@misoto22/design 0.5.0 → 0.6.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.
Files changed (214) hide show
  1. package/README.md +124 -0
  2. package/bin/misoto22-design.mjs +205 -0
  3. package/dist/agent/Accordion.md +41 -0
  4. package/dist/agent/Alert.md +42 -0
  5. package/dist/agent/AppShell.md +40 -0
  6. package/dist/agent/AreaChart.md +68 -0
  7. package/dist/agent/Article.md +41 -0
  8. package/dist/agent/Avatar.md +32 -0
  9. package/dist/agent/Badge.md +40 -0
  10. package/dist/agent/BarChart.md +65 -0
  11. package/dist/agent/BarList.md +40 -0
  12. package/dist/agent/BigNumber.md +45 -0
  13. package/dist/agent/BoxPlot.md +58 -0
  14. package/dist/agent/Breadcrumb.md +32 -0
  15. package/dist/agent/BulletChart.md +48 -0
  16. package/dist/agent/Button.md +56 -0
  17. package/dist/agent/Calendar.md +42 -0
  18. package/dist/agent/Card.md +49 -0
  19. package/dist/agent/Checkbox.md +35 -0
  20. package/dist/agent/Collapsible.md +46 -0
  21. package/dist/agent/Combobox.md +50 -0
  22. package/dist/agent/Command.md +93 -0
  23. package/dist/agent/ComposedChart.md +57 -0
  24. package/dist/agent/ContextMenu.md +59 -0
  25. package/dist/agent/DatePicker.md +75 -0
  26. package/dist/agent/Diagram.md +46 -0
  27. package/dist/agent/Dialog.md +52 -0
  28. package/dist/agent/DropdownMenu.md +70 -0
  29. package/dist/agent/EmptyState.md +37 -0
  30. package/dist/agent/ErrorState.md +41 -0
  31. package/dist/agent/Facet.md +82 -0
  32. package/dist/agent/Field.md +37 -0
  33. package/dist/agent/FigureBand.md +37 -0
  34. package/dist/agent/FloatingIconButton.md +38 -0
  35. package/dist/agent/FunnelChart.md +52 -0
  36. package/dist/agent/Heatmap.md +53 -0
  37. package/dist/agent/Histogram.md +63 -0
  38. package/dist/agent/Input.md +30 -0
  39. package/dist/agent/Kbd.md +29 -0
  40. package/dist/agent/LineChart.md +60 -0
  41. package/dist/agent/LinkArrow.md +29 -0
  42. package/dist/agent/NativeSelect.md +40 -0
  43. package/dist/agent/NavItem.md +35 -0
  44. package/dist/agent/Pagination.md +43 -0
  45. package/dist/agent/PieChart.md +55 -0
  46. package/dist/agent/Popover.md +57 -0
  47. package/dist/agent/Progress.md +33 -0
  48. package/dist/agent/RadarChart.md +54 -0
  49. package/dist/agent/RadialChart.md +57 -0
  50. package/dist/agent/RadioGroup.md +44 -0
  51. package/dist/agent/SankeyChart.md +61 -0
  52. package/dist/agent/ScatterChart.md +54 -0
  53. package/dist/agent/ScrollArea.md +40 -0
  54. package/dist/agent/SearchableMenu.md +46 -0
  55. package/dist/agent/Select.md +75 -0
  56. package/dist/agent/Separator.md +35 -0
  57. package/dist/agent/Sheet.md +57 -0
  58. package/dist/agent/Skeleton.md +73 -0
  59. package/dist/agent/Slider.md +39 -0
  60. package/dist/agent/Sparkline.md +45 -0
  61. package/dist/agent/Spinner.md +39 -0
  62. package/dist/agent/StatusDot.md +36 -0
  63. package/dist/agent/StatusPill.md +28 -0
  64. package/dist/agent/Steps.md +44 -0
  65. package/dist/agent/Switch.md +29 -0
  66. package/dist/agent/Table.md +85 -0
  67. package/dist/agent/Tabs.md +48 -0
  68. package/dist/agent/Tag.md +35 -0
  69. package/dist/agent/Textarea.md +26 -0
  70. package/dist/agent/Toast.md +26 -0
  71. package/dist/agent/ToggleGroup.md +44 -0
  72. package/dist/agent/Tooltip.md +51 -0
  73. package/dist/agent/TreemapChart.md +52 -0
  74. package/dist/agent/WaterfallChart.md +62 -0
  75. package/dist/agent/catalog.json +1791 -0
  76. package/dist/agent/index.md +131 -0
  77. package/dist/charts/AreaChart/AreaChart.d.ts +191 -0
  78. package/dist/charts/AreaChart/AreaChart.js +480 -0
  79. package/dist/charts/AreaChart/AreaChart.js.map +1 -0
  80. package/dist/charts/BarChart/BarChart.d.ts +179 -0
  81. package/dist/charts/BarChart/BarChart.js +591 -0
  82. package/dist/charts/BarChart/BarChart.js.map +1 -0
  83. package/dist/charts/BarList/BarList.d.ts +57 -0
  84. package/dist/charts/BarList/BarList.js +71 -0
  85. package/dist/charts/BarList/BarList.js.map +1 -0
  86. package/dist/charts/BigNumber/BigNumber.d.ts +56 -0
  87. package/dist/charts/BigNumber/BigNumber.js +31 -0
  88. package/dist/charts/BigNumber/BigNumber.js.map +1 -0
  89. package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
  90. package/dist/charts/BoxPlot/BoxPlot.js +495 -0
  91. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
  92. package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
  93. package/dist/charts/BulletChart/BulletChart.js +162 -0
  94. package/dist/charts/BulletChart/BulletChart.js.map +1 -0
  95. package/dist/charts/ComposedChart/ComposedChart.d.ts +171 -0
  96. package/dist/charts/ComposedChart/ComposedChart.js +667 -0
  97. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
  98. package/dist/charts/Facet/Facet.d.ts +240 -0
  99. package/dist/charts/Facet/Facet.js +133 -0
  100. package/dist/charts/Facet/Facet.js.map +1 -0
  101. package/dist/charts/Facet/panels.d.ts +187 -0
  102. package/dist/charts/Facet/panels.js +203 -0
  103. package/dist/charts/Facet/panels.js.map +1 -0
  104. package/dist/charts/FunnelChart/FunnelChart.d.ts +101 -0
  105. package/dist/charts/FunnelChart/FunnelChart.js +147 -0
  106. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
  107. package/dist/charts/Heatmap/Heatmap.d.ts +78 -0
  108. package/dist/charts/Heatmap/Heatmap.js +108 -0
  109. package/dist/charts/Heatmap/Heatmap.js.map +1 -0
  110. package/dist/charts/Histogram/Histogram.d.ts +165 -0
  111. package/dist/charts/Histogram/Histogram.js +350 -0
  112. package/dist/charts/Histogram/Histogram.js.map +1 -0
  113. package/dist/charts/LineChart/LineChart.d.ts +167 -0
  114. package/dist/charts/LineChart/LineChart.js +486 -0
  115. package/dist/charts/LineChart/LineChart.js.map +1 -0
  116. package/dist/charts/PieChart/PieChart.d.ts +128 -0
  117. package/dist/charts/PieChart/PieChart.js +309 -0
  118. package/dist/charts/PieChart/PieChart.js.map +1 -0
  119. package/dist/charts/RadarChart/RadarChart.d.ts +123 -0
  120. package/dist/charts/RadarChart/RadarChart.js +299 -0
  121. package/dist/charts/RadarChart/RadarChart.js.map +1 -0
  122. package/dist/charts/RadialChart/RadialChart.d.ts +124 -0
  123. package/dist/charts/RadialChart/RadialChart.js +257 -0
  124. package/dist/charts/RadialChart/RadialChart.js.map +1 -0
  125. package/dist/charts/SankeyChart/SankeyChart.d.ts +137 -0
  126. package/dist/charts/SankeyChart/SankeyChart.js +501 -0
  127. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
  128. package/dist/charts/ScatterChart/ScatterChart.d.ts +128 -0
  129. package/dist/charts/ScatterChart/ScatterChart.js +269 -0
  130. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
  131. package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
  132. package/dist/charts/Sparkline/Sparkline.js +93 -0
  133. package/dist/charts/Sparkline/Sparkline.js.map +1 -0
  134. package/dist/charts/TreemapChart/TreemapChart.d.ts +93 -0
  135. package/dist/charts/TreemapChart/TreemapChart.js +118 -0
  136. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
  137. package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
  138. package/dist/charts/WaterfallChart/WaterfallChart.js +319 -0
  139. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
  140. package/dist/charts/index.d.ts +41 -0
  141. package/dist/charts/index.js +128 -0
  142. package/dist/charts/index.js.map +1 -0
  143. package/dist/charts/lib/annotations.d.ts +103 -0
  144. package/dist/charts/lib/annotations.js +99 -0
  145. package/dist/charts/lib/annotations.js.map +1 -0
  146. package/dist/charts/lib/axis.d.ts +18 -0
  147. package/dist/charts/lib/axis.js +21 -0
  148. package/dist/charts/lib/axis.js.map +1 -0
  149. package/dist/charts/lib/background.d.ts +33 -0
  150. package/dist/charts/lib/background.js +173 -0
  151. package/dist/charts/lib/background.js.map +1 -0
  152. package/dist/charts/lib/brush.d.ts +94 -0
  153. package/dist/charts/lib/brush.js +535 -0
  154. package/dist/charts/lib/brush.js.map +1 -0
  155. package/dist/charts/lib/chart.d.ts +94 -0
  156. package/dist/charts/lib/chart.js +134 -0
  157. package/dist/charts/lib/chart.js.map +1 -0
  158. package/dist/charts/lib/dot.d.ts +29 -0
  159. package/dist/charts/lib/dot.js +78 -0
  160. package/dist/charts/lib/dot.js.map +1 -0
  161. package/dist/charts/lib/empty.d.ts +31 -0
  162. package/dist/charts/lib/empty.js +13 -0
  163. package/dist/charts/lib/empty.js.map +1 -0
  164. package/dist/charts/lib/export.d.ts +103 -0
  165. package/dist/charts/lib/export.js +204 -0
  166. package/dist/charts/lib/export.js.map +1 -0
  167. package/dist/charts/lib/figure.d.ts +61 -0
  168. package/dist/charts/lib/figure.js +59 -0
  169. package/dist/charts/lib/figure.js.map +1 -0
  170. package/dist/charts/lib/format.d.ts +46 -0
  171. package/dist/charts/lib/format.js +56 -0
  172. package/dist/charts/lib/format.js.map +1 -0
  173. package/dist/charts/lib/legend.d.ts +45 -0
  174. package/dist/charts/lib/legend.js +117 -0
  175. package/dist/charts/lib/legend.js.map +1 -0
  176. package/dist/charts/lib/loading.d.ts +48 -0
  177. package/dist/charts/lib/loading.js +105 -0
  178. package/dist/charts/lib/loading.js.map +1 -0
  179. package/dist/charts/lib/paint.d.ts +154 -0
  180. package/dist/charts/lib/paint.js +551 -0
  181. package/dist/charts/lib/paint.js.map +1 -0
  182. package/dist/charts/lib/sonify-control.d.ts +163 -0
  183. package/dist/charts/lib/sonify-control.js +172 -0
  184. package/dist/charts/lib/sonify-control.js.map +1 -0
  185. package/dist/charts/lib/sonify.d.ts +248 -0
  186. package/dist/charts/lib/sonify.js +262 -0
  187. package/dist/charts/lib/sonify.js.map +1 -0
  188. package/dist/charts/lib/toolbar.d.ts +143 -0
  189. package/dist/charts/lib/toolbar.js +156 -0
  190. package/dist/charts/lib/toolbar.js.map +1 -0
  191. package/dist/charts/lib/tooltip.d.ts +59 -0
  192. package/dist/charts/lib/tooltip.js +135 -0
  193. package/dist/charts/lib/tooltip.js.map +1 -0
  194. package/dist/charts/lib/values.d.ts +56 -0
  195. package/dist/charts/lib/values.js +71 -0
  196. package/dist/charts/lib/values.js.map +1 -0
  197. package/dist/charts/lib/zoom.d.ts +139 -0
  198. package/dist/charts/lib/zoom.js +314 -0
  199. package/dist/charts/lib/zoom.js.map +1 -0
  200. package/dist/semantic.css +19 -0
  201. package/dist/styles.css +1 -1
  202. package/dist/themes.css +50 -0
  203. package/dist/tokens.css +118 -0
  204. package/dist/tokens.d.ts +17 -0
  205. package/dist/tokens.js +101 -0
  206. package/dist/tokens.json +101 -0
  207. package/package.json +26 -4
  208. package/skills/misoto22-design/SKILL.md +171 -0
  209. package/skills/misoto22-design/evals/claims.json +95 -0
  210. package/skills/misoto22-design/rules/a11y.md +115 -0
  211. package/skills/misoto22-design/rules/composition.md +108 -0
  212. package/skills/misoto22-design/rules/forms.md +128 -0
  213. package/skills/misoto22-design/rules/naming.md +155 -0
  214. package/skills/misoto22-design/rules/tokens.md +131 -0
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @misoto22/design
2
+
3
+ A monochrome design system for software, writing and photography: portable CSS
4
+ tokens and accessible React 19 primitives. Paper ground, near-black mark, and
5
+ status is the only chroma in the file.
6
+
7
+ Components ship compiled — you import them, you do not copy them into your
8
+ project.
9
+
10
+ **[ui.misoto22.com](https://ui.misoto22.com)** · [Changelog](./CHANGELOG.md)
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @misoto22/design
16
+ ```
17
+
18
+ ```tsx
19
+ import { Button, Field, Input } from '@misoto22/design'
20
+ import '@misoto22/design/styles.css'
21
+ ```
22
+
23
+ `styles.css` is the whole compiled sheet — tokens, roles, motion and the
24
+ vendored faces. An app that compiles its own Tailwind can take the portable
25
+ layers instead:
26
+
27
+ ```tsx
28
+ import '@misoto22/design/tokens.css' // primitives
29
+ import '@misoto22/design/semantic.css' // roles
30
+ import '@misoto22/design/keyframes.css' // motion
31
+ ```
32
+
33
+ ## Theming
34
+
35
+ Seven independent axes, each an attribute, each working on **any** element
36
+ rather than only on the root. An unset axis is the default.
37
+
38
+ | Attribute | Values |
39
+ | --- | --- |
40
+ | `data-mode` | `light` `dark` |
41
+ | `data-surface` | `warm` `cool` `glass` |
42
+ | `data-radius` | `sharp` `round` |
43
+ | `data-rules` | `quiet` `firm` |
44
+ | `data-type` | `grotesk` `bookish` |
45
+ | `data-motion` | `still` `snappy` |
46
+ | `data-density` | `compact` |
47
+
48
+ ```tsx
49
+ <section data-surface="warm" data-radius="sharp">…</section>
50
+ ```
51
+
52
+ No component reads any of them, and none of them introduces a token. To
53
+ re-accent the system, re-point one custom property:
54
+
55
+ ```css
56
+ :root { --accent: var(--ok); }
57
+ ```
58
+
59
+ ## For agents
60
+
61
+ This package is documented for the reader that installed it, not only for the
62
+ one that can open a browser — and the two need different things. Everything
63
+ below is generated from the source in this same tarball, so it describes the
64
+ version you actually have rather than whatever the website shipped last.
65
+
66
+ **One component, in full** — every prop with its type and default, the exported
67
+ unions, the keyboard contract, the accessibility promises, the examples:
68
+
69
+ ```bash
70
+ npx misoto22-design docs Button
71
+ ```
72
+
73
+ The median component is about 500 tokens. It resolves parts and types too, so
74
+ `docs CardBody`, `docs TH` and `docs ButtonVariant` all land on the right file —
75
+ useful when an import just failed.
76
+
77
+ **What is installed here**, as a few hundred tokens rather than fifty prop
78
+ tables:
79
+
80
+ ```bash
81
+ npx misoto22-design docs --installed
82
+ ```
83
+
84
+ **Install the skill** into your project, so a coding agent picks up the
85
+ conventions without being told each time:
86
+
87
+ ```bash
88
+ npx misoto22-design init --agents-md
89
+ ```
90
+
91
+ That writes `.claude/skills/misoto22-design/` and points your `AGENTS.md` at it.
92
+ The skill is progressive: its name and description are about 110 tokens and are
93
+ all that sits in a session until something actually touches this package. The
94
+ body is around 2,200, and the five rule files load one at a time, only when the
95
+ work reaches them.
96
+
97
+ The names diverge from shadcn/ui in a handful of places that a model writing
98
+ from habit gets wrong — `CardBody` not `CardContent`, `THead`/`TBody`/`TR`/`TH`/`TD`
99
+ not `TableHeader`/…, and `title` as a prop on `DialogContent` rather than a
100
+ `DialogTitle` child. The skill leads with that table, and
101
+ `src/__tests__/skill.test.ts` fails the build if any of it stops being true.
102
+
103
+ On the web, the same content is at
104
+ [`/llms.txt`](https://ui.misoto22.com/llms.txt) (index),
105
+ [`/llms-full.txt`](https://ui.misoto22.com/llms-full.txt) (everything inline),
106
+ and `/components/<slug>/llms.txt` (one component).
107
+
108
+ ## Accessibility
109
+
110
+ Every component is tested against `axe-core` best-practice rules, keyboard
111
+ contracts are asserted key by key, and a prop that is required for
112
+ accessibility is required in the type — `Table.caption`, `Progress.label`,
113
+ `Avatar.alt`, `FloatingIconButton.label`. If it can be forgotten, it will be.
114
+
115
+ Logical properties throughout, so the system is RTL-correct; motion is gated
116
+ behind `prefers-reduced-motion`.
117
+
118
+ ## Requirements
119
+
120
+ React 19, Node 24+. ESM only.
121
+
122
+ ## Licence
123
+
124
+ MIT © Henry Chen
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The package's own documentation, for the reader that installed it.
4
+ *
5
+ * A website is the wrong source for an agent writing against a pinned version:
6
+ * it documents whatever shipped last, the agent is holding whatever is in
7
+ * `node_modules`, and neither side can see the disagreement. Everything printed
8
+ * here is generated at build time from the source in the same tarball, so the
9
+ * answer is always about the version actually installed.
10
+ *
11
+ * It is also the cheap half of the deal. `docs --installed` is a few hundred
12
+ * tokens and says what exists; `docs <Component>` is under a thousand and says
13
+ * everything about one of them. The alternative an agent reaches for otherwise
14
+ * is the whole of `llms-full.txt`, which is fifty times that and mostly about
15
+ * components it is not using.
16
+ */
17
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
18
+ import { dirname, join, resolve } from 'node:path'
19
+ import { fileURLToPath } from 'node:url'
20
+
21
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
22
+ const AGENT = join(ROOT, 'dist', 'agent')
23
+ const SKILL = join(ROOT, 'skills', 'misoto22-design')
24
+
25
+ const { version } = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'))
26
+
27
+ const USAGE = `@misoto22/design ${version}
28
+
29
+ misoto22-design docs <Component> One component, in full — props, types,
30
+ keyboard, accessibility, examples.
31
+ misoto22-design docs --list Every component, one line each.
32
+ misoto22-design docs --installed This package's version and what it ships.
33
+ [--json]
34
+ misoto22-design init [--agents-md] Install the agent skill into this project
35
+ under .claude/skills/, and optionally
36
+ point AGENTS.md at it.
37
+
38
+ Docs on the web: https://ui.misoto22.com`
39
+
40
+ function fail(message) {
41
+ process.stderr.write(`${message}\n`)
42
+ process.exit(1)
43
+ }
44
+
45
+ /** The emitted docs are a build artifact; a source checkout may not have them. */
46
+ function requireBuilt() {
47
+ if (!existsSync(AGENT)) {
48
+ fail(
49
+ 'No generated docs found. This package ships them in dist/agent/;\n' +
50
+ 'in a source checkout, run `pnpm build:agent` first.',
51
+ )
52
+ }
53
+ }
54
+
55
+ function componentNames() {
56
+ return readdirSync(AGENT)
57
+ .filter((file) => file.endsWith('.md') && file !== 'index.md')
58
+ .map((file) => file.replace(/\.md$/, ''))
59
+ .sort()
60
+ }
61
+
62
+ function catalog() {
63
+ return JSON.parse(readFileSync(join(AGENT, 'catalog.json'), 'utf8'))
64
+ }
65
+
66
+ /**
67
+ * What a skill injects at the top of a session: the version in this project and
68
+ * the names it can ask about. Deliberately names-only — the point is that the
69
+ * agent then fetches the one component it needs, rather than being handed all
70
+ * fifty-two prop tables it does not.
71
+ */
72
+ function installed(asJson) {
73
+ requireBuilt()
74
+ const { groups, components } = catalog()
75
+ if (asJson) {
76
+ const byGroup = Object.fromEntries(
77
+ groups
78
+ .map((group) => [group, components.filter((c) => c.group === group).map((c) => c.name)])
79
+ .filter(([, names]) => names.length > 0),
80
+ )
81
+ process.stdout.write(
82
+ `${JSON.stringify(
83
+ {
84
+ package: '@misoto22/design',
85
+ version,
86
+ components: byGroup,
87
+ styles: [
88
+ '@misoto22/design/styles.css',
89
+ '@misoto22/design/tokens.css',
90
+ '@misoto22/design/semantic.css',
91
+ '@misoto22/design/keyframes.css',
92
+ ],
93
+ detail: 'npx misoto22-design docs <Component>',
94
+ },
95
+ null,
96
+ 2,
97
+ )}\n`,
98
+ )
99
+ return
100
+ }
101
+ const lines = [`@misoto22/design ${version} — ${components.length} components`, '']
102
+ for (const group of groups) {
103
+ const names = components.filter((c) => c.group === group).map((c) => c.name)
104
+ if (names.length > 0) lines.push(`${group}: ${names.join(', ')}`)
105
+ }
106
+ lines.push('', 'One in full: npx misoto22-design docs <Component>')
107
+ process.stdout.write(`${lines.join('\n')}\n`)
108
+ }
109
+
110
+ function docs(args) {
111
+ if (args.includes('--installed')) return installed(args.includes('--json'))
112
+ requireBuilt()
113
+ if (args.includes('--list')) {
114
+ process.stdout.write(readFileSync(join(AGENT, 'index.md'), 'utf8'))
115
+ return
116
+ }
117
+
118
+ const name = args.find((arg) => !arg.startsWith('-'))
119
+ if (!name) fail(`Which component? Try one of:\n\n ${componentNames().join(', ')}`)
120
+
121
+ // What the caller holds is usually the identifier it just failed to import —
122
+ // a part (`CardBody`, `TH`) or a type (`ButtonVariant`) rather than the
123
+ // component that owns it. Resolve those rather than making it guess again.
124
+ const owner = catalog().exports?.[name]
125
+ const file = join(AGENT, `${owner ?? name}.md`)
126
+ if (existsSync(file)) {
127
+ if (owner && owner !== name) {
128
+ process.stderr.write(`\`${name}\` is part of ${owner}.\n`)
129
+ }
130
+ process.stdout.write(readFileSync(file, 'utf8'))
131
+ return
132
+ }
133
+
134
+ // A miss is usually a near miss — a habit from another library, or a part
135
+ // name rather than the component that owns it. Say what exists instead.
136
+ const wanted = name.toLowerCase()
137
+ const near = componentNames().filter(
138
+ (candidate) =>
139
+ candidate.toLowerCase().startsWith(wanted.slice(0, 3)) ||
140
+ wanted.startsWith(candidate.toLowerCase()),
141
+ )
142
+ fail(
143
+ near.length > 0
144
+ ? `No component named "${name}". Did you mean: ${near.join(', ')}?`
145
+ : `No component named "${name}". Run \`misoto22-design docs --list\` for all ${componentNames().length}.`,
146
+ )
147
+ }
148
+
149
+ const AGENTS_BLOCK = `
150
+ ## @misoto22/design
151
+
152
+ UI comes from \`@misoto22/design\`. Read \`.claude/skills/misoto22-design/SKILL.md\`
153
+ before writing components against it — the names diverge from shadcn/ui in
154
+ several places, and colour is never written as a raw class.
155
+
156
+ - One component in full: \`npx misoto22-design docs <Component>\`
157
+ - Everything it ships: \`npx misoto22-design docs --installed\`
158
+ `
159
+
160
+ function init(args) {
161
+ const target = join(process.cwd(), '.claude', 'skills', 'misoto22-design')
162
+ if (!existsSync(SKILL)) fail('This build has no skills/ directory.')
163
+
164
+ const existed = existsSync(target)
165
+ mkdirSync(dirname(target), { recursive: true })
166
+ cpSync(SKILL, target, { recursive: true })
167
+ process.stdout.write(
168
+ `${existed ? 'Updated' : 'Installed'} the skill at ${resolve(target)}\n`,
169
+ )
170
+
171
+ if (!args.includes('--agents-md')) {
172
+ process.stdout.write('Pass --agents-md to also point AGENTS.md at it.\n')
173
+ return
174
+ }
175
+
176
+ const agentsFile = join(process.cwd(), 'AGENTS.md')
177
+ const current = existsSync(agentsFile) ? readFileSync(agentsFile, 'utf8') : '# AGENTS.md\n'
178
+ if (current.includes('@misoto22/design')) {
179
+ process.stdout.write('AGENTS.md already mentions the package; left alone.\n')
180
+ return
181
+ }
182
+ writeFileSync(agentsFile, `${current.trimEnd()}\n${AGENTS_BLOCK}`)
183
+ process.stdout.write(`Appended a section to ${resolve(agentsFile)}\n`)
184
+ }
185
+
186
+ const [command, ...args] = process.argv.slice(2)
187
+ switch (command) {
188
+ case 'docs':
189
+ docs(args)
190
+ break
191
+ case 'init':
192
+ init(args)
193
+ break
194
+ case undefined:
195
+ case '--help':
196
+ case '-h':
197
+ process.stdout.write(`${USAGE}\n`)
198
+ break
199
+ case '--version':
200
+ case '-v':
201
+ process.stdout.write(`${version}\n`)
202
+ break
203
+ default:
204
+ fail(`Unknown command "${command}".\n\n${USAGE}`)
205
+ }
@@ -0,0 +1,41 @@
1
+ # Accordion
2
+
3
+ Disclosure rows that open in place.
4
+
5
+ - Group: Navigation
6
+ - Import: `import { Accordion } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/accordion/
9
+ - Related: tabs
10
+
11
+ ## When to reach for it
12
+
13
+ The marker is a plus, not a chevron: a plus says “this opens”, a chevron says “there is more below”.
14
+
15
+ ## Keyboard
16
+
17
+ - Tab — Moves between rows.
18
+ - Enter / Space — Opens or closes the focused row.
19
+
20
+ ## Accordion
21
+
22
+ Radix root, re-exported. Pass `type="single" collapsible` for an FAQ and `type="multiple"` for a settings stack; Radix's own discriminated union then types `value` correctly for each.
23
+
24
+ ## AccordionItem
25
+
26
+ One disclosure row: a hairline-ruled trigger and its panel. The marker is a plus that rotates into a minus, not a chevron. A chevron says "there is more below"; a plus says "this opens" — and in a stack of rows the difference decides whether the reader expects navigation or expansion. The panel animates on Radix's own `--radix-accordion-content-height`, so it opens to its real height without measuring anything at the call site.
27
+
28
+ ### Props
29
+
30
+ - `title` (required) — `ReactNode`. The row's summary — what the reader clicks. Named `title` rather than inherited from the DOM attribute of the same name, which is a tooltip.
31
+ - `children` (required) — `ReactNode`.
32
+
33
+ Also accepts: `Omit<ComponentProps<typeof AccordionPrimitive.Item>, 'children' | 'title'>`.
34
+
35
+ ## Examples
36
+
37
+ ```tsx
38
+ <Accordion type="single" collapsible>
39
+ <AccordionItem value="ship" title="How do I ship it?">Push to main.</AccordionItem>
40
+ </Accordion>
41
+ ```
@@ -0,0 +1,42 @@
1
+ # Alert
2
+
3
+ A message about the page, in place.
4
+
5
+ - Group: Feedback
6
+ - Import: `import { Alert } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/alert/
9
+ - Related: toast, error-state
10
+
11
+ ## When to reach for it
12
+
13
+ Something the reader needs to see and may need to act on. Something they only need to notice is a Toast.
14
+
15
+ ## Accessibility
16
+
17
+ - danger is role="alert" and interrupts; the other three are role="status" and wait for a pause.
18
+ - Colour is doubled by an icon and by the words.
19
+
20
+ ## Alert
21
+
22
+ A message about the page, in place. Carries `role="alert"` for the danger tone and `role="status"` for the rest, which is the difference between interrupting the reader and waiting for a pause. Getting that backwards is the usual accessibility failure here: a "saved" toast that talks over someone mid-sentence, or a payment error that is never announced at all. The tone is the message's SEVERITY, not its decoration. Colour is doubled by an icon and by the words, so the meaning survives both monochrome printing and colour-blindness.
23
+
24
+ ### Props
25
+
26
+ - `tone` — `AlertTone` default `'info'`.
27
+ - `title` — `ReactNode`.
28
+ - `children` — `ReactNode`.
29
+ - `action` — `ReactNode`. Optional action — a retry, a link to the settings that fix this.
30
+ - `hideIcon` — `boolean` default `false`. Hides the leading icon for a dense inline notice.
31
+
32
+ Also accepts: `Omit<HTMLAttributes<HTMLDivElement>, 'title'>`.
33
+
34
+ ## Types
35
+
36
+ - `AlertTone` = `'info' | 'success' | 'warning' | 'danger'`
37
+
38
+ ## Examples
39
+
40
+ ```tsx
41
+ <Alert tone="danger" title="Upload failed">The file exceeds 25 MB.</Alert>
42
+ ```
@@ -0,0 +1,40 @@
1
+ # AppShell
2
+
3
+ Two columns on a desktop, a drawer on a phone.
4
+
5
+ - Group: Surfaces
6
+ - Import: `import { AppShell } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/app-shell/
9
+ - Related: nav-item
10
+
11
+ ## Accessibility
12
+
13
+ - The drawer closes on Escape as well as on the scrim, so a keyboard user is not stranded inside it.
14
+ - The scrim is a <button>, because a div with an onClick is neither reachable nor announced.
15
+
16
+ ## AppShell
17
+
18
+ Two columns on a desktop, one column and a drawer on a phone. The drawer closes on Escape as well as on the scrim, because a drawer that only closes by tapping outside it strands a keyboard user inside a menu they cannot leave. The scrim is a `<button>` for the same reason — a `<div>` with an `onClick` is not reachable by keyboard and not announced as anything.
19
+
20
+ ### Props
21
+
22
+ - `sidebar` (required) — `ReactNode`. Navigation content for the sidebar (e.g. a stack of `NavItem`s).
23
+ - `topbar` — `ReactNode`. Optional content for the sticky topbar, laid out after the mobile toggle.
24
+ - `brand` — `ReactNode`. Optional brand lockup pinned to the top of the sidebar.
25
+ - `contentAs` — `'main' | 'div'`. Which element the content well renders as. `main` is right for the shell of an application, and is the default. A document may contain exactly one `main` landmark, so an AppShell rendered INSIDE another page — a preview on a documentation site, a screenshot harness — must pass `div`, or the page has two and assistive tech can no longer answer "where is the content".
26
+ - `sidebarLabel` — `string` default `'Sidebar'`. Names the sidebar landmark. Two `complementary` landmarks with the same name cannot be told apart, and a shell rendered inside another page — a preview, a screenshot harness — makes exactly that pair. It is also the only way a non-English app gets a landmark name its readers can read.
27
+ - `navLabel` — `string` default `'Primary'`. Names the navigation landmark inside the sidebar.
28
+ - `openLabel` — `string` default `'Open navigation'`. The drawer toggle, closed and open.
29
+ - `closeLabel` — `string` default `'Close navigation'`.
30
+ - `children` (required) — `ReactNode`.
31
+
32
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
33
+
34
+ ## Examples
35
+
36
+ ```tsx
37
+ <AppShell brand={<Wordmark />} sidebar={<NavItem href="/">Home</NavItem>}>
38
+ <Card>…</Card>
39
+ </AppShell>
40
+ ```
@@ -0,0 +1,68 @@
1
+ # AreaChart
2
+
3
+ A filled series over a continuous axis, where the area means something.
4
+
5
+ - Group: Charts
6
+ - Import: `import { AreaChart } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/area-chart/
9
+ - Related: line-chart, bar-chart, composed-chart
10
+
11
+ ## When to reach for it
12
+
13
+ Reading one magnitude over time. Comparing several series against each other is a LineChart — four translucent fills stacked on each other answer neither question.
14
+
15
+ ## Accessibility
16
+
17
+ - title is required and becomes the figure’s accessible name, printed or not.
18
+ - The rows are rendered again as a visually hidden table, so the numbers are reachable rather than only drawn. hideDataTable opts out when the page already prints them.
19
+ - Six fill variants exist because in the monochrome default TEXTURE is the primary carrier of identity and the grey ramp is the second — which is also what keeps two series apart in greyscale print and under forced colours.
20
+ - The intro reveal is a per-frame SVG mask and is dropped entirely under prefers-reduced-motion, as is the crawling dash.
21
+
22
+ ## Keyboard
23
+
24
+ - Tab — Reaches the plot, which Recharts’ accessibility layer makes navigable.
25
+ - ← / → — Moves the cursor between points, announcing each.
26
+
27
+ ## AreaChart
28
+
29
+ A filled series over a category axis — the shape for a magnitude that is continuous, where the area under the line means something. Composed rather than configured: axes, grid, tooltip, legend and the areas themselves are children, so a chart renders exactly the parts it asked for and nothing is switched on by a prop nobody can see. Reach for `<LineChart>` instead when the reader is comparing several series against each other rather than reading one total, and for `<BarChart>` when the categories are discrete.
30
+
31
+ ### Props
32
+
33
+ - `config` (required) — `TConfig & ValidateKeys<TData, TConfig>`. Series keys → their label and paint. Declaration order is ramp order.
34
+ - `data` (required) — `TData[]`. The rows the chart draws. One entry per point, bar or category.
35
+ - `title` (required) — `string`. What the chart shows, in a sentence a reader could act on. Required, and announced to a screen reader even when it is not printed.
36
+ - `showTitle` — `boolean`. Prints the title above the plot instead of hiding it from sight.
37
+ - `description` — `ReactNode`. A line under the title — the unit, the window, the caveat.
38
+ - `children` (required) — `ReactNode`. The composed parts — axes, grid, tooltip, legend, and the marks themselves.
39
+ - `className` — `string`. Merged onto the figure, last, so a call site can size or space it.
40
+ - `chartProps` — `ComponentProps<typeof RechartsAreaChart>`. Escape hatch onto the raw Recharts chart element.
41
+ - `curveType` — `ChartCurveType` default `'linear'`. The curve every `<AreaChart.Area>` inherits.
42
+ - `animationType` — `ChartRevealType` default `'forward'`. The intro wipe every `<AreaChart.Area>` inherits.
43
+ - `stackType` — `AreaStackType` default `'default'`. How several marks combine: side by side, stacked, or normalised to 100%.
44
+ - `defaultSelectedDataKey` — `string | null` default `null`. The series lit on first render. Selection dims every other series.
45
+ - `onSelectionChange` — `(selectedDataKey: string | null) => void`. Fires when the selection changes, and with null when it is cleared.
46
+ - `isLoading` — `boolean` default `false`. Swaps the marks for an animated skeleton, keeping the measured height so the page does not jump when the data lands.
47
+ - `loadingPoints` — `number`. How many points the skeleton draws.
48
+ - `xDataKey` — `keyof TData & string`. The row field on the category axis. Needed by the brush and by the table view.
49
+ - `hideDataTable` — `boolean` default `false`. Drops the hidden table view. Only correct when the page prints the data itself.
50
+ - `empty` — `ChartEmptyProps | false`. What the chart shows when it has nothing to draw. Rendered instead of the plot whenever `data` is empty and the chart is not loading — the state a real dashboard reaches within a week, and the one an empty pair of axes is indistinguishable from a failed load. `false` keeps the axes, for a chart whose emptiness is itself the reading.
51
+
52
+ ## Types
53
+
54
+ - `ChartCurveType` = `ComponentProps<typeof RechartsArea>['type']`
55
+ - `AreaVariant` = `'gradient' | 'gradient-reverse' | 'solid' | 'dotted' | 'lines' | 'hatched'`
56
+ - `AreaStrokeVariant` = `'solid' | 'dashed' | 'animated-dashed'`
57
+ - `AreaStackType` = `'default' | 'stacked' | 'expanded'`
58
+
59
+ ## Examples
60
+
61
+ ```tsx
62
+ <AreaChart title="Visitors per month" config={config} data={data} xDataKey="month">
63
+ <AreaChart.Grid />
64
+ <AreaChart.XAxis dataKey="month" />
65
+ <AreaChart.Tooltip />
66
+ <AreaChart.Area dataKey="desktop" variant="gradient" />
67
+ </AreaChart>
68
+ ```
@@ -0,0 +1,41 @@
1
+ # Article
2
+
3
+ The long-form reading surface — everything a Markdown pipeline emits, in this system’s type.
4
+
5
+ - Group: Surfaces
6
+ - Import: `import { Article } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/article/
9
+ - Related: diagram, card
10
+
11
+ ## When to reach for it
12
+
13
+ A post, a changelog entry, a document. Not for interface copy: a paragraph inside a card is a paragraph, and this is a whole reading column with its own rhythm.
14
+
15
+ ## Accessibility
16
+
17
+ - An <article> by default, so the piece is a landmark a reader can jump to.
18
+ - Every heading carries scroll-margin, so an anchored link does not park the heading under a fixed masthead.
19
+ - The styles are element selectors at low specificity, so a component dropped inside keeps its own.
20
+
21
+ ## Article
22
+
23
+ The long-form reading surface. Everything a Markdown pipeline can emit — headings, prose, lists, tables, quotations, code, figures, footnotes, MathML — set in this system's type, colour and rules. The styles live in `article.css` rather than in a class string, because the input is not JSX: there is no component to hang a class on when the markup arrived as a string, so the contract has to be the element names themselves. That file is published on its own as `@misoto22/design/article.css`, so a site with its own Markdown pipeline can take the reading surface without taking the components — which is the case this exists for. Three sites hand-rolling a prose stylesheet is three prose stylesheets that drift. Composable either way: pass `html` for a rendered string, or children for real elements. A post that mixes the two — prose with a `Diagram` dropped into the middle — renders its blocks in order and gives each one an `Article`; a component inside keeps its own classes, because every rule in the layer is a bare element selector that a utility outranks.
24
+
25
+ ### Props
26
+
27
+ - `html` — `string`. Rendered HTML from a Markdown or MDX pipeline. Trusted markup only. This sets `dangerouslySetInnerHTML`, so it must come from content you control — a repository's own posts, a CMS you author — and never from a reader. Untrusted Markdown has to be sanitised before it reaches here; that is a pipeline decision, not a component one, and a sanitiser bolted on inside a styling primitive would be the wrong place to make it and the easiest place to get it wrong.
28
+ - `as` — `'article' | 'div' | 'section'`. The element to render. `article` by default; pass `div` for a fragment.
29
+
30
+ Also accepts: `HTMLAttributes<HTMLElement>`.
31
+
32
+ ## Examples
33
+
34
+ ```tsx
35
+ <Article html={renderedMarkdown} />
36
+ <Article>
37
+ <h1>The White Reset</h1>
38
+ <p className="lead">A monochrome system for software and writing.</p>
39
+ <Diagram spec={spec} />
40
+ </Article>
41
+ ```
@@ -0,0 +1,32 @@
1
+ # Avatar
2
+
3
+ A person, as a circle, with initials until the image lands.
4
+
5
+ - Group: Display
6
+ - Import: `import { Avatar } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/avatar/
9
+
10
+ ## Accessibility
11
+
12
+ - alt describes the person, not the picture. An empty string is correct when the name is already printed beside it.
13
+ - The initials are aria-hidden — read aloud they are noise.
14
+
15
+ ## Avatar
16
+
17
+ A person, as a circle. Wraps Radix so the fallback appears only after the image has actually failed or is still loading — a hand-rolled `onError` swap flashes the initials on every render before the cache answers.
18
+
19
+ ### Props
20
+
21
+ - `src` — `string`.
22
+ - `alt` (required) — `string`. Describes the person, not the picture. Empty string is correct and deliberate when the name is already printed beside the avatar — repeating it makes a screen reader say it twice.
23
+ - `fallback` (required) — `string`. Shown while the image loads and if it never does. Usually initials.
24
+ - `size` — `'sm' | 'md' | 'lg'` default `'md'`.
25
+
26
+ Also accepts: `Omit<ComponentProps<typeof AvatarPrimitive.Root>, 'children'>`.
27
+
28
+ ## Examples
29
+
30
+ ```tsx
31
+ <Avatar src={user.photo} alt={user.name} fallback="HC" />
32
+ ```
@@ -0,0 +1,40 @@
1
+ # Badge
2
+
3
+ A count or a state, set in mono so it reads as metadata.
4
+
5
+ - Group: Display
6
+ - Import: `import { Badge } from '@misoto22/design'`
7
+ - Version: 0.6.0
8
+ - Docs: https://ui.misoto22.com/components/badge/
9
+ - Related: tag, status-pill
10
+
11
+ ## When to reach for it
12
+
13
+ One fact about one record. If it names what something is ABOUT, that is a Tag.
14
+
15
+ ## Accessibility
16
+
17
+ - Not interactive. A badge with an onClick is a control a keyboard cannot reach.
18
+ - The status tones double their colour with words, so the meaning survives monochrome and colour-blindness.
19
+
20
+ ## Badge
21
+
22
+ A count, a state, a small inline marker. Mono and small, so it reads as metadata rather than as content. A badge is not interactive — if it can be clicked or dismissed it is a `Tag` or a button, and giving this one an `onClick` produces a control a keyboard cannot reach.
23
+
24
+ ### Props
25
+
26
+ - `children` (required) — `ReactNode`.
27
+ - `tone` — `BadgeTone` default `'neutral'`. `neutral` is the default and the right answer nearly always. The three status tones are the system's only chroma and are bound to STATE — a badge that is red because the design wanted a red badge is the thing this scale exists to prevent.
28
+
29
+ Also accepts: `HTMLAttributes<HTMLSpanElement>`.
30
+
31
+ ## Types
32
+
33
+ - `BadgeTone` = `'neutral' | 'success' | 'warning' | 'danger' | 'outline'`
34
+
35
+ ## Examples
36
+
37
+ ```tsx
38
+ <Badge>12</Badge>
39
+ <Badge tone="success">Deployed</Badge>
40
+ ```