@kazamitte/design-token 0.0.0-stage → 0.4.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kazamitte
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,281 @@
1
- # Temporary Holding Version
1
+ # @kazamitte/design-token
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A design token layer for Tailwind CSS v4 — color, typography, and style themes. Requires Tailwind v4.
4
+
5
+ Every color token clears WCAG AA for normal text. No single scale can do that across every hue, so the steps differ from color to color.
6
+
7
+ ## Setup
8
+
9
+ Install the package alongside Tailwind CSS v4, which it expects as a peer dependency.
10
+
11
+ ```sh
12
+ npm install @kazamitte/design-token tailwindcss
13
+ ```
14
+
15
+ ### CSS
16
+
17
+ Import Tailwind first, then the package. The package does not import Tailwind itself, so it is loaded once and you keep control over how it is imported.
18
+
19
+ ```css
20
+ @import "tailwindcss";
21
+
22
+ @import "@kazamitte/design-token/index.css";
23
+ @import "@kazamitte/design-token/theme/color/default.css";
24
+ @import "@kazamitte/design-token/theme/style/soft.css";
25
+
26
+ @source '../node_modules/@kazamitte/design-token';
27
+
28
+ body {
29
+ background-color: var(--r-base-bg);
30
+ color: var(--r-base-fg);
31
+ }
32
+ ```
33
+
34
+ The `@source` directive is required because Tailwind v4 excludes `node_modules` from scanning by default. See [Detecting classes in source files](https://tailwindcss.com/docs/detecting-classes-in-source-files) in the Tailwind docs.
35
+
36
+ ### JavaScript
37
+
38
+ The JavaScript API exposes one function, for generating a color theme.
39
+
40
+ ```ts
41
+ import { generateColorTheme } from "@kazamitte/design-token";
42
+ ```
43
+
44
+ Everything the package does is delivered as CSS, so the JavaScript API is optional. Reach for it to generate several themes at once, or to swap themes at runtime from the app. See [Color theme generation](./docs/generate-color-theme.md) for usage.
45
+
46
+ ### Further reading
47
+
48
+ - [Color theme generation](./docs/generate-color-theme.md) — writing a theme file with `generateColorTheme`
49
+ - [Color pairings](./docs/color-pairings.md) — which secondary, base and link colors suit each primary (Japanese)
50
+ - [Fixing class conflicts with tailwind-merge](./docs/tailwind-merge.md) — registering the package's utilities with tailwind-merge
51
+
52
+ ---
53
+
54
+ ## Layout
55
+
56
+ ```text
57
+ tailwind/
58
+ ├─ base/
59
+ │ ├─ initialize.css clears the Tailwind color / font / text namespaces
60
+ │ ├─ color/
61
+ │ │ ├─ palette.css the raw palette (every --color-*)
62
+ │ │ ├─ semantic.css --c-<hue>-*, 26 hues x 15 tokens, light/dark
63
+ │ │ ├─ status.css error / warning / success / info
64
+ │ │ └─ utility.css role utilities (primary-bg, base-fg, …)
65
+ │ ├─ typography/
66
+ │ │ ├─ font.css
67
+ │ │ └─ utility.css
68
+ │ └─ style/
69
+ │ ├─ animation.css the keyframes and the --animate-* steps on them
70
+ │ ├─ radius.css the radius scale
71
+ │ ├─ shadow.css the shadow scale and the colors it is built from
72
+ │ └─ z-index.css the layering scale
73
+ ├─ theme/
74
+ │ ├─ color/ base / primary / secondary / link
75
+ │ └─ style/ neutral / editorial / soft / dense
76
+ └─ index.css loads the base, the dark variant, duration utilities
77
+ ```
78
+
79
+ ## Color
80
+
81
+ ### Roles
82
+
83
+ - Theme colors
84
+ - primary
85
+ - secondary
86
+ - base
87
+ - link
88
+ - Status colors
89
+ - error — red
90
+ - warning — amber
91
+ - success — green
92
+ - info — blue
93
+
94
+ Each role carries 15 tokens.
95
+
96
+ | Group | Tokens |
97
+ | ---------- | ---------------------------------------------------------------------------- |
98
+ | Text | `fg-strong`, `fg`, `fg-muted`, `fg-subtle` |
99
+ | Background | `bg`, `bg-subtle`, `bg-muted`, `bg-selected`, `bg-solid` |
100
+ | Border | `border-subtle`, `border-muted`, `border-selected`, `border`, `border-solid` |
101
+ | Contrast | `fg-contrast` |
102
+ | Focus ring | `focus-ring` |
103
+
104
+ ### Pairs that clear the contrast requirement
105
+
106
+ These four clear the WCAG AA threshold for normal text (4.5:1) across all 26 hues, in both light and dark.
107
+
108
+ - `fg-strong` on `bg-selected` — emphasized text on a hover surface
109
+ - `fg` on `bg-muted` — body text on a selected surface
110
+ - `fg-muted` on `bg` — secondary text on a tinted surface
111
+ - `fg-contrast` on `bg-solid` — the label on a filled control
112
+
113
+ `fg-subtle` is exempt from the requirement: it is meant for decoration and disabled states.
114
+
115
+ Roles can take different hues, so text from one role often sits on a surface from another — base text on a primary surface, or a link on a base surface. These clear 4.5:1 for text from any hue on a surface from any other hue, in both light and dark.
116
+
117
+ - `fg-strong` on `bg`, `bg-subtle` or `bg-muted`
118
+ - `fg` on `bg` or `bg-subtle`
119
+ - `fg-muted` on `bg`
120
+ - `fg-contrast` on `bg-solid`
121
+
122
+ For links, `link-fg` is the `fg-muted` of the link hue and `link-fg-strong` is its `fg`, so a link on any `bg` clears, and `link-fg-strong` also clears on `bg-subtle`.
123
+
124
+ One exception: in dark, indigo `fg` on a yellow or lime `bg-subtle` falls to about 4.3:1.
125
+
126
+ For non-text contrast (WCAG 1.4.11, 3:1), `border-solid`, `bg-solid` and `focus-ring` share a step and stand out from `bg` and `bg-subtle` of any hue, and from `bg-muted` of the same hue or of a neutral. Use them for input borders, checkboxes, progress bars, focus indicators and the like. A focus ring drawn against a solid control matches its fill, so separate the two with an offset in a `bg` color.
127
+
128
+ In dark, `bg-solid` is a light fill and `fg-contrast` a dark label. No fill dark enough for a white label also stands out 3:1 from a dark surface.
129
+
130
+ `fg-subtle` is not held to 3:1.
131
+
132
+ ### Choosing a border
133
+
134
+ - `border` is the default frame for containers: cards, lists, tables, code blocks, popovers, menus and toasts. It is decorative, about 2.5:1 against `bg`, and is not held to 3:1.
135
+ - `border-solid` is for controls that need 3:1 under WCAG 1.4.11, such as inputs and checkboxes.
136
+ - `border-subtle` and `border-muted` are for faint dividers.
137
+ - `border-selected` marks a selected state.
138
+
139
+ The steps run `border-subtle` < `border-muted` < `border-selected` < `border` < `border-solid` in strength, in every hue and both modes.
140
+
141
+ Contrast is measured the way axe-core measures it: out-of-gamut colors are clipped to sRGB, nothing is rounded, and a pair passes only when its ratio is strictly greater than the threshold.
142
+
143
+ ### Semantic tokens
144
+
145
+ All 26 hues expose the same 15 tokens under `--c-*`. Use them where a specific color is wanted directly — tags, categories, charts.
146
+
147
+ ```html
148
+ <span class="bg-(--c-lime-bg-subtle) text-(--c-lime-fg)">Draft</span>
149
+ ```
150
+
151
+ ### Palette
152
+
153
+ Adjusted from the Tailwind 4.3.0 default theme. All 26 hues are defined, including mauve, olive, mist and taupe, which Tailwind added in 4.2.
154
+
155
+ Every hue also carries two steps Tailwind does not have — 350 and 750 — each the OKLCH midpoint of its neighbours. They let a semantic token sit between two Tailwind steps where neither one holds the contrast requirement across hues.
156
+
157
+ ## Typography
158
+
159
+ Modeled on [digital-go-jp/tailwind-theme-plugin](https://github.com/digital-go-jp/tailwind-theme-plugin).
160
+
161
+ Each utility sets font-size, line-height and letter-spacing together.
162
+
163
+ ```html
164
+ <h1 class="text-display-48">…</h1>
165
+ <p class="text-body-16">…</p>
166
+ ```
167
+
168
+ | Utility | Variants | Use |
169
+ | ------------------ | ------------------------- | ---------------- |
170
+ | `text-display-*` | 64, 56, 48, 44 | Hero, page title |
171
+ | `text-highlight-*` | 36, 32, 28, 26, 24, 22 | Headings |
172
+ | `text-body-*` | 20, 18, 16 | Body copy |
173
+ | `text-dense-*` | 18, 16, 14 (+ `-compact`) | Tables, dense UI |
174
+ | `text-oneline-*` | 18, 16, 14 | Labels, buttons |
175
+ | `text-mono-*` | 18, 16, 14 | Code |
176
+
177
+ ## Style
178
+
179
+ A style preset sets spacing, radius, shadow, duration and easing together, so that the whole interface reads as one.
180
+
181
+ | Preset | Character |
182
+ | ----------- | ---------------------------------------------------------------------- |
183
+ | `neutral` | A balanced default |
184
+ | `editorial` | Sharp corners and the shallowest shadows; hierarchy comes from borders |
185
+ | `soft` | Generous rounding and pronounced elevation |
186
+ | `dense` | Minimal rounding and elevation, for information-dense UI |
187
+
188
+ ```html
189
+ <div class="rounded-surface shadow-raised hover:shadow-raised-hover"></div>
190
+ ```
191
+
192
+ Radius and easing do not name their utilities after the `@theme` namespace they live in: `--radius-*` generates `rounded-*`, and `--ease-*` generates `ease-*`.
193
+
194
+ `--spacing` is the base step of the spacing scale and has no utility of its own. `p-4` is emitted as `calc(var(--spacing) * 4)`, so switching preset moves `p-*`, `m-*`, `gap-*`, `size-*` and the rest together — note that the sizing utilities read the same variable.
195
+
196
+ | Utility | Variants | Sets |
197
+ | --------------- | ---------------------------------------------- | ---------------------------- |
198
+ | `p-*` `gap-*` … | every utility reads `--spacing`, the base step | spacing and sizing |
199
+ | `rounded-*` | tight, control, surface, overlay, pill | `border-radius` |
200
+ | `shadow-*` | flat, raised, floating (+ `-hover`), overlay | `box-shadow` |
201
+ | `duration-*` | instant, transition, enter | `transition-duration` |
202
+ | `ease-*` | standard, emphasized | `transition-timing-function` |
203
+ | `animate-*` | fade / scale / slide, in and out | `animation` |
204
+
205
+ Every duration collapses to 1ms under `prefers-reduced-motion: reduce`.
206
+
207
+ ### Motion
208
+
209
+ `animate-*` covers the enter and exit of the things that appear over the page.
210
+
211
+ | Utility | Use |
212
+ | --------------------------- | ------------------------ |
213
+ | `animate-fade-in` / `-out` | Scrims, tab panels |
214
+ | `animate-scale-in` / `-out` | Dialogs, menus, popovers |
215
+ | `animate-slide-in-from-*` | Drawers, sheets, toasts |
216
+ | `animate-slide-out-to-*` | The same, leaving |
217
+
218
+ The slide steps take `top`, `right`, `bottom` and `left`, and travel the full
219
+ size of the element unless it says otherwise.
220
+
221
+ ```html
222
+ <div class="animate-slide-in-from-bottom [--slide-distance:1rem]"></div>
223
+ ```
224
+
225
+ Every step is composed from the preset's duration and easing, so it follows the
226
+ preset and collapses to 1ms under reduced motion. Tailwind's own `animate-spin`,
227
+ `-ping`, `-pulse` and `-bounce` are untouched and keep animating under reduced
228
+ motion.
229
+
230
+ Exit animations only play while the element is still in the tree; unmount it on
231
+ `animationend`.
232
+
233
+ Collapse and expand are not included. They need a measured height, which no
234
+ keyframe can supply.
235
+
236
+ ### Layering
237
+
238
+ `z-*` follows [Chakra UI's z-index scale](https://chakra-ui.com/docs/theming/z-index), so the order matches what component libraries assume — notably `popover` above `modal`, since a select opened inside a dialog has to clear it.
239
+
240
+ | Step | Value | Step | Value |
241
+ | ---------- | ----- | ---------- | ---------- |
242
+ | `hide` | -1 | `overlay` | 1300 |
243
+ | `base` | 0 | `modal` | 1400 |
244
+ | `docked` | 10 | `popover` | 1500 |
245
+ | `dropdown` | 1000 | `skip-nav` | 1600 |
246
+ | `sticky` | 1100 | `toast` | 1700 |
247
+ | `banner` | 1200 | `tooltip` | 1800 |
248
+ | | | `max` | 2147483647 |
249
+
250
+ Layering does not vary by preset, so these are used directly rather than through
251
+ one. `z-10` and `z-auto` still work alongside them. `<dialog>` and the Popover
252
+ API render in the top layer, where z-index has no effect.
253
+
254
+ ### Shadow
255
+
256
+ `--shadow-2xs` through `--shadow-2xl` are the base scale, seven steps. A preset picks one step per role and does nothing more; light and dark are resolved inside the scale, so no preset carries a dark override.
257
+
258
+ Each step reads its colors through the custom properties below. These four are all that `[data-mode='dark']` swaps.
259
+
260
+ | Custom property | Light | Dark |
261
+ | ----------------------- | --------- | --------- |
262
+ | `--shadow-color-subtle` | black 5% | black 35% |
263
+ | `--shadow-color` | black 10% | black 50% |
264
+ | `--shadow-color-strong` | black 25% | black 70% |
265
+ | `--shadow-rim-color` | black 7% | white 12% |
266
+
267
+ A cast shadow barely reads on a dark surface, so every step opens with a `0 0 0 1px var(--shadow-rim-color)` rim. In dark it is that white rim that separates a surface from its background, while the heavier cast carries the elevation. `--shadow-2xs` is the rim alone — an edge with no elevation.
268
+
269
+ To recolor the shadows, redefine those four under `:root` and `[data-mode='dark']`; the whole scale, and every preset built on it, follows.
270
+
271
+ ---
272
+
273
+ ## AI assistance
274
+
275
+ The documentation and code in this package were written with AI agents — Claude and ChatGPT. Every output was reviewed by a human before it was committed.
276
+
277
+ ## License
278
+
279
+ MIT. See [LICENSE](./LICENSE).
280
+
281
+ The color palette comes from Tailwind CSS and the typography scale from digital-go-jp/tailwind-theme-plugin, both MIT. Their notices are reproduced in [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md).
@@ -0,0 +1,69 @@
1
+ # Third-party notices
2
+
3
+ This package contains material derived from the projects below. Both are
4
+ distributed under the MIT License, which requires its copyright notice to
5
+ travel with any substantial portion of the work. The notices are reproduced
6
+ here in full.
7
+
8
+ ## Tailwind CSS
9
+
10
+ `tailwind/base/color/palette.css` holds the 286 color values of the Tailwind
11
+ CSS v4.3 default theme. Those colors are unchanged; only the hue component of
12
+ the achromatic steps is written as `0` rather than `none`.
13
+
14
+ The same file adds 52 colors that are not in Tailwind: a 350 and a 750 step
15
+ for each of the 26 hues, each the OKLCH midpoint of the two Tailwind steps
16
+ around it. They are derived from the Tailwind values above.
17
+
18
+ Tailwind CSS is also the framework this package extends.
19
+
20
+ > MIT License
21
+ >
22
+ > Copyright (c) Tailwind Labs, Inc.
23
+ >
24
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
25
+ > of this software and associated documentation files (the "Software"), to deal
26
+ > in the Software without restriction, including without limitation the rights
27
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28
+ > copies of the Software, and to permit persons to whom the Software is
29
+ > furnished to do so, subject to the following conditions:
30
+ >
31
+ > The above copyright notice and this permission notice shall be included in
32
+ > all copies or substantial portions of the Software.
33
+ >
34
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40
+ > SOFTWARE.
41
+
42
+ ## digital-go-jp/tailwind-theme-plugin
43
+
44
+ The typography scale in `tailwind/base/typography/utility.css` follows the
45
+ Digital Agency Design System as published through that plugin. The utilities
46
+ are written from scratch for Tailwind v4; the font sizes, line heights and
47
+ letter spacings come from the plugin's scale.
48
+
49
+ > MIT License
50
+ >
51
+ > Copyright (c) 2023 デジタル庁
52
+ >
53
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
54
+ > of this software and associated documentation files (the "Software"), to deal
55
+ > in the Software without restriction, including without limitation the rights
56
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
57
+ > copies of the Software, and to permit persons to whom the Software is
58
+ > furnished to do so, subject to the following conditions:
59
+ >
60
+ > The above copyright notice and this permission notice shall be included in
61
+ > all copies or substantial portions of the Software.
62
+ >
63
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
64
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
66
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
67
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
68
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
69
+ > SOFTWARE.
@@ -0,0 +1,25 @@
1
+ export type ChromaticColor =
2
+ | 'red' | 'orange' | 'amber' | 'yellow' | 'lime'
3
+ | 'green' | 'emerald' | 'teal' | 'cyan' | 'sky'
4
+ | 'blue' | 'indigo' | 'violet' | 'purple' | 'fuchsia'
5
+ | 'pink' | 'rose';
6
+
7
+ export type BaseColor =
8
+ | 'slate' | 'gray' | 'zinc' | 'neutral' | 'stone'
9
+ | 'mauve' | 'olive' | 'mist' | 'taupe';
10
+
11
+ export type Palette = ChromaticColor | BaseColor;
12
+
13
+ export interface ColorTheme {
14
+ base: Palette;
15
+ primary: Palette;
16
+ secondary: Palette;
17
+ link: Palette;
18
+ }
19
+
20
+ /**
21
+ * Generates the contents of a color theme stylesheet.
22
+ *
23
+ * Returns CSS as a string.
24
+ */
25
+ export declare const generateColorTheme: (theme: ColorTheme) => string;
@@ -0,0 +1,61 @@
1
+ // indent width: 2 half-width spaces
2
+ const INDENT = " ".repeat(2);
3
+
4
+ /**
5
+ * Role token names.
6
+ *
7
+ * These mirror the `--r-<role>-*` custom properties that
8
+ * `theme/color/default.css` defines and `base/color/utility.css`
9
+ * consumes, so generated themes are drop-in replacements for it.
10
+ */
11
+ const ROLE_TOKENS = [
12
+ "bg",
13
+ "bg-subtle",
14
+ "bg-muted",
15
+ "bg-selected",
16
+ "bg-solid",
17
+ "border-subtle",
18
+ "border-muted",
19
+ "border-selected",
20
+ "border",
21
+ "border-solid",
22
+ "fg-strong",
23
+ "fg",
24
+ "fg-muted",
25
+ "fg-subtle",
26
+ "fg-contrast",
27
+ "focus-ring",
28
+ ];
29
+
30
+ const roleBlock = (role, color) => {
31
+ const lines = ROLE_TOKENS.map(
32
+ (t) => `${INDENT}--r-${role}-${t}: var(--c-${color}-${t});`,
33
+ );
34
+ return lines.join("\n");
35
+ };
36
+
37
+ const linkBlock = (color) =>
38
+ [
39
+ `${INDENT}--r-link-fg: var(--c-${color}-fg-muted);`,
40
+ `${INDENT}--r-link-fg-strong: var(--c-${color}-fg);`,
41
+ ].join("\n");
42
+
43
+ /** Generates the contents of a color theme stylesheet. */
44
+ export const generateColorTheme = (theme) => {
45
+ const { base, primary, secondary, link } = theme;
46
+
47
+ return `:root {
48
+ ${INDENT}/* base - ${base} */
49
+ ${roleBlock("base", base)}
50
+
51
+ ${INDENT}/* primary - ${primary} */
52
+ ${roleBlock("primary", primary)}
53
+
54
+ ${INDENT}/* secondary - ${secondary} */
55
+ ${roleBlock("secondary", secondary)}
56
+
57
+ ${INDENT}/* link - ${link} */
58
+ ${linkBlock(link)}
59
+ }
60
+ `;
61
+ };