From 7bdfd5cc57f35be327a8f396de072e0b12eb3c26 Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Tue, 17 Mar 2026 19:06:52 -0700 Subject: [PATCH 1/9] feat: add responsive auto layout modes to Columns --- .../components/columns/columns.stories.tsx | 19 +++++++++++++ .../src/components/columns/columns.tsx | 24 +++++++++++++---- .../src/components/columns/constants.ts | 27 ++++++++++++++++++- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/packages/components/src/components/columns/columns.stories.tsx b/packages/components/src/components/columns/columns.stories.tsx index 81bd251..b388ea9 100644 --- a/packages/components/src/components/columns/columns.stories.tsx +++ b/packages/components/src/components/columns/columns.stories.tsx @@ -12,6 +12,13 @@ const Box = ({ children }: { children?: React.ReactNode }) => ( const meta: Meta = { title: "Components/Columns", component: Columns, + decorators: [ + (Story) => ( +
+ +
+ ), + ], parameters: { layout: "padded", }, @@ -33,6 +40,10 @@ const meta: Meta = { control: "select", options: [...COL_OPTIONS], }, + layout: { + control: "select", + options: ["static", "fill", "fit"], + }, children: { table: { disable: true }, }, @@ -60,6 +71,14 @@ export const FourColumns: Story = { args: { cols: 4 }, }; +export const AutoFit: Story = { + args: { cols: 3, layout: "fit" }, +}; + +export const AutoFill: Story = { + args: { cols: 3, layout: "fill" }, +}; + export const WithCustomClassName: Story = { args: { cols: 2, diff --git a/packages/components/src/components/columns/columns.tsx b/packages/components/src/components/columns/columns.tsx index 911c2d1..c68e054 100644 --- a/packages/components/src/components/columns/columns.tsx +++ b/packages/components/src/components/columns/columns.tsx @@ -2,25 +2,39 @@ import type React from "react"; import { Classes } from "@/constants/selectors"; import { cn } from "@/utils/cn"; import type { ColCount } from "./constants"; +import { AUTO_MODES, COL_CLASSES, DEFAULT_AUTO_MODE, DEFAULT_COLS, DEFAULT_MIN_COL_WIDTH } from "./constants"; type ColumnsProps = { children: React.ReactNode; cols?: ColCount | `${ColCount}`; + layout?: "static" | "fill" | "fit"; className?: string; }; -const Columns = ({ children, className, cols = 2 }: ColumnsProps) => { +const Columns = ({ + children, + className, + cols = DEFAULT_COLS, + layout = DEFAULT_AUTO_MODE, +}: ColumnsProps) => { + const numCols = Number(cols) || DEFAULT_COLS; + const autoMode = AUTO_MODES[layout]; + const minWidth = `var(--col-min-w, ${DEFAULT_MIN_COL_WIDTH})`; + const autoStyle = autoMode + ? { + gridTemplateColumns: `repeat(${autoMode},minmax(max(${minWidth},calc(100%/${numCols} - 1rem)),1fr))`, + } + : undefined; + return (
{children}
diff --git a/packages/components/src/components/columns/constants.ts b/packages/components/src/components/columns/constants.ts index 6a603b3..9b7a212 100644 --- a/packages/components/src/components/columns/constants.ts +++ b/packages/components/src/components/columns/constants.ts @@ -1,5 +1,30 @@ const COL_OPTIONS = [1, 2, 3, 4] as const; type ColCount = (typeof COL_OPTIONS)[number]; -export { COL_OPTIONS }; +const DEFAULT_COLS = 2; +const DEFAULT_MIN_COL_WIDTH = "200px"; +const DEFAULT_AUTO_MODE = "static"; + +const COL_CLASSES: Record = { + 1: "@sm:grid-cols-1", + 2: "@sm:grid-cols-2", + 3: "@sm:grid-cols-3", + 4: "@sm:grid-cols-4", +}; + +const AUTO_MODES = { + static: undefined, + fill: "auto-fill", + fit: "auto-fit", +} as const; + +export { + COL_OPTIONS, + COL_CLASSES, + AUTO_MODES, + DEFAULT_COLS, + DEFAULT_MIN_COL_WIDTH, + DEFAULT_AUTO_MODE, +}; + export type { ColCount }; From d5b176f88265d4971db6c38ffee4943133d59e80 Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Tue, 17 Mar 2026 22:44:23 -0700 Subject: [PATCH 2/9] refactor: use media query breakpoints for standard column responsiveness --- .../components/src/components/columns/columns.stories.tsx | 7 ------- packages/components/src/components/columns/constants.ts | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/components/src/components/columns/columns.stories.tsx b/packages/components/src/components/columns/columns.stories.tsx index b388ea9..34e3780 100644 --- a/packages/components/src/components/columns/columns.stories.tsx +++ b/packages/components/src/components/columns/columns.stories.tsx @@ -12,13 +12,6 @@ const Box = ({ children }: { children?: React.ReactNode }) => ( const meta: Meta = { title: "Components/Columns", component: Columns, - decorators: [ - (Story) => ( -
- -
- ), - ], parameters: { layout: "padded", }, diff --git a/packages/components/src/components/columns/constants.ts b/packages/components/src/components/columns/constants.ts index 9b7a212..47dea70 100644 --- a/packages/components/src/components/columns/constants.ts +++ b/packages/components/src/components/columns/constants.ts @@ -6,10 +6,10 @@ const DEFAULT_MIN_COL_WIDTH = "200px"; const DEFAULT_AUTO_MODE = "static"; const COL_CLASSES: Record = { - 1: "@sm:grid-cols-1", - 2: "@sm:grid-cols-2", - 3: "@sm:grid-cols-3", - 4: "@sm:grid-cols-4", + 1: "sm:grid-cols-1", + 2: "sm:grid-cols-2", + 3: "sm:grid-cols-3", + 4: "sm:grid-cols-4", }; const AUTO_MODES = { From 1a1554f16f2ae9260942a7024d67b9ab2462019b Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Tue, 17 Mar 2026 22:48:45 -0700 Subject: [PATCH 3/9] style: format constant imports for readability --- packages/components/src/components/columns/columns.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/components/src/components/columns/columns.tsx b/packages/components/src/components/columns/columns.tsx index c68e054..9263985 100644 --- a/packages/components/src/components/columns/columns.tsx +++ b/packages/components/src/components/columns/columns.tsx @@ -2,7 +2,13 @@ import type React from "react"; import { Classes } from "@/constants/selectors"; import { cn } from "@/utils/cn"; import type { ColCount } from "./constants"; -import { AUTO_MODES, COL_CLASSES, DEFAULT_AUTO_MODE, DEFAULT_COLS, DEFAULT_MIN_COL_WIDTH } from "./constants"; +import { + AUTO_MODES, + COL_CLASSES, + DEFAULT_AUTO_MODE, + DEFAULT_COLS, + DEFAULT_MIN_COL_WIDTH, +} from "./constants"; type ColumnsProps = { children: React.ReactNode; From ea8fa9379f0b0fd6a481cb75cf5541ab14fd4a59 Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Wed, 18 Mar 2026 11:06:34 -0700 Subject: [PATCH 4/9] docs: refactor Columns layout stories for side-by-side comparison --- .../components/columns/columns.stories.tsx | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/components/src/components/columns/columns.stories.tsx b/packages/components/src/components/columns/columns.stories.tsx index 34e3780..50085f0 100644 --- a/packages/components/src/components/columns/columns.stories.tsx +++ b/packages/components/src/components/columns/columns.stories.tsx @@ -1,10 +1,10 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import type React from "react"; import { Columns } from "./columns"; -import { COL_OPTIONS } from "./constants"; +import { type AUTO_MODES, COL_OPTIONS } from "./constants"; const Box = ({ children }: { children?: React.ReactNode }) => ( -
+
{children}
); @@ -64,12 +64,43 @@ export const FourColumns: Story = { args: { cols: 4 }, }; -export const AutoFit: Story = { - args: { cols: 3, layout: "fit" }, -}; - -export const AutoFill: Story = { - args: { cols: 3, layout: "fill" }, +/** + * Side-by-side comparison showing the difference between `layout`. + * + * With 3 items in a 4-column grid: + * - `static` (default): no dynamic wrapping, 1 column on small screens + * - `fit`: items stretch to fill all available space + * - `fill`: items keep their column width, leaving empty tracks visible + * + * Resize the browser window to see columns wrap responsively in both cases. + */ +export const LayoutModes: StoryObj = { + render: () => ( +
+ {Object.entries({ + static: "items fall back to default behavior", + fit: "items stretch to fill row", + fill: "empty columns preserve space", + } satisfies Record).map( + ([layout, description]) => ( +
+

+ layout="{layout}" → {description} +

+ + 1 + 2 + 3 + +
+ ) + )} +
+ ), }; export const WithCustomClassName: Story = { From 8cae62679759bb7753e722acc382fd0f4ca38717 Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Wed, 18 Mar 2026 11:06:52 -0700 Subject: [PATCH 5/9] fix: remove max-width constraint from Columns component Ensure the component can utilize its full allocated width without being restricted by `prose` typography styles, allowing for more flexible layouts. --- packages/components/src/components/columns/columns.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/components/columns/columns.tsx b/packages/components/src/components/columns/columns.tsx index 9263985..1133457 100644 --- a/packages/components/src/components/columns/columns.tsx +++ b/packages/components/src/components/columns/columns.tsx @@ -36,7 +36,7 @@ const Columns = ({
Date: Wed, 18 Mar 2026 12:06:43 -0700 Subject: [PATCH 6/9] feat: add container query support for Columns responsiveness --- packages/components/src/components/columns/constants.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/components/columns/constants.ts b/packages/components/src/components/columns/constants.ts index 47dea70..5ffab2c 100644 --- a/packages/components/src/components/columns/constants.ts +++ b/packages/components/src/components/columns/constants.ts @@ -6,10 +6,10 @@ const DEFAULT_MIN_COL_WIDTH = "200px"; const DEFAULT_AUTO_MODE = "static"; const COL_CLASSES: Record = { - 1: "sm:grid-cols-1", - 2: "sm:grid-cols-2", - 3: "sm:grid-cols-3", - 4: "sm:grid-cols-4", + 1: "sm:grid-cols-1 @sm:grid-cols-1", + 2: "sm:grid-cols-2 @sm:grid-cols-2", + 3: "sm:grid-cols-3 @sm:grid-cols-3", + 4: "sm:grid-cols-4 @sm:grid-cols-4", }; const AUTO_MODES = { From 7eabadeb7d4537c328c3a0121d6a8d6d13d9d44d Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Wed, 18 Mar 2026 12:17:28 -0700 Subject: [PATCH 7/9] refactor: standardize base container query for columns --- packages/components/src/components/columns/constants.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/components/columns/constants.ts b/packages/components/src/components/columns/constants.ts index 5ffab2c..585fb08 100644 --- a/packages/components/src/components/columns/constants.ts +++ b/packages/components/src/components/columns/constants.ts @@ -6,10 +6,10 @@ const DEFAULT_MIN_COL_WIDTH = "200px"; const DEFAULT_AUTO_MODE = "static"; const COL_CLASSES: Record = { - 1: "sm:grid-cols-1 @sm:grid-cols-1", - 2: "sm:grid-cols-2 @sm:grid-cols-2", - 3: "sm:grid-cols-3 @sm:grid-cols-3", - 4: "sm:grid-cols-4 @sm:grid-cols-4", + 1: "sm:grid-cols-1 @[0px]:grid-cols-1", + 2: "sm:grid-cols-2 @[0px]:grid-cols-1 @sm:grid-cols-2", + 3: "sm:grid-cols-3 @[0px]:grid-cols-1 @sm:grid-cols-3", + 4: "sm:grid-cols-4 @[0px]:grid-cols-1 @sm:grid-cols-4", }; const AUTO_MODES = { From 3ea70fb24a6401ec7f0a1959aa79ac608452c061 Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Wed, 18 Mar 2026 12:19:01 -0700 Subject: [PATCH 8/9] refactor: rename columns layout option from static to none Update the "static" layout mode to "none" for improved clarity and consistency. This change better communicates that no specific auto-flow behavior is applied, allowing the default grid styling to take precedence. --- .../components/src/components/columns/columns.stories.tsx | 6 +++--- packages/components/src/components/columns/columns.tsx | 2 +- packages/components/src/components/columns/constants.ts | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/src/components/columns/columns.stories.tsx b/packages/components/src/components/columns/columns.stories.tsx index 50085f0..2e1da11 100644 --- a/packages/components/src/components/columns/columns.stories.tsx +++ b/packages/components/src/components/columns/columns.stories.tsx @@ -35,7 +35,7 @@ const meta: Meta = { }, layout: { control: "select", - options: ["static", "fill", "fit"], + options: ["none", "fill", "fit"], }, children: { table: { disable: true }, @@ -68,7 +68,7 @@ export const FourColumns: Story = { * Side-by-side comparison showing the difference between `layout`. * * With 3 items in a 4-column grid: - * - `static` (default): no dynamic wrapping, 1 column on small screens + * - `none` (default): no dynamic wrapping, 1 column on small screens * - `fit`: items stretch to fill all available space * - `fill`: items keep their column width, leaving empty tracks visible * @@ -78,7 +78,7 @@ export const LayoutModes: StoryObj = { render: () => (
{Object.entries({ - static: "items fall back to default behavior", + none: "items fall back to default behavior", fit: "items stretch to fill row", fill: "empty columns preserve space", } satisfies Record).map( diff --git a/packages/components/src/components/columns/columns.tsx b/packages/components/src/components/columns/columns.tsx index 1133457..824fb2a 100644 --- a/packages/components/src/components/columns/columns.tsx +++ b/packages/components/src/components/columns/columns.tsx @@ -13,7 +13,7 @@ import { type ColumnsProps = { children: React.ReactNode; cols?: ColCount | `${ColCount}`; - layout?: "static" | "fill" | "fit"; + layout?: "none" | "fill" | "fit"; className?: string; }; diff --git a/packages/components/src/components/columns/constants.ts b/packages/components/src/components/columns/constants.ts index 585fb08..81e825c 100644 --- a/packages/components/src/components/columns/constants.ts +++ b/packages/components/src/components/columns/constants.ts @@ -3,17 +3,17 @@ type ColCount = (typeof COL_OPTIONS)[number]; const DEFAULT_COLS = 2; const DEFAULT_MIN_COL_WIDTH = "200px"; -const DEFAULT_AUTO_MODE = "static"; +const DEFAULT_AUTO_MODE = "none"; const COL_CLASSES: Record = { - 1: "sm:grid-cols-1 @[0px]:grid-cols-1", + 1: "", 2: "sm:grid-cols-2 @[0px]:grid-cols-1 @sm:grid-cols-2", 3: "sm:grid-cols-3 @[0px]:grid-cols-1 @sm:grid-cols-3", 4: "sm:grid-cols-4 @[0px]:grid-cols-1 @sm:grid-cols-4", }; const AUTO_MODES = { - static: undefined, + none: undefined, fill: "auto-fill", fit: "auto-fit", } as const; From 606297ec851a7ed90becd1a28e89377923d507cd Mon Sep 17 00:00:00 2001 From: Brandon McConnell Date: Wed, 18 Mar 2026 13:02:55 -0700 Subject: [PATCH 9/9] docs: enhance columns stories for container query responsiveness --- .../src/components/columns/columns.stories.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/components/src/components/columns/columns.stories.tsx b/packages/components/src/components/columns/columns.stories.tsx index 2e1da11..a7e516b 100644 --- a/packages/components/src/components/columns/columns.stories.tsx +++ b/packages/components/src/components/columns/columns.stories.tsx @@ -12,6 +12,13 @@ const Box = ({ children }: { children?: React.ReactNode }) => ( const meta: Meta = { title: "Components/Columns", component: Columns, + decorators: [ + (Story) => ( +
+ +
+ ), + ], parameters: { layout: "padded", }, @@ -88,7 +95,7 @@ export const LayoutModes: StoryObj = { layout="{layout}" → {description}