From 4ec34fdbea110b5f50fb12694d5004a466199336 Mon Sep 17 00:00:00 2001 From: Joren Broekema Date: Fri, 17 May 2024 11:54:22 +0200 Subject: [PATCH] fix: pass options to transforms filters, live demo main page (#1208) --- .changeset/serious-years-jam.md | 5 + __tests__/common/transforms.test.js | 39 ++--- docs/public/demo-tokens.json | 237 ++++++++++++++++++++++++++++ docs/src/content/docs/index.mdx | 11 ++ docs/src/remark-playground.ts | 1 - lib/common/transforms.js | 72 +++++---- 6 files changed, 315 insertions(+), 50 deletions(-) create mode 100644 .changeset/serious-years-jam.md create mode 100644 docs/public/demo-tokens.json diff --git a/.changeset/serious-years-jam.md b/.changeset/serious-years-jam.md new file mode 100644 index 000000000..02ad8f135 --- /dev/null +++ b/.changeset/serious-years-jam.md @@ -0,0 +1,5 @@ +--- +'style-dictionary': patch +--- + +Pass options to all of the filter functions in our built-in transforms, to check for `usesDTCG` and `$type` property. diff --git a/__tests__/common/transforms.test.js b/__tests__/common/transforms.test.js index c0ba04924..b3e1b4586 100644 --- a/__tests__/common/transforms.test.js +++ b/__tests__/common/transforms.test.js @@ -1311,52 +1311,53 @@ describe('common', () => { describe('transform filters', () => { describe('isColor', () => { it('should match short hex colors', () => { - expect(isColor({ type: 'color', value: '369' })).to.be.true; - expect(isColor({ type: 'color', value: '#369' })).to.be.true; + expect(isColor({ type: 'color', value: '369' }, {})).to.be.true; + expect(isColor({ type: 'color', value: '#369' }, {})).to.be.true; }); it('should match standard hex colors', () => { - expect(isColor({ type: 'color', value: 'e66465' })).to.be.true; - expect(isColor({ type: 'color', value: '#e66465' })).to.be.true; + expect(isColor({ type: 'color', value: 'e66465' }, {})).to.be.true; + expect(isColor({ type: 'color', value: '#e66465' }, {})).to.be.true; }); it('should match 8-digit hex colors', () => { - expect(isColor({ type: 'color', value: 'e66465FF' })).to.be.true; - expect(isColor({ type: 'color', value: '#e66465FF' })).to.be.true; + expect(isColor({ type: 'color', value: 'e66465FF' }, {})).to.be.true; + expect(isColor({ type: 'color', value: '#e66465FF' }, {})).to.be.true; }); it('should match legacy rgb/rgba colors', () => { - expect(isColor({ type: 'color', value: 'rgb(132, 99, 255)' })).to.be.true; - expect(isColor({ type: 'color', value: 'rgb(132, 99, 255, 0.5)' })).to.be.true; - expect(isColor({ type: 'color', value: 'rgba(132, 99, 255, 0.5)' })).to.be.true; + expect(isColor({ type: 'color', value: 'rgb(132, 99, 255)' }, {})).to.be.true; + expect(isColor({ type: 'color', value: 'rgb(132, 99, 255, 0.5)' }, {})).to.be.true; + expect(isColor({ type: 'color', value: 'rgba(132, 99, 255, 0.5)' }, {})).to.be.true; }); it('should match rgb colors', () => { - expect(isColor({ type: 'color', value: 'rgb(132 99 255)' })).to.be.true; - expect(isColor({ type: 'color', value: 'rgb(132 99 255 / .5)' })).to.be.true; - expect(isColor({ type: 'color', value: 'rgb(132 99 255 / 50%)' })).to.be.true; + expect(isColor({ type: 'color', value: 'rgb(132 99 255)' }, {})).to.be.true; + expect(isColor({ type: 'color', value: 'rgb(132 99 255 / .5)' }, {})).to.be.true; + expect(isColor({ type: 'color', value: 'rgb(132 99 255 / 50%)' }, {})).to.be.true; }); it('should match legacy hsl/hsla colors', () => { - expect(isColor({ type: 'color', value: 'hsl(30, 100%, 50%, 0.6)' })).to.be.true; - expect(isColor({ type: 'color', value: 'hsla(30, 100%, 50%, 0.6)' })).to.be.true; + expect(isColor({ type: 'color', value: 'hsl(30, 100%, 50%, 0.6)' }, {})).to.be.true; + expect(isColor({ type: 'color', value: 'hsla(30, 100%, 50%, 0.6)' }, {})).to.be.true; }); it('should match hsl colors', () => { - expect(isColor({ type: 'color', value: 'hsl(30 100% 50% / .6)' })).to.be.true; - expect(isColor({ type: 'color', value: 'hsl(30.2 100% 50% / 60%)' })).to.be.true; + expect(isColor({ type: 'color', value: 'hsl(30 100% 50% / .6)' }, {})).to.be.true; + expect(isColor({ type: 'color', value: 'hsl(30.2 100% 50% / 60%)' }, {})).to.be.true; }); it('should match named colors', () => { - expect(isColor({ type: 'color', value: 'red' })).to.be.true; + expect(isColor({ type: 'color', value: 'red' }, {})).to.be.true; }); it('should ignore gradients', () => { - expect(isColor({ type: 'color', value: 'linear-gradient(#e66465, #9198e5)' })).to.be.false; + expect(isColor({ type: 'color', value: 'linear-gradient(#e66465, #9198e5)' }, {})).to.be + .false; }); it('should ignore values that cannot convert to a color', () => { - expect(isColor({ type: 'color', value: 'currentColor' })).to.be.false; + expect(isColor({ type: 'color', value: 'currentColor' }, {})).to.be.false; }); }); }); diff --git a/docs/public/demo-tokens.json b/docs/public/demo-tokens.json new file mode 100644 index 000000000..ffdbfa8c1 --- /dev/null +++ b/docs/public/demo-tokens.json @@ -0,0 +1,237 @@ +{ + "colors": { + "$type": "color", + "black": { + "$value": "#000000" + }, + "white": { + "$value": "#ffffff" + }, + "orange": { + "100": { + "$value": "#fffaf0" + }, + "200": { + "$value": "#feebc8" + }, + "300": { + "$value": "#fbd38d" + }, + "400": { + "$value": "#f6ad55" + }, + "500": { + "$value": "#ed8936" + }, + "600": { + "$value": "#dd6b20" + }, + "700": { + "$value": "#c05621" + }, + "800": { + "$value": "#9c4221" + }, + "900": { + "$value": "#7b341e" + } + } + }, + "dimensions": { + "$type": "dimension", + "0": { + "$value": "0px" + }, + "1": { + "$value": "4px" + }, + "2": { + "$value": "8px" + }, + "3": { + "$value": "12px" + }, + "4": { + "$value": "16px" + }, + "5": { + "$value": "20px" + }, + "6": { + "$value": "24px" + }, + "7": { + "$value": "28px" + }, + "8": { + "$value": "32px" + }, + "9": { + "$value": "36px" + }, + "10": { + "$value": "40px" + }, + "11": { + "$value": "44px" + }, + "12": { + "$value": "48px" + }, + "13": { + "$value": "52px" + }, + "14": { + "$value": "56px" + }, + "15": { + "$value": "60px" + }, + "max": { + "$value": "9999px" + } + }, + "text": { + "fonts": { + "$type": "fontFamily", + "serif": { + "$value": "Times New Roman, serif" + }, + "sans": { + "$value": "Open Sans, sans-serif" + } + }, + "weights": { + "$type": "fontWeight", + "light": { + "$value": "thin" + }, + "regular": { + "$value": "regular" + }, + "bold": { + "$value": "extra-bold" + } + }, + "lineHeights": { + "$type": "number", + "normal": { + "$value": 1.2 + }, + "large": { + "$value": 1.8 + } + }, + "typography": { + "$type": "typography", + "heading": { + "$value": { + "fontFamily": "{text.fonts.sans}", + "fontWeight": "{text.weights.bold}", + "fontSize": "{dimensions.7}", + "lineHeight": "{text.lineHeights.large}" + } + }, + "body": { + "$value": { + "fontFamily": "{text.fonts.serif}", + "fontWeight": "{text.weights.regular}", + "fontSize": "{dimensions.4}", + "lineHeight": "{text.lineHeights.normal}" + } + } + } + }, + "transitions": { + "$type": "transition", + "emphasis": { + "$value": { + "duration": "{transitions.durations.medium}", + "delay": "{transitions.durations.instant}", + "timingFunction": "{transitions.easingFunctions.accelerate}" + } + }, + "fade": { + "$value": { + "duration": "{transitions.durations.long}", + "delay": "{transitions.durations.instant}", + "timingFunction": "{transitions.easingFunctions.decelerate}" + } + }, + "easingFunctions": { + "$type": "cubicBezier", + "accelerate": { + "$value": [0.5, 0, 1, 1] + }, + "decelerate": { + "$value": [0, 0, 0.5, 1] + } + }, + "durations": { + "$type": "duration", + "instant": { + "$value": "0ms" + }, + "short": { + "$value": "100ms" + }, + "medium": { + "$value": "300ms" + }, + "long": { + "$value": "600ms" + } + } + }, + "borders": { + "$type": "border", + "heavy": { + "$value": { + "color": "{colors.black}", + "width": "{dimensions.1}", + "style": "{borders.styles.solid}" + } + }, + "wireframe": { + "$value": { + "color": "{colors.orange.600}", + "width": "{dimensions.2}", + "style": "{borders.styles.dashed}" + } + }, + "styles": { + "$type": "strokeStyle", + "solid": { + "$value": "solid" + }, + "dashed": { + "$value": { + "dashArray": ["0.5rem", "0.25rem"], + "lineCap": "round" + } + } + } + }, + "shadows": { + "$type": "shadow", + "sm": { + "$value": { + "color": "{colors.black}", + "offsetX": "{dimensions.0}", + "offsetY": "{dimensions.1}", + "blur": "{dimensions.3}" + } + }, + "lg": { + "$value": { + "color": "{colors.black}", + "offsetX": "{dimensions.0}", + "offsetY": "{dimensions.2}", + "blur": "{dimensions.4}" + } + }, + "multi": { + "$value": ["{shadows.sm}", "{shadows.lg}"] + } + } +} diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 9a8186c18..0b9e212e0 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -20,3 +20,14 @@ hero: link: https://github.com/amzn/style-dictionary icon: external --- + +import tokens from '/public/demo-tokens.json'; + +## Live Demo + +Below is a showcase of how a set of DTCG tokens would be exported to CSS: + + + +
+
diff --git a/docs/src/remark-playground.ts b/docs/src/remark-playground.ts index 7ec664f78..0ca752fde 100644 --- a/docs/src/remark-playground.ts +++ b/docs/src/remark-playground.ts @@ -54,7 +54,6 @@ const paragraphVisitor = ( script="${scriptData}" >
`, } as Html; - parent.children.splice(index, skipAmount, newNode); } }; diff --git a/lib/common/transforms.js b/lib/common/transforms.js index efb455a30..565cfa41e 100644 --- a/lib/common/transforms.js +++ b/lib/common/transforms.js @@ -38,42 +38,50 @@ const camelOpts = { /** * @param {Token} token + * @param {Config} options * @returns {boolean} */ -export function isColor(token) { - return token.type === 'color' && Color(token.$value ?? token.value).isValid(); +export function isColor(token, options) { + return ( + (options.usesDtcg ? token.$type : token.type) === 'color' && + Color(options.usesDtcg ? token.$value : token.value).isValid() + ); } /** * @param {Token} token + * @param {Config} options * @returns {boolean} */ -function isDimension(token) { - return token.type === 'dimension'; +function isDimension(token, options) { + return (options.usesDtcg ? token.$type : token.type) === 'dimension'; } /** * @param {Token} token + * @param {Config} options * @returns {boolean} */ -function isFontSize(token) { - return token.type === 'fontSize'; +function isFontSize(token, options) { + return (options.usesDtcg ? token.$type : token.type) === 'fontSize'; } /** * @param {Token} token + * @param {Config} options * @returns {boolean} */ -function isAsset(token) { - return token.type === 'asset'; +function isAsset(token, options) { + return (options.usesDtcg ? token.$type : token.type) === 'asset'; } /** * @param {Token} token + * @param {Config} options * @returns {boolean} */ -function isContent(token) { - return token.type === 'content'; +function isContent(token, options) { + return (options.usesDtcg ? token.$type : token.type) === 'content'; } /** @@ -679,7 +687,7 @@ export default { */ 'size/object': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, config, options) { const value = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(value); @@ -753,7 +761,7 @@ export default { */ 'size/px': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, _, options) { const value = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(value); @@ -775,7 +783,7 @@ export default { */ 'size/rem': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, _, options) { const nonParsed = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(nonParsed); @@ -797,7 +805,7 @@ export default { */ 'size/remToPt': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, config, options) { const value = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(value); @@ -887,7 +895,7 @@ export default { */ 'size/swift/remToCGFloat': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, config, options) { const value = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(value); @@ -910,7 +918,7 @@ export default { */ 'size/remToPx': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, config, options) { const value = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(value); @@ -934,7 +942,7 @@ export default { */ 'size/pxToRem': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: (token, config, options) => { const value = options.usesDtcg ? token.$value : token.value; const parsedVal = parseFloat(value); @@ -965,8 +973,8 @@ export default { */ 'html/icon': { type: 'value', - filter: function (token) { - return token.type === 'html'; + filter: function (token, options) { + return (options.usesDtcg ? token.$type : token.type) === 'html'; }, transform: function (token, _, options) { return (options.usesDtcg ? token.$value : token.value).replace( @@ -1049,8 +1057,8 @@ export default { */ 'time/seconds': { type: 'value', - filter: function (token) { - return token.type === 'time'; + filter: function (token, options) { + return (options.usesDtcg ? token.$type : token.type) === 'time'; }, transform: function (token, _, options) { return (parseFloat(options.usesDtcg ? token.$value : token.value) / 1000).toFixed(2) + 's'; @@ -1072,7 +1080,7 @@ export default { */ 'fontFamily/css': { type: 'value', - filter: (token) => token.type === 'fontFamily', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'fontFamily', transform: (token, _, options) => { /** @type {string|string[]} */ const fontFamily = options.usesDtcg ? token.$value : token.value; @@ -1096,7 +1104,7 @@ export default { */ 'cubicBezier/css': { type: 'value', - filter: (token) => token.type === 'cubicBezier', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'cubicBezier', transform: (token, _, options) => { /** @type {number[]|string} */ const cubicBezier = options.usesDtcg ? token.$value : token.value; @@ -1121,7 +1129,7 @@ export default { type: 'value', // border properties can be references transitive: true, - filter: (token) => token.type === 'strokeStyle', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'strokeStyle', transform: (token, _, options) => { const val = options.usesDtcg ? token.$value : token.value; if (typeof val !== 'object') { @@ -1148,7 +1156,7 @@ export default { type: 'value', // border properties can be references transitive: true, - filter: (token) => token.type === 'border', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'border', transform: (token, _, options) => { const val = options.usesDtcg ? token.$value : token.value; if (typeof val !== 'object') { @@ -1188,7 +1196,7 @@ export default { type: 'value', // typography properties can be references transitive: true, - filter: (token) => token.type === 'typography', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'typography', transform: (token, platform, options) => { const val = options.usesDtcg ? token.$value : token.value; if (typeof val !== 'object') { @@ -1244,7 +1252,7 @@ export default { type: 'value', // transition properties can be references transitive: true, - filter: (token) => token.type === 'transition', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'transition', transform: (token, _, options) => { const val = options.usesDtcg ? token.$value : token.value; if (typeof val !== 'object') { @@ -1273,7 +1281,7 @@ export default { type: 'value', // shadow properties can be references transitive: true, - filter: (token) => token.type === 'shadow', + filter: (token, options) => (options.usesDtcg ? token.$type : token.type) === 'shadow', transform: (token, _, options) => { const val = options.usesDtcg ? token.$value : token.value; if (typeof val !== 'object') { @@ -1283,6 +1291,10 @@ export default { /** @param {any} val */ const stringifyShadow = (val) => { + // check if the shadows are objects, they might already be transformed to strings if they were refs + if (typeof val !== 'object') { + return val; + } const { type, color, offsetX, offsetY, blur, spread } = val; return `${type ? `${type} ` : ''}${offsetX ?? 0} ${offsetY ?? 0} ${blur ?? 0} ${ spread ? `${spread} ` : '' @@ -1420,7 +1432,7 @@ export default { */ 'content/flutter/literal': { type: 'value', - filter: (token) => isContent(token), + filter: isContent, transform: (token, _, options) => wrapValueWithDoubleQuote(token, options), }, @@ -1452,7 +1464,7 @@ export default { */ 'size/flutter/remToDouble': { type: 'value', - filter: (token) => isDimension(token) || isFontSize(token), + filter: (token, options) => isDimension(token, options) || isFontSize(token, options), transform: function (token, config, options) { const baseFont = getBasePxFontSize(config); return (parseFloat(options.usesDtcg ? token.$value : token.value) * baseFont).toFixed(2);