division-ds 0.1.2 → 0.2.1
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 +23 -3
- package/README.md +11 -0
- package/division-ds-0.2.1.tgz +0 -0
- package/package.json +2 -2
- package/public/docs/components/accordion.md +207 -0
- package/public/docs/components/ai-label.md +90 -0
- package/public/docs/components/alert-dialog.md +292 -0
- package/public/docs/components/alert.md +175 -0
- package/public/docs/components/approval-request.md +148 -0
- package/public/docs/components/auth-form.md +132 -0
- package/public/docs/components/avatar-group.md +152 -0
- package/public/docs/components/avatar.md +179 -0
- package/public/docs/components/badge.md +178 -0
- package/public/docs/components/breadcrumbs.md +112 -0
- package/public/docs/components/button.md +204 -0
- package/public/docs/components/card.md +257 -0
- package/public/docs/components/carousel.md +130 -0
- package/public/docs/components/cart.md +172 -0
- package/public/docs/components/chart-panel.md +358 -0
- package/public/docs/components/chat-message.md +157 -0
- package/public/docs/components/chat-thread.md +244 -0
- package/public/docs/components/checkbox.md +149 -0
- package/public/docs/components/checkout-form.md +128 -0
- package/public/docs/components/command-palette.md +147 -0
- package/public/docs/components/data-table.md +401 -0
- package/public/docs/components/description-list.md +103 -0
- package/public/docs/components/dialog.md +197 -0
- package/public/docs/components/divider.md +97 -0
- package/public/docs/components/dropdown-menu.md +222 -0
- package/public/docs/components/empty-state.md +145 -0
- package/public/docs/components/footer.md +397 -0
- package/public/docs/components/form-field.md +216 -0
- package/public/docs/components/icon-button.md +127 -0
- package/public/docs/components/input.md +200 -0
- package/public/docs/components/kanban-board.md +300 -0
- package/public/docs/components/kbd.md +72 -0
- package/public/docs/components/link.md +98 -0
- package/public/docs/components/list-item.md +241 -0
- package/public/docs/components/loading-animation.md +72 -0
- package/public/docs/components/multi-select.md +202 -0
- package/public/docs/components/navbar.md +144 -0
- package/public/docs/components/newsletter-form.md +112 -0
- package/public/docs/components/page-header.md +151 -0
- package/public/docs/components/pagination.md +212 -0
- package/public/docs/components/product-card.md +172 -0
- package/public/docs/components/progress.md +101 -0
- package/public/docs/components/prompt-input.md +151 -0
- package/public/docs/components/quantity-stepper.md +140 -0
- package/public/docs/components/radio.md +177 -0
- package/public/docs/components/rating.md +106 -0
- package/public/docs/components/score-ring.md +95 -0
- package/public/docs/components/search.md +116 -0
- package/public/docs/components/section-heading.md +113 -0
- package/public/docs/components/segmented-control.md +126 -0
- package/public/docs/components/select.md +224 -0
- package/public/docs/components/sheet.md +145 -0
- package/public/docs/components/sidebar.md +193 -0
- package/public/docs/components/skeleton.md +135 -0
- package/public/docs/components/slider.md +114 -0
- package/public/docs/components/sparkline.md +128 -0
- package/public/docs/components/spinner.md +98 -0
- package/public/docs/components/stat.md +106 -0
- package/public/docs/components/status-tracker.md +145 -0
- package/public/docs/components/stepper.md +147 -0
- package/public/docs/components/switch.md +153 -0
- package/public/docs/components/tabs.md +180 -0
- package/public/docs/components/tag.md +105 -0
- package/public/docs/components/textarea.md +148 -0
- package/public/docs/components/timeline.md +152 -0
- package/public/docs/components/toast.md +194 -0
- package/public/docs/components/tool-call.md +107 -0
- package/public/docs/components/tooltip.md +108 -0
- package/public/manifest/components.json +198 -15
- package/public/manifest/tokens.json +75 -5
- package/scripts/division-ds.mjs +78 -42
- package/scripts/lib/agent-docs.mjs +80 -6
- package/scripts/lib/ai-copy.mjs +120 -0
- package/scripts/lib/button-spacing.mjs +5 -5
- package/scripts/lib/check-text.mjs +57 -0
- package/scripts/lib/contrast.mjs +111 -0
- package/scripts/lib/host-inline.mjs +59 -0
- package/scripts/lib/mcp-server.mjs +116 -0
- package/scripts/lib/mcp-tools.mjs +266 -0
- package/scripts/lib/props-validator.mjs +3 -2
- package/scripts/lib/rules-installer.mjs +42 -4
- package/scripts/lib/token-discipline.mjs +10 -3
- package/skills/division-ds/SKILL.md +90 -0
- package/skills/division-ds/commands/add.md +25 -0
- package/skills/division-ds/commands/build.md +46 -0
- package/skills/division-ds/commands/fix.md +28 -0
- package/skills/division-ds/commands/review.md +25 -0
- package/skills/division-ds/topics/ai.md +8 -0
- package/skills/division-ds/topics/colour.md +11 -0
- package/skills/division-ds/topics/feedback.md +9 -0
- package/skills/division-ds/topics/forms.md +22 -0
- package/skills/division-ds/topics/layout.md +36 -0
- package/skills/division-ds/topics/motion.md +10 -0
- package/skills/division-ds/topics/overlays.md +9 -0
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
// Colour only, on purpose. Spacing is not gated: enforcing it before the scale is complete makes
|
|
10
10
|
// an author (or an agent) invent a token name to satisfy the rule, which is the worse failure.
|
|
11
11
|
|
|
12
|
+
import { DOCS_SITE } from './agent-docs.mjs'
|
|
13
|
+
|
|
14
|
+
/** Where a token list lives for whoever reads the finding: the MCP tool, or the docs site. A
|
|
15
|
+
* repository path meant nothing in a project that installed the components (2026-10-29 test). */
|
|
16
|
+
const TOKEN_LIST = `get_tokens over MCP, or ${DOCS_SITE}llms-tokens.txt`
|
|
17
|
+
|
|
12
18
|
export const SCANNED_ROOTS = ['src']
|
|
13
19
|
export const SCANNED_EXTENSIONS = /\.(tsx?|css)$/
|
|
14
20
|
|
|
@@ -16,6 +22,7 @@ export const SCANNED_EXTENSIONS = /\.(tsx?|css)$/
|
|
|
16
22
|
* A new entry needs a reason as good as these; "it was easier" is the case the gate exists for. */
|
|
17
23
|
export const EXEMPT = [
|
|
18
24
|
{ pattern: /^src\/styles\/tokens\.css$/, why: 'generated from tokens/: this is where the literals are meant to be' },
|
|
25
|
+
{ pattern: /(^|\/)division-ds\/styles\/tokens\.css$/, why: 'the same file, installed into a project by shadcn; it also names the MCP Apps host\'s own variables' },
|
|
19
26
|
{ pattern: /\.test\.tsx?$/, why: 'tests assert on literal values and on deliberately wrong input' },
|
|
20
27
|
{ pattern: /^src\/demo\/(scene|blob|terrain)\//, why: 'WebGL materials: three.js takes colours as numbers, not CSS variables' },
|
|
21
28
|
{ pattern: /^src\/components\/atoms\/loading-animation\/(palette|scene|kit|variants)\.ts$/, why: 'WebGL materials, read from the tokens at runtime where they can be' },
|
|
@@ -98,9 +105,9 @@ export function findViolations(text, path, tokenNames) {
|
|
|
98
105
|
if (name.endsWith('-')) continue
|
|
99
106
|
if (!known.has(name)) {
|
|
100
107
|
const near = suggest(name, tokenNames)
|
|
101
|
-
add('unknown-token', `var(${name})`, near.length ? `No such token. Did you mean ${near.join(', ')}?` :
|
|
108
|
+
add('unknown-token', `var(${name})`, near.length ? `No such token. Did you mean ${near.join(', ')}?` : `No such token. The full list: ${TOKEN_LIST}.`)
|
|
102
109
|
} else if (PRIMITIVE_RAMP.test(name) && inComponents(path)) {
|
|
103
|
-
add('primitive-in-component', `var(${name})`,
|
|
110
|
+
add('primitive-in-component', `var(${name})`, `A component reads semantic tokens, not a ramp step. Pick one by intent (accent.<state>.text, .fill or .ink): ${TOKEN_LIST}.`)
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
|
|
@@ -108,7 +115,7 @@ export function findViolations(text, path, tokenNames) {
|
|
|
108
115
|
// where a literal colour would be.
|
|
109
116
|
const rest = line.replace(/var\([^)]*\)/g, '')
|
|
110
117
|
for (const match of rest.matchAll(HEX)) {
|
|
111
|
-
add('raw-colour', match[0],
|
|
118
|
+
add('raw-colour', match[0], `Use a semantic token: text-[var(--color-text-primary)], bg-[var(--color-surface-base)]. Tokens and what each is for: ${TOKEN_LIST}.`)
|
|
112
119
|
}
|
|
113
120
|
for (const match of rest.matchAll(COLOR_FUNCTION)) {
|
|
114
121
|
add('raw-colour', match[0] + '…)', 'Use a semantic token. If no token fits, the colour is a change to the system: add it under tokens/ with a contrast pair.')
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: division-ds
|
|
3
|
+
description: Use when building or changing UI with Division DS (React 19, Tailwind 4, Radix; 68 components). Covers which component and token to use, the composition rules prop types cannot express (providers, FormField, button gaps, card borders), planning a screen's states, and how to check the result. Load it before writing any screen or component in a project that has Division DS components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Division DS
|
|
7
|
+
|
|
8
|
+
Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
9
|
+
|
|
10
|
+
This file is the core: what every screen needs. The topic and command files below hold the rest; load one when the work reaches it, not before.
|
|
11
|
+
|
|
12
|
+
## Plan first
|
|
13
|
+
|
|
14
|
+
Before writing a screen, list its regions and, for each, its states: empty, loading, error, success, and disabled or no permission. Pick a component for each from `public/llms.txt` by its "Best for" and "Not for". `commands/build.md` is the whole procedure.
|
|
15
|
+
|
|
16
|
+
## Where things are
|
|
17
|
+
|
|
18
|
+
| You want | Read |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Every component, one line each with best for and not for | `public/llms.txt` |
|
|
21
|
+
| One component: props, examples, keyboard, mistakes | `public/docs/components/<slug>.md` |
|
|
22
|
+
| Which token to use for what | `public/llms-tokens.txt` |
|
|
23
|
+
| Shared helpers: form errors, money, links, theme, streamed text | `public/docs/helpers.md` |
|
|
24
|
+
| The same as data | `public/manifest/components.json`, `public/manifest/tokens.json` |
|
|
25
|
+
|
|
26
|
+
Outside this repository, read the same files online: `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, `https://victor-ilioiu.vercel.app/systems/division-ds/docs/components/<slug>.md`, and so on. Add a component to a project with `npx shadcn@latest add https://raw.githubusercontent.com/Victor-Ilioiu/division-ds/main/public/r/<slug>.json`, or every component with `division-ds-all` as the slug. The setup steps, in plain text: `https://victor-ilioiu.vercel.app/systems/division-ds/install.md`.
|
|
27
|
+
|
|
28
|
+
## Check your work
|
|
29
|
+
|
|
30
|
+
- In a project that uses the components: `npx division-ds check <files or dirs>` (the checker is on npm; Node 22 or newer). It flags a raw colour, an invented token, touching buttons, an unknown prop and a value outside a prop's union.
|
|
31
|
+
- In the Division DS repository itself: `npm run verify` (type-check, every gate, the unit tests).
|
|
32
|
+
|
|
33
|
+
A finding says what to write instead. `commands/fix.md` explains each one.
|
|
34
|
+
|
|
35
|
+
## Topics: load when
|
|
36
|
+
|
|
37
|
+
- `topics/colour.md`: choosing an accent, the text on a fill, or a status colour.
|
|
38
|
+
- `topics/layout.md`: laying out a page: the shell, background, width, type sizes, cards, links.
|
|
39
|
+
- `topics/forms.md`: a screen has a field, a form or more than one button.
|
|
40
|
+
- `topics/overlays.md`: adding a Dialog, an AlertDialog or a Sheet.
|
|
41
|
+
- `topics/feedback.md`: a screen reports a result or a wait: a toast, an alert, progress, a spinner.
|
|
42
|
+
- `topics/motion.md`: animating anything yourself.
|
|
43
|
+
- `topics/ai.md`: wording a chat.
|
|
44
|
+
|
|
45
|
+
## Commands: load when
|
|
46
|
+
|
|
47
|
+
- `commands/build.md`: building a new screen or page. Plans the regions and their states before any code.
|
|
48
|
+
- `commands/add.md`: adding one component to a screen that already exists.
|
|
49
|
+
- `commands/fix.md`: a gate, `division-ds check` or a test has failed and named a rule. What each message means and the fix.
|
|
50
|
+
- `commands/review.md`: a screen is written and you are about to say it is done. The checklist to run over it.
|
|
51
|
+
|
|
52
|
+
## Core rules
|
|
53
|
+
|
|
54
|
+
Each of these is something an agent got wrong or had to guess when it first used the system.
|
|
55
|
+
|
|
56
|
+
**Imports.** Import a component from its own file, by relative path. There is no path alias: the
|
|
57
|
+
docs write `src/components/atoms/button/Button`, and from `src/pages/Screen.tsx` that is
|
|
58
|
+
`'../components/atoms/button/Button'`. Helpers work the same way: `src/lib/money` is
|
|
59
|
+
`'../lib/money'` from there. The tier barrels (`components/atoms`, `/molecules`,
|
|
60
|
+
`/organisms`) are for the system's own composition; the organisms barrel pulls the chart library
|
|
61
|
+
into whatever imports it. Icons come from `lucide-react`, with `aria-hidden="true"` unless the
|
|
62
|
+
icon is the only content. Installed with shadcn, paths start `src/division-ds/` instead of `src/`.
|
|
63
|
+
|
|
64
|
+
**Colour.** Every colour is a semantic token inside a Tailwind arbitrary value:
|
|
65
|
+
`text-[var(--color-text-primary)]`, `bg-[var(--color-surface-base)]`. Never a hex, never
|
|
66
|
+
`rgb()`, never a Tailwind palette class (`bg-red-500`, `text-white`), never a token name you
|
|
67
|
+
have not seen in `llms-tokens.txt`. An invented name fails silently in the browser and loudly in
|
|
68
|
+
`npm run verify`.
|
|
69
|
+
|
|
70
|
+
**Providers.** One `<Toaster>` and one `<TooltipProvider>` sit at the root of the app (`AppShell`,
|
|
71
|
+
`DemoLayout` in this repository). Assume both, including for a screen you are writing that is not
|
|
72
|
+
mounted anywhere yet: it will be mounted under one of the two shells. Call `useToast()` freely; do
|
|
73
|
+
not mount a second `Toaster`, and do not drop a toast or a tooltip because you cannot see the
|
|
74
|
+
provider. A project that uses the components mounts both itself (step 4 of `install.md`).
|
|
75
|
+
|
|
76
|
+
**Focus.** Anything focusable that you style yourself gets
|
|
77
|
+
`focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--color-focus-ring)]`.
|
|
78
|
+
|
|
79
|
+
**Page title, empty, loading.** Plan these before writing a screen. A page title is `PageHeader`
|
|
80
|
+
(it renders the `h1`). An empty list or result is `EmptyState`; inside a `DataTable`, pass it as
|
|
81
|
+
`emptyMessage`. A loading region is `Skeleton` shapes inside a `SkeletonGroup`. The demo's
|
|
82
|
+
`src/demo/states/` files are not part of the system.
|
|
83
|
+
|
|
84
|
+
**What the system does not have.** No Popover, no Combobox (single value: use `Select`; several:
|
|
85
|
+
`MultiSelect`), no date picker. Do not reach into `src/demo/` from a component.
|
|
86
|
+
|
|
87
|
+
**Vocabulary.** Inside this repository, `npm run check:vocabulary` bans a list of words in `src/`,
|
|
88
|
+
`scripts/` and `e2e/` (the list is `scripts/lib/vocabulary.mjs`; it is not published with the
|
|
89
|
+
docs). Run it on sample copy too: an ordinary phrase can match. Products in sample data are
|
|
90
|
+
"replicas". The gate does not apply to a project that only uses the components.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Division DS: add
|
|
2
|
+
|
|
3
|
+
> Load when adding one component to a screen that already exists. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
|
+
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
|
+
|
|
7
|
+
1. Find it in `public/llms.txt`. Its "Best for" should describe your case and its "Not for"
|
|
8
|
+
should not; if "Not for" names your case, use the component it names instead.
|
|
9
|
+
2. Open `public/docs/components/<slug>.md` and read, in order: **Requires** (a provider, a
|
|
10
|
+
wrapper such as `FormField`, a landmark), **Props**, **Examples**, **Common mistakes** and
|
|
11
|
+
**Don't**.
|
|
12
|
+
3. Take the import from the page's Import block and rewrite it as a relative path from your
|
|
13
|
+
file. Import a type with `import type`.
|
|
14
|
+
4. Start from the closest example on the page and change only the content. Keep what it sets
|
|
15
|
+
for access: `label`, `id`, `aria-*`, the heading level.
|
|
16
|
+
5. Supply what Requires names: a field inside a `FormField`; `Switch`, `Checkbox` and `Radio`
|
|
17
|
+
with an `id` and a `<label htmlFor>`; a button beside another inside a parent with a gap.
|
|
18
|
+
6. Add the states it brings with it: why a control is disabled, what a list shows when empty,
|
|
19
|
+
a button's `loading`.
|
|
20
|
+
7. Run the check below on the file.
|
|
21
|
+
|
|
22
|
+
## Check
|
|
23
|
+
|
|
24
|
+
- In a project that uses the components: `npx division-ds check <files or dirs>` (the checker is on npm; Node 22 or newer). It flags a raw colour, an invented token, touching buttons, an unknown prop and a value outside a prop's union.
|
|
25
|
+
- In the Division DS repository itself: `npm run verify` (type-check, every gate, the unit tests).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Division DS: build
|
|
2
|
+
|
|
3
|
+
> Load when building a new screen or page. Plans the regions and their states before any code. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
|
+
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
|
+
|
|
7
|
+
Plan before code. The states a screen gets wrong are the ones nobody planned: an empty list
|
|
8
|
+
with no message, a load that fails into a blank panel, a button that is disabled with no reason.
|
|
9
|
+
|
|
10
|
+
1. **Regions.** List the screen top to bottom: the page header, each block of content (a table,
|
|
11
|
+
a form, a row of stats, a list), then anything that opens on top (a dialog, a sheet).
|
|
12
|
+
2. **States.** Under each region, write one line per state, even when the answer is "none":
|
|
13
|
+
- **empty**: nothing yet, or a filter emptied it;
|
|
14
|
+
- **loading**: the first load, and a refresh;
|
|
15
|
+
- **error**: the load failed, or a save was rejected;
|
|
16
|
+
- **success**: the content, and what confirms an action;
|
|
17
|
+
- **disabled or no permission**: what someone who cannot act sees, and the reason they are told.
|
|
18
|
+
3. **Components.** Pick one component per region and state from `public/llms.txt`. Each line there
|
|
19
|
+
has "Best for" and "Not for"; when "Not for" names your case, take the component it names.
|
|
20
|
+
The usual picks: page title `PageHeader`; empty `EmptyState`; loading `Skeleton` shapes in a
|
|
21
|
+
`SkeletonGroup`; failed load `Alert` in the `hostile` tone with a retry; a done action `Toast`;
|
|
22
|
+
a destructive confirm `AlertDialog`.
|
|
23
|
+
4. **Read.** Open `public/docs/components/<slug>.md` for every component in the plan (Requires,
|
|
24
|
+
props, examples, Common mistakes). Load the topic files the plan touches: a field means
|
|
25
|
+
`topics/forms.md`, an overlay `topics/overlays.md`, a status colour `topics/colour.md`.
|
|
26
|
+
5. **Write.** Each component imported from its own file; every colour a token from
|
|
27
|
+
`public/llms-tokens.txt`.
|
|
28
|
+
6. **Check.** Run the check below and fix every finding (`commands/fix.md`), then go through
|
|
29
|
+
`commands/review.md`.
|
|
30
|
+
|
|
31
|
+
A plan looks like this:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
PageHeader: "Orders", action "New order"
|
|
35
|
+
Region: orders table (DataTable, Pagination below)
|
|
36
|
+
empty: EmptyState "No orders yet", action "Browse replicas", as emptyMessage
|
|
37
|
+
loading: SkeletonGroup "Loading orders", one Skeleton line per row
|
|
38
|
+
error: Alert hostile "Orders did not load", Retry button
|
|
39
|
+
success: rows; a bulk action confirms with a Toast
|
|
40
|
+
no access: the "New order" button is absent, a sentence says who can create orders
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Check
|
|
44
|
+
|
|
45
|
+
- In a project that uses the components: `npx division-ds check <files or dirs>` (the checker is on npm; Node 22 or newer). It flags a raw colour, an invented token, touching buttons, an unknown prop and a value outside a prop's union.
|
|
46
|
+
- In the Division DS repository itself: `npm run verify` (type-check, every gate, the unit tests).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Division DS: fix
|
|
2
|
+
|
|
3
|
+
> Load when a gate, `division-ds check` or a test has failed and named a rule. What each message means and the fix. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
|
+
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
|
+
|
|
7
|
+
Every finding prints `path:line [rule] what was found` and a line saying what to write instead.
|
|
8
|
+
Do what that line says. Never silence a gate: no new EXEMPT entry, no `token-discipline: allow`
|
|
9
|
+
comment and no ALLOWED_IDIOMS entry to get past one.
|
|
10
|
+
|
|
11
|
+
| Message | Fix |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `[raw-colour]` a hex, `rgb()` or `hsl()` | Replace it with a semantic token by intent, `text-[var(--color-text-primary)]`. Pick from `public/llms-tokens.txt`. |
|
|
14
|
+
| `[palette-class]` `bg-red-500`, `text-white` | Same: an arbitrary value on a token, `bg-[var(--color-surface-raised)]`. |
|
|
15
|
+
| `[unknown-token]` | The name is not a token. Take the "Did you mean" suggestion, or look it up in `public/llms-tokens.txt`. Never define it yourself. |
|
|
16
|
+
| `[primitive-in-component]` | A ramp step (`--color-signal-500`). Use the semantic token for what it does: `accent.<state>.text`, `.fill` or `.ink`. |
|
|
17
|
+
| `touching-buttons`, "Button-spacing gate FAILED" | Wrap the buttons in one parent with a gap (`flex flex-wrap items-center gap-3`) and move any margin onto it. `DialogFooter` and `CardFooter` already are one. |
|
|
18
|
+
| `[unknown-prop]` "has no prop" | The prop does not exist. Open the page the message names and use a prop from its table. |
|
|
19
|
+
| `[unknown-prop]` "types X away on purpose" | The component sets that attribute itself. Use the prop it names (`label` for a name, `invalid` for an error state). |
|
|
20
|
+
| `[invalid-value]` | The value is not in the prop's union. The message lists the allowed values. |
|
|
21
|
+
| `[ai-in-cta]` | A button says "AI". Name what it does instead: "Summarize", "Draft a reply". |
|
|
22
|
+
| `[assistant-copy]` | An assistant component's label says "answer", "please" or "!". Write "response", drop "please", drop the exclamation point. |
|
|
23
|
+
| "Vocabulary gate FAILED" (this repository only) | Reword the line. If it is an ordinary idiom, ask before adding it to ALLOWED_IDIOMS. |
|
|
24
|
+
| "Agent docs are stale" (this repository only) | Run `npm run agent-docs`, then `npm run verify`. |
|
|
25
|
+
| A props-table test fails in `meta.test.ts` (this repository only) | The `<Name>.meta.ts` table and the real props disagree. Change the table to match the code, both ways. |
|
|
26
|
+
| A type error on a component prop | Read the prop's type on its page; for a link that is disabled or busy, render the state directly instead of fighting the type. |
|
|
27
|
+
|
|
28
|
+
After the fix, run the same command again until it passes.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Division DS: review
|
|
2
|
+
|
|
3
|
+
> Load when a screen is written and you are about to say it is done. The checklist to run over it. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
|
+
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
|
+
|
|
7
|
+
Go through every line. A line that does not hold is a change to make, not a note to leave.
|
|
8
|
+
|
|
9
|
+
- [ ] **States.** Every region has its empty, loading, error, success and disabled or no-permission state, as planned before the code (the regions-and-states plan of `commands/build.md`). An empty list says what is empty and offers the action that fills it.
|
|
10
|
+
- [ ] **Headings.** One `PageHeader`, so one `h1`. Section headings continue the outline: `h2` under the `h1`, `h3` inside an `h2`, no level skipped. `SectionHeading` is given the level.
|
|
11
|
+
- [ ] **Tokens only.** No hex, `rgb()`, palette class or invented token name. `division-ds check` passes.
|
|
12
|
+
- [ ] **Buttons.** Two or more side by side share a parent with a gap. One primary button per view. A busy button takes `loading`; a disabled one says why nearby. Icon-only actions are `IconButton` with a `label`.
|
|
13
|
+
- [ ] **Forms.** Every `Input`, `Textarea`, `Select`, `MultiSelect` and `QuantityStepper` is inside a `FormField`; `Switch`, `Checkbox` and `Radio` have an `id` and a `<label htmlFor>`. A failed submit shows `ErrorSummary` and focuses it.
|
|
14
|
+
- [ ] **Status.** Every status has a word, not only a colour.
|
|
15
|
+
- [ ] **Focus.** Everything interactive is reached by Tab in reading order and shows the focus ring; anything styled by hand has the `focus-visible:outline-*` classes. An overlay hands focus back to what opened it. A button that removes its own row or item (Acknowledge, Delete, Dismiss) moves focus to the next one, else the previous one, else the empty state; focus never drops to the page.
|
|
16
|
+
- [ ] **Text size.** Secondary text is 14px or larger; 11 to 12px only for uppercase mono labels.
|
|
17
|
+
- [ ] **320px.** At 320px wide nothing scrolls sideways (`document.documentElement.scrollWidth <= 320`) and button rows wrap.
|
|
18
|
+
- [ ] **Both themes.** It reads in dark and in light (`data-theme="light"` on `<html>`).
|
|
19
|
+
- [ ] **Motion.** Anything animated by hand stops under reduced motion; nothing moves on its own.
|
|
20
|
+
- [ ] **Live data.** Values that update on their own change in place, with no announcement for each number; a change of status (good to unhealthy) is announced once, through one polite live region (`role="status"`). Charts animate only their first draw, so new data every few seconds is fine.
|
|
21
|
+
|
|
22
|
+
## Check
|
|
23
|
+
|
|
24
|
+
- In a project that uses the components: `npx division-ds check <files or dirs>` (the checker is on npm; Node 22 or newer). It flags a raw colour, an invented token, touching buttons, an unknown prop and a value outside a prop's union.
|
|
25
|
+
- In the Division DS repository itself: `npm run verify` (type-check, every gate, the unit tests).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Division DS: assistant copy
|
|
2
|
+
|
|
3
|
+
> Load when wording a chat. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Assistant copy.** A button names the action ("Summarize"), never "AI". Say "response", not
|
|
6
|
+
"answer". No "please" or "!" in assistant labels. The interface says "Assistant"; only its own
|
|
7
|
+
messages say "I". Response feedback: `ResponseFeedback` in `actions`.
|
|
8
|
+
A value the assistant filled is `aiValue` on that `Input` or `Textarea` only; leaving it accepts it.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Division DS: colour roles
|
|
2
|
+
|
|
3
|
+
> Load when choosing an accent, the text on a fill, or a status colour. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Fill, text, ink.** Each accent has three roles. `accent.<state>.fill` is a solid block;
|
|
6
|
+
`accent.<state>.ink` is the text on that block; `accent.<state>.text` is coloured text on a
|
|
7
|
+
normal surface. Never put `text.primary` on a fill.
|
|
8
|
+
|
|
9
|
+
**Status tones.** `ok` done or healthy; `warning` degraded or needs attention; `hostile` failed
|
|
10
|
+
or destructive; `info` in progress or neutral news; `signal` brand emphasis (a sale, the
|
|
11
|
+
selected thing); `neutral` inactive. Always with a word: colour alone is not a status.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Division DS: feedback
|
|
2
|
+
|
|
3
|
+
> Load when a screen reports a result or a wait: a toast, an alert, progress, a spinner. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Feedback.** A `Toast` confirms something the person just did and then leaves, so it never holds
|
|
6
|
+
the only copy of anything; a message that must stay is an `Alert` in the page. A failed load is
|
|
7
|
+
an `Alert` in the `hostile` tone with a retry, not an `EmptyState`. Measurable work is
|
|
8
|
+
`Progress`; a short wait inside a control or a line of text is `Spinner`; a busy `Button` takes
|
|
9
|
+
`loading`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Division DS: forms and actions
|
|
2
|
+
|
|
3
|
+
> Load when a screen has a field, a form or more than one button. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Forms.** In a form, `Input`, `Textarea`, `Select`, `MultiSelect` and `QuantityStepper` go inside a `FormField`,
|
|
6
|
+
which supplies the label, help and error and keeps an `id` you pass to the control. The one
|
|
7
|
+
exception is a control repeated per row of a list (a role `Select` on each member): leave it
|
|
8
|
+
bare and name it through its own `label` prop ("Role for Ilse Varga"). `Switch`, `Checkbox` and
|
|
9
|
+
`Radio` are not `FormField` children: give them an `id` and a `<label htmlFor>`. A failed submit
|
|
10
|
+
renders `ErrorSummary` at the top and focuses it; `useFieldErrors` holds the state (signature in
|
|
11
|
+
`public/docs/helpers.md`).
|
|
12
|
+
|
|
13
|
+
A `RadioGroup` in a form sits in a `<fieldset>` whose `<legend>` names it (code on the Radio
|
|
14
|
+
page). A date is `<Input type="date">` in a `FormField`.
|
|
15
|
+
|
|
16
|
+
**Buttons.** Two or more buttons side by side need a parent with a gap
|
|
17
|
+
(`flex flex-wrap gap-3`); `DialogFooter` and `CardFooter` already are one. A `Button` is
|
|
18
|
+
`type="button"` unless you say `type="submit"`. A busy button takes `loading`, not `disabled`.
|
|
19
|
+
`disabled` is for an action that is not available; say why in text nearby.
|
|
20
|
+
|
|
21
|
+
**Icon-only buttons** are `IconButton` with a required `label`. A `Tooltip` adds detail; it does
|
|
22
|
+
not replace the label.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Division DS: layout and type
|
|
2
|
+
|
|
3
|
+
> Load when laying out a page: the shell, background, width, type sizes, cards, links. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Themes.** The theme is `data-theme="light"` or `"dark"` on `<html>` (`src/lib/theme.ts`); dark
|
|
6
|
+
is the default. Tokens switch on their own, so a screen built from tokens needs no theme logic.
|
|
7
|
+
The shell paints the page background (`surface.base`) and supplies the gutter; a screen sets its
|
|
8
|
+
own `max-w-*` and vertical spacing, and no page background. A form or an overlay is the
|
|
9
|
+
exception: it paints `surface.base` on itself, so its field colours never depend on what is
|
|
10
|
+
behind it. In a project that uses the components, your own root does this
|
|
11
|
+
(step 4 of `install.md`). Toggle it with `setTheme()` from `src/lib/theme.ts`.
|
|
12
|
+
|
|
13
|
+
**App navigation.** A few views: `Navbar` (`current: true` on the open one). Many: `Sidebar`.
|
|
14
|
+
|
|
15
|
+
**Type.** Three families, as utilities: `font-display` (headings, figures), `font-body` (the
|
|
16
|
+
default, set by the shell), `font-mono` (labels, code, tabular numbers). A page title is
|
|
17
|
+
`<h1 className="font-display font-semibold text-2xl">`; body is `text-base` or `text-sm`; a label
|
|
18
|
+
is `font-mono text-xs font-semibold uppercase tracking-[0.18em]`. Tailwind's own size, weight
|
|
19
|
+
and spacing utilities are fine; only colour is restricted to tokens.
|
|
20
|
+
|
|
21
|
+
**Text size.** Secondary text is 14px or larger. 11 to 12px is for uppercase mono labels only.
|
|
22
|
+
|
|
23
|
+
**Cards.** To highlight or select a `Card`, set the border inline with a token:
|
|
24
|
+
`style={{ border: '2px solid var(--color-accent-signal-fill)' }}`. A border utility class does
|
|
25
|
+
not win against the panel's own border. `interactive` is only for a card that holds one link or
|
|
26
|
+
button; give that link `className={cardLinkClass}` (from `Card`) to stretch it over the card.
|
|
27
|
+
|
|
28
|
+
**Links.** Components that render links take `renderLink`, defaulting to a plain `<a>`. Under a
|
|
29
|
+
router, pass an adapter: `({ href, ...rest }) => <Link to={href} {...rest} />`. No component
|
|
30
|
+
imports a router.
|
|
31
|
+
|
|
32
|
+
**Charts and bundle size.** `ChartPanel` and `Sparkline` bring in recharts, a few hundred kB.
|
|
33
|
+
Load the route or screen that uses them with `React.lazy` and a `<Suspense>` fallback, so recharts
|
|
34
|
+
lands in its own chunk and screens without a chart never download it. Without that, Vite warns
|
|
35
|
+
about a chunk over 500 kB; the warning is about load time only, and the build is fine. On a
|
|
36
|
+
live page, data may change as often as you like: a chart animates its first draw only.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Division DS: motion
|
|
2
|
+
|
|
3
|
+
> Load when animating anything yourself. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Motion.** The components animate themselves, and the shell animates a route change. A screen
|
|
6
|
+
adds no keyframes of its own: use the classes in `src/styles/motion.css` (`anim-snap-in` for an
|
|
7
|
+
element arriving, `anim-draw-on` for a hairline) and the motion tokens (`--duration-fast` for
|
|
8
|
+
hover, `--duration-base` by default, `--duration-slow` for a larger change, `--ease-snap`).
|
|
9
|
+
Anything you animate yourself stops under `prefers-reduced-motion` (`motion-reduce:` in
|
|
10
|
+
Tailwind), and nothing moves on its own: no autoplay.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Division DS: overlays
|
|
2
|
+
|
|
3
|
+
> Load when adding a Dialog, an AlertDialog or a Sheet. Generated from AGENTS.md by `npm run agent-docs`. Edit the rules there, not here.
|
|
4
|
+
|
|
5
|
+
**Overlays.** A task on top of the page is a `Dialog`; a destructive confirm is `AlertDialog`,
|
|
6
|
+
not `Dialog`; filters, navigation on a narrow screen or one item's detail beside a list is a
|
|
7
|
+
`Sheet`. Never open a dialog from a dialog or a sheet from a sheet. Never open one from a
|
|
8
|
+
`DropdownMenu` item: the item is gone by the time the overlay closes, so focus has nowhere to go.
|
|
9
|
+
Put a dialog's actions in `DialogFooter`.
|