Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 61 additions & 4 deletions lib/hacks/grid-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,30 @@ function selectorsEqual(ruleA, ruleB) {
})
}

function selectorStartsWith(base, selector) {
if (!selector.startsWith(base)) {
return false
}

let next = selector[base.length]
return !next || /[\s.#[:>+~]/.test(next)
}

function selectorMayOverlap(previous, current) {
let base = previous.replace(/\s*\*\s*/g, ' ').replace(/\s+/g, ' ').trim()
let selector = current.replace(/\s+/g, ' ').trim()

return !base || selectorStartsWith(base, selector)
}

function selectorsMayOverlap(previous, current) {
return previous.some(previousSelector => {
return current.some(currentSelector => {
return selectorMayOverlap(previousSelector, currentSelector)
})
})
}

/**
* Parse data from all grid-template(-areas) declarations
* @param {Root} css css root
Expand Down Expand Up @@ -483,6 +507,7 @@ function insertAreas(css, isDisabled) {

// we need to store the rules that we will insert later
let rulesToInsert = {}
let previousGridAreas = []

css.walkDecls('grid-area', gridArea => {
let gridAreaRule = gridArea.parent
Expand Down Expand Up @@ -515,6 +540,20 @@ function insertAreas(css, isDisabled) {
return false
}

function shouldResetSpan(rule, area, dimension) {
return previousGridAreas.some(previous => {
if (previous.data !== data) {
return false
}
if (!selectorsMayOverlap(previous.selectors, gridAreaRule.selectors)) {
return false
}

let previousArea = rule.areas[previous.value]
return previousArea && previousArea[dimension].span > area[dimension].span
})
}

// create the empty object with the key as the last area name
// e.g if we have templates with "a b c" values, "c" will be the last area
if (!rulesToInsert[lastArea]) {
Expand Down Expand Up @@ -553,8 +592,10 @@ function insertAreas(css, isDisabled) {

if ((!rule.hasDuplicates || !hasDuplicateName) && !rule.params) {
// grid-template has no duplicates and not inside media rule
let addRowSpan = shouldResetSpan(rule, area, 'row')
let addColumnSpan = shouldResetSpan(rule, area, 'column')

getMSDecls(area, false, false)
getMSDecls(area, addRowSpan, addColumnSpan)
.reverse()
.forEach(i =>
gridAreaRule.prepend(
Expand All @@ -572,8 +613,11 @@ function insertAreas(css, isDisabled) {
// grid-template has duplicates and not inside media rule
let cloned = gridAreaRule.clone()
cloned.removeAll()
let addRowSpan = area.row.updateSpan || shouldResetSpan(rule, area, 'row')
let addColumnSpan =
area.column.updateSpan || shouldResetSpan(rule, area, 'column')

getMSDecls(area, area.row.updateSpan, area.column.updateSpan)
getMSDecls(area, addRowSpan, addColumnSpan)
.reverse()
.forEach(i =>
cloned.prepend(
Expand Down Expand Up @@ -604,7 +648,11 @@ function insertAreas(css, isDisabled) {
// grid-template has duplicates and not inside media rule
// and the selector is complex
gridAreaRule.walkDecls(/-ms-grid-(row|column)/, d => d.remove())
getMSDecls(area, area.row.updateSpan, area.column.updateSpan)
let addRowSpan = area.row.updateSpan || shouldResetSpan(rule, area, 'row')
let addColumnSpan =
area.column.updateSpan || shouldResetSpan(rule, area, 'column')

getMSDecls(area, addRowSpan, addColumnSpan)
.reverse()
.forEach(i =>
gridAreaRule.prepend(
Expand All @@ -622,8 +670,11 @@ function insertAreas(css, isDisabled) {
// rules and merge them easily
let cloned = gridAreaRule.clone()
cloned.removeAll()
let addRowSpan = area.row.updateSpan || shouldResetSpan(rule, area, 'row')
let addColumnSpan =
area.column.updateSpan || shouldResetSpan(rule, area, 'column')

getMSDecls(area, area.row.updateSpan, area.column.updateSpan)
getMSDecls(area, addRowSpan, addColumnSpan)
.reverse()
.forEach(i =>
cloned.prepend(
Expand Down Expand Up @@ -661,6 +712,12 @@ function insertAreas(css, isDisabled) {
}
}

previousGridAreas.push({
data,
selectors: gridAreaRule.selectors,
value
})

return undefined
})

Expand Down
54 changes: 54 additions & 0 deletions test/autoprefixer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,60 @@ test('should merge complex duplicate grid-area rules successfully', () => {
equal(result.css, output)
})

test('resets grid-area spans when overriding a broader area', () => {
let input = `/* autoprefixer grid: autoplace */
body {
display: grid;
grid-template:
"other other"
"one two";
}

body > * {
grid-area: other;
}

body > .one {
grid-area: one;
}

body > .two {
grid-area: two;
}`
let output = `/* autoprefixer grid: autoplace */
body {
display: -ms-grid;
display: grid;
-ms-grid-rows: auto;
grid-template:
"other other"
"one two";
}

body > * {
-ms-grid-row: 1;
-ms-grid-column: 1;
-ms-grid-column-span: 2;
grid-area: other;
}

body > .one {
-ms-grid-row: 2;
-ms-grid-column: 1;
-ms-grid-column-span: 1;
grid-area: one;
}

body > .two {
-ms-grid-row: 2;
-ms-grid-column: 2;
-ms-grid-column-span: 1;
grid-area: two;
}`
let result = postcss([prefixer('grid-area')]).process(input)
equal(result.css, output)
})

test('ignores values for CSS3PIE props', () => {
let css = read('pie')
equal(postcss([compiler]).process(css).css, css)
Expand Down