From 43d913f46191785e063915334daf44f95f3735df Mon Sep 17 00:00:00 2001 From: Balbina K <41303231+BalbinaK@users.noreply.github.com> Date: Fri, 26 Apr 2024 08:03:34 +0200 Subject: [PATCH] feat: support css vars as arbitrary values for margins and paddings (#219) --- src/_rules/spacing.js | 22 ++++----- src/_utils/utilities.js | 2 +- test/__snapshots__/spacing.js.snap | 72 ++++++++++++++++++++++++++++++ test/spacing.js | 42 ++++++++++++++++- 4 files changed, 125 insertions(+), 13 deletions(-) diff --git a/src/_rules/spacing.js b/src/_rules/spacing.js index ee74cab..ee62edd 100644 --- a/src/_rules/spacing.js +++ b/src/_rules/spacing.js @@ -3,31 +3,31 @@ import { directionSize, resolveArbitraryValues, directionMap } from '#utils'; // negatives come in via the negative variant export const padding = [ // empty capture group here sets an empty string for 'direction' instead of undefined - [/^p()-(.\d*)$/, directionSize('padding'), { autocomplete: '(m|p)-' }], - [/^p([xy])-(.\d*)$/, directionSize('padding')], - [/^p([rltb])-(.\d*)$/, directionSize('padding'), { autocomplete: '(m|p)-' }], - // matching arbitrary values + [/^p()-(.+)$/, directionSize('padding'), { autocomplete: '(m|p)-' }], + [/^p([xy])-(.+)$/, directionSize('padding')], + [/^p([rltb])-(.+)$/, directionSize('padding'), { autocomplete: '(m|p)-' }], + // matching arbitrary values containing 'var(--)', '--', or a (negative) number with optional unit [ - /^p-\[(.\d*)(rem|px)?]$/, + /^p-\[(var\(--.+\)|--.+|-?\d+)(rem|px)?]$/, ([, value, unit], context) => ({ padding: resolveArbitraryValues(value, unit, context), }), ], - [/^p([xy])-\[(.\d*)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`padding${i}`, resolveArbitraryValues(value, unit, context)])], - [/^p([rltb])-\[(.\d*)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`padding${i}`, resolveArbitraryValues(value, unit, context)])], + [/^p([xy])-\[(var\(--.+\)|--.+|-?\d+)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`padding${i}`, resolveArbitraryValues(value, unit, context)])], + [/^p([rltb])-\[(var\(--.+\)|--.+|-?\d+)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`padding${i}`, resolveArbitraryValues(value, unit, context)])], ]; export const margin = [ [/^m()-(.+)$/, directionSize('margin')], [/^m([xy])-(.+)$/, directionSize('margin')], [/^m([rltb])-(.+)$/, directionSize('margin')], - // matching arbitrary values + // matching arbitrary values containing 'var(--)', '--', or a (negative) number with optional unit [ - /^m-\[(.\d*)(rem|px)?]$/, + /^m-\[(var\(--.+\)|--.+|-?\d+)(rem|px)?]$/, ([, value, unit], context) => ({ margin: resolveArbitraryValues(value, unit, context), }), ], - [/^m([xy])-\[(.\d*)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`margin${i}`, resolveArbitraryValues(value, unit, context)])], - [/^m([rltb])-\[(.\d*)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`margin${i}`, resolveArbitraryValues(value, unit, context)])], + [/^m([xy])-\[(var\(--.+\)|--.+|-?\d+)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`margin${i}`, resolveArbitraryValues(value, unit, context)])], + [/^m([rltb])-\[(var\(--.+\)|--.+|-?\d+)(rem|px)?]$/, ([, direction, value, unit], context) => directionMap[direction].map((i) => [`margin${i}`, resolveArbitraryValues(value, unit, context)])], ]; diff --git a/src/_utils/utilities.js b/src/_utils/utilities.js index 5191edf..dd9ca59 100644 --- a/src/_utils/utilities.js +++ b/src/_utils/utilities.js @@ -13,7 +13,7 @@ import { percent } from './handlers/handlers.js'; */ export function directionSize(propertyPrefix) { return ([_, direction, size], { theme }) => { - const v = theme.spacing?.[size] ?? h.bracket.global.auto.fraction(size); + const v = theme.spacing?.[size] ?? h.global.auto.fraction(size); if (v != null) return directionMap[direction].map((i) => [`${propertyPrefix}${i}`, v]); }; } diff --git a/test/__snapshots__/spacing.js.snap b/test/__snapshots__/spacing.js.snap index 514c0a2..834f049 100644 --- a/test/__snapshots__/spacing.js.snap +++ b/test/__snapshots__/spacing.js.snap @@ -1,5 +1,38 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`arbitrary margin with css variables works 1`] = ` +"/* layer: default */ +.m-\\[var\\(--w-spacing\\)\\]{margin:var(--w-spacing);} +.mx-\\[var\\(--w-spacing\\)\\]{margin-left:var(--w-spacing);margin-right:var(--w-spacing);} +.my-\\[var\\(--w-spacing\\)\\]{margin-top:var(--w-spacing);margin-bottom:var(--w-spacing);} +.mb-\\[var\\(--w-spacing\\)\\]{margin-bottom:var(--w-spacing);} +.ml-\\[var\\(--w-spacing\\)\\]{margin-left:var(--w-spacing);} +.mr-\\[var\\(--w-spacing\\)\\]{margin-right:var(--w-spacing);} +.mt-\\[var\\(--w-spacing\\)\\]{margin-top:var(--w-spacing);}" +`; + +exports[`arbitrary margin with warp css var and default value works 1`] = ` +"/* layer: default */ +.m-\\[var\\(--w-spacing\\,_8px\\)\\]{margin:var(--w-spacing, 8px);} +.mx-\\[var\\(--w-spacing\\,_8px\\)\\]{margin-left:var(--w-spacing, 8px);margin-right:var(--w-spacing, 8px);} +.my-\\[var\\(--w-spacing\\,_8px\\)\\]{margin-top:var(--w-spacing, 8px);margin-bottom:var(--w-spacing, 8px);} +.mb-\\[var\\(--w-spacing\\,_8px\\)\\]{margin-bottom:var(--w-spacing, 8px);} +.ml-\\[var\\(--w-spacing\\,_8px\\)\\]{margin-left:var(--w-spacing, 8px);} +.mr-\\[var\\(--w-spacing\\,_8px\\)\\]{margin-right:var(--w-spacing, 8px);} +.mt-\\[var\\(--w-spacing\\,_8px\\)\\]{margin-top:var(--w-spacing, 8px);}" +`; + +exports[`arbitrary margin with warp tokens works 1`] = ` +"/* layer: default */ +.m-\\[--w-spacing\\]{margin:var(--w-spacing);} +.mx-\\[--w-spacing\\]{margin-left:var(--w-spacing);margin-right:var(--w-spacing);} +.my-\\[--w-spacing\\]{margin-top:var(--w-spacing);margin-bottom:var(--w-spacing);} +.mb-\\[--w-spacing\\]{margin-bottom:var(--w-spacing);} +.ml-\\[--w-spacing\\]{margin-left:var(--w-spacing);} +.mr-\\[--w-spacing\\]{margin-right:var(--w-spacing);} +.mt-\\[--w-spacing\\]{margin-top:var(--w-spacing);}" +`; + exports[`arbitrary margin works 1`] = ` "/* layer: default */ .m-\\[8\\]{margin:0.8rem;} @@ -25,6 +58,39 @@ exports[`arbitrary margin works 1`] = ` .mt-\\[8rem\\]{margin-top:8rem;}" `; +exports[`arbitrary padding with css variables works 1`] = ` +"/* layer: default */ +.p-\\[var\\(--w-spacing\\)\\]{padding:var(--w-spacing);} +.px-\\[var\\(--w-spacing\\)\\]{padding-left:var(--w-spacing);padding-right:var(--w-spacing);} +.py-\\[var\\(--w-spacing\\)\\]{padding-top:var(--w-spacing);padding-bottom:var(--w-spacing);} +.pb-\\[var\\(--w-spacing\\)\\]{padding-bottom:var(--w-spacing);} +.pl-\\[var\\(--w-spacing\\)\\]{padding-left:var(--w-spacing);} +.pr-\\[var\\(--w-spacing\\)\\]{padding-right:var(--w-spacing);} +.pt-\\[var\\(--w-spacing\\)\\]{padding-top:var(--w-spacing);}" +`; + +exports[`arbitrary padding with warp css var and default value works 1`] = ` +"/* layer: default */ +.p-\\[var\\(--w-spacing\\,_8px\\)\\]{padding:var(--w-spacing, 8px);} +.px-\\[var\\(--w-spacing\\,_8px\\)\\]{padding-left:var(--w-spacing, 8px);padding-right:var(--w-spacing, 8px);} +.py-\\[var\\(--w-spacing\\,_8px\\)\\]{padding-top:var(--w-spacing, 8px);padding-bottom:var(--w-spacing, 8px);} +.pb-\\[var\\(--w-spacing\\,_8px\\)\\]{padding-bottom:var(--w-spacing, 8px);} +.pl-\\[var\\(--w-spacing\\,_8px\\)\\]{padding-left:var(--w-spacing, 8px);} +.pr-\\[var\\(--w-spacing\\,_8px\\)\\]{padding-right:var(--w-spacing, 8px);} +.pt-\\[var\\(--w-spacing\\,_8px\\)\\]{padding-top:var(--w-spacing, 8px);}" +`; + +exports[`arbitrary padding with warp tokens works 1`] = ` +"/* layer: default */ +.p-\\[--w-spacing\\]{padding:var(--w-spacing);} +.px-\\[--w-spacing\\]{padding-left:var(--w-spacing);padding-right:var(--w-spacing);} +.py-\\[--w-spacing\\]{padding-top:var(--w-spacing);padding-bottom:var(--w-spacing);} +.pb-\\[--w-spacing\\]{padding-bottom:var(--w-spacing);} +.pl-\\[--w-spacing\\]{padding-left:var(--w-spacing);} +.pr-\\[--w-spacing\\]{padding-right:var(--w-spacing);} +.pt-\\[--w-spacing\\]{padding-top:var(--w-spacing);}" +`; + exports[`arbitrary padding works 1`] = ` "/* layer: default */ .p-\\[8\\]{padding:0.8rem;} @@ -67,10 +133,16 @@ exports[`margin works 1`] = ` exports[`padding works 1`] = ` "/* layer: default */ .p-8{padding:0.8rem;} +.p-auto{padding:auto;} .px-2{padding-left:0.2rem;padding-right:0.2rem;} .py-4{padding-top:0.4rem;padding-bottom:0.4rem;} .pb-8{padding-bottom:0.8rem;} .pl-32{padding-left:3.2rem;} +.pl-auto{padding-left:auto;} .pr-16{padding-right:1.6rem;} .pt-16{padding-top:1.6rem;}" `; + +exports[`should not render styles for margin with invalid arbitrary values 1`] = `""`; + +exports[`should not render styles for padding with invalid arbitrary values 1`] = `""`; diff --git a/test/spacing.js b/test/spacing.js index f65ff29..b2d84a8 100644 --- a/test/spacing.js +++ b/test/spacing.js @@ -4,7 +4,7 @@ import { setup } from './_helpers.js'; setup(); test('padding works', async ({ uno }) => { - const classes = ['p-8', 'px-2', 'py-4', 'pl-32', 'pr-16', 'pb-8', 'pt-16']; + const classes = ['p-8', 'px-2', 'py-4', 'pl-32', 'pr-16', 'pb-8', 'pt-16', 'p-auto', 'pl-auto']; const { css } = await uno.generate(classes); expect(css).toMatchSnapshot(); }); @@ -37,3 +37,43 @@ test('arbitrary margin works', async ({ uno }) => { const { css } = await uno.generate(classes); expect(css).toMatchSnapshot(); }); +test('arbitrary padding with warp tokens works', async ({ uno }) => { + const classes = ['p-[--w-spacing]', 'px-[--w-spacing]', 'py-[--w-spacing]', 'pt-[--w-spacing]', 'pb-[--w-spacing]', 'pl-[--w-spacing]', 'pr-[--w-spacing]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('arbitrary padding with css variables works', async ({ uno }) => { + const classes = ['p-[var(--w-spacing)]', 'px-[var(--w-spacing)]', 'py-[var(--w-spacing)]', 'pt-[var(--w-spacing)]', 'pb-[var(--w-spacing)]', 'pl-[var(--w-spacing)]', 'pr-[var(--w-spacing)]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('arbitrary padding with warp css var and default value works', async ({ uno }) => { + const classes = ['p-[var(--w-spacing,_8px)]', 'px-[var(--w-spacing,_8px)]', 'py-[var(--w-spacing,_8px)]', 'pt-[var(--w-spacing,_8px)]', 'pb-[var(--w-spacing,_8px)]', 'pl-[var(--w-spacing,_8px)]', 'pr-[var(--w-spacing,_8px)]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('should not render styles for padding with invalid arbitrary values', async ({ uno }) => { + const classes = ['p-[kvar(--w-spacing,_8px)]', 'px-[hello]', 'py-[-hello]', 'pt-[]', 'pb-[..]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('arbitrary margin with warp tokens works', async ({ uno }) => { + const classes = ['m-[--w-spacing]', 'mx-[--w-spacing]', 'my-[--w-spacing]', 'mt-[--w-spacing]', 'mb-[--w-spacing]', 'ml-[--w-spacing]', 'mr-[--w-spacing]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('arbitrary margin with css variables works', async ({ uno }) => { + const classes = ['m-[var(--w-spacing)]', 'mx-[var(--w-spacing)]', 'my-[var(--w-spacing)]', 'mt-[var(--w-spacing)]', 'mb-[var(--w-spacing)]', 'ml-[var(--w-spacing)]', 'mr-[var(--w-spacing)]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('arbitrary margin with warp css var and default value works', async ({ uno }) => { + const classes = ['m-[var(--w-spacing,_8px)]', 'mx-[var(--w-spacing,_8px)]', 'my-[var(--w-spacing,_8px)]', 'mt-[var(--w-spacing,_8px)]', 'mb-[var(--w-spacing,_8px)]', 'ml-[var(--w-spacing,_8px)]', 'mr-[var(--w-spacing,_8px)]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +}); +test('should not render styles for margin with invalid arbitrary values', async ({ uno }) => { + const classes = ['m-[kvar(--w-spacing,_8px)]', 'mx-[hello]', 'my-[-hello]', 'mt-[]', 'mb-[..]']; + const { css } = await uno.generate(classes); + expect(css).toMatchSnapshot(); +});