@assure-one/design-system 1.34.0 → 1.36.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/README.md +53 -0
- package/codemods/README.md +225 -10
- package/codemods/lib/jsx-edit.mjs +63 -4
- package/codemods/lib/registry.mjs +7 -0
- package/codemods/transforms/cm-04-button-variant-intent.mjs +223 -0
- package/codemods/transforms/cm-05-button-icon-slots.mjs +117 -0
- package/codemods/transforms/cm-06-tone-to-intent.mjs +190 -0
- package/codemods/transforms/cm-07-input-size.mjs +104 -0
- package/codemods/transforms/cm-08-search-select-to-combobox.mjs +236 -0
- package/codemods/transforms/cm-10-date-picker-value-change.mjs +416 -0
- package/codemods/transforms/cm-14-hidden-mirrors.mjs +2 -2
- package/codemods/transforms/cm-19-progress-explicit-intent.mjs +192 -0
- package/dist/css/components.css +1 -1
- package/dist/css/legacy-aliases.css +5 -0
- package/dist/css/tokens.css +5 -0
- package/dist/design-system-provider-cPUklDJv.d.ts +220 -0
- package/dist/icons/index.d.ts +3 -0
- package/dist/icons/index.js +1833 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index-CQwzTm0v.d.ts +509 -0
- package/dist/index.d.ts +2967 -823
- package/dist/index.js +7644 -3062
- package/dist/index.js.map +1 -1
- package/dist/next/index.d.ts +20 -0
- package/dist/next/index.js +16 -0
- package/dist/next/index.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/testing/index.cjs +133 -11
- package/dist/testing/index.d.cts +98 -2
- package/dist/testing/index.d.ts +98 -2
- package/dist/testing/index.js +132 -12
- package/docs/components.md +601 -0
- package/docs/components.registry.json +1586 -0
- package/docs/for-ai-agents.md +153 -0
- package/package.json +21 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# `@assure-one/design-system` — the short rulebook for AI agents and new contributors
|
|
2
|
+
|
|
3
|
+
You are writing UI in an Assure product (Pro, Tax, Books, Audit, the client portal) or in this repository. This page is the ten-minute version of the rules; every line links to the source of truth. The full component list is [`docs/components.md`](./components.md) — it is generated from the API reports, so it is complete: if a component is not there, the package does not export it.
|
|
4
|
+
|
|
5
|
+
Both files ship in the npm package, so they are readable offline:
|
|
6
|
+
`node_modules/@assure-one/design-system/docs/components.md` and `…/docs/for-ai-agents.md`.
|
|
7
|
+
|
|
8
|
+
## 1. Install and import
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pnpm add @assure-one/design-system
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
// root layout, once
|
|
16
|
+
import "@assure-one/design-system/styles.css";
|
|
17
|
+
|
|
18
|
+
// components — everything public is on the root entry
|
|
19
|
+
import { Button, Field, Input, Label, Select } from "@assure-one/design-system";
|
|
20
|
+
|
|
21
|
+
// icons — the same components, server-safe (no "use client"), for Server Components
|
|
22
|
+
import { CheckIcon } from "@assure-one/design-system/icons";
|
|
23
|
+
|
|
24
|
+
// tokens as JavaScript, for the rare inline style or chart config
|
|
25
|
+
import { systemTokens } from "@assure-one/design-system/tokens";
|
|
26
|
+
|
|
27
|
+
// test helpers, for Jest / Vitest suites that render the real package
|
|
28
|
+
import { withAssureDesignSystem } from "@assure-one/design-system/testing";
|
|
29
|
+
|
|
30
|
+
// the Next.js adapter: the provider preconfigured with next/link and next/image
|
|
31
|
+
import { NextDesignSystemProvider } from "@assure-one/design-system/next";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Mount `DesignSystemProvider` (or `NextDesignSystemProvider` on Next.js) once in the root layout: it carries the string overrides (`messages`), `locale`, `dir`, the portal container and the router link/image adapters that `LinkButton` and `Logo` render. `ThemeScope` themes one subtree (scheme, brand, density) and re-stamps the overlays opened from inside it; `BrandScope` is the product brand alone.
|
|
35
|
+
|
|
36
|
+
The root entry is `"use client"`; import icons from `/icons` when you need them in a Server Component. The split CSS entries (`css/tokens.css`, `css/components.css`, …) and how an app declares its layer order are in [`docs/integration/css.md`](./integration/css.md). Nothing outside `src/index.ts` and the five entries above is public ([ADR-011](./adr/011-public-api-governance.md)).
|
|
37
|
+
|
|
38
|
+
## 2. Never raw HTML, never re-implement
|
|
39
|
+
|
|
40
|
+
If a UI element exists in the design system, use it. Do not write `<button>`, `<input>`, `<select>`, `<textarea>`, `<dialog>`, `<table>`, `<a role="button">`, `<div onClick>`, `<h1>`, `<p>`, `<hr>`, `<kbd>`, `<code>` or an inline `<svg>` in product code, and do not build a local copy of a component that ships here. The mapping is the ["Never hand-roll"](./components.md#never-hand-roll) table; the short form:
|
|
41
|
+
|
|
42
|
+
| Instead of | Use |
|
|
43
|
+
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `<button>`, `<a role="button">`, `<div onClick>` | `Button`, `IconButton`, `LinkButton`, `SubmitButton`, `Pressable` |
|
|
45
|
+
| `<input>` and its types | `Input`, `NumberInput`, `SearchInput`, `PhoneField`, `OTPInput`, `DatePicker`, `FileUpload`, `Checkbox`, `RadioGroup`, `Switch`, `Slider` |
|
|
46
|
+
| `<textarea>` | `Textarea` |
|
|
47
|
+
| `<select>`, `<datalist>` | `Select`, `Combobox`, `MultiSelect` |
|
|
48
|
+
| `<label>`, `aria-describedby` wiring, red error `<p>` | `Field` + `Label` + `FieldDescription` + `FieldError` |
|
|
49
|
+
| `<fieldset>`, `<legend>` | `Fieldset` + `FieldsetLegend` |
|
|
50
|
+
| `<dialog>`, fixed overlay divs | `Dialog`, `AlertDialog`, `Sheet`, `ResponsiveDialog`, `Popover` |
|
|
51
|
+
| `<table>` | `Table`, `DataTable`, `DataTableView` |
|
|
52
|
+
| `<h1>`–`<h6>`, `<p>`, `<code>`, `<kbd>` | `Heading`, `Text`, `Code`, `Kbd` |
|
|
53
|
+
| `<hr>` | `Separator` |
|
|
54
|
+
| `<svg>`, `lucide-react` | the icon catalogue (`/icons`) |
|
|
55
|
+
| `flex gap-*` wrappers | `Stack`, `Inline`; `Surface` / `Card` for boxes |
|
|
56
|
+
| `title="…"`, `window.confirm()`, `alert()` | `Tooltip`, `ConfirmActionButton` / `AlertDialog`, `useToast` |
|
|
57
|
+
|
|
58
|
+
Before writing any element, look it up in the ["Pick a component"](./components.md#pick-a-component) table. The only raw elements that are fine are structural ones the design system does not model (`<main>`, `<article>`, `<ul>` for plain lists, `<img>` for content images, `<form>` itself).
|
|
59
|
+
|
|
60
|
+
## 3. Forms: the `Field` recipe
|
|
61
|
+
|
|
62
|
+
The full guide — `Field` + design-system controls + a Server Action + zod, reset and `required`, what each control submits, and how to test it — is [`docs/forms.md`](./forms.md). The rules in one breath:
|
|
63
|
+
|
|
64
|
+
Every design-system control binds itself to the surrounding `Field` (ids, `aria-describedby`, `aria-invalid`, `required`) and posts a real value on native form submission — there is no need for hidden inputs, manual ids or `htmlFor` plumbing ([ADR-006](./adr/006-field-native-form-participation.md), contract ids `C-FORM-*`, `C-HIDDEN-MIRRORS`).
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<Field invalid={!!errors.email}>
|
|
68
|
+
<Label>Email</Label>
|
|
69
|
+
<Input name="email" type="email" autoComplete="email" />
|
|
70
|
+
<FieldDescription>We only use it for receipts.</FieldDescription>
|
|
71
|
+
<FieldError>{errors.email}</FieldError>
|
|
72
|
+
</Field>
|
|
73
|
+
|
|
74
|
+
<Fieldset disabled={saving}>
|
|
75
|
+
<FieldsetLegend>Notifications</FieldsetLegend>
|
|
76
|
+
<Field><Label>Email me</Label><Switch name="notify_email" /></Field>
|
|
77
|
+
<Field><Label>Text me</Label><Switch name="notify_sms" /></Field>
|
|
78
|
+
</Fieldset>
|
|
79
|
+
|
|
80
|
+
<SubmitButton>Save</SubmitButton>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- A control that is not from the design system (a rich-text editor, a canvas) gets the same wiring through `<FieldControl>` around it, or by calling `useFieldControl()` inside it.
|
|
84
|
+
- Every control takes `size` on the shared control scale (`xs` `sm` `md` `lg` `xl`, [`docs/design-system/control-sizes.md`](./design-system/control-sizes.md)) and `onValueChange` with the plain value. `inputSize`, `triggerClassName` and fake `onChange` events are deprecated aliases (§7).
|
|
85
|
+
- `Select` has a real empty value; never invent a sentinel option such as `"none"` (`C-SELECT-EMPTY`, finder codemod CM-20).
|
|
86
|
+
- Test a form through its labels with the `/testing` helpers: `fillField`, `selectOption`, `pickDate` (§8).
|
|
87
|
+
|
|
88
|
+
## 4. Styling: `className`, `classNames`, and who wins
|
|
89
|
+
|
|
90
|
+
- **`className`** lands on the component's styling root (its `data-slot="<component>"` element), `style` with it. Compound components (`Card`, `Dialog`, `DataTable`…) expose their parts as JSX, each taking its own `className`.
|
|
91
|
+
- **`classNames`** is for data-driven components whose parts are not JSX (`Select`, `Combobox`, `DataTableView`, `Pagination`, `FileUpload`, `Questions`): `classNames={{ trigger: "…", content: "…" }}`, typed by the component's exported `*Slot` union. The old `triggerClassName` / `contentClassName` / `wrapperClassName` / `iconClassName` props are deprecated aliases ([ADR-008](./adr/008-component-anatomy.md)).
|
|
92
|
+
- **Your class wins by cascade, not by `tailwind-merge`.** Component classes are `ds:`-prefixed and compiled into the package stylesheet at the `components` layer; your Tailwind utilities sit in your `utilities` layer, so `<Button className="rounded-none">` beats the component's `ds:rounded-md` without `!important` ([ADR-004](./adr/004-css-delivery-cascade.md) decision 4). Do not try to "remove" a component class; add yours.
|
|
93
|
+
- **Do not select a component's internals** (`.rounded-md.font-medium` into a card, `> div > span`). Internal DOM, wrapper elements and class names are not a contract; `data-slot` attributes and `classNames` are. The finder codemod CM-15 lists offending selectors (`C-DOM-*`).
|
|
94
|
+
- **Geometry comes from the component's CSS variable** where one is documented (for example the sidebar width), never from overriding a width class.
|
|
95
|
+
|
|
96
|
+
## 5. The `ds:` prefix and the CSS entries
|
|
97
|
+
|
|
98
|
+
- Every class a component renders is prefixed: `ds:flex ds:bg-surface`. These compile inside `styles.css` (and `css/components.css`), not in your build — that is what makes them stable. Your own code writes ordinary, unprefixed Tailwind. You never write `ds:` classes in a product.
|
|
99
|
+
- `styles.css` still ships the frozen legacy unprefixed utilities the 1.x apps used directly (`bg-surface`, `text-fg-3`…); they are additive-only until 2.0. Do not depend on new ones.
|
|
100
|
+
- `@source` into `node_modules/@assure-one/design-system` in your Tailwind config is unnecessary and no longer regenerates component classes with your theme; the per-app preset is the supported way to keep a theme value ([`docs/integration/css.md`](./integration/css.md) §3–4, "What changed in W1-11").
|
|
101
|
+
- Inline styles the design system writes read `var(--ds-x, var(--x))`; do the same when you must write an inline `var()` in this repository.
|
|
102
|
+
|
|
103
|
+
## 6. Tokens
|
|
104
|
+
|
|
105
|
+
- Components consume **system tokens** (`--color-action-primary-bg`, `--ds-*` names), never reference values (`--color-navy-700`). The namespaced `--ds-*` name of every token is in `tokens/src/ds-name-map.json`; the roles are documented in [`docs/design-system/`](./design-system/) (`shape-roles.md`, `typography-roles.md`, `control-sizes.md`, `microinteractions.md`).
|
|
106
|
+
- In an app, use the generated utilities (`bg-surface`, `text-fg-2`, `border-rule`) or the `--ds-*` custom properties. Override a token by redeclaring the variable in your preset or on a scope, not by editing component classes. Product theming is `BrandScope` / `data-brand` and runtime brand themes (`createBrandTheme`, [`docs/integration/css.md`](./integration/css.md) §5); status colour is the `intent` prop; service-line colour is `serviceToneStyle`.
|
|
107
|
+
- Tokens are additive: nothing is renamed or removed without a major.
|
|
108
|
+
|
|
109
|
+
## 7. Deprecated aliases and codemods
|
|
110
|
+
|
|
111
|
+
Every deprecated name keeps rendering what it did until 3.0, and most have a codemod. The complete table with codemod ids is ["Deprecated aliases and their replacements"](./components.md#deprecated-aliases-and-their-replacements). The ones you will meet most:
|
|
112
|
+
|
|
113
|
+
| Deprecated | Write instead | Codemod |
|
|
114
|
+
| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------- |
|
|
115
|
+
| `Button variant="primary" \| "secondary" \| "destructive" \| "success"` | `variant` (`solid` `soft` `outline` `ghost` `link`) + `intent` (`brand` `neutral` `success` `danger`) | CM-04 |
|
|
116
|
+
| `iconLeft` / `iconRight` | `iconStart` / `iconEnd` | CM-05 |
|
|
117
|
+
| `inputSize` | `size` | CM-07 |
|
|
118
|
+
| `tone` on StatusDot, IconTile, Spinner, SegmentedProgress, SuiteProgress | `intent` | CM-06 |
|
|
119
|
+
| ProgressBar / ProgressRing `variant` | `intent` | CM-19 |
|
|
120
|
+
| `SearchSelect` | `Combobox` with `Option` (`{ value, label }`) | CM-08 |
|
|
121
|
+
| `DatePicker onChange={e => …e.target.value}` | `onValueChange={value => …}` | CM-10 |
|
|
122
|
+
| `FormError` / `FormSuccess` / `FormSection` | `FieldError` / `FieldDescription` / `Fieldset` | — |
|
|
123
|
+
| `triggerClassName` etc. | `classNames={{ trigger }}` | — |
|
|
124
|
+
|
|
125
|
+
Run codemods from the installed package so they match your design-system version ([`codemods/README.md`](../codemods/README.md)):
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
node node_modules/@assure-one/design-system/codemods/run.mjs list
|
|
129
|
+
node node_modules/@assure-one/design-system/codemods/run.mjs upgrade --dry # everything this project is missing
|
|
130
|
+
node node_modules/@assure-one/design-system/codemods/run.mjs CM-07 src # one codemod, writes the ledger
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Transforming codemods append to **`.ds-migrations.json`** in the project root — commit it. The ledger is what makes one-shot codemods refuse to run twice, prerequisites enforceable and `upgrade` exact; the consumer scanner reads it for the migration dashboard. Class X codemods (CM-14 hidden mirrors, CM-15 DOM selectors, CM-16 globals.css, CM-20 select sentinels) only report; fix what they list by hand.
|
|
134
|
+
|
|
135
|
+
## 8. Testing with the real package
|
|
136
|
+
|
|
137
|
+
Do not stub the design system in unit tests. `@assure-one/design-system/testing` (experimental) makes the real build load under Jest — `withAssureDesignSystem(config)` — or Vitest (`installDomPolyfills()`), and ships DOM-level helpers: `fillField` (type into a control by its Field label), `selectOption` for `Select`, `pickDate` for `DatePicker`, `openMenu` for `DropdownMenu`, `createToastRecorder` for toasts. Guide: [`docs/testing.md`](./testing.md); architecture: [ADR-014](./adr/014-testing-architecture.md). Query by role and name, never by internal class.
|
|
138
|
+
|
|
139
|
+
## 9. What is experimental
|
|
140
|
+
|
|
141
|
+
`@experimental` (ADR-011) means the API may change in a minor release; pin the version and read the changelog on upgrade. Today that is: the **Field family** (`Field`, `FieldControl`, `Fieldset`, `useFieldControl`), the **new controls and variants** (`Combobox`, `MultiSelect`, `NumberInput`, `IconButton`, `Chip`, `Pressable`), the **layout and typography primitives** (`Stack`, `Inline`, `Surface`, `Heading`, `Text`, `Code`, `Kbd`), `defineStatusMap`, the **provider and theming layer** (`DesignSystemProvider`, `useDsMessages`, `ThemeScope`, the **`/next` entry**), the **`/icons` entry**, the **`/testing` entry**, the split CSS entries and runtime brand theming. The catalogue marks each row; the source of truth is the JSDoc tag in `src/`.
|
|
142
|
+
|
|
143
|
+
## 10. The component you need is not there
|
|
144
|
+
|
|
145
|
+
Do not build it in the product and do not fork one from here. Check the catalogue's "Pick a component" table first — the need is usually covered by a composition (`Field` + `Input`, `Card` + `Stack`, `Popover` + a form). If it is genuinely missing:
|
|
146
|
+
|
|
147
|
+
1. Compose from primitives locally **behind one component in your app**, with no design-system internals selected, so the swap is one file later.
|
|
148
|
+
2. Propose it for the shared layer through [ADR-009](./adr/009-shared-product-promotion.md): the API is free of product vocabulary and business rules, two products commit to adopting it with named owners, an owning team is named, and it ships `@experimental` with a story, interaction tests, axe checks and a docs page ([template](./design-system/component-docs-template.md)). Open the proposal as an issue or PR in this repository.
|
|
149
|
+
3. Once two production consumers use it (visible on the migration dashboard, `docs/migration/status.md`), it becomes stable and the local copies are removed.
|
|
150
|
+
|
|
151
|
+
## 11. Working inside this repository
|
|
152
|
+
|
|
153
|
+
Read `CLAUDE.md` and `CONTRIBUTING.md` first. Every new or changed public component updates [`docs/components.registry.json`](./components.registry.json) and regenerates the catalogue (`pnpm docs:catalogue`); `pnpm test:contracts` fails otherwise. Every component ships a story next to it, uses system tokens only, names its transition property (no `transition-all`), respects `prefers-reduced-motion`, and is axe-clean.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assure-one/design-system",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.0",
|
|
4
4
|
"description": "Assure One design system — tokens, primitives, and patterns for the Assure Suite.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"types": "./dist/tokens/index.d.ts",
|
|
28
28
|
"import": "./dist/tokens/index.js"
|
|
29
29
|
},
|
|
30
|
+
"./icons": {
|
|
31
|
+
"types": "./dist/icons/index.d.ts",
|
|
32
|
+
"import": "./dist/icons/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./next": {
|
|
35
|
+
"types": "./dist/next/index.d.ts",
|
|
36
|
+
"import": "./dist/next/index.js"
|
|
37
|
+
},
|
|
30
38
|
"./testing": {
|
|
31
39
|
"import": {
|
|
32
40
|
"types": "./dist/testing/index.d.ts",
|
|
@@ -43,6 +51,9 @@
|
|
|
43
51
|
"dist",
|
|
44
52
|
"codemods",
|
|
45
53
|
"!codemods/__test__",
|
|
54
|
+
"docs/components.md",
|
|
55
|
+
"docs/components.registry.json",
|
|
56
|
+
"docs/for-ai-agents.md",
|
|
46
57
|
"README.md"
|
|
47
58
|
],
|
|
48
59
|
"publishConfig": {
|
|
@@ -71,6 +82,7 @@
|
|
|
71
82
|
"@radix-ui/react-collapsible": "^1.1.12",
|
|
72
83
|
"@radix-ui/react-context-menu": "^2.2.16",
|
|
73
84
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
85
|
+
"@radix-ui/react-dismissable-layer": "^1.1.11",
|
|
74
86
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
75
87
|
"@radix-ui/react-hover-card": "^1.1.15",
|
|
76
88
|
"@radix-ui/react-label": "^2.1.8",
|
|
@@ -147,7 +159,8 @@
|
|
|
147
159
|
"vite": "^6.0.7",
|
|
148
160
|
"vitest": "^4.1.11",
|
|
149
161
|
"vitest-browser-react": "^2.3.0",
|
|
150
|
-
"wait-on": "^9.0.6"
|
|
162
|
+
"wait-on": "^9.0.6",
|
|
163
|
+
"zod": "^4.6.5"
|
|
151
164
|
},
|
|
152
165
|
"engines": {
|
|
153
166
|
"node": ">=22"
|
|
@@ -158,6 +171,10 @@
|
|
|
158
171
|
"build:css": "tailwindcss -i ./src/tokens/consumer.css -o ./dist/styles.css --minify && node scripts/css/compat.mjs",
|
|
159
172
|
"class-flip": "node scripts/class-flip/run.mjs",
|
|
160
173
|
"class-flip:check": "node scripts/class-flip/run.mjs --check",
|
|
174
|
+
"icons:generate": "node scripts/icons/generate.mjs",
|
|
175
|
+
"icons:check": "node scripts/icons/generate.mjs --check",
|
|
176
|
+
"messages:generate": "node scripts/messages/generate.mjs",
|
|
177
|
+
"messages:check": "node scripts/messages/generate.mjs --check",
|
|
161
178
|
"build:css:entries": "node scripts/build-css-entries.mjs",
|
|
162
179
|
"build:testing": "tsup --config tsup.testing.config.ts",
|
|
163
180
|
"dev": "tsup --watch",
|
|
@@ -175,7 +192,8 @@
|
|
|
175
192
|
"test": "vitest run",
|
|
176
193
|
"test:browser": "vitest run --config vitest.browser.config.ts",
|
|
177
194
|
"typecheck:browser": "tsc -p tests/browser/tsconfig.json --noEmit",
|
|
178
|
-
"test:contracts": "node --test tests/design-system-contracts.test.mjs",
|
|
195
|
+
"test:contracts": "node --test tests/design-system-contracts.test.mjs && pnpm messages:check && node scripts/docs/catalogue.mjs --check",
|
|
196
|
+
"docs:catalogue": "node scripts/docs/catalogue.mjs",
|
|
179
197
|
"contracts:check": "node scripts/contracts/run.mjs --check",
|
|
180
198
|
"contracts:snapshot": "node scripts/contracts/run.mjs --snapshot",
|
|
181
199
|
"typecheck": "tsc --noEmit",
|