Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/stage-1-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@reactive/silk-core": minor
"@reactive/silk": minor
---

Stage 1 layout system: `Inline`, `Grid`, `Center`, `Container`, `Separator`, and `Box` padding; system density via `compactSpace` + `data-density` space remaps; web-only `collapseBelow` container queries; ThemeProvider density / nested theme inheritance.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ yarn docs # http://localhost:6006

## Status

Foundation milestone (Stage 0): token/theme/variant architecture, layout/visual/interaction exemplars, Identity composite, and a shadcn-protocol registry scaffold. The staged plan is in [docs/ROADMAP.md](docs/ROADMAP.md); the project charter is [docs/PRINCIPLES.md](docs/PRINCIPLES.md).
Stage 1 (layout system): layout vocabulary (`Inline`, `Grid`, `Center`, `Container`, `Separator`), system density through space tokens, intrinsic-first + container-query responsive strategy, AppSkeleton fixture, native contract spike, and [pre-1.0 API policy](docs/API_POLICY.md). The staged plan is in [docs/ROADMAP.md](docs/ROADMAP.md); the project charter is [docs/PRINCIPLES.md](docs/PRINCIPLES.md).

## Packages

Expand All @@ -31,6 +31,7 @@ Foundation milestone (Stage 0): token/theme/variant architecture, layout/visual/
| App | Description |
| --- | --- |
| [`@reactive/silk-docs`](apps/docs) | Private Storybook docs site (not published) |
| [`@reactive/silk-native-spike`](apps/native-spike) | Throwaway Expo spike consuming `silk-core` (Stage 1; not published) |

Libraries live under `packages/`; runnable consumers (docs, future playgrounds / native examples) live under `apps/`.

Expand Down
31 changes: 28 additions & 3 deletions apps/docs/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import type { Decorator, Preview } from 'storybook-react-rsbuild';
import { SilkProvider, type ColorScheme } from '@reactive/silk';
import {
SilkProvider,
type ColorScheme,
type DensityName,
} from '@reactive/silk';
import type { JSX } from 'react';
import './preview.css';

const withSilkProvider: Decorator = (Story, context): JSX.Element => {
const colorScheme = (context.globals.colorScheme ?? 'light') as
| ColorScheme
| 'system';
const density = (context.globals.density ?? 'comfortable') as DensityName;

return (
<SilkProvider colorScheme={colorScheme}>
<SilkProvider colorScheme={colorScheme} density={density}>
<div className="silk-story-canvas">
<Story />
</div>
Expand All @@ -21,7 +26,14 @@ const preview: Preview = {
parameters: {
options: {
storySort: {
order: ['Introduction', 'Theming', 'Theme', 'Components', '*'],
order: [
'Introduction',
'Theming',
'Theme',
'Fixtures',
'Components',
'*',
],
},
},
},
Expand All @@ -39,9 +51,22 @@ const preview: Preview = {
dynamicTitle: true,
},
},
density: {
description: 'System density (space token remap)',
toolbar: {
title: 'Density',
icon: 'component',
items: [
{ value: 'comfortable', title: 'Comfortable' },
{ value: 'compact', title: 'Compact' },
],
dynamicTitle: true,
},
},
},
initialGlobals: {
colorScheme: 'light',
density: 'comfortable',
},
decorators: [withSilkProvider],
};
Expand Down
10 changes: 9 additions & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"scripts": {
"storybook": "storybook dev -p 6006",
"build:storybook": "storybook build -o storybook-static",
"typecheck": "tsc -p tsconfig.json --noEmit"
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "rstest run"
},
"dependencies": {
"@reactive/silk": "workspace:*",
Expand All @@ -17,13 +18,20 @@
"devDependencies": {
"@rsbuild/core": "~2.1.8",
"@rsbuild/plugin-react": "^1.4.5",
"@rspack/plugin-react-refresh": "^1.6.1",
"@rstest/core": "^0.11.4",
"@storybook/addon-a11y": "10.5.4",
"@storybook/addon-docs": "10.5.4",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.2",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@types/react-refresh": "^0",
"@wyw-in-js/webpack-loader": "^2.3.0",
"jsdom": "^29.1.1",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-refresh": "^0.18.0",
"remark-gfm": "^4.0.1",
"storybook": "10.5.4",
"storybook-react-rsbuild": "3.3.4",
Expand Down
8 changes: 8 additions & 0 deletions apps/docs/rstest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { pluginReact } from '@rsbuild/plugin-react';
import { defineConfig } from '@rstest/core';

export default defineConfig({
plugins: [pluginReact()],
testEnvironment: 'jsdom',
include: ['src/**/*.test.ts', 'src/**/*.test.tsx'],
});
42 changes: 37 additions & 5 deletions apps/docs/src/components/Box.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,49 @@
import { Box, Text } from '@reactive/silk';
import { Box, Text, boxRecipe } from '@reactive/silk';
import type { Meta, StoryObj } from 'storybook-react-rsbuild';
import type { CSSProperties, JSX } from 'react';

const meta = {
title: 'Components/Box',
component: Box,
tags: ['autodocs'],
args: {
...boxRecipe.defaults,
},
argTypes: {
padding: {
control: 'select',
options: [...boxRecipe.variants.padding],
},
},
} satisfies Meta<typeof Box>;

export default meta;

type Story = StoryObj<typeof meta>;

const surfaceStyle: CSSProperties = {
padding: 'var(--silk-space-4)',
border: '1px solid var(--silk-color-border-subtle)',
borderRadius: 'var(--silk-radius-md)',
backgroundColor: 'var(--silk-color-surface-raised)',
};

export const Basic: Story = {
args: {
padding: '4',
style: surfaceStyle,
children: <Text>Box provides box-model reset with semantic surface/text defaults.</Text>,
children: (
<Text>
Box provides box-model reset with semantic surface/text defaults and a
padding axis from space tokens.
</Text>
),
},
};

export const AsChild: Story = {
parameters: { controls: { disable: true } },
render: (): JSX.Element => (
<Box asChild style={surfaceStyle}>
<Box asChild padding="4" style={surfaceStyle}>
<section>
<Text role="heading">Polymorphic via asChild</Text>
<Text tone="secondary">Renders as a semantic section element.</Text>
Expand All @@ -38,11 +52,29 @@ export const AsChild: Story = {
),
};

export const Contain: Story = {
parameters: { controls: { disable: true } },
render: (): JSX.Element => (
<Box
contain
padding="4"
style={{ ...surfaceStyle, maxWidth: '20rem' }}
data-testid="box-contain"
>
<Text role="label">contain</Text>
<Text tone="secondary" role="caption">
Establishes container-type: inline-size for nested collapseBelow.
</Text>
</Box>
),
};

export const EscapeHatches: Story = {
parameters: { controls: { disable: true } },
render: (): JSX.Element => (
<Box
className="docs-box-escape"
padding="4"
style={{
...surfaceStyle,
display: 'grid',
Expand All @@ -53,7 +85,7 @@ export const EscapeHatches: Story = {
>
<Text role="label">className + style + data-*</Text>
<Text tone="secondary" role="caption">
Layout primitive — compose with Stack for flex layouts.
Layout primitive — compose with Stack / Inline / Grid.
</Text>
</Box>
),
Expand Down
60 changes: 60 additions & 0 deletions apps/docs/src/components/Center.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Box, Center, Text, centerRecipe } from '@reactive/silk';
import type { Meta, StoryObj } from 'storybook-react-rsbuild';
import type { CSSProperties } from 'react';

const meta = {
title: 'Components/Center',
component: Center,
tags: ['autodocs'],
args: {
...centerRecipe.defaults,
},
argTypes: {
axis: {
control: 'select',
options: [...centerRecipe.variants.axis],
},
},
} satisfies Meta<typeof Center>;

export default meta;

type Story = StoryObj<typeof meta>;

const frameStyle: CSSProperties = {
height: '10rem',
border: '1px dashed var(--silk-color-border-subtle)',
borderRadius: 'var(--silk-radius-md)',
backgroundColor: 'var(--silk-color-surface-raised)',
};

const badgeStyle: CSSProperties = {
padding: 'var(--silk-space-2) var(--silk-space-3)',
borderRadius: 'var(--silk-radius-md)',
backgroundColor: 'var(--silk-color-tone-accent-subtle)',
color: 'var(--silk-color-tone-accent-solid)',
};

export const Both: Story = {
args: {
axis: 'both',
style: frameStyle,
children: (
<Box style={badgeStyle}>
<Text role="label">Centered</Text>
</Box>
),
},
};

export const Inline: Story = {
args: {
axis: 'inline',
style: frameStyle,
children: (
<Box style={badgeStyle}>
<Text role="label">Inline axis</Text>
</Box>
),
},
};
64 changes: 64 additions & 0 deletions apps/docs/src/components/Container.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Box, Container, Stack, Text, containerRecipe } from '@reactive/silk';
import type { Meta, StoryObj } from 'storybook-react-rsbuild';
import type { CSSProperties, JSX } from 'react';

const meta = {
title: 'Components/Container',
component: Container,
tags: ['autodocs'],
args: {
...containerRecipe.defaults,
},
argTypes: {
size: {
control: 'select',
options: [...containerRecipe.variants.size],
},
padding: {
control: 'select',
options: [...containerRecipe.variants.padding],
},
},
} satisfies Meta<typeof Container>;

export default meta;

type Story = StoryObj<typeof meta>;

const panelStyle: CSSProperties = {
padding: 'var(--silk-space-4)',
borderRadius: 'var(--silk-radius-md)',
border: '1px solid var(--silk-color-border-subtle)',
backgroundColor: 'var(--silk-color-surface-raised)',
};

export const Sizes: Story = {
parameters: { controls: { disable: true } },
render: (): JSX.Element => (
<Stack gap="4">
{containerRecipe.variants.size.map((size) => (
<Container key={size} size={size} padding="3">
<Box style={panelStyle}>
<Text role="label">size="{size}"</Text>
<Text tone="secondary" role="caption">
Centered max-width column with container-type for collapseBelow.
</Text>
</Box>
</Container>
))}
</Stack>
),
};

export const Default: Story = {
args: {
children: (
<Box style={panelStyle}>
<Text role="heading">Container</Text>
<Text tone="secondary">
Default size is lg with horizontal padding from space tokens.
</Text>
</Box>
),
},
};
Loading
Loading