@misoto22/design 0.3.1 → 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.
- package/README.md +124 -0
- package/bin/misoto22-design.mjs +205 -0
- package/dist/agent/Accordion.md +41 -0
- package/dist/agent/Alert.md +42 -0
- package/dist/agent/AppShell.md +40 -0
- package/dist/agent/AreaChart.md +68 -0
- package/dist/agent/Article.md +41 -0
- package/dist/agent/Avatar.md +32 -0
- package/dist/agent/Badge.md +40 -0
- package/dist/agent/BarChart.md +65 -0
- package/dist/agent/BarList.md +40 -0
- package/dist/agent/BigNumber.md +45 -0
- package/dist/agent/BoxPlot.md +58 -0
- package/dist/agent/Breadcrumb.md +32 -0
- package/dist/agent/BulletChart.md +48 -0
- package/dist/agent/Button.md +56 -0
- package/dist/agent/Calendar.md +42 -0
- package/dist/agent/Card.md +49 -0
- package/dist/agent/Checkbox.md +35 -0
- package/dist/agent/Collapsible.md +46 -0
- package/dist/agent/Combobox.md +50 -0
- package/dist/agent/Command.md +93 -0
- package/dist/agent/ComposedChart.md +57 -0
- package/dist/agent/ContextMenu.md +59 -0
- package/dist/agent/DatePicker.md +75 -0
- package/dist/agent/Diagram.md +46 -0
- package/dist/agent/Dialog.md +52 -0
- package/dist/agent/DropdownMenu.md +70 -0
- package/dist/agent/EmptyState.md +37 -0
- package/dist/agent/ErrorState.md +41 -0
- package/dist/agent/Facet.md +82 -0
- package/dist/agent/Field.md +37 -0
- package/dist/agent/FigureBand.md +37 -0
- package/dist/agent/FloatingIconButton.md +38 -0
- package/dist/agent/FunnelChart.md +52 -0
- package/dist/agent/Heatmap.md +53 -0
- package/dist/agent/Histogram.md +63 -0
- package/dist/agent/Input.md +30 -0
- package/dist/agent/Kbd.md +29 -0
- package/dist/agent/LineChart.md +60 -0
- package/dist/agent/LinkArrow.md +29 -0
- package/dist/agent/NativeSelect.md +40 -0
- package/dist/agent/NavItem.md +35 -0
- package/dist/agent/Pagination.md +43 -0
- package/dist/agent/PieChart.md +55 -0
- package/dist/agent/Popover.md +57 -0
- package/dist/agent/Progress.md +33 -0
- package/dist/agent/RadarChart.md +54 -0
- package/dist/agent/RadialChart.md +57 -0
- package/dist/agent/RadioGroup.md +44 -0
- package/dist/agent/SankeyChart.md +61 -0
- package/dist/agent/ScatterChart.md +54 -0
- package/dist/agent/ScrollArea.md +40 -0
- package/dist/agent/SearchableMenu.md +46 -0
- package/dist/agent/Select.md +75 -0
- package/dist/agent/Separator.md +35 -0
- package/dist/agent/Sheet.md +57 -0
- package/dist/agent/Skeleton.md +73 -0
- package/dist/agent/Slider.md +39 -0
- package/dist/agent/Sparkline.md +45 -0
- package/dist/agent/Spinner.md +39 -0
- package/dist/agent/StatusDot.md +36 -0
- package/dist/agent/StatusPill.md +28 -0
- package/dist/agent/Steps.md +44 -0
- package/dist/agent/Switch.md +29 -0
- package/dist/agent/Table.md +85 -0
- package/dist/agent/Tabs.md +48 -0
- package/dist/agent/Tag.md +35 -0
- package/dist/agent/Textarea.md +26 -0
- package/dist/agent/Toast.md +26 -0
- package/dist/agent/ToggleGroup.md +44 -0
- package/dist/agent/Tooltip.md +51 -0
- package/dist/agent/TreemapChart.md +52 -0
- package/dist/agent/WaterfallChart.md +62 -0
- package/dist/agent/catalog.json +1791 -0
- package/dist/agent/index.md +131 -0
- package/dist/article.css +393 -0
- package/dist/charts/AreaChart/AreaChart.d.ts +191 -0
- package/dist/charts/AreaChart/AreaChart.js +480 -0
- package/dist/charts/AreaChart/AreaChart.js.map +1 -0
- package/dist/charts/BarChart/BarChart.d.ts +179 -0
- package/dist/charts/BarChart/BarChart.js +591 -0
- package/dist/charts/BarChart/BarChart.js.map +1 -0
- package/dist/charts/BarList/BarList.d.ts +57 -0
- package/dist/charts/BarList/BarList.js +71 -0
- package/dist/charts/BarList/BarList.js.map +1 -0
- package/dist/charts/BigNumber/BigNumber.d.ts +56 -0
- package/dist/charts/BigNumber/BigNumber.js +31 -0
- package/dist/charts/BigNumber/BigNumber.js.map +1 -0
- package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
- package/dist/charts/BoxPlot/BoxPlot.js +495 -0
- package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
- package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
- package/dist/charts/BulletChart/BulletChart.js +162 -0
- package/dist/charts/BulletChart/BulletChart.js.map +1 -0
- package/dist/charts/ComposedChart/ComposedChart.d.ts +171 -0
- package/dist/charts/ComposedChart/ComposedChart.js +667 -0
- package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
- package/dist/charts/Facet/Facet.d.ts +240 -0
- package/dist/charts/Facet/Facet.js +133 -0
- package/dist/charts/Facet/Facet.js.map +1 -0
- package/dist/charts/Facet/panels.d.ts +187 -0
- package/dist/charts/Facet/panels.js +203 -0
- package/dist/charts/Facet/panels.js.map +1 -0
- package/dist/charts/FunnelChart/FunnelChart.d.ts +101 -0
- package/dist/charts/FunnelChart/FunnelChart.js +147 -0
- package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
- package/dist/charts/Heatmap/Heatmap.d.ts +78 -0
- package/dist/charts/Heatmap/Heatmap.js +108 -0
- package/dist/charts/Heatmap/Heatmap.js.map +1 -0
- package/dist/charts/Histogram/Histogram.d.ts +165 -0
- package/dist/charts/Histogram/Histogram.js +350 -0
- package/dist/charts/Histogram/Histogram.js.map +1 -0
- package/dist/charts/LineChart/LineChart.d.ts +167 -0
- package/dist/charts/LineChart/LineChart.js +486 -0
- package/dist/charts/LineChart/LineChart.js.map +1 -0
- package/dist/charts/PieChart/PieChart.d.ts +128 -0
- package/dist/charts/PieChart/PieChart.js +309 -0
- package/dist/charts/PieChart/PieChart.js.map +1 -0
- package/dist/charts/RadarChart/RadarChart.d.ts +123 -0
- package/dist/charts/RadarChart/RadarChart.js +299 -0
- package/dist/charts/RadarChart/RadarChart.js.map +1 -0
- package/dist/charts/RadialChart/RadialChart.d.ts +124 -0
- package/dist/charts/RadialChart/RadialChart.js +257 -0
- package/dist/charts/RadialChart/RadialChart.js.map +1 -0
- package/dist/charts/SankeyChart/SankeyChart.d.ts +137 -0
- package/dist/charts/SankeyChart/SankeyChart.js +501 -0
- package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
- package/dist/charts/ScatterChart/ScatterChart.d.ts +128 -0
- package/dist/charts/ScatterChart/ScatterChart.js +269 -0
- package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
- package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
- package/dist/charts/Sparkline/Sparkline.js +93 -0
- package/dist/charts/Sparkline/Sparkline.js.map +1 -0
- package/dist/charts/TreemapChart/TreemapChart.d.ts +93 -0
- package/dist/charts/TreemapChart/TreemapChart.js +118 -0
- package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
- package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js +319 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
- package/dist/charts/index.d.ts +41 -0
- package/dist/charts/index.js +128 -0
- package/dist/charts/index.js.map +1 -0
- package/dist/charts/lib/annotations.d.ts +103 -0
- package/dist/charts/lib/annotations.js +99 -0
- package/dist/charts/lib/annotations.js.map +1 -0
- package/dist/charts/lib/axis.d.ts +18 -0
- package/dist/charts/lib/axis.js +21 -0
- package/dist/charts/lib/axis.js.map +1 -0
- package/dist/charts/lib/background.d.ts +33 -0
- package/dist/charts/lib/background.js +173 -0
- package/dist/charts/lib/background.js.map +1 -0
- package/dist/charts/lib/brush.d.ts +94 -0
- package/dist/charts/lib/brush.js +535 -0
- package/dist/charts/lib/brush.js.map +1 -0
- package/dist/charts/lib/chart.d.ts +94 -0
- package/dist/charts/lib/chart.js +134 -0
- package/dist/charts/lib/chart.js.map +1 -0
- package/dist/charts/lib/dot.d.ts +29 -0
- package/dist/charts/lib/dot.js +78 -0
- package/dist/charts/lib/dot.js.map +1 -0
- package/dist/charts/lib/empty.d.ts +31 -0
- package/dist/charts/lib/empty.js +13 -0
- package/dist/charts/lib/empty.js.map +1 -0
- package/dist/charts/lib/export.d.ts +103 -0
- package/dist/charts/lib/export.js +204 -0
- package/dist/charts/lib/export.js.map +1 -0
- package/dist/charts/lib/figure.d.ts +61 -0
- package/dist/charts/lib/figure.js +59 -0
- package/dist/charts/lib/figure.js.map +1 -0
- package/dist/charts/lib/format.d.ts +46 -0
- package/dist/charts/lib/format.js +56 -0
- package/dist/charts/lib/format.js.map +1 -0
- package/dist/charts/lib/legend.d.ts +45 -0
- package/dist/charts/lib/legend.js +117 -0
- package/dist/charts/lib/legend.js.map +1 -0
- package/dist/charts/lib/loading.d.ts +48 -0
- package/dist/charts/lib/loading.js +105 -0
- package/dist/charts/lib/loading.js.map +1 -0
- package/dist/charts/lib/paint.d.ts +154 -0
- package/dist/charts/lib/paint.js +551 -0
- package/dist/charts/lib/paint.js.map +1 -0
- package/dist/charts/lib/sonify-control.d.ts +163 -0
- package/dist/charts/lib/sonify-control.js +172 -0
- package/dist/charts/lib/sonify-control.js.map +1 -0
- package/dist/charts/lib/sonify.d.ts +248 -0
- package/dist/charts/lib/sonify.js +262 -0
- package/dist/charts/lib/sonify.js.map +1 -0
- package/dist/charts/lib/toolbar.d.ts +143 -0
- package/dist/charts/lib/toolbar.js +156 -0
- package/dist/charts/lib/toolbar.js.map +1 -0
- package/dist/charts/lib/tooltip.d.ts +59 -0
- package/dist/charts/lib/tooltip.js +135 -0
- package/dist/charts/lib/tooltip.js.map +1 -0
- package/dist/charts/lib/values.d.ts +56 -0
- package/dist/charts/lib/values.js +71 -0
- package/dist/charts/lib/values.js.map +1 -0
- package/dist/charts/lib/zoom.d.ts +139 -0
- package/dist/charts/lib/zoom.js +314 -0
- package/dist/charts/lib/zoom.js.map +1 -0
- package/dist/components/AppShell/AppShell.d.ts +15 -1
- package/dist/components/AppShell/AppShell.js +8 -4
- package/dist/components/AppShell/AppShell.js.map +1 -1
- package/dist/components/Article/Article.d.ts +51 -0
- package/dist/components/Article/Article.js +21 -0
- package/dist/components/Article/Article.js.map +1 -0
- package/dist/components/Button/Button.js +2 -2
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Calendar/Calendar.d.ts +1 -1
- package/dist/components/Calendar/Calendar.js +259 -24
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.js +1 -1
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/Collapsible/Collapsible.d.ts +15 -1
- package/dist/components/Collapsible/Collapsible.js +18 -0
- package/dist/components/Collapsible/Collapsible.js.map +1 -1
- package/dist/components/Combobox/Combobox.js +1 -1
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Command/Command.js +7 -7
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.js +2 -2
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/Diagram/Diagram.d.ts +81 -0
- package/dist/components/Diagram/Diagram.js +139 -0
- package/dist/components/Diagram/Diagram.js.map +1 -0
- package/dist/components/Dialog/Dialog.js +1 -1
- package/dist/components/Dialog/Dialog.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.js +2 -2
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/FigureBand/FigureBand.js +41 -30
- package/dist/components/FigureBand/FigureBand.js.map +1 -1
- package/dist/components/Popover/Popover.js +1 -1
- package/dist/components/Popover/Popover.js.map +1 -1
- package/dist/components/Select/Select.js +2 -2
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Sheet/Sheet.js +1 -1
- package/dist/components/Sheet/Sheet.js.map +1 -1
- package/dist/components/Slider/Slider.js +1 -1
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/Steps/Steps.d.ts +65 -0
- package/dist/components/Steps/Steps.js +55 -0
- package/dist/components/Steps/Steps.js.map +1 -0
- package/dist/components/Switch/Switch.js +1 -1
- package/dist/components/Switch/Switch.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +1 -1
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/useSelectionIndicator.js +14 -10
- package/dist/lib/useSelectionIndicator.js.map +1 -1
- package/dist/semantic.css +19 -0
- package/dist/styles.css +1 -1
- package/dist/themes.css +103 -7
- package/dist/tokens.css +193 -10
- package/dist/tokens.d.ts +25 -0
- package/dist/tokens.js +154 -8
- package/dist/tokens.json +154 -8
- package/package.json +45 -20
- package/skills/misoto22-design/SKILL.md +171 -0
- package/skills/misoto22-design/evals/claims.json +95 -0
- package/skills/misoto22-design/rules/a11y.md +115 -0
- package/skills/misoto22-design/rules/composition.md +108 -0
- package/skills/misoto22-design/rules/forms.md +128 -0
- package/skills/misoto22-design/rules/naming.md +155 -0
- 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
|
+
```
|