diff --git a/apps/pigment-css-next-app/src/app/grid/demo3.tsx b/apps/pigment-css-next-app/src/app/grid/demo3.tsx
new file mode 100644
index 00000000..b3419d9c
--- /dev/null
+++ b/apps/pigment-css-next-app/src/app/grid/demo3.tsx
@@ -0,0 +1,43 @@
+'use client';
+import * as React from 'react';
+import Grid from '@pigment-css/react/Grid';
+import { styled } from '@pigment-css/react';
+
+const Item = styled.div`
+ background-color: #fff;
+ border: 1px solid #ced7e0;
+ padding: 8px;
+ border-radius: 4px;
+ text-align: center;
+`;
+
+export default function GridDemo3() {
+ const [spacing, setSpacing] = React.useState(2);
+ return (
+
+
+ {[0, 1, 2].map((value) => (
+
+
+
+ ))}
+
+
+ Spacing:
+ {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => (
+
+
+
+ ))}
+
+
+ )
+}
diff --git a/apps/pigment-css-next-app/src/app/grid/page.tsx b/apps/pigment-css-next-app/src/app/grid/page.tsx
new file mode 100644
index 00000000..4ac3c87a
--- /dev/null
+++ b/apps/pigment-css-next-app/src/app/grid/page.tsx
@@ -0,0 +1,272 @@
+import Box from '@pigment-css/react/Box';
+import Grid from '@pigment-css/react/Grid';
+import { styled } from '@pigment-css/react';
+import GridDemo3 from './demo3';
+
+const Item = styled.div`
+ background-color: #fff;
+ border: 1px solid #ced7e0;
+ padding: 8px;
+ border-radius: 4px;
+ text-align: center;
+`;
+
+function GridDemo1() {
+ return (
+
+
+ - size=8
+
+
+ - size=4
+
+
+ - size=4
+
+
+ - size=8
+
+
+ )
+}
+
+function GridDemo2() {
+ return (
+
+
+ - xs=6 md=8
+
+
+ - xs=6 md=4
+
+
+ - xs=6 md=4
+
+
+ - xs=6 md=8
+
+
+ )
+}
+
+function GridDemo4() {
+ return (
+
+
+ - 1
+
+
+ - 2
+
+
+ - 3
+
+
+ - 4
+
+
+ )
+}
+
+function GridDemo5() {
+ return (
+
+ {Array.from(Array(6)).map((_, index) => (
+
+ - {index + 1}
+
+ ))}
+
+ )
+}
+
+function GridDemo6() {
+ return (
+
+
+ - grow
+
+
+ - size=6
+
+
+ - grow
+
+
+ )
+}
+
+function GridDemo7() {
+ return (
+
+
+ - Variable width item
+
+
+ - size=6
+
+
+ - grow
+
+
+ )
+}
+
+function GridDemo8() {
+ return (
+
+
+
+ - Email subscribe section
+
+
+
+ -
+
+ Category A
+
+
+ Link 1.1
+ Link 1.2
+ Link 1.3
+
+
+
+
+ -
+
+ Category B
+
+
+ Link 2.1
+ Link 2.2
+ Link 2.3
+
+
+
+
+ -
+
+ Category C
+
+
+ Link 3.1
+ Link 3.2
+ Link 3.3
+
+
+
+
+ -
+
+ Category D
+
+
+ Link 4.1
+ Link 4.2
+ Link 4.3
+
+
+
+
+
+
+ - © Copyright
+
+
+
+ - Link A
+
+
+ - Link B
+
+
+ - Link C
+
+
+
+
+
+ )
+}
+
+function GridDemo9() {
+ return (
+
+
+ - size=8
+
+
+ - size=8
+
+
+ )
+}
+
+function GridDemo10() {
+ return (
+
+
+ - 1
+
+
+ - 2
+
+
+ - 3
+
+
+ - 4
+
+
+ )
+}
+
+const demos = [
+ { id: '1', component: GridDemo1 },
+ { id: '2', component: GridDemo2 },
+ { id: '3', component: GridDemo3 },
+ { id: '4', component: GridDemo4 },
+ { id: '5', component: GridDemo5 },
+ { id: '6', component: GridDemo6 },
+ { id: '7', component: GridDemo7 },
+ { id: '8', component: GridDemo8 },
+ { id: '9', component: GridDemo9 },
+ { id: '10', component: GridDemo10 },
+]
+
+export default function InteractiveGrid() {
+
+ return (
+
+
Benchmark v5
+
Benchmark next
+ {demos.map(demo => {
+ const Demo = demo.component;
+ return (
+
+
Grid Demo {demo.id}
+
+
+ );
+ })}
+
+ );
+}
diff --git a/apps/pigment-css-vite-app/src/pages/grid.tsx b/apps/pigment-css-vite-app/src/pages/grid.tsx
new file mode 100644
index 00000000..ee70440f
--- /dev/null
+++ b/apps/pigment-css-vite-app/src/pages/grid.tsx
@@ -0,0 +1,303 @@
+import * as React from 'react';
+import Box from '@pigment-css/react/Box';
+import Grid from '@pigment-css/react/Grid';
+import { styled } from '@pigment-css/react';
+
+const Item = styled.div`
+ background-color: #fff;
+ border: 1px solid #ced7e0;
+ padding: 8px;
+ border-radius: 4px;
+ text-align: center;
+`;
+
+function GridDemo1() {
+ return (
+
+
+ - size=8
+
+
+ - size=4
+
+
+ - size=4
+
+
+ - size=8
+
+
+ )
+}
+
+function GridDemo2() {
+ return (
+
+
+ - xs=6 md=8
+
+
+ - xs=6 md=4
+
+
+ - xs=6 md=4
+
+
+ - xs=6 md=8
+
+
+ )
+}
+
+function GridDemo3() {
+ const [spacing, setSpacing] = React.useState(2);
+ return (
+
+
+ {[0, 1, 2].map((value) => (
+
+
+
+ ))}
+
+
+ Spacing:
+ {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => (
+
+
+
+ ))}
+
+
+ )
+}
+
+function GridDemo4() {
+ return (
+
+
+ - 1
+
+
+ - 2
+
+
+ - 3
+
+
+ - 4
+
+
+ )
+}
+
+function GridDemo5() {
+ return (
+
+ {Array.from(Array(6)).map((_, index) => (
+
+ - {index + 1}
+
+ ))}
+
+ )
+}
+
+function GridDemo6() {
+ return (
+
+
+ - grow
+
+
+ - size=6
+
+
+ - grow
+
+
+ )
+}
+
+function GridDemo7() {
+ return (
+
+
+ - Variable width item
+
+
+ - size=6
+
+
+ - grow
+
+
+ )
+}
+
+function GridDemo8() {
+ return (
+
+
+
+ - Email subscribe section
+
+
+
+ -
+
+ Category A
+
+
+ Link 1.1
+ Link 1.2
+ Link 1.3
+
+
+
+
+ -
+
+ Category B
+
+
+ Link 2.1
+ Link 2.2
+ Link 2.3
+
+
+
+
+ -
+
+ Category C
+
+
+ Link 3.1
+ Link 3.2
+ Link 3.3
+
+
+
+
+ -
+
+ Category D
+
+
+ Link 4.1
+ Link 4.2
+ Link 4.3
+
+
+
+
+
+
+ - © Copyright
+
+
+
+ - Link A
+
+
+ - Link B
+
+
+ - Link C
+
+
+
+
+
+ )
+}
+
+function GridDemo9() {
+ return (
+
+
+ - size=8
+
+
+ - size=8
+
+
+ )
+}
+
+function GridDemo10() {
+ return (
+
+
+ - 1
+
+
+ - 2
+
+
+ - 3
+
+
+ - 4
+
+
+ )
+}
+
+const demos = [
+ { id: '1', component: GridDemo1 },
+ { id: '2', component: GridDemo2 },
+ { id: '3', component: GridDemo3 },
+ { id: '4', component: GridDemo4 },
+ { id: '5', component: GridDemo5 },
+ { id: '6', component: GridDemo6 },
+ { id: '7', component: GridDemo7 },
+ { id: '8', component: GridDemo8 },
+ { id: '9', component: GridDemo9 },
+ { id: '10', component: GridDemo10 },
+]
+
+export default function InteractiveGrid() {
+
+ return (
+
+
Benchmark v5
+
Benchmark next
+ {demos.map(demo => {
+ const Demo = demo.component;
+ return (
+
+
Grid Demo {demo.id}
+
+
+ );
+ })}
+
+ );
+}
diff --git a/packages/pigment-css-react/package.json b/packages/pigment-css-react/package.json
index c0c2d053..7619f5d3 100644
--- a/packages/pigment-css-react/package.json
+++ b/packages/pigment-css-react/package.json
@@ -161,6 +161,15 @@
},
"require": "./build/Stack.js",
"default": "./build/Stack.js"
+ },
+ "./Grid": {
+ "types": "./build/Grid.d.ts",
+ "import": {
+ "types": "./build/Grid.d.mts",
+ "default": "./build/Grid.mjs"
+ },
+ "require": "./build/Grid.js",
+ "default": "./build/Grid.js"
}
},
"nx": {
diff --git a/packages/pigment-css-react/src/Grid.d.ts b/packages/pigment-css-react/src/Grid.d.ts
new file mode 100644
index 00000000..262d8c85
--- /dev/null
+++ b/packages/pigment-css-react/src/Grid.d.ts
@@ -0,0 +1,22 @@
+import * as CSS from 'csstype';
+
+import { Breakpoint } from './base';
+import { PolymorphicComponent } from './Box';
+
+type CssProperty = T | Array | Partial>;
+
+type GridBaseProps = {
+ className?: string;
+ columns?: CssProperty;
+ columnSpacing?: CssProperty;
+ container?: boolean;
+ direction?: CssProperty;
+ offset?: CssProperty;
+ rowSpacing?: CssProperty;
+ size?: CssProperty;
+ spacing?: CssProperty;
+};
+
+declare const Grid: PolymorphicComponent;
+
+export default Grid;
diff --git a/packages/pigment-css-react/src/Grid.jsx b/packages/pigment-css-react/src/Grid.jsx
new file mode 100644
index 00000000..200b192d
--- /dev/null
+++ b/packages/pigment-css-react/src/Grid.jsx
@@ -0,0 +1,226 @@
+/* eslint-disable @typescript-eslint/no-unused-expressions */
+/* eslint-disable react/jsx-filename-extension */
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import * as React from 'react';
+
+import { gridAtomics } from './baseAtomics';
+import styled from './styled';
+
+function isGridComponent(element) {
+ // For server components `muiName` is avaialble in element.type._payload.value.muiName
+ // relevant info - https://github.com/facebook/react/blob/2807d781a08db8e9873687fccc25c0f12b4fb3d4/packages/react/src/ReactLazy.js#L45
+ // eslint-disable-next-line no-underscore-dangle
+ return element.type.muiName === 'Grid' || element.type?._payload?.value?.muiName === 'Grid';
+}
+
+const GridComponent = styled('div')({
+ variants: [
+ {
+ props: { container: true },
+ style: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ gap: 'var(--Grid-self-row-spacing) var(--Grid-self-column-spacing)',
+ }
+ },
+ {
+ props: ({ size }) => size !== undefined,
+ style: {
+ width: 'var(--Grid-self-width)',
+ maxWidth: 'var(--Grid-self-max-width)',
+ flex: 'var(--Grid-self-flex)',
+ }
+ },
+ {
+ props: ({ offset }) => offset !== undefined,
+ style: {
+ marginLeft: 'var(--Grid-self-margin-left)',
+ }
+ }
+ ]
+})
+
+const Grid = React.forwardRef(function Grid(
+ {
+ children,
+ columns,
+ spacing,
+ columnSpacing,
+ rowSpacing,
+ direction = 'row',
+ style,
+ className,
+ component = 'div',
+ container = false,
+ size,
+ offset,
+ // internal props
+ // eslint-disable-next-line react/prop-types
+ unstable_parent_columns,
+ // eslint-disable-next-line react/prop-types
+ unstable_parent_column_spacing,
+ // eslint-disable-next-line react/prop-types
+ unstable_parent_row_spacing,
+ ...rest
+ },
+ ref,
+) {
+
+ const selfColumns = columns ?? unstable_parent_columns ?? 12;
+ const selfColumnSpacing = columnSpacing ?? spacing ?? unstable_parent_column_spacing ?? 0;
+ const selfRowSpacing = rowSpacing ?? spacing ?? unstable_parent_row_spacing ?? 0;
+
+ const GridAtomicsObj = {
+ direction,
+ };
+
+ if (unstable_parent_columns !== undefined) {
+ GridAtomicsObj['--Grid-parent-column-count'] = unstable_parent_columns;
+ }
+
+ if (unstable_parent_column_spacing !== undefined) {
+ GridAtomicsObj['--Grid-parent-column-spacing'] = unstable_parent_column_spacing;
+ }
+
+ if (unstable_parent_row_spacing !== undefined) {
+ GridAtomicsObj['--Grid-parent-row-spacing'] = unstable_parent_row_spacing;
+ }
+
+ if (container) {
+ GridAtomicsObj['--Grid-self-column-spacing'] = selfColumnSpacing;
+ GridAtomicsObj['--Grid-self-row-spacing'] = selfRowSpacing;
+ }
+
+ if (size) {
+ GridAtomicsObj['--Grid-self-column-span'] = size;
+ GridAtomicsObj['--Grid-self-width'] = size;
+ GridAtomicsObj['--Grid-self-max-width'] = size;
+ GridAtomicsObj['--Grid-self-flex'] = size;
+
+ }
+ if (offset) {
+ GridAtomicsObj['--Grid-self-offset'] = offset;
+ GridAtomicsObj['--Grid-self-margin-left'] = offset;
+ }
+
+ const ownerState = { container, size, offset };
+
+ const GridClasses = gridAtomics(GridAtomicsObj);
+ return (
+
+ {React.Children.map(children, (child) => {
+ if (React.isValidElement(child) && isGridComponent(child)) {
+ return React.cloneElement(child, {
+ unstable_parent_columns: selfColumns,
+ unstable_parent_column_spacing: selfColumnSpacing,
+ unstable_parent_row_spacing: selfRowSpacing,
+ });
+ }
+ return child;
+ })}
+
+ );
+});
+
+Grid.muiName = 'Grid';
+
+process.env.NODE_ENV !== 'production'
+ && (Grid.propTypes /* remove-proptypes */ = {
+ // ┌────────────────────────────── Warning ──────────────────────────────┐
+ // │ These PropTypes are generated from the TypeScript type definitions. │
+ // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
+ // └─────────────────────────────────────────────────────────────────────┘
+ /**
+ * The content of the component.
+ */
+ children: PropTypes.node,
+ /**
+ * @ignore
+ */
+ className: PropTypes.string,
+ /**
+ * @ignore
+ */
+ columns: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.arrayOf(PropTypes.number),
+ PropTypes.number,
+ PropTypes.object,
+ ]),
+ /**
+ * @ignore
+ */
+ columnSpacing: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired),
+ PropTypes.number,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /**
+ * The component used for the root node.
+ * Either a string to use a HTML element or a component.
+ */
+ component: PropTypes.elementType,
+ /**
+ * @ignore
+ */
+ container: PropTypes.bool,
+ /**
+ * @ignore
+ */
+ direction: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.oneOf(['column', 'column-reverse', 'row', 'row-reverse']),
+ PropTypes.arrayOf(PropTypes.oneOf(['column', 'column-reverse', 'row', 'row-reverse'])),
+ PropTypes.object,
+ ]),
+ /**
+ * @ignore
+ */
+ offset: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.arrayOf(PropTypes.number),
+ PropTypes.number,
+ PropTypes.object,
+ ]),
+ /**
+ * @ignore
+ */
+ rowSpacing: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired),
+ PropTypes.number,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /**
+ * @ignore
+ */
+ size: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.arrayOf(PropTypes.number),
+ PropTypes.number,
+ PropTypes.object,
+ ]),
+ /**
+ * @ignore
+ */
+ spacing: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
+ PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired),
+ PropTypes.number,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /**
+ * @ignore
+ */
+ style: PropTypes.object,
+
+ })
+
+Grid.displayName = 'Grid';
+
+export default Grid;
diff --git a/packages/pigment-css-react/src/Stack.jsx b/packages/pigment-css-react/src/Stack.jsx
index ea1db349..58c57166 100644
--- a/packages/pigment-css-react/src/Stack.jsx
+++ b/packages/pigment-css-react/src/Stack.jsx
@@ -23,7 +23,9 @@ const stackAtomics = generateAtomics(({ theme }) => {
direction: ['flexDirection'],
spacing: ['gap'],
},
- multiplier: Array.isArray(theme.vars?.spacing) ? theme.vars.spacing[0] : theme.vars?.spacing,
+ multipliers: {
+ gap: Array.isArray(theme.vars?.spacing) ? theme.vars.spacing[0] : theme.vars?.spacing
+ },
};
});
diff --git a/packages/pigment-css-react/src/baseAtomics.js b/packages/pigment-css-react/src/baseAtomics.js
new file mode 100644
index 00000000..03995b50
--- /dev/null
+++ b/packages/pigment-css-react/src/baseAtomics.js
@@ -0,0 +1,121 @@
+import { generateAtomics } from './generateAtomics';
+
+export const stackAtomics = generateAtomics(({ theme }) => ({
+ conditions: Object.keys(theme.breakpoints.values).reduce((acc, breakpoint) => {
+ acc[breakpoint] = `@media (min-width: ${theme.breakpoints.values[breakpoint]}${
+ theme.breakpoints.unit ?? 'px'
+ })`;
+ return acc;
+ }, {}),
+ defaultCondition: theme.breakpoints?.keys?.[0] ?? 'xs',
+ properties: {
+ display: ['flex', 'inline-flex'],
+ flexDirection: ['column', 'column-reverse', 'row', 'row-reverse'],
+ justifyContent: [
+ 'end',
+ 'start',
+ 'flex-end',
+ 'flex-start',
+ 'center',
+ 'space-between',
+ 'space-around',
+ 'space-evenly',
+ ],
+ alignItems: [
+ 'center',
+ 'end',
+ 'flex-end',
+ 'flex-start',
+ 'self-end',
+ 'self-start',
+ 'start',
+ 'baseline',
+ 'normal',
+ 'stretch',
+ ],
+ gap: ['--Stack-gap'],
+ },
+ shorthands: {
+ direction: ['flexDirection'],
+ spacing: ['gap'],
+ },
+ multipliers: {
+ gap: 8,
+ },
+}));
+
+export const gridAtomics = generateAtomics(({ theme }) => ({
+ conditions: Object.keys(theme.breakpoints.values).reduce((acc, breakpoint) => {
+ acc[breakpoint] = `@media (min-width: ${theme.breakpoints.values[breakpoint]}${
+ theme.breakpoints.unit ?? 'px'
+ })`;
+ return acc;
+ }, {}),
+ defaultCondition: theme.breakpoints?.keys?.[0] ?? 'xs',
+ properties: {
+ flexDirection: ['column', 'column-reverse', 'row', 'row-reverse'],
+ '--Grid-parent-column-count': ['--Grid-parent-column-count'],
+ '--Grid-parent-column-spacing': ['--Grid-parent-column-spacing'],
+ '--Grid-parent-row-spacing': ['--Grid-parent-row-spacing'],
+ '--Grid-self-column-span': ['--Grid-self-column-span'],
+ '--Grid-self-width': ['--Grid-self-width'],
+ '--Grid-self-max-width': ['--Grid-self-max-width'],
+ '--Grid-self-flex': ['--Grid-self-flex'],
+ '--Grid-self-column-spacing': ['--Grid-self-column-spacing'],
+ '--Grid-self-row-spacing': ['--Grid-self-row-spacing'],
+ '--Grid-self-offset': ['--Grid-self-offset'],
+ '--Grid-self-margin-left': ['--Grid-self-margin-left'],
+ },
+ shorthands: {
+ direction: ['flexDirection'],
+ },
+ unitless: ['--Grid-parent-column-count', '--Grid-self-column-span', '--Grid-self-offset'],
+ multipliers: {
+ '--Grid-parent-column-spacing': Array.isArray(theme.vars?.spacing) ? theme.vars.spacing[0] : theme.vars?.spacing,
+ '--Grid-parent-row-spacing': Array.isArray(theme.vars?.spacing) ? theme.vars.spacing[0] : theme.vars?.spacing,
+ '--Grid-self-column-spacing': Array.isArray(theme.vars?.spacing) ? theme.vars.spacing[0] : theme.vars?.spacing,
+ '--Grid-self-row-spacing': Array.isArray(theme.vars?.spacing) ? theme.vars.spacing[0] : theme.vars?.spacing,
+ },
+ inlineGetters: {
+ '--Grid-self-width': (value) => {
+ if (value === 'grow') {
+ return 'unset';
+ }
+
+ if (value === 'auto') {
+ return 'auto';
+ }
+
+ return 'calc(100% * var(--Grid-self-column-span) / var(--Grid-parent-column-count) - (var(--Grid-parent-column-count) - var(--Grid-self-column-span)) * var(--Grid-parent-column-spacing) / var(--Grid-parent-column-count))';
+ },
+ '--Grid-self-max-width': (value) => {
+ if (value === 'grow') {
+ return '100%';
+ }
+
+ if (value === 'auto') {
+ return 'none';
+ }
+
+ return 'unset';
+ },
+ '--Grid-self-flex': (value) => {
+ if (value === 'grow') {
+ return '1 1 0';
+ }
+
+ if (value === 'auto') {
+ return '0 0 auto';
+ }
+
+ return '0 1 auto';
+ },
+ '--Grid-self-margin-left': (value) => {
+ if (value === 'auto') {
+ return 'auto';
+ }
+
+ return 'calc(100% * var(--Grid-self-offset) / var(--Grid-parent-column-count) + var(--Grid-parent-column-spacing) * var(--Grid-self-offset) / var(--Grid-parent-column-count))';
+ },
+ },
+}));
diff --git a/packages/pigment-css-react/src/generateAtomics.js b/packages/pigment-css-react/src/generateAtomics.js
index 7b0c2fdc..f9433768 100644
--- a/packages/pigment-css-react/src/generateAtomics.js
+++ b/packages/pigment-css-react/src/generateAtomics.js
@@ -12,7 +12,8 @@ export function generateAtomics() {
* @property {Object.} shorthands
* @property {string[]} conditions
* @property {string} defaultCondition
- * @property {string} multiplier
+ * @property {string[]} unitless
+ * @property {string} multipliers
*/
/**
@@ -21,14 +22,27 @@ export function generateAtomics() {
*
* @param {RuntimeConfig} runtimeConfig
*/
-export function atomics({ styles, shorthands, conditions, defaultCondition, multiplier }) {
+export function atomics({
+ styles,
+ shorthands,
+ conditions,
+ defaultCondition,
+ unitless = [],
+ multipliers = {},
+ inlineGetters = {},
+}) {
function addStyles(cssProperty, propertyValue, classes, inlineStyle) {
const styleClasses = styles[cssProperty];
if (!styleClasses) {
return;
}
- function handlePrimitive(value, breakpoint = defaultCondition) {
+ function handlePrimitive(
+ value,
+ multiplier = undefined,
+ inlineGetter = undefined,
+ breakpoint = defaultCondition,
+ ) {
if (!(value in styleClasses)) {
const keys = Object.keys(styleClasses);
if (keys.length !== 1) {
@@ -37,34 +51,47 @@ export function atomics({ styles, shorthands, conditions, defaultCondition, mult
const key = keys[0];
let styleValue = value;
if (typeof value === 'number') {
- styleValue = multiplier ? `calc(${value} * ${multiplier})` : `${value}px`;
+ if (multiplier) {
+ styleValue = `calc(${value} * ${multiplier})`;
+ } else if (!unitless.includes(cssProperty)) {
+ styleValue = `${value}px`;
+ }
}
classes.push(styleClasses[key][breakpoint]);
- inlineStyle[`${key}${breakpoint === defaultCondition ? '' : `-${breakpoint}`}`] =
- styleValue;
+ inlineStyle[`${key}-${breakpoint}`] = inlineGetter ? inlineGetter(styleValue) : styleValue;
} else {
classes.push(styleClasses[value][breakpoint]);
}
}
if (typeof propertyValue === 'string' || typeof propertyValue === 'number') {
- handlePrimitive(propertyValue);
+ handlePrimitive(propertyValue, multipliers[cssProperty], inlineGetters[cssProperty]);
} else if (Array.isArray(propertyValue)) {
propertyValue.forEach((value, index) => {
- if (value) {
+ if (value !== undefined && value !== null) {
const breakpoint = conditions[index];
if (!breakpoint) {
return;
}
- handlePrimitive(value, conditions[index]);
+ handlePrimitive(
+ value,
+ multipliers[cssProperty],
+ inlineGetters[cssProperty],
+ conditions[index],
+ );
}
});
} else if (propertyValue) {
Object.keys(propertyValue).forEach((condition) => {
- if (propertyValue[condition]) {
+ if (propertyValue[condition] !== undefined && propertyValue[condition] !== null) {
const propertyClasses = styleClasses[propertyValue[condition]];
if (!propertyClasses) {
- handlePrimitive(propertyValue[condition], condition);
+ handlePrimitive(
+ propertyValue[condition],
+ multipliers[cssProperty],
+ inlineGetters[cssProperty],
+ condition,
+ );
return;
}
classes.push(propertyClasses[condition]);
diff --git a/packages/pigment-css-react/src/utils/convertAtomicsToCss.ts b/packages/pigment-css-react/src/utils/convertAtomicsToCss.ts
index 4408e0bb..b398a5cd 100644
--- a/packages/pigment-css-react/src/utils/convertAtomicsToCss.ts
+++ b/packages/pigment-css-react/src/utils/convertAtomicsToCss.ts
@@ -7,7 +7,9 @@ export type Atomics = {
[key: string]: string[];
};
shorthands: Record;
- multiplier?: string;
+ unitless: string[];
+ multipliers?: Record;
+ inlineGetters: Record string>;
};
export type RuntimeConfig = {
@@ -15,7 +17,9 @@ export type RuntimeConfig = {
styles: Record>>;
shorthands: Atomics['shorthands'];
defaultCondition: string;
- multiplier?: string;
+ unitless: string[];
+ multipliers?: Record;
+ inlineGetters: Record string>;
};
function getClassName(...items: string[]) {
@@ -28,7 +32,9 @@ export function convertAtomicsToCss(
defaultCondition,
properties,
shorthands = {},
- multiplier = undefined,
+ unitless = [],
+ multipliers = {},
+ inlineGetters = {},
}: Atomics,
mainClassName: string,
isGlobal = false,
@@ -40,7 +46,9 @@ export function convertAtomicsToCss(
shorthands,
conditions: Object.keys(conditions),
defaultCondition,
- multiplier,
+ unitless,
+ multipliers,
+ inlineGetters,
};
let count = 1;
function getCount() {
@@ -58,9 +66,7 @@ export function convertAtomicsToCss(
Object.entries(properties).forEach(([cssPropertyName, propertyValues]) => {
propertyValues.forEach((propertyValue) => {
const propValue = propertyValue.startsWith('--')
- ? cssesc(
- `var(${propertyValue}${conditionName === defaultCondition ? '' : `-${conditionName}`})`,
- )
+ ? cssesc(`var(${propertyValue}-${conditionName})`)
: propertyValue;
const className =
isGlobal || debug
diff --git a/packages/pigment-css-react/tests/generateAtomics.test.js b/packages/pigment-css-react/tests/generateAtomics.test.js
index 940f108f..7d752b35 100644
--- a/packages/pigment-css-react/tests/generateAtomics.test.js
+++ b/packages/pigment-css-react/tests/generateAtomics.test.js
@@ -47,7 +47,10 @@ const atomic = atomics({
// @ts-ignore This is not expected while calling the pre-transpiled generateAtomics
conditions: ['xs', 'sm', 'md', 'lg', 'xl'],
defaultCondition: 'xs',
- multiplier: '8px',
+ unitless: [],
+ multipliers: {
+ gap: '8px',
+ },
});
describe('generateAtomics', () => {
@@ -62,7 +65,7 @@ describe('generateAtomics', () => {
).to.deep.equal({
className: 'gap--Stack-gap-lg gap--Stack-gap-xs',
style: {
- '--Stack-gap': 'calc(2 * 8px)',
+ '--Stack-gap-xs': 'calc(2 * 8px)',
'--Stack-gap-lg': 'calc(1 * 8px)',
},
});
@@ -77,7 +80,7 @@ describe('generateAtomics', () => {
).to.deep.equal({
className: 'flex-direction-row-xs gap--Stack-gap-xs',
style: {
- '--Stack-gap': 'calc(1 * 8px)',
+ '--Stack-gap-xs': 'calc(1 * 8px)',
},
});
});
@@ -104,7 +107,7 @@ describe('generateAtomics', () => {
className:
'flex-direction-row-xs flex-direction-column-sm gap--Stack-gap-xs gap--Stack-gap-sm',
style: {
- '--Stack-gap': 'calc(1 * 8px)',
+ '--Stack-gap-xs': 'calc(1 * 8px)',
'--Stack-gap-sm': 'calc(2 * 8px)',
},
});
@@ -132,7 +135,7 @@ describe('generateAtomics', () => {
className:
'flex-direction-row-xs flex-direction-column-sm gap--Stack-gap-xs gap--Stack-gap-sm',
style: {
- '--Stack-gap': 'calc(1 * 8px)',
+ '--Stack-gap-xs': 'calc(1 * 8px)',
'--Stack-gap-sm': 'calc(2 * 8px)',
},
});
diff --git a/packages/pigment-css-react/tsup.config.ts b/packages/pigment-css-react/tsup.config.ts
index 57dfbe01..e2b94548 100644
--- a/packages/pigment-css-react/tsup.config.ts
+++ b/packages/pigment-css-react/tsup.config.ts
@@ -20,7 +20,7 @@ const baseConfig: Options = {
external,
};
-const BASE_FILES = ['index.ts', 'theme.ts', 'Box.jsx', 'RtlProvider.tsx', 'Stack.jsx'];
+const BASE_FILES = ['index.ts', 'theme.ts', 'Box.jsx', 'RtlProvider.tsx', 'Stack.jsx', 'Grid.jsx'];
export default defineConfig([
{