@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.
@@ -0,0 +1,220 @@
1
+ # 配色の組み合わせ
2
+
3
+ primaryを決めたあとに、secondary・base・linkをどこから選ぶかの一覧である。出発点として使い、最終判断はデザインに委ねる。
4
+
5
+ ## 推奨の組み合わせ表
6
+
7
+ SecondaryとBase (harmonized)は推奨順に並べている。Base (achromatic)とLinkはどの候補を選んでもよく、既定値は列の1番目である。
8
+
9
+ | Primary | Secondary | Base (harmonized) | Base (achromatic) | Link |
10
+ | --------- | ------------------------------- | ------------------- | ------------------- | ---------------------------- |
11
+ | `red` | indigo, fuchsia, purple, violet | taupe, stone | neutral, zinc, gray | indigo, violet, purple, blue |
12
+ | `orange` | indigo, purple, violet, fuchsia | taupe, stone | neutral, zinc, gray | indigo, violet, purple, blue |
13
+ | `amber` | indigo, violet, purple, blue | stone, taupe, olive | neutral, zinc, gray | indigo, violet, purple, blue |
14
+ | `yellow` | indigo, violet, purple, blue | olive, stone | neutral, zinc, gray | indigo, violet, purple, blue |
15
+ | `lime` | indigo, violet, purple, blue | olive, stone | neutral, gray, zinc | indigo, violet, purple, blue |
16
+ | `green` | indigo, blue, violet, purple | olive, mist | neutral, gray, zinc | indigo, violet, purple, blue |
17
+ | `emerald` | indigo, blue, violet, purple | mist, olive | neutral, gray, zinc | indigo, violet, purple, blue |
18
+ | `teal` | lime, orange, amber, yellow | mist, slate | neutral, gray, zinc | indigo, violet, purple, blue |
19
+ | `cyan` | lime, yellow, amber, orange | mist, slate | neutral, gray, zinc | indigo, violet, purple, blue |
20
+ | `sky` | lime, yellow, amber, orange | slate, mist | neutral, gray, zinc | indigo, violet, purple, blue |
21
+ | `blue` | lime, yellow, amber, orange | slate, mist | neutral, gray, zinc | indigo, violet, purple, blue |
22
+ | `indigo` | lime, yellow, amber, orange | slate, mauve | neutral, zinc, gray | indigo, violet, purple, blue |
23
+ | `violet` | yellow, lime, amber, orange | mauve, slate | neutral, zinc, gray | indigo, violet, purple, blue |
24
+ | `purple` | yellow, amber, lime, orange | mauve, slate | neutral, zinc, gray | indigo, violet, purple, blue |
25
+ | `fuchsia` | amber, yellow, orange, lime | mauve, slate | neutral, zinc, gray | indigo, violet, purple, blue |
26
+ | `pink` | orange, amber, yellow, red | mauve, taupe | neutral, zinc, gray | indigo, violet, purple, blue |
27
+ | `rose` | indigo, fuchsia, purple, violet | taupe, stone | neutral, zinc, gray | indigo, violet, purple, blue |
28
+
29
+ ## Secondary の選び方
30
+
31
+ Secondaryは、P型・D型の色覚シミュレーション後でもprimaryとできるだけ離れて見える色を選ぶ。
32
+
33
+ - P型(1型色覚/protan): 赤系の光に対する感度が低い、または欠けるタイプ
34
+ - D型(2型色覚/deutan): 緑系の光に対する感度が低い、または欠けるタイプ
35
+
36
+ primary以外の16色すべてについて、P型・D型に変換した後の色差を、ΔE2000(CIEDE2000)指標を用いて、2色の知覚的な違いを数値化する。0に近いほど似ており、値が大きいほど違って見える。
37
+
38
+ なお、T型(3型色覚/tritan)は、青系の色に対応するが、まれな色覚特性であるため今回の評価からは除外している。
39
+
40
+ 評価には次の4つの表示条件を使う。
41
+
42
+ - ライトモードの`bg-solid`(step 700)
43
+ - ダークモードの`bg-solid`(step 350)
44
+ - ライトモードの`fg-subtle`
45
+ - ダークモードの`fg-subtle`
46
+
47
+ P型・D型それぞれで測るため、合計8条件になる。そのうち最も小さいΔE2000値を、そのprimaryとsecondaryの組み合わせのスコアとする。
48
+
49
+ つまり、ある条件だけで大きく離れて見える色ではなく、P型・D型やライト・ダークをまたいでも安定して見分けやすい色を優先している。
50
+
51
+ そのスコアが大きい順に上位4色をSecondary候補とした。
52
+
53
+ ### P型・D型での見え方
54
+
55
+ 赤と緑を見分けにくい色覚(P型・D型)では、このパレットの多くの色が「黄っぽく見える色」と「青っぽく見える色」に大きく分かれる。
56
+
57
+ - 黄グループ: `rose`, `red`, `orange`, `amber`, `yellow`, `lime`, `green`, `emerald`
58
+ - 青グループ: `cyan`, `sky`, `blue`, `indigo`, `violet`, `purple`, `fuchsia`
59
+ - 境界にある色: `teal`, `pink`
60
+
61
+ `teal`と`pink`はP型とD型で見え方の方向が異なるため、どちらか一方のグループには固定していない。
62
+
63
+ 同じ側にある色どうしはP型・D型への変換後に色相差が小さくなり、主に明るさや鮮やかさの違いとして知覚されやすい。たとえば`red`と`green`は、通常色覚では大きく異なるが、P型・D型ではどちらも黄寄りに見える。
64
+
65
+ ### 数値での評価
66
+
67
+ P型・D型の見え方の変換にはMachado et al. (2009) の行列を使う。severityは1.0で、Chromium DevToolsの色覚エミュレーションで使われている行列と同じものである。
68
+
69
+ 変換手順は次のとおり。
70
+
71
+ ```text
72
+ OKLCH
73
+ → sRGB 8bit
74
+ → 線形RGB
75
+ → Machado 2009 行列
76
+ → CIELAB
77
+ → ΔE2000
78
+ ```
79
+
80
+ 2色の違いはΔE2000で測る。0に近いほど似ており、値が大きいほど離れている。
81
+
82
+ この評価では、十分な余裕を持たせるため20以上をひとつの目安としている。これはP型・D型における一般的な知覚閾値を意味するものではなく、この配色評価のための基準である。
83
+
84
+ 評価には、実際にsemantic tokenが参照する次の条件を使う。
85
+
86
+ - ライトモードの`bg-solid`: step 700
87
+ - ダークモードの`bg-solid`: step 350
88
+ - ライトモードの`fg-subtle`: 色ごとにstep 500または600
89
+ - ダークモードの`fg-subtle`: 色ごとにstep 500または600
90
+
91
+ P型・D型それぞれについて4つの表示条件を測り、8条件のうち最も小さいΔE2000をその組み合わせの値とする。
92
+
93
+ 代表的な結果は次のとおり。
94
+
95
+ - `teal`と`pink`を除く15色では、表の上位4候補はすべて26以上(`rose`が26〜27、`red`と`emerald`が35前後、ほかは40以上)
96
+ - `teal`では23〜24程度
97
+ - `pink`では最大でも16程度
98
+ - `red` × `green`: 6
99
+ - `orange` × `green`: 7
100
+ - `rose` × `green`: 3
101
+
102
+ `pink`は、この評価で採用した20の目安を満たすSecondary候補がない。PrimaryとSecondaryを色だけで明確に区別する必要がある用途では注意が必要である。
103
+
104
+ ## Base の選び方
105
+
106
+ Baseは、primaryに色みを寄せるharmonizedと、色みを抑えるachromaticの2系統から選ぶ。
107
+
108
+ ### harmonized — primaryに寄せた灰色
109
+
110
+ primaryと色相の近い灰色を選ぶ。画面全体に統一感を持たせながら、地の色としては灰色に近い見た目を保つ。
111
+
112
+ 候補は次の6色である。
113
+
114
+ - `taupe`
115
+ - `stone`
116
+ - `olive`
117
+ - `mist`
118
+ - `slate`
119
+ - `mauve`
120
+
121
+ 順位にはstep 500のOKLCH hueを使い、primaryとの色相角の差が小さい順に並べる。
122
+
123
+ 候補には常に上位2色を載せる。3番目の色もprimaryとの色相差が40°以内であれば候補に加える。
124
+
125
+ ### achromatic — 色みを抑えた灰色
126
+
127
+ primaryを灰色の上で目立たせたい場合や、画面内ですでに多くの色を使っている場合に使う。
128
+
129
+ 候補は次の3色で固定する。
130
+
131
+ - `neutral`
132
+ - `zinc`
133
+ - `gray`
134
+
135
+ 既定値は色みを持たない`neutral`である。
136
+
137
+ 残りの`zinc`と`gray`は、step 500のOKLCH hueがprimaryから近い順に並べる。順位は選択時の参考であり、どちらを使ってもよい。
138
+
139
+ ## Link の選び方
140
+
141
+ Linkはprimaryとは独立して選ぶ。
142
+
143
+ `link-fg`と`link-fg-strong`の2トークンを使い、それぞれ選んだ色の`fg-muted`と`fg`を参照する。
144
+
145
+ 表に載せた4色で、参照するstepは次のとおり。
146
+
147
+ | Mode | `link-fg` | `link-fg-strong` |
148
+ | ----- | --------- | ---------------- |
149
+ | Light | 600 | 700 |
150
+ | Dark | 400 (indigoのみ350) | 300 |
151
+
152
+ ### Link の順位
153
+
154
+ 各色について、P型・D型変換後のリンク色と本文色との差を測る。
155
+
156
+ 評価対象は次の4条件である。
157
+
158
+ - Lightの`link-fg`
159
+ - Lightの`link-fg-strong`
160
+ - Darkの`link-fg`
161
+ - Darkの`link-fg-strong`
162
+
163
+ さらにP型・D型の両方を評価し、その中で最も小さいΔE2000をその色の値とする。
164
+
165
+ 青グループの結果は次のとおり。
166
+
167
+ - `indigo`: 23
168
+ - `violet`: 22
169
+ - `purple`: 20
170
+ - `blue`: 20
171
+ - `sky`: 17
172
+ - `cyan`: 12
173
+ - `teal`: 5
174
+
175
+ このうち上位4色を候補として表に載せる。
176
+
177
+ - `indigo`, `violet`, `purple`, `blue`
178
+
179
+ 既定値は`indigo`である。
180
+
181
+ どの候補でも、最小値はダークモードのhover時に使うstep 300で発生する。
182
+
183
+ 黄グループでは`lime`、`yellow`、`amber`もダークモードで本文との色差を取りやすい。ただし、一般的なリンク色としての慣習を優先し、標準候補には含めていない。ダークモード主体のUIでは選択肢になり得る。
184
+
185
+ 一方、`red`、`rose`、`teal`、`pink`はP型・D型変換後に本文との差が小さくなりやすいため、リンク色としては避ける。特に`teal`はダークモードで無彩色に近づき、本文との差が小さくなる。
186
+
187
+ ### 色以外でもリンクを示す
188
+
189
+ リンクは下線など、色以外の視覚的な目印を付ける前提とする。
190
+
191
+ WCAG 2.2 Success Criterion 1.4.1 Use of Colorに従い、色だけでリンクであることを伝えない。
192
+
193
+ ## ステータスカラーとの競合
194
+
195
+ ステータスカラーは慣例に沿って次の色を使う。
196
+
197
+ - Error: `red`
198
+ - Warning: `amber`
199
+ - Success: `green`
200
+ - Info: `blue`
201
+
202
+ PrimaryやSecondaryがこれらと同色または近い色になる場合、ブランド表現と状態表現を色だけでは区別しにくくなる。
203
+
204
+ 特に`red`、`amber`、`green`、`blue`はステータスカラーと直接競合する。`rose`や`orange`などの近似色も、用途によっては同じ意味の色に見えることがある。
205
+
206
+ ### 回避策
207
+
208
+ 1. ステータス色とブランド色を近接して配置しない。
209
+ 2. アイコン、形状、ラベルなど色以外の視覚要素を併用する。
210
+ 3. 必要に応じてステータスカラーの変数を個別に上書きする。
211
+ 4. Warningでは、黄と黒の高コントラストな意匠を使う方法もある。
212
+
213
+ 色だけで状態を伝えず、意味の違いを他の視覚表現でも示すことを基本とする。
214
+
215
+ ## 参考文献
216
+
217
+ - カラーユニバーサルデザイン機構(CUDO)『カラーユニバーサルデザイン推奨配色セット ガイドブック』ver.4、2018年。[配布ページ](https://jfly.uni-koeln.de/colorset/)
218
+ - Machado, G. M., Oliveira, M. M., Fernandes, L. A. F. (2009). A Physiologically-based Model for Simulation of Color Vision Deficiency. _IEEE TVCG_ 15(6)
219
+ - Chromium, [Simulating color vision deficiencies in the Blink Renderer](https://developer.chrome.com/docs/chromium/cvd)
220
+ - W3C, [WCAG 2.2 Success Criterion 1.4.1 Use of Color](https://www.w3.org/TR/WCAG22/#use-of-color)
@@ -0,0 +1,138 @@
1
+ {
2
+ "red": {
3
+ "secondary": ["indigo", "fuchsia", "purple", "violet"],
4
+ "base": {
5
+ "harmonized": ["taupe", "stone"],
6
+ "achromatic": ["neutral", "zinc", "gray"]
7
+ },
8
+ "link": ["indigo", "violet", "purple", "blue"]
9
+ },
10
+ "orange": {
11
+ "secondary": ["indigo", "purple", "violet", "fuchsia"],
12
+ "base": {
13
+ "harmonized": ["taupe", "stone"],
14
+ "achromatic": ["neutral", "zinc", "gray"]
15
+ },
16
+ "link": ["indigo", "violet", "purple", "blue"]
17
+ },
18
+ "amber": {
19
+ "secondary": ["indigo", "violet", "purple", "blue"],
20
+ "base": {
21
+ "harmonized": ["stone", "taupe", "olive"],
22
+ "achromatic": ["neutral", "zinc", "gray"]
23
+ },
24
+ "link": ["indigo", "violet", "purple", "blue"]
25
+ },
26
+ "yellow": {
27
+ "secondary": ["indigo", "violet", "purple", "blue"],
28
+ "base": {
29
+ "harmonized": ["olive", "stone"],
30
+ "achromatic": ["neutral", "zinc", "gray"]
31
+ },
32
+ "link": ["indigo", "violet", "purple", "blue"]
33
+ },
34
+ "lime": {
35
+ "secondary": ["indigo", "violet", "purple", "blue"],
36
+ "base": {
37
+ "harmonized": ["olive", "stone"],
38
+ "achromatic": ["neutral", "gray", "zinc"]
39
+ },
40
+ "link": ["indigo", "violet", "purple", "blue"]
41
+ },
42
+ "green": {
43
+ "secondary": ["indigo", "blue", "violet", "purple"],
44
+ "base": {
45
+ "harmonized": ["olive", "mist"],
46
+ "achromatic": ["neutral", "gray", "zinc"]
47
+ },
48
+ "link": ["indigo", "violet", "purple", "blue"]
49
+ },
50
+ "emerald": {
51
+ "secondary": ["indigo", "blue", "violet", "purple"],
52
+ "base": {
53
+ "harmonized": ["mist", "olive"],
54
+ "achromatic": ["neutral", "gray", "zinc"]
55
+ },
56
+ "link": ["indigo", "violet", "purple", "blue"]
57
+ },
58
+ "teal": {
59
+ "secondary": ["lime", "orange", "amber", "yellow"],
60
+ "base": {
61
+ "harmonized": ["mist", "slate"],
62
+ "achromatic": ["neutral", "gray", "zinc"]
63
+ },
64
+ "link": ["indigo", "violet", "purple", "blue"]
65
+ },
66
+ "cyan": {
67
+ "secondary": ["lime", "yellow", "amber", "orange"],
68
+ "base": {
69
+ "harmonized": ["mist", "slate"],
70
+ "achromatic": ["neutral", "gray", "zinc"]
71
+ },
72
+ "link": ["indigo", "violet", "purple", "blue"]
73
+ },
74
+ "sky": {
75
+ "secondary": ["lime", "yellow", "amber", "orange"],
76
+ "base": {
77
+ "harmonized": ["slate", "mist"],
78
+ "achromatic": ["neutral", "gray", "zinc"]
79
+ },
80
+ "link": ["indigo", "violet", "purple", "blue"]
81
+ },
82
+ "blue": {
83
+ "secondary": ["lime", "yellow", "amber", "orange"],
84
+ "base": {
85
+ "harmonized": ["slate", "mist"],
86
+ "achromatic": ["neutral", "gray", "zinc"]
87
+ },
88
+ "link": ["indigo", "violet", "purple", "blue"]
89
+ },
90
+ "indigo": {
91
+ "secondary": ["lime", "yellow", "amber", "orange"],
92
+ "base": {
93
+ "harmonized": ["slate", "mauve"],
94
+ "achromatic": ["neutral", "zinc", "gray"]
95
+ },
96
+ "link": ["indigo", "violet", "purple", "blue"]
97
+ },
98
+ "violet": {
99
+ "secondary": ["yellow", "lime", "amber", "orange"],
100
+ "base": {
101
+ "harmonized": ["mauve", "slate"],
102
+ "achromatic": ["neutral", "zinc", "gray"]
103
+ },
104
+ "link": ["indigo", "violet", "purple", "blue"]
105
+ },
106
+ "purple": {
107
+ "secondary": ["yellow", "amber", "lime", "orange"],
108
+ "base": {
109
+ "harmonized": ["mauve", "slate"],
110
+ "achromatic": ["neutral", "zinc", "gray"]
111
+ },
112
+ "link": ["indigo", "violet", "purple", "blue"]
113
+ },
114
+ "fuchsia": {
115
+ "secondary": ["amber", "yellow", "orange", "lime"],
116
+ "base": {
117
+ "harmonized": ["mauve", "slate"],
118
+ "achromatic": ["neutral", "zinc", "gray"]
119
+ },
120
+ "link": ["indigo", "violet", "purple", "blue"]
121
+ },
122
+ "pink": {
123
+ "secondary": ["orange", "amber", "yellow", "red"],
124
+ "base": {
125
+ "harmonized": ["mauve", "taupe"],
126
+ "achromatic": ["neutral", "zinc", "gray"]
127
+ },
128
+ "link": ["indigo", "violet", "purple", "blue"]
129
+ },
130
+ "rose": {
131
+ "secondary": ["indigo", "fuchsia", "purple", "violet"],
132
+ "base": {
133
+ "harmonized": ["taupe", "stone"],
134
+ "achromatic": ["neutral", "zinc", "gray"]
135
+ },
136
+ "link": ["indigo", "violet", "purple", "blue"]
137
+ }
138
+ }
@@ -0,0 +1,19 @@
1
+ # Color theme generation
2
+
3
+ `generateColorTheme` is a function that returns CSS as a string, allowing the application to generate its own custom themes. A sample showing how to write the output to a file is provided below.
4
+
5
+ ```js
6
+ import { writeFile } from 'node:fs/promises';
7
+ import { generateColorTheme } from '@kazamitte/design-token';
8
+
9
+ const css = generateColorTheme({
10
+ primary: 'teal',
11
+ secondary: 'violet',
12
+ base: 'mist',
13
+ link: 'blue',
14
+ });
15
+
16
+ await writeFile('src/styles/generated/theme.css', css);
17
+ ```
18
+
19
+ For information on color pairings, please refer to [color-pairings.md](./color-pairings.md). It lists recommended secondary, base, and link colors for each of the 17 primary colors.
@@ -0,0 +1,180 @@
1
+ # Fixing class conflicts with tailwind-merge
2
+
3
+ - Classes made with the `@utility` directive are invisible to tailwind-merge. By default `text-body-16` and `text-dense-14` do not cancel each other.
4
+ - Semantic names generated from a `@theme` namespace have the same problem. `rounded-surface`, `shadow-raised`, `ease-standard`, `animate-fade-in` and `z-modal` are not on a scale tailwind-merge knows.
5
+ - `conflictingClassGroups` copies what Tailwind's own `text-lg` does: a later `text-*` cancels an earlier `leading-*`.
6
+
7
+ ## Use tailwind-merge's own group names
8
+
9
+ Every key in `extend.classGroups` **must match an existing group name exactly**. A key that does not match adds a new group instead of extending the old one.
10
+
11
+ Say you write `'transition-duration'`. Then `duration-instant` and `duration-enter` do cancel each other, but they sit in a different group from Tailwind's `duration-200`, so `duration-200 duration-transition` keeps both classes. The correct key is `'duration'`.
12
+
13
+ Read the keys of `getDefaultConfig().classGroups` to check a name. These are the ones this package needs.
14
+
15
+ | Token | Group name |
16
+ | ---------------------------- | --------------- |
17
+ | `text-body-16` and the rest | `font-size` |
18
+ | `rounded-surface` and so on | `rounded` |
19
+ | `shadow-raised` and so on | `shadow` |
20
+ | `duration-enter` and so on | `duration` |
21
+ | `ease-standard` and so on | `ease` |
22
+ | `animate-fade-in` and so on | `animate` |
23
+ | `z-modal` and so on | `z` |
24
+ | `primary-bg-solid` and so on | `bg-color` |
25
+ | `primary-fg` and so on | `text-color` |
26
+ | `primary-border-solid` … | `border-color` |
27
+ | `primary-focus-ring` … | `outline-color` |
28
+
29
+ Two of these are easy to get wrong: the z-index group is `z`, not `z-index`, and the font size group is `font-size`, not `text`.
30
+
31
+ `animate-*` can also be registered through `extend.theme.animate`, which tailwind-merge reads as a scale. The config below uses `classGroups` for it so that every token is registered the same way. There is no theme key for z-index, so `z` has to go through `classGroups` in any case.
32
+
33
+ ## Color roles need their full class names
34
+
35
+ A color role utility is named `{role}-{token}`, so its prefix is not Tailwind's `bg-*` or `text-*`. The short form (`{ bg: [...] }`) cannot say that, so the full class names are listed instead.
36
+
37
+ Without them an override like `tv({ base: 'primary-bg-solid', variants: { disabled: { true: 'base-bg-muted' } } })` does nothing. Both classes stay, and the CSS order decides which one wins.
38
+
39
+ ## Config
40
+
41
+ ```ts
42
+ import { createTV, type VariantProps } from 'tailwind-variants';
43
+
44
+ const ROLES = [
45
+ 'base',
46
+ 'primary',
47
+ 'secondary',
48
+ 'error',
49
+ 'warning',
50
+ 'success',
51
+ 'info',
52
+ ];
53
+
54
+ const roleClasses = (suffixes: string[]) =>
55
+ ROLES.flatMap((role) => suffixes.map((suffix) => `${role}-${suffix}`));
56
+
57
+ export const tv = createTV({
58
+ twMerge: true,
59
+ twMergeConfig: {
60
+ extend: {
61
+ classGroups: {
62
+ 'font-size': [
63
+ {
64
+ text: [
65
+ 'display-64',
66
+ 'display-56',
67
+ 'display-48',
68
+ 'display-44',
69
+ 'highlight-36',
70
+ 'highlight-32',
71
+ 'highlight-28',
72
+ 'highlight-26',
73
+ 'highlight-24',
74
+ 'highlight-22',
75
+ 'body-20',
76
+ 'body-18',
77
+ 'body-16',
78
+ 'dense-18',
79
+ 'dense-16',
80
+ 'dense-14',
81
+ 'dense-18-compact',
82
+ 'dense-16-compact',
83
+ 'dense-14-compact',
84
+ 'oneline-18',
85
+ 'oneline-16',
86
+ 'oneline-14',
87
+ 'mono-18',
88
+ 'mono-16',
89
+ 'mono-14',
90
+ ],
91
+ },
92
+ ],
93
+ duration: [{ duration: ['instant', 'transition', 'enter'] }],
94
+ rounded: [
95
+ { rounded: ['tight', 'control', 'surface', 'overlay', 'pill'] },
96
+ ],
97
+ shadow: [
98
+ {
99
+ shadow: [
100
+ 'flat',
101
+ 'flat-hover',
102
+ 'raised',
103
+ 'raised-hover',
104
+ 'floating',
105
+ 'floating-hover',
106
+ 'overlay',
107
+ ],
108
+ },
109
+ ],
110
+ ease: [{ ease: ['standard', 'emphasized'] }],
111
+ animate: [
112
+ {
113
+ animate: [
114
+ 'fade-in',
115
+ 'fade-out',
116
+ 'scale-in',
117
+ 'scale-out',
118
+ 'slide-in-from-top',
119
+ 'slide-in-from-right',
120
+ 'slide-in-from-bottom',
121
+ 'slide-in-from-left',
122
+ 'slide-out-to-top',
123
+ 'slide-out-to-right',
124
+ 'slide-out-to-bottom',
125
+ 'slide-out-to-left',
126
+ ],
127
+ },
128
+ ],
129
+ z: [
130
+ {
131
+ z: [
132
+ 'hide',
133
+ 'base',
134
+ 'docked',
135
+ 'dropdown',
136
+ 'sticky',
137
+ 'banner',
138
+ 'overlay',
139
+ 'modal',
140
+ 'popover',
141
+ 'skip-nav',
142
+ 'toast',
143
+ 'tooltip',
144
+ 'max',
145
+ ],
146
+ },
147
+ ],
148
+
149
+ 'bg-color': roleClasses([
150
+ 'bg',
151
+ 'bg-subtle',
152
+ 'bg-muted',
153
+ 'bg-selected',
154
+ 'bg-solid',
155
+ ]),
156
+ 'text-color': [
157
+ ...roleClasses(['fg-strong', 'fg', 'fg-muted', 'fg-subtle', 'fg-contrast']),
158
+ 'link-fg',
159
+ 'link-fg-strong',
160
+ ],
161
+ 'border-color': roleClasses([
162
+ 'border-subtle',
163
+ 'border-muted',
164
+ 'border-selected',
165
+ 'border',
166
+ 'border-solid',
167
+ ]),
168
+ 'outline-color': roleClasses(['focus-ring']),
169
+ },
170
+ conflictingClassGroups: {
171
+ 'font-size': ['leading'],
172
+ },
173
+ },
174
+ },
175
+ });
176
+
177
+ export type { VariantProps };
178
+ ```
179
+
180
+ `example/src/lib/tv.test.ts` checks two things for every group: that the classes in it cancel each other, and that pairs which must **not** cancel both survive — `text-red-500` with `text-body-16`, `shadow-red-500` with `shadow-raised`, `animate-slide-in-from-bottom` with `[--slide-distance:1rem]`.
package/package.json CHANGED
@@ -1,6 +1,46 @@
1
1
  {
2
2
  "name": "@kazamitte/design-token",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.4.0",
4
+ "description": "Tailwind CSS v4 design token — color, typography, and style themes.",
5
+ "license": "MIT",
6
+ "author": "kazaminn",
7
+ "homepage": "https://github.com/kazamitte/design-token#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kazamitte/design-token.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/kazamitte/design-token/issues"
14
+ },
15
+ "type": "module",
16
+ "sideEffects": [
17
+ "*.css"
18
+ ],
19
+ "files": [
20
+ "dist",
21
+ "docs",
22
+ "tailwind",
23
+ "THIRD-PARTY-NOTICES.md"
24
+ ],
25
+ "types": "./dist/generate-theme.d.mts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/generate-theme.d.mts",
29
+ "import": "./dist/generate-theme.mjs"
30
+ },
31
+ "./index.css": "./tailwind/index.css",
32
+ "./base/initialize.css": "./tailwind/base/initialize.css",
33
+ "./base/color/*.css": "./tailwind/base/color/*.css",
34
+ "./base/typography/*.css": "./tailwind/base/typography/*.css",
35
+ "./base/style/*.css": "./tailwind/base/style/*.css",
36
+ "./theme/color/*.css": "./tailwind/theme/color/*.css",
37
+ "./theme/style/*.css": "./tailwind/theme/style/*.css",
38
+ "./package.json": "./package.json"
39
+ },
40
+ "peerDependencies": {
41
+ "tailwindcss": "^4.0.0"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
6
46
  }