@tangle-network/brand 1.16.0 → 1.17.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ffd18ec: `palettes` exports Brand's resolved colors (light, dark, websiteLight, websiteDark) for renderers that cannot read CSS variables, such as PDF, canvas, WebGL, email and the theme-color meta. `scripts/gen-palette.mjs` generates them from tokens.css and named-themes.css, and the build fails when they are stale.
8
+
3
9
  ## 1.16.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -101,6 +101,8 @@ import { Logo, TangleKnot } from "@tangle-network/brand";
101
101
 
102
102
  ## Palette and typography
103
103
 
104
+ Renderers that cannot read CSS variables (PDF, canvas, WebGL, email, the `theme-color` meta) import `palettes` from `@tangle-network/brand`: resolved hex values for `light`, `dark`, `websiteLight` and `websiteDark`, generated from the stylesheets by `pnpm gen:palette`. Pages styled with CSS keep using the variables.
105
+
104
106
  The base surface ladder is the one GTM proved out: dark is indigo-lifted `#0a0a14` / `#191826` / `#221f33` / `#2c2942`; light is a cool `#eceef3` canvas, white paper cards and overlays, and `#f1f2f7` nested wells. The cast stays below 0.1 chroma and ink stays achromatic, so indigo still reads as the interaction accent, not the base field. Existing named products may supply deliberate surface overrides.
105
107
 
106
108
  Chrome radii are 6/8/10/12px in both base modes; the composer has its own 26px role. Inter leads body and display stacks, with Geist fallbacks; Geist Mono leads code with JetBrains Mono and system fallbacks. Runtime font/radius registrations retain their public override names; tests keep Tailwind registration defaults aligned with the canonical declarations.
package/dist/index.d.ts CHANGED
@@ -12,4 +12,175 @@ export declare function TangleKnot({ size, className }: {
12
12
  }): React.JSX.Element;
13
13
  export declare function Logo({ size, variant, suffix, className }: LogoProps): React.JSX.Element;
14
14
  //#endregion
15
- export type { LogoProps };
15
+ //#region src/palette.generated.d.ts
16
+ /** A theme's resolved roles: hex strings, or rgba() where the token is translucent. */
17
+ interface BrandPalette {
18
+ canvas: string;
19
+ card: string;
20
+ well: string;
21
+ nested: string;
22
+ overlay: string;
23
+ deepest: string;
24
+ hairline: string;
25
+ ink: string;
26
+ inkSecondary: string;
27
+ inkMuted: string;
28
+ accent: string;
29
+ accentHover: string;
30
+ onAccent: string;
31
+ accentText: string;
32
+ danger: string;
33
+ successBg: string;
34
+ successBorder: string;
35
+ successText: string;
36
+ warningBg: string;
37
+ warningBorder: string;
38
+ warningText: string;
39
+ dangerBg: string;
40
+ dangerBorder: string;
41
+ dangerText: string;
42
+ infoBg: string;
43
+ infoBorder: string;
44
+ infoText: string;
45
+ brandVibrant: string;
46
+ brandCool: string;
47
+ brandGlow: string;
48
+ brandPurple: string;
49
+ }
50
+ /** Resolved palettes for the canonical light and dark themes and the website named theme. */
51
+ export declare const palettes: {
52
+ readonly light: {
53
+ readonly canvas: "#eceef3";
54
+ readonly card: "#ffffff";
55
+ readonly well: "#f6f7fa";
56
+ readonly nested: "#f1f2f7";
57
+ readonly overlay: "#ffffff";
58
+ readonly deepest: "#ffffff";
59
+ readonly hairline: "#c7c6d6";
60
+ readonly ink: "#2d2d2d";
61
+ readonly inkSecondary: "#3f3f3f";
62
+ readonly inkMuted: "#4c4c4c";
63
+ readonly accent: "#4c3fc5";
64
+ readonly accentHover: "#5a50d6";
65
+ readonly onAccent: "#ffffff";
66
+ readonly accentText: "#3c32e9";
67
+ readonly danger: "#b41d1d";
68
+ readonly successBg: "#ecfdf5";
69
+ readonly successBorder: "#a7f3d0";
70
+ readonly successText: "#047857";
71
+ readonly warningBg: "#fffbeb";
72
+ readonly warningBorder: "#fde68a";
73
+ readonly warningText: "#ab4f09";
74
+ readonly dangerBg: "#fff1f2";
75
+ readonly dangerBorder: "#fecdd3";
76
+ readonly dangerText: "#b91c1c";
77
+ readonly infoBg: "#f0f9ff";
78
+ readonly infoBorder: "#bae6fd";
79
+ readonly infoText: "#0369a1";
80
+ readonly brandVibrant: "#6366f1";
81
+ readonly brandCool: "#818cf8";
82
+ readonly brandGlow: "#a5aafc";
83
+ readonly brandPurple: "#6366f1";
84
+ };
85
+ readonly dark: {
86
+ readonly canvas: "#0a0a14";
87
+ readonly card: "#191826";
88
+ readonly well: "#12111f";
89
+ readonly nested: "#221f33";
90
+ readonly overlay: "#2c2942";
91
+ readonly deepest: "#050509";
92
+ readonly hairline: "#2a293d";
93
+ readonly ink: "#e6e6e6";
94
+ readonly inkSecondary: "#c7c7c7";
95
+ readonly inkMuted: "#b5b5b5";
96
+ readonly accent: "#4c3fc5";
97
+ readonly accentHover: "#5a50d6";
98
+ readonly onAccent: "#ffffff";
99
+ readonly accentText: "#a5b4fc";
100
+ readonly danger: "#d52044";
101
+ readonly successBg: "#2f5146";
102
+ readonly successBorder: "#3c7760";
103
+ readonly successText: "#5ed7a4";
104
+ readonly warningBg: "#4b4232";
105
+ readonly warningBorder: "#7a6236";
106
+ readonly warningText: "#f4c14f";
107
+ readonly dangerBg: "#5a3b40";
108
+ readonly dangerBorder: "#7d4d53";
109
+ readonly dangerText: "#ffada9";
110
+ readonly infoBg: "#2d4e67";
111
+ readonly infoBorder: "#3d7292";
112
+ readonly infoText: "#67cdff";
113
+ readonly brandVibrant: "#6366f1";
114
+ readonly brandCool: "#818cf8";
115
+ readonly brandGlow: "#a5aafc";
116
+ readonly brandPurple: "#c7d2fe";
117
+ };
118
+ readonly websiteLight: {
119
+ readonly canvas: "#f5f5fb";
120
+ readonly card: "#ffffff";
121
+ readonly well: "#fafafd";
122
+ readonly nested: "#ececf6";
123
+ readonly overlay: "#ffffff";
124
+ readonly deepest: "#ffffff";
125
+ readonly hairline: "#dbdbea";
126
+ readonly ink: "#191c24";
127
+ readonly inkSecondary: "#3a3a50";
128
+ readonly inkMuted: "#5e5e7a";
129
+ readonly accent: "#4c3fc5";
130
+ readonly accentHover: "#5a50d6";
131
+ readonly onAccent: "#ffffff";
132
+ readonly accentText: "#3c32e9";
133
+ readonly danger: "#b41d1d";
134
+ readonly successBg: "#ecfdf5";
135
+ readonly successBorder: "#a7f3d0";
136
+ readonly successText: "#047857";
137
+ readonly warningBg: "#fffbeb";
138
+ readonly warningBorder: "#fde68a";
139
+ readonly warningText: "#ab4f09";
140
+ readonly dangerBg: "#fff1f2";
141
+ readonly dangerBorder: "#fecdd3";
142
+ readonly dangerText: "#b91c1c";
143
+ readonly infoBg: "#f0f9ff";
144
+ readonly infoBorder: "#bae6fd";
145
+ readonly infoText: "#0369a1";
146
+ readonly brandVibrant: "#6366f1";
147
+ readonly brandCool: "#818cf8";
148
+ readonly brandGlow: "#a5aafc";
149
+ readonly brandPurple: "#6366f1";
150
+ };
151
+ readonly websiteDark: {
152
+ readonly canvas: "#0c0b1d";
153
+ readonly card: "#1d1b38";
154
+ readonly well: "#141328";
155
+ readonly nested: "#222041";
156
+ readonly overlay: "#262448";
157
+ readonly deepest: "#080814";
158
+ readonly hairline: "#33315f";
159
+ readonly ink: "#fdfdfd";
160
+ readonly inkSecondary: "#aaa8b8";
161
+ readonly inkMuted: "#9496bc";
162
+ readonly accent: "#4c3fc5";
163
+ readonly accentHover: "#5a50d6";
164
+ readonly onAccent: "#ffffff";
165
+ readonly accentText: "#a5b4fc";
166
+ readonly danger: "#d52044";
167
+ readonly successBg: "#2f5146";
168
+ readonly successBorder: "#3c7760";
169
+ readonly successText: "#5ed7a4";
170
+ readonly warningBg: "#4b4232";
171
+ readonly warningBorder: "#7a6236";
172
+ readonly warningText: "#f4c14f";
173
+ readonly dangerBg: "#5a3b40";
174
+ readonly dangerBorder: "#7d4d53";
175
+ readonly dangerText: "#ffada9";
176
+ readonly infoBg: "#2d4e67";
177
+ readonly infoBorder: "#3d7292";
178
+ readonly infoText: "#67cdff";
179
+ readonly brandVibrant: "#6366f1";
180
+ readonly brandCool: "#818cf8";
181
+ readonly brandGlow: "#a5aafc";
182
+ readonly brandPurple: "#c7d2fe";
183
+ };
184
+ };
185
+ //#endregion
186
+ export type { BrandPalette, LogoProps };
package/dist/index.js CHANGED
@@ -105,4 +105,141 @@ function Logo({ size = "md", variant = "full", suffix = null, className }) {
105
105
  });
106
106
  }
107
107
  //#endregion
108
- export { Logo, TangleKnot };
108
+ //#region src/palette.generated.ts
109
+ /** Resolved palettes for the canonical light and dark themes and the website named theme. */
110
+ const palettes = {
111
+ light: {
112
+ canvas: "#eceef3",
113
+ card: "#ffffff",
114
+ well: "#f6f7fa",
115
+ nested: "#f1f2f7",
116
+ overlay: "#ffffff",
117
+ deepest: "#ffffff",
118
+ hairline: "#c7c6d6",
119
+ ink: "#2d2d2d",
120
+ inkSecondary: "#3f3f3f",
121
+ inkMuted: "#4c4c4c",
122
+ accent: "#4c3fc5",
123
+ accentHover: "#5a50d6",
124
+ onAccent: "#ffffff",
125
+ accentText: "#3c32e9",
126
+ danger: "#b41d1d",
127
+ successBg: "#ecfdf5",
128
+ successBorder: "#a7f3d0",
129
+ successText: "#047857",
130
+ warningBg: "#fffbeb",
131
+ warningBorder: "#fde68a",
132
+ warningText: "#ab4f09",
133
+ dangerBg: "#fff1f2",
134
+ dangerBorder: "#fecdd3",
135
+ dangerText: "#b91c1c",
136
+ infoBg: "#f0f9ff",
137
+ infoBorder: "#bae6fd",
138
+ infoText: "#0369a1",
139
+ brandVibrant: "#6366f1",
140
+ brandCool: "#818cf8",
141
+ brandGlow: "#a5aafc",
142
+ brandPurple: "#6366f1"
143
+ },
144
+ dark: {
145
+ canvas: "#0a0a14",
146
+ card: "#191826",
147
+ well: "#12111f",
148
+ nested: "#221f33",
149
+ overlay: "#2c2942",
150
+ deepest: "#050509",
151
+ hairline: "#2a293d",
152
+ ink: "#e6e6e6",
153
+ inkSecondary: "#c7c7c7",
154
+ inkMuted: "#b5b5b5",
155
+ accent: "#4c3fc5",
156
+ accentHover: "#5a50d6",
157
+ onAccent: "#ffffff",
158
+ accentText: "#a5b4fc",
159
+ danger: "#d52044",
160
+ successBg: "#2f5146",
161
+ successBorder: "#3c7760",
162
+ successText: "#5ed7a4",
163
+ warningBg: "#4b4232",
164
+ warningBorder: "#7a6236",
165
+ warningText: "#f4c14f",
166
+ dangerBg: "#5a3b40",
167
+ dangerBorder: "#7d4d53",
168
+ dangerText: "#ffada9",
169
+ infoBg: "#2d4e67",
170
+ infoBorder: "#3d7292",
171
+ infoText: "#67cdff",
172
+ brandVibrant: "#6366f1",
173
+ brandCool: "#818cf8",
174
+ brandGlow: "#a5aafc",
175
+ brandPurple: "#c7d2fe"
176
+ },
177
+ websiteLight: {
178
+ canvas: "#f5f5fb",
179
+ card: "#ffffff",
180
+ well: "#fafafd",
181
+ nested: "#ececf6",
182
+ overlay: "#ffffff",
183
+ deepest: "#ffffff",
184
+ hairline: "#dbdbea",
185
+ ink: "#191c24",
186
+ inkSecondary: "#3a3a50",
187
+ inkMuted: "#5e5e7a",
188
+ accent: "#4c3fc5",
189
+ accentHover: "#5a50d6",
190
+ onAccent: "#ffffff",
191
+ accentText: "#3c32e9",
192
+ danger: "#b41d1d",
193
+ successBg: "#ecfdf5",
194
+ successBorder: "#a7f3d0",
195
+ successText: "#047857",
196
+ warningBg: "#fffbeb",
197
+ warningBorder: "#fde68a",
198
+ warningText: "#ab4f09",
199
+ dangerBg: "#fff1f2",
200
+ dangerBorder: "#fecdd3",
201
+ dangerText: "#b91c1c",
202
+ infoBg: "#f0f9ff",
203
+ infoBorder: "#bae6fd",
204
+ infoText: "#0369a1",
205
+ brandVibrant: "#6366f1",
206
+ brandCool: "#818cf8",
207
+ brandGlow: "#a5aafc",
208
+ brandPurple: "#6366f1"
209
+ },
210
+ websiteDark: {
211
+ canvas: "#0c0b1d",
212
+ card: "#1d1b38",
213
+ well: "#141328",
214
+ nested: "#222041",
215
+ overlay: "#262448",
216
+ deepest: "#080814",
217
+ hairline: "#33315f",
218
+ ink: "#fdfdfd",
219
+ inkSecondary: "#aaa8b8",
220
+ inkMuted: "#9496bc",
221
+ accent: "#4c3fc5",
222
+ accentHover: "#5a50d6",
223
+ onAccent: "#ffffff",
224
+ accentText: "#a5b4fc",
225
+ danger: "#d52044",
226
+ successBg: "#2f5146",
227
+ successBorder: "#3c7760",
228
+ successText: "#5ed7a4",
229
+ warningBg: "#4b4232",
230
+ warningBorder: "#7a6236",
231
+ warningText: "#f4c14f",
232
+ dangerBg: "#5a3b40",
233
+ dangerBorder: "#7d4d53",
234
+ dangerText: "#ffada9",
235
+ infoBg: "#2d4e67",
236
+ infoBorder: "#3d7292",
237
+ infoText: "#67cdff",
238
+ brandVibrant: "#6366f1",
239
+ brandCool: "#818cf8",
240
+ brandGlow: "#a5aafc",
241
+ brandPurple: "#c7d2fe"
242
+ }
243
+ };
244
+ //#endregion
245
+ export { Logo, TangleKnot, palettes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/brand",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Tangle brand system — design tokens, logo, Tailwind v4 theme. Single source of truth for every Tangle app.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -69,11 +69,12 @@
69
69
  "tailwind"
70
70
  ],
71
71
  "scripts": {
72
- "build": "node scripts/gen-ladders.mjs --check && node scripts/gen-compat.mjs --check && tsdown",
72
+ "build": "node scripts/gen-ladders.mjs --check && node scripts/gen-compat.mjs --check && node scripts/gen-palette.mjs --check && tsdown",
73
73
  "gen:ladders": "node scripts/gen-ladders.mjs",
74
74
  "gen:compat": "node scripts/gen-compat.mjs",
75
75
  "check:compat": "node scripts/gen-ladders.mjs --check && node scripts/gen-compat.mjs --check && node --test scripts/gen-compat.test.mjs",
76
76
  "check:drift": "node --test scripts/tangle-drift.test.mjs",
77
- "dev": "tsdown --watch"
77
+ "dev": "tsdown --watch",
78
+ "gen:palette": "node scripts/gen-palette.mjs"
78
79
  }
79
80
  }
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { Logo, TangleKnot, type LogoProps } from "./logo.js";
2
+ export { palettes, type BrandPalette } from "./palette.generated.js";
@@ -0,0 +1,174 @@
1
+ // GENERATED by scripts/gen-palette.mjs from tokens.css and named-themes.css; do not edit.
2
+ // Brand's resolved colors for renderers that cannot read CSS variables: PDF, canvas,
3
+ // WebGL, email and the theme-color meta. Pages styled with CSS use the variables.
4
+
5
+ /** A theme's resolved roles: hex strings, or rgba() where the token is translucent. */
6
+ export interface BrandPalette {
7
+ canvas: string;
8
+ card: string;
9
+ well: string;
10
+ nested: string;
11
+ overlay: string;
12
+ deepest: string;
13
+ hairline: string;
14
+ ink: string;
15
+ inkSecondary: string;
16
+ inkMuted: string;
17
+ accent: string;
18
+ accentHover: string;
19
+ onAccent: string;
20
+ accentText: string;
21
+ danger: string;
22
+ successBg: string;
23
+ successBorder: string;
24
+ successText: string;
25
+ warningBg: string;
26
+ warningBorder: string;
27
+ warningText: string;
28
+ dangerBg: string;
29
+ dangerBorder: string;
30
+ dangerText: string;
31
+ infoBg: string;
32
+ infoBorder: string;
33
+ infoText: string;
34
+ brandVibrant: string;
35
+ brandCool: string;
36
+ brandGlow: string;
37
+ brandPurple: string;
38
+ }
39
+
40
+ /** Resolved palettes for the canonical light and dark themes and the website named theme. */
41
+ export const palettes = {
42
+ light: {
43
+ canvas: "#eceef3",
44
+ card: "#ffffff",
45
+ well: "#f6f7fa",
46
+ nested: "#f1f2f7",
47
+ overlay: "#ffffff",
48
+ deepest: "#ffffff",
49
+ hairline: "#c7c6d6",
50
+ ink: "#2d2d2d",
51
+ inkSecondary: "#3f3f3f",
52
+ inkMuted: "#4c4c4c",
53
+ accent: "#4c3fc5",
54
+ accentHover: "#5a50d6",
55
+ onAccent: "#ffffff",
56
+ accentText: "#3c32e9",
57
+ danger: "#b41d1d",
58
+ successBg: "#ecfdf5",
59
+ successBorder: "#a7f3d0",
60
+ successText: "#047857",
61
+ warningBg: "#fffbeb",
62
+ warningBorder: "#fde68a",
63
+ warningText: "#ab4f09",
64
+ dangerBg: "#fff1f2",
65
+ dangerBorder: "#fecdd3",
66
+ dangerText: "#b91c1c",
67
+ infoBg: "#f0f9ff",
68
+ infoBorder: "#bae6fd",
69
+ infoText: "#0369a1",
70
+ brandVibrant: "#6366f1",
71
+ brandCool: "#818cf8",
72
+ brandGlow: "#a5aafc",
73
+ brandPurple: "#6366f1",
74
+ },
75
+ dark: {
76
+ canvas: "#0a0a14",
77
+ card: "#191826",
78
+ well: "#12111f",
79
+ nested: "#221f33",
80
+ overlay: "#2c2942",
81
+ deepest: "#050509",
82
+ hairline: "#2a293d",
83
+ ink: "#e6e6e6",
84
+ inkSecondary: "#c7c7c7",
85
+ inkMuted: "#b5b5b5",
86
+ accent: "#4c3fc5",
87
+ accentHover: "#5a50d6",
88
+ onAccent: "#ffffff",
89
+ accentText: "#a5b4fc",
90
+ danger: "#d52044",
91
+ successBg: "#2f5146",
92
+ successBorder: "#3c7760",
93
+ successText: "#5ed7a4",
94
+ warningBg: "#4b4232",
95
+ warningBorder: "#7a6236",
96
+ warningText: "#f4c14f",
97
+ dangerBg: "#5a3b40",
98
+ dangerBorder: "#7d4d53",
99
+ dangerText: "#ffada9",
100
+ infoBg: "#2d4e67",
101
+ infoBorder: "#3d7292",
102
+ infoText: "#67cdff",
103
+ brandVibrant: "#6366f1",
104
+ brandCool: "#818cf8",
105
+ brandGlow: "#a5aafc",
106
+ brandPurple: "#c7d2fe",
107
+ },
108
+ websiteLight: {
109
+ canvas: "#f5f5fb",
110
+ card: "#ffffff",
111
+ well: "#fafafd",
112
+ nested: "#ececf6",
113
+ overlay: "#ffffff",
114
+ deepest: "#ffffff",
115
+ hairline: "#dbdbea",
116
+ ink: "#191c24",
117
+ inkSecondary: "#3a3a50",
118
+ inkMuted: "#5e5e7a",
119
+ accent: "#4c3fc5",
120
+ accentHover: "#5a50d6",
121
+ onAccent: "#ffffff",
122
+ accentText: "#3c32e9",
123
+ danger: "#b41d1d",
124
+ successBg: "#ecfdf5",
125
+ successBorder: "#a7f3d0",
126
+ successText: "#047857",
127
+ warningBg: "#fffbeb",
128
+ warningBorder: "#fde68a",
129
+ warningText: "#ab4f09",
130
+ dangerBg: "#fff1f2",
131
+ dangerBorder: "#fecdd3",
132
+ dangerText: "#b91c1c",
133
+ infoBg: "#f0f9ff",
134
+ infoBorder: "#bae6fd",
135
+ infoText: "#0369a1",
136
+ brandVibrant: "#6366f1",
137
+ brandCool: "#818cf8",
138
+ brandGlow: "#a5aafc",
139
+ brandPurple: "#6366f1",
140
+ },
141
+ websiteDark: {
142
+ canvas: "#0c0b1d",
143
+ card: "#1d1b38",
144
+ well: "#141328",
145
+ nested: "#222041",
146
+ overlay: "#262448",
147
+ deepest: "#080814",
148
+ hairline: "#33315f",
149
+ ink: "#fdfdfd",
150
+ inkSecondary: "#aaa8b8",
151
+ inkMuted: "#9496bc",
152
+ accent: "#4c3fc5",
153
+ accentHover: "#5a50d6",
154
+ onAccent: "#ffffff",
155
+ accentText: "#a5b4fc",
156
+ danger: "#d52044",
157
+ successBg: "#2f5146",
158
+ successBorder: "#3c7760",
159
+ successText: "#5ed7a4",
160
+ warningBg: "#4b4232",
161
+ warningBorder: "#7a6236",
162
+ warningText: "#f4c14f",
163
+ dangerBg: "#5a3b40",
164
+ dangerBorder: "#7d4d53",
165
+ dangerText: "#ffada9",
166
+ infoBg: "#2d4e67",
167
+ infoBorder: "#3d7292",
168
+ infoText: "#67cdff",
169
+ brandVibrant: "#6366f1",
170
+ brandCool: "#818cf8",
171
+ brandGlow: "#a5aafc",
172
+ brandPurple: "#c7d2fe",
173
+ },
174
+ } as const satisfies Record<string, BrandPalette>;
@@ -0,0 +1,25 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import path from "node:path";
3
+ import { describe, expect, it } from "vitest";
4
+ import { palettes } from "./palette.generated";
5
+
6
+ describe("resolved palettes", () => {
7
+ it("are fresh against tokens.css and named-themes.css", () => {
8
+ const script = path.resolve(import.meta.dirname, "..", "scripts", "gen-palette.mjs");
9
+ expect(() => execFileSync(process.execPath, [script, "--check"], { stdio: "pipe" })).not.toThrow();
10
+ });
11
+
12
+ it("hold only concrete colors", () => {
13
+ for (const [theme, roles] of Object.entries(palettes)) {
14
+ for (const [role, value] of Object.entries(roles)) {
15
+ expect(value, `${theme}.${role}`).toMatch(/^(#[0-9a-f]{6}|rgba?\([^)]+\))$/);
16
+ }
17
+ }
18
+ });
19
+
20
+ it("keep the canonical planes", () => {
21
+ expect(palettes.light.card).toBe("#ffffff");
22
+ expect(palettes.light.canvas).not.toBe(palettes.light.card);
23
+ expect(palettes.dark.canvas).not.toBe(palettes.dark.card);
24
+ });
25
+ });