division-ds 0.2.0 → 0.3.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/AGENTS.md +11 -5
- package/division-ds-0.3.0.tgz +0 -0
- package/package.json +1 -1
- package/public/docs/components/accordion.md +2 -0
- package/public/docs/components/ai-label.md +2 -0
- package/public/docs/components/alert-dialog.md +2 -0
- package/public/docs/components/alert.md +2 -0
- package/public/docs/components/approval-request.md +2 -0
- package/public/docs/components/auth-form.md +2 -0
- package/public/docs/components/avatar-group.md +2 -0
- package/public/docs/components/avatar.md +2 -0
- package/public/docs/components/badge.md +2 -0
- package/public/docs/components/breadcrumbs.md +2 -0
- package/public/docs/components/button.md +2 -0
- package/public/docs/components/card.md +2 -0
- package/public/docs/components/carousel.md +2 -0
- package/public/docs/components/cart.md +2 -0
- package/public/docs/components/chart-panel.md +2 -0
- package/public/docs/components/chat-message.md +3 -0
- package/public/docs/components/chat-thread.md +2 -0
- package/public/docs/components/checkbox.md +2 -0
- package/public/docs/components/checkout-form.md +2 -0
- package/public/docs/components/command-palette.md +6 -1
- package/public/docs/components/data-table.md +2 -0
- package/public/docs/components/date-picker.md +166 -0
- package/public/docs/components/date-presets.md +111 -0
- package/public/docs/components/date-range-picker.md +135 -0
- package/public/docs/components/description-list.md +2 -0
- package/public/docs/components/dialog.md +2 -0
- package/public/docs/components/divider.md +2 -0
- package/public/docs/components/dropdown-menu.md +2 -0
- package/public/docs/components/empty-state.md +2 -0
- package/public/docs/components/footer.md +2 -0
- package/public/docs/components/form-field.md +4 -1
- package/public/docs/components/icon-button.md +2 -0
- package/public/docs/components/input.md +2 -0
- package/public/docs/components/kanban-board.md +2 -0
- package/public/docs/components/kbd.md +2 -0
- package/public/docs/components/link.md +2 -0
- package/public/docs/components/list-item.md +3 -0
- package/public/docs/components/loading-animation.md +2 -0
- package/public/docs/components/multi-select.md +2 -0
- package/public/docs/components/navbar.md +2 -0
- package/public/docs/components/newsletter-form.md +2 -0
- package/public/docs/components/page-header.md +2 -0
- package/public/docs/components/pagination.md +2 -0
- package/public/docs/components/product-card.md +3 -0
- package/public/docs/components/progress.md +3 -1
- package/public/docs/components/prompt-input.md +2 -0
- package/public/docs/components/quantity-stepper.md +2 -0
- package/public/docs/components/radio.md +38 -1
- package/public/docs/components/rating.md +2 -0
- package/public/docs/components/score-ring.md +2 -0
- package/public/docs/components/search.md +2 -0
- package/public/docs/components/section-heading.md +2 -0
- package/public/docs/components/segmented-control.md +2 -0
- package/public/docs/components/select.md +3 -1
- package/public/docs/components/sheet.md +2 -0
- package/public/docs/components/sidebar.md +2 -0
- package/public/docs/components/skeleton.md +2 -0
- package/public/docs/components/slider.md +3 -1
- package/public/docs/components/sparkline.md +2 -0
- package/public/docs/components/spinner.md +4 -2
- package/public/docs/components/stat.md +2 -0
- package/public/docs/components/status-tracker.md +2 -0
- package/public/docs/components/stepper.md +2 -0
- package/public/docs/components/switch.md +4 -2
- package/public/docs/components/tabs.md +2 -0
- package/public/docs/components/tag.md +2 -0
- package/public/docs/components/textarea.md +2 -0
- package/public/docs/components/time-field.md +127 -0
- package/public/docs/components/timeline.md +2 -0
- package/public/docs/components/toast.md +2 -0
- package/public/docs/components/tool-call.md +2 -0
- package/public/docs/components/tooltip.md +2 -0
- package/public/manifest/components.json +947 -72
- package/public/manifest/tokens.json +36 -5
- package/scripts/division-ds.mjs +5 -5
- package/scripts/lib/agent-docs.mjs +49 -6
- package/scripts/lib/ai-copy.mjs +15 -1
- package/scripts/lib/check-text.mjs +13 -0
- package/scripts/lib/mcp-server.mjs +2 -1
- package/scripts/lib/mcp-tools.mjs +25 -12
- package/scripts/lib/props-validator.mjs +2 -1
- package/scripts/lib/search-score.mjs +24 -0
- package/scripts/lib/token-discipline.mjs +10 -3
- package/skills/division-ds/SKILL.md +2 -2
- package/skills/division-ds/commands/add.md +1 -1
- package/skills/division-ds/commands/build.md +1 -1
- package/skills/division-ds/commands/fix.md +1 -1
- package/skills/division-ds/commands/review.md +2 -2
- package/skills/division-ds/topics/ai.md +2 -1
- package/skills/division-ds/topics/forms.md +3 -0
- package/skills/division-ds/topics/layout.md +3 -1
- package/division-ds-0.2.0.tgz +0 -0
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Division DS: instructions for coding agents
|
|
2
2
|
|
|
3
|
-
A React 19 + Tailwind 4 + Radix design system:
|
|
3
|
+
A React 19 + Tailwind 4 + Radix design system: 72 components, tokens in three layers, light and
|
|
4
4
|
dark themes, WCAG 2.2 AA. This file is the entry point. It is short on purpose; everything it
|
|
5
5
|
points to is generated from the code, so it is current.
|
|
6
6
|
|
|
@@ -51,7 +51,7 @@ installs these rules into that project's `AGENTS.md`, `GEMINI.md` and Cursor rul
|
|
|
51
51
|
`.claude/skills/` (Claude Code).
|
|
52
52
|
|
|
53
53
|
An agent that supports MCP can have the docs and the same checks as tools instead:
|
|
54
|
-
`claude mcp add division-ds -- npx -y division-ds mcp` (`list_components`, `get_component`,
|
|
54
|
+
`claude mcp add division-ds -- npx -y division-ds@0.3.0 mcp` (`list_components`, `get_component`,
|
|
55
55
|
`search`, `get_tokens`, `validate_code`, `check_contrast`, `get_add_command`,
|
|
56
56
|
`get_review_checklist`).
|
|
57
57
|
|
|
@@ -91,7 +91,7 @@ provider. A project that uses the components mounts both itself (step 4 of `inst
|
|
|
91
91
|
`src/demo/states/` files are not part of the system.
|
|
92
92
|
|
|
93
93
|
**What the system does not have.** No Popover, no Combobox (single value: use `Select`; several:
|
|
94
|
-
`MultiSelect`)
|
|
94
|
+
`MultiSelect`). Do not reach into `src/demo/` from a component.
|
|
95
95
|
|
|
96
96
|
**Vocabulary.** Inside this repository, `npm run check:vocabulary` bans a list of words in `src/`,
|
|
97
97
|
`scripts/` and `e2e/` (the list is `scripts/lib/vocabulary.mjs`; it is not published with the
|
|
@@ -116,7 +116,9 @@ The shell paints the page background (`surface.base`) and supplies the gutter; a
|
|
|
116
116
|
own `max-w-*` and vertical spacing, and no page background. A form or an overlay is the
|
|
117
117
|
exception: it paints `surface.base` on itself, so its field colours never depend on what is
|
|
118
118
|
behind it. In a project that uses the components, your own root does this
|
|
119
|
-
(step 4 of `install.md`).
|
|
119
|
+
(step 4 of `install.md`). Toggle it with `setTheme()` from `src/lib/theme.ts`.
|
|
120
|
+
|
|
121
|
+
**App navigation.** A few views: `Navbar` (`current: true` on the open one). Many: `Sidebar`.
|
|
120
122
|
|
|
121
123
|
**Type.** Three families, as utilities: `font-display` (headings, figures), `font-body` (the
|
|
122
124
|
default, set by the shell), `font-mono` (labels, code, tabular numbers). A page title is
|
|
@@ -151,6 +153,9 @@ bare and name it through its own `label` prop ("Role for Ilse Varga"). `Switch`,
|
|
|
151
153
|
renders `ErrorSummary` at the top and focuses it; `useFieldErrors` holds the state (signature in
|
|
152
154
|
`public/docs/helpers.md`).
|
|
153
155
|
|
|
156
|
+
A `RadioGroup` in a form sits in a `<fieldset>` whose `<legend>` names it (code on the Radio
|
|
157
|
+
page). A date is `DatePicker` in a `FormField`; its value is 'YYYY-MM-DD'.
|
|
158
|
+
|
|
154
159
|
**Buttons.** Two or more buttons side by side need a parent with a gap
|
|
155
160
|
(`flex flex-wrap gap-3`); `DialogFooter` and `CardFooter` already are one. A `Button` is
|
|
156
161
|
`type="button"` unless you say `type="submit"`. A busy button takes `loading`, not `disabled`.
|
|
@@ -188,7 +193,8 @@ Tailwind), and nothing moves on its own: no autoplay.
|
|
|
188
193
|
|
|
189
194
|
**Assistant copy.** A button names the action ("Summarize"), never "AI". Say "response", not
|
|
190
195
|
"answer". No "please" or "!" in assistant labels. The interface says "Assistant"; only its own
|
|
191
|
-
messages say "I".
|
|
196
|
+
messages say "I". Response feedback: `ResponseFeedback` in `actions`.
|
|
197
|
+
A value the assistant filled is `aiValue` on that `Input` or `Textarea` only; leaving it accepts it.
|
|
192
198
|
<!-- rules:end -->
|
|
193
199
|
|
|
194
200
|
## Changing the system itself
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "division-ds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Checks a project that uses Division DS components (raw colours, invented tokens, touching buttons, unknown props), and serves the docs and the same checks to agents over MCP.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Victor Ilioiu",
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from 'src/components/molecules/accordion/Accordion'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { AiLabel } from 'src/components/atoms/ai-label/AiLabel'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogFooter, AlertDialogTrigger } from 'src/components/organisms/alert-dialog/AlertDialog'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Alert } from 'src/components/molecules/alert/Alert'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { ApprovalRequest } from 'src/components/molecules/approval-request/ApprovalRequest'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Requires
|
|
17
19
|
|
|
18
20
|
- A parent that holds the state and sets it to approved or rejected in onApprove and onReject.
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { AuthForm } from 'src/components/organisms/auth-form/AuthForm'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { AvatarGroup } from 'src/components/molecules/avatar-group/AvatarGroup'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Requires
|
|
17
19
|
|
|
18
20
|
- With overflowTooltip, the root <TooltipProvider>. AppShell and the demo layout each include one.
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Avatar, avatarVariants, initialsFrom } from 'src/components/atoms/avatar/Avatar'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Badge, badgeVariants } from 'src/components/atoms/badge/Badge'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Breadcrumbs, collapseCrumbs } from 'src/components/molecules/breadcrumbs/Breadcrumbs'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Button, buttonVariants } from 'src/components/atoms/button/Button'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Card, CardActions, CardBody, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, cardLinkClass } from 'src/components/molecules/card/Card'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Carousel } from 'src/components/organisms/carousel/Carousel'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Cart } from 'src/components/organisms/cart/Cart'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { ChartPanel } from 'src/components/organisms/chart-panel/ChartPanel'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
- **Best for:** Each turn inside a ChatThread.
|
|
6
6
|
- **Not for:** Comments or an activity history between people: use Timeline.
|
|
7
|
+
- **Also on this page:** `ResponseFeedback`
|
|
7
8
|
- Molecule. Source: `src/components/molecules/chat-message/ChatMessage.tsx`
|
|
8
9
|
- Rendered docs page: `/components/chat-message`
|
|
9
10
|
|
|
@@ -14,6 +15,8 @@ import { ChatMessage } from 'src/components/molecules/chat-message/ChatMessage'
|
|
|
14
15
|
import { ResponseFeedback } from 'src/components/molecules/chat-message/ResponseFeedback'
|
|
15
16
|
```
|
|
16
17
|
|
|
18
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
19
|
+
|
|
17
20
|
## Requires
|
|
18
21
|
|
|
19
22
|
- A ChatThread around it. Outside one, a message still shows, but nothing announces it when it finishes.
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { ChatThread } from 'src/components/organisms/chat-thread/ChatThread'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Requires
|
|
17
19
|
|
|
18
20
|
- A height, because the thread scrolls and the page doesn't. Use h-[28rem], or flex-1 min-h-0 inside a column.
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { Checkbox } from 'src/components/atoms/checkbox/Checkbox'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { CheckoutForm, DELIVERY_OPTIONS } from 'src/components/organisms/checkout-form/CheckoutForm'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
import { CommandPalette, filterCommands, groupCommands } from 'src/components/organisms/command-palette/CommandPalette'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
19
21
|
|---|---|---|---|
|
|
20
|
-
| `commands` | `Command[]` | | Required. Each has id, label, group, keywords, shortcut, icon and onSelect. |
|
|
22
|
+
| `commands` | `Command[]` | | Required. Each has id, label, description (a quieter second line), group, keywords, shortcut, icon and onSelect. |
|
|
21
23
|
| `open` | `boolean` | | Open state when controlled, meaning your code decides whether it is open. |
|
|
22
24
|
| `defaultOpen` | `boolean` | `false` | Starting open state when uncontrolled, meaning the palette keeps track of it itself. |
|
|
23
25
|
| `onOpenChange` | `(open: boolean) => void` | | Called on every open and close, including Escape and a click on the scrim (the dimmed backdrop). If you refuse the close, the chosen command stays ready to run until the user does anything else in the palette. Closing it yourself later counts as accepting it. |
|
|
@@ -26,6 +28,7 @@ import { CommandPalette, filterCommands, groupCommands } from 'src/components/or
|
|
|
26
28
|
| `searchLabel` | `string` | `'Search commands'` | The search field's accessible name. |
|
|
27
29
|
| `placeholder` | `string` | `'Type a command or search'` | Shown in the empty search field. |
|
|
28
30
|
| `emptyMessage` | `string` | `'No matching commands'` | Shown when nothing matches the search. |
|
|
31
|
+
| `filter` | `(commands: readonly Command[], query: string) => Command[]` | `filterCommands` | Your own matching and ranking. Gets every command and the query, returns the ones to show in order; groups follow that order. The docs site search uses it to rank with the same scorer as the MCP server. |
|
|
29
32
|
| `ref` | `Ref<HTMLInputElement>` | | The search field, while the palette is open. |
|
|
30
33
|
|
|
31
34
|
## Types and helpers
|
|
@@ -36,6 +39,8 @@ Exported beside the component, from the same file. Import a type with `import ty
|
|
|
36
39
|
export type Command = {
|
|
37
40
|
id: string
|
|
38
41
|
label: string
|
|
42
|
+
/** A second, quieter line under the label, e.g. what a search result is for. */
|
|
43
|
+
description?: string
|
|
39
44
|
/** Commands with the same group are drawn together under its heading. */
|
|
40
45
|
group?: string
|
|
41
46
|
/** Extra words a search matches on. */
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { DataTable, sortRows } from 'src/components/organisms/data-table/DataTable'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
16
18
|
## Props
|
|
17
19
|
|
|
18
20
|
| Prop | Type | Default | Description |
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# DatePicker
|
|
2
|
+
|
|
3
|
+
> One date, typed or picked. The field has a segment for the day, the month and the year, in the order your language writes them: type the digits and it moves on by itself, or use the arrow keys. The button inside it opens a calendar. The value is a plain 'YYYY-MM-DD' string with no time zone, so it means the same day for everyone. Calendar and DateField are exported too, for building your own.
|
|
4
|
+
|
|
5
|
+
- **Best for:** One date: a delivery day, a deadline, a birthday.
|
|
6
|
+
- **Not for:** A range: DateRangePicker. A time: TimeField.
|
|
7
|
+
- **Also on this page:** `Calendar`, `DateField`
|
|
8
|
+
- Molecule. Source: `src/components/molecules/date-picker/DatePicker.tsx`
|
|
9
|
+
- Rendered docs page: `/components/date-picker`
|
|
10
|
+
|
|
11
|
+
## Import
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Calendar } from 'src/components/molecules/date-picker/Calendar'
|
|
15
|
+
import { DateField } from 'src/components/molecules/date-picker/DateField'
|
|
16
|
+
import { DatePicker } from 'src/components/molecules/date-picker/DatePicker'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Default | Description |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| `label` | `string` | | Required. Names the field. Inside a FormField, FormField sets it from its own label. |
|
|
26
|
+
| `value` | `string ('YYYY-MM-DD' \| '')` | | Controlled value (your page holds it). |
|
|
27
|
+
| `defaultValue` | `string` | `''` | Starting value when the picker holds the value itself. |
|
|
28
|
+
| `onValueChange` | `(value: string) => void` | | Fires with a whole, real date, or '' when the field is emptied. A half-typed date does not fire. |
|
|
29
|
+
| `min` | `string` | | Earliest date, 'YYYY-MM-DD'. Earlier days are struck through; typing one marks the field invalid. |
|
|
30
|
+
| `max` | `string` | | Latest date, 'YYYY-MM-DD'. |
|
|
31
|
+
| `isDateDisabled` | `(date: string) => boolean` | | Days that cannot be picked, such as weekends or holidays. |
|
|
32
|
+
| `locale` | `string` | | A language tag such as 'en-GB' or 'de'. Sets the segment order, the separator, the month and day names and the first day of the week. Defaults to the browser's. |
|
|
33
|
+
| `weekStartsOn` | `number` | | 0 Sunday to 6 Saturday. Defaults to the locale's. |
|
|
34
|
+
| `showToday` | `boolean` | `true` | Shows the Today button under the calendar when today can be picked. |
|
|
35
|
+
| `disabled` | `boolean` | `false` | Disables the field and the calendar button. |
|
|
36
|
+
| `name` | `string` | | Submits the 'YYYY-MM-DD' value with a form, through a hidden input. |
|
|
37
|
+
| `invalid` | `boolean` | | Marks the field invalid. FormField sets it when there is an error. |
|
|
38
|
+
| `required` | `boolean` | | Marks the field required. FormField sets it. |
|
|
39
|
+
| `id` | `string` | | The field's id, so a FormField's error text can point at it. FormField sets it. |
|
|
40
|
+
| `aria-describedby` | `string` | | The ids of the help and error text. FormField sets it. |
|
|
41
|
+
| `className` | `string` | | Combined with the field's classes. |
|
|
42
|
+
| `ref` | `Ref<HTMLDivElement>` | | The field's group element. |
|
|
43
|
+
| `trailing (DateField)` | `ReactNode` | | Something inside the field after the segments. DatePicker puts its calendar button here. |
|
|
44
|
+
| `bare (DateField)` | `boolean` | `false` | No border, fill or ring of its own, for two dates inside one border (DateRangePicker draws them). |
|
|
45
|
+
| `onSelect (Calendar)` | `(date: string) => void` | | A day was picked with a click, Enter or Space. |
|
|
46
|
+
| `value (Calendar)` | `string \| null` | | The picked day. Ignored when dayState is given. |
|
|
47
|
+
| `month (Calendar)` | `string` | | Any day in the first month shown. Controlled with onMonthChange. |
|
|
48
|
+
| `defaultMonth (Calendar)` | `string` | | The first month shown when the calendar holds it itself. Defaults to the value's month, or today's. |
|
|
49
|
+
| `onMonthChange (Calendar)` | `(month: string) => void` | | Fires with the new first month's 1st day. |
|
|
50
|
+
| `dayState (Calendar)` | `(date: string) => 'single' \| 'start' \| 'end' \| 'start-end' \| 'middle' \| undefined` | | Draws each day yourself, for a range or any other selection. |
|
|
51
|
+
| `onDayEnter (Calendar)` | `(date: string) => void` | | The keyboard or the pointer moved onto a day. A range uses it to preview the band. |
|
|
52
|
+
| `numberOfMonths (Calendar)` | `1 \| 2` | `1` | Months side by side, stacked on narrow screens. |
|
|
53
|
+
| `autoFocus (Calendar)` | `boolean` | `false` | Moves focus to the picked day, or today, when the calendar appears. |
|
|
54
|
+
|
|
55
|
+
## Types and helpers
|
|
56
|
+
|
|
57
|
+
Exported beside the component, from the same file. Import a type with `import type { ... }`.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
/** How a day is drawn. `single` is one picked day; the rest belong to a range. */
|
|
61
|
+
export type DayState = 'single' | 'start' | 'end' | 'start-end' | 'middle'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
|
|
66
|
+
Each is compiled and rendered on the docs page. Imports are omitted; see above.
|
|
67
|
+
|
|
68
|
+
### Default
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<div className="w-full max-w-xs">
|
|
72
|
+
<DatePicker label="Delivery date" />
|
|
73
|
+
</div>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### In a FormField, with help text
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<div className="w-full max-w-xs">
|
|
80
|
+
<FormField label="Trip date" help="Type it, or open the calendar.">
|
|
81
|
+
<DatePicker label="Trip date" />
|
|
82
|
+
</FormField>
|
|
83
|
+
</div>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Controlled: the page holds the value
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
function Controlled() {
|
|
90
|
+
const [date, setDate] = useState('2026-11-14')
|
|
91
|
+
return (
|
|
92
|
+
<div className="flex w-full max-w-xs flex-col gap-2">
|
|
93
|
+
<DatePicker label="Dispatch date" value={date} onValueChange={setDate} />
|
|
94
|
+
<span className="font-mono text-xs text-[var(--color-text-secondary)]">value: {date ? `'${date}'` : "''"}</span>
|
|
95
|
+
</div>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
<Controlled />
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Limits: weekdays only, within the next two months
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
const weekend = (date: string) => [0, 6].includes(new Date(`${date}T12:00:00Z`).getUTCDay())
|
|
106
|
+
|
|
107
|
+
<div className="w-full max-w-xs">
|
|
108
|
+
<DatePicker label="Collection day" min="2026-11-02" max="2026-12-31" defaultValue="2026-11-16" isDateDisabled={weekend} />
|
|
109
|
+
</div>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### US order and a Sunday start, from the locale
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<div className="w-full max-w-xs">
|
|
116
|
+
<DatePicker label="Ship date" locale="en-US" defaultValue="2026-11-14" />
|
|
117
|
+
</div>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### The calendar on its own
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
function InlineCalendar() {
|
|
124
|
+
const [date, setDate] = useState<string | null>(null)
|
|
125
|
+
return (
|
|
126
|
+
<div className="flex flex-col gap-2">
|
|
127
|
+
<Calendar value={date} onSelect={setDate} />
|
|
128
|
+
<span className="font-mono text-xs text-[var(--color-text-secondary)]">{date ? formatLong(date) : 'No day picked'}</span>
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
<InlineCalendar />
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Keyboard
|
|
137
|
+
|
|
138
|
+
| Keys | Result |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `0–9` | Types into the focused segment and moves on once it is full. |
|
|
141
|
+
| `↑` `↓` | In the field: one more or one less in the segment. In the calendar: a week earlier or later. |
|
|
142
|
+
| `←` `→` | In the field: the previous or next segment. In the calendar: the day before or after. |
|
|
143
|
+
| `Backspace` | Clears the segment, or moves back when it is already empty. |
|
|
144
|
+
| `Page Up` `Page Down` | The same day a month earlier or later. With Shift, a year. |
|
|
145
|
+
| `Home` `End` | The first or last day of the week. |
|
|
146
|
+
| `Enter` `Space` | Picks the focused day and closes the calendar. |
|
|
147
|
+
| `Esc` | Closes the calendar without a change. |
|
|
148
|
+
|
|
149
|
+
## Do
|
|
150
|
+
|
|
151
|
+
- Store and send the 'YYYY-MM-DD' value as it is. It has no time zone, so it can't shift by a day.
|
|
152
|
+
- Set min and max to the real limits, so days nobody can book are struck through rather than refused after the fact.
|
|
153
|
+
- Wrap it in a FormField for a visible label, help text and errors.
|
|
154
|
+
|
|
155
|
+
## Don't
|
|
156
|
+
|
|
157
|
+
- Don't convert the value with new Date('2026-11-14'): that reads it as midnight UTC and can show the day before in the Americas.
|
|
158
|
+
- Don't hide unavailable days. Struck through and announced, they explain themselves.
|
|
159
|
+
- Don't use it for a date of birth without setting max to today.
|
|
160
|
+
|
|
161
|
+
## Anatomy
|
|
162
|
+
|
|
163
|
+
- **Field (DateField)**: A group named by the label, holding three spinbuttons (Day, Month, Year). Each says its value or "Empty". A date that does not exist (31 February) or falls outside min and max marks the field invalid.
|
|
164
|
+
- **Calendar button**: A ghost IconButton inside the field. Its name includes the picked date: "Choose date, Saturday, 14 November 2026".
|
|
165
|
+
- **Calendar**: A grid with one tab stop. Each day is a button named with the full date. The picked day is a solid accent square with a cut corner; today has aria-current and a short bar under its number. Days that can't be picked stay visible, struck through and announced as unavailable.
|
|
166
|
+
- **Today**: A secondary Button under the calendar, shown only when today can be picked.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# DatePresets
|
|
2
|
+
|
|
3
|
+
> Named periods such as Last 7 days, one click each. The defaults: Today, Yesterday, Last 7 days, Last 30 days, This month, Last month, This year, or your own. An add-on: put it in a DateRangePicker's aside and it reads and sets the picker's range by itself, then closes it. On its own it is a list you give a value and an onSelect. Installs DateRangePicker and DatePicker with it.
|
|
4
|
+
|
|
5
|
+
- **Best for:** Reports and logs, where people want the usual periods.
|
|
6
|
+
- **Not for:** Exact dates: DateRangePicker alone.
|
|
7
|
+
- Molecule. Source: `src/components/molecules/date-presets/DatePresets.tsx`
|
|
8
|
+
- Rendered docs page: `/components/date-presets`
|
|
9
|
+
|
|
10
|
+
## Import
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { DatePresets, defaultPresets } from 'src/components/molecules/date-presets/DatePresets'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Paths are from the Division DS repository root. Installed with shadcn they start `src/division-ds/` instead of `src/` (`src/division-ds/components/...`); import them relative to your file.
|
|
17
|
+
|
|
18
|
+
## Props
|
|
19
|
+
|
|
20
|
+
| Prop | Type | Default | Description |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| `presets` | `DatePreset[]` | `defaultPresets()` | Each { label, range }. Make your own, or start from defaultPresets(today). |
|
|
23
|
+
| `value` | `{ start: string; end: string }` | | The current range. Inside a DateRangePicker it comes from the picker. |
|
|
24
|
+
| `onSelect` | `(range: DateRange) => void` | | A preset was chosen. Inside a DateRangePicker the picker also takes it and closes. |
|
|
25
|
+
| `label` | `string` | `'Presets'` | The list's accessible name. |
|
|
26
|
+
| `className` | `string` | | Combined with the list's classes. |
|
|
27
|
+
| `ref` | `Ref<HTMLDivElement>` | | The list element. |
|
|
28
|
+
| `defaultPresets()` | `(today?: string) => DatePreset[]` | | The seven usual periods counted back from today ('YYYY-MM-DD'; defaults to the reader's today). Every one includes today. |
|
|
29
|
+
|
|
30
|
+
## Types and helpers
|
|
31
|
+
|
|
32
|
+
Exported beside the component, from the same file. Import a type with `import type { ... }`.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
export type DatePreset = { label: string; range: DateRange }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
/** The usual periods, counted back from `today` (default: the reader's today). Each includes today. */
|
|
40
|
+
export function defaultPresets(today: IsoDate = todayIso()): DatePreset[]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
Each is compiled and rendered on the docs page. Imports are omitted; see above.
|
|
46
|
+
|
|
47
|
+
### Inside a DateRangePicker: no wiring
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<div className="w-full max-w-sm">
|
|
51
|
+
<DateRangePicker label="Activity" aside={<DatePresets />} />
|
|
52
|
+
</div>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### On its own
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
function OnItsOwn() {
|
|
59
|
+
const [range, setRange] = useState<DateRange>(defaultPresets()[2].range)
|
|
60
|
+
return (
|
|
61
|
+
<div className="flex flex-col gap-3">
|
|
62
|
+
<DatePresets value={range} onSelect={setRange} />
|
|
63
|
+
<span className="font-mono text-xs text-[var(--color-text-secondary)]">
|
|
64
|
+
{range.start} to {range.end}
|
|
65
|
+
</span>
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
<OnItsOwn />
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Your own periods
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
<div className="w-full max-w-sm">
|
|
77
|
+
<DateRangePicker
|
|
78
|
+
label="Season"
|
|
79
|
+
aside={
|
|
80
|
+
<DatePresets
|
|
81
|
+
label="Seasons"
|
|
82
|
+
presets={[
|
|
83
|
+
{ label: 'Winter 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
|
|
84
|
+
{ label: 'Spring 2026', range: { start: '2026-04-01', end: '2026-06-30' } },
|
|
85
|
+
{ label: 'Summer 2026', range: { start: '2026-07-01', end: '2026-09-30' } },
|
|
86
|
+
]}
|
|
87
|
+
/>
|
|
88
|
+
}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Keyboard
|
|
94
|
+
|
|
95
|
+
| Keys | Result |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `Tab` | Moves through the presets. |
|
|
98
|
+
| `Enter` `Space` | Chooses the focused preset. |
|
|
99
|
+
|
|
100
|
+
## Do
|
|
101
|
+
|
|
102
|
+
- Keep the list short, seven or fewer.
|
|
103
|
+
- Name periods the way your users say them: "This quarter" if they plan in quarters.
|
|
104
|
+
|
|
105
|
+
## Don't
|
|
106
|
+
|
|
107
|
+
- Don't offer a preset nobody can pick, such as a future period when max is today.
|
|
108
|
+
|
|
109
|
+
## Anatomy
|
|
110
|
+
|
|
111
|
+
- **List**: A group named "Presets". Each period is a button; the one matching the current range is pressed (aria-pressed) and filled.
|