@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.
- package/dist/app-shell-core.css +1 -1
- package/dist/app-shell.d.ts +811 -131
- package/dist/app-shell.js +7155 -5797
- package/dist/{appshell-DLVBFo5J.js → appshell-CahhZy7v.js} +656 -524
- package/dist/semantic-contrast.test.ts +154 -0
- package/dist/style-entry.d.ts +147 -92
- package/dist/testing.d.ts +152 -95
- package/dist/testing.js +1 -1
- package/dist/theme-bridge.test.ts +101 -1
- package/dist/theme.bridge.css +91 -0
- package/dist/theme.css +6 -1
- package/dist/themes/_template.css +7 -1
- package/dist/themes/bloom.css +0 -6
- package/dist/themes/cream.css +0 -6
- package/dist/themes/default.css +389 -69
- package/dist/vite-plugin.d.ts +147 -92
- package/package.json +8 -8
- package/skills/app-shell-patterns/SKILL.md +108 -19
- package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
- package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
- package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
- package/skills/app-shell-patterns/references/api/define-module.md +247 -0
- package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
- package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
- package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
- package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
- package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
- package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
- package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
- package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
- package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-config.md +132 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-data.md +150 -0
- package/skills/app-shell-patterns/references/api/use-app-shell.md +150 -0
- package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
- package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
- package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
- package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
- package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
- package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
- package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
- package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
- package/skills/app-shell-patterns/references/api/use-toast.md +104 -0
- package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
- package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
- package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
- package/skills/app-shell-patterns/references/components/alert.md +202 -0
- package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
- package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
- package/skills/app-shell-patterns/references/components/attachment.md +138 -0
- package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
- package/skills/app-shell-patterns/references/components/avatar.md +80 -0
- package/skills/app-shell-patterns/references/components/badge.md +309 -0
- package/skills/app-shell-patterns/references/components/button.md +164 -0
- package/skills/app-shell-patterns/references/components/card.md +181 -0
- package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
- package/skills/app-shell-patterns/references/components/combobox.md +318 -0
- package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
- package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
- package/skills/app-shell-patterns/references/components/data-table.md +1168 -0
- package/skills/app-shell-patterns/references/components/date-picker.md +259 -0
- package/skills/app-shell-patterns/references/components/default-header.md +75 -0
- package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
- package/skills/app-shell-patterns/references/components/description-card.md +569 -0
- package/skills/app-shell-patterns/references/components/dialog.md +164 -0
- package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
- package/skills/app-shell-patterns/references/components/filter-rail.md +165 -0
- package/skills/app-shell-patterns/references/components/form.md +378 -0
- package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
- package/skills/app-shell-patterns/references/components/grid.md +184 -0
- package/skills/app-shell-patterns/references/components/input.md +83 -0
- package/skills/app-shell-patterns/references/components/layout.md +539 -0
- package/skills/app-shell-patterns/references/components/menu.md +218 -0
- package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
- package/skills/app-shell-patterns/references/components/select.md +283 -0
- package/skills/app-shell-patterns/references/components/sheet.md +237 -0
- package/skills/app-shell-patterns/references/components/sidebar-group.md +472 -0
- package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
- package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
- package/skills/app-shell-patterns/references/components/sidebar-section.md +114 -0
- package/skills/app-shell-patterns/references/components/spinner.md +81 -0
- package/skills/app-shell-patterns/references/components/table.md +188 -0
- package/skills/app-shell-patterns/references/components/tabs.md +158 -0
- package/skills/app-shell-patterns/references/components/textarea.md +122 -0
- package/skills/app-shell-patterns/references/components/timeline.md +317 -0
- package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
- package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
- package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
- package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
- package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
- package/skills/app-shell-patterns/references/concepts/file-based-routing.md +356 -0
- package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +31 -18
- package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
- package/skills/app-shell-patterns/references/concepts/routing-navigation.md +425 -0
- package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +420 -0
- package/skills/app-shell-patterns/references/concepts/styling-theming.md +785 -0
- package/skills/app-shell-patterns/references/migrations.md +55 -0
- package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +10 -33
- package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
- package/skills/app-shell-patterns/references/patterns/form-modal.md +37 -92
- package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
- package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
- package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
- package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
- package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +136 -139
- package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
- package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +13 -88
- package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
- 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
|
+
```
|