diff --git a/.changeset/slimy-donuts-report.md b/.changeset/slimy-donuts-report.md
new file mode 100644
index 00000000000..3aa224c29a8
--- /dev/null
+++ b/.changeset/slimy-donuts-report.md
@@ -0,0 +1,5 @@
+---
+'@shopify/polaris': minor
+---
+
+Added support for non-responsive values to `Grid`'s `gap`, `columns`, and `areas` props.
diff --git a/polaris-react/src/components/Grid/Grid.scss b/polaris-react/src/components/Grid/Grid.scss
index 2a29a0f880a..e384d7345c2 100644
--- a/polaris-react/src/components/Grid/Grid.scss
+++ b/polaris-react/src/components/Grid/Grid.scss
@@ -1,60 +1,24 @@
@import '../../styles/common';
.Grid {
- // Remap custom properties as mobile first fallbacks for grid-template-areas and grid-template-columns
- // stylelint-disable -- Polaris component custom properties
- --pc-grid-areas-xs: initial;
- --pc-grid-areas-sm: var(--pc-grid-areas-xs);
- --pc-grid-areas-md: var(--pc-grid-areas-sm);
- --pc-grid-areas-lg: var(--pc-grid-areas-md);
- --pc-grid-areas-xl: var(--pc-grid-areas-lg);
- --pc-grid-columns-xs: 6;
- --pc-grid-columns-sm: var(--pc-grid-columns-xs);
- --pc-grid-columns-md: var(--pc-grid-columns-sm);
- --pc-grid-columns-lg: 12;
- --pc-grid-columns-xl: var(--pc-grid-columns-lg);
- // stylelint-enable
display: grid;
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- gap: var(--pc-grid-gap-xs, var(--p-space-400));
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-areas: var(--pc-grid-areas-xs);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-columns: repeat(var(--pc-grid-columns-xs), minmax(0, 1fr));
-
- @media #{$p-breakpoints-sm-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- gap: var(--pc-grid-gap-sm, var(--p-space-400));
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-areas: var(--pc-grid-areas-sm);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-columns: repeat(var(--pc-grid-columns-sm), minmax(0, 1fr));
- }
- @media #{$p-breakpoints-md-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- gap: var(--pc-grid-gap-md, var(--p-space-400));
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-areas: var(--pc-grid-areas-md);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-columns: repeat(var(--pc-grid-columns-md), minmax(0, 1fr));
- }
-
- @media #{$p-breakpoints-lg-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- gap: var(--pc-grid-gap-lg, var(--p-space-400));
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-areas: var(--pc-grid-areas-lg);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-columns: repeat(var(--pc-grid-columns-lg), minmax(0, 1fr));
- }
-
- @media #{$p-breakpoints-xl-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- gap: var(--pc-grid-gap-xl, var(--p-space-400));
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-areas: var(--pc-grid-areas-xl);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-template-columns: repeat(var(--pc-grid-columns-xl), minmax(0, 1fr));
- }
+ @include responsive-props(
+ 'grid',
+ 'gap',
+ 'gap',
+ $default: 'var(--p-space-400)'
+ );
+ @include responsive-props('grid', 'areas', 'grid-template-areas');
+ @include responsive-props(
+ 'grid',
+ 'columns',
+ '--pc-grid-template-columns',
+ $default: ('xs': 6, 'lg': 12)
+ );
+ // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
+ grid-template-columns: repeat(
+ var(--pc-grid-template-columns),
+ minmax(0, 1fr)
+ );
}
diff --git a/polaris-react/src/components/Grid/Grid.tsx b/polaris-react/src/components/Grid/Grid.tsx
index 7d7f5c7f492..c0cbe7c0e41 100644
--- a/polaris-react/src/components/Grid/Grid.tsx
+++ b/polaris-react/src/components/Grid/Grid.tsx
@@ -1,21 +1,17 @@
import React from 'react';
+import type {SpaceScale} from '@shopify/polaris-tokens';
+
+import {
+ getResponsiveProps,
+ getResponsiveValue,
+ mapResponsivePropValues,
+} from '../../utilities/css';
+import type {ResponsiveProp} from '../../utilities/css';
import {Cell} from './components';
import styles from './Grid.scss';
-type Breakpoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
-
-type Areas = {
- [Breakpoint in Breakpoints]?: string[];
-};
-
-type Columns = {
- [Breakpoint in Breakpoints]?: number;
-};
-
-type Gap = {
- [Breakpoint in Breakpoints]?: string;
-};
+type Area = string[];
export interface GridProps {
/**
@@ -24,32 +20,25 @@ export interface GridProps {
* cells instead. See:
* https://polaris.shopify.com/components/layout-and-structure
*/
- areas?: Areas;
+ areas?: ResponsiveProp;
/* Number of columns */
- columns?: Columns;
+ columns?: ResponsiveProp;
/* Grid gap */
- gap?: Gap;
+ gap?: ResponsiveProp;
children?: React.ReactNode;
}
+
export const Grid: React.FunctionComponent & {
Cell: typeof Cell;
} = function Grid({gap, areas, children, columns}: GridProps) {
const style = {
- '--pc-grid-gap-xs': gap?.xs,
- '--pc-grid-gap-sm': gap?.sm,
- '--pc-grid-gap-md': gap?.md,
- '--pc-grid-gap-lg': gap?.lg,
- '--pc-grid-gap-xl': gap?.xl,
- '--pc-grid-columns-xs': columns?.xs,
- '--pc-grid-columns-sm': columns?.sm,
- '--pc-grid-columns-md': columns?.md,
- '--pc-grid-columns-lg': columns?.lg,
- '--pc-grid-columns-xl': columns?.xl,
- '--pc-grid-areas-xs': formatAreas(areas?.xs),
- '--pc-grid-areas-sm': formatAreas(areas?.sm),
- '--pc-grid-areas-md': formatAreas(areas?.md),
- '--pc-grid-areas-lg': formatAreas(areas?.lg),
- '--pc-grid-areas-xl': formatAreas(areas?.xl),
+ ...getResponsiveProps('grid', 'gap', 'space', gap),
+ ...getResponsiveValue('grid', 'columns', columns),
+ ...getResponsiveValue(
+ 'grid',
+ 'areas',
+ mapResponsivePropValues(areas, formatAreas),
+ ),
} as React.CSSProperties;
return (
@@ -59,7 +48,7 @@ export const Grid: React.FunctionComponent & {
);
};
-export function formatAreas(areas?: string[]) {
+export function formatAreas(areas?: Area) {
if (!areas) return;
return `'${areas?.join(`' '`)}'`;
}
diff --git a/polaris-react/src/components/Grid/components/Cell/Cell.scss b/polaris-react/src/components/Grid/components/Cell/Cell.scss
index a2746d9105f..ae8343c0b91 100644
--- a/polaris-react/src/components/Grid/components/Cell/Cell.scss
+++ b/polaris-react/src/components/Grid/components/Cell/Cell.scss
@@ -1,52 +1,10 @@
@import '../../../../styles/common';
.Cell {
+ @include responsive-props('grid-cell', 'row', 'grid-row');
+ @include responsive-props('grid-cell', 'column', 'grid-column');
// Remap custom properties as mobile first fallbacks for grid-row and grid-column
- // stylelint-disable -- Polaris component custom properties
- --pc-row-xs: initial;
- --pc-row-sm: var(--pc-row-xs);
- --pc-row-md: var(--pc-row-sm);
- --pc-row-lg: var(--pc-row-md);
- --pc-row-xl: var(--pc-row-lg);
- --pc-column-xs: initial;
- --pc-column-sm: var(--pc-column-xs);
- --pc-column-md: var(--pc-column-sm);
- --pc-column-lg: var(--pc-column-md);
- --pc-column-xl: var(--pc-column-lg);
- // stylelint-enable
min-width: 0;
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-row: var(--pc-row-xs);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-column: var(--pc-column-xs);
-
- @media #{$p-breakpoints-sm-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-row: var(--pc-row-sm);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-column: var(--pc-column-sm);
- }
-
- @media #{$p-breakpoints-md-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-row: var(--pc-row-md);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-column: var(--pc-column-md);
- }
-
- @media #{$p-breakpoints-lg-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-row: var(--pc-row-lg);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-column: var(--pc-column-lg);
- }
-
- @media #{$p-breakpoints-xl-up} {
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-row: var(--pc-row-xl);
- // stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
- grid-column: var(--pc-column-xl);
- }
}
@for $i from 1 through 6 {
diff --git a/polaris-react/src/components/Grid/components/Cell/Cell.tsx b/polaris-react/src/components/Grid/components/Cell/Cell.tsx
index 802c9c48b89..b23364e7901 100644
--- a/polaris-react/src/components/Grid/components/Cell/Cell.tsx
+++ b/polaris-react/src/components/Grid/components/Cell/Cell.tsx
@@ -1,14 +1,11 @@
import React from 'react';
-import {classNames} from '../../../../utilities/css';
+import {classNames, getResponsiveValue} from '../../../../utilities/css';
+import type {ResponsiveProp} from '../../../../utilities/css';
import styles from './Cell.scss';
-type Breakpoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
-
-type Cell = {
- [Breakpoint in Breakpoints]?: string;
-};
+type Cell = ResponsiveProp;
interface Columns {
/** Number of columns the section should span on extra small screens */
@@ -54,16 +51,8 @@ export function Cell({
const style = {
gridArea,
- '--pc-column-xs': column?.xs,
- '--pc-column-sm': column?.sm,
- '--pc-column-md': column?.md,
- '--pc-column-lg': column?.lg,
- '--pc-column-xl': column?.xl,
- '--pc-row-xs': row?.xs,
- '--pc-row-sm': row?.sm,
- '--pc-row-md': row?.md,
- '--pc-row-lg': row?.lg,
- '--pc-row-xl': row?.xl,
+ ...getResponsiveValue('grid-cell', 'column', column),
+ ...getResponsiveValue('grid-cell', 'row', row),
};
return (
diff --git a/polaris-react/src/components/Grid/components/Cell/tests/Cell.test.tsx b/polaris-react/src/components/Grid/components/Cell/tests/Cell.test.tsx
index 462fd0c5c2c..60cf997be94 100644
--- a/polaris-react/src/components/Grid/components/Cell/tests/Cell.test.tsx
+++ b/polaris-react/src/components/Grid/components/Cell/tests/Cell.test.tsx
@@ -37,8 +37,8 @@ describe(' | ', () => {
expect(cell).toContainReactComponent('div', {
style: {
- '--pc-column-xs': '2 / span 1',
- '--pc-column-lg': 'span 12',
+ '--pc-grid-cell-column-xs': '2 / span 1',
+ '--pc-grid-cell-column-lg': 'span 12',
} as React.CSSProperties,
});
});
@@ -50,8 +50,8 @@ describe(' | ', () => {
expect(cell).toContainReactComponent('div', {
style: {
- '--pc-row-xs': '2 / span 3',
- '--pc-row-lg': '1 / span 2',
+ '--pc-grid-cell-row-xs': '2 / span 3',
+ '--pc-grid-cell-row-lg': '1 / span 2',
} as React.CSSProperties,
});
});
diff --git a/polaris-react/src/components/Grid/tests/Grid.test.tsx b/polaris-react/src/components/Grid/tests/Grid.test.tsx
index 038c84f47a0..73d0e92cac2 100644
--- a/polaris-react/src/components/Grid/tests/Grid.test.tsx
+++ b/polaris-react/src/components/Grid/tests/Grid.test.tsx
@@ -21,67 +21,103 @@ describe('', () => {
const lgAreas = ['lg1', 'lg2', 'lg3'];
const xlAreas = ['xl1', 'xl2', 'xl3'];
- it('applies grid-template-areas as custom properties', () => {
- const grid = mountWithApp(
- ,
- );
-
- expect(grid).toContainReactComponent('div', {
- style: {
- '--pc-grid-areas-xs': formatAreas(xsAreas),
- '--pc-grid-areas-sm': formatAreas(smAreas),
- '--pc-grid-areas-md': formatAreas(mdAreas),
- '--pc-grid-areas-lg': formatAreas(lgAreas),
- '--pc-grid-areas-xl': formatAreas(xlAreas),
- } as React.CSSProperties,
+ describe('applies grid-template-areas as custom properties', () => {
+ it('responsively', () => {
+ const grid = mountWithApp(
+ ,
+ );
+
+ expect(grid).toContainReactComponent('div', {
+ style: {
+ '--pc-grid-areas-xs': formatAreas(xsAreas),
+ '--pc-grid-areas-sm': formatAreas(smAreas),
+ '--pc-grid-areas-md': formatAreas(mdAreas),
+ '--pc-grid-areas-lg': formatAreas(lgAreas),
+ '--pc-grid-areas-xl': formatAreas(xlAreas),
+ } as React.CSSProperties,
+ });
+ });
+
+ it('non-responsively', () => {
+ const grid = mountWithApp();
+
+ expect(grid).toContainReactComponent('div', {
+ style: {
+ '--pc-grid-areas-xs': formatAreas(xsAreas),
+ } as React.CSSProperties,
+ });
});
});
- it('renders inline custom properties for custom columns', () => {
- const grid = mountWithApp(
- ,
- );
-
- expect(grid).toContainReactComponent('div', {
- style: {
- '--pc-grid-columns-xs': 1,
- '--pc-grid-columns-sm': 3,
- '--pc-grid-columns-md': 7,
- '--pc-grid-columns-lg': 12,
- '--pc-grid-columns-xl': 12,
- } as React.CSSProperties,
+ describe('renders inline custom properties for custom columns', () => {
+ it('responsively', () => {
+ const grid = mountWithApp(
+ ,
+ );
+
+ expect(grid).toContainReactComponent('div', {
+ style: {
+ '--pc-grid-columns-xs': 1,
+ '--pc-grid-columns-sm': 3,
+ '--pc-grid-columns-md': 7,
+ '--pc-grid-columns-lg': 12,
+ '--pc-grid-columns-xl': 12,
+ } as React.CSSProperties,
+ });
+ });
+
+ it('non-responsively', () => {
+ const grid = mountWithApp();
+
+ expect(grid).toContainReactComponent('div', {
+ style: {
+ '--pc-grid-columns-xs': 3,
+ } as React.CSSProperties,
+ });
});
});
- it('renders inline custom properties for custom gap', () => {
- const grid = mountWithApp(
- ,
- );
-
- expect(grid).toContainReactComponent('div', {
- style: {
- '--pc-grid-gap-xs': 'var(--p-space-100)',
- '--pc-grid-gap-sm': 'var(--p-space-100)',
- '--pc-grid-gap-md': 'var(--p-space-200)',
- '--pc-grid-gap-lg': 'var(--p-space-400)',
- '--pc-grid-gap-xl': 'var(--p-space-400)',
- } as React.CSSProperties,
+ describe('renders inline custom properties for custom gap', () => {
+ it('responsively', () => {
+ const grid = mountWithApp(
+ ,
+ );
+
+ expect(grid).toContainReactComponent('div', {
+ style: {
+ '--pc-grid-gap-xs': 'var(--p-space-100)',
+ '--pc-grid-gap-sm': 'var(--p-space-100)',
+ '--pc-grid-gap-md': 'var(--p-space-200)',
+ '--pc-grid-gap-lg': 'var(--p-space-400)',
+ '--pc-grid-gap-xl': 'var(--p-space-400)',
+ } as React.CSSProperties,
+ });
+ });
+
+ it('non-responsively', () => {
+ const grid = mountWithApp();
+
+ expect(grid).toContainReactComponent('div', {
+ style: {
+ '--pc-grid-gap-xs': 'var(--p-space-300)',
+ } as React.CSSProperties,
+ });
});
});
diff --git a/polaris-react/src/utilities/css.ts b/polaris-react/src/utilities/css.ts
index 0a7380fa7bc..131a8731568 100644
--- a/polaris-react/src/utilities/css.ts
+++ b/polaris-react/src/utilities/css.ts
@@ -45,19 +45,12 @@ export function createPolarisCSSVar(
tokenSubgroup: string,
tokenValue: T,
): PolarisCSSVar {
- // For backwards compatibility with `Grid` and `Grid.Cell`, accept already
- // formed var()'s using either polaris or polaris component custom properties.
+ // `Grid`'s `gap` prop used to allow passing fully formed var() functions as
+ // the value. This is no longer supported in v12+.
if (typeof tokenValue === 'string' && tokenValue.startsWith('var(')) {
- if (
- !tokenValue.startsWith(`var(--p-${tokenSubgroup}-`) &&
- !tokenValue.startsWith(`var(--pc-${tokenSubgroup}-`)
- ) {
- throw new Error(
- `"${tokenValue}" is not from the ${tokenSubgroup} token group.`,
- );
- }
-
- return tokenValue as PolarisCSSVar;
+ throw new Error(
+ `"${tokenValue}" is not from the ${tokenSubgroup} token group.`,
+ );
}
// NOTE: All our token values today are either strings or numbers, so