diff --git a/packages/components/src/components/columns/columns.stories.tsx b/packages/components/src/components/columns/columns.stories.tsx index 81bd251..a7e516b 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}
); @@ -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: ["none", "fill", "fit"], + }, children: { table: { disable: true }, }, @@ -60,6 +71,45 @@ export const FourColumns: Story = { args: { cols: 4 }, }; +/** + * Side-by-side comparison showing the difference between `layout`. + * + * With 3 items in a 4-column grid: + * - `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 + * + * Resize the browser window to see columns wrap responsively in both cases. + */ +export const LayoutModes: StoryObj = { + render: () => ( +
+ {Object.entries({ + none: "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 = { args: { cols: 2, diff --git a/packages/components/src/components/columns/columns.tsx b/packages/components/src/components/columns/columns.tsx index 911c2d1..824fb2a 100644 --- a/packages/components/src/components/columns/columns.tsx +++ b/packages/components/src/components/columns/columns.tsx @@ -2,25 +2,45 @@ 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?: "none" | "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..81e825c 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 = "none"; + +const COL_CLASSES: Record = { + 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 = { + none: 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 };