@designtools/manifest 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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +169 -2
- package/dist/chunk-EFGVJ5ZQ.js +1809 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +254 -0
- package/dist/index.d.ts +541 -0
- package/dist/index.js +70 -0
- package/package.json +73 -3
- package/schemas/rule.schema.json +31 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @designtools/manifest
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- First release. `designtools-manifest build` reads a React design system, and the brand around it, into committed JSON inside the system folder:
|
|
8
|
+
- `components.json`: props through react-docgen-typescript; variants from `tv()` or `cva()` configs, local or imported, or the props' literal unions when there is neither; `data-slot` parts; status and usage from JSDoc (`@status`, `@use`, `@avoid`, `@instead`, `@replaces`, `@role`, `@keyboard`); and `*.examples.tsx`: canonical, do and don't, each with its JSX.
|
|
9
|
+
- `tokens.json`: every custom property in the token stylesheets, with its light, dark and P3 values and the comment above it.
|
|
10
|
+
- `rules.json`, `patterns.json`, `taxonomy.json` and `assets.json`: rules from `*.rule.json` (with a JSON Schema), patterns from `*.pattern.tsx`, the system's names with their curated wrong forms, and the brand assets with how to use them.
|
|
11
|
+
|
|
12
|
+
`check` fails when the committed files are out of date. `diff <base>` classifies every change as breaking, additive, visual or docs. `agents` writes the pointer section of CLAUDE.md or AGENTS.md, `prose-check` warns about wrong and restated names without ever failing, and `provenance` prints the version and commit for generated pages.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Made by Many Ltd
|
|
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,170 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @designtools/manifest
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Reads a React design system, and the brand around it, into committed JSON: every component with its props, variants, parts, usage, status and examples; every token; the rules, brand and interface alike; the product's patterns; one vocabulary with its wrong forms; and the brand assets. Docs pages, checks and agents read those files instead of the source, so none of them has to parse TypeScript, and none of them drifts from it.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @designtools/manifest build # writes src/ds/manifest/*.json
|
|
7
|
+
npx @designtools/manifest check # exits 1 if the committed files are out of date
|
|
8
|
+
npx @designtools/manifest diff main # classifies every change against main
|
|
9
|
+
npx @designtools/manifest agents # writes the pointer section of CLAUDE.md or AGENTS.md
|
|
10
|
+
npx @designtools/manifest prose-check # warns about wrong and restated names in prose; never fails
|
|
11
|
+
npx @designtools/manifest provenance # "Generated from acme-web@1.4.0 at 3f2a9c1", for generated pages
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Deterministic: the same source gives the same bytes, with sorted keys, no timestamps and no absolute paths, so a diff of the files shows only real changes.
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
Record the system folder and the token stylesheets once, in `designtools.json` at the project root:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"manifest": {
|
|
23
|
+
"system": "src/ds",
|
|
24
|
+
"tokens": ["app/styles/tokens.css", "app/styles/scale.css"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The manifest is written inside the system folder (`src/ds/manifest/`), so it moves with the system if the system moves to its own package. Flags override the file: `--system`, `--tokens` (repeat it), `--tsconfig`, `--out`, `--root`.
|
|
30
|
+
|
|
31
|
+
## What it reads
|
|
32
|
+
|
|
33
|
+
**Components.** Every exported component in a `.tsx` file under the system folder. Fixtures, tests, stories and `.d.ts` files are skipped. Props come from [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript), run once over a single TypeScript program, so types resolve across files and through the project's path aliases. A component's own props are kept, and so are those of a Base UI primitive it wraps. Props inherited from the DOM, ARIA or React are left out, and recorded as what it `inherits` (`"span"`, `"@base-ui/react/select:Select.Root"`).
|
|
34
|
+
|
|
35
|
+
**Variants.** Read from the `tv()` (tailwind-variants) or `cva()` call, not inferred from types, because the config is already data: axes, options, defaults, compound conditions, and a `tv()` config's named parts. The config can be in the component's file or imported from another project file. A component with no config falls back to its own props whose types are unions of string literals.
|
|
36
|
+
|
|
37
|
+
**Slots.** Every literal `data-slot` the component renders, including those rendered by private helpers in the same file.
|
|
38
|
+
|
|
39
|
+
**Examples.** A co-located `<name>.examples.tsx`. `canonical` is the one to copy; `do…` and `dont…` exports pair up in order; anything else is a further example. Each records its JSDoc (the why) and the JSX it returns, as written, so docs can show the code and agents can copy it. The manifest never runs them. There is no register of states: loading, empty and error stay with each screen.
|
|
40
|
+
|
|
41
|
+
**JSDoc.** Optional, and nothing is required. A component's JSDoc, or failing that its variant config's, is its description. These tags are read:
|
|
42
|
+
|
|
43
|
+
| Tag | Becomes |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `@name` | The display name, when it should differ from the export |
|
|
46
|
+
| `@description` | Added to the description |
|
|
47
|
+
| `@category` | The docs navigation group |
|
|
48
|
+
| `@example` | A JSX snippet; repeat for several |
|
|
49
|
+
| `@see` | A link or a related component; repeat for several |
|
|
50
|
+
| `@deprecated` | The component, or a prop, is deprecated, with the reason |
|
|
51
|
+
| `@primitive` | The primitive it wraps |
|
|
52
|
+
| `@aria` | The ARIA pattern it follows |
|
|
53
|
+
| `@status` | `stable`, `emerging` or `deprecated`, then an optional note |
|
|
54
|
+
| `@use` | When to reach for it |
|
|
55
|
+
| `@avoid` | When not to |
|
|
56
|
+
| `@instead` | What to use instead, comma-separated |
|
|
57
|
+
| `@replaces` | Raw elements it stands in for (`button`), which the adherence report counts |
|
|
58
|
+
| `@role`, `@keyboard` | What assistive technology meets, and the keys it answers |
|
|
59
|
+
| `@nodocgen` | Leaves the component out |
|
|
60
|
+
|
|
61
|
+
Any other tag is a warning, with a suggestion when it is close to one of these.
|
|
62
|
+
|
|
63
|
+
**Tokens.** Every custom property in the listed stylesheets: the colour tiers `@designtools/tokens` generates and the scale you author beside them. Each token records its value in every context it is declared in: `default` (`@theme`, `:root`), `light`, `dark`, `p3:` for the wide-gamut layer, and any other selector as written. A `prefers-color-scheme` fallback never overrides an explicit dark block. The comment above a declaration, or above the run of declarations it starts, becomes its description. Tiers follow Tailwind's namespaces (`--text-*`, `--radius-*`, …); semantic colours like `--primary` are recognised by their values.
|
|
64
|
+
|
|
65
|
+
**Rules.** One `<id>.rule.json` per rule in `<system>/rules`, brand and interface in the same format: title, statement, rationale, threshold, what it applies to, exceptions, the tokens it rests on, whether it is `confirmed` or still an `assumption`, and the check that proves it. [`schemas/rule.schema.json`](schemas/rule.schema.json) validates them in an editor.
|
|
66
|
+
|
|
67
|
+
**Patterns.** Any `<id>.pattern.tsx` in the system folder. The file's JSDoc names and describes it (`@name`, `@status`), its imports say which components it composes, and each named export is a composition, recorded like an example.
|
|
68
|
+
|
|
69
|
+
**Taxonomy.** The canonical names come from everything else: components, variant axes and their meaningful options, semantic colours, patterns and rules. `<system>/taxonomy.json` adds the wrong forms (`{ "name": "destructive", "wrong": ["error", "danger"] }`) and product terms the code never names (`{ "name": "sign in", "kind": "product", "wrong": ["log in"] }`).
|
|
70
|
+
|
|
71
|
+
**Brand assets.** Every image in `<system>/brand`, with an `assets.json` there saying how to use each: kind, usage, minimum size, clear space, the surfaces it may sit on, alt text. SVG and PNG sizes are read from the files. A file the index does not mention is listed anyway, with a warning.
|
|
72
|
+
|
|
73
|
+
## The files
|
|
74
|
+
|
|
75
|
+
`components.json`, abridged:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"generator": "@designtools/manifest@0.1.0",
|
|
80
|
+
"schema": "designtools.manifest/1",
|
|
81
|
+
"system": "src/ds",
|
|
82
|
+
"components": [
|
|
83
|
+
{
|
|
84
|
+
"name": "Badge",
|
|
85
|
+
"export": "Badge",
|
|
86
|
+
"source": "src/ds/badge/badge.tsx",
|
|
87
|
+
"description": "A pill: soft tinted background, strong text of the same hue.",
|
|
88
|
+
"inherits": ["span"],
|
|
89
|
+
"props": {
|
|
90
|
+
"intent": { "type": "\"default\" | \"neutral\" | \"success\"", "values": ["default", "neutral", "success"], "required": false }
|
|
91
|
+
},
|
|
92
|
+
"variants": {
|
|
93
|
+
"from": "tv",
|
|
94
|
+
"config": "badge",
|
|
95
|
+
"axes": [{ "name": "intent", "default": "neutral", "options": [{ "name": "default" }, { "name": "neutral" }, { "name": "success" }] }]
|
|
96
|
+
},
|
|
97
|
+
"slots": ["badge"],
|
|
98
|
+
"status": "stable",
|
|
99
|
+
"usage": { "use": "A short status beside the thing it describes.", "avoid": "Anything people can press.", "instead": ["Button"] },
|
|
100
|
+
"examples": {
|
|
101
|
+
"source": "src/ds/badge/badge.examples.tsx",
|
|
102
|
+
"canonical": { "name": "canonical", "code": "<Badge intent=\"success\">Paid</Badge>" },
|
|
103
|
+
"do": [{ "name": "doShortLabel", "description": "One or two words, in sentence case." }],
|
|
104
|
+
"dont": [{ "name": "dontClickable", "description": "A badge is not a button." }],
|
|
105
|
+
"other": []
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`tokens.json`, abridged:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"generator": "@designtools/manifest@0.1.0",
|
|
117
|
+
"schema": "designtools.manifest/1",
|
|
118
|
+
"sources": ["app/styles/tokens.css", "app/styles/scale.css"],
|
|
119
|
+
"tokens": [
|
|
120
|
+
{ "name": "--primary", "tier": "color", "values": { "light": "var(--color-primary-700)", "dark": "var(--color-primary-800)" }, "source": "app/styles/tokens.css" },
|
|
121
|
+
{ "name": "--radius-md", "tier": "radius", "values": { "default": "0.375rem" }, "description": "corners, scaled to the element", "source": "app/styles/scale.css" }
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Beside them sit `rules.json`, `patterns.json`, `taxonomy.json` and `assets.json`, under the same rules. The full schema is in [`src/types.ts`](src/types.ts), which has no imports so it can be copied: `@designtools/blocks` carries an identical copy.
|
|
127
|
+
|
|
128
|
+
## Commands
|
|
129
|
+
|
|
130
|
+
| Command | Exit code |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| `build` | 0, or 2 on a usage error |
|
|
133
|
+
| `check` | 0 when both files match the source, 1 when either is missing or out of date. A version change is reported as such |
|
|
134
|
+
| `diff [base]` | 0, or 1 with `--fail-on <class>` when a change of that class is found. `base` defaults to `main` |
|
|
135
|
+
| `agents` | 0; with `--check`, 1 when the section is out of date |
|
|
136
|
+
| `prose-check [file…]` | Always 0. Prose is for people to fix, never a reason to fail a build |
|
|
137
|
+
| `provenance` | 0 |
|
|
138
|
+
|
|
139
|
+
`diff` builds the manifest from the current source and compares it with the files committed at `base`. Every change is classified:
|
|
140
|
+
|
|
141
|
+
| Class | Examples |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| breaking | A component, prop, variant option, token or `data-slot` removed; a prop made required; a new required prop; a prop type changed |
|
|
144
|
+
| additive | A new component, optional prop, variant option, token, slot or state |
|
|
145
|
+
| visual | A token value or a default variant changed |
|
|
146
|
+
| docs | A description, status, usage, example, rule, pattern, term or asset changed |
|
|
147
|
+
|
|
148
|
+
Components are matched by their path inside the system folder, so moving the whole system is not a change. The report is markdown, ready to post on a pull request; `--json` prints the changes as data.
|
|
149
|
+
|
|
150
|
+
## For agents
|
|
151
|
+
|
|
152
|
+
`agents` writes a section of `CLAUDE.md` (or `AGENTS.md`) between markers, and leaves the rest of the file alone. It points agents at each manifest file and the docs, and lists nothing: a list of components or tokens written into prose is a second copy that drifts.
|
|
153
|
+
|
|
154
|
+
`prose-check` reads `CLAUDE.md`, `AGENTS.md`, `.claude/`, `docs/` and the system folder's markdown, and warns about a component tag the system does not have (`<Modal>`), a wrong form from the taxonomy (`Dropdown` for `Select`, "log in" for "sign in"), and a paragraph or list that restates several components or tokens. The generated section is skipped.
|
|
155
|
+
|
|
156
|
+
`provenance` prints the project's version and the commit it was built at (`VERCEL_GIT_COMMIT_SHA` or `GITHUB_SHA` when set, else git), for the header of a generated docs page. A generated page never carries a review date.
|
|
157
|
+
|
|
158
|
+
## Programmatic use
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { buildManifest, diffManifests, loadConfig } from "@designtools/manifest";
|
|
162
|
+
|
|
163
|
+
const built = buildManifest(loadConfig({ root: "." }));
|
|
164
|
+
built.components.components; // ComponentEntry[]
|
|
165
|
+
built.files; // { "src/ds/manifest/components.json": "…" }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Licence
|
|
169
|
+
|
|
170
|
+
[MIT](LICENSE), © Made by Many Ltd.
|