├── .travis.yml ├── lib ├── utils.js ├── justify-self.js ├── align-self.js ├── caniuse.js ├── calc-utils.js ├── grid-template-rows.js ├── grid-template-areas.js ├── align-content.js ├── justify-content.js ├── grid-template-columns.js ├── dimension.js ├── parse.js ├── main.js └── fallback.js ├── .gitignore ├── .editorconfig ├── .eslintrc.json ├── package.json ├── LICENSE ├── test.js ├── README.md └── pnpm-lock.yaml /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "10" -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | const 2 | findLastIndex = (arr, test) => arr.length - 1 - arr.slice().reverse().findIndex(test), 3 | 4 | indentMultiline = (lines, indent) => "\n" + lines.map(line => indent + line).join("\n") 5 | 6 | module.exports = { findLastIndex, indentMultiline } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node template 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Dependency directories 13 | node_modules 14 | 15 | # Optional npm cache directory 16 | .npm 17 | 18 | # npm local config 19 | .npmrc 20 | 21 | # Optional REPL history 22 | .node_repl_history 23 | 24 | # IDE 25 | .idea 26 | .vscode 27 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines 7 | [*] 8 | end_of_line = lf 9 | indent_style = tab 10 | indent_size = 4 11 | 12 | # Matches multiple files with brace expansion notation 13 | # Set default charset 14 | [*.{js,html,css}] 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "rules": { 9 | "indent": [ "error", "tab", { "SwitchCase": 1 } ], 10 | "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], 11 | "no-console": "off" 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": 2017, 15 | "sourceType": "module" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/justify-self.js: -------------------------------------------------------------------------------- 1 | module.exports = function getJustifySelf(zone) { 2 | 3 | let leftIndicator = zone.content.search(/←|<-*/), 4 | rightIndicator = zone.content.search(/→|-*>/); 5 | 6 | if (leftIndicator >= 0 && rightIndicator > leftIndicator) 7 | return "stretch" 8 | if (rightIndicator >= 0 && leftIndicator > rightIndicator) 9 | return "center" 10 | if (leftIndicator >= 0) 11 | return "start" 12 | if (rightIndicator >= 0) 13 | return "end" 14 | 15 | return null; 16 | } -------------------------------------------------------------------------------- /lib/align-self.js: -------------------------------------------------------------------------------- 1 | module.exports = function getAlignSelf(zone) { 2 | 3 | const 4 | topIndicator = zone.content.search(/[↑^]/), 5 | bottomIndicator = zone.content.search(/↓|[^\w]v[^\w]/); 6 | 7 | if (topIndicator >= 0 && bottomIndicator > topIndicator) 8 | return "stretch" 9 | if (bottomIndicator >= 0 && topIndicator >= bottomIndicator) 10 | return "center" 11 | if (topIndicator >= 0) 12 | return "start" 13 | if (bottomIndicator >= 0) 14 | return "end" 15 | 16 | return null; 17 | } -------------------------------------------------------------------------------- /lib/caniuse.js: -------------------------------------------------------------------------------- 1 | const 2 | browserslist = require('browserslist'), 3 | caniuselite = require('caniuse-lite'); 4 | 5 | function caniuse(feature, browsers, accepted = ["y"]) { 6 | const { stats } = caniuselite.feature(caniuselite.features[feature]); 7 | return browserslist(browsers) 8 | .map((browser) => browser.split(" ")) 9 | .every(([browser, version]) => stats[browser] && accepted.includes(stats[browser][version])) 10 | } 11 | 12 | caniuse.cssGrid = function caniuseCssGrid(browsers) { 13 | return caniuse("css-grid", browsers) 14 | } 15 | 16 | caniuse.cssSupportsApi = function caniuseCssSupports(browsers) { 17 | // a #2: Does not support parentheses-less one-argument version ; so we always add parenthesis 18 | return caniuse("css-supports-api", browsers, ["y", "a #2"]) 19 | } 20 | 21 | module.exports = caniuse -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-grid-kiss", 3 | "version": "3.1.0", 4 | "description": "A PostCSS plugin to keep CSS grids stupidly simple", 5 | "main": "lib/main.js", 6 | "author": "Sylvain Pollet-Villard", 7 | "license": "MIT", 8 | "repository": "https://github.com/sylvainpolletvillard/postcss-grid-kiss", 9 | "keywords": [ 10 | "postcss", 11 | "postcss-plugin", 12 | "ascii-art", 13 | "visual", 14 | "css", 15 | "grid", 16 | "kiss" 17 | ], 18 | "scripts": { 19 | "test": "ava test.js", 20 | "lint": "eslint lib --fix" 21 | }, 22 | "engines": { 23 | "node": ">=6.0.0" 24 | }, 25 | "dependencies": { 26 | "browserslist": "^4.19.1", 27 | "caniuse-lite": "^1.0.30001301", 28 | "postcss-merge-grid-template": "^0.8.1", 29 | "reduce-css-calc": "^2.1.8" 30 | }, 31 | "devDependencies": { 32 | "ava": "^4.0.1", 33 | "eslint": "^8.7.0", 34 | "postcss": "^8.4.5" 35 | }, 36 | "peerDependencies": { 37 | "postcss": "^8.2.14" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/calc-utils.js: -------------------------------------------------------------------------------- 1 | const 2 | reduceCSSCalc = require('reduce-css-calc'), 3 | {isFluid, isFixed} = require("./dimension"), 4 | 5 | calc = expr => reduceCSSCalc(`calc(${expr})`), 6 | sum = (...args) => calc(args.filter(arg => !!arg).join(" + ") || "0"), 7 | remaining = (...dims) => calc(`100% - ${sum(...dims)}`), 8 | 9 | fraction = (dims, allDims) => { 10 | if (dims.length === 0 || dims.length === allDims.length) 11 | return null; // use default value 12 | 13 | if (dims.every(isFixed)) 14 | return sum(...dims); 15 | 16 | const 17 | fr = dims.filter(isFluid).reduce((total, dim) => total + parseInt(dim), 0), 18 | totalFr = allDims.filter(isFluid).reduce((total, dim) => total + parseInt(dim), 0), 19 | remainingSpace = remaining(...allDims.filter(isFixed)), 20 | remainingFr = calc(fr === totalFr ? remainingSpace : `${remainingSpace} * ${fr} / ${totalFr}`) 21 | 22 | return sum(...dims.filter(isFixed), remainingFr); 23 | } 24 | 25 | module.exports = { sum, remaining, fraction } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Sylvain Pollet-Villard 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /lib/grid-template-rows.js: -------------------------------------------------------------------------------- 1 | const { parseDimension, cleanupDimInput } = require("./dimension"); 2 | 3 | module.exports = function getGridRows({ rows, colIndexes, rowIndexes, options }){ 4 | 5 | const rowDims = []; 6 | 7 | for(let y=0; y < rowIndexes.length; y+=2) { 8 | let dimension = getRowDim({ 9 | rows, colIndexes, 10 | from: rowIndexes[y], 11 | to: rowIndexes[y + 1], 12 | options 13 | }); 14 | 15 | if (dimension === null){ dimension = "1fr"; } 16 | rowDims.push(dimension); 17 | } 18 | 19 | // check vertical gaps 20 | for(let y=0; y row.substring(lastContentColIndex + 1)) 41 | .join(" ") 42 | ); 43 | return parseDimension(dimInput, "vertical", options) 44 | } -------------------------------------------------------------------------------- /lib/grid-template-areas.js: -------------------------------------------------------------------------------- 1 | const {indentMultiline} = require("./utils"); 2 | 3 | module.exports = function getGridAreas({ zones, rowIndexes, colIndexes, indent }){ 4 | 5 | const areaNames = []; 6 | 7 | for(let y = 0; y < rowIndexes.length/2; y++) { 8 | areaNames[y]=[]; 9 | for (let x = 0; x < colIndexes.length/2; x++) { 10 | let currentZone = zones.find( 11 | zone => rowIndexes[2*y] >= zone.top 12 | && rowIndexes[2*y+1] <= zone.bottom 13 | && colIndexes[2*x] >= zone.left 14 | && colIndexes[2*x+1] <= zone.right 15 | ); 16 | 17 | if(currentZone){ 18 | areaNames[y][x] = currentZone.name || "..."; 19 | } else { // gap 20 | areaNames[y][x] = "..."; 21 | zones.push({ 22 | isGap: true, 23 | top: rowIndexes[2*y], 24 | bottom: rowIndexes[2*y+1], 25 | left: colIndexes[2*x], 26 | right: colIndexes[2*x+1] 27 | }) 28 | } 29 | } 30 | } 31 | 32 | let longestNameLengthByCol = []; 33 | for(let y=0; y < areaNames.length; y++){ 34 | for(let x=0; x < areaNames[y].length; x++){ 35 | let nameLength = areaNames[y][x].length; 36 | if(nameLength > (longestNameLengthByCol[x] || 0)){ 37 | longestNameLengthByCol[x] = nameLength; 38 | } 39 | } 40 | } 41 | 42 | return indentMultiline(areaNames.map( 43 | row => `"${row.map( 44 | (name, x) => (name + " ".repeat(longestNameLengthByCol[x])).slice(0, longestNameLengthByCol[x]) 45 | ).join(" ")}"` 46 | ), indent); 47 | } -------------------------------------------------------------------------------- /lib/align-content.js: -------------------------------------------------------------------------------- 1 | const { findLastIndex } = require("./utils"); 2 | 3 | module.exports = function getAlignContent({ rows }){ 4 | 5 | const 6 | isSpaceRow = row => /^\s*$/.test(row), 7 | 8 | firstContentRowIndex = rows.findIndex(row => !isSpaceRow(row)), 9 | lastContentRowIndex = findLastIndex(rows, row => !isSpaceRow(row)), 10 | 11 | hasContent = firstContentRowIndex >= 0 && lastContentRowIndex < rows.length, 12 | 13 | hasSpaceRows = rows.some(isSpaceRow), 14 | hasSpaceRowsBeforeContent = isSpaceRow(rows[0]), 15 | hasSpaceRowsAfterContent = isSpaceRow(rows[rows.length - 1]), 16 | 17 | hasSpaceRowsBetweenContent = hasContent 18 | && rows.slice(firstContentRowIndex, lastContentRowIndex).some(isSpaceRow), 19 | 20 | hasDoubleSpaceRowsBetweenContent = hasContent 21 | && rows 22 | .slice(firstContentRowIndex, lastContentRowIndex-1) 23 | .some((row, index, rows) => isSpaceRow(row) && isSpaceRow(rows[index+1])); 24 | 25 | if(!hasSpaceRows) 26 | return "stretch" 27 | if(hasSpaceRowsBeforeContent && hasSpaceRowsAfterContent && hasDoubleSpaceRowsBetweenContent) 28 | return "space-around" 29 | if(hasSpaceRowsBeforeContent && hasSpaceRowsAfterContent && hasSpaceRowsBetweenContent) 30 | return "space-evenly" 31 | if(hasSpaceRowsBeforeContent && hasSpaceRowsAfterContent) 32 | return "center" 33 | if(hasSpaceRowsBeforeContent) 34 | return "end" 35 | if(hasSpaceRowsAfterContent) 36 | return "start" 37 | if(hasSpaceRowsBetweenContent) 38 | return "space-between" 39 | 40 | } -------------------------------------------------------------------------------- /lib/justify-content.js: -------------------------------------------------------------------------------- 1 | const { findLastIndex } = require("./utils"); 2 | 3 | module.exports = function getJustifyContent({ cols }) { 4 | 5 | const 6 | isSpaceCol = col => /^\s*$/.test(col), 7 | isContentCol = col => !isSpaceCol(col), 8 | 9 | firstContentColIndex = cols.findIndex(isContentCol), 10 | lastContentColIndex = findLastIndex(cols, isContentCol), 11 | 12 | hasContent = firstContentColIndex >= 0 && lastContentColIndex < cols.length, 13 | 14 | hasSpaceCols = cols.some(isSpaceCol), 15 | hasSpaceColsBeforeContent = isSpaceCol(cols[0]) && isSpaceCol(cols[1]), 16 | hasSpaceRowsAfterContent = isSpaceCol(cols[cols.length-1]) && isSpaceCol(cols[cols.length-2]), 17 | 18 | hasSpaceColsBetweenContent = hasContent 19 | && cols 20 | .slice(firstContentColIndex, lastContentColIndex-1) 21 | .some((col, index, cols) => isSpaceCol(col) && isSpaceCol(cols[index+1])), 22 | 23 | hasDoubleSpaceColsBetweenContent = hasContent 24 | && cols 25 | .slice(firstContentColIndex, lastContentColIndex-3) 26 | .some((col, index, cols) => [0,1,2,3].every(i => isSpaceCol(cols[index+i]))) 27 | 28 | 29 | if(!hasSpaceCols) 30 | return "stretch" 31 | if(hasDoubleSpaceColsBetweenContent && hasSpaceColsBeforeContent && hasSpaceRowsAfterContent) 32 | return "space-around" 33 | if(hasSpaceColsBetweenContent && hasSpaceColsBeforeContent && hasSpaceRowsAfterContent) 34 | return "space-evenly" 35 | if(hasSpaceColsBetweenContent && !hasSpaceColsBeforeContent && !hasSpaceRowsAfterContent) 36 | return "space-between" 37 | if(hasSpaceColsBeforeContent && hasSpaceRowsAfterContent) 38 | return "center" 39 | if(hasSpaceColsBeforeContent) 40 | return "end" 41 | if(hasSpaceRowsAfterContent) 42 | return "start" 43 | 44 | } -------------------------------------------------------------------------------- /lib/grid-template-columns.js: -------------------------------------------------------------------------------- 1 | const { parseDimension, cleanupDimInput } = require("./dimension"); 2 | 3 | module.exports = function getGridCols({ decl, rows, zones, colIndexes, rowIndexes, options }){ 4 | 5 | const colDims = new Array(Math.floor(colIndexes.length / 2)).fill("1fr"); // autofill by default 6 | 7 | // match border content 8 | for(let zone of zones) { 9 | for (let side of ["top", "bottom"]) { 10 | const 11 | colIndexLeft = colIndexes.indexOf(zone.left), 12 | colIndexRight = colIndexes.indexOf(zone.right), 13 | colDim = getColDim({ row: rows[zone[side]], from: zone.left, to: zone.right, options }); 14 | 15 | if (colDim != null) { 16 | if (colIndexRight === colIndexLeft + 1) { 17 | colDims[Math.floor(colIndexLeft / 2)] = colDim; 18 | } 19 | else throw decl.error(`You cannot specify the width of a zone occupying more than one column.`); 20 | } 21 | } 22 | } 23 | 24 | // check the last row 25 | let lastRow = rows[rowIndexes.slice(-1)[0] + 1]; 26 | if(lastRow){ 27 | for(let x=0; x < colDims.length; x++){ 28 | const 29 | left = colIndexes[2*x], 30 | right = colIndexes[2*x + 1], 31 | colDim = getColDim({ row: lastRow, from: left, to: right, options }); 32 | 33 | if (colDim != null) { 34 | colDims[x] = colDim; 35 | } 36 | } 37 | 38 | // check horizontal gaps 39 | for(let x=0; x < colIndexes.length-2; x+=2){ 40 | const 41 | left = colIndexes[x + 1] + 1, 42 | right = colIndexes[x + 2] - 1, 43 | gapDim = getColDim({ row: lastRow, from: left, to : right, options }); 44 | 45 | if(gapDim != null){ // horizontal gap detected 46 | colDims.splice(Math.floor(x/2)+1, 0, gapDim); 47 | colIndexes.splice(x+2, 0, left, right); 48 | x+=2; 49 | } 50 | } 51 | 52 | } 53 | 54 | return colDims; 55 | } 56 | 57 | function getColDim({ row, from, to, options }){ 58 | const dimInput = cleanupDimInput(row.substring(from, to + 1)); 59 | return parseDimension(dimInput, "horizontal", options) 60 | } -------------------------------------------------------------------------------- /lib/dimension.js: -------------------------------------------------------------------------------- 1 | const 2 | REGEX_LENGTH = /^(\d+(?:\.\d+)?)([a-z]{1,4})$/, 3 | REGEX_PERCENT = /^(\d+(?:\.\d+)?)%\s*(free|grid|view)?$/, 4 | REGEX_DIMENSION = /(\d+(?:\.\d+)?)%?\s*([a-z]{1,4})/, 5 | REGEX_CALC = /^calc\((.*)\)$/, 6 | REGEX_VAR = /^var\((.*)\)$/, 7 | 8 | isFluid = dim => dim.endsWith("fr"), 9 | isFixed = dim => !isFluid(dim) 10 | 11 | function parseDimension(str, direction, options){ 12 | 13 | str = str.trim(); 14 | 15 | // when no value is specified, row and column sizes are set as `auto` 16 | if(str.length === 0) 17 | return null; 18 | 19 | if(str === "auto") 20 | return "1fr"; 21 | 22 | // non-negative number representing a fraction of the free space in the grid container 23 | if(!isNaN(str)) 24 | return `${parseFloat(str)}fr` 25 | 26 | if(REGEX_LENGTH.test(str)) 27 | return str; 28 | 29 | // calc() expression 30 | if(REGEX_CALC.test(str)) 31 | return str; 32 | 33 | // var() expression 34 | if(REGEX_VAR.test(str)) 35 | return str; 36 | 37 | if(REGEX_PERCENT.test(str)){ 38 | let [, percentage, referential] = str.match(REGEX_PERCENT); 39 | switch(referential){ 40 | case "free": 41 | return `${percentage}fr` 42 | case "view": 43 | return `${percentage}${direction === "vertical" ? "vh" : "vw"}` 44 | case "grid": 45 | default: 46 | return `${percentage}%`; 47 | } 48 | } 49 | 50 | // `> *length*` or `< *length*`: a minimum or maximum value 51 | if(str.startsWith("<")) 52 | return `minmax(auto, ${parseDimension(str.substring(1), direction, options)})` 53 | 54 | if(str.startsWith(">")) 55 | return `minmax(${parseDimension(str.substring(1), direction, options)}, auto)` 56 | 57 | // a range between a minimum and a maximum or `minmax(min, max)` 58 | let [min, max] = str.split("-") 59 | if([min, max].every(dim => REGEX_DIMENSION.test(dim))){ 60 | return `minmax(${parseDimension(min, direction, options)}, ${parseDimension(max, direction, options)})` 61 | } 62 | 63 | // a keyword representing the largest maximal content contribution of the grid items occupying the grid track 64 | if(str === "max" || str === "max-content") 65 | return "max-content" 66 | 67 | // a keyword representing the largest minimal content contribution of the grid items occupying the grid track 68 | if(str === "min" || str === "min-content") 69 | return "min-content" 70 | 71 | // a keyword representing the formula min(max-content, max(auto, *length*)), 72 | // which is calculated similar to auto (i.e. minmax(auto, max-content)), 73 | // except that the track size is clamped at argument *length* if it is greater than the auto minimum. 74 | 75 | if(str.startsWith("fit")) 76 | return str.replace(/fit (.*)$/, "fit-content($1)"); 77 | 78 | // empty or unknwown dimension syntax, calls custom parser if provided 79 | if(options.dimensionParser){ 80 | return options.dimensionParser(str) 81 | } 82 | 83 | return null; // will default to 1fr 84 | } 85 | 86 | function cleanupDimInput(input){ 87 | return input 88 | .replace(/[|─└┘┌┐═╚╝╔╗]/g, "") // remove borders and separators characters 89 | .replace(/^[-+\s]+|[-+\s]+$/g, "") // remove remaining '-' '+' segments but preserve range dimensions 90 | } 91 | 92 | module.exports = { parseDimension, cleanupDimInput, isFluid, isFixed } -------------------------------------------------------------------------------- /lib/parse.js: -------------------------------------------------------------------------------- 1 | const CORNERS_CHARS = /[+┌┐└┘╔╗╚╝]/ 2 | 3 | module.exports = function parse(decl, options) { 4 | const 5 | rows = getRows(decl.value), 6 | cols = getCols({ rows }), 7 | { colIndexes, rowIndexes } = getCorners({ rows }), 8 | zones = getZones({ rows, cols, colIndexes, rowIndexes, options }); 9 | 10 | return { rows, cols, zones, rowIndexes, colIndexes }; 11 | } 12 | 13 | function getRows(str) { 14 | return str.match(/".*?"|'.*?'/g).map(row => row.slice(1, row.length - 1)); 15 | } 16 | 17 | function getCols({ rows }) { 18 | const 19 | getCol = n => rows.map(row => row[n]).join(''), 20 | colsLength = Math.min(...rows.map(row => row.length)); 21 | return [...Array(colsLength).keys()].map(getCol); 22 | } 23 | 24 | function getCorners({ rows }) { 25 | let colIndexes = new Set, 26 | rowIndexes = new Set; 27 | 28 | rows.forEach((row, rowIndex) => { 29 | row.split('').forEach((char, colIndex) => { 30 | if (CORNERS_CHARS.test(char)) { 31 | colIndexes.add(colIndex); 32 | rowIndexes.add(rowIndex); 33 | } 34 | }); 35 | }); 36 | 37 | colIndexes = Array.from(colIndexes).sort((a, b) => a - b) 38 | rowIndexes = Array.from(rowIndexes).sort((a, b) => a - b) 39 | 40 | return { colIndexes, rowIndexes }; 41 | } 42 | 43 | function getZones({ rows, cols, colIndexes, rowIndexes, options }) { 44 | const zones = []; 45 | 46 | for (let y = 0; y < rowIndexes.length - 1; y += 2) { 47 | for (let x = 0; x < colIndexes.length - 1; x += 2) { 48 | const 49 | top = rowIndexes[y], 50 | left = colIndexes[x], 51 | zone = { top, left }; 52 | 53 | if (!isInZone({ zones, x: left, y: top })) { 54 | let bottom, right; 55 | 56 | if (CORNERS_CHARS.test(rows[top][left])) { 57 | // a zone starts here, see how far if goes 58 | bottom = cols[left].slice(top + 1).search(CORNERS_CHARS) + top + 1; 59 | right = rows[top].slice(left + 1).search(CORNERS_CHARS) + left + 1; 60 | } else { 61 | zone.isHole = true; // no zone found, presumed as hole 62 | bottom = rowIndexes[y + 1]; 63 | right = colIndexes[x + 1]; 64 | } 65 | 66 | zone.bottom = bottom; 67 | zone.right = right; 68 | zone.content = rows 69 | .slice(top + 1, bottom) 70 | .map(row => row.substring(left + 1, right)) 71 | .join(" "); 72 | zone.selector = getZoneSelector(zone, options) || null; 73 | zone.name = getZoneName({ zone, zones }); 74 | 75 | zones.push(zone); 76 | } 77 | } 78 | } 79 | 80 | return zones; 81 | } 82 | 83 | function getZoneSelector(zone, options) { 84 | const selector = zone.content 85 | .replace(/[^\w]v[^\w]|→|-*>|←|<-*|[^\w#.:\-[\]()]/g, "") 86 | .replace(/^:(\d+)$/, "*:nth-child($1)") // :2 => *:nth-child(2) 87 | .replace(/(^[\w-]+):(\d+)$/, "$1:nth-of-type($2)") // button:1 => button:nth-of-type(1) 88 | 89 | return options.selectorParser ? options.selectorParser(selector) : selector 90 | } 91 | 92 | function getZoneName({ zone, zones }) { 93 | if (!zone.selector) return null; 94 | 95 | const 96 | zoneNames = new Set(zones.map(z => z.name)), 97 | zoneSelectors = new Set(zones.map(z => z.selector)), 98 | zoneNamesBySelector = new Map([...zoneSelectors].map(s => [s, zones.find(z => z.selector === s).name])); 99 | 100 | if (zoneNamesBySelector.has(zone.selector)) { 101 | return zoneNamesBySelector.get(zone.selector) 102 | } 103 | 104 | let baseName = zone.selector 105 | .replace(/(\w)([#.[])/g, "$1_") // .foo#bar.baz[qux] => .foo_bar_baz_qux] 106 | .replace(/[^\w]/g, ""); // .foo_bar_baz_qux] => foo_baz_baz_qux 107 | 108 | let aliasNum = 1, 109 | name = baseName; 110 | 111 | while (zoneNames.has(name)) { 112 | name = baseName + aliasNum; 113 | aliasNum++; 114 | } 115 | 116 | zoneNames.add(name); 117 | zoneNamesBySelector.set(zone.selector, name); 118 | return name; 119 | } 120 | 121 | function isInZone({ zones, x, y }) { 122 | return zones.some( 123 | zone => x >= zone.left 124 | && x <= zone.right 125 | && y >= zone.top 126 | && y <= zone.bottom 127 | ); 128 | } -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | const 2 | optimizeRule = require("postcss-merge-grid-template/lib/optimize"), 3 | 4 | caniuse = require("./caniuse"), 5 | parse = require("./parse"), 6 | getAlignContent = require("./align-content"), 7 | getJustifyContent = require("./justify-content"), 8 | getAlignSelf = require("./align-self"), 9 | getJustifySelf = require("./justify-self"), 10 | getGridRows = require("./grid-template-rows"), 11 | getGridCols = require("./grid-template-columns"), 12 | getGridAreas = require("./grid-template-areas"), 13 | getFallback = require("./fallback"); 14 | 15 | const DEFAULTS_OPTIONS = { 16 | optimize: true 17 | } 18 | 19 | module.exports = function (options) { 20 | options = Object.assign({}, DEFAULTS_OPTIONS, options); 21 | 22 | let isFallbackNeeded = !caniuse.cssGrid(options.browsers); 23 | let isIEHackNeeded = !caniuse.cssSupportsApi(options.browsers); 24 | 25 | if ("fallback" in options) { 26 | isFallbackNeeded = options.fallback; 27 | isIEHackNeeded = options.fallback; 28 | } 29 | 30 | const gridKiss = (decl, { result, Rule, AtRule }) => { 31 | const 32 | { rows, cols, zones, rowIndexes, colIndexes } = parse(decl, options), 33 | grid = { props: new Map, rule: decl.parent }, 34 | indent = decl.raws.before.match(/.*$/)[0], 35 | nameMapping = new Map(), 36 | rowDims = getGridRows({ rows, colIndexes, rowIndexes, options }), 37 | colDims = getGridCols({ decl, rows, zones, colIndexes, rowIndexes, options }) 38 | 39 | let lastRule = grid.rule; 40 | 41 | grid.props.set("display", "grid"); 42 | grid.props.set("align-content", getAlignContent({ rows })); 43 | grid.props.set("justify-content", getJustifyContent({ cols })); 44 | grid.props.set("grid-template-rows", rowDims.join(" ")); 45 | grid.props.set("grid-template-columns", colDims.join(" ")); 46 | grid.props.set("grid-template-areas", getGridAreas({ zones, rowIndexes, colIndexes, indent })); 47 | 48 | // grid properties 49 | for (let [prop, value] of grid.props) { 50 | if (value) { 51 | decl.cloneBefore({ prop, value, raws: { before: '\n\t', after: '' } }); 52 | } 53 | } 54 | 55 | if (options.optimize) { 56 | optimizeRule(grid.rule, nameMapping); 57 | } 58 | 59 | // zone declarations 60 | 61 | zones.filter(zone => zone.selector).forEach(zone => { 62 | zone.props = new Map; 63 | 64 | let name = zone.name; 65 | if (options.optimize && nameMapping.has(zone.name)) { 66 | name = nameMapping.get(zone.name); 67 | } 68 | 69 | zone.props.set("grid-area", name); 70 | zone.props.set("justify-self", getJustifySelf(zone)); 71 | zone.props.set("align-self", getAlignSelf(zone)); 72 | 73 | zone.rule = new Rule({ 74 | selector: `${grid.rule.selector} > ${zone.selector}`, 75 | source: decl.source, 76 | raws: { before: '\n\n', after: '\n' } 77 | }); 78 | 79 | for (let [prop, value] of zone.props) { 80 | if (value) { 81 | zone.rule.append({ prop, value, raws: { before: '\n\t', after: '' } }); 82 | } 83 | } 84 | 85 | grid.rule.parent.insertAfter(lastRule, zone.rule); 86 | lastRule = zone.rule 87 | }) 88 | 89 | if (isFallbackNeeded) { 90 | const fallback = getFallback({ 91 | zones, grid, decl, result, options, colIndexes, rowIndexes, colDims, rowDims 92 | }); 93 | 94 | const supportsRule = new AtRule({ 95 | name: "supports", 96 | params: 'not (grid-template-areas:"test")' 97 | }); 98 | 99 | const ieHackRule = new AtRule({ 100 | name: "media", 101 | params: 'screen and (min-width:0\\0)' 102 | }); 103 | 104 | supportsRule.append(fallback.grid.rule.clone({ raws: { before: '\n\t', after: '\n\t' } })); 105 | ieHackRule.append(fallback.grid.rule.clone({ raws: { before: '\n\t', after: '\n\t' } })); 106 | for (let zoneFallback of fallback.zones.values()) { 107 | supportsRule.append(zoneFallback.rule.clone({ raws: { before: '\n\n\t', after: '\n\t' } })); 108 | ieHackRule.append(zoneFallback.rule.clone({ raws: { before: '\n\n\t', after: '\n\t' } })); 109 | } 110 | 111 | if (isIEHackNeeded) { 112 | grid.rule.parent.insertAfter(lastRule, ieHackRule); 113 | } 114 | 115 | grid.rule.parent.insertAfter(lastRule, supportsRule); 116 | } 117 | 118 | decl.remove(); // remove grid-kiss rule in output 119 | } 120 | 121 | return { 122 | postcssPlugin: 'postcss-grid-kiss', 123 | Declaration: { 124 | "grid-kiss": gridKiss, 125 | "grid-template-kiss": gridKiss // see https://github.com/sylvainpolletvillard/postcss-grid-kiss/issues/25 126 | } 127 | } 128 | }; 129 | 130 | module.exports.postcss = true -------------------------------------------------------------------------------- /lib/fallback.js: -------------------------------------------------------------------------------- 1 | const 2 | { isFluid } = require("./dimension"), 3 | { sum, remaining, fraction } = require("./calc-utils"); 4 | 5 | module.exports = function getFallback({ 6 | zones, grid, decl, result, colIndexes, rowIndexes, colDims, rowDims 7 | }){ 8 | const dimensionsFallback = dims => dims.map(dim => dimensionFallback(dim, { decl, result })); 9 | colDims = dimensionsFallback(colDims); 10 | rowDims = dimensionsFallback(rowDims); 11 | 12 | const 13 | fallback = { 14 | grid: getGridFallback({ colDims, rowDims, rule: grid.rule, props: grid.props }), 15 | zones: new Map 16 | }, 17 | 18 | zonesCommonRule = grid.rule.clone({ 19 | selector: grid.rule.selector + ' > *', 20 | nodes: [] 21 | }); 22 | 23 | zonesCommonRule.append({ prop: "position", value: "absolute" }); 24 | zonesCommonRule.append({ prop: "box-sizing", value: "border-box" }); 25 | fallback.zones.set('*', { rule: zonesCommonRule }) 26 | 27 | for(let zone of zones.filter(zone => zone.selector)){ 28 | fallback.zones.set(zone, getZoneFallback({ 29 | zone, grid, colIndexes, rowIndexes, colDims, rowDims 30 | })) 31 | } 32 | 33 | return fallback; 34 | } 35 | 36 | function dimensionFallback(dim, { decl, result }){ 37 | if(dim === "max-content" 38 | || dim === "min-content" 39 | || dim.startsWith("minmax(") 40 | || dim.startsWith("fit-content")){ 41 | decl.warn(result, dim + " operator is not supported in fallback mode. Replaced by 1fr."); 42 | dim = "1fr"; 43 | } 44 | return dim; 45 | } 46 | 47 | function getGridFallback({ 48 | rowDims, colDims, rule 49 | }){ 50 | const grid = { 51 | rule: rule.clone({ nodes: [] }), 52 | props: new Map 53 | }; 54 | 55 | const gridWidth = colDims.some(isFluid) ? "100%" : sum(...colDims); 56 | const gridHeight = rowDims.some(isFluid) ? "100%" : sum(...rowDims); 57 | 58 | grid.props.set("position", "relative"); 59 | grid.props.set("display", "block"); 60 | grid.props.set("width", gridWidth); 61 | grid.props.set("height", gridHeight); 62 | 63 | for (let [prop,value] of grid.props) { 64 | if (value != null){ 65 | grid.rule.append({ prop, value }); 66 | } 67 | } 68 | 69 | return grid; 70 | } 71 | 72 | function getZoneFallback({ 73 | zone, rowIndexes, colIndexes, rowDims, colDims, grid 74 | }) { 75 | 76 | const fallbackRule = zone.rule.clone({ nodes: [] }); 77 | const fallbackProps = new Map; 78 | 79 | const {height, isStretchingVertically} = getHeight({ zone, rowDims, rowIndexes }); 80 | const {width, isStretchingHorizontally} = getWidth({ zone, colDims, colIndexes }); 81 | const {verticalOffset, alignByBottom} = getVerticalOffset({ zone, grid, rowDims, rowIndexes, height }); 82 | const {horizontalOffset, alignByRight} = getHorizontalOffset({ zone, grid, colDims, colIndexes, width }); 83 | 84 | fallbackProps.set("transform", getTransform(zone)); 85 | fallbackProps.set(isStretchingVertically ? "height" : "max-height", height); 86 | fallbackProps.set(isStretchingHorizontally ? "width" : "max-width", width); 87 | fallbackProps.set(alignByBottom ? "bottom" : "top", verticalOffset); 88 | fallbackProps.set(alignByRight ? "right" : "left", horizontalOffset); 89 | 90 | for (let [prop,value] of fallbackProps) { 91 | if (value != null){ 92 | fallbackRule.append({ prop, value }) 93 | } 94 | } 95 | 96 | return { props: fallbackProps, rule: fallbackRule } 97 | } 98 | 99 | function getVerticalOffset({ zone, grid, rowDims, rowIndexes, height }){ 100 | const alignSelf = zone.props.get("align-self") || "stretch"; 101 | 102 | let offsetDims = [], 103 | alignByBottom = false, 104 | gridDelta = getAlignContentFallbackDelta({ zone, grid, rowDims, rowIndexes }); 105 | 106 | if(alignSelf === "end") { 107 | alignByBottom = true; 108 | let bottomIndex = rowIndexes.findIndex(rowIndex => rowIndex === zone.bottom); 109 | for (let y = rowIndexes.length - 1; y > bottomIndex; y -= 2) { 110 | offsetDims.push(rowDims[Math.floor(y / 2)]); 111 | } 112 | } else { 113 | let topIndex = rowIndexes.findIndex(rowIndex => rowIndex === zone.top); 114 | for (let y = 0; y < topIndex; y += 2) { 115 | offsetDims.push(rowDims[Math.floor(y / 2)]); 116 | } 117 | } 118 | 119 | if(alignByBottom && gridDelta && gridDelta !== "0"){ 120 | gridDelta = remaining(gridDelta); 121 | } 122 | 123 | let offset = sum( 124 | gridDelta, 125 | fraction(offsetDims, rowDims), 126 | alignSelf === "center" ? `calc(${height} / 2)` : "0" 127 | ) || "0"; 128 | 129 | return { 130 | verticalOffset: offset, 131 | alignByBottom 132 | } 133 | } 134 | 135 | function getHorizontalOffset({ zone, grid, colDims, colIndexes, width }){ 136 | const justifySelf = zone.props.get("justify-self") || "stretch"; 137 | 138 | let offsetDims = [], 139 | alignByRight = false, 140 | gridDelta = getJustifyContentFallbackDelta({ zone, grid, colDims, colIndexes }); 141 | 142 | if(justifySelf === "end") { 143 | alignByRight = true; 144 | let rightIndex = colIndexes.findIndex(colIndex => colIndex === zone.right); 145 | for (let x = colIndexes.length - 1; x > rightIndex; x -= 2) { 146 | offsetDims.push(colDims[Math.floor(x / 2)]); 147 | } 148 | } else { 149 | let leftIndex = colIndexes.findIndex(colIndex => colIndex === zone.left); 150 | for(let x=0; x rowIndex === zone.top), 177 | bottomIndex = rowIndexes.findIndex(rowIndex => rowIndex === zone.bottom); 178 | 179 | for(let y=topIndex; y colIndex === zone.left), 195 | rightIndex = colIndexes.findIndex(colIndex => colIndex === zone.right); 196 | for(let x=leftIndex; x colIndex === zone.left), 231 | index = Math.floor(leftIndex / 2), 232 | nbCols = colDims.length; 233 | 234 | if(justifyGrid === "end") 235 | return remainingSpace; 236 | if(justifyGrid === "center") 237 | return `calc(${remainingSpace} / 2)` 238 | if(justifyGrid === "space-between") 239 | return `calc(${remainingSpace} * ${index} / ${nbCols - 1})` 240 | if(justifyGrid === "space-around") 241 | return `calc(${remainingSpace} * ${(index * 2) + 1} / ${nbCols * 2})` 242 | if(justifyGrid === "space-evenly") 243 | return `calc(${remainingSpace} * ${index + 1} / ${nbCols + 1})` 244 | } 245 | 246 | function getAlignContentFallbackDelta({ zone, grid, rowDims, rowIndexes }){ 247 | 248 | if(rowDims.some(isFluid)) return "0" // fluid zone will fit all the remaining space 249 | 250 | const alignGrid = grid.props.get("align-content") || "stretch"; 251 | 252 | if(alignGrid === "stretch") 253 | return "0" 254 | if(alignGrid === "start") 255 | return "0" 256 | 257 | const remainingSpace = remaining(...rowDims), 258 | topIndex = rowIndexes.findIndex(rowIndex => rowIndex === zone.top), 259 | index = Math.floor(topIndex / 2), 260 | nbRows = rowDims.length; 261 | 262 | if(alignGrid === "end") 263 | return remainingSpace 264 | if(alignGrid === "center") 265 | return `calc(${remainingSpace} / 2)` 266 | if(alignGrid === "space-between") 267 | return `calc(${remainingSpace} * ${index} / ${nbRows - 1})` 268 | if(alignGrid === "space-around") 269 | return `calc(${remainingSpace} * ${(index * 2) + 1} / ${nbRows * 2})` 270 | if(alignGrid === "space-evenly") 271 | return `calc(${remainingSpace} * ${index + 1} / ${nbRows + 1})` 272 | 273 | } -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss'), 2 | gridkiss = require('./lib/main'), 3 | test = require('ava'); 4 | 5 | const { remaining, sum } = require("./lib/calc-utils"); 6 | const { parseDimension } = require("./lib/dimension"); 7 | const caniuse = require("./lib/caniuse"); 8 | 9 | async function process(input, options) { 10 | return postcss(gridkiss(options)).process(input, { from: undefined }).then(res => { 11 | const output = {}; 12 | res.root.walkRules((rule) => { 13 | if (rule.parent === res.root) { 14 | output[rule.selector] = {}; 15 | rule.walkDecls((decl) => { 16 | output[rule.selector][decl.prop] = decl.value; 17 | }) 18 | } 19 | }); 20 | res.root.walkAtRules((atrule) => { 21 | output[atrule.name] = { params: atrule.params }; 22 | atrule.walkRules((rule) => { 23 | output[atrule.name][rule.selector] = {}; 24 | rule.walkDecls((decl) => { 25 | output[atrule.name][rule.selector][decl.prop] = decl.value; 26 | }) 27 | }); 28 | }); 29 | 30 | return output; 31 | }).catch(err => console.error(err)); 32 | } 33 | 34 | test("parsing dimensions", t => { 35 | t.is(parseDimension("1"), "1fr") 36 | t.is(parseDimension("1px"), "1px") 37 | t.is(parseDimension("0"), "0fr") 38 | t.is(parseDimension("10"), "10fr") 39 | t.is(parseDimension("12.34em"), "12.34em") 40 | t.is(parseDimension("12.34em - 56.78vmin"), "minmax(12.34em, 56.78vmin)") 41 | t.is(parseDimension("> 3rem"), "minmax(3rem, auto)") 42 | t.is(parseDimension("< 10"), "minmax(auto, 10fr)") 43 | t.is(parseDimension("50%"), "50%") 44 | t.is(parseDimension("12.5%"), "12.5%") 45 | t.is(parseDimension("50% grid"), "50%") 46 | t.is(parseDimension("5.55% free"), "5.55fr") 47 | t.is(parseDimension("50% view", "horizontal"), "50vw") 48 | t.is(parseDimension("50% view", "vertical"), "50vh") 49 | t.is(parseDimension("calc(20% + 10px)"), "calc(20% + 10px)") 50 | t.is(parseDimension("calc(20% + 10%)"), "calc(20% + 10%)") 51 | t.is(parseDimension("min"), "min-content") 52 | t.is(parseDimension("max"), "max-content") 53 | t.is(parseDimension("var(--test)"), "var(--test)") 54 | t.is(parseDimension("$customVar", "vertical", { 55 | dimensionParser(dim) { 56 | if (/\$[\w-]+/.test(dim)) return dim // custom var syntax, leave untouched for next pcss plugin in the chain 57 | return null; // unrecognized syntax 58 | } 59 | }), "$customVar"); 60 | t.is(parseDimension("v(my-cool-length)", "horizontal", { 61 | dimensionParser(dim) { 62 | const CUSTOM_VAR_SYNTAX = /v\(([^)]+)\)/ 63 | const varMatch = dim.match(CUSTOM_VAR_SYNTAX) 64 | if (varMatch != null) { 65 | return `var(--${varMatch[1]})` 66 | } 67 | return null; // unrecognized syntax 68 | } 69 | }), "var(--my-cool-length)"); 70 | }) 71 | 72 | test("calc utils", t => { 73 | t.is(sum("120px", "1em", "100px", "2em"), "calc(220px + 3em)"); 74 | t.is(remaining('120px', '1em', '2em', '100px'), "calc(100% - 220px - 3em)"); 75 | }) 76 | 77 | test("browser support", t => { 78 | t.is(caniuse.cssGrid("IE 11"), false) 79 | t.is(caniuse.cssGrid("last 2 Chrome versions"), true) 80 | t.is(caniuse.cssSupportsApi("Firefox > 20"), false) 81 | t.is(caniuse.cssSupportsApi("Firefox > 40"), true) 82 | }) 83 | 84 | test('display grid', async t => { 85 | let output = await process( 86 | `div { 87 | grid-kiss: 88 | "+------+" 89 | "| test |" 90 | "+------+" 91 | }`, { fallback: true }); 92 | 93 | t.is(output["div"]["display"], "grid"); 94 | }); 95 | 96 | test('align-content stretch', async t => { 97 | let output = await process( 98 | `div { 99 | grid-kiss: 100 | "+------+" 101 | "| test |" 102 | "+------+" 103 | }`); 104 | 105 | t.is(output["div"]["align-content"], "stretch"); 106 | }) 107 | 108 | test('align-content start', async t => { 109 | let output = await process( 110 | `div { 111 | grid-kiss: 112 | "+------+" 113 | "| test |" 114 | "+------+" 115 | " " 116 | }`); 117 | 118 | t.is(output["div"]["align-content"], "start"); 119 | }) 120 | 121 | test('align-content end', async t => { 122 | let output = await process( 123 | `div { 124 | grid-kiss: 125 | " " 126 | "+------+" 127 | "| test |" 128 | "+------+" 129 | }`); 130 | 131 | t.is(output["div"]["align-content"], "end"); 132 | }); 133 | 134 | test('align-content center', async t => { 135 | let output = await process( 136 | `div { 137 | grid-kiss: 138 | " " 139 | "+------+" 140 | "| test |" 141 | "+------+" 142 | " " 143 | }`); 144 | 145 | t.is(output["div"]["align-content"], "center"); 146 | }); 147 | 148 | test('align-content space-between', async t => { 149 | let output = await process( 150 | `div { 151 | grid-kiss: 152 | "+------+" 153 | "| foo |" 154 | "+------+" 155 | " " 156 | "+------+" 157 | "| bar |" 158 | "+------+" 159 | }`); 160 | 161 | t.is(output["div"]["align-content"], "space-between"); 162 | }) 163 | 164 | test('align-content space-evenly', async t => { 165 | let output = await process( 166 | `div { 167 | grid-kiss: 168 | " " 169 | "+------+" 170 | "| foo |" 171 | "+------+" 172 | " " 173 | "+------+" 174 | "| bar |" 175 | "+------+" 176 | " " 177 | }`); 178 | 179 | t.is(output["div"]["align-content"], "space-evenly"); 180 | }) 181 | 182 | test('align-content space-around', async t => { 183 | let output = await process( 184 | `div { 185 | grid-kiss: 186 | " " 187 | "+------+" 188 | "| foo |" 189 | "+------+" 190 | " " 191 | " " 192 | "+------+" 193 | "| bar |" 194 | "+------+" 195 | " " 196 | }`); 197 | 198 | t.is(output["div"]["align-content"], "space-around"); 199 | }) 200 | 201 | test('justify-content start', async t => { 202 | let output = await process( 203 | `div { 204 | grid-kiss: 205 | "+------++------+ " 206 | "| foo || bar | " 207 | "+------++------+ " 208 | }`); 209 | 210 | t.is(output["div"]["justify-content"], "start"); 211 | }); 212 | 213 | test('justify-content end', async t => { 214 | let output = await process( 215 | `div { 216 | grid-kiss: 217 | " +-----++-----+" 218 | " | foo || bar |" 219 | " +-----++-----+" 220 | }`) 221 | 222 | t.is(output["div"]["justify-content"], "end"); 223 | }); 224 | 225 | test('justify-content center', async t => { 226 | let output = await process( 227 | `div { 228 | grid-kiss: 229 | " +------++------+ " 230 | " | foo || bar | " 231 | " +------++------+ " 232 | }`) 233 | 234 | t.is(output["div"]["justify-content"], "center"); 235 | }); 236 | 237 | test('justify-content space-between', async t => { 238 | let output = await process( 239 | `div { 240 | grid-kiss: 241 | "+------+ +------+" 242 | "| foo | | bar |" 243 | "+------+ +------+" 244 | }`) 245 | 246 | t.is(output["div"]["justify-content"], "space-between"); 247 | }); 248 | 249 | test('justify-content space-evenly', async t => { 250 | let output = await process( 251 | `div { 252 | grid-kiss: 253 | " +------+ +------+ " 254 | " | foo | | bar | " 255 | " +------+ +------+ " 256 | }`) 257 | 258 | t.is(output["div"]["justify-content"], "space-evenly"); 259 | }); 260 | 261 | test('justify-content space-around', async t => { 262 | let output = await process( 263 | `div { 264 | grid-kiss: 265 | " +------+ +------+ " 266 | " | foo | | bar | " 267 | " +------+ +------+ " 268 | }`) 269 | 270 | t.is(output["div"]["justify-content"], "space-around"); 271 | }); 272 | 273 | test('grid template rows', async t => { 274 | let output = await process( 275 | `div { 276 | grid-kiss: 277 | " +------+ +------+ " 278 | " | foo | | bar | 40px " 279 | " +------+ +------+ " 280 | " +------+ +------+ " 281 | " | bar | | foo | 15% " 282 | " +------+ +------+ " 283 | }`, { optimize: false }) 284 | 285 | t.is(output["div"]["grid-template-rows"], "40px 15%"); 286 | 287 | output = await process( 288 | `div { 289 | grid-kiss: 290 | "+------+ +------+ " 291 | "| | | bar | " 292 | "| | +------+ " 293 | "| baz | " 294 | "| | +------+ " 295 | "| | | foo | 50% free" 296 | "+------+ +------+ " 297 | " " 298 | "+------+ +------+ " 299 | "| bar | | foo | > 20fr" 300 | "+------+ +------+ " 301 | }`, { optimize: false }) 302 | 303 | t.is(output["div"]["grid-template-rows"], "1fr 50fr minmax(20fr, auto)"); 304 | 305 | output = await process( 306 | `div { 307 | grid-kiss: 308 | '+------+ +------+ - ' 309 | '| | | ^ | <10% ' 310 | '| | | bar >| ' 311 | '| v | +------+ - ' 312 | '| baz | ' 313 | '| ^ | +------+ - ' 314 | '| | | ^ | 50% free' 315 | '+------+ | | - ' 316 | ' | foo | ' 317 | '+------+ | | - ' 318 | '| < qux| | v | > 20fr' 319 | '| v | | | ' 320 | '+------+ +------+ - ' 321 | }`, { optimize: false }); 322 | 323 | t.is(output["div"]["grid-template-rows"], "minmax(auto, 10%) 50fr minmax(20fr, auto)"); 324 | 325 | }); 326 | 327 | test('grid template columns', async t => { 328 | let output = await process( 329 | `div { 330 | grid-kiss: 331 | " +-50px-+ +------+ " 332 | " | foo | | bar | 40px " 333 | " +------+ +------+ " 334 | " +------+ +-25.5%+ " 335 | " | bar | | foo | 15% " 336 | " +------+ +------+ " 337 | }`, { optimize: false }) 338 | 339 | t.is(output["div"]["grid-template-columns"], "50px 25.5%"); 340 | 341 | output = await process( 342 | `div { 343 | grid-kiss: 344 | "+----------------+ +-----+" 345 | "| foobar | | baz |" 346 | "+----------------+ +100px+" 347 | "+-------+ +-20% -+ +-----+" 348 | "| bar | | foo | | qux |" 349 | "+ > 4em + +------+ +-----+" 350 | }`, { optimize: false }) 351 | 352 | t.is(output["div"]["grid-template-columns"], "minmax(4em, auto) 20% 100px"); 353 | 354 | output = await process( 355 | `div { 356 | grid-kiss: 357 | "+-------------+ +-----+" 358 | "| .bigzone | | |" 359 | "+-------------+ +-----+" 360 | "+-----+ +-------------+" 361 | "| | | .bigzone2 |" 362 | "+-----+ +-------------+" 363 | "|20% | |66.7%| |13.3%|" 364 | }`, { optimize: false }) 365 | 366 | t.is(output["div"]["grid-template-columns"], "20% 66.7% 13.3%"); 367 | 368 | output = await process( 369 | `div { 370 | grid-kiss: 371 | "+-------------+ +-20%-+" 372 | "| .bigzone | | |" 373 | "+-------------+ +-----+" 374 | "+-----+ +-------------+" 375 | "| | | .bigzone2 |" 376 | "+-20%-+ +-------------+" 377 | " | 60% | " 378 | }`, { optimize: false }) 379 | 380 | t.is(output["div"]["grid-template-columns"], "20% 60% 20%"); 381 | 382 | }); 383 | 384 | test('grid template areas', async t => { 385 | let output = await process( 386 | `div { 387 | grid-kiss: 388 | "+------+ +------+ " 389 | "| | | bar | " 390 | "| | +------+ " 391 | "| baz | " 392 | "| | +------+ " 393 | "| | | foo | 50% free" 394 | "+------+ +------+ " 395 | " " 396 | "+------+ +------+ " 397 | "| bar | | foo | > 20fr" 398 | "+------+ +------+ " 399 | }`, { optimize: false }) 400 | 401 | t.is(output["div"]["grid-template-areas"], `\n\t\t"baz bar"\n\t\t"baz foo"\n\t\t"bar foo"`); 402 | t.is(output["div > bar"]["grid-area"], "bar"); 403 | t.is(output["div > baz"]["grid-area"], "baz"); 404 | t.is(output["div > foo"]["grid-area"], "foo"); 405 | 406 | output = await process( 407 | `div { 408 | grid-kiss: 409 | "+----------------+ +-----+" 410 | "|foo#bar.baz[qux]| | baz |" 411 | "+----------------+ +100px+" 412 | "+------+ +-20% -+ +-----+" 413 | "| .bar | | #foo | | qux |" 414 | "+ > 4em+ +------+ +-----+" 415 | }`, { optimize: false }) 416 | 417 | t.is(output["div"]["grid-template-areas"], 418 | `\n\t\t"foo_bar_baz_qux foo_bar_baz_qux baz"\n\t\t"bar foo qux"`); 419 | t.is(output["div > .bar"]["grid-area"], "bar"); 420 | t.is(output["div > baz"]["grid-area"], "baz"); 421 | t.is(output["div > #foo"]["grid-area"], "foo"); 422 | t.is(output["div > qux"]["grid-area"], "qux"); 423 | t.is(output["div > foo#bar.baz[qux]"]["grid-area"], "foo_bar_baz_qux"); 424 | 425 | }); 426 | 427 | test('zone justify-self', async t => { 428 | let output = await process( 429 | `div { 430 | grid-kiss: 431 | "+-----------+ +------------+ " 432 | "| | | ^ | " 433 | "| | | bar -> | " 434 | "| v | +------------+ " 435 | "| baz <-- | " 436 | "| ^ | +------------+ " 437 | "| | | | " 438 | "+-----------+ | | " 439 | " | → foo ← | " 440 | "+-----------+ | | " 441 | "| < qux > | | | " 442 | "| v | | | " 443 | "+-----------+ +------------+ " 444 | }`); 445 | 446 | t.is(output["div > baz"]["justify-self"], "start"); 447 | t.is(output["div > bar"]["justify-self"], "end"); 448 | t.is(output["div > qux"]["justify-self"], "stretch"); 449 | t.is(output["div > foo"]["justify-self"], "center"); 450 | 451 | }); 452 | 453 | test('zone align-self', async t => { 454 | let output = await process( 455 | `div { 456 | grid-kiss: 457 | "+------+ +------+ " 458 | "| | | ^ | " 459 | "| | | bar >| " 460 | "| v | +------+ " 461 | "| baz | " 462 | "| ^ | +------+ " 463 | "| | | ^ | 50% free" 464 | "+------+ | | " 465 | " | foo | " 466 | "+------+ | | " 467 | "| < qux| | v | > 20fr" 468 | "| v | | | " 469 | "+------+ +------+ " 470 | }`); 471 | 472 | t.is(output["div > baz"]["align-self"], "center"); 473 | t.is(output["div > bar"]["align-self"], "start"); 474 | t.is(output["div > qux"]["align-self"], "end"); 475 | t.is(output["div > foo"]["align-self"], "stretch"); 476 | 477 | }); 478 | 479 | test('gaps', async t => { 480 | let output = await process( 481 | `div { 482 | grid-kiss: 483 | "+--------------------+ +-----+" 484 | "| .bigzone | |.foo |" 485 | "+--------------------+ +-----+" 486 | "+-----+ +--------------------+" 487 | "|.bar | | .bigzone2 |" 488 | "+-----+ +--------------------+" 489 | "| 20% | 10px | min | auto | 10% |" 490 | }`, { optimize: false }); 491 | 492 | t.is(output["div"]["grid-template-columns"], "20% 10px min-content 1fr 10%"); 493 | 494 | output = await process( 495 | `div { 496 | grid-kiss: 497 | "+------+ +------+ " 498 | "| | | ^ | " 499 | "| | | bar >| 1 " 500 | "| v | +------+ " 501 | "| baz | 2 " 502 | "| ^ | +------+ " 503 | "| | | ^ | 3 " 504 | "+------+ | | " 505 | " | foo | 4 " 506 | "+------+ | | " 507 | "| < qux| | v | 5 " 508 | "| v | | | " 509 | "+------+ +------+ " 510 | }`, { optimize: false }); 511 | t.is(output["div"]["grid-template-rows"], "1fr 2fr 3fr 4fr 5fr"); 512 | 513 | output = await process( 514 | `body { 515 | grid-kiss: 516 | "+-----+ +-----+ +-----+100px " 517 | "| .nw | | .n | | .ne | " 518 | "+-----+ +-----+ +-----+ ----" 519 | " 50px" 520 | "+-----+ +-----+ +-----+ ----" 521 | "| .w | | | | .e | 100px" 522 | "+-----+ +-----+ +-----+ " 523 | " 50px " 524 | "+-----+ +-----+ +-----+ ----" 525 | "| .sw | | .s | | .se | " 526 | "+-----+ +-----+ +-----+ 100px" 527 | "| 100px50px |100px| 50px100px " 528 | }`, { optimize: false }); 529 | 530 | t.is(output["body"]["grid-template-columns"], "100px 50px 100px 50px 100px"); 531 | t.is(output["body"]["grid-template-rows"], "100px 50px 100px 50px 100px"); 532 | t.is(output["body"]["grid-template-areas"], 533 | `\n\t\t"nw ... n ... ne "\n\t\t"... ... ... ... ..."\n\t\t"w ... ... ... e "` 534 | + `\n\t\t"... ... ... ... ..."\n\t\t"sw ... s ... se "`); 535 | }) 536 | 537 | test('other ascii formats: simple segments', async t => { 538 | let output = await process( 539 | `div { 540 | grid-kiss: 541 | "┌──────┐ ┌──────┐ " 542 | "│ │ │ bar →│ 200px" 543 | "│ ↓ │ └──────┘ " 544 | "│ baz │ - " 545 | "│ ↑ │ ┌──────┐ " 546 | "│ │ │ ↑ │ max" 547 | "└──────┘ │ │ " 548 | " │ foo │ - " 549 | "┌──────┐ │ │ " 550 | "│ ← qux│ │ ↓ │ 200px" 551 | "│ ↓ │ │ │ " 552 | "└─20em─┘ └──────┘ " 553 | }`, { optimize: false }); 554 | 555 | t.deepEqual(output["div > baz"], { 556 | "grid-area": "baz", 557 | "align-self": "center" 558 | }) 559 | t.deepEqual(output["div > bar"], { 560 | "grid-area": "bar", 561 | "justify-self": "end" 562 | }) 563 | t.deepEqual(output["div > foo"], { 564 | "grid-area": "foo", 565 | "align-self": "stretch" 566 | }) 567 | t.deepEqual(output["div > qux"], { 568 | "grid-area": "qux", 569 | "justify-self": "start", 570 | "align-self": "end" 571 | }) 572 | t.deepEqual(output["div"], { 573 | "display": "grid", 574 | "align-content": "stretch", 575 | "justify-content": "space-between", 576 | "grid-template-rows": "200px max-content 200px", 577 | "grid-template-columns": "20em 1fr", 578 | "grid-template-areas": '\n\t\t"baz bar"\n\t\t"baz foo"\n\t\t"qux foo"' 579 | }) 580 | }); 581 | 582 | test('other ascii formats: double segments', async t => { 583 | let output = await process( 584 | `main { 585 | grid-kiss: 586 | "╔═══════╗ ╔════════════════╗ " 587 | "║ ║ ║ .article ║ " 588 | "║ ║ ╚════════════════╝ " 589 | "║ nav ║ ╔════╗ ╔════════╗ " 590 | "║ ║ ║ ║ ║ aside ║ 320px" 591 | "╚═200px═╝ ╚════╝ ╚════════╝ " 592 | }`, { optimize: false }); 593 | 594 | t.deepEqual(output["main > nav"], { 595 | "grid-area": "nav" 596 | }) 597 | t.deepEqual(output["main > .article"], { 598 | "grid-area": "article" 599 | }) 600 | t.deepEqual(output["main > aside"], { 601 | "grid-area": "aside" 602 | }) 603 | t.deepEqual(output["main"], { 604 | "display": "grid", 605 | "align-content": "stretch", 606 | "justify-content": "space-between", 607 | "grid-template-rows": "1fr 320px", 608 | "grid-template-columns": "200px 1fr 1fr", 609 | "grid-template-areas": '\n\t\t"nav article article"\n\t\t"nav ... aside "' 610 | }) 611 | }); 612 | 613 | test('fallback properties with mixed relative/fixed', async t => { 614 | let output = await process( 615 | `body { 616 | grid-kiss: 617 | "+------------------------------+ " 618 | "| header ↑ | 120px" 619 | "+------------------------------+ " 620 | " 1em " 621 | "+--150px---+ +--- auto ----+ " 622 | "| .sidebar | | main | auto " 623 | "+----------+ +-------------+ " 624 | " 2em " 625 | "+------------------------------+ " 626 | "| ↓ | " 627 | "| → footer ← | 100px" 628 | "+------------------------------+ " 629 | " | 4vw | " 630 | }`, { fallback: true }); 631 | 632 | t.is("supports" in output, true); 633 | t.is(output["supports"].params, 'not (grid-template-areas:"test")'); 634 | 635 | t.deepEqual(output["supports"]["body"], { 636 | "position": "relative", 637 | "display": "block", 638 | "width": "100%", 639 | "height": "100%" 640 | }) 641 | 642 | t.deepEqual(output["supports"]["body > *"], { 643 | "position": "absolute", 644 | "box-sizing": "border-box", 645 | }) 646 | 647 | t.deepEqual(output["supports"]["body > header"], { 648 | "top": "0", 649 | "max-height": "120px", 650 | "left": "0", 651 | "width": "100%" 652 | }) 653 | 654 | t.deepEqual(output["supports"]["body > .sidebar"], { 655 | "top": "calc(120px + 1em)", 656 | "height": "calc(100% - 220px - 3em)", 657 | "left": "0", 658 | "width": "150px" 659 | }) 660 | 661 | t.deepEqual(output["supports"]["body > main"], { 662 | "top": "calc(120px + 1em)", 663 | "height": "calc(100% - 220px - 3em)", 664 | "left": "calc(150px + 4vw)", 665 | "width": "calc(100% - 150px - 4vw)" 666 | }) 667 | 668 | t.deepEqual(output["supports"]["body > footer"], { 669 | "bottom": "0", 670 | "max-height": "100px", 671 | "left": "50%", 672 | "max-width": "100%", 673 | "transform": "translateX(-50%)" 674 | }) 675 | 676 | }) 677 | 678 | test('fallback properties with all fixed', async t => { 679 | let output = await process( 680 | `body { 681 | grid-kiss: 682 | "┌──────┐ ┌────────────────┐ " 683 | "│ │ │ │ 100px " 684 | "│ ↑ │ │ < .bar │ " 685 | "│ .baz │ └────────────────┘ - " 686 | "│ ↓ │ ┌───────┐ ┌──────┐ " 687 | "│ │ | | │ │ 100px " 688 | "└──────┘ └───────┘ │ ↓ │ " 689 | "┌────────────────┐ │ .foo │ - " 690 | "│ .qux │ │ ↑ │ " 691 | "│ > < │ │ │ 100px " 692 | "└────────────────┘ └──────┘ " 693 | " 100px | 100px | 100px " 694 | ; 695 | }`, { browsers: ["ie 11"] }); 696 | 697 | t.is("supports" in output, true); 698 | t.is(output["supports"].params, 'not (grid-template-areas:"test")'); 699 | t.is("media" in output, true); 700 | t.is(output["media"].params, 'screen and (min-width:0\\0)'); 701 | 702 | t.deepEqual(output["supports"]["body"], { 703 | "position": "relative", 704 | "display": "block", 705 | "width": "300px", 706 | "height": "300px" 707 | }) 708 | 709 | t.deepEqual(output["supports"]["body > *"], { 710 | "position": "absolute", 711 | "box-sizing": "border-box", 712 | }) 713 | 714 | t.deepEqual(output["supports"]["body > .baz"], { 715 | "top": "0", 716 | "height": "200px", 717 | "left": "0", 718 | "width": "100px" 719 | }) 720 | 721 | t.deepEqual(output["supports"]["body > .bar"], { 722 | "top": "0", 723 | "height": "100px", 724 | "left": "100px", 725 | "max-width": "200px" 726 | }) 727 | 728 | t.deepEqual(output["supports"]["body > .qux"], { 729 | "top": "200px", 730 | "height": "100px", 731 | "left": "100px", 732 | "max-width": "200px", 733 | "transform": "translateX(-50%)" 734 | }) 735 | 736 | t.deepEqual(output["supports"]["body > .foo"], { 737 | "top": "200px", 738 | "max-height": "200px", 739 | "left": "200px", 740 | "transform": "translateY(-50%)", 741 | "width": "100px" 742 | }) 743 | 744 | }) 745 | 746 | test('fallback properties with all relative', async t => { 747 | let output = await process( 748 | `body { 749 | grid-kiss: 750 | "╔═10═╗ ╔═10═╗ " 751 | "║ .a>║ ║<.b ║ 3fr" 752 | "╚════╝ ╚════╝ " 753 | " ╔═20═╗ ╔═20═╗ " 754 | " ║ .c ║ ║ .d ║ 5fr" 755 | " ╚════╝ ╚════╝ " 756 | " ╔═30═╗ " 757 | " ║ .e ║ 7fr" 758 | " ╚════╝ " 759 | ; 760 | }`, { browsers: ["chrome 50"], optimize: false }); 761 | 762 | t.is("supports" in output, true); 763 | t.is(output["supports"].params, 'not (grid-template-areas:"test")'); 764 | t.is("media" in output, false); 765 | 766 | t.deepEqual(output["supports"]["body"], { 767 | "position": "relative", 768 | "display": "block", 769 | "width": "100%", 770 | "height": "100%" 771 | }) 772 | 773 | t.deepEqual(output["supports"]["body > *"], { 774 | "position": "absolute", 775 | "box-sizing": "border-box", 776 | }) 777 | 778 | t.deepEqual(output["supports"]["body > .a"], { 779 | "top": "0", 780 | "height": "20%", 781 | "right": "88.88889%", 782 | "max-width": "11.11111%", 783 | }) 784 | 785 | t.deepEqual(output["supports"]["body > .b"], { 786 | "top": "0", 787 | "height": "20%", 788 | "left": "88.88889%", 789 | "max-width": "11.11111%", 790 | }) 791 | 792 | t.deepEqual(output["supports"]["body > .c"], { 793 | "top": "20%", 794 | "height": "33.33333%", 795 | "left": "11.11111%", 796 | "width": "22.22222%", 797 | }) 798 | 799 | t.deepEqual(output["supports"]["body > .d"], { 800 | "top": "20%", 801 | "height": "33.33333%", 802 | "left": "66.66667%", 803 | "width": "22.22222%", 804 | }) 805 | 806 | t.deepEqual(output["supports"]["body > .e"], { 807 | "top": "53.33333%", 808 | "height": "46.66667%", 809 | "left": "33.33333%", 810 | "width": "33.33333%", 811 | }) 812 | 813 | }) 814 | 815 | test("optimize option", async t => { 816 | let output = await process( 817 | `div { 818 | grid-kiss: 819 | "+----------------+ +-----+" 820 | "|foo#bar.baz[qux]| | baz |" 821 | "+----------------+ +100px+" 822 | "+------+ +-20% -+ +-----+" 823 | "| .bar | | #foo | | qux |" 824 | "+ > 4em+ +------+ +-----+" 825 | }`, { optimize: true }) 826 | 827 | t.is(output["div"]["grid-template"], `"a a b" 1fr "c d e" 1fr / minmax(4em, auto) 20% 100px`); 828 | t.is(output["div > .bar"]["grid-area"], "c"); 829 | t.is(output["div > baz"]["grid-area"], "b"); 830 | t.is(output["div > #foo"]["grid-area"], "d"); 831 | t.is(output["div > qux"]["grid-area"], "e"); 832 | t.is(output["div > foo#bar.baz[qux]"]["grid-area"], "a"); 833 | }) 834 | 835 | 836 | test("advanced selectors", async t => { 837 | 838 | let output = await process( 839 | `div { 840 | grid-kiss: 841 | "+-------+" 842 | "| :1 |" 843 | "+-------+" 844 | " " 845 | "+-------+" 846 | "| p:2 |" 847 | "+-------+" 848 | " " 849 | "+-------+" 850 | "| Hello |" 851 | "+-------+" 852 | }`, { 853 | selectorParser: function (selector) { 854 | if (/[A-Z]/.test(selector[0])) { 855 | return `[data-component-name='${selector}']` 856 | } else return selector 857 | } 858 | } 859 | ); 860 | 861 | t.is("div > *:nth-child(1)" in output, true) 862 | t.is("div > p:nth-of-type(2)" in output, true) 863 | t.is("div > [data-component-name='Hello']" in output, true) 864 | 865 | }) 866 | 867 | test("css vars", async t => { 868 | let output = await process( 869 | `div { 870 | grid-kiss: 871 | "+-------------+ +--------------+" 872 | "| foo | | baz | var(--fooh)" 873 | "+-------------+ +--------------+" 874 | "+-------------+ +-var(--quxw) -+" 875 | "| bar | | qux |" 876 | "+-------------+ +--------------+" 877 | "| var(--barw) | | |" 878 | }`, { optimize: false }) 879 | 880 | t.is(output["div"]["grid-template-rows"], `var(--fooh) 1fr`) 881 | t.is(output["div"]["grid-template-columns"], `var(--barw) var(--quxw)`) 882 | }) 883 | 884 | test("should be able to parse inline grid declarations", async t => { 885 | let output = await process(`div { grid-kiss: "+--------------------------+ -- " "| header | 48px " "+--------------------------+ -- " "+--------+ +---------------+ -- " "| aside | | main | auto " "+--------+ +---------------+ -- " "| 48px | | auto | " ; }`); 886 | t.is("div > header" in output, true) 887 | t.is("div > aside" in output, true) 888 | t.is("div > main" in output, true) 889 | t.is(output["div"]["grid-template"], `"a a" 48px "b c " 1fr / 48px 1fr`) 890 | }) 891 | 892 | test("alternative property name", async t => { 893 | let output = await process( 894 | `div { 895 | grid-template-kiss: 896 | "+-------------+ +--------------+" 897 | "| foo | | baz |" 898 | "+-------------+ +--------------+" 899 | "+-------------+ +--------------+" 900 | "| bar | | qux |" 901 | "+-------------+ +--------------+" 902 | }`, { optimize: false }) 903 | 904 | t.is(output["div"]["grid-template-areas"], `\n\t"foo baz"\n\t"bar qux"`) 905 | }) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grid-kiss: Keep CSS Grids simple, stupid 2 | 3 | This is a [PostCSS][postcss-website] plugin aiming to replace the 24 new properties brought by [CSS Grids][w3c-spec] with a single one that you immediately understand when you see it. 4 | 5 |

6 | Downloads 7 | Version 8 | Build Status 9 | License 10 | Discuss about this project on gitter 11 |

12 | 13 | ## Table of contents 14 | 15 | * [Examples](#examples) 16 | * [Installation](#installation) 17 | * [Usage](#usage) 18 | * [Fallback](#fallback-for-older-browsers) 19 | * [Options](#options) 20 | * [Alternative styles](#alternative-styles) 21 | * [Documentation](#documentation) 22 | - [How to draw a grid](#how-to-draw-a-grid) 23 | - [Values accepted for selectors](#values-accepted-for-selectors) 24 | - [Dimensions of rows](#dimensions-of-rows) 25 | - [Dimensions of columns](#dimensions-of-columns) 26 | - [Dimensions of gaps](#dimensions-of-gaps) 27 | - [Values accepted for dimensions](#values-accepted-for-dimensions) 28 | - [Horizontal alignment of the grid](#horizontal-alignment-of-the-grid) 29 | - [Vertical alignment of the grid](#vertical-alignment-of-the-grid) 30 | - [Horizontal alignment inside a zone](#horizontal-alignment-inside-a-zone) 31 | - [Vertical alignment inside a zone](#vertical-alignment-inside-a-zone) 32 | 33 | ## Examples 34 | 35 | ### [Try it online][playground] 36 | 37 | Try the different examples and play with the plugin on the [playground][playground]. Edit the CSS and HTML on the left and the grid will be updated instantly. 38 | 39 | ### Basic website layout 40 | 41 | ```css 42 | body { 43 | grid-kiss: 44 | "+-------------------------------+ " 45 | "| header ↑ | 120px" 46 | "+-------------------------------+ " 47 | " " 48 | "+-- 30% ---+ +--- auto --------+ " 49 | "| .sidebar | | main | auto " 50 | "+----------+ +-----------------+ " 51 | " " 52 | "+-------------------------------+ " 53 | "| ↓ | 60px " 54 | "| → footer ← | " 55 | "+-------------------------------+ " 56 | } 57 | ``` 58 | 59 | is converted to: 60 | 61 | ```css 62 | body > header { 63 | grid-area: header; 64 | align-self: start; 65 | } 66 | 67 | body > .sidebar { 68 | grid-area: sidebar; 69 | } 70 | 71 | body > main { 72 | grid-area: main; 73 | } 74 | 75 | body > footer { 76 | grid-area: footer; 77 | justify-self: center; 78 | align-self: end; 79 | } 80 | 81 | body { 82 | display: grid; 83 | align-content: space-between; 84 | grid-template-rows: 120px 1fr 60px; 85 | grid-template-columns: 30% 1fr; 86 | grid-template-areas: 87 | "header header" 88 | "sidebar main " 89 | "footer footer"; 90 | } 91 | ``` 92 | 93 | which displays this kind of grid layout: 94 | 95 | ![example-result](https://cloud.githubusercontent.com/assets/566536/23096165/41d569d4-f617-11e6-92b3-532b20e750c8.png) 96 | 97 | ### Responsive layouts 98 | 99 | Use different `grid-kiss` declarations in media queries to easily get responsive layouts. It is recommended to start by the grid on small screens, then use media queries to progressively enhance your layouts on wider screens. 100 | 101 | ![responsive-layout](https://cloud.githubusercontent.com/assets/566536/23096187/4217359e-f617-11e6-8917-4edb017c3cda.png) 102 | 103 | ## Installation 104 | 105 | - with [npm](https://www.npmjs.com/) 106 | 107 | ```bash 108 | npm install postcss-grid-kiss --save-dev 109 | ``` 110 | 111 | - with [yarn](https://yarnpkg.com/) 112 | 113 | ```bash 114 | yarn add postcss-grid-kiss --dev 115 | ``` 116 | 117 | ## Usage 118 | 119 | If you never used PostCSS before, read [PostCSS usage documentation](https://github.com/postcss/postcss#usage) first. 120 | 121 | - with command line interface : 122 | 123 | ```bash 124 | postcss src/your.css --output dist/compiled.css --use postcss-grid-kiss 125 | ``` 126 | 127 | - with Node: 128 | 129 | ```js 130 | const postcss = require('postcss'), 131 | gridkiss = require('postcss-grid-kiss'); 132 | 133 | postcss([ gridkiss ]) 134 | .process(css, { from: 'src/your.css', to: 'compiled.css' }) 135 | .then(function (result) { 136 | fs.writeFileSync('compiled.css', result.css); 137 | if( result.map ) fs.writeFileSync('compiled.css.map', result.map); 138 | }); 139 | ``` 140 | 141 | Read PostCSS documentation to make it work with Webpack, Gulp or your other build system. 142 | 143 | ## Fallback for older browsers 144 | 145 | [CSS Grid Layout][w3c-spec] is a W3C Candidate Recommandation supported in all the evergreen browsers. It is available in Chrome 57, Firefox 52, Safari 10.1, Edge 16 and Opera 44. It is also supported on mobile iOS Safari and Chrome for Android. See [Can I Use][can-i-use] for more information on browser support. 146 | 147 | For browsers not supporting CSS Grid Layout, Grid-kiss proposes a *fallback* that use absolute positionning and `calc()` operator. It uses a `@supports` query to only apply on non-supported browsers, and does not involve JavaScript. 148 | 149 | **With this fallback, Grid-kiss layouts will work on any browser supporting `calc()`, which is like [95% of browsers](http://caniuse.com/#search=calc).** But you should note that a fallback based on absolute positionning has some limitations: 150 | 151 | - It is only a fallback for `grid-kiss` declarations. The reason this fallback works is because of the constraints designed by purpose for grid-kiss layouts. Other Grid Layout properties such as `grid-gap` are not covered by this fallback. 152 | - New dimensions properties defined in the Grid layout specification such as `min-content`, `max-content`, `minmax()`, `fit-content` also are not supported 153 | - Zones with `position: absolute` are out of the flow. This implies that the container will no longer resize based on the zones content. Grid-kiss tries to calculate the total size of the grid when possible. If one of the rows/columns dimensions is `auto` or a fraction of the remaining space (`fr`), the height/width is set to `100%`. 154 | - Grid-kiss adds the property `box-sizing: border-box` to each zone so that they don't overlap because of their padding or border size. If you don't already use this property, it may change a bit the zones dimensions. 155 | - The CSS output is significally bigger, between 2x and 3x in size depending on the targeted browsers 156 | 157 | Internet Explorer does not support `@supports` 🙄 , so Grid-kiss needs to add another media query hack that is known to run only on IE: `@media screen and (min-width:0\0)`. This extends support from **IE9 to IE11** at the cost of a bigger output size. If you don't care about Internet Explorer support and want to reduce the output size, you should omit IE in your [browserslist][browserslist]. 158 | 159 | By default, Grid-kiss is looking in your [browserslist][browserslist] config for the list of supported browsers and automatically deduce what fallbacks are needed for your project by using [Can I Use data][can-i-use]. You can override this automatic detection with the `fallback` option explained below. 160 | 161 | ## Options 162 | 163 | Grid-kiss comes with a few options: 164 | 165 | ```javascript 166 | postcss([ gridkiss({ ...options }) ]) 167 | ``` 168 | 169 | ### `fallback` : add fallback for browsers not supporting CSS Grid Layout 170 | 171 | **Note: it is recommended to use automatic detection through browserslist instead of using this option. See [Fallback](#fallback-for-older-browsers) section.** 172 | 173 | If this option is provided, it overrides automatic detection and tells explicitely whether to add or not the fallback styles to the output. 174 | 175 | ```javascript 176 | postcss([ gridkiss({ fallback: true }) ]) // always add all fallbacks 177 | postcss([ gridkiss({ fallback: false }) ]) // never add any fallback 178 | ``` 179 | 180 | ### `optimize` - reduce output size 181 | 182 | This option *(enabled by default)* reduces the size of the output while keeping it readable. It does so by merging grid properties and renaming zone identifiers. For complete minification, use it with [cssnano](http://cssnano.co/). 183 | 184 | Set this option to `false` if you prefer a more verbose and descriptive output. Try to toggle the option in the [playground][playground] to compare the outputs. 185 | 186 | ```javascript 187 | postcss([ gridkiss({ optimize: false }) ]) 188 | ``` 189 | 190 | ### `selectorParser` - apply custom transforms to zone selectors 191 | 192 | This option receives a function that is applied on the selectors you wrote in the zones. This is useful to add your own transforms or selector syntax, for example to use component names in a component-based framework like Vue or React. 193 | 194 | ```javascript 195 | postcss([ 196 | gridkiss({ 197 | selectorParser: function (selector) { 198 | if (/[A-Z]/.test(selector[0])) { 199 | return `[data-component-name='${selector}']` 200 | } 201 | return selector 202 | } 203 | }) 204 | ]) 205 | ``` 206 | 207 | ## Alternative styles 208 | 209 | These alternative styles for zone syntax are also supported : 210 | 211 | - `┌ ┐ └ ┘` for corners and `│ ─` for segments 212 | 213 | ```css 214 | div { 215 | grid-kiss: 216 | "┌──────┐ ┌──────┐ " 217 | "│ │ │ ↑ │ " 218 | "│ │ │ bar →│ 200px " 219 | "│ ↓ │ └──────┘ " 220 | "│ baz │ - " 221 | "│ ↑ │ ┌──────┐ " 222 | "│ │ │ ↑ │ 200px " 223 | "└──────┘ │ │ " 224 | " │ foo │ - " 225 | "┌──────┐ │ │ " 226 | "│ qux │ │ ↓ │ 200px " 227 | "│ ↓ │ │ │ " 228 | "└─20em─┘ └──────┘ " 229 | } 230 | ``` 231 | 232 | - `╔ ╗ ╚ ╝` for corners and `║ ═` for segments 233 | 234 | ```css 235 | main { 236 | grid-kiss: 237 | "╔═══════╗ ╔════════════════╗ " 238 | "║ ║ ║ .article ║ auto " 239 | "║ ↑ ║ ╚════════════════╝ " 240 | "║ nav ║ ╔════╗ ╔════════╗ " 241 | "║ ║ ║ ║ ║ aside →║ 240px" 242 | "╚═ 25% ═╝ ╚════╝ ╚═ 80em ═╝ " 243 | } 244 | ``` 245 | 246 | ## Documentation 247 | 248 | ### How to draw a grid 249 | 250 | - Draw the different zones of your grid as shown in the example. You can use some tools like [AsciiFlow](http://asciiflow.com/). 251 | - Inside every zone, write a selector that matches the corresponding element. See [Values accepted for selectors](#values-accepted-for-selectors) 252 | - The elements matched have to be **direct descendants** of the grid element 253 | - Separate each row by a newline (`\n`) and give the same indentation level to every row 254 | - Make sure each row starts and end by a double quote `"` 255 | - Make sure the zone corners (`+`) are correctly aligned. Every index in the rows where a corner character is found creates a new column. 256 | - Do not hesitate to make large zones with unused space, it may be useful for future modifications 257 | - Use Insert. key and Multi-cursor if supported by your editor to draw and edit your grids easily 258 | 259 | ### Values accepted for selectors 260 | 261 | Inside each zone, you can write a selector to associate a zone to a DOM element. It can be a `tag` name, a `.class`, an `#id`, or `any.other[valid]#selector`. 262 | 263 | Since v1.2.0, selectors in zones may use some shortened notations specific to grid-kiss, although using a class is still the recommended method. 264 | 265 | - `:1` ⇒ `*:nth-child(1)` 266 | - `button:2` ⇒ `button:nth-of-type(2)` 267 | 268 | Since v1.4.0, you can also apply custom transforms and make your own syntax with the `selectorParser` [option](#options) 269 | 270 | ### Dimensions of rows 271 | 272 | Declare the size of a row by writing the dimension **just after the last column of the grid** 273 | 274 | ``` 275 | +------+ +------+ --- 276 | | ^ | | .bar | 40em 277 | | | +------+ --- 278 | | .baz | 279 | | | +------+ --- 280 | | v | | ^ | 38em 281 | +------+ | | --- 282 | | .foo | 283 | +------+ | | --- 284 | | .qux | | v | 40em 285 | +------+ +------+ --- 286 | ``` 287 | 288 | The `-` separators between dimensions are not mandatory, they are only here to make the grid more readable. 289 | 290 | ### Dimensions of columns 291 | 292 | Declare the size of a column by writing the dimension **inside the top or bottom border of a zone**: 293 | 294 | ``` 295 | +-- 640px --+ +----------+ 296 | | selector | or | selector | 297 | +-----------+ +---30%----+ 298 | ``` 299 | 300 | You cannot set the width of a zone occupying more than one column. This would imply some calculations that may or may not have a solution. As an alternative, you can declare the size of a column **just after the last row of the grid**: 301 | 302 | ``` 303 | +-------------+ +-----+ +-------------+ +-20%-+ 304 | | .bigzone | | | | .bigzone | | | 305 | +-------------+ +-----+ +-------------+ +-----+ 306 | +-----+ +-------------+ or +-----+ +-------------+ 307 | | | | .bigzone2 | | | | .bigzone2 | 308 | +-----+ +-------------+ +-20%-+ +-------------+ 309 | | 20% | | 60% | | 20% | | 60% | 310 | ``` 311 | 312 | The `|` separators between dimensions are not mandatory, they are only here to make the grid more readable. 313 | 314 | ### Dimensions of gaps 315 | 316 | You can also declare the dimension of spacing between zones the same way you do with rows and columns. These spaces are called _gaps_ and act like empty zones. The example below defines gaps of _50px_. 317 | 318 | ``` 319 | +-----+ +-----+ +-----+ ---- 320 | | .nw | | .n | | .ne | 100px 321 | +-----+ +-----+ +-----+ ---- 322 | 50px 323 | +-----+ +-----+ +-----+ ---- 324 | | .w | | | | .e | 100px 325 | +-----+ +-----+ +-----+ ---- 326 | 50px 327 | +-----+ +-----+ +-----+ ---- 328 | | .sw | | .s | | .se | 100px 329 | +-----+ +-----+ +-----+ ---- 330 | |100px| 50px |100px| 50px |100px| 331 | ``` 332 | 333 | ### Values accepted for dimensions 334 | 335 | Dimensions can be any of the specified values: 336 | 337 | - a non-negative length. 338 | - `15px` 339 | - `4rem` 340 | 341 | - a non-negative percentage value, optionally with a context keyword 342 | - `20%` 343 | - `25% free` ⇒ `25fr` 344 | - `30% grid` ⇒ `30%` 345 | - `5% view` ⇒ `5vw` or `5vh` depending on the direction 346 | 347 | - a non-negative number representing a fraction of the free space in the grid container. 348 | - `5` ⇒ `5fr` 349 | 350 | - `max` or `max-content`: a keyword representing the largest maximal content contribution of the grid items occupying the grid track 351 | 352 | - `min` or `min-content`: a keyword representing the largest minimal content contribution of the grid items occupying the grid track 353 | 354 | - a range between a minimum and a maximum or `minmax(min, max)` 355 | - `100px - 200px` ⇒ `minmax(100px, 200px)` 356 | 357 | - `> *length*` or `< *length*`: a minimum or maximum value 358 | - `> 100px` ⇒ `minmax(100px, auto)` 359 | - `< 50%` ⇒ `minmax(auto, 50%)` 360 | 361 | - `fit *length*` or `fit-content(*length*)`: a keyword representing the formula min(max-content, max(auto, *length*)), which is calculated similar to auto (i.e. minmax(auto, max-content)), except that the track size is clamped at argument *length* if it is greater than the auto minimum. 362 | - `fit 100px` ⇒ `fit-content(100px)` 363 | 364 | - `calc( expr )` : an expression using native [calc()](https://developer.mozilla.org/en-US/docs/Web/CSS/calc) CSS function 365 | 366 | - `var(--name)` : a [CSS variable](https://developer.mozilla.org/en-US/docs/Web/CSS/var) interpolation 367 | 368 | - `auto`: a keyword representing one part of the remaining free space, i.e. `1fr`. When used as a maximum value, it is equal to `max-content`. When used as a minimum value, it it is equal to `min-content`. 369 | 370 | When no value is specified, row and column sizes are set as `auto`. 371 | 372 | Since v2.5.0, you can also apply custom transforms and make your own syntax with the `dimensionParser` [option](#options) 373 | 374 | ### Horizontal alignment of the grid 375 | 376 | Specifies how all the zones are aligned horizontally inside the grid container. Irrelevant if one of the zones fits all the remaining free space. 377 | 378 | - `justify-content: stretch` 379 | when there are no two consecutive spaces at the beginning or the end of the rows 380 | 381 | ``` 382 | "+---+ +---+ +---+" 383 | "| a | | b | | c |" 384 | "+---+ +---+ +---+" 385 | "+---+ +---+ +---+" 386 | "| d | | e | | f |" 387 | "+---+ +---+ +---+" 388 | "+---+ +---+ +---+" 389 | "| g | | h | | i |" 390 | "+---+ +---+ +---+" 391 | ``` 392 | 393 | ![grid-justify-content-stretch](https://cloud.githubusercontent.com/assets/566536/23096183/4211e616-f617-11e6-9819-701ef3958093.png) 394 | 395 | - `justify-content: start` 396 | when there are two consecutive spaces or more at the end of the rows 397 | 398 | ``` 399 | "+---+ +---+ +---+ " 400 | "| a | | b | | c | " 401 | "+---+ +---+ +---+ " 402 | "+---+ +---+ +---+ " 403 | "| d | | e | | f | " 404 | "+---+ +---+ +---+ " 405 | "+---+ +---+ +---+ " 406 | "| g | | h | | i | " 407 | "+---+ +---+ +---+ " 408 | ``` 409 | 410 | ![grid-justify-content-start](https://cloud.githubusercontent.com/assets/566536/23096182/4203ebd8-f617-11e6-8972-1ee145bb8359.png) 411 | 412 | - `justify-content: end` 413 | 414 | when there are two consecutive spaces or more at the beginning of the rows 415 | 416 | ``` 417 | " +---+ +---+ +---+" 418 | " | a | | b | | c |" 419 | " +---+ +---+ +---+" 420 | " +---+ +---+ +---+" 421 | " | d | | e | | f |" 422 | " +---+ +---+ +---+" 423 | " +---+ +---+ +---+" 424 | " | g | | h | | i |" 425 | " +---+ +---+ +---+" 426 | ``` 427 | 428 | ![grid-justify-content-end](https://cloud.githubusercontent.com/assets/566536/23096179/41fefe70-f617-11e6-9340-c53943440a44.png) 429 | 430 | - `justify-content: center` 431 | when there are two consecutive spaces or more at the beginning and the end of the rows 432 | 433 | ``` 434 | " +---+ +---+ +---+ " 435 | " | a | | b | | c | " 436 | " +---+ +---+ +---+ " 437 | " +---+ +---+ +---+ " 438 | " | d | | e | | f | " 439 | " +---+ +---+ +---+ " 440 | " +---+ +---+ +---+ " 441 | " | g | | h | | i | " 442 | " +---+ +---+ +---+ " 443 | ``` 444 | 445 | ![grid-justify-content-center](https://cloud.githubusercontent.com/assets/566536/23096177/41fe1078-f617-11e6-94b3-446296152dfc.png) 446 | 447 | - `justify-content: space-between` 448 | when there are two consecutive spaces or more between zones 449 | 450 | ``` 451 | "+---+ +---+ +---+" 452 | "| a | | b | | c |" 453 | "+---+ +---+ +---+" 454 | "+---+ +---+ +---+" 455 | "| d | | e | | f |" 456 | "+---+ +---+ +---+" 457 | "+---+ +---+ +---+" 458 | "| g | | h | | i |" 459 | "+---+ +---+ +---+" 460 | ``` 461 | 462 | ![grid-justify-content-space-between](https://cloud.githubusercontent.com/assets/566536/23096180/41ffe254-f617-11e6-8caf-2a4cc2ca467b.png) 463 | 464 | - `justify-content: space-evenly` 465 | when there are two consecutive spaces or more at the beginning and the end of the rows, and exactly two consecutive spaces between zones 466 | 467 | ``` 468 | " +---+ +---+ +---+ " 469 | " | a | | b | | c | " 470 | " +---+ +---+ +---+ " 471 | " +---+ +---+ +---+ " 472 | " | d | | e | | f | " 473 | " +---+ +---+ +---+ " 474 | " +---+ +---+ +---+ " 475 | " | g | | h | | i | " 476 | " +---+ +---+ +---+ " 477 | ``` 478 | 479 | ![grid-justify-content-space-evenly](https://cloud.githubusercontent.com/assets/566536/23096181/4201ba70-f617-11e6-8b9a-5f86ca80b423.png) 480 | 481 | - `justify-content: space-around` 482 | when there are two consecutive spaces or more at the beginning and the end of the rows, and four consecutive spaces or more between zones 483 | 484 | ``` 485 | " +---+ +---+ +---+ " 486 | " | a | | b | | c | " 487 | " +---+ +---+ +---+ " 488 | " +---+ +---+ +---+ " 489 | " | d | | e | | f | " 490 | " +---+ +---+ +---+ " 491 | " +---+ +---+ +---+ " 492 | " | g | | h | | i | " 493 | " +---+ +---+ +---+ " 494 | ``` 495 | 496 | ![grid-justify-content-space-around](https://cloud.githubusercontent.com/assets/566536/23096178/41febbea-f617-11e6-92aa-e68ef32e7d54.png) 497 | 498 | ### Vertical alignment of the grid 499 | 500 | Specifies how all the zones are aligned vertically inside the grid container. Irrelevant if one of the zones fits all the remaining free space. 501 | 502 | - `align content: stretch` 503 | when no space rows 504 | 505 | ``` 506 | "+---+ +---+ +---+" 507 | "| a | | b | | c |" 508 | "+---+ +---+ +---+" 509 | "+---+ +---+ +---+" 510 | "| d | | e | | f |" 511 | "+---+ +---+ +---+" 512 | "+---+ +---+ +---+" 513 | "| g | | h | | i |" 514 | "+---+ +---+ +---+" 515 | ``` 516 | 517 | ![grid-align-content-stretch](https://cloud.githubusercontent.com/assets/566536/23096172/41e9bc04-f617-11e6-9de4-a0906fa68a7e.png) 518 | 519 | - `align-content: start` 520 | when at least one space row at the end 521 | 522 | ``` 523 | "+---+ +---+ +---+" 524 | "| a | | b | | c |" 525 | "+---+ +---+ +---+" 526 | "+---+ +---+ +---+" 527 | "| d | | e | | f |" 528 | "+---+ +---+ +---+" 529 | "+---+ +---+ +---+" 530 | "| g | | h | | i |" 531 | "+---+ +---+ +---+" 532 | " " 533 | " " 534 | ``` 535 | 536 | ![grid-align-content-start](https://cloud.githubusercontent.com/assets/566536/23096171/41e983f6-f617-11e6-8e8c-89425ca2c76c.png) 537 | 538 | - `align-content: end` 539 | when at least one space row at the beginning 540 | 541 | ``` 542 | " " 543 | " " 544 | "+---+ +---+ +---+" 545 | "| a | | b | | c |" 546 | "+---+ +---+ +---+" 547 | "+---+ +---+ +---+" 548 | "| d | | e | | f |" 549 | "+---+ +---+ +---+" 550 | "+---+ +---+ +---+" 551 | "| g | | h | | i |" 552 | "+---+ +---+ +---+" 553 | ``` 554 | 555 | ![grid-align-content-end](https://cloud.githubusercontent.com/assets/566536/23096167/41d703e8-f617-11e6-928b-ef29645c132a.png) 556 | 557 | - `align-content: center` 558 | when at least one space row at the beginning and one space row at the end 559 | 560 | ``` 561 | " " 562 | "+---+ +---+ +---+" 563 | "| a | | b | | c |" 564 | "+---+ +---+ +---+" 565 | "+---+ +---+ +---+" 566 | "| d | | e | | f |" 567 | "+---+ +---+ +---+" 568 | "+---+ +---+ +---+" 569 | "| g | | h | | i |" 570 | "+---+ +---+ +---+" 571 | " " 572 | ``` 573 | 574 | ![grid-align-content-center](https://cloud.githubusercontent.com/assets/566536/23096166/41d67752-f617-11e6-96c7-61f8ba81f4a9.png) 575 | 576 | - `align-content: space-between` 577 | when there is one space row between zones 578 | 579 | ``` 580 | "+---+ +---+ +---+" 581 | "| a | | b | | c |" 582 | "+---+ +---+ +---+" 583 | " " 584 | "+---+ +---+ +---+" 585 | "| d | | e | | f |" 586 | "+---+ +---+ +---+" 587 | " " 588 | "+---+ +---+ +---+" 589 | "| g | | h | | i |" 590 | "+---+ +---+ +---+" 591 | ``` 592 | 593 | ![grid-align-content-space-between](https://cloud.githubusercontent.com/assets/566536/23096168/41d7ea74-f617-11e6-861a-963f87debf74.png) 594 | 595 | - `align-content: space-evenly` 596 | when there is one space row at the beginning, at the end and between zones 597 | 598 | ``` 599 | " " 600 | "+---+ +---+ +---+" 601 | "| a | | b | | c |" 602 | "+---+ +---+ +---+" 603 | " " 604 | "+---+ +---+ +---+" 605 | "| d | | e | | f |" 606 | "+---+ +---+ +---+" 607 | " " 608 | "+---+ +---+ +---+" 609 | "| g | | h | | i |" 610 | "+---+ +---+ +---+" 611 | " " 612 | ``` 613 | 614 | ![grid-align-content-space-evenly](https://cloud.githubusercontent.com/assets/566536/23096169/41d855cc-f617-11e6-883d-712654b4d4b8.png) 615 | 616 | - `align-content: space-around` 617 | when there is one space row at the beginning and at the end, and two space rows between zones 618 | 619 | ``` 620 | " " 621 | "+---+ +---+ +---+" 622 | "| a | | b | | c |" 623 | "+---+ +---+ +---+" 624 | " " 625 | " " 626 | "+---+ +---+ +---+" 627 | "| d | | e | | f |" 628 | "+---+ +---+ +---+" 629 | " " 630 | " " 631 | "+---+ +---+ +---+" 632 | "| g | | h | | i |" 633 | "+---+ +---+ +---+" 634 | " " 635 | ``` 636 | 637 | ![grid-align-content-space-around](https://cloud.githubusercontent.com/assets/566536/23096170/41dc894e-f617-11e6-836f-ec22738413fd.png) 638 | 639 | ### Horizontal alignment inside a zone 640 | 641 | Each zone can specify an alignment indicator. When no indicators are specified, defaults are stretch horizontally and vertically. 642 | 643 | - `justify-self: start` with `<` or `←` 644 | 645 | ``` 646 | +-------------+ +-------------+ 647 | | .item-a < | or | .item-a ← | 648 | +-------------+ +-------------+ 649 | ``` 650 | 651 | ![grid-justify-self-start](https://cloud.githubusercontent.com/assets/566536/23096186/4213332c-f617-11e6-9fb1-13e46b932364.png) 652 | 653 | - `justify-self: end` with `>` or `→` 654 | 655 | ``` 656 | +-------------+ +-------------+ 657 | | > .item-a | or | → .item-a | 658 | +-------------+ +-------------+ 659 | ``` 660 | 661 | ![grid-justify-self-end](https://cloud.githubusercontent.com/assets/566536/23096185/42121c8a-f617-11e6-830d-2be797b6c71a.png) 662 | 663 | - `justify-self: stretch` with `<` and `>` or `←` and `→` in this order 664 | 665 | ``` 666 | +--------------+ +--------------+ 667 | | < .item-a > | or | ← .item-a → | 668 | +--------------+ +--------------+ 669 | ``` 670 | 671 | ![grid-justify-self-stretch](https://cloud.githubusercontent.com/assets/566536/23096188/42182026-f617-11e6-9ee0-8f43f2065562.png) 672 | 673 | - `justify-self: center` with `>` and `<` or `→` and `←` in this order 674 | 675 | ``` 676 | +--------------+ +--------------+ 677 | | > .item-a < | or | → .item-a ← | 678 | +--------------+ +--------------+ 679 | ``` 680 | 681 | ![grid-justify-self-center](https://cloud.githubusercontent.com/assets/566536/23096184/4211f75a-f617-11e6-9f7c-0e2a5dc959e7.png) 682 | 683 | ### Vertical alignment inside a zone 684 | 685 | - `align-self: start` with `^` or `↑` 686 | 687 | ``` 688 | +-------------+ +-------------+ 689 | | .item-a | or | .item-a | 690 | | ^ | | ↑ | 691 | +-------------+ +-------------+ 692 | ``` 693 | 694 | ![grid-align-self-start](https://cloud.githubusercontent.com/assets/566536/23096175/41ecd68c-f617-11e6-91bb-37789cd16c32.png) 695 | 696 | - `align-self: end` with `v` or `↓` 697 | 698 | ``` 699 | +-------------+ +-------------+ 700 | | v | or | ↓ | 701 | | .item-a | | .item-a | 702 | +-------------+ +-------------+ 703 | ``` 704 | 705 | ![grid-align-self-end](https://cloud.githubusercontent.com/assets/566536/23096174/41ebf460-f617-11e6-9f6a-70c7ea8e4c1f.png) 706 | 707 | - `align-self: stretch` with `^` and `v` or `↑` and `↓` in this order 708 | 709 | ``` 710 | +-------------+ +-------------+ 711 | | ^ | | ↑ | 712 | | .item-a | or | .item-a | 713 | | v | | ↓ | 714 | +-------------+ +-------------+ 715 | ``` 716 | 717 | ![grid-align-self-stretch](https://cloud.githubusercontent.com/assets/566536/23096176/41f05fa0-f617-11e6-8841-f353256e0b3a.png) 718 | 719 | - `align-self: center` with `v` and `^` or `↓` and `↑` in this order 720 | 721 | ``` 722 | +-------------+ +-------------+ 723 | | v | | ↓ | 724 | | .item-a | or | .item-a | 725 | | ^ | | ↑ | 726 | +-------------+ +-------------+ 727 | ``` 728 | 729 | ![grid-align-self-center](https://cloud.githubusercontent.com/assets/566536/23096173/41eaf966-f617-11e6-91c1-251888ee903b.png) 730 | 731 | New lines and position of alignement characters do not matter. Just make it visually understandable. 732 | 733 | ### Usage with Prettier formatter 734 | 735 | People using [Prettier](https://prettier.io) code formatter may have issues with the automatic formating of `grid-kiss` declarations. In that case, write `grid-template-kiss` instead of `grid-kiss`. For some reason, Prettier correctly formats the declarations starting with `grid-template-***`. 736 | 737 | --- 738 | 739 | ![Sketchnote](https://user-images.githubusercontent.com/566536/52332976-553bf180-29fc-11e9-9578-8365ae7eee1b.jpg) 740 | 741 | --- 742 | 743 | Credits for images : [CSS Tricks](https://css-tricks.com/snippets/css/complete-guide-grid/), [@aneveux](https://github.com/aneveux/) 744 | 745 | [playground]: https://sylvainpolletvillard.github.io/grid-kiss-playground/index.html 746 | [codepen]: http://codepen.io/sylvainpv/pen/oBxKWg 747 | [postcss-website]: http://postcss.org/ 748 | [w3c-spec]: https://www.w3.org/TR/css-grid-1/ 749 | [can-i-use]: http://caniuse.com/#feat=css-grid 750 | [browserslist]: https://github.com/ai/browserslist 751 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | ava: ^4.0.1 5 | browserslist: ^4.19.1 6 | caniuse-lite: ^1.0.30001301 7 | eslint: ^8.7.0 8 | postcss: ^8.4.5 9 | postcss-merge-grid-template: ^0.8.1 10 | reduce-css-calc: ^2.1.8 11 | 12 | dependencies: 13 | browserslist: 4.20.3 14 | caniuse-lite: 1.0.30001346 15 | postcss-merge-grid-template: 0.8.1_postcss@8.4.14 16 | reduce-css-calc: 2.1.8 17 | 18 | devDependencies: 19 | ava: 4.3.0 20 | eslint: 8.17.0 21 | postcss: 8.4.14 22 | 23 | packages: 24 | 25 | /@eslint/eslintrc/1.3.0: 26 | resolution: {integrity: sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==} 27 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 28 | dependencies: 29 | ajv: 6.12.6 30 | debug: 4.3.4 31 | espree: 9.3.2 32 | globals: 13.15.0 33 | ignore: 5.2.0 34 | import-fresh: 3.3.0 35 | js-yaml: 4.1.0 36 | minimatch: 3.1.2 37 | strip-json-comments: 3.1.1 38 | transitivePeerDependencies: 39 | - supports-color 40 | dev: true 41 | 42 | /@humanwhocodes/config-array/0.9.5: 43 | resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} 44 | engines: {node: '>=10.10.0'} 45 | dependencies: 46 | '@humanwhocodes/object-schema': 1.2.1 47 | debug: 4.3.4 48 | minimatch: 3.1.2 49 | transitivePeerDependencies: 50 | - supports-color 51 | dev: true 52 | 53 | /@humanwhocodes/object-schema/1.2.1: 54 | resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} 55 | dev: true 56 | 57 | /@nodelib/fs.scandir/2.1.5: 58 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 59 | engines: {node: '>= 8'} 60 | dependencies: 61 | '@nodelib/fs.stat': 2.0.5 62 | run-parallel: 1.2.0 63 | dev: true 64 | 65 | /@nodelib/fs.stat/2.0.5: 66 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 67 | engines: {node: '>= 8'} 68 | dev: true 69 | 70 | /@nodelib/fs.walk/1.2.8: 71 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 72 | engines: {node: '>= 8'} 73 | dependencies: 74 | '@nodelib/fs.scandir': 2.1.5 75 | fastq: 1.13.0 76 | dev: true 77 | 78 | /acorn-jsx/5.3.2_acorn@8.7.1: 79 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 80 | peerDependencies: 81 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 82 | dependencies: 83 | acorn: 8.7.1 84 | dev: true 85 | 86 | /acorn-walk/8.2.0: 87 | resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} 88 | engines: {node: '>=0.4.0'} 89 | dev: true 90 | 91 | /acorn/8.7.1: 92 | resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==} 93 | engines: {node: '>=0.4.0'} 94 | hasBin: true 95 | dev: true 96 | 97 | /aggregate-error/3.1.0: 98 | resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} 99 | engines: {node: '>=8'} 100 | dependencies: 101 | clean-stack: 2.2.0 102 | indent-string: 4.0.0 103 | dev: true 104 | 105 | /aggregate-error/4.0.1: 106 | resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} 107 | engines: {node: '>=12'} 108 | dependencies: 109 | clean-stack: 4.2.0 110 | indent-string: 5.0.0 111 | dev: true 112 | 113 | /ajv/6.12.6: 114 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 115 | dependencies: 116 | fast-deep-equal: 3.1.3 117 | fast-json-stable-stringify: 2.1.0 118 | json-schema-traverse: 0.4.1 119 | uri-js: 4.4.1 120 | dev: true 121 | 122 | /ansi-regex/5.0.1: 123 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 124 | engines: {node: '>=8'} 125 | dev: true 126 | 127 | /ansi-regex/6.0.1: 128 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 129 | engines: {node: '>=12'} 130 | dev: true 131 | 132 | /ansi-styles/4.3.0: 133 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 134 | engines: {node: '>=8'} 135 | dependencies: 136 | color-convert: 2.0.1 137 | dev: true 138 | 139 | /ansi-styles/6.1.0: 140 | resolution: {integrity: sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==} 141 | engines: {node: '>=12'} 142 | dev: true 143 | 144 | /anymatch/3.1.2: 145 | resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} 146 | engines: {node: '>= 8'} 147 | dependencies: 148 | normalize-path: 3.0.0 149 | picomatch: 2.3.1 150 | dev: true 151 | 152 | /argparse/1.0.10: 153 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 154 | dependencies: 155 | sprintf-js: 1.0.3 156 | dev: true 157 | 158 | /argparse/2.0.1: 159 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 160 | dev: true 161 | 162 | /array-find-index/1.0.2: 163 | resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} 164 | engines: {node: '>=0.10.0'} 165 | dev: true 166 | 167 | /array-union/2.1.0: 168 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 169 | engines: {node: '>=8'} 170 | dev: true 171 | 172 | /arrgv/1.0.2: 173 | resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} 174 | engines: {node: '>=8.0.0'} 175 | dev: true 176 | 177 | /arrify/3.0.0: 178 | resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} 179 | engines: {node: '>=12'} 180 | dev: true 181 | 182 | /ava/4.3.0: 183 | resolution: {integrity: sha512-Ap0u8rp8wOBN6CxshgxrPSe191e8g52RWGoXeDB57ubo4fyZyStfI6OxQi/bl0yxIDEOYHhCiGwihbzlMNJw3Q==} 184 | engines: {node: '>=12.22 <13 || >=14.17 <15 || >=16.4 <17 || >=18'} 185 | hasBin: true 186 | peerDependencies: 187 | '@ava/typescript': '*' 188 | peerDependenciesMeta: 189 | '@ava/typescript': 190 | optional: true 191 | dependencies: 192 | acorn: 8.7.1 193 | acorn-walk: 8.2.0 194 | ansi-styles: 6.1.0 195 | arrgv: 1.0.2 196 | arrify: 3.0.0 197 | callsites: 4.0.0 198 | cbor: 8.1.0 199 | chalk: 5.0.1 200 | chokidar: 3.5.3 201 | chunkd: 2.0.1 202 | ci-info: 3.3.1 203 | ci-parallel-vars: 1.0.1 204 | clean-yaml-object: 0.1.0 205 | cli-truncate: 3.1.0 206 | code-excerpt: 4.0.0 207 | common-path-prefix: 3.0.0 208 | concordance: 5.0.4 209 | currently-unhandled: 0.4.1 210 | debug: 4.3.4 211 | del: 6.1.1 212 | emittery: 0.11.0 213 | figures: 4.0.1 214 | globby: 13.1.1 215 | ignore-by-default: 2.1.0 216 | indent-string: 5.0.0 217 | is-error: 2.2.2 218 | is-plain-object: 5.0.0 219 | is-promise: 4.0.0 220 | matcher: 5.0.0 221 | mem: 9.0.2 222 | ms: 2.1.3 223 | p-event: 5.0.1 224 | p-map: 5.4.0 225 | picomatch: 2.3.1 226 | pkg-conf: 4.0.0 227 | plur: 5.1.0 228 | pretty-ms: 7.0.1 229 | resolve-cwd: 3.0.0 230 | slash: 3.0.0 231 | stack-utils: 2.0.5 232 | strip-ansi: 7.0.1 233 | supertap: 3.0.1 234 | temp-dir: 2.0.0 235 | write-file-atomic: 4.0.1 236 | yargs: 17.5.1 237 | transitivePeerDependencies: 238 | - supports-color 239 | dev: true 240 | 241 | /balanced-match/1.0.2: 242 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 243 | dev: true 244 | 245 | /binary-extensions/2.2.0: 246 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 247 | engines: {node: '>=8'} 248 | dev: true 249 | 250 | /blueimp-md5/2.19.0: 251 | resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} 252 | dev: true 253 | 254 | /brace-expansion/1.1.11: 255 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 256 | dependencies: 257 | balanced-match: 1.0.2 258 | concat-map: 0.0.1 259 | dev: true 260 | 261 | /braces/3.0.2: 262 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 263 | engines: {node: '>=8'} 264 | dependencies: 265 | fill-range: 7.0.1 266 | dev: true 267 | 268 | /browserslist/4.20.3: 269 | resolution: {integrity: sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==} 270 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 271 | hasBin: true 272 | dependencies: 273 | caniuse-lite: 1.0.30001346 274 | electron-to-chromium: 1.4.146 275 | escalade: 3.1.1 276 | node-releases: 2.0.5 277 | picocolors: 1.0.0 278 | dev: false 279 | 280 | /callsites/3.1.0: 281 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 282 | engines: {node: '>=6'} 283 | dev: true 284 | 285 | /callsites/4.0.0: 286 | resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==} 287 | engines: {node: '>=12.20'} 288 | dev: true 289 | 290 | /caniuse-lite/1.0.30001346: 291 | resolution: {integrity: sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ==} 292 | dev: false 293 | 294 | /cbor/8.1.0: 295 | resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} 296 | engines: {node: '>=12.19'} 297 | dependencies: 298 | nofilter: 3.1.0 299 | dev: true 300 | 301 | /chalk/4.1.2: 302 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 303 | engines: {node: '>=10'} 304 | dependencies: 305 | ansi-styles: 4.3.0 306 | supports-color: 7.2.0 307 | dev: true 308 | 309 | /chalk/5.0.1: 310 | resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} 311 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 312 | dev: true 313 | 314 | /chokidar/3.5.3: 315 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 316 | engines: {node: '>= 8.10.0'} 317 | dependencies: 318 | anymatch: 3.1.2 319 | braces: 3.0.2 320 | glob-parent: 5.1.2 321 | is-binary-path: 2.1.0 322 | is-glob: 4.0.3 323 | normalize-path: 3.0.0 324 | readdirp: 3.6.0 325 | optionalDependencies: 326 | fsevents: 2.3.2 327 | dev: true 328 | 329 | /chunkd/2.0.1: 330 | resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} 331 | dev: true 332 | 333 | /ci-info/3.3.1: 334 | resolution: {integrity: sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==} 335 | dev: true 336 | 337 | /ci-parallel-vars/1.0.1: 338 | resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} 339 | dev: true 340 | 341 | /clean-stack/2.2.0: 342 | resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} 343 | engines: {node: '>=6'} 344 | dev: true 345 | 346 | /clean-stack/4.2.0: 347 | resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} 348 | engines: {node: '>=12'} 349 | dependencies: 350 | escape-string-regexp: 5.0.0 351 | dev: true 352 | 353 | /clean-yaml-object/0.1.0: 354 | resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} 355 | engines: {node: '>=0.10.0'} 356 | dev: true 357 | 358 | /cli-truncate/3.1.0: 359 | resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} 360 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 361 | dependencies: 362 | slice-ansi: 5.0.0 363 | string-width: 5.1.2 364 | dev: true 365 | 366 | /cliui/7.0.4: 367 | resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} 368 | dependencies: 369 | string-width: 4.2.3 370 | strip-ansi: 6.0.1 371 | wrap-ansi: 7.0.0 372 | dev: true 373 | 374 | /code-excerpt/4.0.0: 375 | resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} 376 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 377 | dependencies: 378 | convert-to-spaces: 2.0.1 379 | dev: true 380 | 381 | /color-convert/2.0.1: 382 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 383 | engines: {node: '>=7.0.0'} 384 | dependencies: 385 | color-name: 1.1.4 386 | dev: true 387 | 388 | /color-name/1.1.4: 389 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 390 | dev: true 391 | 392 | /common-path-prefix/3.0.0: 393 | resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} 394 | dev: true 395 | 396 | /concat-map/0.0.1: 397 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 398 | dev: true 399 | 400 | /concordance/5.0.4: 401 | resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} 402 | engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} 403 | dependencies: 404 | date-time: 3.1.0 405 | esutils: 2.0.3 406 | fast-diff: 1.2.0 407 | js-string-escape: 1.0.1 408 | lodash: 4.17.21 409 | md5-hex: 3.0.1 410 | semver: 7.3.7 411 | well-known-symbols: 2.0.0 412 | dev: true 413 | 414 | /convert-to-spaces/2.0.1: 415 | resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} 416 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 417 | dev: true 418 | 419 | /cross-spawn/7.0.3: 420 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 421 | engines: {node: '>= 8'} 422 | dependencies: 423 | path-key: 3.1.1 424 | shebang-command: 2.0.0 425 | which: 2.0.2 426 | dev: true 427 | 428 | /css-unit-converter/1.1.2: 429 | resolution: {integrity: sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==} 430 | dev: false 431 | 432 | /currently-unhandled/0.4.1: 433 | resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} 434 | engines: {node: '>=0.10.0'} 435 | dependencies: 436 | array-find-index: 1.0.2 437 | dev: true 438 | 439 | /date-time/3.1.0: 440 | resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} 441 | engines: {node: '>=6'} 442 | dependencies: 443 | time-zone: 1.0.0 444 | dev: true 445 | 446 | /debug/4.3.4: 447 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 448 | engines: {node: '>=6.0'} 449 | peerDependencies: 450 | supports-color: '*' 451 | peerDependenciesMeta: 452 | supports-color: 453 | optional: true 454 | dependencies: 455 | ms: 2.1.2 456 | dev: true 457 | 458 | /deep-is/0.1.4: 459 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 460 | dev: true 461 | 462 | /del/6.1.1: 463 | resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} 464 | engines: {node: '>=10'} 465 | dependencies: 466 | globby: 11.1.0 467 | graceful-fs: 4.2.10 468 | is-glob: 4.0.3 469 | is-path-cwd: 2.2.0 470 | is-path-inside: 3.0.3 471 | p-map: 4.0.0 472 | rimraf: 3.0.2 473 | slash: 3.0.0 474 | dev: true 475 | 476 | /dir-glob/3.0.1: 477 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 478 | engines: {node: '>=8'} 479 | dependencies: 480 | path-type: 4.0.0 481 | dev: true 482 | 483 | /doctrine/3.0.0: 484 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 485 | engines: {node: '>=6.0.0'} 486 | dependencies: 487 | esutils: 2.0.3 488 | dev: true 489 | 490 | /eastasianwidth/0.2.0: 491 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 492 | dev: true 493 | 494 | /electron-to-chromium/1.4.146: 495 | resolution: {integrity: sha512-4eWebzDLd+hYLm4csbyMU2EbBnqhwl8Oe9eF/7CBDPWcRxFmqzx4izxvHH+lofQxzieg8UbB8ZuzNTxeukzfTg==} 496 | dev: false 497 | 498 | /emittery/0.11.0: 499 | resolution: {integrity: sha512-S/7tzL6v5i+4iJd627Nhv9cLFIo5weAIlGccqJFpnBoDB8U1TF2k5tez4J/QNuxyyhWuFqHg1L84Kd3m7iXg6g==} 500 | engines: {node: '>=12'} 501 | dev: true 502 | 503 | /emoji-regex/8.0.0: 504 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 505 | dev: true 506 | 507 | /emoji-regex/9.2.2: 508 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 509 | dev: true 510 | 511 | /escalade/3.1.1: 512 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 513 | engines: {node: '>=6'} 514 | 515 | /escape-string-regexp/2.0.0: 516 | resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} 517 | engines: {node: '>=8'} 518 | dev: true 519 | 520 | /escape-string-regexp/4.0.0: 521 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 522 | engines: {node: '>=10'} 523 | dev: true 524 | 525 | /escape-string-regexp/5.0.0: 526 | resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} 527 | engines: {node: '>=12'} 528 | dev: true 529 | 530 | /eslint-scope/7.1.1: 531 | resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} 532 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 533 | dependencies: 534 | esrecurse: 4.3.0 535 | estraverse: 5.3.0 536 | dev: true 537 | 538 | /eslint-utils/3.0.0_eslint@8.17.0: 539 | resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} 540 | engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} 541 | peerDependencies: 542 | eslint: '>=5' 543 | dependencies: 544 | eslint: 8.17.0 545 | eslint-visitor-keys: 2.1.0 546 | dev: true 547 | 548 | /eslint-visitor-keys/2.1.0: 549 | resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} 550 | engines: {node: '>=10'} 551 | dev: true 552 | 553 | /eslint-visitor-keys/3.3.0: 554 | resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} 555 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 556 | dev: true 557 | 558 | /eslint/8.17.0: 559 | resolution: {integrity: sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==} 560 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 561 | hasBin: true 562 | dependencies: 563 | '@eslint/eslintrc': 1.3.0 564 | '@humanwhocodes/config-array': 0.9.5 565 | ajv: 6.12.6 566 | chalk: 4.1.2 567 | cross-spawn: 7.0.3 568 | debug: 4.3.4 569 | doctrine: 3.0.0 570 | escape-string-regexp: 4.0.0 571 | eslint-scope: 7.1.1 572 | eslint-utils: 3.0.0_eslint@8.17.0 573 | eslint-visitor-keys: 3.3.0 574 | espree: 9.3.2 575 | esquery: 1.4.0 576 | esutils: 2.0.3 577 | fast-deep-equal: 3.1.3 578 | file-entry-cache: 6.0.1 579 | functional-red-black-tree: 1.0.1 580 | glob-parent: 6.0.2 581 | globals: 13.15.0 582 | ignore: 5.2.0 583 | import-fresh: 3.3.0 584 | imurmurhash: 0.1.4 585 | is-glob: 4.0.3 586 | js-yaml: 4.1.0 587 | json-stable-stringify-without-jsonify: 1.0.1 588 | levn: 0.4.1 589 | lodash.merge: 4.6.2 590 | minimatch: 3.1.2 591 | natural-compare: 1.4.0 592 | optionator: 0.9.1 593 | regexpp: 3.2.0 594 | strip-ansi: 6.0.1 595 | strip-json-comments: 3.1.1 596 | text-table: 0.2.0 597 | v8-compile-cache: 2.3.0 598 | transitivePeerDependencies: 599 | - supports-color 600 | dev: true 601 | 602 | /espree/9.3.2: 603 | resolution: {integrity: sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==} 604 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 605 | dependencies: 606 | acorn: 8.7.1 607 | acorn-jsx: 5.3.2_acorn@8.7.1 608 | eslint-visitor-keys: 3.3.0 609 | dev: true 610 | 611 | /esprima/4.0.1: 612 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 613 | engines: {node: '>=4'} 614 | hasBin: true 615 | dev: true 616 | 617 | /esquery/1.4.0: 618 | resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} 619 | engines: {node: '>=0.10'} 620 | dependencies: 621 | estraverse: 5.3.0 622 | dev: true 623 | 624 | /esrecurse/4.3.0: 625 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 626 | engines: {node: '>=4.0'} 627 | dependencies: 628 | estraverse: 5.3.0 629 | dev: true 630 | 631 | /estraverse/5.3.0: 632 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 633 | engines: {node: '>=4.0'} 634 | dev: true 635 | 636 | /esutils/2.0.3: 637 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 638 | engines: {node: '>=0.10.0'} 639 | dev: true 640 | 641 | /fast-deep-equal/3.1.3: 642 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 643 | dev: true 644 | 645 | /fast-diff/1.2.0: 646 | resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} 647 | dev: true 648 | 649 | /fast-glob/3.2.11: 650 | resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} 651 | engines: {node: '>=8.6.0'} 652 | dependencies: 653 | '@nodelib/fs.stat': 2.0.5 654 | '@nodelib/fs.walk': 1.2.8 655 | glob-parent: 5.1.2 656 | merge2: 1.4.1 657 | micromatch: 4.0.5 658 | dev: true 659 | 660 | /fast-json-stable-stringify/2.1.0: 661 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 662 | dev: true 663 | 664 | /fast-levenshtein/2.0.6: 665 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 666 | dev: true 667 | 668 | /fastq/1.13.0: 669 | resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} 670 | dependencies: 671 | reusify: 1.0.4 672 | dev: true 673 | 674 | /figures/4.0.1: 675 | resolution: {integrity: sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==} 676 | engines: {node: '>=12'} 677 | dependencies: 678 | escape-string-regexp: 5.0.0 679 | is-unicode-supported: 1.2.0 680 | dev: true 681 | 682 | /file-entry-cache/6.0.1: 683 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 684 | engines: {node: ^10.12.0 || >=12.0.0} 685 | dependencies: 686 | flat-cache: 3.0.4 687 | dev: true 688 | 689 | /fill-range/7.0.1: 690 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 691 | engines: {node: '>=8'} 692 | dependencies: 693 | to-regex-range: 5.0.1 694 | dev: true 695 | 696 | /find-up/6.3.0: 697 | resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} 698 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 699 | dependencies: 700 | locate-path: 7.1.1 701 | path-exists: 5.0.0 702 | dev: true 703 | 704 | /flat-cache/3.0.4: 705 | resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} 706 | engines: {node: ^10.12.0 || >=12.0.0} 707 | dependencies: 708 | flatted: 3.2.5 709 | rimraf: 3.0.2 710 | dev: true 711 | 712 | /flatted/3.2.5: 713 | resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} 714 | dev: true 715 | 716 | /fs.realpath/1.0.0: 717 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 718 | dev: true 719 | 720 | /fsevents/2.3.2: 721 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 722 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 723 | os: [darwin] 724 | requiresBuild: true 725 | dev: true 726 | optional: true 727 | 728 | /functional-red-black-tree/1.0.1: 729 | resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} 730 | dev: true 731 | 732 | /get-caller-file/2.0.5: 733 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 734 | engines: {node: 6.* || 8.* || >= 10.*} 735 | dev: true 736 | 737 | /glob-parent/5.1.2: 738 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 739 | engines: {node: '>= 6'} 740 | dependencies: 741 | is-glob: 4.0.3 742 | dev: true 743 | 744 | /glob-parent/6.0.2: 745 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 746 | engines: {node: '>=10.13.0'} 747 | dependencies: 748 | is-glob: 4.0.3 749 | dev: true 750 | 751 | /glob/7.2.3: 752 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 753 | dependencies: 754 | fs.realpath: 1.0.0 755 | inflight: 1.0.6 756 | inherits: 2.0.4 757 | minimatch: 3.1.2 758 | once: 1.4.0 759 | path-is-absolute: 1.0.1 760 | dev: true 761 | 762 | /globals/13.15.0: 763 | resolution: {integrity: sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==} 764 | engines: {node: '>=8'} 765 | dependencies: 766 | type-fest: 0.20.2 767 | dev: true 768 | 769 | /globby/11.1.0: 770 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 771 | engines: {node: '>=10'} 772 | dependencies: 773 | array-union: 2.1.0 774 | dir-glob: 3.0.1 775 | fast-glob: 3.2.11 776 | ignore: 5.2.0 777 | merge2: 1.4.1 778 | slash: 3.0.0 779 | dev: true 780 | 781 | /globby/13.1.1: 782 | resolution: {integrity: sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==} 783 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 784 | dependencies: 785 | dir-glob: 3.0.1 786 | fast-glob: 3.2.11 787 | ignore: 5.2.0 788 | merge2: 1.4.1 789 | slash: 4.0.0 790 | dev: true 791 | 792 | /graceful-fs/4.2.10: 793 | resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} 794 | dev: true 795 | 796 | /has-flag/4.0.0: 797 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 798 | engines: {node: '>=8'} 799 | dev: true 800 | 801 | /ignore-by-default/2.1.0: 802 | resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} 803 | engines: {node: '>=10 <11 || >=12 <13 || >=14'} 804 | dev: true 805 | 806 | /ignore/5.2.0: 807 | resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} 808 | engines: {node: '>= 4'} 809 | dev: true 810 | 811 | /import-fresh/3.3.0: 812 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 813 | engines: {node: '>=6'} 814 | dependencies: 815 | parent-module: 1.0.1 816 | resolve-from: 4.0.0 817 | dev: true 818 | 819 | /imurmurhash/0.1.4: 820 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 821 | engines: {node: '>=0.8.19'} 822 | dev: true 823 | 824 | /indent-string/4.0.0: 825 | resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} 826 | engines: {node: '>=8'} 827 | dev: true 828 | 829 | /indent-string/5.0.0: 830 | resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} 831 | engines: {node: '>=12'} 832 | dev: true 833 | 834 | /inflight/1.0.6: 835 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 836 | dependencies: 837 | once: 1.4.0 838 | wrappy: 1.0.2 839 | dev: true 840 | 841 | /inherits/2.0.4: 842 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 843 | dev: true 844 | 845 | /irregular-plurals/3.3.0: 846 | resolution: {integrity: sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==} 847 | engines: {node: '>=8'} 848 | dev: true 849 | 850 | /is-binary-path/2.1.0: 851 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 852 | engines: {node: '>=8'} 853 | dependencies: 854 | binary-extensions: 2.2.0 855 | dev: true 856 | 857 | /is-error/2.2.2: 858 | resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} 859 | dev: true 860 | 861 | /is-extglob/2.1.1: 862 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 863 | engines: {node: '>=0.10.0'} 864 | dev: true 865 | 866 | /is-fullwidth-code-point/3.0.0: 867 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 868 | engines: {node: '>=8'} 869 | dev: true 870 | 871 | /is-fullwidth-code-point/4.0.0: 872 | resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} 873 | engines: {node: '>=12'} 874 | dev: true 875 | 876 | /is-glob/4.0.3: 877 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 878 | engines: {node: '>=0.10.0'} 879 | dependencies: 880 | is-extglob: 2.1.1 881 | dev: true 882 | 883 | /is-number/7.0.0: 884 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 885 | engines: {node: '>=0.12.0'} 886 | dev: true 887 | 888 | /is-path-cwd/2.2.0: 889 | resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} 890 | engines: {node: '>=6'} 891 | dev: true 892 | 893 | /is-path-inside/3.0.3: 894 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 895 | engines: {node: '>=8'} 896 | dev: true 897 | 898 | /is-plain-object/5.0.0: 899 | resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} 900 | engines: {node: '>=0.10.0'} 901 | dev: true 902 | 903 | /is-promise/4.0.0: 904 | resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} 905 | dev: true 906 | 907 | /is-unicode-supported/1.2.0: 908 | resolution: {integrity: sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==} 909 | engines: {node: '>=12'} 910 | dev: true 911 | 912 | /isexe/2.0.0: 913 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 914 | dev: true 915 | 916 | /js-string-escape/1.0.1: 917 | resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} 918 | engines: {node: '>= 0.8'} 919 | dev: true 920 | 921 | /js-yaml/3.14.1: 922 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 923 | hasBin: true 924 | dependencies: 925 | argparse: 1.0.10 926 | esprima: 4.0.1 927 | dev: true 928 | 929 | /js-yaml/4.1.0: 930 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 931 | hasBin: true 932 | dependencies: 933 | argparse: 2.0.1 934 | dev: true 935 | 936 | /json-schema-traverse/0.4.1: 937 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 938 | dev: true 939 | 940 | /json-stable-stringify-without-jsonify/1.0.1: 941 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 942 | dev: true 943 | 944 | /levn/0.4.1: 945 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 946 | engines: {node: '>= 0.8.0'} 947 | dependencies: 948 | prelude-ls: 1.2.1 949 | type-check: 0.4.0 950 | dev: true 951 | 952 | /load-json-file/7.0.1: 953 | resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} 954 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 955 | dev: true 956 | 957 | /locate-path/7.1.1: 958 | resolution: {integrity: sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==} 959 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 960 | dependencies: 961 | p-locate: 6.0.0 962 | dev: true 963 | 964 | /lodash.merge/4.6.2: 965 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 966 | dev: true 967 | 968 | /lodash/4.17.21: 969 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 970 | dev: true 971 | 972 | /lru-cache/6.0.0: 973 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 974 | engines: {node: '>=10'} 975 | dependencies: 976 | yallist: 4.0.0 977 | dev: true 978 | 979 | /map-age-cleaner/0.1.3: 980 | resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} 981 | engines: {node: '>=6'} 982 | dependencies: 983 | p-defer: 1.0.0 984 | dev: true 985 | 986 | /matcher/5.0.0: 987 | resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} 988 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 989 | dependencies: 990 | escape-string-regexp: 5.0.0 991 | dev: true 992 | 993 | /md5-hex/3.0.1: 994 | resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} 995 | engines: {node: '>=8'} 996 | dependencies: 997 | blueimp-md5: 2.19.0 998 | dev: true 999 | 1000 | /mem/9.0.2: 1001 | resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} 1002 | engines: {node: '>=12.20'} 1003 | dependencies: 1004 | map-age-cleaner: 0.1.3 1005 | mimic-fn: 4.0.0 1006 | dev: true 1007 | 1008 | /merge2/1.4.1: 1009 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1010 | engines: {node: '>= 8'} 1011 | dev: true 1012 | 1013 | /micromatch/4.0.5: 1014 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 1015 | engines: {node: '>=8.6'} 1016 | dependencies: 1017 | braces: 3.0.2 1018 | picomatch: 2.3.1 1019 | dev: true 1020 | 1021 | /mimic-fn/4.0.0: 1022 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} 1023 | engines: {node: '>=12'} 1024 | dev: true 1025 | 1026 | /minimatch/3.1.2: 1027 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1028 | dependencies: 1029 | brace-expansion: 1.1.11 1030 | dev: true 1031 | 1032 | /ms/2.1.2: 1033 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1034 | dev: true 1035 | 1036 | /ms/2.1.3: 1037 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1038 | dev: true 1039 | 1040 | /nanoid/3.3.4: 1041 | resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} 1042 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1043 | hasBin: true 1044 | 1045 | /natural-compare/1.4.0: 1046 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1047 | dev: true 1048 | 1049 | /node-releases/2.0.5: 1050 | resolution: {integrity: sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==} 1051 | dev: false 1052 | 1053 | /nofilter/3.1.0: 1054 | resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} 1055 | engines: {node: '>=12.19'} 1056 | dev: true 1057 | 1058 | /normalize-path/3.0.0: 1059 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1060 | engines: {node: '>=0.10.0'} 1061 | dev: true 1062 | 1063 | /once/1.4.0: 1064 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1065 | dependencies: 1066 | wrappy: 1.0.2 1067 | dev: true 1068 | 1069 | /optionator/0.9.1: 1070 | resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} 1071 | engines: {node: '>= 0.8.0'} 1072 | dependencies: 1073 | deep-is: 0.1.4 1074 | fast-levenshtein: 2.0.6 1075 | levn: 0.4.1 1076 | prelude-ls: 1.2.1 1077 | type-check: 0.4.0 1078 | word-wrap: 1.2.3 1079 | dev: true 1080 | 1081 | /p-defer/1.0.0: 1082 | resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} 1083 | engines: {node: '>=4'} 1084 | dev: true 1085 | 1086 | /p-event/5.0.1: 1087 | resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} 1088 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1089 | dependencies: 1090 | p-timeout: 5.1.0 1091 | dev: true 1092 | 1093 | /p-limit/4.0.0: 1094 | resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} 1095 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1096 | dependencies: 1097 | yocto-queue: 1.0.0 1098 | dev: true 1099 | 1100 | /p-locate/6.0.0: 1101 | resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} 1102 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1103 | dependencies: 1104 | p-limit: 4.0.0 1105 | dev: true 1106 | 1107 | /p-map/4.0.0: 1108 | resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} 1109 | engines: {node: '>=10'} 1110 | dependencies: 1111 | aggregate-error: 3.1.0 1112 | dev: true 1113 | 1114 | /p-map/5.4.0: 1115 | resolution: {integrity: sha512-obHraaWkwl4y1NHR4vW5D5k+33+S5QrkFqsNrrvK0R7lilXdzo/DZgnloDvYUaRT+Sk6vVK47JUQMQY6cjPMXg==} 1116 | engines: {node: '>=12'} 1117 | dependencies: 1118 | aggregate-error: 4.0.1 1119 | dev: true 1120 | 1121 | /p-timeout/5.1.0: 1122 | resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} 1123 | engines: {node: '>=12'} 1124 | dev: true 1125 | 1126 | /parent-module/1.0.1: 1127 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1128 | engines: {node: '>=6'} 1129 | dependencies: 1130 | callsites: 3.1.0 1131 | dev: true 1132 | 1133 | /parse-ms/2.1.0: 1134 | resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} 1135 | engines: {node: '>=6'} 1136 | dev: true 1137 | 1138 | /path-exists/5.0.0: 1139 | resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} 1140 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1141 | dev: true 1142 | 1143 | /path-is-absolute/1.0.1: 1144 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1145 | engines: {node: '>=0.10.0'} 1146 | dev: true 1147 | 1148 | /path-key/3.1.1: 1149 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1150 | engines: {node: '>=8'} 1151 | dev: true 1152 | 1153 | /path-type/4.0.0: 1154 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1155 | engines: {node: '>=8'} 1156 | dev: true 1157 | 1158 | /picocolors/1.0.0: 1159 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 1160 | 1161 | /picomatch/2.3.1: 1162 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1163 | engines: {node: '>=8.6'} 1164 | dev: true 1165 | 1166 | /pkg-conf/4.0.0: 1167 | resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} 1168 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1169 | dependencies: 1170 | find-up: 6.3.0 1171 | load-json-file: 7.0.1 1172 | dev: true 1173 | 1174 | /plur/5.1.0: 1175 | resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} 1176 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1177 | dependencies: 1178 | irregular-plurals: 3.3.0 1179 | dev: true 1180 | 1181 | /postcss-merge-grid-template/0.8.1_postcss@8.4.14: 1182 | resolution: {integrity: sha512-G/a22yDfoVRp/dC+GKghWeK8mQOEaTYjywbTwBcl7woq3Hq/Pam3ACtlIiUYaschh8VvayhA/9/8Ynn9LvCaPw==} 1183 | engines: {node: '>=6.0.0'} 1184 | peerDependencies: 1185 | postcss: ^8.1.0 1186 | dependencies: 1187 | postcss: 8.4.14 1188 | dev: false 1189 | 1190 | /postcss-value-parser/3.3.1: 1191 | resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==} 1192 | dev: false 1193 | 1194 | /postcss/8.4.14: 1195 | resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} 1196 | engines: {node: ^10 || ^12 || >=14} 1197 | dependencies: 1198 | nanoid: 3.3.4 1199 | picocolors: 1.0.0 1200 | source-map-js: 1.0.2 1201 | 1202 | /prelude-ls/1.2.1: 1203 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1204 | engines: {node: '>= 0.8.0'} 1205 | dev: true 1206 | 1207 | /pretty-ms/7.0.1: 1208 | resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} 1209 | engines: {node: '>=10'} 1210 | dependencies: 1211 | parse-ms: 2.1.0 1212 | dev: true 1213 | 1214 | /punycode/2.1.1: 1215 | resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} 1216 | engines: {node: '>=6'} 1217 | dev: true 1218 | 1219 | /queue-microtask/1.2.3: 1220 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1221 | dev: true 1222 | 1223 | /readdirp/3.6.0: 1224 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1225 | engines: {node: '>=8.10.0'} 1226 | dependencies: 1227 | picomatch: 2.3.1 1228 | dev: true 1229 | 1230 | /reduce-css-calc/2.1.8: 1231 | resolution: {integrity: sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==} 1232 | dependencies: 1233 | css-unit-converter: 1.1.2 1234 | postcss-value-parser: 3.3.1 1235 | dev: false 1236 | 1237 | /regexpp/3.2.0: 1238 | resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} 1239 | engines: {node: '>=8'} 1240 | dev: true 1241 | 1242 | /require-directory/2.1.1: 1243 | resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} 1244 | engines: {node: '>=0.10.0'} 1245 | dev: true 1246 | 1247 | /resolve-cwd/3.0.0: 1248 | resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} 1249 | engines: {node: '>=8'} 1250 | dependencies: 1251 | resolve-from: 5.0.0 1252 | dev: true 1253 | 1254 | /resolve-from/4.0.0: 1255 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1256 | engines: {node: '>=4'} 1257 | dev: true 1258 | 1259 | /resolve-from/5.0.0: 1260 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1261 | engines: {node: '>=8'} 1262 | dev: true 1263 | 1264 | /reusify/1.0.4: 1265 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1266 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1267 | dev: true 1268 | 1269 | /rimraf/3.0.2: 1270 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1271 | hasBin: true 1272 | dependencies: 1273 | glob: 7.2.3 1274 | dev: true 1275 | 1276 | /run-parallel/1.2.0: 1277 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1278 | dependencies: 1279 | queue-microtask: 1.2.3 1280 | dev: true 1281 | 1282 | /semver/7.3.7: 1283 | resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} 1284 | engines: {node: '>=10'} 1285 | hasBin: true 1286 | dependencies: 1287 | lru-cache: 6.0.0 1288 | dev: true 1289 | 1290 | /serialize-error/7.0.1: 1291 | resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} 1292 | engines: {node: '>=10'} 1293 | dependencies: 1294 | type-fest: 0.13.1 1295 | dev: true 1296 | 1297 | /shebang-command/2.0.0: 1298 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1299 | engines: {node: '>=8'} 1300 | dependencies: 1301 | shebang-regex: 3.0.0 1302 | dev: true 1303 | 1304 | /shebang-regex/3.0.0: 1305 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1306 | engines: {node: '>=8'} 1307 | dev: true 1308 | 1309 | /signal-exit/3.0.7: 1310 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1311 | dev: true 1312 | 1313 | /slash/3.0.0: 1314 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1315 | engines: {node: '>=8'} 1316 | dev: true 1317 | 1318 | /slash/4.0.0: 1319 | resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} 1320 | engines: {node: '>=12'} 1321 | dev: true 1322 | 1323 | /slice-ansi/5.0.0: 1324 | resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} 1325 | engines: {node: '>=12'} 1326 | dependencies: 1327 | ansi-styles: 6.1.0 1328 | is-fullwidth-code-point: 4.0.0 1329 | dev: true 1330 | 1331 | /source-map-js/1.0.2: 1332 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 1333 | engines: {node: '>=0.10.0'} 1334 | 1335 | /sprintf-js/1.0.3: 1336 | resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} 1337 | dev: true 1338 | 1339 | /stack-utils/2.0.5: 1340 | resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} 1341 | engines: {node: '>=10'} 1342 | dependencies: 1343 | escape-string-regexp: 2.0.0 1344 | dev: true 1345 | 1346 | /string-width/4.2.3: 1347 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1348 | engines: {node: '>=8'} 1349 | dependencies: 1350 | emoji-regex: 8.0.0 1351 | is-fullwidth-code-point: 3.0.0 1352 | strip-ansi: 6.0.1 1353 | dev: true 1354 | 1355 | /string-width/5.1.2: 1356 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1357 | engines: {node: '>=12'} 1358 | dependencies: 1359 | eastasianwidth: 0.2.0 1360 | emoji-regex: 9.2.2 1361 | strip-ansi: 7.0.1 1362 | dev: true 1363 | 1364 | /strip-ansi/6.0.1: 1365 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1366 | engines: {node: '>=8'} 1367 | dependencies: 1368 | ansi-regex: 5.0.1 1369 | dev: true 1370 | 1371 | /strip-ansi/7.0.1: 1372 | resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} 1373 | engines: {node: '>=12'} 1374 | dependencies: 1375 | ansi-regex: 6.0.1 1376 | dev: true 1377 | 1378 | /strip-json-comments/3.1.1: 1379 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1380 | engines: {node: '>=8'} 1381 | dev: true 1382 | 1383 | /supertap/3.0.1: 1384 | resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} 1385 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1386 | dependencies: 1387 | indent-string: 5.0.0 1388 | js-yaml: 3.14.1 1389 | serialize-error: 7.0.1 1390 | strip-ansi: 7.0.1 1391 | dev: true 1392 | 1393 | /supports-color/7.2.0: 1394 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1395 | engines: {node: '>=8'} 1396 | dependencies: 1397 | has-flag: 4.0.0 1398 | dev: true 1399 | 1400 | /temp-dir/2.0.0: 1401 | resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} 1402 | engines: {node: '>=8'} 1403 | dev: true 1404 | 1405 | /text-table/0.2.0: 1406 | resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=} 1407 | dev: true 1408 | 1409 | /time-zone/1.0.0: 1410 | resolution: {integrity: sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=} 1411 | engines: {node: '>=4'} 1412 | dev: true 1413 | 1414 | /to-regex-range/5.0.1: 1415 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1416 | engines: {node: '>=8.0'} 1417 | dependencies: 1418 | is-number: 7.0.0 1419 | dev: true 1420 | 1421 | /type-check/0.4.0: 1422 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1423 | engines: {node: '>= 0.8.0'} 1424 | dependencies: 1425 | prelude-ls: 1.2.1 1426 | dev: true 1427 | 1428 | /type-fest/0.13.1: 1429 | resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} 1430 | engines: {node: '>=10'} 1431 | dev: true 1432 | 1433 | /type-fest/0.20.2: 1434 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 1435 | engines: {node: '>=10'} 1436 | dev: true 1437 | 1438 | /uri-js/4.4.1: 1439 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1440 | dependencies: 1441 | punycode: 2.1.1 1442 | dev: true 1443 | 1444 | /v8-compile-cache/2.3.0: 1445 | resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} 1446 | dev: true 1447 | 1448 | /well-known-symbols/2.0.0: 1449 | resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} 1450 | engines: {node: '>=6'} 1451 | dev: true 1452 | 1453 | /which/2.0.2: 1454 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1455 | engines: {node: '>= 8'} 1456 | hasBin: true 1457 | dependencies: 1458 | isexe: 2.0.0 1459 | dev: true 1460 | 1461 | /word-wrap/1.2.3: 1462 | resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} 1463 | engines: {node: '>=0.10.0'} 1464 | dev: true 1465 | 1466 | /wrap-ansi/7.0.0: 1467 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1468 | engines: {node: '>=10'} 1469 | dependencies: 1470 | ansi-styles: 4.3.0 1471 | string-width: 4.2.3 1472 | strip-ansi: 6.0.1 1473 | dev: true 1474 | 1475 | /wrappy/1.0.2: 1476 | resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} 1477 | dev: true 1478 | 1479 | /write-file-atomic/4.0.1: 1480 | resolution: {integrity: sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==} 1481 | engines: {node: ^12.13.0 || ^14.15.0 || >=16} 1482 | dependencies: 1483 | imurmurhash: 0.1.4 1484 | signal-exit: 3.0.7 1485 | dev: true 1486 | 1487 | /y18n/5.0.8: 1488 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 1489 | engines: {node: '>=10'} 1490 | dev: true 1491 | 1492 | /yallist/4.0.0: 1493 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1494 | dev: true 1495 | 1496 | /yargs-parser/21.0.1: 1497 | resolution: {integrity: sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==} 1498 | engines: {node: '>=12'} 1499 | dev: true 1500 | 1501 | /yargs/17.5.1: 1502 | resolution: {integrity: sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==} 1503 | engines: {node: '>=12'} 1504 | dependencies: 1505 | cliui: 7.0.4 1506 | escalade: 3.1.1 1507 | get-caller-file: 2.0.5 1508 | require-directory: 2.1.1 1509 | string-width: 4.2.3 1510 | y18n: 5.0.8 1511 | yargs-parser: 21.0.1 1512 | dev: true 1513 | 1514 | /yocto-queue/1.0.0: 1515 | resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} 1516 | engines: {node: '>=12.20'} 1517 | dev: true 1518 | --------------------------------------------------------------------------------