@pure-ds/core 0.7.46 → 0.7.48
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/custom-elements.json +193 -2
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-config.d.ts +4 -5
- package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-generator.d.ts +16 -2
- package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
- package/package.json +1 -1
- package/packages/pds-cli/bin/pds-mcp-health.js +1 -1
- package/packages/pds-cli/bin/pds-mcp-server.js +1 -1
- package/packages/pds-cli/bin/pds-setup-mcp.js +1 -1
- package/packages/pds-cli/bin/templates/bootstrap/esbuild-dev.cjs +65 -6
- package/packages/pds-cli/bin/templates/bootstrap/esbuild-dev.mjs +65 -6
- package/packages/pds-cli/bin/templates/bootstrap/public/assets/js/dev-reload.js +68 -9
- package/public/assets/js/app.js +1 -1
- package/public/assets/js/pds-enhancers.js +1 -1
- package/public/assets/js/pds-manager.js +450 -275
- package/public/assets/pds/components/pds-live-edit.js +1 -1
- package/public/assets/pds/components/pds-toaster.js +30 -4
- package/public/assets/pds/core/pds-enhancers.js +1 -1
- package/public/assets/pds/core/pds-manager.js +450 -275
- package/public/assets/pds/pds-css-complete.json +544 -55
- package/public/assets/pds/pds.css-data.json +154 -0
- package/public/assets/pds/vscode-custom-data.json +30 -0
- package/readme.md +15 -1
- package/src/js/pds-core/pds-config.js +63 -10
- package/src/js/pds-core/pds-enhancers.js +6 -1
- package/src/js/pds-core/pds-generator.js +773 -212
- package/src/js/pds-core/pds-live.js +3 -4
- package/src/js/pds.js +4 -4
|
@@ -190,20 +190,70 @@ export class Generator {
|
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
//
|
|
194
|
-
// Use purpose-specific shade selection for optimal contrast
|
|
193
|
+
// Generate semantic interactive role tokens so components can avoid hardcoded ramp picks.
|
|
195
194
|
colors.interactive = {
|
|
195
|
+
light: this.#buildInteractiveRoleTokens(
|
|
196
|
+
colors.primary,
|
|
197
|
+
colors.surface.base,
|
|
198
|
+
),
|
|
199
|
+
dark: this.#buildInteractiveRoleTokens(
|
|
200
|
+
colors.dark.primary,
|
|
201
|
+
colors.dark.surface.base,
|
|
202
|
+
),
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Accent role tokens mirror primary behavior for expressive accents on UI surfaces.
|
|
206
|
+
colors.accentInteractive = {
|
|
207
|
+
light: this.#buildInteractiveRoleTokens(
|
|
208
|
+
colors.accent,
|
|
209
|
+
colors.surface.base,
|
|
210
|
+
),
|
|
211
|
+
dark: this.#buildInteractiveRoleTokens(
|
|
212
|
+
colors.dark.accent,
|
|
213
|
+
colors.dark.surface.base,
|
|
214
|
+
),
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
colors.surfaceAccent = {
|
|
218
|
+
light: this.#buildSurfaceAccentTokens(colors.accent, colors.surface),
|
|
219
|
+
dark: this.#buildSurfaceAccentTokens(colors.dark.accent, colors.dark.surface),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Semantic role tokens for danger (mirrors primary/accent pattern).
|
|
223
|
+
colors.dangerInteractive = {
|
|
224
|
+
light: this.#buildInteractiveRoleTokens(colors.danger, colors.surface.base),
|
|
225
|
+
dark: this.#buildInteractiveRoleTokens(colors.dark.danger, colors.dark.surface.base),
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Status role tokens for success/warning/info to avoid hardcoded shade picks in UI roles.
|
|
229
|
+
colors.successInteractive = {
|
|
230
|
+
light: this.#buildInteractiveRoleTokens(colors.success, colors.surface.base),
|
|
231
|
+
dark: this.#buildInteractiveRoleTokens(colors.dark.success, colors.dark.surface.base),
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
colors.warningInteractive = {
|
|
235
|
+
light: this.#buildInteractiveRoleTokens(colors.warning, colors.surface.base),
|
|
236
|
+
dark: this.#buildInteractiveRoleTokens(colors.dark.warning, colors.dark.surface.base),
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
colors.infoInteractive = {
|
|
240
|
+
light: this.#buildInteractiveRoleTokens(colors.info, colors.surface.base),
|
|
241
|
+
dark: this.#buildInteractiveRoleTokens(colors.dark.info, colors.dark.surface.base),
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Surface-aware semantic status text tokens for all core status families.
|
|
245
|
+
colors.surfaceStatus = {
|
|
196
246
|
light: {
|
|
197
|
-
|
|
198
|
-
|
|
247
|
+
success: this.#buildSurfaceAccentTokens(colors.success, colors.surface),
|
|
248
|
+
warning: this.#buildSurfaceAccentTokens(colors.warning, colors.surface),
|
|
249
|
+
info: this.#buildSurfaceAccentTokens(colors.info, colors.surface),
|
|
250
|
+
danger: this.#buildSurfaceAccentTokens(colors.danger, colors.surface),
|
|
199
251
|
},
|
|
200
252
|
dark: {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
4.5,
|
|
206
|
-
), // For links/outlines on dark backgrounds
|
|
253
|
+
success: this.#buildSurfaceAccentTokens(colors.dark.success, colors.dark.surface),
|
|
254
|
+
warning: this.#buildSurfaceAccentTokens(colors.dark.warning, colors.dark.surface),
|
|
255
|
+
info: this.#buildSurfaceAccentTokens(colors.dark.info, colors.dark.surface),
|
|
256
|
+
danger: this.#buildSurfaceAccentTokens(colors.dark.danger, colors.dark.surface),
|
|
207
257
|
},
|
|
208
258
|
};
|
|
209
259
|
|
|
@@ -338,34 +388,26 @@ export class Generator {
|
|
|
338
388
|
|
|
339
389
|
const darkSurface = this.#generateBackgroundShades(darkBackgroundBase);
|
|
340
390
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
? this.#generateColorScale(overrides.primary)
|
|
344
|
-
: this.#adjustColorsForDarkMode(lightColors.primary);
|
|
391
|
+
const buildScale = (overrideColor, fallbackScale) =>
|
|
392
|
+
overrideColor ? this.#generateColorScale(overrideColor) : fallbackScale;
|
|
345
393
|
|
|
346
394
|
return {
|
|
347
395
|
surface: {
|
|
348
396
|
...darkSurface,
|
|
349
397
|
fieldset: this.#generateDarkModeFieldsetColors(darkSurface),
|
|
350
398
|
},
|
|
351
|
-
//
|
|
352
|
-
primary:
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
: this.#adjustColorsForDarkMode(lightColors.secondary),
|
|
357
|
-
accent: overrides.accent
|
|
358
|
-
? this.#generateColorScale(overrides.accent)
|
|
359
|
-
: this.#adjustColorsForDarkMode(lightColors.accent),
|
|
360
|
-
// Regenerate grays if secondary override is provided (grays are derived from secondary)
|
|
399
|
+
// Keep scale direction stable in both themes (50 = lightest, 900 = darkest).
|
|
400
|
+
primary: buildScale(overrides.primary, lightColors.primary),
|
|
401
|
+
secondary: buildScale(overrides.secondary, lightColors.secondary),
|
|
402
|
+
accent: buildScale(overrides.accent, lightColors.accent),
|
|
403
|
+
// Grays are derived from secondary, so only regenerate when secondary is overridden.
|
|
361
404
|
gray: overrides.secondary
|
|
362
405
|
? this.#generateGrayScale(overrides.secondary)
|
|
363
406
|
: lightColors.gray,
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
danger: this.#adjustColorsForDarkMode(lightColors.danger),
|
|
407
|
+
success: buildScale(overrides.success, lightColors.success),
|
|
408
|
+
info: buildScale(overrides.info, lightColors.info),
|
|
409
|
+
warning: buildScale(overrides.warning, lightColors.warning),
|
|
410
|
+
danger: buildScale(overrides.danger, lightColors.danger),
|
|
369
411
|
};
|
|
370
412
|
}
|
|
371
413
|
|
|
@@ -473,6 +515,55 @@ export class Generator {
|
|
|
473
515
|
return best.color || primaryScale?.["600"] || primaryScale?.["500"];
|
|
474
516
|
}
|
|
475
517
|
|
|
518
|
+
#buildInteractiveRoleTokens(scale = {}, surfaceBg = "#ffffff") {
|
|
519
|
+
const isDarkSurface = this.#luminance(surfaceBg) < 0.18;
|
|
520
|
+
const fill = this.#pickFillShadeForWhite(scale, 4.5);
|
|
521
|
+
// On dark surfaces hover/active should lighten the fill (move toward visible);
|
|
522
|
+
// on light surfaces they should deepen it.
|
|
523
|
+
const fillHover = isDarkSurface
|
|
524
|
+
? this.#lightenColor(fill, 0.15)
|
|
525
|
+
: this.#darkenColor(fill, 0.1);
|
|
526
|
+
const fillActive = isDarkSurface
|
|
527
|
+
? this.#lightenColor(fill, 0.07)
|
|
528
|
+
: this.#darkenColor(fill, 0.2);
|
|
529
|
+
const text = this.#pickReadablePrimaryOnSurface(scale, surfaceBg, 4.5);
|
|
530
|
+
const textHover = this.#pickReadablePrimaryOnSurface(scale, surfaceBg, 5.5);
|
|
531
|
+
const focusRing = this.#pickReadablePrimaryOnSurface(scale, surfaceBg, 3.0);
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
fill,
|
|
535
|
+
fillHover,
|
|
536
|
+
fillActive,
|
|
537
|
+
text,
|
|
538
|
+
textHover: textHover || text,
|
|
539
|
+
// Keep visited links legible by subtly mixing with the current surface context.
|
|
540
|
+
textVisited: this.#mixTowards(text || fill, surfaceBg, 0.2),
|
|
541
|
+
focusRing: focusRing || text || fill,
|
|
542
|
+
selectionBg: text || fill,
|
|
543
|
+
selectionText: this.#findReadableOnColor(text || fill, 4.5),
|
|
544
|
+
contrast: this.#findReadableOnColor(fill, 4.5),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
#buildSurfaceAccentTokens(scale = {}, surfaces = {}) {
|
|
549
|
+
const roles = {};
|
|
550
|
+
|
|
551
|
+
Object.entries(surfaces).forEach(([surfaceKey, bgColor]) => {
|
|
552
|
+
if (!bgColor || typeof bgColor !== "string" || !bgColor.startsWith("#")) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const text = this.#pickReadablePrimaryOnSurface(scale, bgColor, 4.5);
|
|
557
|
+
const textHover = this.#pickReadablePrimaryOnSurface(scale, bgColor, 5.0);
|
|
558
|
+
roles[surfaceKey] = {
|
|
559
|
+
text,
|
|
560
|
+
textHover: textHover || text,
|
|
561
|
+
};
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
return roles;
|
|
565
|
+
}
|
|
566
|
+
|
|
476
567
|
// Pick a color scale shade that supports white text at AA
|
|
477
568
|
#pickFillShadeForWhite(scale = {}, target = 4.5) {
|
|
478
569
|
const order = ["600", "700", "800", "500", "400", "900"]; // typical UI fills
|
|
@@ -551,46 +642,6 @@ export class Generator {
|
|
|
551
642
|
return this.#hslToHex(hsl.h, hsl.s, lighterLightness);
|
|
552
643
|
}
|
|
553
644
|
|
|
554
|
-
#adjustColorsForDarkMode(colorScale) {
|
|
555
|
-
// Create dimmed and inverted colors for dark mode
|
|
556
|
-
const dimmedScale = {};
|
|
557
|
-
|
|
558
|
-
// Invert the scale and apply dimming for better dark mode appearance
|
|
559
|
-
// For accessibility, mid-range colors (used for buttons/interactive elements) are more heavily dimmed
|
|
560
|
-
const mapping = {
|
|
561
|
-
50: { source: "900", dimFactor: 0.8 },
|
|
562
|
-
100: { source: "800", dimFactor: 0.8 },
|
|
563
|
-
200: { source: "700", dimFactor: 0.8 }, // Increased dimming
|
|
564
|
-
300: { source: "600", dimFactor: 0.8 }, // Increased dimming
|
|
565
|
-
400: { source: "500", dimFactor: 0.85 }, // Increased dimming
|
|
566
|
-
500: { source: "400", dimFactor: 0.85 }, // Increased dimming
|
|
567
|
-
600: { source: "300", dimFactor: 0.85 }, // Increased dimming (buttons use this!)
|
|
568
|
-
700: { source: "200", dimFactor: 0.85 }, // Increased dimming (button hover)
|
|
569
|
-
800: { source: "100", dimFactor: 0.95 }, // Less dimming for text
|
|
570
|
-
900: { source: "50", dimFactor: 0.95 }, // Less dimming for text
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
Object.entries(mapping).forEach(([key, config]) => {
|
|
574
|
-
const sourceColor = colorScale[config.source];
|
|
575
|
-
dimmedScale[key] = this.#dimColorForDarkMode(
|
|
576
|
-
sourceColor,
|
|
577
|
-
config.dimFactor,
|
|
578
|
-
);
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
return dimmedScale;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
#dimColorForDarkMode(hexColor, dimFactor = 0.8) {
|
|
585
|
-
const hsl = this.#hexToHsl(hexColor);
|
|
586
|
-
|
|
587
|
-
// Reduce saturation and lightness for dark mode, similar to image dimming
|
|
588
|
-
const dimmedSaturation = Math.max(hsl.s * dimFactor, 5);
|
|
589
|
-
const dimmedLightness = Math.max(hsl.l * dimFactor, 5);
|
|
590
|
-
|
|
591
|
-
return this.#hslToHex(hsl.h, dimmedSaturation, dimmedLightness);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
645
|
/**
|
|
595
646
|
* Generate spacing tokens based on the provided configuration.
|
|
596
647
|
* @param {Object} spatialConfig
|
|
@@ -1044,6 +1095,13 @@ export class Generator {
|
|
|
1044
1095
|
if (category === "dark") return; // handled elsewhere
|
|
1045
1096
|
if (category === "surfaceSmart") return; // handled below
|
|
1046
1097
|
if (category === "interactive") return; // handled below with semantic tokens
|
|
1098
|
+
if (category === "accentInteractive") return;
|
|
1099
|
+
if (category === "dangerInteractive") return;
|
|
1100
|
+
if (category === "successInteractive") return;
|
|
1101
|
+
if (category === "warningInteractive") return;
|
|
1102
|
+
if (category === "infoInteractive") return;
|
|
1103
|
+
if (category === "surfaceAccent") return;
|
|
1104
|
+
if (category === "surfaceStatus") return;
|
|
1047
1105
|
if (typeof values === "object" && values !== null) {
|
|
1048
1106
|
generateNestedColors(values, `${category}-`);
|
|
1049
1107
|
}
|
|
@@ -1075,7 +1133,7 @@ export class Generator {
|
|
|
1075
1133
|
chunks.push(` /* Semantic Text Colors */\n`);
|
|
1076
1134
|
chunks.push(` --color-text-primary: var(--color-gray-900);\n`);
|
|
1077
1135
|
chunks.push(` --color-text-secondary: var(--color-gray-600);\n`);
|
|
1078
|
-
chunks.push(` --color-text-muted: var(--color-gray-
|
|
1136
|
+
chunks.push(` --color-text-muted: var(--color-gray-500);\n`);
|
|
1079
1137
|
chunks.push(` --color-border: var(--color-gray-300);\n`);
|
|
1080
1138
|
chunks.push(` --color-input-bg: var(--color-surface-base);\n`);
|
|
1081
1139
|
chunks.push(` --color-input-disabled-bg: var(--color-gray-50);\n`);
|
|
@@ -1090,9 +1148,124 @@ export class Generator {
|
|
|
1090
1148
|
chunks.push(
|
|
1091
1149
|
` --color-primary-fill: ${colors.interactive.light.fill}; /* For button backgrounds with white text */\n`,
|
|
1092
1150
|
);
|
|
1151
|
+
chunks.push(
|
|
1152
|
+
` --color-primary-fill-hover: ${colors.interactive.light.fillHover};\n`,
|
|
1153
|
+
);
|
|
1154
|
+
chunks.push(
|
|
1155
|
+
` --color-primary-fill-active: ${colors.interactive.light.fillActive};\n`,
|
|
1156
|
+
);
|
|
1093
1157
|
chunks.push(
|
|
1094
1158
|
` --color-primary-text: ${colors.interactive.light.text}; /* For links and outline buttons on light surfaces */\n`,
|
|
1095
1159
|
);
|
|
1160
|
+
chunks.push(
|
|
1161
|
+
` --color-primary-text-hover: ${colors.interactive.light.textHover};\n`,
|
|
1162
|
+
);
|
|
1163
|
+
chunks.push(
|
|
1164
|
+
` --color-primary-text-visited: ${colors.interactive.light.textVisited};\n`,
|
|
1165
|
+
);
|
|
1166
|
+
chunks.push(
|
|
1167
|
+
` --color-primary-contrast: ${colors.interactive.light.contrast};\n`,
|
|
1168
|
+
);
|
|
1169
|
+
chunks.push(
|
|
1170
|
+
` --color-focus-ring: ${colors.interactive.light.focusRing};\n`,
|
|
1171
|
+
);
|
|
1172
|
+
chunks.push(
|
|
1173
|
+
` --color-selection-bg: ${colors.interactive.light.selectionBg};\n`,
|
|
1174
|
+
);
|
|
1175
|
+
chunks.push(
|
|
1176
|
+
` --color-selection-text: ${colors.interactive.light.selectionText};\n`,
|
|
1177
|
+
);
|
|
1178
|
+
chunks.push(` --color-link: var(--color-primary-text);\n`);
|
|
1179
|
+
chunks.push(` --color-link-hover: var(--color-primary-text-hover);\n`);
|
|
1180
|
+
chunks.push(` --color-link-visited: var(--color-primary-text-visited);\n`);
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
if (colors.accentInteractive?.light) {
|
|
1184
|
+
chunks.push(` /* Accent Role Colors */\n`);
|
|
1185
|
+
chunks.push(
|
|
1186
|
+
` --color-accent-fill: ${colors.accentInteractive.light.fill};\n`,
|
|
1187
|
+
);
|
|
1188
|
+
chunks.push(
|
|
1189
|
+
` --color-accent-fill-hover: ${colors.accentInteractive.light.fillHover};\n`,
|
|
1190
|
+
);
|
|
1191
|
+
chunks.push(
|
|
1192
|
+
` --color-accent-fill-active: ${colors.accentInteractive.light.fillActive};\n`,
|
|
1193
|
+
);
|
|
1194
|
+
chunks.push(
|
|
1195
|
+
` --color-accent-text: ${colors.accentInteractive.light.text};\n`,
|
|
1196
|
+
);
|
|
1197
|
+
chunks.push(
|
|
1198
|
+
` --color-accent-text-hover: ${colors.accentInteractive.light.textHover};\n`,
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
if (colors.surfaceAccent?.light) {
|
|
1203
|
+
chunks.push(` /* Surface-Aware Accent Text Tokens */\n`);
|
|
1204
|
+
Object.entries(colors.surfaceAccent.light).forEach(([surfaceKey, role]) => {
|
|
1205
|
+
chunks.push(` --surface-${surfaceKey}-accent-text: ${role.text};\n`);
|
|
1206
|
+
chunks.push(
|
|
1207
|
+
` --surface-${surfaceKey}-accent-text-hover: ${role.textHover};\n`,
|
|
1208
|
+
);
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
if (colors.dangerInteractive?.light) {
|
|
1213
|
+
chunks.push(` /* Danger Role Colors */\n`);
|
|
1214
|
+
chunks.push(` --color-danger-fill: ${colors.dangerInteractive.light.fill};\n`);
|
|
1215
|
+
chunks.push(` --color-danger-fill-hover: ${colors.dangerInteractive.light.fillHover};\n`);
|
|
1216
|
+
chunks.push(` --color-danger-fill-active: ${colors.dangerInteractive.light.fillActive};\n`);
|
|
1217
|
+
chunks.push(` --color-danger-text: ${colors.dangerInteractive.light.text};\n`);
|
|
1218
|
+
chunks.push(` --color-danger-text-hover: ${colors.dangerInteractive.light.textHover};\n`);
|
|
1219
|
+
chunks.push(` --color-danger-contrast: ${colors.dangerInteractive.light.contrast};\n`);
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (colors.successInteractive?.light) {
|
|
1223
|
+
chunks.push(` /* Success Role Colors */\n`);
|
|
1224
|
+
chunks.push(` --color-success-fill: ${colors.successInteractive.light.fill};\n`);
|
|
1225
|
+
chunks.push(` --color-success-fill-hover: ${colors.successInteractive.light.fillHover};\n`);
|
|
1226
|
+
chunks.push(` --color-success-fill-active: ${colors.successInteractive.light.fillActive};\n`);
|
|
1227
|
+
chunks.push(` --color-success-text: ${colors.successInteractive.light.text};\n`);
|
|
1228
|
+
chunks.push(` --color-success-text-hover: ${colors.successInteractive.light.textHover};\n`);
|
|
1229
|
+
chunks.push(` --color-success-contrast: ${colors.successInteractive.light.contrast};\n`);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
if (colors.warningInteractive?.light) {
|
|
1233
|
+
chunks.push(` /* Warning Role Colors */\n`);
|
|
1234
|
+
chunks.push(` --color-warning-fill: ${colors.warningInteractive.light.fill};\n`);
|
|
1235
|
+
chunks.push(` --color-warning-fill-hover: ${colors.warningInteractive.light.fillHover};\n`);
|
|
1236
|
+
chunks.push(` --color-warning-fill-active: ${colors.warningInteractive.light.fillActive};\n`);
|
|
1237
|
+
chunks.push(` --color-warning-text: ${colors.warningInteractive.light.text};\n`);
|
|
1238
|
+
chunks.push(` --color-warning-text-hover: ${colors.warningInteractive.light.textHover};\n`);
|
|
1239
|
+
chunks.push(` --color-warning-contrast: ${colors.warningInteractive.light.contrast};\n`);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
if (colors.infoInteractive?.light) {
|
|
1243
|
+
chunks.push(` /* Info Role Colors */\n`);
|
|
1244
|
+
chunks.push(` --color-info-fill: ${colors.infoInteractive.light.fill};\n`);
|
|
1245
|
+
chunks.push(` --color-info-fill-hover: ${colors.infoInteractive.light.fillHover};\n`);
|
|
1246
|
+
chunks.push(` --color-info-fill-active: ${colors.infoInteractive.light.fillActive};\n`);
|
|
1247
|
+
chunks.push(` --color-info-text: ${colors.infoInteractive.light.text};\n`);
|
|
1248
|
+
chunks.push(` --color-info-text-hover: ${colors.infoInteractive.light.textHover};\n`);
|
|
1249
|
+
chunks.push(` --color-info-contrast: ${colors.infoInteractive.light.contrast};\n`);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
if (colors.surfaceStatus?.light) {
|
|
1253
|
+
chunks.push(` /* Surface-Aware Status Text Tokens */\n`);
|
|
1254
|
+
Object.entries(colors.surfaceStatus.light).forEach(([family, roleBySurface]) => {
|
|
1255
|
+
Object.entries(roleBySurface).forEach(([surfaceKey, role]) => {
|
|
1256
|
+
chunks.push(` --surface-${surfaceKey}-${family}-text: ${role.text};\n`);
|
|
1257
|
+
chunks.push(` --surface-${surfaceKey}-${family}-text-hover: ${role.textHover};\n`);
|
|
1258
|
+
});
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// Callout display tokens — theme-aware shade aliases for callout bg/border/text.
|
|
1263
|
+
// Dark mode overrides these in the dark variables section.
|
|
1264
|
+
chunks.push(` /* Semantic Callout Display Tokens */\n`);
|
|
1265
|
+
for (const family of ['success', 'info', 'warning', 'danger']) {
|
|
1266
|
+
chunks.push(` --color-${family}-display-bg: var(--color-${family}-50);\n`);
|
|
1267
|
+
chunks.push(` --color-${family}-display-border: var(--color-${family}-600);\n`);
|
|
1268
|
+
chunks.push(` --color-${family}-display-text: var(--color-${family}-900);\n`);
|
|
1096
1269
|
}
|
|
1097
1270
|
|
|
1098
1271
|
// Translucent surface tokens
|
|
@@ -1317,7 +1490,145 @@ export class Generator {
|
|
|
1317
1490
|
smartLines.push(`\n`);
|
|
1318
1491
|
}
|
|
1319
1492
|
|
|
1320
|
-
const
|
|
1493
|
+
const interactiveLines = [];
|
|
1494
|
+
if (colors.interactive?.dark) {
|
|
1495
|
+
interactiveLines.push(
|
|
1496
|
+
` /* Interactive Colors - optimized for specific use cases (dark mode) */\n`,
|
|
1497
|
+
);
|
|
1498
|
+
interactiveLines.push(
|
|
1499
|
+
` --color-primary-fill: ${colors.interactive.dark.fill};\n`,
|
|
1500
|
+
);
|
|
1501
|
+
interactiveLines.push(
|
|
1502
|
+
` --color-primary-fill-hover: ${colors.interactive.dark.fillHover};\n`,
|
|
1503
|
+
);
|
|
1504
|
+
interactiveLines.push(
|
|
1505
|
+
` --color-primary-fill-active: ${colors.interactive.dark.fillActive};\n`,
|
|
1506
|
+
);
|
|
1507
|
+
interactiveLines.push(
|
|
1508
|
+
` --color-primary-text: ${colors.interactive.dark.text};\n`,
|
|
1509
|
+
);
|
|
1510
|
+
interactiveLines.push(
|
|
1511
|
+
` --color-primary-text-hover: ${colors.interactive.dark.textHover};\n`,
|
|
1512
|
+
);
|
|
1513
|
+
interactiveLines.push(
|
|
1514
|
+
` --color-primary-text-visited: ${colors.interactive.dark.textVisited};\n`,
|
|
1515
|
+
);
|
|
1516
|
+
interactiveLines.push(
|
|
1517
|
+
` --color-primary-contrast: ${colors.interactive.dark.contrast};\n`,
|
|
1518
|
+
);
|
|
1519
|
+
interactiveLines.push(
|
|
1520
|
+
` --color-focus-ring: ${colors.interactive.dark.focusRing};\n`,
|
|
1521
|
+
);
|
|
1522
|
+
interactiveLines.push(
|
|
1523
|
+
` --color-selection-bg: ${colors.interactive.dark.selectionBg};\n`,
|
|
1524
|
+
);
|
|
1525
|
+
interactiveLines.push(
|
|
1526
|
+
` --color-selection-text: ${colors.interactive.dark.selectionText};\n`,
|
|
1527
|
+
);
|
|
1528
|
+
interactiveLines.push(` --color-link: var(--color-primary-text);\n`);
|
|
1529
|
+
interactiveLines.push(` --color-link-hover: var(--color-primary-text-hover);\n`);
|
|
1530
|
+
interactiveLines.push(` --color-link-visited: var(--color-primary-text-visited);\n`);
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
const accentLines = [];
|
|
1534
|
+
if (colors.accentInteractive?.dark) {
|
|
1535
|
+
accentLines.push(` /* Accent Role Colors (dark mode) */\n`);
|
|
1536
|
+
accentLines.push(
|
|
1537
|
+
` --color-accent-fill: ${colors.accentInteractive.dark.fill};\n`,
|
|
1538
|
+
);
|
|
1539
|
+
accentLines.push(
|
|
1540
|
+
` --color-accent-fill-hover: ${colors.accentInteractive.dark.fillHover};\n`,
|
|
1541
|
+
);
|
|
1542
|
+
accentLines.push(
|
|
1543
|
+
` --color-accent-fill-active: ${colors.accentInteractive.dark.fillActive};\n`,
|
|
1544
|
+
);
|
|
1545
|
+
accentLines.push(
|
|
1546
|
+
` --color-accent-text: ${colors.accentInteractive.dark.text};\n`,
|
|
1547
|
+
);
|
|
1548
|
+
accentLines.push(
|
|
1549
|
+
` --color-accent-text-hover: ${colors.accentInteractive.dark.textHover};\n`,
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
const surfaceAccentLines = [];
|
|
1554
|
+
if (colors.surfaceAccent?.dark) {
|
|
1555
|
+
surfaceAccentLines.push(` /* Surface-Aware Accent Text Tokens (dark mode) */\n`);
|
|
1556
|
+
Object.entries(colors.surfaceAccent.dark).forEach(([surfaceKey, role]) => {
|
|
1557
|
+
surfaceAccentLines.push(
|
|
1558
|
+
` --surface-${surfaceKey}-accent-text: ${role.text};\n`,
|
|
1559
|
+
);
|
|
1560
|
+
surfaceAccentLines.push(
|
|
1561
|
+
` --surface-${surfaceKey}-accent-text-hover: ${role.textHover};\n`,
|
|
1562
|
+
);
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
const dangerLines = [];
|
|
1567
|
+
if (colors.dangerInteractive?.dark) {
|
|
1568
|
+
dangerLines.push(` /* Danger Role Colors (dark mode) */\n`);
|
|
1569
|
+
dangerLines.push(` --color-danger-fill: ${colors.dangerInteractive.dark.fill};\n`);
|
|
1570
|
+
dangerLines.push(` --color-danger-fill-hover: ${colors.dangerInteractive.dark.fillHover};\n`);
|
|
1571
|
+
dangerLines.push(` --color-danger-fill-active: ${colors.dangerInteractive.dark.fillActive};\n`);
|
|
1572
|
+
dangerLines.push(` --color-danger-text: ${colors.dangerInteractive.dark.text};\n`);
|
|
1573
|
+
dangerLines.push(` --color-danger-text-hover: ${colors.dangerInteractive.dark.textHover};\n`);
|
|
1574
|
+
dangerLines.push(` --color-danger-contrast: ${colors.dangerInteractive.dark.contrast};\n`);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
const successLines = [];
|
|
1578
|
+
if (colors.successInteractive?.dark) {
|
|
1579
|
+
successLines.push(` /* Success Role Colors (dark mode) */\n`);
|
|
1580
|
+
successLines.push(` --color-success-fill: ${colors.successInteractive.dark.fill};\n`);
|
|
1581
|
+
successLines.push(` --color-success-fill-hover: ${colors.successInteractive.dark.fillHover};\n`);
|
|
1582
|
+
successLines.push(` --color-success-fill-active: ${colors.successInteractive.dark.fillActive};\n`);
|
|
1583
|
+
successLines.push(` --color-success-text: ${colors.successInteractive.dark.text};\n`);
|
|
1584
|
+
successLines.push(` --color-success-text-hover: ${colors.successInteractive.dark.textHover};\n`);
|
|
1585
|
+
successLines.push(` --color-success-contrast: ${colors.successInteractive.dark.contrast};\n`);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
const warningLines = [];
|
|
1589
|
+
if (colors.warningInteractive?.dark) {
|
|
1590
|
+
warningLines.push(` /* Warning Role Colors (dark mode) */\n`);
|
|
1591
|
+
warningLines.push(` --color-warning-fill: ${colors.warningInteractive.dark.fill};\n`);
|
|
1592
|
+
warningLines.push(` --color-warning-fill-hover: ${colors.warningInteractive.dark.fillHover};\n`);
|
|
1593
|
+
warningLines.push(` --color-warning-fill-active: ${colors.warningInteractive.dark.fillActive};\n`);
|
|
1594
|
+
warningLines.push(` --color-warning-text: ${colors.warningInteractive.dark.text};\n`);
|
|
1595
|
+
warningLines.push(` --color-warning-text-hover: ${colors.warningInteractive.dark.textHover};\n`);
|
|
1596
|
+
warningLines.push(` --color-warning-contrast: ${colors.warningInteractive.dark.contrast};\n`);
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
const infoLines = [];
|
|
1600
|
+
if (colors.infoInteractive?.dark) {
|
|
1601
|
+
infoLines.push(` /* Info Role Colors (dark mode) */\n`);
|
|
1602
|
+
infoLines.push(` --color-info-fill: ${colors.infoInteractive.dark.fill};\n`);
|
|
1603
|
+
infoLines.push(` --color-info-fill-hover: ${colors.infoInteractive.dark.fillHover};\n`);
|
|
1604
|
+
infoLines.push(` --color-info-fill-active: ${colors.infoInteractive.dark.fillActive};\n`);
|
|
1605
|
+
infoLines.push(` --color-info-text: ${colors.infoInteractive.dark.text};\n`);
|
|
1606
|
+
infoLines.push(` --color-info-text-hover: ${colors.infoInteractive.dark.textHover};\n`);
|
|
1607
|
+
infoLines.push(` --color-info-contrast: ${colors.infoInteractive.dark.contrast};\n`);
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
const surfaceStatusLines = [];
|
|
1611
|
+
if (colors.surfaceStatus?.dark) {
|
|
1612
|
+
surfaceStatusLines.push(` /* Surface-Aware Status Text Tokens (dark mode) */\n`);
|
|
1613
|
+
Object.entries(colors.surfaceStatus.dark).forEach(([family, roleBySurface]) => {
|
|
1614
|
+
Object.entries(roleBySurface).forEach(([surfaceKey, role]) => {
|
|
1615
|
+
surfaceStatusLines.push(` --surface-${surfaceKey}-${family}-text: ${role.text};\n`);
|
|
1616
|
+
surfaceStatusLines.push(` --surface-${surfaceKey}-${family}-text-hover: ${role.textHover};\n`);
|
|
1617
|
+
});
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// Callout display token overrides for dark mode.
|
|
1622
|
+
// Use color-mix() to create a subtle hue-tinted surface (adapts to any dark bg),
|
|
1623
|
+
// a visible medium-bright border, and light text — no hard shade guessing needed.
|
|
1624
|
+
const calloutDisplayLines = [` /* Semantic Callout Display Tokens (dark mode) */\n`];
|
|
1625
|
+
for (const family of ['success', 'info', 'warning', 'danger']) {
|
|
1626
|
+
calloutDisplayLines.push(` --color-${family}-display-bg: color-mix(in oklab, var(--color-${family}-400) 12%, var(--color-surface-base));\n`);
|
|
1627
|
+
calloutDisplayLines.push(` --color-${family}-display-border: var(--color-${family}-400);\n`);
|
|
1628
|
+
calloutDisplayLines.push(` --color-${family}-display-text: var(--color-${family}-100);\n`);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
const semantic = ` --color-text-primary: var(--color-gray-100);\n --color-text-secondary: var(--color-gray-300);\n --color-text-muted: var(--color-gray-500);\n --color-border: var(--color-gray-700);\n --color-input-bg: var(--color-gray-800);\n --color-input-disabled-bg: var(--color-gray-900);\n --color-input-disabled-text: var(--color-gray-600);\n --color-code-bg: var(--color-gray-800);\n`;
|
|
1321
1632
|
|
|
1322
1633
|
const backdrop = ` /* Backdrop tokens - dark mode */\n --backdrop-bg: linear-gradient(\n 135deg,\n rgba(0, 0, 0, 0.6),\n rgba(0, 0, 0, 0.4)\n );\n --backdrop-blur: 10px;\n --backdrop-saturate: 120%;\n --backdrop-brightness: 0.7;\n --backdrop-filter: blur(var(--backdrop-blur)) saturate(var(--backdrop-saturate)) brightness(var(--backdrop-brightness));\n --backdrop-opacity: 1;\n \n /* Legacy alias for backwards compatibility */\n --backdrop-background: var(--backdrop-bg);\n`;
|
|
1323
1634
|
|
|
@@ -1332,6 +1643,15 @@ export class Generator {
|
|
|
1332
1643
|
...smartLines,
|
|
1333
1644
|
...shadowLines,
|
|
1334
1645
|
semantic,
|
|
1646
|
+
...interactiveLines,
|
|
1647
|
+
...accentLines,
|
|
1648
|
+
...surfaceAccentLines,
|
|
1649
|
+
...dangerLines,
|
|
1650
|
+
...successLines,
|
|
1651
|
+
...warningLines,
|
|
1652
|
+
...infoLines,
|
|
1653
|
+
...surfaceStatusLines,
|
|
1654
|
+
...calloutDisplayLines,
|
|
1335
1655
|
backdrop,
|
|
1336
1656
|
mesh,
|
|
1337
1657
|
].join("");
|
|
@@ -1405,17 +1725,141 @@ export class Generator {
|
|
|
1405
1725
|
` /* Interactive Colors - optimized for specific use cases (dark mode) */\n`,
|
|
1406
1726
|
);
|
|
1407
1727
|
interactiveLines.push(
|
|
1408
|
-
` --color-primary-fill: ${colors.interactive.dark.fill}
|
|
1728
|
+
` --color-primary-fill: ${colors.interactive.dark.fill};\n`,
|
|
1729
|
+
);
|
|
1730
|
+
interactiveLines.push(
|
|
1731
|
+
` --color-primary-fill-hover: ${colors.interactive.dark.fillHover};\n`,
|
|
1732
|
+
);
|
|
1733
|
+
interactiveLines.push(
|
|
1734
|
+
` --color-primary-fill-active: ${colors.interactive.dark.fillActive};\n`,
|
|
1735
|
+
);
|
|
1736
|
+
interactiveLines.push(
|
|
1737
|
+
` --color-primary-text: ${colors.interactive.dark.text};\n`,
|
|
1738
|
+
);
|
|
1739
|
+
interactiveLines.push(
|
|
1740
|
+
` --color-primary-text-hover: ${colors.interactive.dark.textHover};\n`,
|
|
1741
|
+
);
|
|
1742
|
+
interactiveLines.push(
|
|
1743
|
+
` --color-primary-text-visited: ${colors.interactive.dark.textVisited};\n`,
|
|
1744
|
+
);
|
|
1745
|
+
interactiveLines.push(
|
|
1746
|
+
` --color-primary-contrast: ${colors.interactive.dark.contrast};\n`,
|
|
1747
|
+
);
|
|
1748
|
+
interactiveLines.push(
|
|
1749
|
+
` --color-focus-ring: ${colors.interactive.dark.focusRing};\n`,
|
|
1750
|
+
);
|
|
1751
|
+
interactiveLines.push(
|
|
1752
|
+
` --color-selection-bg: ${colors.interactive.dark.selectionBg};\n`,
|
|
1409
1753
|
);
|
|
1410
1754
|
interactiveLines.push(
|
|
1411
|
-
` --color-
|
|
1755
|
+
` --color-selection-text: ${colors.interactive.dark.selectionText};\n`,
|
|
1412
1756
|
);
|
|
1757
|
+
interactiveLines.push(` --color-link: var(--color-primary-text);\n`);
|
|
1758
|
+
interactiveLines.push(` --color-link-hover: var(--color-primary-text-hover);\n`);
|
|
1759
|
+
interactiveLines.push(` --color-link-visited: var(--color-primary-text-visited);\n`);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
const accentLines = [];
|
|
1763
|
+
if (colors.accentInteractive?.dark) {
|
|
1764
|
+
accentLines.push(` /* Accent Role Colors (dark mode) */\n`);
|
|
1765
|
+
accentLines.push(
|
|
1766
|
+
` --color-accent-fill: ${colors.accentInteractive.dark.fill};\n`,
|
|
1767
|
+
);
|
|
1768
|
+
accentLines.push(
|
|
1769
|
+
` --color-accent-fill-hover: ${colors.accentInteractive.dark.fillHover};\n`,
|
|
1770
|
+
);
|
|
1771
|
+
accentLines.push(
|
|
1772
|
+
` --color-accent-fill-active: ${colors.accentInteractive.dark.fillActive};\n`,
|
|
1773
|
+
);
|
|
1774
|
+
accentLines.push(
|
|
1775
|
+
` --color-accent-text: ${colors.accentInteractive.dark.text};\n`,
|
|
1776
|
+
);
|
|
1777
|
+
accentLines.push(
|
|
1778
|
+
` --color-accent-text-hover: ${colors.accentInteractive.dark.textHover};\n`,
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
const surfaceAccentLines = [];
|
|
1783
|
+
if (colors.surfaceAccent?.dark) {
|
|
1784
|
+
surfaceAccentLines.push(
|
|
1785
|
+
` /* Surface-Aware Accent Text Tokens (dark mode) */\n`,
|
|
1786
|
+
);
|
|
1787
|
+
Object.entries(colors.surfaceAccent.dark).forEach(([surfaceKey, role]) => {
|
|
1788
|
+
surfaceAccentLines.push(
|
|
1789
|
+
` --surface-${surfaceKey}-accent-text: ${role.text};\n`,
|
|
1790
|
+
);
|
|
1791
|
+
surfaceAccentLines.push(
|
|
1792
|
+
` --surface-${surfaceKey}-accent-text-hover: ${role.textHover};\n`,
|
|
1793
|
+
);
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
const dangerLines2 = [];
|
|
1798
|
+
if (colors.dangerInteractive?.dark) {
|
|
1799
|
+
dangerLines2.push(` /* Danger Role Colors (dark mode) */\n`);
|
|
1800
|
+
dangerLines2.push(` --color-danger-fill: ${colors.dangerInteractive.dark.fill};\n`);
|
|
1801
|
+
dangerLines2.push(` --color-danger-fill-hover: ${colors.dangerInteractive.dark.fillHover};\n`);
|
|
1802
|
+
dangerLines2.push(` --color-danger-fill-active: ${colors.dangerInteractive.dark.fillActive};\n`);
|
|
1803
|
+
dangerLines2.push(` --color-danger-text: ${colors.dangerInteractive.dark.text};\n`);
|
|
1804
|
+
dangerLines2.push(` --color-danger-text-hover: ${colors.dangerInteractive.dark.textHover};\n`);
|
|
1805
|
+
dangerLines2.push(` --color-danger-contrast: ${colors.dangerInteractive.dark.contrast};\n`);
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
const successLines2 = [];
|
|
1809
|
+
if (colors.successInteractive?.dark) {
|
|
1810
|
+
successLines2.push(` /* Success Role Colors (dark mode) */\n`);
|
|
1811
|
+
successLines2.push(` --color-success-fill: ${colors.successInteractive.dark.fill};\n`);
|
|
1812
|
+
successLines2.push(` --color-success-fill-hover: ${colors.successInteractive.dark.fillHover};\n`);
|
|
1813
|
+
successLines2.push(` --color-success-fill-active: ${colors.successInteractive.dark.fillActive};\n`);
|
|
1814
|
+
successLines2.push(` --color-success-text: ${colors.successInteractive.dark.text};\n`);
|
|
1815
|
+
successLines2.push(` --color-success-text-hover: ${colors.successInteractive.dark.textHover};\n`);
|
|
1816
|
+
successLines2.push(` --color-success-contrast: ${colors.successInteractive.dark.contrast};\n`);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
const warningLines2 = [];
|
|
1820
|
+
if (colors.warningInteractive?.dark) {
|
|
1821
|
+
warningLines2.push(` /* Warning Role Colors (dark mode) */\n`);
|
|
1822
|
+
warningLines2.push(` --color-warning-fill: ${colors.warningInteractive.dark.fill};\n`);
|
|
1823
|
+
warningLines2.push(` --color-warning-fill-hover: ${colors.warningInteractive.dark.fillHover};\n`);
|
|
1824
|
+
warningLines2.push(` --color-warning-fill-active: ${colors.warningInteractive.dark.fillActive};\n`);
|
|
1825
|
+
warningLines2.push(` --color-warning-text: ${colors.warningInteractive.dark.text};\n`);
|
|
1826
|
+
warningLines2.push(` --color-warning-text-hover: ${colors.warningInteractive.dark.textHover};\n`);
|
|
1827
|
+
warningLines2.push(` --color-warning-contrast: ${colors.warningInteractive.dark.contrast};\n`);
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
const infoLines2 = [];
|
|
1831
|
+
if (colors.infoInteractive?.dark) {
|
|
1832
|
+
infoLines2.push(` /* Info Role Colors (dark mode) */\n`);
|
|
1833
|
+
infoLines2.push(` --color-info-fill: ${colors.infoInteractive.dark.fill};\n`);
|
|
1834
|
+
infoLines2.push(` --color-info-fill-hover: ${colors.infoInteractive.dark.fillHover};\n`);
|
|
1835
|
+
infoLines2.push(` --color-info-fill-active: ${colors.infoInteractive.dark.fillActive};\n`);
|
|
1836
|
+
infoLines2.push(` --color-info-text: ${colors.infoInteractive.dark.text};\n`);
|
|
1837
|
+
infoLines2.push(` --color-info-text-hover: ${colors.infoInteractive.dark.textHover};\n`);
|
|
1838
|
+
infoLines2.push(` --color-info-contrast: ${colors.infoInteractive.dark.contrast};\n`);
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
const surfaceStatusLines2 = [];
|
|
1842
|
+
if (colors.surfaceStatus?.dark) {
|
|
1843
|
+
surfaceStatusLines2.push(` /* Surface-Aware Status Text Tokens (dark mode) */\n`);
|
|
1844
|
+
Object.entries(colors.surfaceStatus.dark).forEach(([family, roleBySurface]) => {
|
|
1845
|
+
Object.entries(roleBySurface).forEach(([surfaceKey, role]) => {
|
|
1846
|
+
surfaceStatusLines2.push(` --surface-${surfaceKey}-${family}-text: ${role.text};\n`);
|
|
1847
|
+
surfaceStatusLines2.push(` --surface-${surfaceKey}-${family}-text-hover: ${role.textHover};\n`);
|
|
1848
|
+
});
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
const calloutDisplayLines2 = [` /* Semantic Callout Display Tokens (dark mode) */\n`];
|
|
1853
|
+
for (const family of ['success', 'info', 'warning', 'danger']) {
|
|
1854
|
+
calloutDisplayLines2.push(` --color-${family}-display-bg: color-mix(in oklab, var(--color-${family}-400) 12%, var(--color-surface-base));\n`);
|
|
1855
|
+
calloutDisplayLines2.push(` --color-${family}-display-border: var(--color-${family}-400);\n`);
|
|
1856
|
+
calloutDisplayLines2.push(` --color-${family}-display-text: var(--color-${family}-100);\n`);
|
|
1413
1857
|
}
|
|
1414
1858
|
|
|
1415
1859
|
const semantic = [
|
|
1416
1860
|
` --color-text-primary: var(--color-gray-100);\n`,
|
|
1417
1861
|
` --color-text-secondary: var(--color-gray-300);\n`,
|
|
1418
|
-
` --color-text-muted: var(--color-gray-
|
|
1862
|
+
` --color-text-muted: var(--color-gray-500);\n`,
|
|
1419
1863
|
` --color-border: var(--color-gray-700);\n`,
|
|
1420
1864
|
` --color-input-bg: var(--color-gray-800);\n`,
|
|
1421
1865
|
` --color-input-disabled-bg: var(--color-gray-900);\n`,
|
|
@@ -1436,6 +1880,14 @@ export class Generator {
|
|
|
1436
1880
|
...smartLines,
|
|
1437
1881
|
...shadowLines,
|
|
1438
1882
|
semantic,
|
|
1883
|
+
...accentLines,
|
|
1884
|
+
...surfaceAccentLines,
|
|
1885
|
+
...dangerLines2,
|
|
1886
|
+
...successLines2,
|
|
1887
|
+
...warningLines2,
|
|
1888
|
+
...infoLines2,
|
|
1889
|
+
...surfaceStatusLines2,
|
|
1890
|
+
...calloutDisplayLines2,
|
|
1439
1891
|
backdrop,
|
|
1440
1892
|
mesh,
|
|
1441
1893
|
].join("");
|
|
@@ -1517,12 +1969,10 @@ export class Generator {
|
|
|
1517
1969
|
|
|
1518
1970
|
// Generate dark mode component adjustments (for components layer)
|
|
1519
1971
|
#generateDarkModeComponentRules() {
|
|
1520
|
-
|
|
1972
|
+
// Callout display tokens are now overridden in the dark mode token variables section,
|
|
1973
|
+
// so no explicit callout rules are needed here.
|
|
1974
|
+
const rules = /*css*/ `/* Dark mode component adjustments */
|
|
1521
1975
|
html[data-theme="dark"] {
|
|
1522
|
-
.callout-success { background-color: var(--color-success-50); border-color: var(--color-success-500); color: var(--color-success-900); }
|
|
1523
|
-
.callout-info { background-color: var(--color-info-50); border-color: var(--color-info-500); color: var(--color-info-900); }
|
|
1524
|
-
.callout-warning { background-color: var(--color-warning-50); border-color: var(--color-warning-500); color: var(--color-warning-900); }
|
|
1525
|
-
.callout-danger, .callout-error { background-color: var(--color-danger-50); border-color: var(--color-danger-500); color: var(--color-danger-900); }
|
|
1526
1976
|
img, video { opacity: 0.8; transition: opacity var(--transition-normal); }
|
|
1527
1977
|
img:hover, video:hover { opacity: 1; }
|
|
1528
1978
|
}`;
|
|
@@ -1791,7 +2241,7 @@ html[data-theme="dark"] .liquid-glass {
|
|
|
1791
2241
|
:where(blockquote) {
|
|
1792
2242
|
margin: 0 0 var(--spacing-4) 0;
|
|
1793
2243
|
padding: var(--spacing-6) var(--spacing-8);
|
|
1794
|
-
border-left: calc(var(--border-width-thick) + var(--border-width-thin)) solid var(--color-
|
|
2244
|
+
border-left: calc(var(--border-width-thick) + var(--border-width-thin)) solid var(--color-link);
|
|
1795
2245
|
background-color: var(--color-surface-elevated);
|
|
1796
2246
|
border-radius: var(--radius-none);
|
|
1797
2247
|
font-size: var(--font-size-lg);
|
|
@@ -1807,7 +2257,7 @@ html[data-theme="dark"] .liquid-glass {
|
|
|
1807
2257
|
margin-top: var(--spacing-4);
|
|
1808
2258
|
font-size: var(--font-size-base);
|
|
1809
2259
|
font-style: normal;
|
|
1810
|
-
color: var(--color-
|
|
2260
|
+
color: var(--color-link);
|
|
1811
2261
|
}
|
|
1812
2262
|
}
|
|
1813
2263
|
|
|
@@ -1890,8 +2340,8 @@ html[data-theme="dark"] .liquid-glass {
|
|
|
1890
2340
|
}
|
|
1891
2341
|
|
|
1892
2342
|
:where(mark) {
|
|
1893
|
-
background-color: var(--color-warning-
|
|
1894
|
-
color: var(--color-warning-
|
|
2343
|
+
background-color: var(--color-warning-display-bg);
|
|
2344
|
+
color: var(--color-warning-display-text);
|
|
1895
2345
|
padding: 0 var(--spacing-1);
|
|
1896
2346
|
border-radius: var(--radius-sm);
|
|
1897
2347
|
}
|
|
@@ -2044,7 +2494,7 @@ fieldset {
|
|
|
2044
2494
|
margin-bottom: 0;
|
|
2045
2495
|
|
|
2046
2496
|
&:hover {
|
|
2047
|
-
color: var(--color-primary-
|
|
2497
|
+
color: var(--color-link-hover, var(--color-primary-text-hover));
|
|
2048
2498
|
}
|
|
2049
2499
|
}
|
|
2050
2500
|
|
|
@@ -2063,21 +2513,21 @@ fieldset {
|
|
|
2063
2513
|
margin: 0;
|
|
2064
2514
|
cursor: pointer;
|
|
2065
2515
|
flex-shrink: 0;
|
|
2066
|
-
accent-color: var(--color-primary-
|
|
2516
|
+
accent-color: var(--color-primary-fill);
|
|
2067
2517
|
|
|
2068
2518
|
&:focus-visible {
|
|
2069
2519
|
outline: none;
|
|
2070
2520
|
|
|
2071
2521
|
box-shadow:
|
|
2072
|
-
0 0 0 2px var(--color-primary-500),
|
|
2522
|
+
0 0 0 2px var(--color-focus-ring, var(--color-primary-500)),
|
|
2073
2523
|
0 0 0 4px color-mix(in srgb,
|
|
2074
|
-
var(--color-primary-500) 40%,
|
|
2524
|
+
var(--color-focus-ring, var(--color-primary-500)) 40%,
|
|
2075
2525
|
transparent
|
|
2076
2526
|
);
|
|
2077
2527
|
}
|
|
2078
2528
|
|
|
2079
2529
|
&:checked {
|
|
2080
|
-
background-color: var(--color-primary-
|
|
2530
|
+
background-color: var(--color-primary-fill);
|
|
2081
2531
|
}
|
|
2082
2532
|
|
|
2083
2533
|
}
|
|
@@ -2155,7 +2605,7 @@ input, textarea, select {
|
|
|
2155
2605
|
-webkit-appearance: none;
|
|
2156
2606
|
|
|
2157
2607
|
&:focus {
|
|
2158
|
-
border-color: var(--color-primary-500);
|
|
2608
|
+
border-color: var(--color-focus-ring, var(--color-primary-500));
|
|
2159
2609
|
background-color: var(--color-surface-base);
|
|
2160
2610
|
}
|
|
2161
2611
|
|
|
@@ -2168,10 +2618,10 @@ input, textarea, select {
|
|
|
2168
2618
|
}
|
|
2169
2619
|
|
|
2170
2620
|
&:invalid {
|
|
2171
|
-
border-color: var(--color-danger-
|
|
2621
|
+
border-color: var(--color-danger-fill);
|
|
2172
2622
|
|
|
2173
2623
|
&:focus {
|
|
2174
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-danger-
|
|
2624
|
+
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-danger-fill) ${Math.round(
|
|
2175
2625
|
(focusRingOpacity || 0.3) * 100,
|
|
2176
2626
|
)}%, transparent);
|
|
2177
2627
|
}
|
|
@@ -2208,11 +2658,11 @@ input[type="range"] {
|
|
|
2208
2658
|
width: var(--range-thumb-size, 28px);
|
|
2209
2659
|
height: var(--range-thumb-size, 28px);
|
|
2210
2660
|
margin-top: calc((var(--range-track-height, 8px) - var(--range-thumb-size, 28px)) / 2);
|
|
2211
|
-
background: color-mix(in srgb, var(--color-primary-
|
|
2661
|
+
background: color-mix(in srgb, var(--color-primary-fill) 15%, var(--color-surface-base));
|
|
2212
2662
|
border-radius: 50%;
|
|
2213
2663
|
box-shadow: var(--shadow-sm);
|
|
2214
2664
|
cursor: grab;
|
|
2215
|
-
border: var(--border-width-thin) solid color-mix(in srgb, var(--color-primary-
|
|
2665
|
+
border: var(--border-width-thin) solid color-mix(in srgb, var(--color-primary-fill) 30%, var(--color-border));
|
|
2216
2666
|
}
|
|
2217
2667
|
|
|
2218
2668
|
/* Mozilla track */
|
|
@@ -2226,10 +2676,10 @@ input[type="range"] {
|
|
|
2226
2676
|
&::-moz-range-thumb {
|
|
2227
2677
|
width: var(--range-thumb-size, 28px);
|
|
2228
2678
|
height: var(--range-thumb-size, 28px);
|
|
2229
|
-
background: color-mix(in srgb, var(--color-primary-
|
|
2679
|
+
background: color-mix(in srgb, var(--color-primary-fill) 15%, var(--color-surface-base));
|
|
2230
2680
|
border-radius: 50%;
|
|
2231
2681
|
box-shadow: var(--shadow-sm);
|
|
2232
|
-
border: var(--border-width-thin) solid color-mix(in srgb, var(--color-primary-
|
|
2682
|
+
border: var(--border-width-thin) solid color-mix(in srgb, var(--color-primary-fill) 30%, var(--color-border));
|
|
2233
2683
|
transform: translateY(calc((var(--range-track-height, 8px) - var(--range-thumb-size, 28px)) / 2));
|
|
2234
2684
|
}
|
|
2235
2685
|
|
|
@@ -2237,39 +2687,39 @@ input[type="range"] {
|
|
|
2237
2687
|
&:hover::-webkit-slider-thumb,
|
|
2238
2688
|
&:focus-visible::-webkit-slider-thumb {
|
|
2239
2689
|
cursor: grabbing;
|
|
2240
|
-
background: var(--color-primary-
|
|
2690
|
+
background: var(--color-primary-fill);
|
|
2241
2691
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
|
2242
|
-
border-color: var(--color-primary-
|
|
2692
|
+
border-color: var(--color-primary-fill-hover);
|
|
2243
2693
|
}
|
|
2244
2694
|
|
|
2245
2695
|
/* Active state for WebKit */
|
|
2246
2696
|
&:active::-webkit-slider-thumb {
|
|
2247
|
-
background: var(--color-primary-
|
|
2697
|
+
background: var(--color-primary-fill-active);
|
|
2248
2698
|
}
|
|
2249
2699
|
|
|
2250
2700
|
/* Hover and focus states for Mozilla */
|
|
2251
2701
|
&:hover::-moz-range-thumb,
|
|
2252
2702
|
&:focus-visible::-moz-range-thumb {
|
|
2253
|
-
background: var(--color-primary-
|
|
2703
|
+
background: var(--color-primary-fill);
|
|
2254
2704
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
|
2255
|
-
border-color: var(--color-primary-
|
|
2705
|
+
border-color: var(--color-primary-fill-hover);
|
|
2256
2706
|
cursor: grabbing;
|
|
2257
2707
|
}
|
|
2258
2708
|
|
|
2259
2709
|
/* Active state for Mozilla */
|
|
2260
2710
|
&:active::-moz-range-thumb {
|
|
2261
|
-
background: var(--color-primary-
|
|
2711
|
+
background: var(--color-primary-fill-active);
|
|
2262
2712
|
}
|
|
2263
2713
|
}
|
|
2264
2714
|
|
|
2265
2715
|
/* Focus style for container to match input focus */
|
|
2266
2716
|
.range-container:focus-within {
|
|
2267
|
-
border-color: var(--color-primary-500);
|
|
2268
|
-
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary-500) 30%, transparent);
|
|
2717
|
+
border-color: var(--color-focus-ring, var(--color-primary-500));
|
|
2718
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring, var(--color-primary-500)) 30%, transparent);
|
|
2269
2719
|
}
|
|
2270
2720
|
|
|
2271
2721
|
input[type="range"]:active::-moz-range-thumb {
|
|
2272
|
-
background: var(--color-primary-
|
|
2722
|
+
background: var(--color-primary-fill-active);
|
|
2273
2723
|
}
|
|
2274
2724
|
|
|
2275
2725
|
input[type="color"] {
|
|
@@ -2345,27 +2795,27 @@ input[type="color"] {
|
|
|
2345
2795
|
|
|
2346
2796
|
&:hover {
|
|
2347
2797
|
background-color: var(--color-surface-subtle);
|
|
2348
|
-
border-color: var(--color-primary-
|
|
2798
|
+
border-color: var(--color-primary-fill);
|
|
2349
2799
|
}
|
|
2350
2800
|
|
|
2351
2801
|
&:has(input[type="checkbox"]:checked),
|
|
2352
2802
|
input[type="checkbox"]:checked + label:not(fieldset label):not(label[data-toggle]) {
|
|
2353
|
-
background-color: color-mix(in oklab, var(--color-primary-
|
|
2354
|
-
color: var(--color-primary-
|
|
2355
|
-
border-color: var(--color-primary-
|
|
2803
|
+
background-color: color-mix(in oklab, var(--color-primary-fill) 8%, transparent);
|
|
2804
|
+
color: var(--color-primary-text);
|
|
2805
|
+
border-color: var(--color-primary-fill);
|
|
2356
2806
|
border-width: var(--border-width-medium);
|
|
2357
2807
|
font-weight: var(--font-weight-semibold);
|
|
2358
2808
|
|
|
2359
2809
|
&:hover {
|
|
2360
|
-
background-color: color-mix(in oklab, var(--color-primary-
|
|
2361
|
-
border-color: var(--color-primary-
|
|
2810
|
+
background-color: color-mix(in oklab, var(--color-primary-fill) 15%, transparent);
|
|
2811
|
+
border-color: var(--color-primary-fill);
|
|
2362
2812
|
}
|
|
2363
2813
|
}
|
|
2364
2814
|
|
|
2365
2815
|
&:has(input[type="checkbox"]:focus),
|
|
2366
2816
|
input[type="checkbox"]:focus + label:not(fieldset label):not(label[data-toggle]) {
|
|
2367
2817
|
outline: none;
|
|
2368
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
|
|
2818
|
+
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-focus-ring, var(--color-primary-500)) ${Math.round(
|
|
2369
2819
|
(focusRingOpacity || 0.3) * 100,
|
|
2370
2820
|
)}%, transparent);
|
|
2371
2821
|
}
|
|
@@ -2399,6 +2849,7 @@ input[type="radio"]:not(fieldset input[type="radio"]) {
|
|
|
2399
2849
|
opacity: 1;
|
|
2400
2850
|
appearance: auto;
|
|
2401
2851
|
-webkit-appearance: auto;
|
|
2852
|
+
accent-color: var(--color-primary-fill);
|
|
2402
2853
|
|
|
2403
2854
|
&:disabled {
|
|
2404
2855
|
cursor: not-allowed;
|
|
@@ -2453,7 +2904,7 @@ fieldset[role="group"].buttons {
|
|
|
2453
2904
|
|
|
2454
2905
|
&:hover {
|
|
2455
2906
|
background-color: var(--color-surface-subtle);
|
|
2456
|
-
border-color: var(--color-primary-
|
|
2907
|
+
border-color: var(--color-primary-fill);
|
|
2457
2908
|
color: var(--color-text-primary);
|
|
2458
2909
|
}
|
|
2459
2910
|
|
|
@@ -2462,20 +2913,20 @@ fieldset[role="group"].buttons {
|
|
|
2462
2913
|
}
|
|
2463
2914
|
|
|
2464
2915
|
&:has(input:is([type="radio"], [type="checkbox"]):checked) {
|
|
2465
|
-
background-color: color-mix(in oklab, var(--color-primary-
|
|
2466
|
-
border-color: var(--color-primary-
|
|
2916
|
+
background-color: color-mix(in oklab, var(--color-primary-fill) 8%, transparent);
|
|
2917
|
+
border-color: var(--color-primary-fill);
|
|
2467
2918
|
border-width: var(--border-width-medium);
|
|
2468
2919
|
font-weight: var(--font-weight-semibold);
|
|
2469
2920
|
|
|
2470
2921
|
&:hover {
|
|
2471
|
-
background-color: color-mix(in oklab, var(--color-primary-
|
|
2472
|
-
border-color: var(--color-primary-
|
|
2922
|
+
background-color: color-mix(in oklab, var(--color-primary-fill) 15%, transparent);
|
|
2923
|
+
border-color: var(--color-primary-fill-hover);
|
|
2473
2924
|
}
|
|
2474
2925
|
}
|
|
2475
2926
|
|
|
2476
2927
|
&:has(input:is([type="radio"], [type="checkbox"]):focus) {
|
|
2477
2928
|
outline: none;
|
|
2478
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
|
|
2929
|
+
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-focus-ring, var(--color-primary-500)) ${Math.round(
|
|
2479
2930
|
(focusRingOpacity || 0.3) * 100,
|
|
2480
2931
|
)}%, transparent);
|
|
2481
2932
|
}
|
|
@@ -2561,7 +3012,7 @@ label[data-toggle] {
|
|
|
2561
3012
|
&:has(input[type="checkbox"]:checked) {
|
|
2562
3013
|
&.with-icons .toggle-knob::before {
|
|
2563
3014
|
content: "✓";
|
|
2564
|
-
color: var(--color-primary-
|
|
3015
|
+
color: var(--color-primary-contrast, white);
|
|
2565
3016
|
}
|
|
2566
3017
|
|
|
2567
3018
|
.toggle-switch {
|
|
@@ -2575,7 +3026,7 @@ label[data-toggle] {
|
|
|
2575
3026
|
|
|
2576
3027
|
&:has(input[type="checkbox"]:focus) .toggle-switch,
|
|
2577
3028
|
&:focus-visible .toggle-switch {
|
|
2578
|
-
outline: 2px solid var(--color-primary-500);
|
|
3029
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
2579
3030
|
outline-offset: 2px;
|
|
2580
3031
|
}
|
|
2581
3032
|
|
|
@@ -2693,8 +3144,8 @@ label[data-color] {
|
|
|
2693
3144
|
}
|
|
2694
3145
|
|
|
2695
3146
|
&:focus-within .color-control {
|
|
2696
|
-
border-color: var(--color-primary-500);
|
|
2697
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
|
|
3147
|
+
border-color: var(--color-focus-ring, var(--color-primary-500));
|
|
3148
|
+
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-focus-ring, var(--color-primary-500)) ${Math.round(
|
|
2698
3149
|
(focusRingOpacity || 0.3) * 100,
|
|
2699
3150
|
)}%, transparent);
|
|
2700
3151
|
}
|
|
@@ -2764,7 +3215,7 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
|
|
|
2764
3215
|
|
|
2765
3216
|
&:focus {
|
|
2766
3217
|
outline: none;
|
|
2767
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
|
|
3218
|
+
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-focus-ring, var(--color-primary-500)) ${Math.round(
|
|
2768
3219
|
(focusRingOpacity || 0.3) * 100,
|
|
2769
3220
|
)}%, transparent);
|
|
2770
3221
|
}
|
|
@@ -2784,19 +3235,19 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
|
|
|
2784
3235
|
border-color: var(--color-primary-fill);
|
|
2785
3236
|
|
|
2786
3237
|
&:hover {
|
|
2787
|
-
background-color:
|
|
2788
|
-
border-color:
|
|
3238
|
+
background-color: var(--color-primary-fill-hover);
|
|
3239
|
+
border-color: var(--color-primary-fill-hover);
|
|
2789
3240
|
color: white;
|
|
2790
3241
|
}
|
|
2791
3242
|
|
|
2792
3243
|
&:active {
|
|
2793
|
-
background-color:
|
|
2794
|
-
border-color:
|
|
3244
|
+
background-color: var(--color-primary-fill-active);
|
|
3245
|
+
border-color: var(--color-primary-fill-active);
|
|
2795
3246
|
color: white;
|
|
2796
3247
|
}
|
|
2797
3248
|
|
|
2798
3249
|
&:focus {
|
|
2799
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
|
|
3250
|
+
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-focus-ring, var(--color-primary-500)) ${Math.round(
|
|
2800
3251
|
(focusRingOpacity || 0.3) * 100,
|
|
2801
3252
|
)}%, transparent);
|
|
2802
3253
|
}
|
|
@@ -2820,13 +3271,13 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
|
|
|
2820
3271
|
|
|
2821
3272
|
.btn-outline {
|
|
2822
3273
|
background-color: transparent;
|
|
2823
|
-
color: var(--color-
|
|
2824
|
-
border-color: var(--color-
|
|
3274
|
+
color: var(--color-link);
|
|
3275
|
+
border-color: var(--color-link);
|
|
2825
3276
|
|
|
2826
3277
|
&:hover {
|
|
2827
|
-
background-color: var(--color-primary-
|
|
3278
|
+
background-color: var(--color-primary-fill);
|
|
2828
3279
|
color: var(--color-primary-contrast, #ffffff);
|
|
2829
|
-
border-color: var(--color-primary-
|
|
3280
|
+
border-color: var(--color-primary-fill);
|
|
2830
3281
|
|
|
2831
3282
|
pds-icon {
|
|
2832
3283
|
color: var(--color-primary-contrast, #ffffff);
|
|
@@ -2834,8 +3285,8 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
|
|
|
2834
3285
|
}
|
|
2835
3286
|
|
|
2836
3287
|
&:active {
|
|
2837
|
-
background-color:
|
|
2838
|
-
border-color:
|
|
3288
|
+
background-color: var(--color-primary-fill-active);
|
|
3289
|
+
border-color: var(--color-primary-fill-active);
|
|
2839
3290
|
color: var(--color-primary-contrast, #ffffff);
|
|
2840
3291
|
|
|
2841
3292
|
pds-icon {
|
|
@@ -2851,31 +3302,31 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
|
|
|
2851
3302
|
}
|
|
2852
3303
|
|
|
2853
3304
|
.btn-danger {
|
|
2854
|
-
background-color: var(--color-danger-
|
|
3305
|
+
background-color: var(--color-danger-fill);
|
|
2855
3306
|
color: white;
|
|
2856
|
-
border-color: var(--color-danger-
|
|
3307
|
+
border-color: var(--color-danger-fill);
|
|
2857
3308
|
|
|
2858
3309
|
&:hover {
|
|
2859
|
-
background-color:
|
|
2860
|
-
border-color:
|
|
3310
|
+
background-color: var(--color-danger-fill-hover);
|
|
3311
|
+
border-color: var(--color-danger-fill-hover);
|
|
2861
3312
|
color: white;
|
|
2862
3313
|
}
|
|
2863
3314
|
|
|
2864
3315
|
&:active {
|
|
2865
|
-
background-color:
|
|
2866
|
-
border-color:
|
|
3316
|
+
background-color: var(--color-danger-fill-active);
|
|
3317
|
+
border-color: var(--color-danger-fill-active);
|
|
2867
3318
|
color: white;
|
|
2868
3319
|
}
|
|
2869
3320
|
}
|
|
2870
3321
|
|
|
2871
3322
|
.btn-danger.btn-outline {
|
|
2872
3323
|
background-color: transparent;
|
|
2873
|
-
color: var(--color-danger-
|
|
2874
|
-
border-color: var(--color-danger-
|
|
3324
|
+
color: var(--color-danger-fill);
|
|
3325
|
+
border-color: var(--color-danger-fill);
|
|
2875
3326
|
|
|
2876
3327
|
&:hover {
|
|
2877
|
-
background-color: var(--color-danger-
|
|
2878
|
-
border-color: var(--color-danger-
|
|
3328
|
+
background-color: var(--color-danger-fill);
|
|
3329
|
+
border-color: var(--color-danger-fill);
|
|
2879
3330
|
color: white;
|
|
2880
3331
|
|
|
2881
3332
|
pds-icon {
|
|
@@ -2884,8 +3335,8 @@ button, .btn, input[type="submit"], input[type="button"], input[type="reset"] {
|
|
|
2884
3335
|
}
|
|
2885
3336
|
|
|
2886
3337
|
&:active {
|
|
2887
|
-
background-color:
|
|
2888
|
-
border-color:
|
|
3338
|
+
background-color: var(--color-danger-fill-active);
|
|
3339
|
+
border-color: var(--color-danger-fill-active);
|
|
2889
3340
|
color: white;
|
|
2890
3341
|
|
|
2891
3342
|
pds-icon {
|
|
@@ -3268,25 +3719,25 @@ tbody {
|
|
|
3268
3719
|
}
|
|
3269
3720
|
/* Variants: success/info/warning/danger mapped to tokens */
|
|
3270
3721
|
.callout-success {
|
|
3271
|
-
background-color: var(--color-success-
|
|
3272
|
-
border-color: var(--color-success-
|
|
3273
|
-
color: var(--color-success-
|
|
3722
|
+
background-color: var(--color-success-display-bg);
|
|
3723
|
+
border-color: var(--color-success-display-border);
|
|
3724
|
+
color: var(--color-success-display-text);
|
|
3274
3725
|
}
|
|
3275
3726
|
.callout-info {
|
|
3276
|
-
background-color: var(--color-info-
|
|
3277
|
-
border-color: var(--color-info-
|
|
3278
|
-
color: var(--color-info-
|
|
3727
|
+
background-color: var(--color-info-display-bg);
|
|
3728
|
+
border-color: var(--color-info-display-border);
|
|
3729
|
+
color: var(--color-info-display-text);
|
|
3279
3730
|
}
|
|
3280
3731
|
.callout-warning {
|
|
3281
|
-
background-color: var(--color-warning-
|
|
3282
|
-
border-color: var(--color-warning-
|
|
3283
|
-
color: var(--color-warning-
|
|
3732
|
+
background-color: var(--color-warning-display-bg);
|
|
3733
|
+
border-color: var(--color-warning-display-border);
|
|
3734
|
+
color: var(--color-warning-display-text);
|
|
3284
3735
|
}
|
|
3285
3736
|
.callout-danger,
|
|
3286
3737
|
.callout-error {
|
|
3287
|
-
background-color: var(--color-danger-
|
|
3288
|
-
border-color: var(--color-danger-
|
|
3289
|
-
color: var(--color-danger-
|
|
3738
|
+
background-color: var(--color-danger-display-bg);
|
|
3739
|
+
border-color: var(--color-danger-display-border);
|
|
3740
|
+
color: var(--color-danger-display-text);
|
|
3290
3741
|
}
|
|
3291
3742
|
|
|
3292
3743
|
.callout-title {
|
|
@@ -3393,7 +3844,7 @@ tbody {
|
|
|
3393
3844
|
}
|
|
3394
3845
|
|
|
3395
3846
|
&:focus-visible {
|
|
3396
|
-
box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-primary-500) 30%, transparent);
|
|
3847
|
+
box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-focus-ring, var(--color-primary-500)) 30%, transparent);
|
|
3397
3848
|
}
|
|
3398
3849
|
|
|
3399
3850
|
/* Chevron indicator */
|
|
@@ -3453,22 +3904,23 @@ tbody {
|
|
|
3453
3904
|
}
|
|
3454
3905
|
|
|
3455
3906
|
.badge-primary, .badge-secondary, .badge-success, .badge-info, .badge-warning, .badge-danger { color: white; }
|
|
3456
|
-
.badge-primary { background-color: var(--color-primary-
|
|
3907
|
+
.badge-primary { background-color: var(--color-primary-fill); }
|
|
3457
3908
|
.badge-secondary { background-color: var(--color-secondary-600); }
|
|
3458
|
-
.badge-success { background-color: var(--color-success-
|
|
3459
|
-
.badge-info { background-color: var(--color-info-
|
|
3460
|
-
.badge-warning { background-color: var(--color-warning-
|
|
3461
|
-
.badge-danger { background-color: var(--color-danger-
|
|
3909
|
+
.badge-success { background-color: var(--color-success-fill); }
|
|
3910
|
+
.badge-info { background-color: var(--color-info-fill); }
|
|
3911
|
+
.badge-warning { background-color: var(--color-warning-fill); }
|
|
3912
|
+
.badge-danger { background-color: var(--color-danger-fill); }
|
|
3462
3913
|
|
|
3463
3914
|
.badge-outline {
|
|
3464
3915
|
background-color: transparent;
|
|
3916
|
+
color: var(--color-text-secondary);
|
|
3465
3917
|
border: var(--border-width-thin) solid currentColor;
|
|
3466
|
-
&.badge-primary { color: var(--color-text
|
|
3467
|
-
&.badge-secondary { color: var(--color-secondary
|
|
3468
|
-
&.badge-success { color: var(--color-success-
|
|
3469
|
-
&.badge-info { color: var(--color-info-
|
|
3470
|
-
&.badge-warning { color: var(--color-warning-
|
|
3471
|
-
&.badge-danger { color: var(--color-danger-
|
|
3918
|
+
&.badge-primary { color: var(--color-primary-text); }
|
|
3919
|
+
&.badge-secondary { color: var(--color-text-secondary); }
|
|
3920
|
+
&.badge-success { color: var(--color-success-text); }
|
|
3921
|
+
&.badge-info { color: var(--color-info-text); }
|
|
3922
|
+
&.badge-warning { color: var(--color-warning-text); }
|
|
3923
|
+
&.badge-danger { color: var(--color-danger-text); }
|
|
3472
3924
|
}
|
|
3473
3925
|
|
|
3474
3926
|
.badge-sm { padding: 2px var(--spacing-1); font-size: 10px; }
|
|
@@ -3810,7 +4262,7 @@ pds-tabstrip {
|
|
|
3810
4262
|
}
|
|
3811
4263
|
|
|
3812
4264
|
&:focus-visible {
|
|
3813
|
-
outline: var(--focus-ring-width, 2px) solid var(--color-primary-500);
|
|
4265
|
+
outline: var(--focus-ring-width, 2px) solid var(--color-focus-ring, var(--color-primary-500));
|
|
3814
4266
|
outline-offset: -2px;
|
|
3815
4267
|
border-radius: var(--radius-sm);
|
|
3816
4268
|
z-index: 1;
|
|
@@ -3818,14 +4270,14 @@ pds-tabstrip {
|
|
|
3818
4270
|
|
|
3819
4271
|
/* Active tab */
|
|
3820
4272
|
&[aria-current="page"] {
|
|
3821
|
-
color: var(--color-
|
|
4273
|
+
color: var(--color-link);
|
|
3822
4274
|
font-weight: var(--font-weight-semibold);
|
|
3823
|
-
border-bottom-color: var(--color-
|
|
4275
|
+
border-bottom-color: var(--color-link);
|
|
3824
4276
|
|
|
3825
4277
|
&:hover {
|
|
3826
|
-
color: var(--color-
|
|
3827
|
-
border-bottom-color: var(--color-
|
|
3828
|
-
background-color: var(--color-
|
|
4278
|
+
color: var(--color-link-hover);
|
|
4279
|
+
border-bottom-color: var(--color-link-hover);
|
|
4280
|
+
background-color: color-mix(in oklab, var(--color-link) 10%, transparent);
|
|
3829
4281
|
}
|
|
3830
4282
|
}
|
|
3831
4283
|
}
|
|
@@ -3936,13 +4388,13 @@ pds-icon {
|
|
|
3936
4388
|
|
|
3937
4389
|
|
|
3938
4390
|
/* Icon color utilities */
|
|
3939
|
-
.icon-primary, pds-icon.primary { color: var(--color-primary-
|
|
3940
|
-
.icon-secondary, pds-icon.secondary { color: var(--color-secondary
|
|
3941
|
-
.icon-accent, pds-icon.accent { color: var(--color-accent-
|
|
3942
|
-
.icon-success, pds-icon.success { color: var(--color-success-
|
|
3943
|
-
.icon-warning, pds-icon.warning { color: var(--color-warning-
|
|
3944
|
-
.icon-danger, pds-icon.danger { color: var(--color-danger-
|
|
3945
|
-
.icon-info, pds-icon.info { color: var(--color-info-
|
|
4391
|
+
.icon-primary, pds-icon.primary { color: var(--color-primary-text); }
|
|
4392
|
+
.icon-secondary, pds-icon.secondary { color: var(--color-text-secondary); }
|
|
4393
|
+
.icon-accent, pds-icon.accent { color: var(--color-accent-text); }
|
|
4394
|
+
.icon-success, pds-icon.success { color: var(--color-success-text); }
|
|
4395
|
+
.icon-warning, pds-icon.warning { color: var(--color-warning-text); }
|
|
4396
|
+
.icon-danger, pds-icon.danger { color: var(--color-danger-text); }
|
|
4397
|
+
.icon-info, pds-icon.info { color: var(--color-info-text); }
|
|
3946
4398
|
.icon-muted, pds-icon.muted { color: var(--color-text-muted); }
|
|
3947
4399
|
.icon-subtle, pds-icon.subtle { color: var(--color-text-subtle); }
|
|
3948
4400
|
|
|
@@ -4056,7 +4508,7 @@ nav[data-dropdown] {
|
|
|
4056
4508
|
|
|
4057
4509
|
& > :last-child {
|
|
4058
4510
|
position: absolute;
|
|
4059
|
-
padding: var(--spacing-2);
|
|
4511
|
+
padding: 0 var(--spacing-2);
|
|
4060
4512
|
margin: 0;
|
|
4061
4513
|
background: var(--color-surface-overlay);
|
|
4062
4514
|
border: var(--border-width-thin) solid var(--color-border);
|
|
@@ -4111,7 +4563,7 @@ nav[data-dropdown] {
|
|
|
4111
4563
|
}
|
|
4112
4564
|
|
|
4113
4565
|
menu li {
|
|
4114
|
-
padding: var(--spacing-
|
|
4566
|
+
padding: var(--spacing-2) 0;
|
|
4115
4567
|
|
|
4116
4568
|
& + li {
|
|
4117
4569
|
border-top: var(--border-width-thin) solid var(--color-border);
|
|
@@ -4144,7 +4596,7 @@ nav[data-dropdown] {
|
|
|
4144
4596
|
gap: var(--spacing-2);
|
|
4145
4597
|
|
|
4146
4598
|
&.danger {
|
|
4147
|
-
color: var(--color-danger-
|
|
4599
|
+
color: var(--color-danger-text);
|
|
4148
4600
|
}
|
|
4149
4601
|
}
|
|
4150
4602
|
|
|
@@ -4464,7 +4916,7 @@ nav[data-dropdown] {
|
|
|
4464
4916
|
|
|
4465
4917
|
a {
|
|
4466
4918
|
&:hover {
|
|
4467
|
-
color: var(--color-
|
|
4919
|
+
color: var(--color-link-hover);
|
|
4468
4920
|
}
|
|
4469
4921
|
}
|
|
4470
4922
|
}
|
|
@@ -4725,7 +5177,7 @@ nav[data-dropdown] {
|
|
|
4725
5177
|
box-sizing: border-box;
|
|
4726
5178
|
font: inherit;
|
|
4727
5179
|
color: var(--color-primary-contrast, white);
|
|
4728
|
-
background: var(--color-primary-
|
|
5180
|
+
background: var(--color-primary-fill);
|
|
4729
5181
|
padding: var(--spacing-2) var(--spacing-4);
|
|
4730
5182
|
border: 0;
|
|
4731
5183
|
border-radius: var(--radius-md);
|
|
@@ -4744,11 +5196,11 @@ nav[data-dropdown] {
|
|
|
4744
5196
|
|
|
4745
5197
|
:where(button):hover:not(:disabled) {
|
|
4746
5198
|
opacity: 0.9;
|
|
4747
|
-
background-color: var(--color-primary-
|
|
5199
|
+
background-color: var(--color-primary-fill-hover);
|
|
4748
5200
|
}
|
|
4749
5201
|
|
|
4750
5202
|
:where(button):focus-visible {
|
|
4751
|
-
outline: 2px solid var(--color-primary-500);
|
|
5203
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
4752
5204
|
outline-offset: 2px;
|
|
4753
5205
|
}
|
|
4754
5206
|
|
|
@@ -4781,8 +5233,8 @@ nav[data-dropdown] {
|
|
|
4781
5233
|
:where(select):focus-visible,
|
|
4782
5234
|
:where(textarea):focus-visible {
|
|
4783
5235
|
outline: none;
|
|
4784
|
-
border-color: var(--color-primary-500);
|
|
4785
|
-
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary-500) 30%, transparent);
|
|
5236
|
+
border-color: var(--color-focus-ring, var(--color-primary-500));
|
|
5237
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring, var(--color-primary-500)) 30%, transparent);
|
|
4786
5238
|
}
|
|
4787
5239
|
|
|
4788
5240
|
:where(input):disabled,
|
|
@@ -4809,22 +5261,32 @@ nav[data-dropdown] {
|
|
|
4809
5261
|
|
|
4810
5262
|
/* Link primitives */
|
|
4811
5263
|
:where(a) {
|
|
4812
|
-
color: var(--color-primary-text, var(--color-primary-600));
|
|
5264
|
+
color: var(--color-link, var(--color-primary-text, var(--color-primary-600)));
|
|
4813
5265
|
text-decoration: underline;
|
|
4814
5266
|
text-underline-offset: 0.2em;
|
|
4815
|
-
transition: opacity var(--transition-fast);
|
|
5267
|
+
transition: color var(--transition-fast), opacity var(--transition-fast);
|
|
4816
5268
|
}
|
|
4817
5269
|
|
|
4818
5270
|
:where(a):hover {
|
|
4819
|
-
|
|
5271
|
+
color: var(--color-link-hover, var(--color-link, var(--color-primary-text, var(--color-primary-600))));
|
|
5272
|
+
opacity: 0.9;
|
|
5273
|
+
}
|
|
5274
|
+
|
|
5275
|
+
:where(a):visited {
|
|
5276
|
+
color: var(--color-link-visited, var(--color-link, var(--color-primary-text, var(--color-primary-600))));
|
|
4820
5277
|
}
|
|
4821
5278
|
|
|
4822
5279
|
:where(a):focus-visible {
|
|
4823
|
-
outline: 2px solid var(--color-primary-500);
|
|
5280
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
4824
5281
|
outline-offset: 2px;
|
|
4825
5282
|
border-radius: var(--radius-sm);
|
|
4826
5283
|
}
|
|
4827
5284
|
|
|
5285
|
+
::selection {
|
|
5286
|
+
background: var(--color-selection-bg, var(--color-primary-text, var(--color-primary-600)));
|
|
5287
|
+
color: var(--color-selection-text, var(--color-primary-contrast, #ffffff));
|
|
5288
|
+
}
|
|
5289
|
+
|
|
4828
5290
|
/* Form primitives */
|
|
4829
5291
|
:where(label) {
|
|
4830
5292
|
display: block;
|
|
@@ -4882,23 +5344,23 @@ nav[data-dropdown] {
|
|
|
4882
5344
|
}
|
|
4883
5345
|
|
|
4884
5346
|
&:has(input[type="checkbox"]:checked)::before {
|
|
4885
|
-
background: var(--color-primary-
|
|
4886
|
-
border-color: var(--color-primary-
|
|
5347
|
+
background: var(--color-primary-fill);
|
|
5348
|
+
border-color: var(--color-primary-fill);
|
|
4887
5349
|
}
|
|
4888
5350
|
|
|
4889
5351
|
&:has(input[type="checkbox"]:focus)::before {
|
|
4890
|
-
outline: 2px solid var(--color-primary-500);
|
|
5352
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
4891
5353
|
outline-offset: 2px;
|
|
4892
5354
|
}
|
|
4893
5355
|
|
|
4894
5356
|
&:has(input[type="checkbox"]:not(:disabled)):hover::before {
|
|
4895
|
-
border-color: var(--color-primary-
|
|
5357
|
+
border-color: var(--color-primary-fill);
|
|
4896
5358
|
background: var(--color-surface-subtle);
|
|
4897
5359
|
}
|
|
4898
5360
|
|
|
4899
5361
|
&:has(input[type="checkbox"]:checked:not(:disabled)):hover::before {
|
|
4900
|
-
background: var(--color-primary-
|
|
4901
|
-
border-color: var(--color-primary-
|
|
5362
|
+
background: var(--color-primary-fill-hover);
|
|
5363
|
+
border-color: var(--color-primary-fill-hover);
|
|
4902
5364
|
}
|
|
4903
5365
|
|
|
4904
5366
|
&:has(input[type="checkbox"]:disabled) {
|
|
@@ -5189,13 +5651,13 @@ ${this.#generateBorderGradientUtilities()}
|
|
|
5189
5651
|
|
|
5190
5652
|
/* btn-primary stays vibrant in any context */
|
|
5191
5653
|
& .btn-primary {
|
|
5192
|
-
background-color: var(--color-primary-
|
|
5193
|
-
border-color: var(--color-primary-
|
|
5654
|
+
background-color: var(--color-primary-fill);
|
|
5655
|
+
border-color: var(--color-primary-fill);
|
|
5194
5656
|
color: var(--color-primary-contrast, #ffffff);
|
|
5195
5657
|
|
|
5196
5658
|
&:hover {
|
|
5197
|
-
background-color: var(--color-primary-
|
|
5198
|
-
border-color: var(--color-primary-
|
|
5659
|
+
background-color: var(--color-primary-fill-hover);
|
|
5660
|
+
border-color: var(--color-primary-fill-hover);
|
|
5199
5661
|
}
|
|
5200
5662
|
}
|
|
5201
5663
|
}
|
|
@@ -5228,7 +5690,7 @@ html:not([data-theme="dark"]) .surface-inverse {
|
|
|
5228
5690
|
}
|
|
5229
5691
|
|
|
5230
5692
|
& a:not([class*="btn"]) {
|
|
5231
|
-
color: var(--color-
|
|
5693
|
+
color: var(--color-link);
|
|
5232
5694
|
}
|
|
5233
5695
|
}
|
|
5234
5696
|
|
|
@@ -5260,7 +5722,7 @@ html[data-theme="dark"] .surface-inverse {
|
|
|
5260
5722
|
}
|
|
5261
5723
|
|
|
5262
5724
|
& a:not([class*="btn"]) {
|
|
5263
|
-
color: var(--color-
|
|
5725
|
+
color: var(--color-link);
|
|
5264
5726
|
}
|
|
5265
5727
|
}
|
|
5266
5728
|
|
|
@@ -5650,16 +6112,43 @@ export const ${name}CSS = \`${escapedCSS}\`;
|
|
|
5650
6112
|
* @param {object} designConfig - A full or partial PDS config object
|
|
5651
6113
|
* @param {object} [options]
|
|
5652
6114
|
* @param {number} [options.minContrast=4.5] - Minimum contrast ratio for normal text
|
|
5653
|
-
* @
|
|
6115
|
+
* @param {boolean} [options.warnOnHueDrift=true] - Emit non-blocking brand-identity hue drift warnings for darkMode overrides.
|
|
6116
|
+
* @param {number} [options.maxHueDrift=35] - Maximum recommended hue delta (degrees) before warning.
|
|
6117
|
+
* @returns {{ ok: boolean, issues: Array<{path:string, message:string, ratio:number, min:number, context?:string}>, warnings: Array<{path:string, message:string, context?:string}> }}
|
|
5654
6118
|
*/
|
|
5655
6119
|
export function validateDesign(designConfig = {}, options = {}) {
|
|
5656
6120
|
const MIN = Number(options.minContrast || 4.5);
|
|
5657
6121
|
const MIN_MUTED = Number(options.minMutedContrast || 3.0);
|
|
5658
6122
|
const EXTENDED = Boolean(options.extendedChecks);
|
|
6123
|
+
const ENABLE_HUE_DRIFT_WARNINGS = options.warnOnHueDrift !== false;
|
|
6124
|
+
const MAX_HUE_DRIFT = Number.isFinite(Number(options.maxHueDrift))
|
|
6125
|
+
? Number(options.maxHueDrift)
|
|
6126
|
+
: 35;
|
|
6127
|
+
const MIN_SAT_FOR_HUE_WARNING = Number.isFinite(
|
|
6128
|
+
Number(options.minSaturationForHueWarning),
|
|
6129
|
+
)
|
|
6130
|
+
? Number(options.minSaturationForHueWarning)
|
|
6131
|
+
: 18;
|
|
5659
6132
|
|
|
5660
6133
|
// Local helpers (keep public; no dependency on private Generator methods)
|
|
6134
|
+
const normalizeHex = (hex) => {
|
|
6135
|
+
const raw = String(hex || "").trim();
|
|
6136
|
+
const m = raw.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/);
|
|
6137
|
+
if (!m) return null;
|
|
6138
|
+
const body = m[1];
|
|
6139
|
+
const full =
|
|
6140
|
+
body.length === 3
|
|
6141
|
+
? body
|
|
6142
|
+
.split("")
|
|
6143
|
+
.map((c) => c + c)
|
|
6144
|
+
.join("")
|
|
6145
|
+
: body;
|
|
6146
|
+
return `#${full.toLowerCase()}`;
|
|
6147
|
+
};
|
|
5661
6148
|
const hexToRgb = (hex) => {
|
|
5662
|
-
const
|
|
6149
|
+
const normalized = normalizeHex(hex);
|
|
6150
|
+
if (!normalized) return null;
|
|
6151
|
+
const h = normalized.replace("#", "");
|
|
5663
6152
|
const full =
|
|
5664
6153
|
h.length === 3
|
|
5665
6154
|
? h
|
|
@@ -5671,7 +6160,9 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5671
6160
|
return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 };
|
|
5672
6161
|
};
|
|
5673
6162
|
const luminance = (hex) => {
|
|
5674
|
-
const
|
|
6163
|
+
const rgb = hexToRgb(hex);
|
|
6164
|
+
if (!rgb) return 0;
|
|
6165
|
+
const { r, g, b } = rgb;
|
|
5675
6166
|
const srgb = [r / 255, g / 255, b / 255].map((v) =>
|
|
5676
6167
|
v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4),
|
|
5677
6168
|
);
|
|
@@ -5685,8 +6176,39 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5685
6176
|
const darker = Math.min(L1, L2);
|
|
5686
6177
|
return (lighter + 0.05) / (darker + 0.05);
|
|
5687
6178
|
};
|
|
6179
|
+
const hexToHsl = (hex) => {
|
|
6180
|
+
const rgb = hexToRgb(hex);
|
|
6181
|
+
if (!rgb) return null;
|
|
6182
|
+
const r = rgb.r / 255;
|
|
6183
|
+
const g = rgb.g / 255;
|
|
6184
|
+
const b = rgb.b / 255;
|
|
6185
|
+
const max = Math.max(r, g, b);
|
|
6186
|
+
const min = Math.min(r, g, b);
|
|
6187
|
+
const delta = max - min;
|
|
6188
|
+
|
|
6189
|
+
let h = 0;
|
|
6190
|
+
if (delta !== 0) {
|
|
6191
|
+
if (max === r) h = ((g - b) / delta) % 6;
|
|
6192
|
+
else if (max === g) h = (b - r) / delta + 2;
|
|
6193
|
+
else h = (r - g) / delta + 4;
|
|
6194
|
+
h *= 60;
|
|
6195
|
+
if (h < 0) h += 360;
|
|
6196
|
+
}
|
|
6197
|
+
|
|
6198
|
+
const l = (max + min) / 2;
|
|
6199
|
+
const s =
|
|
6200
|
+
delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
|
|
6201
|
+
|
|
6202
|
+
return { h, s: s * 100, l: l * 100 };
|
|
6203
|
+
};
|
|
6204
|
+
const hueDelta = (h1, h2) => {
|
|
6205
|
+
if (!Number.isFinite(h1) || !Number.isFinite(h2)) return null;
|
|
6206
|
+
const diff = Math.abs(h1 - h2);
|
|
6207
|
+
return Math.min(diff, 360 - diff);
|
|
6208
|
+
};
|
|
5688
6209
|
|
|
5689
6210
|
const issues = [];
|
|
6211
|
+
const warnings = [];
|
|
5690
6212
|
try {
|
|
5691
6213
|
// Build tokens from the candidate config
|
|
5692
6214
|
const gen = new Generator({ design: structuredClone(designConfig) });
|
|
@@ -5889,6 +6411,45 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5889
6411
|
}
|
|
5890
6412
|
}
|
|
5891
6413
|
}
|
|
6414
|
+
|
|
6415
|
+
if (ENABLE_HUE_DRIFT_WARNINGS) {
|
|
6416
|
+
const configured = designConfig?.colors || {};
|
|
6417
|
+
const configuredDark = configured?.darkMode || {};
|
|
6418
|
+
const families = ["primary", "secondary", "accent"];
|
|
6419
|
+
|
|
6420
|
+
families.forEach((family) => {
|
|
6421
|
+
const lightBase = configured?.[family];
|
|
6422
|
+
const darkOverride = configuredDark?.[family];
|
|
6423
|
+
if (!lightBase || !darkOverride) return;
|
|
6424
|
+
|
|
6425
|
+
const lightHsl = hexToHsl(lightBase);
|
|
6426
|
+
const darkHsl = hexToHsl(darkOverride);
|
|
6427
|
+
if (!lightHsl || !darkHsl) return;
|
|
6428
|
+
|
|
6429
|
+
// For near-neutrals hue isn't meaningful enough to warn.
|
|
6430
|
+
if (
|
|
6431
|
+
lightHsl.s < MIN_SAT_FOR_HUE_WARNING &&
|
|
6432
|
+
darkHsl.s < MIN_SAT_FOR_HUE_WARNING
|
|
6433
|
+
) {
|
|
6434
|
+
return;
|
|
6435
|
+
}
|
|
6436
|
+
|
|
6437
|
+
const drift = hueDelta(lightHsl.h, darkHsl.h);
|
|
6438
|
+
if (drift == null || drift <= MAX_HUE_DRIFT) return;
|
|
6439
|
+
|
|
6440
|
+
warnings.push({
|
|
6441
|
+
path: `/colors/darkMode/${family}`,
|
|
6442
|
+
message: `Dark mode ${family} hue drifts ${drift.toFixed(
|
|
6443
|
+
1,
|
|
6444
|
+
)}deg from light ${family} (${lightHsl.h.toFixed(
|
|
6445
|
+
1,
|
|
6446
|
+
)}deg -> ${darkHsl.h.toFixed(
|
|
6447
|
+
1,
|
|
6448
|
+
)}deg). This may reduce cross-theme brand identity consistency.`,
|
|
6449
|
+
context: `dark/identity-hue-${family}`,
|
|
6450
|
+
});
|
|
6451
|
+
});
|
|
6452
|
+
}
|
|
5892
6453
|
} catch (err) {
|
|
5893
6454
|
issues.push({
|
|
5894
6455
|
path: "/",
|
|
@@ -5898,7 +6459,7 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5898
6459
|
});
|
|
5899
6460
|
}
|
|
5900
6461
|
|
|
5901
|
-
return { ok: issues.length === 0, issues };
|
|
6462
|
+
return { ok: issues.length === 0, issues, warnings };
|
|
5902
6463
|
}
|
|
5903
6464
|
|
|
5904
6465
|
/**
|
|
@@ -5907,7 +6468,7 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5907
6468
|
*
|
|
5908
6469
|
* @param {Array<object>} designs - Array of design configs; items may include an optional `name` property.
|
|
5909
6470
|
* @param {object} [options] - Options forwarded to validateDesign (e.g., { minContrast })
|
|
5910
|
-
* @returns {{ ok: boolean, results: Array<{ name?: string, ok: boolean, issues: Array<{path:string, message:string, ratio:number, min:number, context?:string}> }> }}
|
|
6471
|
+
* @returns {{ ok: boolean, results: Array<{ name?: string, ok: boolean, issues: Array<{path:string, message:string, ratio:number, min:number, context?:string}>, warnings?: Array<{path:string, message:string, context?:string}> }> }}
|
|
5911
6472
|
*/
|
|
5912
6473
|
export function validateDesigns(designs = [], options = {}) {
|
|
5913
6474
|
const results = [];
|