@tailor-platform/app-shell 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/app-shell-core.css +1 -1
  2. package/dist/app-shell.d.ts +811 -131
  3. package/dist/app-shell.js +7155 -5797
  4. package/dist/{appshell-DLVBFo5J.js → appshell-CahhZy7v.js} +656 -524
  5. package/dist/semantic-contrast.test.ts +154 -0
  6. package/dist/style-entry.d.ts +147 -92
  7. package/dist/testing.d.ts +152 -95
  8. package/dist/testing.js +1 -1
  9. package/dist/theme-bridge.test.ts +101 -1
  10. package/dist/theme.bridge.css +91 -0
  11. package/dist/theme.css +6 -1
  12. package/dist/themes/_template.css +7 -1
  13. package/dist/themes/bloom.css +0 -6
  14. package/dist/themes/cream.css +0 -6
  15. package/dist/themes/default.css +389 -69
  16. package/dist/vite-plugin.d.ts +147 -92
  17. package/package.json +8 -8
  18. package/skills/app-shell-patterns/SKILL.md +108 -19
  19. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
  20. package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
  21. package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
  22. package/skills/app-shell-patterns/references/api/define-module.md +247 -0
  23. package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
  24. package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
  25. package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
  26. package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
  27. package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
  28. package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
  29. package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
  30. package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
  31. package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
  32. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +132 -0
  33. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +150 -0
  34. package/skills/app-shell-patterns/references/api/use-app-shell.md +150 -0
  35. package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
  36. package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
  37. package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
  38. package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
  39. package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
  40. package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
  41. package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
  42. package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
  43. package/skills/app-shell-patterns/references/api/use-toast.md +104 -0
  44. package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
  45. package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
  46. package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
  47. package/skills/app-shell-patterns/references/components/alert.md +202 -0
  48. package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
  49. package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
  50. package/skills/app-shell-patterns/references/components/attachment.md +138 -0
  51. package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
  52. package/skills/app-shell-patterns/references/components/avatar.md +80 -0
  53. package/skills/app-shell-patterns/references/components/badge.md +309 -0
  54. package/skills/app-shell-patterns/references/components/button.md +164 -0
  55. package/skills/app-shell-patterns/references/components/card.md +181 -0
  56. package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
  57. package/skills/app-shell-patterns/references/components/combobox.md +318 -0
  58. package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
  59. package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
  60. package/skills/app-shell-patterns/references/components/data-table.md +1168 -0
  61. package/skills/app-shell-patterns/references/components/date-picker.md +259 -0
  62. package/skills/app-shell-patterns/references/components/default-header.md +75 -0
  63. package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
  64. package/skills/app-shell-patterns/references/components/description-card.md +569 -0
  65. package/skills/app-shell-patterns/references/components/dialog.md +164 -0
  66. package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
  67. package/skills/app-shell-patterns/references/components/filter-rail.md +165 -0
  68. package/skills/app-shell-patterns/references/components/form.md +378 -0
  69. package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
  70. package/skills/app-shell-patterns/references/components/grid.md +184 -0
  71. package/skills/app-shell-patterns/references/components/input.md +83 -0
  72. package/skills/app-shell-patterns/references/components/layout.md +539 -0
  73. package/skills/app-shell-patterns/references/components/menu.md +218 -0
  74. package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
  75. package/skills/app-shell-patterns/references/components/select.md +283 -0
  76. package/skills/app-shell-patterns/references/components/sheet.md +237 -0
  77. package/skills/app-shell-patterns/references/components/sidebar-group.md +472 -0
  78. package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
  79. package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
  80. package/skills/app-shell-patterns/references/components/sidebar-section.md +114 -0
  81. package/skills/app-shell-patterns/references/components/spinner.md +81 -0
  82. package/skills/app-shell-patterns/references/components/table.md +188 -0
  83. package/skills/app-shell-patterns/references/components/tabs.md +158 -0
  84. package/skills/app-shell-patterns/references/components/textarea.md +122 -0
  85. package/skills/app-shell-patterns/references/components/timeline.md +317 -0
  86. package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
  87. package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
  88. package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
  89. package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
  90. package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
  91. package/skills/app-shell-patterns/references/concepts/file-based-routing.md +356 -0
  92. package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +31 -18
  93. package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
  94. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +425 -0
  95. package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +420 -0
  96. package/skills/app-shell-patterns/references/concepts/styling-theming.md +785 -0
  97. package/skills/app-shell-patterns/references/migrations.md +55 -0
  98. package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +10 -33
  99. package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
  100. package/skills/app-shell-patterns/references/patterns/form-modal.md +37 -92
  101. package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
  102. package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
  103. package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
  104. package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
  105. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +136 -139
  106. package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
  107. package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +13 -88
  108. package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
  109. package/skills/app-shell-patterns/references/fundamental/design-system.md +0 -440
@@ -0,0 +1,158 @@
1
+ ---
2
+ title: Tabs
3
+ description: Tab navigation with a compound component API
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/tabs.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Tabs
9
+
10
+ The `Tabs` component provides tab-based navigation for toggling between related panels on the same page. It is backed by Base UI's Tabs primitive.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { Tabs } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ <example-preview name="basic-usage"></example-preview>
21
+
22
+ ```tsx
23
+ function BasicUsage() {
24
+ return (
25
+ <Tabs.Root defaultValue="overview">
26
+ <Tabs.List>
27
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
28
+ <Tabs.Tab value="projects">Projects</Tabs.Tab>
29
+ <Tabs.Tab value="account">Account</Tabs.Tab>
30
+ </Tabs.List>
31
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
32
+ <Tabs.Panel value="projects">Projects content</Tabs.Panel>
33
+ <Tabs.Panel value="account">Account content</Tabs.Panel>
34
+ </Tabs.Root>
35
+ );
36
+ }
37
+ ```
38
+
39
+ ## Sub-components
40
+
41
+ | Sub-component | Description |
42
+ | ------------- | -------------------------------------------------------------- |
43
+ | `Tabs.Root` | Manages tab selection state |
44
+ | `Tabs.List` | Groups the individual tab buttons |
45
+ | `Tabs.Tab` | An interactive tab button that toggles the corresponding panel |
46
+ | `Tabs.Panel` | A panel displayed when the corresponding tab is active |
47
+
48
+ ## Props
49
+
50
+ ### Tabs.Root Props
51
+
52
+ | Prop | Type | Default | Description |
53
+ | --------------- | ----------------------------------- | ----------- | ------------------------------------------------------------- |
54
+ | `defaultValue` | `Tabs.Tab.Value` | `0` | Initial active tab value (uncontrolled) |
55
+ | `value` | `Tabs.Tab.Value` | - | Controlled active tab value |
56
+ | `onValueChange` | `(value: any) => void` | - | Callback when the active tab changes |
57
+ | `variant` | `'default' \| 'line' \| 'capsule'` | `'default'` | Visual style of the tabs |
58
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'default'` | Minimum size (`capsule` only) — mirrors Button's height tiers |
59
+ | `className` | `string` | - | Additional CSS classes for root |
60
+ | `children` | `React.ReactNode` | - | Tabs sub-components |
61
+
62
+ ### Tabs.List Props
63
+
64
+ Accepts `className` and all standard HTML `<div>` props.
65
+
66
+ ### Tabs.Tab Props
67
+
68
+ | Prop | Type | Default | Description |
69
+ | ---------- | ---------------- | ------- | ---------------------------------- |
70
+ | `value` | `Tabs.Tab.Value` | - | **Required.** The value of the tab |
71
+ | `disabled` | `boolean` | - | Whether the tab is disabled |
72
+
73
+ Also accepts `className` and all standard HTML `<button>` props.
74
+
75
+ ### Tabs.Panel Props
76
+
77
+ | Prop | Type | Default | Description |
78
+ | ------------- | ---------------- | ------- | ------------------------------------------------------ |
79
+ | `value` | `Tabs.Tab.Value` | - | **Required.** The value matching the corresponding tab |
80
+ | `keepMounted` | `boolean` | `false` | Whether to keep the panel in the DOM when hidden |
81
+
82
+ Also accepts `className` and all standard HTML `<div>` props.
83
+
84
+ ## Controlled Usage
85
+
86
+ ```tsx
87
+ const [activeTab, setActiveTab] = useState("overview");
88
+
89
+ <Tabs.Root value={activeTab} onValueChange={setActiveTab}>
90
+ <Tabs.List>
91
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
92
+ <Tabs.Tab value="details">Details</Tabs.Tab>
93
+ </Tabs.List>
94
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
95
+ <Tabs.Panel value="details">Details content</Tabs.Panel>
96
+ </Tabs.Root>;
97
+ ```
98
+
99
+ ## Examples
100
+
101
+ ### With Disabled Tab
102
+
103
+ ```tsx
104
+ <Tabs.Root defaultValue="active">
105
+ <Tabs.List>
106
+ <Tabs.Tab value="active">Active</Tabs.Tab>
107
+ <Tabs.Tab value="pending">Pending</Tabs.Tab>
108
+ <Tabs.Tab value="archived" disabled>
109
+ Archived
110
+ </Tabs.Tab>
111
+ </Tabs.List>
112
+ <Tabs.Panel value="active">Active items</Tabs.Panel>
113
+ <Tabs.Panel value="pending">Pending items</Tabs.Panel>
114
+ <Tabs.Panel value="archived">Archived items</Tabs.Panel>
115
+ </Tabs.Root>
116
+ ```
117
+
118
+ ### Use Icons in Tab
119
+
120
+ In the `capsule` variant, a tab whose only child is an icon renders **square** —
121
+ its `min-width` matches its `min-height` — making it a natural fit for icon-only
122
+ view toggles (e.g. table/kanban). Use `size` to align the track with a sibling
123
+ `Button`: `size="default"` (36px) matches `Button`'s default height. Unsized
124
+ icons default to `16px`, so the square is consistent regardless of the icon.
125
+
126
+ > **Accessibility:** an icon-only tab has no visible text, so give each one an
127
+ > `aria-label`. Without it, screen readers announce an unnamed tab.
128
+
129
+ ```tsx
130
+ <Tabs.Root defaultValue="overview" variant="capsule" size="default">
131
+ <Tabs.List>
132
+ <Tabs.Tab value="overview" aria-label="Overview">
133
+ <LayoutDashboardIcon />
134
+ </Tabs.Tab>
135
+ <Tabs.Tab value="projects" aria-label="Projects">
136
+ <FolderKanbanIcon />
137
+ </Tabs.Tab>
138
+ <Tabs.Tab value="settings" aria-label="Settings">
139
+ <SettingsIcon />
140
+ </Tabs.Tab>
141
+ </Tabs.List>
142
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
143
+ <Tabs.Panel value="projects">Projects content</Tabs.Panel>
144
+ <Tabs.Panel value="settings">Settings content</Tabs.Panel>
145
+ </Tabs.Root>
146
+ ```
147
+
148
+ ### Sizing the capsule variant
149
+
150
+ `size` mirrors `Button`'s height tiers, so a capsule can sit flush next to a
151
+ button. The value sets a **minimum** height — taller content still grows.
152
+
153
+ | `size` | Track height | Matches Button |
154
+ | --------- | ------------ | -------------- |
155
+ | `xs` | 28px | `size="xs"` |
156
+ | `sm` | 32px | `size="sm"` |
157
+ | `default` | 36px | default |
158
+ | `lg` | 40px | `size="lg"` |
@@ -0,0 +1,122 @@
1
+ ---
2
+ title: Textarea
3
+ description: Styled multi-line text input sized by rows, with automatic Field / React Hook Form integration
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/textarea.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Textarea
9
+
10
+ The `Textarea` component is a styled multi-line text input. It wraps Base UI's field control rendered as a `<textarea>`, so it works with [`Field`](./form.md) and React Hook Form the same way `Input`, `Checkbox`, and `Select` do — dropped inside a `Field.Root` it inherits label association, `aria-describedby`, `disabled`, and the invalid (error) state automatically.
11
+
12
+ Unlike `Input`, it has no fixed height: `rows` sets the visible line count (floored at `min-h-16`) and the user can drag the box taller, so long text stays readable instead of scrolling inside a single-line window.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { Textarea } from "@tailor-platform/app-shell";
18
+ ```
19
+
20
+ ## Basic Usage
21
+
22
+ <example-preview name="basic-usage"></example-preview>
23
+
24
+ ```tsx
25
+ function BasicUsage() {
26
+ return <Textarea placeholder="Add a note…" />;
27
+ }
28
+ ```
29
+
30
+ ## Props
31
+
32
+ Accepts Base UI's field-control props plus the standard HTML `<textarea>` props, minus `cols` and `wrap` — the control is always `w-full`, so `cols` could never affect its width, and every `wrap` value depends on `cols` being set. The most common:
33
+
34
+ | Prop | Type | Default | Description |
35
+ | --------------- | --------------------------------------- | ------- | ------------------------------------------------------- |
36
+ | `value` | `string` | - | Controlled value. |
37
+ | `defaultValue` | `string` | - | Initial value when uncontrolled. |
38
+ | `onChange` | `(event) => void` | - | Native change handler. |
39
+ | `onValueChange` | `(value: string, eventDetails) => void` | - | Called with the next string value. |
40
+ | `rows` | `number` | - | Visible line count — the height knob. |
41
+ | `placeholder` | `string` | - | Placeholder text. |
42
+ | `disabled` | `boolean` | `false` | Disables the control. |
43
+ | `required` | `boolean` | `false` | Marks the control required for native/Field validation. |
44
+ | `readOnly` | `boolean` | `false` | Renders the value without allowing edits. |
45
+ | `name` | `string` | - | Field name for native form submission. |
46
+ | `className` | `string` | - | Additional CSS classes. |
47
+
48
+ ## Examples
49
+
50
+ ### Controlled
51
+
52
+ ```tsx
53
+ const [note, setNote] = useState("");
54
+
55
+ <Textarea value={note} onChange={(e) => setNote(e.target.value)} placeholder="Add a note…" />;
56
+ ```
57
+
58
+ ### Height
59
+
60
+ `rows` sets the visible line count, and the user can drag the box taller for a long value.
61
+
62
+ `min-h-16` (64px) is a hard floor, so `rows={1}` and `rows={2}` both render at 64px — `rows` only starts moving the height from 3 up. There is no supported way to go below the floor.
63
+
64
+ ```tsx
65
+ <Textarea rows={8} placeholder="Paste the incident log…" />
66
+ ```
67
+
68
+ > The box does not auto-grow as you type. `field-sizing: content` would do that, but the browser then ignores `rows` — leaving height settable only through a `min-h-*` utility. Use `rows` instead.
69
+
70
+ ### Disabled
71
+
72
+ ```tsx
73
+ <Textarea value="Read-only value" disabled />
74
+ ```
75
+
76
+ ## Use With Field
77
+
78
+ Placed inside a `Field.Root`, `Textarea` picks up the field's label, description, and invalid/disabled state automatically — no `error` prop of its own.
79
+
80
+ ```tsx
81
+ <Field.Root name="description">
82
+ <Field.Label>Description</Field.Label>
83
+ <Textarea placeholder="What changed?" />
84
+ <Field.Description>Optional — visible to the whole team.</Field.Description>
85
+ </Field.Root>
86
+ ```
87
+
88
+ ## React Hook Form
89
+
90
+ Drive it with a `Controller`. Spreading `field` wires `value`/`onChange`/`onBlur`, and spreading `fieldState` onto `Field.Root` wires the error/invalid state.
91
+
92
+ ```tsx
93
+ import { useForm, Controller } from "react-hook-form";
94
+ import { Field, Textarea } from "@tailor-platform/app-shell";
95
+
96
+ const { control } = useForm({ defaultValues: { description: "" } });
97
+
98
+ <Controller
99
+ name="description"
100
+ control={control}
101
+ rules={{ required: "Description is required." }}
102
+ render={({ field, fieldState }) => (
103
+ <Field.Root name={field.name} {...fieldState}>
104
+ <Field.Label>Description</Field.Label>
105
+ <Textarea {...field} />
106
+ <Field.Error match={fieldState.invalid}>{fieldState.error?.message}</Field.Error>
107
+ </Field.Root>
108
+ )}
109
+ />;
110
+ ```
111
+
112
+ ## TypeScript
113
+
114
+ ```typescript
115
+ import { type TextareaProps } from "@tailor-platform/app-shell";
116
+ ```
117
+
118
+ ## Related Components
119
+
120
+ - [Input](./input.md) - Single-line text input with the same styling and `Field` integration
121
+ - [Form](./form.md) - Form root and `Field` composition
122
+ - [Button](./button.md) - Pair with a textarea in a composer action row
@@ -0,0 +1,317 @@
1
+ ---
2
+ title: Timeline
3
+ description: Composable primitives for building time-based layouts with axis guides, row backgrounds, intervals, and dependency links
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/timeline.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Timeline
9
+
10
+ `Timeline` provides composable primitives for building time-based layouts such as Gantt charts, schedules, and project timelines. It is a compound component with five sub-components: `Root`, `Viewport`, `Row`, `Interval`, and `Link`.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { Timeline } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ ```tsx
21
+ import { Timeline } from "@tailor-platform/app-shell";
22
+
23
+ <Timeline.Root start={0} end={100}>
24
+ <Timeline.Viewport
25
+ axis={{
26
+ guides: [{ at: 0 }, { at: 50 }, { at: 100 }],
27
+ levels: [
28
+ {
29
+ kind: "spans",
30
+ items: [
31
+ { start: 0, end: 50, label: "Phase 1" },
32
+ { start: 50, end: 100, label: "Phase 2" },
33
+ ],
34
+ },
35
+ ],
36
+ }}
37
+ >
38
+ <Timeline.Row height={40}>
39
+ <Timeline.Interval start={10} end={35}>
40
+ <div className="h-full rounded-md bg-primary" />
41
+ </Timeline.Interval>
42
+ </Timeline.Row>
43
+ </Timeline.Viewport>
44
+ </Timeline.Root>;
45
+ ```
46
+
47
+ ## Sub-components
48
+
49
+ | Sub-component | Description |
50
+ | ------------------- | ------------------------------------------------------------------------------ |
51
+ | `Timeline.Root` | Provides the shared time range for all nested timeline primitives |
52
+ | `Timeline.Viewport` | Renders the axis, decorations, scrolling area, and link overlay layer |
53
+ | `Timeline.Row` | Defines one horizontal lane with a fixed height and optional background |
54
+ | `Timeline.Interval` | Positions content across a time range inside a row |
55
+ | `Timeline.Link` | Draws an orthogonal dependency connector between two named `Interval` elements |
56
+
57
+ ## TimeValue
58
+
59
+ All time position props (`start`, `end`, `at`) accept either a `Date` object or a millisecond-precision number timestamp.
60
+
61
+ ```tsx
62
+ // Using Date objects
63
+ <Timeline.Root start={new Date("2024-01-01")} end={new Date("2024-12-31")}>
64
+
65
+ // Using numeric timestamps
66
+ <Timeline.Root start={0} end={100}>
67
+ ```
68
+
69
+ ## Props
70
+
71
+ ### Timeline.Root Props
72
+
73
+ | Prop | Type | Default | Description |
74
+ | ----------- | ----------------- | ------- | -------------------------------------------------- |
75
+ | `start` | `Date \| number` | — | Inclusive start of the overall timeline range |
76
+ | `end` | `Date \| number` | — | Inclusive end of the overall timeline range |
77
+ | `children` | `React.ReactNode` | — | Timeline subtree, usually a `Timeline.Viewport` |
78
+ | `className` | `string` | — | Additional CSS classes applied to the root element |
79
+ | `style` | `CSSProperties` | — | Inline style applied to the root element |
80
+
81
+ ### Timeline.Viewport Props
82
+
83
+ | Prop | Type | Default | Description |
84
+ | -------------- | ---------------------- | ------- | --------------------------------------------------------------------- |
85
+ | `children` | `React.ReactNode` | — | Rows and links, in any order |
86
+ | `axis` | `TimelineAxis` | — | Axis configuration: guides and stacked header levels |
87
+ | `decorations` | `TimelineDecorations` | — | Decorative layers: bands and markers |
88
+ | `linkDefaults` | `TimelineLinkDefaults` | — | Shared defaults applied to all `Timeline.Link` nodes in this viewport |
89
+ | `canvasWidth` | `number` | — | Fixed canvas width in pixels for horizontally scrollable timelines |
90
+ | `stickyAxis` | `boolean` | `false` | Pins the axis to the top of the viewport during vertical scrolling |
91
+ | `className` | `string` | — | Additional CSS classes applied to the scroll viewport |
92
+ | `style` | `CSSProperties` | — | Inline style applied to the scroll viewport |
93
+
94
+ ### Timeline.Row Props
95
+
96
+ | Prop | Type | Default | Description |
97
+ | ------------ | ------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
98
+ | `children` | `React.ReactNode` | — | Row contents, typically `Timeline.Interval` elements |
99
+ | `height` | `number` | `32` | Row height in pixels |
100
+ | `background` | `TimelineRowBackground \| null` | — | Optional background rendered in a dedicated layer, in front of bands but behind guide lines |
101
+ | `className` | `string` | — | Additional CSS classes applied to the row content container |
102
+ | `style` | `CSSProperties` | — | Inline style applied to the row content container |
103
+
104
+ ### Timeline.Interval Props
105
+
106
+ | Prop | Type | Default | Description |
107
+ | ----------- | ----------------- | ------- | ------------------------------------------------------------------- |
108
+ | `start` | `Date \| number` | — | Start of the interval |
109
+ | `end` | `Date \| number` | — | End of the interval |
110
+ | `children` | `React.ReactNode` | — | Rendered content for the interval |
111
+ | `id` | `string` | — | Stable id used by `Timeline.Link` to reference this interval |
112
+ | `insetY` | `number` | `0` | Top and bottom inset in pixels within the row |
113
+ | `className` | `string` | — | Additional CSS classes applied to the positioned interval container |
114
+ | `style` | `CSSProperties` | — | Inline style applied to the positioned interval container |
115
+
116
+ ### Timeline.Link Props
117
+
118
+ | Prop | Type | Default | Description |
119
+ | ------------- | ------------------------------ | --------- | ------------------------------------------------- |
120
+ | `from` | `string` | — | Source `Timeline.Interval` id |
121
+ | `to` | `string` | — | Target `Timeline.Interval` id |
122
+ | `fromAnchor` | `"start" \| "center" \| "end"` | `"end"` | Source anchor used for routing |
123
+ | `toAnchor` | `"start" \| "center" \| "end"` | `"start"` | Target anchor used for routing |
124
+ | `arrow` | `boolean` | — | Overrides the viewport-level `linkDefaults.arrow` |
125
+ | `gap` | `number` | — | Overrides the viewport-level `linkDefaults.gap` |
126
+ | `strokeWidth` | `number` | — | Optional stroke width for the link path |
127
+ | `className` | `string` | — | Additional CSS classes applied to the link SVG |
128
+ | `style` | `CSSProperties` | — | Inline style applied to the link SVG |
129
+
130
+ ## Type Reference
131
+
132
+ ### TimelineAxis
133
+
134
+ Axis configuration for `Timeline.Viewport`.
135
+
136
+ | Field | Type | Description |
137
+ | ----------- | --------------------- | ----------------------------------------------------- |
138
+ | `guides` | `TimelineGuide[]` | Vertical boundary lines rendered in the axis and body |
139
+ | `levels` | `TimelineAxisLevel[]` | Stacked header levels rendered above the body |
140
+ | `className` | `string` | Optional class applied to the axis container |
141
+
142
+ ### TimelineAxisLevel
143
+
144
+ A stacked axis level. Has a discriminated union `kind` field:
145
+
146
+ - `kind: "spans"` — renders labeled time ranges (`TimelineAxisSpan[]`)
147
+ - `kind: "ticks"` — renders labeled point-in-time markers (`TimelineAxisTick[]`)
148
+
149
+ | Field | Type | Default | Description |
150
+ | ----------- | ------------------------------------------ | ------- | --------------------------------------------- |
151
+ | `kind` | `"spans" \| "ticks"` | — | Level rendering mode |
152
+ | `items` | `TimelineAxisSpan[] \| TimelineAxisTick[]` | — | Items to render in this level |
153
+ | `height` | `number` | `28` | Height of this axis level in pixels |
154
+ | `className` | `string` | — | Optional class applied to the level container |
155
+
156
+ ### TimelineGuide
157
+
158
+ A vertical guide line rendered in both the axis and the body.
159
+
160
+ | Field | Type | Description |
161
+ | --------------- | ---------------- | ------------------------------------------------ |
162
+ | `at` | `Date \| number` | Time position for the guide line |
163
+ | `key` | `React.Key` | Optional stable React key |
164
+ | `axisClassName` | `string` | Optional class for the axis portion of the guide |
165
+ | `axisStyle` | `CSSProperties` | Optional style for the axis portion of the guide |
166
+ | `bodyClassName` | `string` | Optional class for the body portion of the guide |
167
+ | `bodyStyle` | `CSSProperties` | Optional style for the body portion of the guide |
168
+
169
+ ### TimelineDecorations
170
+
171
+ Decorative layers rendered by `Timeline.Viewport`.
172
+
173
+ | Field | Type | Description |
174
+ | --------- | ------------------ | ------------------------------------------------- |
175
+ | `bands` | `TimelineBand[]` | Background range highlights rendered behind rows |
176
+ | `markers` | `TimelineMarker[]` | Vertical markers rendered in the axis and/or body |
177
+
178
+ ### TimelineBand
179
+
180
+ A decorative horizontal band rendered behind rows.
181
+
182
+ | Field | Type | Description |
183
+ | ----------- | ---------------- | ------------------------------------------ |
184
+ | `start` | `Date \| number` | Start of the band |
185
+ | `end` | `Date \| number` | End of the band |
186
+ | `key` | `React.Key` | Optional stable React key |
187
+ | `color` | `string` | Optional background color convenience prop |
188
+ | `className` | `string` | Optional class applied to the band element |
189
+ | `style` | `CSSProperties` | Optional inline style applied to the band |
190
+
191
+ ### TimelineMarker
192
+
193
+ A decorative vertical marker line.
194
+
195
+ | Field | Type | Default | Description |
196
+ | ---------------- | ---------------------------- | -------- | -------------------------------------------------- |
197
+ | `at` | `Date \| number` | — | Time position for the marker |
198
+ | `key` | `React.Key` | — | Optional stable React key |
199
+ | `color` | `string` | — | Optional line color convenience prop |
200
+ | `label` | `React.ReactNode` | — | Optional marker label |
201
+ | `placement` | `"axis" \| "body" \| "both"` | `"body"` | Controls where the marker is rendered |
202
+ | `className` | `string` | — | Optional class applied to the outer marker wrapper |
203
+ | `lineClassName` | `string` | — | Optional class applied to the marker line |
204
+ | `labelClassName` | `string` | — | Optional class applied to the marker label |
205
+
206
+ ### TimelineLinkDefaults
207
+
208
+ Shared defaults for all `Timeline.Link` nodes inside one viewport.
209
+
210
+ | Field | Type | Default | Description |
211
+ | ------------- | --------------- | -------------- | -------------------------------------------------------- |
212
+ | `routing` | `"orthogonal"` | `"orthogonal"` | Link routing strategy |
213
+ | `arrow` | `boolean` | `true` | Whether links end with an arrow marker |
214
+ | `gap` | `number` | `16` | Horizontal gap in px used when routing out of/into items |
215
+ | `strokeWidth` | `number` | — | Optional default stroke width for link paths |
216
+ | `className` | `string` | — | Optional class applied to each link SVG |
217
+ | `style` | `CSSProperties` | — | Optional style applied to each link SVG |
218
+
219
+ ### TimelineRowBackground
220
+
221
+ Background content for a row rendered in a dedicated layer (in front of bands, behind guides).
222
+
223
+ | Field | Type | Description |
224
+ | ----------- | --------------- | ------------------------------------------------------ |
225
+ | `className` | `string` | Optional class applied to the background layer element |
226
+ | `style` | `CSSProperties` | Optional style applied to the background layer element |
227
+
228
+ ## Examples
229
+
230
+ ### Horizontal Scrolling
231
+
232
+ Use `canvasWidth` on `Timeline.Viewport` to enable horizontal scrolling:
233
+
234
+ ```tsx
235
+ <Timeline.Root start={projectStart} end={projectEnd}>
236
+ <Timeline.Viewport canvasWidth={2400} axis={axis}>
237
+ {rows}
238
+ </Timeline.Viewport>
239
+ </Timeline.Root>
240
+ ```
241
+
242
+ ### Sticky Axis
243
+
244
+ Pin the axis to the top during vertical scrolling with `stickyAxis`:
245
+
246
+ ```tsx
247
+ <Timeline.Root start={0} end={100}>
248
+ <Timeline.Viewport stickyAxis axis={axis}>
249
+ {rows}
250
+ </Timeline.Viewport>
251
+ </Timeline.Root>
252
+ ```
253
+
254
+ ### Dependency Links
255
+
256
+ Use `id` on `Timeline.Interval` and `Timeline.Link` to draw dependency connectors:
257
+
258
+ ```tsx
259
+ <Timeline.Root start={0} end={100}>
260
+ <Timeline.Viewport
261
+ linkDefaults={{ style: { color: "var(--muted-foreground)" }, strokeWidth: 1.5 }}
262
+ >
263
+ <Timeline.Row height={40}>
264
+ <Timeline.Interval id="task-a" start={10} end={40}>
265
+ <div className="h-full rounded-md bg-primary" />
266
+ </Timeline.Interval>
267
+ </Timeline.Row>
268
+ <Timeline.Row height={40}>
269
+ <Timeline.Interval id="task-b" start={50} end={80}>
270
+ <div className="h-full rounded-md bg-secondary" />
271
+ </Timeline.Interval>
272
+ </Timeline.Row>
273
+ <Timeline.Link from="task-a" to="task-b" />
274
+ </Timeline.Viewport>
275
+ </Timeline.Root>
276
+ ```
277
+
278
+ ### Background Bands and Markers
279
+
280
+ Use `decorations` to add background highlights and vertical marker lines:
281
+
282
+ ```tsx
283
+ <Timeline.Viewport
284
+ axis={axis}
285
+ decorations={{
286
+ bands: [
287
+ {
288
+ start: freezeStart,
289
+ end: freezeEnd,
290
+ color: "var(--destructive/10)",
291
+ className: "border-x border-destructive/30",
292
+ },
293
+ ],
294
+ markers: [
295
+ {
296
+ at: today,
297
+ color: "var(--primary)",
298
+ label: <span className="text-xs text-primary">Today</span>,
299
+ },
300
+ ],
301
+ }}
302
+ >
303
+ {rows}
304
+ </Timeline.Viewport>
305
+ ```
306
+
307
+ ### Row Background
308
+
309
+ Use `background` on `Timeline.Row` to apply a background that respects guide lines:
310
+
311
+ ```tsx
312
+ <Timeline.Row height={40} background={{ style: { background: "var(--muted)" } }}>
313
+ <Timeline.Interval start={10} end={35}>
314
+ <div className="h-full rounded-md bg-primary" />
315
+ </Timeline.Interval>
316
+ </Timeline.Row>
317
+ ```