@pure-ds/core 0.7.45 → 0.7.47
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/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/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 +444 -269
- package/public/assets/pds/core/pds-enhancers.js +1 -1
- package/public/assets/pds/core/pds-manager.js +444 -269
- package/public/assets/pds/external/shiki.js +1 -1
- 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 +770 -210
- 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`,
|
|
1409
1732
|
);
|
|
1410
1733
|
interactiveLines.push(
|
|
1411
|
-
` --color-primary-
|
|
1734
|
+
` --color-primary-fill-active: ${colors.interactive.dark.fillActive};\n`,
|
|
1412
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`,
|
|
1753
|
+
);
|
|
1754
|
+
interactiveLines.push(
|
|
1755
|
+
` --color-selection-text: ${colors.interactive.dark.selectionText};\n`,
|
|
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,22 @@ 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;
|
|
3465
3916
|
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-
|
|
3917
|
+
&.badge-primary { color: var(--color-primary-text); }
|
|
3918
|
+
&.badge-secondary { color: var(--color-text-secondary); }
|
|
3919
|
+
&.badge-success { color: var(--color-success-text); }
|
|
3920
|
+
&.badge-info { color: var(--color-info-text); }
|
|
3921
|
+
&.badge-warning { color: var(--color-warning-text); }
|
|
3922
|
+
&.badge-danger { color: var(--color-danger-text); }
|
|
3472
3923
|
}
|
|
3473
3924
|
|
|
3474
3925
|
.badge-sm { padding: 2px var(--spacing-1); font-size: 10px; }
|
|
@@ -3810,7 +4261,7 @@ pds-tabstrip {
|
|
|
3810
4261
|
}
|
|
3811
4262
|
|
|
3812
4263
|
&:focus-visible {
|
|
3813
|
-
outline: var(--focus-ring-width, 2px) solid var(--color-primary-500);
|
|
4264
|
+
outline: var(--focus-ring-width, 2px) solid var(--color-focus-ring, var(--color-primary-500));
|
|
3814
4265
|
outline-offset: -2px;
|
|
3815
4266
|
border-radius: var(--radius-sm);
|
|
3816
4267
|
z-index: 1;
|
|
@@ -3818,14 +4269,14 @@ pds-tabstrip {
|
|
|
3818
4269
|
|
|
3819
4270
|
/* Active tab */
|
|
3820
4271
|
&[aria-current="page"] {
|
|
3821
|
-
color: var(--color-
|
|
4272
|
+
color: var(--color-link);
|
|
3822
4273
|
font-weight: var(--font-weight-semibold);
|
|
3823
|
-
border-bottom-color: var(--color-
|
|
4274
|
+
border-bottom-color: var(--color-link);
|
|
3824
4275
|
|
|
3825
4276
|
&:hover {
|
|
3826
|
-
color: var(--color-
|
|
3827
|
-
border-bottom-color: var(--color-
|
|
3828
|
-
background-color: var(--color-
|
|
4277
|
+
color: var(--color-link-hover);
|
|
4278
|
+
border-bottom-color: var(--color-link-hover);
|
|
4279
|
+
background-color: color-mix(in oklab, var(--color-link) 10%, transparent);
|
|
3829
4280
|
}
|
|
3830
4281
|
}
|
|
3831
4282
|
}
|
|
@@ -3936,13 +4387,13 @@ pds-icon {
|
|
|
3936
4387
|
|
|
3937
4388
|
|
|
3938
4389
|
/* 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-
|
|
4390
|
+
.icon-primary, pds-icon.primary { color: var(--color-primary-text); }
|
|
4391
|
+
.icon-secondary, pds-icon.secondary { color: var(--color-text-secondary); }
|
|
4392
|
+
.icon-accent, pds-icon.accent { color: var(--color-accent-text); }
|
|
4393
|
+
.icon-success, pds-icon.success { color: var(--color-success-text); }
|
|
4394
|
+
.icon-warning, pds-icon.warning { color: var(--color-warning-text); }
|
|
4395
|
+
.icon-danger, pds-icon.danger { color: var(--color-danger-text); }
|
|
4396
|
+
.icon-info, pds-icon.info { color: var(--color-info-text); }
|
|
3946
4397
|
.icon-muted, pds-icon.muted { color: var(--color-text-muted); }
|
|
3947
4398
|
.icon-subtle, pds-icon.subtle { color: var(--color-text-subtle); }
|
|
3948
4399
|
|
|
@@ -4144,7 +4595,7 @@ nav[data-dropdown] {
|
|
|
4144
4595
|
gap: var(--spacing-2);
|
|
4145
4596
|
|
|
4146
4597
|
&.danger {
|
|
4147
|
-
color: var(--color-danger-
|
|
4598
|
+
color: var(--color-danger-text);
|
|
4148
4599
|
}
|
|
4149
4600
|
}
|
|
4150
4601
|
|
|
@@ -4464,7 +4915,7 @@ nav[data-dropdown] {
|
|
|
4464
4915
|
|
|
4465
4916
|
a {
|
|
4466
4917
|
&:hover {
|
|
4467
|
-
color: var(--color-
|
|
4918
|
+
color: var(--color-link-hover);
|
|
4468
4919
|
}
|
|
4469
4920
|
}
|
|
4470
4921
|
}
|
|
@@ -4725,7 +5176,7 @@ nav[data-dropdown] {
|
|
|
4725
5176
|
box-sizing: border-box;
|
|
4726
5177
|
font: inherit;
|
|
4727
5178
|
color: var(--color-primary-contrast, white);
|
|
4728
|
-
background: var(--color-primary-
|
|
5179
|
+
background: var(--color-primary-fill);
|
|
4729
5180
|
padding: var(--spacing-2) var(--spacing-4);
|
|
4730
5181
|
border: 0;
|
|
4731
5182
|
border-radius: var(--radius-md);
|
|
@@ -4744,11 +5195,11 @@ nav[data-dropdown] {
|
|
|
4744
5195
|
|
|
4745
5196
|
:where(button):hover:not(:disabled) {
|
|
4746
5197
|
opacity: 0.9;
|
|
4747
|
-
background-color: var(--color-primary-
|
|
5198
|
+
background-color: var(--color-primary-fill-hover);
|
|
4748
5199
|
}
|
|
4749
5200
|
|
|
4750
5201
|
:where(button):focus-visible {
|
|
4751
|
-
outline: 2px solid var(--color-primary-500);
|
|
5202
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
4752
5203
|
outline-offset: 2px;
|
|
4753
5204
|
}
|
|
4754
5205
|
|
|
@@ -4781,8 +5232,8 @@ nav[data-dropdown] {
|
|
|
4781
5232
|
:where(select):focus-visible,
|
|
4782
5233
|
:where(textarea):focus-visible {
|
|
4783
5234
|
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);
|
|
5235
|
+
border-color: var(--color-focus-ring, var(--color-primary-500));
|
|
5236
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring, var(--color-primary-500)) 30%, transparent);
|
|
4786
5237
|
}
|
|
4787
5238
|
|
|
4788
5239
|
:where(input):disabled,
|
|
@@ -4809,22 +5260,32 @@ nav[data-dropdown] {
|
|
|
4809
5260
|
|
|
4810
5261
|
/* Link primitives */
|
|
4811
5262
|
:where(a) {
|
|
4812
|
-
color: var(--color-primary-text, var(--color-primary-600));
|
|
5263
|
+
color: var(--color-link, var(--color-primary-text, var(--color-primary-600)));
|
|
4813
5264
|
text-decoration: underline;
|
|
4814
5265
|
text-underline-offset: 0.2em;
|
|
4815
|
-
transition: opacity var(--transition-fast);
|
|
5266
|
+
transition: color var(--transition-fast), opacity var(--transition-fast);
|
|
4816
5267
|
}
|
|
4817
5268
|
|
|
4818
5269
|
:where(a):hover {
|
|
4819
|
-
|
|
5270
|
+
color: var(--color-link-hover, var(--color-link, var(--color-primary-text, var(--color-primary-600))));
|
|
5271
|
+
opacity: 0.9;
|
|
5272
|
+
}
|
|
5273
|
+
|
|
5274
|
+
:where(a):visited {
|
|
5275
|
+
color: var(--color-link-visited, var(--color-link, var(--color-primary-text, var(--color-primary-600))));
|
|
4820
5276
|
}
|
|
4821
5277
|
|
|
4822
5278
|
:where(a):focus-visible {
|
|
4823
|
-
outline: 2px solid var(--color-primary-500);
|
|
5279
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
4824
5280
|
outline-offset: 2px;
|
|
4825
5281
|
border-radius: var(--radius-sm);
|
|
4826
5282
|
}
|
|
4827
5283
|
|
|
5284
|
+
::selection {
|
|
5285
|
+
background: var(--color-selection-bg, var(--color-primary-text, var(--color-primary-600)));
|
|
5286
|
+
color: var(--color-selection-text, var(--color-primary-contrast, #ffffff));
|
|
5287
|
+
}
|
|
5288
|
+
|
|
4828
5289
|
/* Form primitives */
|
|
4829
5290
|
:where(label) {
|
|
4830
5291
|
display: block;
|
|
@@ -4882,23 +5343,23 @@ nav[data-dropdown] {
|
|
|
4882
5343
|
}
|
|
4883
5344
|
|
|
4884
5345
|
&:has(input[type="checkbox"]:checked)::before {
|
|
4885
|
-
background: var(--color-primary-
|
|
4886
|
-
border-color: var(--color-primary-
|
|
5346
|
+
background: var(--color-primary-fill);
|
|
5347
|
+
border-color: var(--color-primary-fill);
|
|
4887
5348
|
}
|
|
4888
5349
|
|
|
4889
5350
|
&:has(input[type="checkbox"]:focus)::before {
|
|
4890
|
-
outline: 2px solid var(--color-primary-500);
|
|
5351
|
+
outline: 2px solid var(--color-focus-ring, var(--color-primary-500));
|
|
4891
5352
|
outline-offset: 2px;
|
|
4892
5353
|
}
|
|
4893
5354
|
|
|
4894
5355
|
&:has(input[type="checkbox"]:not(:disabled)):hover::before {
|
|
4895
|
-
border-color: var(--color-primary-
|
|
5356
|
+
border-color: var(--color-primary-fill);
|
|
4896
5357
|
background: var(--color-surface-subtle);
|
|
4897
5358
|
}
|
|
4898
5359
|
|
|
4899
5360
|
&:has(input[type="checkbox"]:checked:not(:disabled)):hover::before {
|
|
4900
|
-
background: var(--color-primary-
|
|
4901
|
-
border-color: var(--color-primary-
|
|
5361
|
+
background: var(--color-primary-fill-hover);
|
|
5362
|
+
border-color: var(--color-primary-fill-hover);
|
|
4902
5363
|
}
|
|
4903
5364
|
|
|
4904
5365
|
&:has(input[type="checkbox"]:disabled) {
|
|
@@ -5189,13 +5650,13 @@ ${this.#generateBorderGradientUtilities()}
|
|
|
5189
5650
|
|
|
5190
5651
|
/* btn-primary stays vibrant in any context */
|
|
5191
5652
|
& .btn-primary {
|
|
5192
|
-
background-color: var(--color-primary-
|
|
5193
|
-
border-color: var(--color-primary-
|
|
5653
|
+
background-color: var(--color-primary-fill);
|
|
5654
|
+
border-color: var(--color-primary-fill);
|
|
5194
5655
|
color: var(--color-primary-contrast, #ffffff);
|
|
5195
5656
|
|
|
5196
5657
|
&:hover {
|
|
5197
|
-
background-color: var(--color-primary-
|
|
5198
|
-
border-color: var(--color-primary-
|
|
5658
|
+
background-color: var(--color-primary-fill-hover);
|
|
5659
|
+
border-color: var(--color-primary-fill-hover);
|
|
5199
5660
|
}
|
|
5200
5661
|
}
|
|
5201
5662
|
}
|
|
@@ -5228,7 +5689,7 @@ html:not([data-theme="dark"]) .surface-inverse {
|
|
|
5228
5689
|
}
|
|
5229
5690
|
|
|
5230
5691
|
& a:not([class*="btn"]) {
|
|
5231
|
-
color: var(--color-
|
|
5692
|
+
color: var(--color-link);
|
|
5232
5693
|
}
|
|
5233
5694
|
}
|
|
5234
5695
|
|
|
@@ -5260,7 +5721,7 @@ html[data-theme="dark"] .surface-inverse {
|
|
|
5260
5721
|
}
|
|
5261
5722
|
|
|
5262
5723
|
& a:not([class*="btn"]) {
|
|
5263
|
-
color: var(--color-
|
|
5724
|
+
color: var(--color-link);
|
|
5264
5725
|
}
|
|
5265
5726
|
}
|
|
5266
5727
|
|
|
@@ -5650,16 +6111,43 @@ export const ${name}CSS = \`${escapedCSS}\`;
|
|
|
5650
6111
|
* @param {object} designConfig - A full or partial PDS config object
|
|
5651
6112
|
* @param {object} [options]
|
|
5652
6113
|
* @param {number} [options.minContrast=4.5] - Minimum contrast ratio for normal text
|
|
5653
|
-
* @
|
|
6114
|
+
* @param {boolean} [options.warnOnHueDrift=true] - Emit non-blocking brand-identity hue drift warnings for darkMode overrides.
|
|
6115
|
+
* @param {number} [options.maxHueDrift=35] - Maximum recommended hue delta (degrees) before warning.
|
|
6116
|
+
* @returns {{ ok: boolean, issues: Array<{path:string, message:string, ratio:number, min:number, context?:string}>, warnings: Array<{path:string, message:string, context?:string}> }}
|
|
5654
6117
|
*/
|
|
5655
6118
|
export function validateDesign(designConfig = {}, options = {}) {
|
|
5656
6119
|
const MIN = Number(options.minContrast || 4.5);
|
|
5657
6120
|
const MIN_MUTED = Number(options.minMutedContrast || 3.0);
|
|
5658
6121
|
const EXTENDED = Boolean(options.extendedChecks);
|
|
6122
|
+
const ENABLE_HUE_DRIFT_WARNINGS = options.warnOnHueDrift !== false;
|
|
6123
|
+
const MAX_HUE_DRIFT = Number.isFinite(Number(options.maxHueDrift))
|
|
6124
|
+
? Number(options.maxHueDrift)
|
|
6125
|
+
: 35;
|
|
6126
|
+
const MIN_SAT_FOR_HUE_WARNING = Number.isFinite(
|
|
6127
|
+
Number(options.minSaturationForHueWarning),
|
|
6128
|
+
)
|
|
6129
|
+
? Number(options.minSaturationForHueWarning)
|
|
6130
|
+
: 18;
|
|
5659
6131
|
|
|
5660
6132
|
// Local helpers (keep public; no dependency on private Generator methods)
|
|
6133
|
+
const normalizeHex = (hex) => {
|
|
6134
|
+
const raw = String(hex || "").trim();
|
|
6135
|
+
const m = raw.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/);
|
|
6136
|
+
if (!m) return null;
|
|
6137
|
+
const body = m[1];
|
|
6138
|
+
const full =
|
|
6139
|
+
body.length === 3
|
|
6140
|
+
? body
|
|
6141
|
+
.split("")
|
|
6142
|
+
.map((c) => c + c)
|
|
6143
|
+
.join("")
|
|
6144
|
+
: body;
|
|
6145
|
+
return `#${full.toLowerCase()}`;
|
|
6146
|
+
};
|
|
5661
6147
|
const hexToRgb = (hex) => {
|
|
5662
|
-
const
|
|
6148
|
+
const normalized = normalizeHex(hex);
|
|
6149
|
+
if (!normalized) return null;
|
|
6150
|
+
const h = normalized.replace("#", "");
|
|
5663
6151
|
const full =
|
|
5664
6152
|
h.length === 3
|
|
5665
6153
|
? h
|
|
@@ -5671,7 +6159,9 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5671
6159
|
return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 };
|
|
5672
6160
|
};
|
|
5673
6161
|
const luminance = (hex) => {
|
|
5674
|
-
const
|
|
6162
|
+
const rgb = hexToRgb(hex);
|
|
6163
|
+
if (!rgb) return 0;
|
|
6164
|
+
const { r, g, b } = rgb;
|
|
5675
6165
|
const srgb = [r / 255, g / 255, b / 255].map((v) =>
|
|
5676
6166
|
v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4),
|
|
5677
6167
|
);
|
|
@@ -5685,8 +6175,39 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5685
6175
|
const darker = Math.min(L1, L2);
|
|
5686
6176
|
return (lighter + 0.05) / (darker + 0.05);
|
|
5687
6177
|
};
|
|
6178
|
+
const hexToHsl = (hex) => {
|
|
6179
|
+
const rgb = hexToRgb(hex);
|
|
6180
|
+
if (!rgb) return null;
|
|
6181
|
+
const r = rgb.r / 255;
|
|
6182
|
+
const g = rgb.g / 255;
|
|
6183
|
+
const b = rgb.b / 255;
|
|
6184
|
+
const max = Math.max(r, g, b);
|
|
6185
|
+
const min = Math.min(r, g, b);
|
|
6186
|
+
const delta = max - min;
|
|
6187
|
+
|
|
6188
|
+
let h = 0;
|
|
6189
|
+
if (delta !== 0) {
|
|
6190
|
+
if (max === r) h = ((g - b) / delta) % 6;
|
|
6191
|
+
else if (max === g) h = (b - r) / delta + 2;
|
|
6192
|
+
else h = (r - g) / delta + 4;
|
|
6193
|
+
h *= 60;
|
|
6194
|
+
if (h < 0) h += 360;
|
|
6195
|
+
}
|
|
6196
|
+
|
|
6197
|
+
const l = (max + min) / 2;
|
|
6198
|
+
const s =
|
|
6199
|
+
delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
|
|
6200
|
+
|
|
6201
|
+
return { h, s: s * 100, l: l * 100 };
|
|
6202
|
+
};
|
|
6203
|
+
const hueDelta = (h1, h2) => {
|
|
6204
|
+
if (!Number.isFinite(h1) || !Number.isFinite(h2)) return null;
|
|
6205
|
+
const diff = Math.abs(h1 - h2);
|
|
6206
|
+
return Math.min(diff, 360 - diff);
|
|
6207
|
+
};
|
|
5688
6208
|
|
|
5689
6209
|
const issues = [];
|
|
6210
|
+
const warnings = [];
|
|
5690
6211
|
try {
|
|
5691
6212
|
// Build tokens from the candidate config
|
|
5692
6213
|
const gen = new Generator({ design: structuredClone(designConfig) });
|
|
@@ -5889,6 +6410,45 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5889
6410
|
}
|
|
5890
6411
|
}
|
|
5891
6412
|
}
|
|
6413
|
+
|
|
6414
|
+
if (ENABLE_HUE_DRIFT_WARNINGS) {
|
|
6415
|
+
const configured = designConfig?.colors || {};
|
|
6416
|
+
const configuredDark = configured?.darkMode || {};
|
|
6417
|
+
const families = ["primary", "secondary", "accent"];
|
|
6418
|
+
|
|
6419
|
+
families.forEach((family) => {
|
|
6420
|
+
const lightBase = configured?.[family];
|
|
6421
|
+
const darkOverride = configuredDark?.[family];
|
|
6422
|
+
if (!lightBase || !darkOverride) return;
|
|
6423
|
+
|
|
6424
|
+
const lightHsl = hexToHsl(lightBase);
|
|
6425
|
+
const darkHsl = hexToHsl(darkOverride);
|
|
6426
|
+
if (!lightHsl || !darkHsl) return;
|
|
6427
|
+
|
|
6428
|
+
// For near-neutrals hue isn't meaningful enough to warn.
|
|
6429
|
+
if (
|
|
6430
|
+
lightHsl.s < MIN_SAT_FOR_HUE_WARNING &&
|
|
6431
|
+
darkHsl.s < MIN_SAT_FOR_HUE_WARNING
|
|
6432
|
+
) {
|
|
6433
|
+
return;
|
|
6434
|
+
}
|
|
6435
|
+
|
|
6436
|
+
const drift = hueDelta(lightHsl.h, darkHsl.h);
|
|
6437
|
+
if (drift == null || drift <= MAX_HUE_DRIFT) return;
|
|
6438
|
+
|
|
6439
|
+
warnings.push({
|
|
6440
|
+
path: `/colors/darkMode/${family}`,
|
|
6441
|
+
message: `Dark mode ${family} hue drifts ${drift.toFixed(
|
|
6442
|
+
1,
|
|
6443
|
+
)}deg from light ${family} (${lightHsl.h.toFixed(
|
|
6444
|
+
1,
|
|
6445
|
+
)}deg -> ${darkHsl.h.toFixed(
|
|
6446
|
+
1,
|
|
6447
|
+
)}deg). This may reduce cross-theme brand identity consistency.`,
|
|
6448
|
+
context: `dark/identity-hue-${family}`,
|
|
6449
|
+
});
|
|
6450
|
+
});
|
|
6451
|
+
}
|
|
5892
6452
|
} catch (err) {
|
|
5893
6453
|
issues.push({
|
|
5894
6454
|
path: "/",
|
|
@@ -5898,7 +6458,7 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5898
6458
|
});
|
|
5899
6459
|
}
|
|
5900
6460
|
|
|
5901
|
-
return { ok: issues.length === 0, issues };
|
|
6461
|
+
return { ok: issues.length === 0, issues, warnings };
|
|
5902
6462
|
}
|
|
5903
6463
|
|
|
5904
6464
|
/**
|
|
@@ -5907,7 +6467,7 @@ export function validateDesign(designConfig = {}, options = {}) {
|
|
|
5907
6467
|
*
|
|
5908
6468
|
* @param {Array<object>} designs - Array of design configs; items may include an optional `name` property.
|
|
5909
6469
|
* @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}> }> }}
|
|
6470
|
+
* @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
6471
|
*/
|
|
5912
6472
|
export function validateDesigns(designs = [], options = {}) {
|
|
5913
6473
|
const results = [];
|