@loworbitstudio/visor-theme-engine 0.4.0 → 0.4.2

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.
@@ -964,8 +964,11 @@ var LIGHTNESS_TARGETS = {
964
964
  200: 0.87,
965
965
  300: 0.78,
966
966
  400: 0.65,
967
- 500: -1,
968
- // placeholder replaced by input L at anchor (brand color lives at 500)
967
+ // 500 is the reference midpoint (Tailwind gray-500's OKLCH L ≈ 0.55).
968
+ // At the anchor shade the input L is used directly; this value seeds the
969
+ // interpolation math in computeLightness() for inputs that don't land at
970
+ // the reference midpoint.
971
+ 500: 0.55,
969
972
  600: 0.45,
970
973
  700: 0.38,
971
974
  800: 0.3,
@@ -1012,20 +1015,20 @@ function computeLightness(step, inputL, anchorShade) {
1012
1015
  if (step === anchorShade) {
1013
1016
  return inputL;
1014
1017
  }
1015
- const anchorTarget = anchorShade === 600 ? inputL : LIGHTNESS_TARGETS[anchorShade];
1018
+ const anchorTarget = LIGHTNESS_TARGETS[anchorShade];
1016
1019
  const stepTarget = LIGHTNESS_TARGETS[step];
1017
1020
  if (Math.abs(anchorTarget - inputL) < 0.01) {
1018
1021
  return stepTarget;
1019
1022
  }
1020
1023
  if (step < anchorShade) {
1021
- const anchorDefaultL = anchorShade === 600 ? 0.45 : LIGHTNESS_TARGETS[anchorShade];
1024
+ const anchorDefaultL = LIGHTNESS_TARGETS[anchorShade];
1022
1025
  const rawRange = 0.97 - anchorDefaultL;
1023
1026
  const newRange = 0.97 - inputL;
1024
1027
  if (rawRange <= 0) return stepTarget;
1025
1028
  const t = (stepTarget - anchorDefaultL) / rawRange;
1026
1029
  return inputL + t * newRange;
1027
1030
  } else {
1028
- const anchorDefaultL = anchorShade === 600 ? 0.45 : LIGHTNESS_TARGETS[anchorShade];
1031
+ const anchorDefaultL = LIGHTNESS_TARGETS[anchorShade];
1029
1032
  const rawRange = anchorDefaultL - 0.14;
1030
1033
  const newRange = inputL - 0.14;
1031
1034
  if (rawRange <= 0) return stepTarget;
@@ -1043,7 +1046,7 @@ function generateShadeScale(color, role) {
1043
1046
  for (const step of steps) {
1044
1047
  const targetL = computeLightness(step, inputL, anchorShade);
1045
1048
  let targetC = inputC * CHROMA_MULTIPLIERS[step];
1046
- if (role === "neutral") {
1049
+ if (role === "neutral" && step !== anchorShade) {
1047
1050
  targetC = Math.min(targetC, maxNeutralChroma);
1048
1051
  }
1049
1052
  scale[step] = oklchToHex(targetL, targetC, inputH);
@@ -1366,6 +1369,26 @@ function generateFullBundleCss(primitives, tokens, config) {
1366
1369
  return lines.join("\n");
1367
1370
  }
1368
1371
 
1372
+ // src/types.ts
1373
+ var MATERIAL_TEXT_SLOTS = [
1374
+ "displayLarge",
1375
+ "displayMedium",
1376
+ "displaySmall",
1377
+ "headlineLarge",
1378
+ "headlineMedium",
1379
+ "headlineSmall",
1380
+ "titleLarge",
1381
+ "titleMedium",
1382
+ "titleSmall",
1383
+ "bodyLarge",
1384
+ "bodyMedium",
1385
+ "bodySmall",
1386
+ "labelLarge",
1387
+ "labelMedium",
1388
+ "labelSmall",
1389
+ "labelXSmall"
1390
+ ];
1391
+
1369
1392
  export {
1370
1393
  googleFontsCatalog,
1371
1394
  lookupGoogleFont,
@@ -1392,6 +1415,7 @@ export {
1392
1415
  isValidColor,
1393
1416
  compositeOverBackground,
1394
1417
  serializeColor,
1418
+ MATERIAL_TEXT_SLOTS,
1395
1419
  FULL_SHADE_STEPS,
1396
1420
  SELECTIVE_SHADE_STEPS,
1397
1421
  TAILWIND_GRAY,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FontResolveOptions, a as FontResolution, V as VisorTypography, b as FontDisplayStrategy, T as ThemeFontResult, G as GoogleFontEntry, R as ResolvedThemeConfig, c as GeneratedPrimitives, d as ThemeOutput, e as ThemeData, f as VisorThemeConfig, g as FullShadeScale, C as ColorRole, S as SelectiveShadeScale, h as RGB, P as ParsedColor, O as OKLCH, i as SemanticTokens, j as ShadeStep } from './types-DgAumoCX.js';
2
- export { k as ColorFormat, l as FontSource, m as RGBA, n as SemanticTokenValue } from './types-DgAumoCX.js';
1
+ import { F as FontResolveOptions, a as FontResolution, V as VisorTypography, b as FontDisplayStrategy, T as ThemeFontResult, G as GoogleFontEntry, R as ResolvedThemeConfig, c as GeneratedPrimitives, d as ThemeOutput, e as ThemeData, f as VisorThemeConfig, g as FullShadeScale, C as ColorRole, S as SelectiveShadeScale, h as RGB, P as ParsedColor, O as OKLCH, i as SemanticTokens, j as ShadeStep } from './types-ljcTtODU.js';
2
+ export { k as ColorFormat, l as FontSource, m as RGBA, n as SemanticTokenValue } from './types-ljcTtODU.js';
3
3
 
4
4
  /**
5
5
  * Font resolver — maps font family names to loadable font resources.
@@ -97,7 +97,7 @@ declare function lookupGoogleFont(family: string): GoogleFontEntry | undefined;
97
97
  */
98
98
 
99
99
  /**
100
- * Generate all shade scales from a resolved config.
100
+ * Generate all shade scales from a resolved config (light-mode colors).
101
101
  * If neutral is null, uses Tailwind Gray verbatim.
102
102
  */
103
103
  declare function generatePrimitives(config: ResolvedThemeConfig): GeneratedPrimitives;
@@ -367,6 +367,61 @@ var properties = {
367
367
  type: "string"
368
368
  }
369
369
  }
370
+ },
371
+ slots: {
372
+ type: "object",
373
+ description: "Per-slot overrides for the generated Flutter Material TextTheme. Any subset of the 16 slots may be specified; omitted slots fall through to the Material 3 2024 defaults shipped in visor_core.",
374
+ additionalProperties: false,
375
+ properties: {
376
+ displayLarge: {
377
+ $ref: "#/$defs/textSlotOverride"
378
+ },
379
+ displayMedium: {
380
+ $ref: "#/$defs/textSlotOverride"
381
+ },
382
+ displaySmall: {
383
+ $ref: "#/$defs/textSlotOverride"
384
+ },
385
+ headlineLarge: {
386
+ $ref: "#/$defs/textSlotOverride"
387
+ },
388
+ headlineMedium: {
389
+ $ref: "#/$defs/textSlotOverride"
390
+ },
391
+ headlineSmall: {
392
+ $ref: "#/$defs/textSlotOverride"
393
+ },
394
+ titleLarge: {
395
+ $ref: "#/$defs/textSlotOverride"
396
+ },
397
+ titleMedium: {
398
+ $ref: "#/$defs/textSlotOverride"
399
+ },
400
+ titleSmall: {
401
+ $ref: "#/$defs/textSlotOverride"
402
+ },
403
+ bodyLarge: {
404
+ $ref: "#/$defs/textSlotOverride"
405
+ },
406
+ bodyMedium: {
407
+ $ref: "#/$defs/textSlotOverride"
408
+ },
409
+ bodySmall: {
410
+ $ref: "#/$defs/textSlotOverride"
411
+ },
412
+ labelLarge: {
413
+ $ref: "#/$defs/textSlotOverride"
414
+ },
415
+ labelMedium: {
416
+ $ref: "#/$defs/textSlotOverride"
417
+ },
418
+ labelSmall: {
419
+ $ref: "#/$defs/textSlotOverride"
420
+ },
421
+ labelXSmall: {
422
+ $ref: "#/$defs/textSlotOverride"
423
+ }
424
+ }
370
425
  }
371
426
  }
372
427
  },
@@ -432,6 +487,29 @@ var properties = {
432
487
  }
433
488
  }
434
489
  },
490
+ strokeWidths: {
491
+ type: "object",
492
+ description: "Stroke-width scale in pixels — used for borders, outlines, dividers, progress-indicator strokes. Defaults: thin=1, regular=1.5, medium=2, thick=2.5.",
493
+ additionalProperties: false,
494
+ properties: {
495
+ thin: {
496
+ type: "number",
497
+ minimum: 0
498
+ },
499
+ regular: {
500
+ type: "number",
501
+ minimum: 0
502
+ },
503
+ medium: {
504
+ type: "number",
505
+ minimum: 0
506
+ },
507
+ thick: {
508
+ type: "number",
509
+ minimum: 0
510
+ }
511
+ }
512
+ },
435
513
  motion: {
436
514
  type: "object",
437
515
  description: "Motion/animation configuration.",
@@ -478,6 +556,20 @@ var properties = {
478
556
  }
479
557
  }
480
558
  }
559
+ },
560
+ migrate: {
561
+ type: "object",
562
+ description: "Migration metadata consumed by `visor migrate` commands. Does not affect CSS generation or theme application.",
563
+ additionalProperties: false,
564
+ properties: {
565
+ "token-substitution": {
566
+ type: "object",
567
+ description: "§3.1 V7-primitive → Visor-semantic substitution table. Maps V7 CSS custom property names (with -- prefix) to Visor semantic token names. Consumed by `visor migrate token-substitution`.",
568
+ additionalProperties: {
569
+ type: "string"
570
+ }
571
+ }
572
+ }
481
573
  }
482
574
  };
483
575
  var $defs = {
@@ -498,6 +590,28 @@ var $defs = {
498
590
  pattern: "^oklch\\("
499
591
  }
500
592
  ]
593
+ },
594
+ textSlotOverride: {
595
+ type: "object",
596
+ description: "Per-slot override for one Material TextTheme entry.",
597
+ additionalProperties: false,
598
+ properties: {
599
+ size: {
600
+ type: "number",
601
+ exclusiveMinimum: 0,
602
+ description: "Font size in logical pixels (Flutter TextStyle.fontSize)."
603
+ },
604
+ weight: {
605
+ type: "integer",
606
+ minimum: 100,
607
+ maximum: 900,
608
+ description: "Font weight."
609
+ },
610
+ "letter-spacing": {
611
+ type: "number",
612
+ description: "Letter spacing in logical pixels (Flutter TextStyle.letterSpacing). Material defaults include negative values, e.g. -0.25 for displayLarge."
613
+ }
614
+ }
501
615
  }
502
616
  };
503
617
  var visorTheme_schema = {
@@ -658,10 +772,12 @@ declare function resolveConfig(config: VisorThemeConfig): ResolvedThemeConfig;
658
772
  */
659
773
 
660
774
  /**
661
- * Assign semantic tokens from generated shade scales and resolved config.
662
- * Returns concrete hex values for all ~55 tokens in both light and dark modes.
775
+ * Assign semantic tokens from mode-specific shade scales and resolved config.
776
+ * lightPrimitives drives light-mode token values; darkPrimitives drives dark-mode
777
+ * values — allowing themes with colors-dark overrides to produce correct dark
778
+ * semantic tokens (e.g. surface-accent-default uses the dark brand color).
663
779
  */
664
- declare function assignSemanticTokens(primitives: GeneratedPrimitives, config: ResolvedThemeConfig): SemanticTokens;
780
+ declare function assignSemanticTokens(lightPrimitives: GeneratedPrimitives, darkPrimitives: GeneratedPrimitives, config: ResolvedThemeConfig): SemanticTokens;
665
781
 
666
782
  /**
667
783
  * Override Application (Stage 4)