Skip to content

Commit

Permalink
feat(stylesheet): rework box model style parsing (#1535)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeetiss authored Dec 18, 2021
1 parent 5d2d688 commit 1f0eb6e
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 63 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-zoos-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@react-pdf/stylesheet': minor
---

fixed `margin: auto` parsing
1 change: 1 addition & 0 deletions packages/stylesheet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"color-string": "^1.5.3",
"hsl-to-hex": "^1.0.0",
"media-engine": "^1.0.3",
"postcss-value-parser": "^4.1.0",
"ramda": "^0.26.1"
},
"files": [
Expand Down
112 changes: 72 additions & 40 deletions packages/stylesheet/src/expand/boxModel.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,81 @@
import * as R from 'ramda';

const BOX_MODEL_REGEX = /-?\d+(\.\d+)?(px|in|mm|cm|pt|%|vw|vh|px)?/g;

const matchBoxModelValue = R.match(BOX_MODEL_REGEX);

const expandBoxModel = model => (key, value) => {
if (value === 'auto')
return {
[`${model}Top`]: 'auto',
[`${model}Right`]: 'auto',
[`${model}Bottom`]: 'auto',
[`${model}Left`]: 'auto',
};

const match = matchBoxModelValue(`${value}`);

if (match) {
const top = match[0];
const right = match[1] || match[0];
const bottom = match[2] || match[0];
const left = match[3] || match[1] || match[0];

if (key.match(/Horizontal$/)) {
return {
[`${model}Right`]: right,
[`${model}Left`]: left,
};
/* eslint-disable no-plusplus */
import parse from 'postcss-value-parser/lib/parse';
import parseUnit from 'postcss-value-parser/lib/unit';

const BOX_MODEL_UNITS = 'px,in,mm,cm,pt,%,vw,vh';

const logError = (style, value) => {
console.error(`
@react-pdf/stylesheet parsing error:
${style}: ${value},
${' '.repeat(style.length + 2)}^
Unsupported ${style} value format
`);
};

const expandBoxModel = ({
expandsTo,
maxValues = 1,
autoSupported = false,
} = {}) => (model, value) => {
const nodes = parse(`${value}`);

const parts = [];

for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];

// value contains `calc`, `url` or other css function
// `,`, `/` or strings that unsupported by margin and padding
if (
node.type === 'function' ||
node.type === 'string' ||
node.type === 'div'
) {
logError(model, value);

return {};
}

if (key.match(/Vertical$/)) {
return {
[`${model}Top`]: top,
[`${model}Bottom`]: bottom,
};
if (node.type === 'word') {
if (node.value === 'auto' && autoSupported) {
parts.push(node.value);
} else {
const result = parseUnit(node.value);

// when unit isn't specified this condition is true
if (result && BOX_MODEL_UNITS.includes(result.unit)) {
parts.push(node.value);
} else {
logError(model, value);

return {};
}
}
}
}

// checks that we have enough parsed values
if (parts.length > maxValues) {
logError(model, value);

return {};
}

const first = parts[0];

if (expandsTo) {
const second = parts[1] || parts[0];
const third = parts[2] || parts[0];
const fourth = parts[3] || parts[1] || parts[0];

return {
[`${model}Top`]: top,
[`${model}Right`]: right,
[`${model}Bottom`]: bottom,
[`${model}Left`]: left,
};
return expandsTo({ first, second, third, fourth });
}

return value;
return {
[model]: first,
};
};

export default expandBoxModel;
30 changes: 24 additions & 6 deletions packages/stylesheet/src/expand/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
import processFlex from './flex';
import processMargin from './margins';
import {
processMargin,
processMarginVertical,
processMarginHorizontal,
processMarginSingle,
} from './margins';
import processBorders from './borders';
import processPadding from './paddings';
import {
processPadding,
processPaddingVertical,
processPaddingHorizontal,
processPaddingSingle,
} from './paddings';
import processObjectPosition from './objectPosition';
import processTransformOrigin from './transformOrigin';

const shorthands = {
flex: processFlex,
margin: processMargin,
marginHorizontal: processMargin,
marginVertical: processMargin,
marginHorizontal: processMarginHorizontal,
marginVertical: processMarginVertical,
marginTop: processMarginSingle,
marginRight: processMarginSingle,
marginBottom: processMarginSingle,
marginLeft: processMarginSingle,
padding: processPadding,
paddingHorizontal: processPadding,
paddingVertical: processPadding,
paddingHorizontal: processPaddingHorizontal,
paddingVertical: processPaddingVertical,
paddingTop: processPaddingSingle,
paddingRight: processPaddingSingle,
paddingBottom: processPaddingSingle,
paddingLeft: processPaddingSingle,
border: processBorders,
borderTop: processBorders,
borderRight: processBorders,
Expand Down
40 changes: 38 additions & 2 deletions packages/stylesheet/src/expand/margins.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
import processBoxModel from './boxModel';

const expandMargin = processBoxModel('margin');
const processMargin = processBoxModel({
expandsTo: ({ first, second, third, fourth }) => ({
marginTop: first,
marginRight: second,
marginBottom: third,
marginLeft: fourth,
}),
maxValues: 4,
autoSupported: true,
});

export default expandMargin;
const processMarginVertical = processBoxModel({
expandsTo: ({ first, second }) => ({
marginTop: first,
marginBottom: second,
}),
maxValues: 2,
autoSupported: true,
});

const processMarginHorizontal = processBoxModel({
expandsTo: ({ first, second }) => ({
marginRight: first,
marginLeft: second,
}),
maxValues: 2,
autoSupported: true,
});

const processMarginSingle = processBoxModel({
autoSupported: true,
});

export {
processMargin,
processMarginVertical,
processMarginHorizontal,
processMarginSingle,
};
35 changes: 33 additions & 2 deletions packages/stylesheet/src/expand/paddings.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
import processBoxModel from './boxModel';

const expandPadding = processBoxModel('padding');
const processPadding = processBoxModel({
expandsTo: ({ first, second, third, fourth }) => ({
paddingTop: first,
paddingRight: second,
paddingBottom: third,
paddingLeft: fourth,
}),
maxValues: 4,
});

export default expandPadding;
const processPaddingVertical = processBoxModel({
expandsTo: ({ first, second }) => ({
paddingTop: first,
paddingBottom: second,
}),
maxValues: 2,
});

const processPaddingHorizontal = processBoxModel({
expandsTo: ({ first, second }) => ({
paddingRight: first,
paddingLeft: second,
}),
maxValues: 2,
});

const processPaddingSingle = processBoxModel();

export {
processPadding,
processPaddingVertical,
processPaddingHorizontal,
processPaddingSingle,
};
Loading

0 comments on commit 1f0eb6e

Please sign in to comment.