division-ds 0.0.0-stage → 0.1.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 +190 -0
- package/LICENSE +21 -0
- package/README.md +18 -2
- package/package.json +20 -4
- package/public/manifest/components.json +10550 -0
- package/public/manifest/tokens.json +932 -0
- package/scripts/division-ds.mjs +188 -0
- package/scripts/lib/agent-docs.mjs +510 -0
- package/scripts/lib/button-spacing.mjs +416 -0
- package/scripts/lib/component-props.mjs +181 -0
- package/scripts/lib/props-validator.mjs +320 -0
- package/scripts/lib/rules-installer.mjs +132 -0
- package/scripts/lib/token-discipline.mjs +125 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Division DS: instructions for coding agents
|
|
2
|
+
|
|
3
|
+
A React 19 + Tailwind 4 + Radix design system: 67 components, tokens in three layers, light and
|
|
4
|
+
dark themes, WCAG 2.2 AA. This file is the entry point. It is short on purpose; everything it
|
|
5
|
+
points to is generated from the code, so it is current.
|
|
6
|
+
|
|
7
|
+
## Find what you need
|
|
8
|
+
|
|
9
|
+
| You want | Read |
|
|
10
|
+
|---|---|
|
|
11
|
+
| The list of components, one line each | `public/llms.txt` |
|
|
12
|
+
| One component: props, examples as code, keyboard, do and don't | `public/docs/components/<slug>.md` |
|
|
13
|
+
| Every component's props in one compact file | `public/llms-components.txt` |
|
|
14
|
+
| Which token to use for what | `public/llms-tokens.txt` |
|
|
15
|
+
| Shared helpers: form errors, money, links, theme, streamed text | `public/docs/helpers.md` |
|
|
16
|
+
| The same as data | `public/manifest/components.json`, `public/manifest/tokens.json` |
|
|
17
|
+
| Why a rule exists | `design.md` (long: search it by heading, do not read it whole) |
|
|
18
|
+
| Every command, and what fails silently | `commands.md` |
|
|
19
|
+
| The installable skill: a short core, topic files, and build / add / fix / review procedures | `skills/division-ds/SKILL.md` |
|
|
20
|
+
|
|
21
|
+
Read the component's page before its source. The page has the prop contract and working
|
|
22
|
+
examples; the source has the reasons, at ten times the length.
|
|
23
|
+
|
|
24
|
+
## Check your work
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
npm run verify
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Type-check, every gate and the unit tests, in one command. It only compares: it changes no file in
|
|
31
|
+
the repository and writes no build output, so running it never breaks a "create only one file" rule.
|
|
32
|
+
A gate's message says what to change. To check a single file anywhere:
|
|
33
|
+
`node scripts/check-token-discipline.mjs path/to/File.tsx`.
|
|
34
|
+
|
|
35
|
+
## Working in a project that uses the components
|
|
36
|
+
|
|
37
|
+
`npm run verify` exists only in this repository. In another project, check every screen you
|
|
38
|
+
write before you finish:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
npx division-ds check <files or dirs> (from npm; Node 22 or newer)
|
|
42
|
+
node <path-to-division-ds>/scripts/division-ds.mjs check <files or dirs> (the same, from a clone)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
It runs the colour and button-spacing gates and checks every Division DS element's props against
|
|
46
|
+
`public/manifest/components.json`: an unknown prop, or a value that is not in the prop's union.
|
|
47
|
+
Exit 1 means a finding; each one says what to write instead. `division-ds rules --target <dir>`
|
|
48
|
+
installs these rules into that project's `AGENTS.md`, `GEMINI.md` and Cursor rules.
|
|
49
|
+
|
|
50
|
+
<!-- rules:start -->
|
|
51
|
+
## Rules
|
|
52
|
+
|
|
53
|
+
Each of these is something an agent got wrong or had to guess when it first used the system.
|
|
54
|
+
|
|
55
|
+
<!-- topic: core -->
|
|
56
|
+
|
|
57
|
+
**Imports.** Import a component from its own file, by relative path. There is no path alias: the
|
|
58
|
+
docs write `src/components/atoms/button/Button`, and from `src/pages/Screen.tsx` that is
|
|
59
|
+
`'../components/atoms/button/Button'`. Helpers work the same way: `src/lib/money` is
|
|
60
|
+
`'../lib/money'` from there. The tier barrels (`components/atoms`, `/molecules`,
|
|
61
|
+
`/organisms`) are for the system's own composition; the organisms barrel pulls the chart library
|
|
62
|
+
into whatever imports it. Icons come from `lucide-react`, with `aria-hidden="true"` unless the
|
|
63
|
+
icon is the only content.
|
|
64
|
+
|
|
65
|
+
**Colour.** Every colour is a semantic token inside a Tailwind arbitrary value:
|
|
66
|
+
`text-[var(--color-text-primary)]`, `bg-[var(--color-surface-base)]`. Never a hex, never
|
|
67
|
+
`rgb()`, never a Tailwind palette class (`bg-red-500`, `text-white`), never a token name you
|
|
68
|
+
have not seen in `llms-tokens.txt`. An invented name fails silently in the browser and loudly in
|
|
69
|
+
`npm run verify`.
|
|
70
|
+
|
|
71
|
+
**Providers.** One `<Toaster>` and one `<TooltipProvider>` sit at the root of the app (`AppShell`,
|
|
72
|
+
`DemoLayout`). Assume both, including for a screen you are writing that is not mounted anywhere
|
|
73
|
+
yet: it will be mounted under one of the two shells. Call `useToast()` freely; do not mount a
|
|
74
|
+
second `Toaster`, and do not drop a toast or a tooltip because you cannot see the provider.
|
|
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.
|
|
91
|
+
|
|
92
|
+
<!-- topic: colour -->
|
|
93
|
+
|
|
94
|
+
**Fill, text, ink.** Each accent has three roles. `accent.<state>.fill` is a solid block;
|
|
95
|
+
`accent.<state>.ink` is the text on that block; `accent.<state>.text` is coloured text on a
|
|
96
|
+
normal surface. Never put `text.primary` on a fill.
|
|
97
|
+
|
|
98
|
+
**Status tones.** `ok` done or healthy; `warning` degraded or needs attention; `hostile` failed
|
|
99
|
+
or destructive; `info` in progress or neutral news; `signal` brand emphasis (a sale, the
|
|
100
|
+
selected thing); `neutral` inactive. Always with a word: colour alone is not a status.
|
|
101
|
+
|
|
102
|
+
<!-- topic: layout -->
|
|
103
|
+
|
|
104
|
+
**Themes.** The theme is `data-theme="light"` or `"dark"` on `<html>` (`src/lib/theme.ts`); dark
|
|
105
|
+
is the default. Tokens switch on their own, so a screen built from tokens needs no theme logic.
|
|
106
|
+
The shell paints the page background (`surface.base`) and supplies the gutter; a screen sets its
|
|
107
|
+
own `max-w-*` and vertical spacing, and no page background. A form or an overlay is the
|
|
108
|
+
exception: it paints `surface.base` on itself, so its field colours never depend on what is
|
|
109
|
+
behind it.
|
|
110
|
+
|
|
111
|
+
**Type.** Three families, as utilities: `font-display` (headings, figures), `font-body` (the
|
|
112
|
+
default, set by the shell), `font-mono` (labels, code, tabular numbers). A page title is
|
|
113
|
+
`<h1 className="font-display font-semibold text-2xl">`; body is `text-base` or `text-sm`; a label
|
|
114
|
+
is `font-mono text-xs font-semibold uppercase tracking-[0.18em]`. Tailwind's own size, weight
|
|
115
|
+
and spacing utilities are fine; only colour is restricted to tokens.
|
|
116
|
+
|
|
117
|
+
**Text size.** Secondary text is 14px or larger. 11 to 12px is for uppercase mono labels only.
|
|
118
|
+
|
|
119
|
+
**Cards.** To highlight or select a `Card`, set the border inline with a token:
|
|
120
|
+
`style={{ border: '2px solid var(--color-accent-signal-fill)' }}`. A border utility class does
|
|
121
|
+
not win against the panel's own border. `interactive` is only for a card that holds one link or
|
|
122
|
+
button.
|
|
123
|
+
|
|
124
|
+
**Links.** Components that render links take `renderLink`, defaulting to a plain `<a>`. Under a
|
|
125
|
+
router, pass an adapter (`src/demo/routerLink.tsx` is the example). No component imports a router.
|
|
126
|
+
|
|
127
|
+
**Charts and bundle size.** `ChartPanel` and `Sparkline` bring in recharts, a few hundred kB.
|
|
128
|
+
Load the route or screen that uses them with `React.lazy` and a `<Suspense>` fallback, so recharts
|
|
129
|
+
lands in its own chunk and screens without a chart never download it. Without that, Vite warns
|
|
130
|
+
about a chunk over 500 kB; the warning is about load time only, and the build is fine.
|
|
131
|
+
|
|
132
|
+
<!-- topic: forms -->
|
|
133
|
+
|
|
134
|
+
**Forms.** In a form, `Input`, `Textarea`, `Select`, `MultiSelect` and `QuantityStepper` go inside a `FormField`,
|
|
135
|
+
which supplies the label, help and error and keeps an `id` you pass to the control. The one
|
|
136
|
+
exception is a control repeated per row of a list (a role `Select` on each member): leave it
|
|
137
|
+
bare and name it through its own `label` prop ("Role for Ilse Varga"). `Switch`, `Checkbox` and
|
|
138
|
+
`Radio` are not `FormField` children: give them an `id` and a `<label htmlFor>`. A failed submit
|
|
139
|
+
renders `ErrorSummary` at the top and focuses it; `useFieldErrors` holds the state (signature in
|
|
140
|
+
`public/docs/helpers.md`).
|
|
141
|
+
|
|
142
|
+
**Buttons.** Two or more buttons side by side need a parent with a gap
|
|
143
|
+
(`flex flex-wrap gap-3`); `DialogFooter` and `CardFooter` already are one. A `Button` is
|
|
144
|
+
`type="button"` unless you say `type="submit"`. A busy button takes `loading`, not `disabled`.
|
|
145
|
+
`disabled` is for an action that is not available; say why in text nearby.
|
|
146
|
+
|
|
147
|
+
**Icon-only buttons** are `IconButton` with a required `label`. A `Tooltip` adds detail; it does
|
|
148
|
+
not replace the label.
|
|
149
|
+
|
|
150
|
+
<!-- topic: overlays -->
|
|
151
|
+
|
|
152
|
+
**Overlays.** A task on top of the page is a `Dialog`; a destructive confirm is `AlertDialog`,
|
|
153
|
+
not `Dialog`; filters, navigation on a narrow screen or one item's detail beside a list is a
|
|
154
|
+
`Sheet`. Never open a dialog from a dialog or a sheet from a sheet. Never open one from a
|
|
155
|
+
`DropdownMenu` item: the item is gone by the time the overlay closes, so focus has nowhere to go.
|
|
156
|
+
Put a dialog's actions in `DialogFooter`.
|
|
157
|
+
|
|
158
|
+
<!-- topic: feedback -->
|
|
159
|
+
|
|
160
|
+
**Feedback.** A `Toast` confirms something the person just did and then leaves, so it never holds
|
|
161
|
+
the only copy of anything; a message that must stay is an `Alert` in the page. A failed load is
|
|
162
|
+
an `Alert` in the `hostile` tone with a retry, not an `EmptyState`. Measurable work is
|
|
163
|
+
`Progress`; a short wait inside a control or a line of text is `Spinner`; a busy `Button` takes
|
|
164
|
+
`loading`.
|
|
165
|
+
|
|
166
|
+
<!-- topic: motion -->
|
|
167
|
+
|
|
168
|
+
**Motion.** The components animate themselves, and the shell animates a route change. A screen
|
|
169
|
+
adds no keyframes of its own: use the classes in `src/styles/motion.css` (`anim-snap-in` for an
|
|
170
|
+
element arriving, `anim-draw-on` for a hairline) and the motion tokens (`--duration-fast` for
|
|
171
|
+
hover, `--duration-base` by default, `--duration-slow` for a larger change, `--ease-snap`).
|
|
172
|
+
Anything you animate yourself stops under `prefers-reduced-motion` (`motion-reduce:` in
|
|
173
|
+
Tailwind), and nothing moves on its own: no autoplay.
|
|
174
|
+
<!-- rules:end -->
|
|
175
|
+
|
|
176
|
+
## Changing the system itself
|
|
177
|
+
|
|
178
|
+
- A component is a folder: `<Name>.tsx`, `<Name>.test.tsx`, `<Name>.meta.ts`, `<Name>Docs.tsx`.
|
|
179
|
+
`<Name>.meta.ts` is the one description; the docs page and every file under `public/docs`,
|
|
180
|
+
`public/llms*.txt` and `public/manifest` are generated from it.
|
|
181
|
+
- After changing a component's props, a meta file, a docs example or a token:
|
|
182
|
+
`npm run agent-docs`, then `npm run verify`. A stale generated file fails a test.
|
|
183
|
+
- `src/components/docs/meta.test.ts` holds each props table against the real TypeScript props,
|
|
184
|
+
and requires a one-sentence `useWhen` and `notFor` in every meta.
|
|
185
|
+
- Each rule above sits under a `<!-- topic: ... -->` marker that decides which skill file
|
|
186
|
+
carries it; `core` is for the rules every screen needs. A rule before the first marker fails
|
|
187
|
+
the generator.
|
|
188
|
+
- A new token needs a sentence in `tokens/usage.json` and, if it is a colour pair, an entry in
|
|
189
|
+
`scripts/lib/contrast-pairs.mjs`.
|
|
190
|
+
- The full procedure for adding a component is in `commands.md`, "Add a component".
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Victor Ilioiu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# division-ds
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The checker for [Division DS](https://github.com/Victor-Ilioiu/division-ds), for a project that uses
|
|
4
|
+
its components (for example installed with shadcn).
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx division-ds check src
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
It flags a raw colour, a Tailwind palette class, a token name that does not exist, two buttons with
|
|
11
|
+
no gap between them, an unknown prop and a value outside a prop's union, and says what to write
|
|
12
|
+
instead. It exits 1 on any finding. Node 22 or newer.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx division-ds rules # writes the Division DS rules into AGENTS.md / CLAUDE.md and similar
|
|
16
|
+
npx division-ds help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The components, the docs and the agent skill: https://github.com/Victor-Ilioiu/division-ds
|
package/package.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "division-ds",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Checks a project that uses Division DS components: raw colours, invented tokens, touching buttons, unknown props.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Victor Ilioiu",
|
|
7
|
+
"homepage": "https://victor-ilioiu.vercel.app/systems/division-ds/",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Victor-Ilioiu/division-ds.git"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"bin": {
|
|
14
|
+
"division-ds": "scripts/division-ds.mjs"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"typescript": "~6.0.2"
|
|
21
|
+
}
|
|
22
|
+
}
|