Skip to content

Commit

Permalink
feat: support arbitrary values for flex-basis, flex-grow, flex-shrink…
Browse files Browse the repository at this point in the history
…, grid-auto-rows, grid-auto-columns (#180)
  • Loading branch information
felicia-haggqvist committed Jan 2, 2024
1 parent 6dabb14 commit d3106cd
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 18 deletions.
9 changes: 8 additions & 1 deletion src/_rules/flex.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { handler as h } from '#utils';
import { handler as h, resolveArbitraryValues } from '#utils';

export const flex = [
// flex
Expand Down Expand Up @@ -27,6 +27,13 @@ export const flex = [
([, d], { theme }) => ({ 'flex-basis': theme.spacing?.[d] ?? h.auto.fraction(d) }),
{ autocomplete: ['basis-$spacing'] },
],
// matching arbitrary values
[
/^basis-\[(.\d*)(rem|px|%)?]$/,
([, value, unit], context) => ({
'flex-basis': resolveArbitraryValues(value, unit, context),
}),
],
// directions
['flex-row', { 'flex-direction': 'row' }],
['flex-row-reverse', { 'flex-direction': 'row-reverse' }],
Expand Down
9 changes: 8 additions & 1 deletion src/_rules/grid.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { handler as h } from '#utils';
import { handler as h, resolveArbitraryValues } from '#utils';

const autoDirection = (prop) => {
switch (prop) {
Expand Down Expand Up @@ -53,6 +53,13 @@ export const grid = [
([, v]) => ({ 'grid-auto-columns': autoDirection(v) }),
{ autocomplete: ['auto-(rows|cols)-<num>'] },
],

// matching arbitrary values auto-rows + auto-cols
[/^auto-rows-\[([\w%]+(?:[-\w()%,.]+)*)\]$/, ([, v]) => ({ 'grid-auto-rows': resolveArbitraryValues(v, null, null) })],
[/^auto-cols-\[([\w%]+(?:[-\w()%,.]+)*)\]$/, ([, v]) => ({ 'grid-auto-columns': resolveArbitraryValues(v, null, null) }),
{ autocomplete: ['auto-(rows|cols)-<num>'] },
],

['grid-flow-row', { 'grid-auto-flow': 'row' }],
['grid-flow-col', { 'grid-auto-flow': 'column' }],
['grid-flow-dense', { 'grid-auto-flow': 'dense' }],
Expand Down
2 changes: 1 addition & 1 deletion src/_rules/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const whitespaces = [
export const contents = [
[/^content-(.+)$/, ([, v]) => ({ content: h.bracket.cssvar(v) })],
['content-empty', { content: '""' }],
['content-none', { content: '""' }],
['content-none', { content: 'none' }],
];

export const breaks = [
Expand Down
5 changes: 3 additions & 2 deletions src/_utils/handlers/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ export function px(str) {
if (!Number.isNaN(num)) return unit ? `${round(num)}${unit}` : `${round(num)}px`;
}
export function number(str) {
if (!numberRE.test(str)) return;
const num = parseFloat(str);
const newStr = (str.startsWith('[') && str.endsWith(']')) ? bracket(str) : str;
if (!numberRE.test(newStr)) return;
const num = parseFloat(newStr);
if (!Number.isNaN(num)) return round(num);
}
export function percent(str) {
Expand Down
2 changes: 1 addition & 1 deletion src/_utils/handlers/regex.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const numberWithUnitRE = /^(-?[0-9.]+)(px|pt|pc|%|r?em|ex|ch|ic|(?:[sld]?v|cq)(?:[whib]|min|max)|in|cm|mm|rpx)?$/i;
export const numberWithUnitRE = /^(-?[0-9.]+)(fr|px|pt|pc|%|r?em|ex|ch|ic|(?:[sld]?v|cq)(?:[whib]|min|max)|in|cm|mm|rpx)?$/i;
export const numberRE = /^(-?[0-9.]+)$/i;
export const unitOnlyRE = /^(px)$/i;
13 changes: 11 additions & 2 deletions src/_utils/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,18 @@ export function getBracket(str, open, close) {
}

export function resolveArbitraryValues(value, unit, context) {
if (value.includes('_')) {
const valueWithoutUnderscore = value.replace(/_/g, " ");
if (/\d/.test(valueWithoutUnderscore)) {
const digits = valueWithoutUnderscore.split(' ');
return digits?.map(number => h.rem(number) || number).join(' ');
} else {
return valueWithoutUnderscore;
}
}
if (unit === 'rem') return h.rem(`${value}${unit}`);
if (unit === 'px' || context.theme.usingPixels) return h.px(value);
if (unit === 'px' || context?.theme?.usingPixels) return h.px(value);
if (unit === '%') return `${h.percent(`${value}`) * 100 }${unit}`;
if (value.startsWith('--')) return `var(${value})`;
return h.rem(value) || value;
}
}
43 changes: 43 additions & 0 deletions test/__snapshots__/flex.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`flex shrink/grow with arbitrary values 1`] = `
"/* layer: default */
.shrink,
.shrink-\\\\[1\\\\]{flex-shrink:1;}
.shrink-\\\\[0\\\\]{flex-shrink:0;}
.shrink-\\\\[2\\\\]{flex-shrink:2;}
.shrink-\\\\[3\\\\]{flex-shrink:3;}
.shrink-\\\\[4\\\\]{flex-shrink:4;}
.shrink-\\\\[5\\\\]{flex-shrink:5;}
.grow,
.grow-\\\\[1\\\\]{flex-grow:1;}
.grow-\\\\[0\\\\]{flex-grow:0;}
.grow-\\\\[2\\\\]{flex-grow:2;}
.grow-\\\\[3\\\\]{flex-grow:3;}
.grow-\\\\[4\\\\]{flex-grow:4;}
.grow-\\\\[5\\\\]{flex-grow:5;}"
`;

exports[`flex-basis 1`] = `
"/* layer: default */
.basis-1{flex-basis:0.1rem;}
.basis-1\\\\/2{flex-basis:50%;}
.basis-1\\\\/4{flex-basis:25%;}
.basis-1\\\\/5{flex-basis:20%;}
.basis-16{flex-basis:1.6rem;}
.basis-2{flex-basis:0.2rem;}
.basis-2\\\\/5{flex-basis:40%;}
.basis-32{flex-basis:3.2rem;}
.basis-4{flex-basis:0.4rem;}
.basis-48{flex-basis:4.8rem;}
.basis-64{flex-basis:6.4rem;}
.basis-8{flex-basis:0.8rem;}"
`;

exports[`flex-basis with arbitrary values 1`] = `
"/* layer: default */
.basis-\\\\[15\\\\]{flex-basis:1.5rem;}
.basis-\\\\[15\\\\%\\\\]{flex-basis:15%;}
.basis-\\\\[15px\\\\]{flex-basis:15px;}
.basis-\\\\[15rem\\\\]{flex-basis:15rem;}"
`;
25 changes: 25 additions & 0 deletions test/__snapshots__/general.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`testing content-empty 1`] = `
"/* layer: default */
.before\\\\:content-empty::before{content:\\"\\";}
@media (min-width: 480px){
.sm\\\\:grid{display:grid;}
}"
`;

exports[`testing content-none 1`] = `
"/* layer: default */
.before\\\\:content-none::before{content:none;}
@media (min-width: 480px){
.sm\\\\:grid{display:grid;}
}"
`;

exports[`testing empty string as arbitrary value 1`] = `
"/* layer: default */
.before\\\\:content-\\\\[\\\\\\"\\\\\\"\\\\]::before{content:\\"\\";}
@media (min-width: 480px){
.sm\\\\:grid{display:grid;}
}"
`;
26 changes: 26 additions & 0 deletions test/__snapshots__/grid.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,32 @@ exports[`grid auto flows 1`] = `
.grid-flow-col-dense{grid-auto-flow:column dense;}"
`;

exports[`grid auto rows and cols with arbitrary values 1`] = `
"/* layer: default */
.auto-rows-\\\\[20\\\\]{grid-auto-rows:2rem;}
.auto-rows-\\\\[20\\\\%\\\\]{grid-auto-rows:20%;}
.auto-rows-\\\\[20cm\\\\]{grid-auto-rows:20cm;}
.auto-rows-\\\\[20fr_20_0\\\\%\\\\]{grid-auto-rows:20fr 2rem 0%;}
.auto-rows-\\\\[20fr_20cm_0\\\\%\\\\]{grid-auto-rows:20fr 20cm 0%;}
.auto-rows-\\\\[20fr\\\\]{grid-auto-rows:20fr;}
.auto-rows-\\\\[20px\\\\]{grid-auto-rows:20px;}
.auto-rows-\\\\[20rem\\\\]{grid-auto-rows:20rem;}
.auto-rows-\\\\[min-content_max-content_auto\\\\]{grid-auto-rows:min-content max-content auto;}
.auto-rows-\\\\[minmax\\\\(0\\\\,2fr\\\\)\\\\]{grid-auto-rows:minmax(0,2fr);}
.auto-rows-\\\\[minmax\\\\(100px\\\\,auto\\\\)_minmax\\\\(max-content\\\\,2fr\\\\)_minmax\\\\(20\\\\%\\\\,80vmax\\\\)\\\\]{grid-auto-rows:minmax(100px,auto) minmax(max-content,2fr) minmax(20%,80vmax);}
.auto-cols-\\\\[20\\\\]{grid-auto-columns:2rem;}
.auto-cols-\\\\[20\\\\%\\\\]{grid-auto-columns:20%;}
.auto-cols-\\\\[20cm\\\\]{grid-auto-columns:20cm;}
.auto-cols-\\\\[20fr_20_0\\\\%\\\\]{grid-auto-columns:20fr 2rem 0%;}
.auto-cols-\\\\[20fr_20cm_0\\\\%\\\\]{grid-auto-columns:20fr 20cm 0%;}
.auto-cols-\\\\[20fr\\\\]{grid-auto-columns:20fr;}
.auto-cols-\\\\[20px\\\\]{grid-auto-columns:20px;}
.auto-cols-\\\\[20rem\\\\]{grid-auto-columns:20rem;}
.auto-cols-\\\\[min-content_max-content_auto\\\\]{grid-auto-columns:min-content max-content auto;}
.auto-cols-\\\\[minmax\\\\(0\\\\,2fr\\\\)\\\\]{grid-auto-columns:minmax(0,2fr);}
.auto-cols-\\\\[minmax\\\\(100px\\\\,auto\\\\)_minmax\\\\(max-content\\\\,2fr\\\\)_minmax\\\\(20\\\\%\\\\,80vmax\\\\)\\\\]{grid-auto-columns:minmax(100px,auto) minmax(max-content,2fr) minmax(20%,80vmax);}"
`;

exports[`grid span 1`] = `
"/* layer: default */
.col-auto{grid-column:auto;}
Expand Down
8 changes: 0 additions & 8 deletions test/__snapshots__/position.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -519,14 +519,6 @@ exports[`justifies > check justify- classes and their expected justify-content v
.justify-evenly{justify-content:space-evenly;}"
`;

exports[`justifies > check justify-items- classes and their expected justify-itemns values 1`] = `
"/* layer: default */
.justify-items-start{justify-items:start;}
.justify-items-end{justify-items:end;}
.justify-items-center{justify-items:center;}
.justify-items-stretch{justify-items:stretch;}"
`;

exports[`justifies > check justify-items- classes and their expected justify-items values 1`] = `
"/* layer: default */
.justify-items-start{justify-items:start;}
Expand Down
4 changes: 2 additions & 2 deletions test/__snapshots__/static.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ exports[`static rules do static things 1`] = `
.select-revert{user-select:revert;}
.select-revert-layer{user-select:revert-layer;}
.select-unset{user-select:unset;}
.content-empty,
.content-none{content:\\"\\";}
.content-empty{content:\\"\\";}
.content-none{content:none;}
.break-normal{overflow-wrap:normal;word-break:normal;}
.break-words{overflow-wrap:break-word;}
.break-all{word-break:break-all;}
Expand Down
11 changes: 11 additions & 0 deletions test/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ test("supports setting arbitrary background colors", async ({ uno }) => {
expect(css).toMatchSnapshot();
});

// TODO: Uncomment this once there is a fix for support arbitrary values for background-position:
// test("supports setting arbitrary background positions", async ({ uno }) => {
// const classes = [
// "bg-[25%_75%]",
// "bg-[right_3em_bottom_10px]",
// "bg-[center_top_1rem]",
// ];
// const { css } = await uno.generate(classes);
// expect(css).toMatchSnapshot();
// });

test('invalid background color classes', async({ uno }) => {
const classes = ['bg-color', 'background-[--w-s-color-background]', 'background-[var(--w-s-color-background)]'];
const { css } = await uno.generate(classes);
Expand Down
41 changes: 41 additions & 0 deletions test/flex.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,44 @@ test('flex shrink/grow', async (t) => {
`);

});

test('flex shrink/grow with arbitrary values', async (t) => {
const autoClasses = ['grow', 'shrink'];
const classes = Array.from({ length: 6 }, (_, index) => [`shrink-[${index}]`, `grow-[${index}]`]).flat();

const { css } = await t.uno.generate([...classes, ...autoClasses]);
expect(css).toMatchSnapshot();
});

test('flex-basis', async (t) => {
const autoClasses = ['basis'];
const classes = [
'basis-1',
'basis-2',
'basis-4',
'basis-8',
'basis-16',
'basis-32',
'basis-48',
'basis-64',
'basis-1/2',
'basis-1/5',
'basis-1/4',
'basis-2/5',
];

const { css } = await t.uno.generate([...classes, ...autoClasses]);
expect(css).toMatchSnapshot();
});
test('flex-basis with arbitrary values', async (t) => {
const autoClasses = ['basis'];
const classes = [
'basis-[15]',
'basis-[15rem]',
'basis-[15px]',
'basis-[15%]',
];

const { css } = await t.uno.generate([...classes, ...autoClasses]);
expect(css).toMatchSnapshot();
});
13 changes: 13 additions & 0 deletions test/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ test(`the HTML parser is sane`, async ({ uno }) => {
}"
`);
});
test(`testing empty string as arbitrary value`, async ({ uno }) => {
const { css } = await uno.generate([`before:content-[""]`, 'sm:grid']);
expect(css).toMatchSnapshot();
});
test(`testing content-empty`, async ({ uno }) => {
const { css } = await uno.generate([`before:content-empty`, 'sm:grid']);
expect(css).toMatchSnapshot();
});

test(`testing content-none`, async ({ uno }) => {
const { css } = await uno.generate([`before:content-none`, 'sm:grid']);
expect(css).toMatchSnapshot();
});

test('can generate pixel values for theme', async () => {
const uno = getGenerator({ usePixels: true });
Expand Down
30 changes: 30 additions & 0 deletions test/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,36 @@ test('grid auto flows', async (t) => {
expect(css).toMatchSnapshot();
});

test('grid auto rows and cols with arbitrary values', async (t) => {
const gridRowsCols = [
'auto-rows-[20]',
'auto-rows-[20px]',
'auto-rows-[20rem]',
'auto-rows-[20fr]',
'auto-rows-[20%]',
'auto-rows-[20cm]',
'auto-rows-[20fr_20cm_0%]',
'auto-rows-[20fr_20_0%]',
'auto-rows-[minmax(0,2fr)]',
'auto-rows-[min-content_max-content_auto]',
'auto-rows-[minmax(100px,auto)_minmax(max-content,2fr)_minmax(20%,80vmax)]',
'auto-cols-[20]',
'auto-cols-[20px]',
'auto-cols-[20rem]',
'auto-cols-[20fr]',
'auto-cols-[20%]',
'auto-cols-[20cm]',
'auto-cols-[20fr_20cm_0%]',
'auto-cols-[20fr_20_0%]',
'auto-cols-[minmax(0,2fr)]',
'auto-cols-[min-content_max-content_auto]',
'auto-cols-[minmax(100px,auto)_minmax(max-content,2fr)_minmax(20%,80vmax)]',
];
const { css } = await t.uno.generate(gridRowsCols);

expect(css).toMatchSnapshot();
});

test('grid templates basic', async (t) => {
const classesRows = rows.map((num) => `grid-rows-${num}`);
const classesCols = columns.map((num) => `grid-cols-${num}`);
Expand Down

0 comments on commit d3106cd

Please sign in to comment.