Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-grid] Implement autoplacement (#1148) #1151

Merged
merged 46 commits into from Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
25e9bc5
[css-grid] Implement Autoplacement feature
bogdan0083 Oct 24, 2018
72f7a13
[css-grid] Add test cases for autoplacement
bogdan0083 Oct 24, 2018
8c1279e
[css-grid] fix grid-template-rows/columns values
bogdan0083 Oct 24, 2018
1dd4eac
[css-grid] add support for 'grid-auto-flow' property in autoplacement
bogdan0083 Oct 24, 2018
e253bb7
[refactor] move part of functionality to grid-rows-columns hack
bogdan0083 Oct 24, 2018
c62db47
[css-grid] Add test cases for grid-auto-flow and for rows warning
bogdan0083 Oct 24, 2018
5338805
update size limit
bogdan0083 Oct 24, 2018
82e28bb
[css-grid] Comment out grid-auto-flow warning (at least for now)
bogdan0083 Oct 25, 2018
522d45a
[css-grid] Show warning when grid-auto-flow: dense is used
bogdan0083 Oct 25, 2018
61c5a27
[css-grid] add FIXME about commented out warning
bogdan0083 Oct 25, 2018
8da5b59
update size limit again to make CI pass
bogdan0083 Oct 25, 2018
94c09fa
[css-grid] Show grid-auto-flow warning only if grid template is present
bogdan0083 Oct 25, 2018
9a6b9ad
[css-grid] Fix warnings
bogdan0083 Oct 26, 2018
cd51a65
[refactor] Add comments
bogdan0083 Oct 26, 2018
cdab55b
[css-grid] Add support for grid: 'autoplace'
bogdan0083 Oct 27, 2018
88be1ed
[css-grid] Remove the unneeded output
bogdan0083 Oct 27, 2018
c14d9c9
update size limit value
bogdan0083 Oct 27, 2018
b243f7f
[css-grid] Add autoplace conditional comment
bogdan0083 Oct 27, 2018
739e6e6
[css-grid] Add test cases with autoplace conditional comments
bogdan0083 Oct 27, 2018
02284f1
[playground] Add support for grid autoplacement
bogdan0083 Oct 27, 2018
c127917
[refactor] Remove todo comment
bogdan0083 Oct 28, 2018
4e7407d
[css-grid] Change autoplace conditional comment and fix test cases
bogdan0083 Oct 28, 2018
8368e08
update size limit value
bogdan0083 Oct 28, 2018
4767743
update readme.md
bogdan0083 Oct 28, 2018
83a9abc
update readme 2
bogdan0083 Oct 28, 2018
38c95ab
Adding a table of contents
Dan503 Oct 29, 2018
7ea4758
Fixing FAQ heading levels
Dan503 Oct 29, 2018
75c5d02
Grid autoplacement readme updates
Dan503 Oct 29, 2018
4894aab
(alias for deprecated value `on`) text in readme
Dan503 Oct 29, 2018
5af6a75
[css-grid] fix grid areas algorithm
bogdan0083 Oct 29, 2018
aaab224
Merge remote-tracking branch 'dan/feature/grid-autoplacement' into fe…
bogdan0083 Oct 29, 2018
f575cb3
[css-grid] Add test to check the output for different grid options
bogdan0083 Oct 30, 2018
890fcf4
Updating readme with "no-autoplace" grid setting.
Dan503 Oct 30, 2018
17952a7
Readme "Do not create `::before` and `::after` pseudo elements" section
Dan503 Oct 30, 2018
6e47c0b
Fixing ::before/::after example in readme
Dan503 Oct 30, 2018
5166035
Removed word "both" (there are 3 items)
Dan503 Oct 30, 2018
1acbfa8
Minor readme fixes
Oct 31, 2018
63f3a60
[css-grid] Add warning when grid-gap is used without template or auto…
bogdan0083 Nov 6, 2018
19e9c11
[css-grid] fix grid-gap warnings
bogdan0083 Nov 6, 2018
8c2d43f
update size limit
bogdan0083 Nov 6, 2018
9ebbccc
Added section about changing the grid-gap value to the Autoplacement …
Dan503 Nov 8, 2018
e6c061a
Adding note about the lack of auto-fit and auto-fill support
Dan503 Nov 10, 2018
d69792b
Fixing inconsistent indentation in Readme
Dan503 Nov 10, 2018
aee51bb
[css-grid] fix rows/columns values
bogdan0083 Nov 10, 2018
309525f
[css-grid] Add warning for grid-template-columns property
bogdan0083 Nov 11, 2018
c77e86c
Merge branch 'master' into feature/grid-autoplacement
ai Dec 3, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
439 changes: 413 additions & 26 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gulpfile.js
Expand Up @@ -97,7 +97,7 @@ gulp.task('compile-playground', () => {
let autoprefixer = require('./build')
return gulp.src('./playground/input.css')
.pipe(rename('output.css'))
.pipe(postcss([autoprefixer({ grid: true })]))
.pipe(postcss([autoprefixer({ grid: 'autoplace' })]))
.pipe(gulp.dest('./playground'))
})

Expand Down
83 changes: 75 additions & 8 deletions lib/hacks/grid-rows-columns.js
@@ -1,8 +1,12 @@
let Declaration = require('../declaration')
let {
prefixTrackProp,
prefixTrackValue
prefixTrackValue,
autoplaceGridItems,
getGridGap,
inheritGridGap
} = require('./grid-utils')
let Processor = require('../processor')

class GridRowsColumns extends Declaration {
static names = [
Expand All @@ -27,14 +31,77 @@ class GridRowsColumns extends Declaration {
return prop.replace(/^grid-(rows|columns)/, 'grid-template-$1')
}

/**
* Change repeating syntax for IE
*/
set (decl, prefix) {
if (prefix === '-ms-' && decl.value.indexOf('repeat(') !== -1) {
decl.value = prefixTrackValue({ value: decl.value })
insert (decl, prefix, prefixes, result) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)

let { parent, prop, value } = decl
let isRowProp = prop.includes('rows')
let isColumnProp = prop.includes('columns')

let hasGridTemplate = parent.some(i =>
i.prop === 'grid-template' || i.prop === 'grid-template-areas')

/**
* Not to prefix rows declaration if grid-template(-areas) is present
*/
if (hasGridTemplate && isRowProp) {
return false
}

let processor = new Processor({})
let status = processor.gridStatus(parent, result)
let gap = getGridGap(decl)
gap = inheritGridGap(decl, gap) || gap

let gapValue = isRowProp ? gap.row : gap.column

if ((status === 'no-autoplace' || status === true) && !hasGridTemplate) {
gapValue = null
}

let prefixValue = prefixTrackValue({
value,
gap: gapValue
})

/**
* Insert prefixes
*/
decl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixValue
})

let autoflow = parent.nodes.find(i => i.prop === 'grid-auto-flow')
let autoflowValue = 'row'

if (autoflow && !processor.disabled(autoflow, result)) {
autoflowValue = autoflow.value.trim()
}

/**
* Show warning if grid-template-rows decl is not found
*/
let rowDecl = parent.nodes.find(i => i.prop === 'grid-template-rows')

if (!rowDecl && hasGridTemplate) {
return undefined
} else if (!rowDecl && !hasGridTemplate) {
decl.warn(result,
`Autoplacement does not work without grid-template-rows property`
)
return undefined
}
return super.set(decl, prefix)

/**
* Autoplace grid items
*/
let autoplaceEnabled = status === 'autoplace'
if (isColumnProp && !hasGridTemplate && autoplaceEnabled) {
autoplaceGridItems(decl, result, gap, autoflowValue)
}

return undefined
}
}

Expand Down
47 changes: 9 additions & 38 deletions lib/hacks/grid-template-areas.js
Expand Up @@ -26,52 +26,23 @@ class GridTemplateAreas extends Declaration {
let hasRows = false
let parent = decl.parent
let gap = getGridGap(decl)
let inheritedGap = inheritGridGap(decl, gap)
gap = inheritGridGap(decl, gap) || gap

// remove already prefixed rows and columns
// without gutter to prevent doubling prefixes
parent.walkDecls(/-ms-grid-(rows|columns)/, i => i.remove())
// remove already prefixed rows
// to prevent doubling prefixes
parent.walkDecls(/-ms-grid-rows/, i => i.remove())

// add empty tracks to rows and columns
// add empty tracks to rows
parent.walkDecls(/grid-template-(rows|columns)/, trackDecl => {
if (trackDecl.prop === 'grid-template-rows') {
hasRows = true
let { prop, value } = trackDecl

/**
* we must insert inherited gap values in some cases:
* if we are inside media query && if we have no grid-gap value
*/
if (inheritedGap) {
trackDecl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixTrackValue({ value, gap: inheritedGap.row })
})
} else {
trackDecl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixTrackValue({ value, gap: gap.row })
})
}
trackDecl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixTrackValue({ value, gap: gap.row })
})
} else {
hasColumns = true
let { prop, value } = trackDecl

/**
* we must insert inherited gap values in some cases:
* if we are inside media query && if we have no grid-gap value
*/
if (inheritedGap) {
trackDecl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixTrackValue({ value, gap: inheritedGap.column })
})
} else {
trackDecl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixTrackValue({ value, gap: gap.column })
})
}
}
})

Expand Down
106 changes: 105 additions & 1 deletion lib/hacks/grid-utils.js
Expand Up @@ -525,6 +525,7 @@ function insertAreas (css, isDisabled) {

if ((!rule.hasDuplicates || !hasDuplicateName) && !rule.params) {
// grid-template has no duplicates and not inside media rule

getMSDecls(area, false, false).reverse()
.forEach(i => gridAreaRule.prepend(
Object.assign(i, {
Expand Down Expand Up @@ -945,6 +946,108 @@ function warnGridGap ({
}
}

/**
* normalize the grid-template-rows/columns values
* @param {String} str grid-template-rows/columns value
* @return {Array} normalized array with values
* @example
* let normalized = normalizeRowColumn('1fr repeat(2, 20px 50px) 1fr')
* normalized // <= ['1fr', '20px', '50px', '20px', '50px', '1fr']
*/
function normalizeRowColumn (str) {
let normalized = parser(str)
.nodes
.reduce((result, node) => {
if (node.type === 'function' && node.value === 'repeat') {
let key = 'count'

let [count, value] = node.nodes.reduce((acc, n) => {
if (n.type === 'word' && key === 'count') {
acc[0] = Math.abs(parseInt(n.value))
return acc
}
if (n.type === 'div' && n.value === ',') {
key = 'value'
return acc
}
if (key === 'value') {
acc[1] += parser.stringify(n)
}
return acc
}, [0, ''])

if (count) {
for (let i = 0; i < count; i++) {
result.push(value)
}
}

return result
}
if (node.type === 'space') {
return result
}
return result.concat(parser.stringify(node))
}, [])

return normalized
}

/**
* Autoplace grid items
* @param {Declaration} decl
* @param {Result} result
* @param {Object} gap gap values
* @param {String} autoflowValue grid-auto-flow value
* @return {void}
* @see https://github.com/postcss/autoprefixer/issues/1148
*/
function autoplaceGridItems (decl, result, gap, autoflowValue = 'row') {
let { parent } = decl

let rowDecl = parent.nodes.find(i => i.prop === 'grid-template-rows')
let rows = normalizeRowColumn(rowDecl.value)
let columns = normalizeRowColumn(decl.value)

// Build array of area names with dummy values. If we have 3 columns and
// 2 rows, filledRows will be equal to ['1 2 3', '4 5 6']
let filledRows = rows.map((_, rowIndex) => {
return Array.from({ length: columns.length }, (v, k) =>
k + (rowIndex * columns.length) + 1).join(' ')
})

let areas = parseGridAreas({ rows: filledRows, gap })
let keys = Object.keys(areas)
let items = keys.map(i => areas[i])

// Change the order of cells if grid-auto-flow value is 'column'
if (autoflowValue.includes('column')) {
items = items.sort((a, b) => a.column.start - b.column.start)
}

// Insert new rules
items.reverse().forEach((item, index) => {
let { column, row } = item
let nodeSelector = parent.selectors.map(sel =>
sel + ` > *:nth-child(${ keys.length - index })`).join(', ')

// create new rule
let node = parent.clone().removeAll()

// change rule selector
node.selector = nodeSelector

// insert prefixed row/column values
node.append({ prop: '-ms-grid-row', value: row.start })
node.append({ prop: '-ms-grid-column', value: column.start })

// insert rule
parent.after(node)
})

return undefined
}

module.exports = {
parse,
translate,
Expand All @@ -959,5 +1062,6 @@ module.exports = {
warnGridGap,
warnTemplateSelectorNotFound,
warnIfGridRowColumnExists,
inheritGridGap
inheritGridGap,
autoplaceGridItems
}