dowel-ui 0.25.0 → 0.26.1
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 +42 -177
- package/dist/registry.json +224 -72
- package/dist/theme.css +14 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
<img src="https://raw.githubusercontent.com/lacodda/dowel/main/assets/banner.svg" width="720" alt="dowel">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> The lacodda line design system: theme tokens and React primitives, distributed as a shadcn-compatible registry.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/dowel-ui"><img src="https://img.shields.io/npm/v/dowel-ui?style=flat-square" alt="npm"></a>
|
|
9
|
+
<a href="https://github.com/lacodda/dowel/actions"><img src="https://img.shields.io/github/actions/workflow/status/lacodda/dowel/ci.yml?style=flat-square" alt="CI"></a>
|
|
10
|
+
<a href="https://github.com/lacodda/dowel/blob/main/LICENSE"><img src="https://img.shields.io/github/license/lacodda/dowel?style=flat-square" alt="License"></a>
|
|
11
|
+
</p>
|
|
8
12
|
|
|
9
13
|
A dowel is the hidden peg that joins two boards so the seam does not show. That is what this does for the products of the line: they look made by one hand, and nobody sees the joint.
|
|
10
14
|
|
|
11
15
|
**[Documentation](https://lacodda.github.io/dowel/)** — what everything is and why it is that way.
|
|
12
16
|
**[The stand](https://lacodda.github.io/dowel/stand/)** — every component, live, in either theme and in the accent of any product of the line.
|
|
13
17
|
|
|
14
|
-
**Status:** v0.25.0 - the theme, the scales, an accent per product, seventy-six components - overlays, menus, the command palette, the table, a hundred thousand rows, the screens between asking for data and showing it, the three ways of saying something happened, charts, and now text and code: rendered markdown through one stylesheet, a code block whose highlighter is yours, a comparison whose two columns stay in step, and a JSON document read rather than parsed by eye - and the gates each one passes: axe, the keyboard, a dependency budget and a picture in both themes. Every component has a page of its own on the stand, which remembers the theme and the accent you left it in. Components install from a versioned registry, the docs are served in the form an agent reads, and `dowel check` tells a project what stands between it and the vocabulary. Two products of the line live on it. See the [roadmap](#roadmap).
|
|
15
|
-
|
|
16
18
|
## The theme
|
|
17
19
|
|
|
18
20
|
One import, and a product has the vocabulary of the line:
|
|
@@ -32,58 +34,21 @@ npm install dowel-ui
|
|
|
32
34
|
}
|
|
33
35
|
```
|
|
34
36
|
|
|
35
|
-
That single line moves the accent and both of its partners, the accent's soft
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<html class="light"> <!-- pinned light -->
|
|
42
|
-
<html class="dark"> <!-- pinned dark -->
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
With Tailwind 4 the tokens are utilities, because the theme declares them in a `@theme` block:
|
|
46
|
-
|
|
47
|
-
```html
|
|
48
|
-
<div class="bg-raise text-text border border-line">
|
|
49
|
-
<button class="bg-accent text-on-accent">Save</button>
|
|
50
|
-
</div>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
The stock palette is dropped deliberately, so a stray `bg-zinc-800` does not compile. If a colour is worth using, it is worth a name in the vocabulary.
|
|
54
|
-
|
|
55
|
-
### What makes it different
|
|
56
|
-
|
|
57
|
-
- **The accent is derived, not configured.** A product states one hue and the theme works out the rest, including what colour text has to be to sit on top of it. A light accent takes dark glyphs, a dark one white - checked against every colour in the line rather than left to each product to get right.
|
|
58
|
-
- **The greys belong to the product.** They carry a trace of its hue, so the chrome of one product is not the chrome of another with a different button colour.
|
|
59
|
-
- **Contrast is a test, not an intention.** Every accent of the line is measured against WCAG AA in CI, in both themes, as a fill and as text.
|
|
60
|
-
- **The scales were read, not invented.** Radius, type, elevation and stacking order come from what the line's products already draw, so existing code fits them - and the places where those products disagreed with themselves are settled rather than preserved.
|
|
61
|
-
|
|
62
|
-
The same vocabulary also ships as [DTCG](https://www.designtokens.org/tr/2025.10/format/) JSON at `dowel-ui/tokens.json`, generated from the stylesheet so the two cannot drift.
|
|
63
|
-
|
|
64
|
-
A product of the line states one thing about its appearance - which product it is:
|
|
65
|
-
|
|
66
|
-
```css
|
|
67
|
-
@import 'dowel-ui/theme.css';
|
|
68
|
-
@import 'dowel-ui/accents/kilna.css';
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Text a product does not write by hand - rendered markdown, a description from a CMS, a model's reply - is the one thing a component cannot style, because the tags arrive already made. That is a second stylesheet, imported the same way and applied with one class:
|
|
72
|
-
|
|
73
|
-
```css
|
|
74
|
-
@import 'dowel-ui/prose.css';
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
```tsx
|
|
78
|
-
<div className="prose" dangerouslySetInnerHTML={{ __html: sanitised }} />
|
|
79
|
-
```
|
|
37
|
+
That single line moves the accent and both of its partners, the accent's soft
|
|
38
|
+
fill, the focus ring, the scrollbars and the tint in the greys. **The accent is
|
|
39
|
+
derived, not configured**: a product states one hue and the theme works out the
|
|
40
|
+
rest, including what colour text has to be to sit on top of it - checked
|
|
41
|
+
against WCAG AA in CI, in both themes. Dark is the default; light arrives with
|
|
42
|
+
the reader's system preference.
|
|
80
43
|
|
|
81
|
-
|
|
44
|
+
With Tailwind 4 the tokens are utilities, and the stock palette is dropped
|
|
45
|
+
deliberately, so a stray `bg-zinc-800` does not compile. If a colour is worth
|
|
46
|
+
using, it is worth a name in the vocabulary - a convention the package also
|
|
47
|
+
ships as a lint rule.
|
|
82
48
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
```
|
|
49
|
+
Full vocabulary, shown rather than tabulated:
|
|
50
|
+
**[colours](https://lacodda.github.io/dowel/reference/tokens/)** and
|
|
51
|
+
**[the scales](https://lacodda.github.io/dowel/reference/scales/)**.
|
|
87
52
|
|
|
88
53
|
## Primitives
|
|
89
54
|
|
|
@@ -92,122 +57,28 @@ your code:
|
|
|
92
57
|
|
|
93
58
|
```bash
|
|
94
59
|
npx shadcn@latest add https://lacodda.github.io/dowel/r/button.json
|
|
60
|
+
npx shadcn@latest add https://lacodda.github.io/dowel/r/app.json # or a whole set
|
|
95
61
|
```
|
|
96
62
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
installs you could have typed, so nothing of it survives in your project and
|
|
106
|
-
there is no membership to leave. Each minor of the registry is also served
|
|
107
|
-
frozen at `r/v0.25/…`, for an install that has to be repeatable - inside a
|
|
108
|
-
snapshot the cross-references point into the same snapshot, so a component and
|
|
109
|
-
the sibling it reuses are the pair that shipped together. See
|
|
110
|
-
[installing from the registry](https://lacodda.github.io/dowel/guides/registry/).
|
|
111
|
-
|
|
112
|
-
Seventy-six of them so far. The everyday ones - Button, Input, Textarea, Panel,
|
|
113
|
-
Badge, Chip, Kbd, Spinner, Truncate and Copyable; Field and the three controls
|
|
114
|
-
that answer a question - Checkbox, RadioGroup and Switch; five for a number or
|
|
115
|
-
a judgement - NumberField, Slider, RatingScale, DurationField and
|
|
116
|
-
PasswordField; the harder half of a form - TagInput, FileDrop, ColorField,
|
|
117
|
-
ActionBar and SaveState; five for a date or a time - Calendar, DatePicker,
|
|
118
|
-
DateRangePicker, TimeField and the `calendar-math` under them; the six that
|
|
119
|
-
float above the page - Dialog, ConfirmDialog, Drawer, Popover, PreviewCard and
|
|
120
|
-
Tooltip; four for choosing something - Menu, ContextMenu, Select and Combobox;
|
|
121
|
-
three for finding it - SearchField, CommandPalette and the `useShortcut` behind
|
|
122
|
-
them; three for saying that something happened - Toast, Alert and Banner; six
|
|
123
|
-
for showing rows of data - Table, Pagination, PageSize, NumberFormat,
|
|
124
|
-
RelativeTime and the `table-sort` with no React in it; four for a long list or
|
|
125
|
-
a deep one - VirtualList, TreeView with the `tree-rows` under it, and KeyValue;
|
|
126
|
-
StatTile, for one figure and what it is a figure of, with Sparkline for the
|
|
127
|
-
shape of its history, and Track with its `track-segments` for a bar divided
|
|
128
|
-
into stretches; ActivityHeatmap with its legend and its `activity-weeks`, for a
|
|
129
|
-
year of days; BarChart for a period at a time, LineChart with its `line-scale` for a level
|
|
130
|
-
between the readings; and five for the screens
|
|
131
|
-
between asking for data and showing it: Skeleton, EmptyState, Progress,
|
|
132
|
-
QueryState and ErrorBoundary. And six for text and code: the `prose`
|
|
133
|
-
stylesheet for markdown a product did not write by hand, CodeBlock with
|
|
134
|
-
CopyButton beside it, DiffView with the `diff-lines` that keeps its two
|
|
135
|
-
columns in step, and JsonViewer over its `json-rows`.
|
|
136
|
-
|
|
137
|
-
Those last three are the ones products keep confusing, so each page names all
|
|
138
|
-
four options: a **toast** goes away, an **alert** is still true after a reload,
|
|
139
|
-
a **banner** is true on every screen, and anything that needs an answer is a
|
|
140
|
-
**dialog**.
|
|
141
|
-
|
|
142
|
-
The palette is a Combobox rather than a Dialog with a field in it, which is
|
|
143
|
-
Base UI's own arrangement: put the input inside the popup and the popup becomes
|
|
144
|
-
a dialog on its own, with the input still the combobox that owns the list. So
|
|
145
|
-
the filtering, the highlight and the arrow keys are the ones Combobox already
|
|
146
|
-
has - there is no second implementation of any of it.
|
|
147
|
-
|
|
148
|
-
`Select` is the one the line's oldest rule is about. It renders
|
|
149
|
-
`<button role="combobox">` and no native `<select>` at all - the browser draws
|
|
150
|
-
that popup in the operating system's own chrome, where no stylesheet reaches
|
|
151
|
-
it, and on a screen of the product's own controls it reads as a foreign object.
|
|
152
|
-
`multiple` is a prop on Select and on Combobox rather than a component of its
|
|
153
|
-
own.
|
|
154
|
-
|
|
155
|
-
The overlays are built on [Base UI](https://base-ui.com), which supplies the
|
|
156
|
-
part that is genuinely hard and invisible when it works: the focus trap, the
|
|
157
|
-
return of focus to whatever opened the thing, `Escape`, the scroll lock, and
|
|
158
|
-
the `aria-labelledby` that names a popup by its own title. Choosing between
|
|
159
|
-
them is the harder question, and [a guide](https://lacodda.github.io/dowel/guides/overlays/) covers it.
|
|
160
|
-
|
|
161
|
-
Each is written in the vocabulary - no raw colours, no `dark:` utilities - so
|
|
162
|
-
the same component is correct in both themes and in every product's accent.
|
|
163
|
-
Every one of them is on [the stand](https://lacodda.github.io/dowel/stand/), live - change the theme and the accent and watch what follows.
|
|
164
|
-
|
|
165
|
-
That convention is a lint rule, and it ships with the package:
|
|
166
|
-
|
|
167
|
-
```js
|
|
168
|
-
// eslint.config.js
|
|
169
|
-
import dowel from 'dowel-ui/eslint'
|
|
170
|
-
|
|
171
|
-
export default [...dowel.configs.recommended]
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Two rules come with it. One reports a hex, an `rgb()`, a stock Tailwind colour,
|
|
175
|
-
`bg-white` and any `dark:` utility, in the file that wrote one. The other
|
|
176
|
-
forbids the native `<select>`, whose popup the browser draws in the operating
|
|
177
|
-
system's own chrome where no CSS reaches it - see [the guide](https://lacodda.github.io/dowel/guides/linting/).
|
|
63
|
+
Eighty-four primitives so far - the everyday controls, forms, overlays built on
|
|
64
|
+
[Base UI](https://base-ui.com), menus and selection, the command palette,
|
|
65
|
+
tables and long lists, charts, the screens between asking for data and showing
|
|
66
|
+
it, markdown, code and diffs, a desktop window's own chrome and the three
|
|
67
|
+
abilities of a catalogue table. Each is
|
|
68
|
+
written in the vocabulary - no raw
|
|
69
|
+
colours, no `dark:` utilities - and runs its own gate before it ships: axe, the
|
|
70
|
+
keyboard, a dependency budget and a picture in both themes.
|
|
178
71
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
against a baseline, and a check that it carries no word of its own to translate
|
|
183
|
-
- [what a component has to pass](https://lacodda.github.io/dowel/guides/gates/).
|
|
184
|
-
|
|
185
|
-
Full vocabulary, shown rather than tabulated: **[colours](https://lacodda.github.io/dowel/reference/tokens/)** in both themes, **[the scales](https://lacodda.github.io/dowel/reference/scales/)** - radius, type, motion, elevation and stacking order - and **[the accents](https://lacodda.github.io/dowel/reference/accents/)**, where the same screen is drawn in every colour of the line.
|
|
72
|
+
The full catalogue, live: **[the stand](https://lacodda.github.io/dowel/stand/)**.
|
|
73
|
+
One page per component: **[components](https://lacodda.github.io/dowel/components/button/)**.
|
|
74
|
+
Installing, sets and frozen versions: **[the registry guide](https://lacodda.github.io/dowel/guides/registry/)**.
|
|
186
75
|
|
|
187
76
|
## Moving an existing project over
|
|
188
77
|
|
|
189
78
|
A product arriving at dowel almost never arrives from nothing - it arrives from
|
|
190
|
-
stock shadcn/ui, whose theme names colours by their role in a page
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
```console
|
|
195
|
-
$ npx dowel check # what is not on the dowel vocabulary yet
|
|
196
|
-
$ npx dowel codemod --write # rewrite the names that can be rewritten
|
|
197
|
-
$ npx dowel doctor # whether the installation itself is wired right
|
|
198
|
-
$ npx dowel diff dialog # what you changed since you copied it in
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
`check`, `doctor` and `diff` only read; `codemod` writes, and only when asked
|
|
202
|
-
twice. Everything reads the catalogue inside the installed package, so none of
|
|
203
|
-
it needs the network.
|
|
204
|
-
|
|
205
|
-
Two things are deliberately never rewritten, and the tools say so rather than
|
|
206
|
-
guessing: a colour, because which token it was reaching for is a decision; and
|
|
207
|
-
`--accent`, because it is the one name both vocabularies use for opposite
|
|
208
|
-
things - stock's hover fill and dowel's product hue. The first run of `check`
|
|
209
|
-
against dowel's own stand reported twenty-four violations that were all correct
|
|
210
|
-
code, which is exactly how that rule was learned - see
|
|
79
|
+
stock shadcn/ui, whose theme names colours by their role in a page where dowel
|
|
80
|
+
names them by what they are on a screen. Four commands read a project, rewrite
|
|
81
|
+
the names that can be rewritten, and say what is left for a person to decide:
|
|
211
82
|
[the migration guide](https://lacodda.github.io/dowel/guides/migration/).
|
|
212
83
|
|
|
213
84
|
## A day in the life
|
|
@@ -242,8 +113,7 @@ every dowel component targets:
|
|
|
242
113
|
}
|
|
243
114
|
```
|
|
244
115
|
|
|
245
|
-
|
|
246
|
-
|
|
116
|
+
> Copy in what the screen needs.
|
|
247
117
|
```console
|
|
248
118
|
$ npx shadcn@latest add https://lacodda.github.io/dowel/r/app.json
|
|
249
119
|
```
|
|
@@ -281,19 +151,14 @@ fixed: the hand-written theme pinned dark ink on the accent for both themes,
|
|
|
281
151
|
which was right on gold and wrong on the darkened gold the light theme uses,
|
|
282
152
|
where it measured 3.49:1. Derived, it is white there, at 6.01:1.
|
|
283
153
|
|
|
284
|
-
##
|
|
154
|
+
## Status
|
|
285
155
|
|
|
286
|
-
|
|
156
|
+
The theme, the scales, an accent per product, and eighty-four primitives are
|
|
157
|
+
in daily use across two products of the line. Every component installs from a
|
|
158
|
+
versioned registry and passes its own gate - axe, the keyboard, a dependency
|
|
159
|
+
budget and a picture in both themes - before it ships.
|
|
287
160
|
|
|
288
|
-
|
|
289
|
-
| --- | --- |
|
|
290
|
-
| **0.1 - 0.3** | The vocabulary: colours and modes, scales and motion, the accents of the line |
|
|
291
|
-
| **0.4 - 0.7** | The primitive pipeline, the base components, the first consumer, the quality gates |
|
|
292
|
-
| **0.8 - 0.11** | Overlays, menus and selection, the command palette, feedback |
|
|
293
|
-
| **0.12 - 0.15** | The registry as a product, AI-readiness, migration tooling, the second consumer |
|
|
294
|
-
| **0.16 - 0.24** | Forms, data and charts |
|
|
295
|
-
| **0.25 - 0.33** | Frame and navigation, blocks, resilience and docs |
|
|
296
|
-
| **1.0** | Four web products of the line on dowel; the token vocabulary and the registry format frozen |
|
|
161
|
+
Released versions and what landed in each: [CHANGELOG](https://github.com/lacodda/dowel/blob/main/CHANGELOG.md).
|
|
297
162
|
|
|
298
163
|
## Documentation
|
|
299
164
|
|
|
@@ -321,4 +186,4 @@ same sources the site is built from:
|
|
|
321
186
|
|
|
322
187
|
## License
|
|
323
188
|
|
|
324
|
-
MIT
|
|
189
|
+
MIT (c) [Kirill Lakhtachev](https://lacodda.com)
|