dowel-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/lacodda/dowel/main/assets/banner.svg" width="720" alt="dowel">
3
+ </p>
4
+
5
+ # dowel
6
+
7
+ The lacodda line design system: theme tokens and React primitives, distributed as a shadcn-compatible registry.
8
+
9
+ 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
+
11
+ **Status:** v0.1.0 - the theme. Primitives and the registry follow; see the [roadmap](#roadmap).
12
+
13
+ ## The theme
14
+
15
+ One import, and a product has the vocabulary of the line:
16
+
17
+ ```bash
18
+ npm install dowel-ui
19
+ ```
20
+
21
+ > The package is `dowel-ui`: npm declines the bare name as too close to `del` and `bower`. The system is dowel everywhere else.
22
+
23
+ ```css
24
+ @import 'dowel-ui/theme.css';
25
+
26
+ :root {
27
+ /* The product's own colour. Everything else follows from it. */
28
+ --accent-base: #d9569e;
29
+ }
30
+ ```
31
+
32
+ That single line moves the accent and both of its partners, the accent's soft fill, the focus ring, and the tint in the greys. Set nothing at all and you get dowel's own amber.
33
+
34
+ Dark is the default; light arrives with the reader's system preference, or pinned with a class:
35
+
36
+ ```html
37
+ <html> <!-- follows the operating system -->
38
+ <html class="light"> <!-- pinned light -->
39
+ <html class="dark"> <!-- pinned dark -->
40
+ ```
41
+
42
+ With Tailwind 4 the tokens are utilities, because the theme declares them in a `@theme` block:
43
+
44
+ ```html
45
+ <div class="bg-raise text-text border border-line">
46
+ <button class="bg-accent text-on-accent">Save</button>
47
+ </div>
48
+ ```
49
+
50
+ 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.
51
+
52
+ ### What makes it different
53
+
54
+ - **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.
55
+ - **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.
56
+ - **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.
57
+
58
+ Full vocabulary, with every token shown in both themes: **[the token reference](https://lacodda.github.io/dowel/reference/tokens/)**.
59
+
60
+ ## Roadmap
61
+
62
+ Development goes in versions; each one is a single coherent theme, and ends in a release.
63
+
64
+ | | Delivers |
65
+ | --- | --- |
66
+ | **0.1 - 0.3** | The vocabulary: colours and modes, scales and motion, the accents of the line |
67
+ | **0.4 - 0.7** | The primitive pipeline, the base components, the first consumer, the quality gates |
68
+ | **0.8 - 0.11** | Overlays, menus and selection, the command palette, feedback |
69
+ | **0.12 - 0.15** | The registry as a product, AI-readiness, migration tooling, the second consumer |
70
+ | **0.16 - 0.24** | Forms, data and charts |
71
+ | **0.25 - 0.33** | Frame and navigation, blocks, resilience and docs |
72
+ | **1.0** | Four web products of the line on dowel; the token vocabulary and the registry format frozen |
73
+
74
+ ## Documentation
75
+
76
+ - [Getting started](https://lacodda.github.io/dowel/getting-started/)
77
+ - [Token reference](https://lacodda.github.io/dowel/reference/tokens/)
78
+
79
+ ## License
80
+
81
+ MIT
@@ -0,0 +1,17 @@
1
+ /** Tokens that carry a colour. Ordered as they read on a screen: grounds,
2
+ * then hairlines, then ink, then the accent, then status. */
3
+ export declare const colorTokens: readonly ["bg", "raise", "soft", "softer", "line", "line-2", "text", "dim", "faint", "accent", "accent-2", "accent-soft", "on-accent", "good", "good-soft", "warn", "warn-soft", "bad", "bad-soft", "info", "info-soft"];
4
+ /** Tokens a product overrides to make the theme its own: the accent from the
5
+ * brand-line registry, and how much of it bleeds into the greys. */
6
+ export declare const themeParameters: readonly ["accent-base", "neutral-base", "neutral-tint", "neutral-tint-strong", "ground", "ink"];
7
+ /** Everything else the theme defines. */
8
+ export declare const otherTokens: readonly ["shadow-raise"];
9
+ export type ColorToken = (typeof colorTokens)[number];
10
+ export type ThemeParameter = (typeof themeParameters)[number];
11
+ export type OtherToken = (typeof otherTokens)[number];
12
+ export type Token = ColorToken | ThemeParameter | OtherToken;
13
+ /** The custom property a token is read from: `token('accent')` is
14
+ * `'--accent'`. Spelled out here so that no caller builds the string itself
15
+ * and gets the prefix subtly wrong. */
16
+ export declare function token(name: Token): string;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA;6DAC6D;AAC7D,eAAO,MAAM,WAAW,0NAsBd,CAAA;AAEV;oEACoE;AACpE,eAAO,MAAM,eAAe,kGAOlB,CAAA;AAEV,yCAAyC;AACzC,eAAO,MAAM,WAAW,2BAA4B,CAAA;AAEpD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,cAAc,GAAG,UAAU,CAAA;AAE5D;;uCAEuC;AACvC,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAEzC"}
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ /*
2
+ * Public surface of the package.
3
+ *
4
+ * The product is dowel; the package is `dowel-ui`, because npm declined the
5
+ * bare name as too close to `del` and `bower`. Everything else - repository,
6
+ * docs, mark - keeps the product's own name.
7
+ *
8
+ * The theme is the product here, and it is CSS: `import 'dowel-ui/theme.css'`.
9
+ * This entry point carries only what JavaScript can usefully say about the
10
+ * theme - the token names, so that a product can iterate them (a token
11
+ * inspector, a docs page, a test) without re-typing the list and drifting from
12
+ * the stylesheet.
13
+ *
14
+ * Primitives are distributed through the registry, not from here: a component
15
+ * is copied into the product and becomes the product's own code.
16
+ */
17
+ /** Tokens that carry a colour. Ordered as they read on a screen: grounds,
18
+ * then hairlines, then ink, then the accent, then status. */
19
+ export const colorTokens = [
20
+ 'bg',
21
+ 'raise',
22
+ 'soft',
23
+ 'softer',
24
+ 'line',
25
+ 'line-2',
26
+ 'text',
27
+ 'dim',
28
+ 'faint',
29
+ 'accent',
30
+ 'accent-2',
31
+ 'accent-soft',
32
+ 'on-accent',
33
+ 'good',
34
+ 'good-soft',
35
+ 'warn',
36
+ 'warn-soft',
37
+ 'bad',
38
+ 'bad-soft',
39
+ 'info',
40
+ 'info-soft',
41
+ ];
42
+ /** Tokens a product overrides to make the theme its own: the accent from the
43
+ * brand-line registry, and how much of it bleeds into the greys. */
44
+ export const themeParameters = [
45
+ 'accent-base',
46
+ 'neutral-base',
47
+ 'neutral-tint',
48
+ 'neutral-tint-strong',
49
+ 'ground',
50
+ 'ink',
51
+ ];
52
+ /** Everything else the theme defines. */
53
+ export const otherTokens = ['shadow-raise'];
54
+ /** The custom property a token is read from: `token('accent')` is
55
+ * `'--accent'`. Spelled out here so that no caller builds the string itself
56
+ * and gets the prefix subtly wrong. */
57
+ export function token(name) {
58
+ return `--${name}`;
59
+ }
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;6DAC6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI;IACJ,OAAO;IACP,MAAM;IACN,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,UAAU;IACV,aAAa;IACb,WAAW;IACX,MAAM;IACN,WAAW;IACX,MAAM;IACN,WAAW;IACX,KAAK;IACL,UAAU;IACV,MAAM;IACN,WAAW;CACH,CAAA;AAEV;oEACoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa;IACb,cAAc;IACd,cAAc;IACd,qBAAqB;IACrB,QAAQ;IACR,KAAK;CACG,CAAA;AAEV,yCAAyC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,cAAc,CAAU,CAAA;AAOpD;;uCAEuC;AACvC,MAAM,UAAU,KAAK,CAAC,IAAW;IAC/B,OAAO,KAAK,IAAI,EAAE,CAAA;AACpB,CAAC"}
package/dist/theme.css ADDED
@@ -0,0 +1,312 @@
1
+ /*
2
+ * dowel theme - the token vocabulary every product of the lacodda line shares.
3
+ *
4
+ * The vocabulary comes from the products themselves: kilna and kasl-server
5
+ * already ship the same token names (bg / raise / soft / line / text / dim /
6
+ * accent / good / warn / bad / info) and differ only in values. That is the
7
+ * contract this file freezes. Names are the mockup's own words rather than
8
+ * stock component-library names, so a screen can be checked against a mockup
9
+ * in the mockup's words.
10
+ *
11
+ * Two things are parametric, and everything else is derived from them:
12
+ *
13
+ * --accent-base the product's hue from the brand-line registry
14
+ * --neutral-base the hue the greys are tinted with (the accent, by default)
15
+ *
16
+ * Tinting the neutrals is not decoration - it is what the two live products do
17
+ * by hand: kilna's greys lean magenta, kasl-server's lean gold. Here that lean
18
+ * is one declaration instead of thirty hand-picked hex values.
19
+ *
20
+ * Soft variants are mixed from their own base with `color-mix`, so a product
21
+ * that overrides `--accent-base` gets a matching `--accent-soft` for free and
22
+ * cannot pick one that disagrees with it.
23
+ *
24
+ * Theme selection: no class on the root element follows the operating system,
25
+ * an explicit `light` or `dark` class pins the theme. Components never use
26
+ * `dark:` utilities - every colour goes through a token, and the theme swaps
27
+ * the token underneath.
28
+ */
29
+
30
+ :root {
31
+ /* The two parameters. `--accent-base` is overridden per product by an accent
32
+ * file; `--neutral-base` follows it unless a product says otherwise. */
33
+ --accent-base: #e8862d;
34
+ --neutral-base: var(--accent-base);
35
+
36
+ /* Ink and ground of the dark theme, before the neutral tint is mixed in.
37
+ * Kept as their own tokens so the tint amount is the only thing that
38
+ * changes when a product wants greyer or warmer chrome. */
39
+ --ground: #131316;
40
+ --ink: #ece9ef;
41
+
42
+ /* How much of `--neutral-base` bleeds into the greys. The live products sit
43
+ * at roughly this much: enough that the chrome belongs to the product,
44
+ * little enough that it still reads as grey. */
45
+ --neutral-tint: 6%;
46
+ --neutral-tint-strong: 9%;
47
+
48
+ color-scheme: dark;
49
+
50
+ --bg: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), var(--ground));
51
+ --raise: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), #1c1c21);
52
+
53
+ /* Surfaces that lift by translucency rather than by their own colour: they
54
+ * must work over `--bg` and over `--raise` alike. */
55
+ --soft: rgb(255 255 255 / 0.045);
56
+ --softer: rgb(255 255 255 / 0.025);
57
+ --line: rgb(255 255 255 / 0.08);
58
+ --line-2: rgb(255 255 255 / 0.15);
59
+
60
+ --text: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), var(--ink));
61
+ --dim: color-mix(in oklab, var(--neutral-base) var(--neutral-tint-strong), #a7a2ad);
62
+ --faint: color-mix(in oklab, var(--neutral-base) var(--neutral-tint-strong), #6e6a76);
63
+
64
+ --accent: var(--accent-base);
65
+ /* The hover/active partner: lighter on dark, where the ground is what the
66
+ * accent has to separate from. */
67
+ --accent-2: color-mix(in oklab, white 22%, var(--accent-base));
68
+ --accent-soft: color-mix(in oklab, var(--accent-base) 16%, transparent);
69
+
70
+ /* Status hues are the line's own and do not follow the product accent: a
71
+ * green that shifted per product would stop meaning "good". Meaning never
72
+ * rests on colour alone - a badge carries an icon and a word - so these
73
+ * exist for emphasis, not as the message. */
74
+ --good: #45d18f;
75
+ --warn: #e8b13f;
76
+ --bad: #ef6a6a;
77
+ --info: #4cc4e0;
78
+ --good-soft: color-mix(in oklab, var(--good) 14%, transparent);
79
+ --warn-soft: color-mix(in oklab, var(--warn) 14%, transparent);
80
+ --bad-soft: color-mix(in oklab, var(--bad) 14%, transparent);
81
+ --info-soft: color-mix(in oklab, var(--info) 15%, transparent);
82
+
83
+ --shadow-raise: 0 10px 34px rgb(0 0 0 / 0.45);
84
+ }
85
+
86
+ /*
87
+ * Light theme, twice: once for the operating system's preference, once for the
88
+ * explicit `light` class. The declarations are identical - only the selector
89
+ * differs - so that a product can pin a theme against the system setting.
90
+ */
91
+ @media (prefers-color-scheme: light) {
92
+ :root:not(.dark) {
93
+ color-scheme: light;
94
+
95
+ --ground: #f6f5f7;
96
+ --ink: #232027;
97
+
98
+ --bg: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), var(--ground));
99
+ --raise: #ffffff;
100
+
101
+ --soft: color-mix(in oklab, var(--neutral-base) 60%, rgb(24 20 28 / 0.05));
102
+ --softer: color-mix(in oklab, var(--neutral-base) 60%, rgb(24 20 28 / 0.03));
103
+ --line: color-mix(in oklab, var(--neutral-base) 40%, rgb(24 20 28 / 0.11));
104
+ --line-2: color-mix(in oklab, var(--neutral-base) 40%, rgb(24 20 28 / 0.2));
105
+
106
+ --text: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), var(--ink));
107
+ --dim: color-mix(in oklab, var(--neutral-base) var(--neutral-tint-strong), #63606b);
108
+ --faint: color-mix(in oklab, var(--neutral-base) var(--neutral-tint-strong), #8a8692);
109
+
110
+ /* On a light ground the accent has to darken to stay legible as text and
111
+ * as a fill. It darkens *to* a lightness rather than *by* an amount: how
112
+ * far a hue has to travel depends on where it starts, and a fixed step
113
+ * that suits magenta leaves lime and gold short. Pinning the lightness and
114
+ * keeping the hue and chroma clears 5:1 for every accent in the line. */
115
+ --accent: oklch(from var(--accent-base) 0.5 c h);
116
+ --accent-2: oklch(from var(--accent-base) 0.4 c h);
117
+ --accent-soft: color-mix(in oklab, var(--accent-base) 12%, transparent);
118
+
119
+ --good: #178a58;
120
+ --warn: #9a6b0c;
121
+ --bad: #c93b3b;
122
+ --info: #0d7f9c;
123
+ --good-soft: color-mix(in oklab, var(--good) 12%, transparent);
124
+ --warn-soft: color-mix(in oklab, var(--warn) 14%, transparent);
125
+ --bad-soft: color-mix(in oklab, var(--bad) 12%, transparent);
126
+ --info-soft: color-mix(in oklab, var(--info) 11%, transparent);
127
+
128
+ --shadow-raise: 0 10px 30px rgb(30 24 38 / 0.14);
129
+ }
130
+ }
131
+
132
+ :root.light {
133
+ color-scheme: light;
134
+
135
+ --ground: #f6f5f7;
136
+ --ink: #232027;
137
+
138
+ --bg: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), var(--ground));
139
+ --raise: #ffffff;
140
+
141
+ --soft: color-mix(in oklab, var(--neutral-base) 60%, rgb(24 20 28 / 0.05));
142
+ --softer: color-mix(in oklab, var(--neutral-base) 60%, rgb(24 20 28 / 0.03));
143
+ --line: color-mix(in oklab, var(--neutral-base) 40%, rgb(24 20 28 / 0.11));
144
+ --line-2: color-mix(in oklab, var(--neutral-base) 40%, rgb(24 20 28 / 0.2));
145
+
146
+ --text: color-mix(in oklab, var(--neutral-base) var(--neutral-tint), var(--ink));
147
+ --dim: color-mix(in oklab, var(--neutral-base) var(--neutral-tint-strong), #63606b);
148
+ --faint: color-mix(in oklab, var(--neutral-base) var(--neutral-tint-strong), #8a8692);
149
+
150
+ /* Darkened to a lightness, not by an amount - see the note above. */
151
+ --accent: oklch(from var(--accent-base) 0.5 c h);
152
+ --accent-2: oklch(from var(--accent-base) 0.4 c h);
153
+ --accent-soft: color-mix(in oklab, var(--accent-base) 12%, transparent);
154
+
155
+ --good: #178a58;
156
+ --warn: #9a6b0c;
157
+ --bad: #c93b3b;
158
+ --info: #0d7f9c;
159
+ --good-soft: color-mix(in oklab, var(--good) 12%, transparent);
160
+ --warn-soft: color-mix(in oklab, var(--warn) 14%, transparent);
161
+ --bad-soft: color-mix(in oklab, var(--bad) 12%, transparent);
162
+ --info-soft: color-mix(in oklab, var(--info) 11%, transparent);
163
+
164
+ --shadow-raise: 0 10px 30px rgb(30 24 38 / 0.14);
165
+ }
166
+
167
+ /*
168
+ * `--on-accent` - what sits on top of an accent fill.
169
+ *
170
+ * A light accent (gold, lime, amber) needs dark glyphs; a dark one needs
171
+ * white. The live products picked this by hand and wrote the answer into the
172
+ * theme; here the theme works it out, by the same rule the brand-line S tile
173
+ * uses.
174
+ *
175
+ * `contrast-color()` is the direct way to say it and is used where supported.
176
+ * The fallback covers browsers that lack it. Relative colour syntax exposes
177
+ * the accent's own lightness as `l`; `clamp()` turns that into a hard switch,
178
+ * because the multiplication drives the middle term far past either bound
179
+ * everywhere except within a hair of the threshold. Below it the accent is
180
+ * dark and the result is 1 (white); above it, 0 (black). Chroma is dropped to
181
+ * zero, so what comes out is neutral rather than a tinted grey.
182
+ *
183
+ * The threshold is 0.58, and it is deliberately far below the midpoint an eye
184
+ * would guess. Contrast is not symmetric about it: a mid-lightness colour is
185
+ * still much closer to white than to black in luminance, so black wins well
186
+ * before the colour looks light. Checked against all fourteen accents of the
187
+ * line - every one of them reads better with dark glyphs, the closest being
188
+ * cobalt at 4.86:1 against 4.32:1 for white. A higher threshold is what puts
189
+ * white text on magenta at 3.6:1, which is the defect this rule exists to
190
+ * prevent.
191
+ */
192
+ :root {
193
+ --on-accent: oklch(from var(--accent) clamp(0, (0.58 - l) * 1000, 1) 0 0);
194
+ }
195
+
196
+ @supports (color: contrast-color(red)) {
197
+ :root {
198
+ --on-accent: contrast-color(var(--accent));
199
+ }
200
+ }
201
+
202
+ /*
203
+ * The Tailwind 4 surface. `--color-*: initial` drops the stock palette on
204
+ * purpose: a raw `bg-zinc-800` in a product should not compile, because the
205
+ * only colours that exist here are the line's own.
206
+ */
207
+ @theme inline {
208
+ --color-*: initial;
209
+ --color-bg: var(--bg);
210
+ --color-raise: var(--raise);
211
+ --color-soft: var(--soft);
212
+ --color-softer: var(--softer);
213
+ --color-line: var(--line);
214
+ --color-line-2: var(--line-2);
215
+ --color-text: var(--text);
216
+ --color-dim: var(--dim);
217
+ --color-faint: var(--faint);
218
+ --color-accent: var(--accent);
219
+ --color-accent-2: var(--accent-2);
220
+ --color-accent-soft: var(--accent-soft);
221
+ --color-on-accent: var(--on-accent);
222
+ --color-good: var(--good);
223
+ --color-good-soft: var(--good-soft);
224
+ --color-warn: var(--warn);
225
+ --color-warn-soft: var(--warn-soft);
226
+ --color-bad: var(--bad);
227
+ --color-bad-soft: var(--bad-soft);
228
+ --color-info: var(--info);
229
+ --color-info-soft: var(--info-soft);
230
+
231
+ /* Kept because they are not palette choices: a hairline is `transparent`,
232
+ * an SVG follows `currentColor`, and pure black and white are what an
233
+ * overlay scrim and a print sheet are made of. */
234
+ --color-transparent: transparent;
235
+ --color-current: currentColor;
236
+ --color-white: #fff;
237
+ --color-black: #000;
238
+
239
+ --font-sans: 'Segoe UI Variable Text', 'Segoe UI', system-ui, -apple-system, sans-serif;
240
+ --font-mono: ui-monospace, 'Cascadia Code', 'SF Mono', Consolas, monospace;
241
+
242
+ --shadow-raise: var(--shadow-raise);
243
+ }
244
+
245
+ /*
246
+ * Base layer: what every product would otherwise write again. Scoped to
247
+ * elements and to `:focus-visible`, never to a class, so nothing here can
248
+ * collide with a component.
249
+ */
250
+ body {
251
+ margin: 0;
252
+ background-color: var(--bg);
253
+ color: var(--text);
254
+ font-family: var(--font-sans);
255
+ -webkit-font-smoothing: antialiased;
256
+ }
257
+
258
+ :focus-visible {
259
+ outline: 2px solid var(--accent);
260
+ outline-offset: 2px;
261
+ }
262
+
263
+ @media (prefers-reduced-motion: reduce) {
264
+ *,
265
+ *::before,
266
+ *::after {
267
+ transition-duration: 0.01ms !important;
268
+ animation-duration: 0.01ms !important;
269
+ animation-iteration-count: 1 !important;
270
+ scroll-behavior: auto !important;
271
+ }
272
+ }
273
+
274
+ /*
275
+ * Scrollbars. A browser's default bar is a piece of someone else's chrome
276
+ * sitting in the middle of the product - full width, with step arrows. These
277
+ * are the line's own: thin, in the palette, drawn only where something
278
+ * actually scrolls.
279
+ */
280
+ * {
281
+ scrollbar-width: thin;
282
+ scrollbar-color: var(--line-2) transparent;
283
+ }
284
+
285
+ *::-webkit-scrollbar {
286
+ width: 10px;
287
+ height: 10px;
288
+ }
289
+
290
+ *::-webkit-scrollbar-track {
291
+ background: transparent;
292
+ }
293
+
294
+ *::-webkit-scrollbar-thumb {
295
+ border: 3px solid transparent;
296
+ border-radius: 999px;
297
+ background: var(--line-2);
298
+ background-clip: content-box;
299
+ }
300
+
301
+ *::-webkit-scrollbar-thumb:hover {
302
+ background: var(--dim);
303
+ background-clip: content-box;
304
+ }
305
+
306
+ *::-webkit-scrollbar-corner {
307
+ background: transparent;
308
+ }
309
+
310
+ *::-webkit-scrollbar-button {
311
+ display: none;
312
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "dowel-ui",
3
+ "version": "0.1.0",
4
+ "description": "The lacodda line design system: theme tokens and React primitives, distributed as a shadcn-compatible registry.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "author": "Kirill Lakhtachev <lahtachev@gmail.com>",
8
+ "homepage": "https://lacodda.github.io/dowel",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/lacodda/dowel.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/lacodda/dowel/issues"
15
+ },
16
+ "keywords": [
17
+ "design-system",
18
+ "design-tokens",
19
+ "react",
20
+ "tailwindcss",
21
+ "shadcn",
22
+ "registry"
23
+ ],
24
+ "sideEffects": [
25
+ "*.css"
26
+ ],
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js"
35
+ },
36
+ "./theme.css": "./dist/theme.css"
37
+ },
38
+ "scripts": {
39
+ "build": "tsc && node ../../tools/copy-theme.mjs",
40
+ "typecheck": "tsc --noEmit",
41
+ "prepack": "node ../../tools/copy-readme.mjs"
42
+ },
43
+ "peerDependencies": {
44
+ "react": "^19.0.0",
45
+ "react-dom": "^19.0.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^26.4.0",
49
+ "@types/react": "^19.2.18",
50
+ "@types/react-dom": "^19.2.5",
51
+ "react": "^19.2.8",
52
+ "react-dom": "^19.2.8"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public",
56
+ "provenance": true
57
+ }
58
+ }