@breadstone/mosaik-themes 0.0.231 → 0.0.233

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/index.d.mts CHANGED
@@ -1,5 +1,200 @@
1
1
  import { IEventEmitter } from '@breadstone/mosaik-elements';
2
2
 
3
+ /**
4
+ * @public
5
+ */
6
+ declare function darken(hex: string, factor: number): string;
7
+ /**
8
+ * @public
9
+ */
10
+ declare function lighten(hex: string, factor: number): string;
11
+
12
+ /**
13
+ * Generate an analogous color palette
14
+ * @param baseHex
15
+ * @param adjustment
16
+ * @returns
17
+ */
18
+ declare function generateAnalogousPalette(baseHex: string, adjustment: number): Record<string, string>;
19
+ /**
20
+ * Generate a single analogous color
21
+ * @param baseHex
22
+ * @param adjustment
23
+ * @returns
24
+ */
25
+ declare function generateAnalogousColor(baseHex: string, adjustment: number): string;
26
+
27
+ /**
28
+ * Generates a complementary color palette based on the given base color.
29
+ * @param baseHex
30
+ * @returns
31
+ */
32
+ declare function generateComplementaryPalette(baseHex: string): Record<string, string>;
33
+ /**
34
+ * Generates a single complementary color based on the given base color.
35
+ * @param baseHex
36
+ * @returns
37
+ */
38
+ declare function generateComplementaryColor(baseHex: string): string;
39
+
40
+ /**
41
+ * Generates a material color palette based on the given hex color.
42
+ * @param hexColor
43
+ * @returns
44
+ */
45
+ declare function generateMaterialPalette(hexColor: string): Record<string, string>;
46
+
47
+ /**
48
+ * Generates split-complementary colors based on the given base color.
49
+ * Split-complementary uses two colors adjacent to the complement (150° and 210°).
50
+ *
51
+ * @param baseHex - The base color in hex format.
52
+ * @returns An array of two split-complementary colors.
53
+ * @public
54
+ */
55
+ declare function generateSplitComplementaryColors(baseHex: string): [string, string];
56
+ /**
57
+ * Generates the first split-complementary color (150° from base).
58
+ *
59
+ * @param baseHex - The base color in hex format.
60
+ * @returns The first split-complementary color.
61
+ * @public
62
+ */
63
+ declare function generateSplitComplementaryColor1(baseHex: string): string;
64
+ /**
65
+ * Generates the second split-complementary color (210° from base).
66
+ *
67
+ * @param baseHex - The base color in hex format.
68
+ * @returns The second split-complementary color.
69
+ * @public
70
+ */
71
+ declare function generateSplitComplementaryColor2(baseHex: string): string;
72
+
73
+ /**
74
+ * Generates tetradic (square) colors based on the given base color.
75
+ * Tetradic uses four colors evenly spaced around the color wheel (90° apart).
76
+ *
77
+ * @param baseHex - The base color in hex format.
78
+ * @returns An array of three tetradic colors (excluding the base).
79
+ * @public
80
+ */
81
+ declare function generateTetradicColors(baseHex: string): [string, string, string];
82
+ /**
83
+ * Generates the first tetradic color (90° from base).
84
+ *
85
+ * @param baseHex - The base color in hex format.
86
+ * @returns The first tetradic color.
87
+ * @public
88
+ */
89
+ declare function generateTetradicColor1(baseHex: string): string;
90
+ /**
91
+ * Generates the third tetradic color (270° from base).
92
+ *
93
+ * @param baseHex - The base color in hex format.
94
+ * @returns The third tetradic color.
95
+ * @public
96
+ */
97
+ declare function generateTetradicColor3(baseHex: string): string;
98
+
99
+ /**
100
+ * Generate a triadic color palette
101
+ * @param baseHex
102
+ * @param adjustment
103
+ * @returns
104
+ */
105
+ declare function generateTriadicPalette(baseHex: string, adjustment: number): Record<string, string>;
106
+ /**
107
+ * Generate a single triadic color
108
+ * @param baseHex
109
+ * @param adjustment
110
+ * @returns
111
+ */
112
+ declare function generateTriadicColor(baseHex: string, adjustment: number): string;
113
+
114
+ declare namespace Colors {
115
+ const toDarken: typeof darken;
116
+ const toLighten: typeof lighten;
117
+ const toMaterialPalette: typeof generateMaterialPalette;
118
+ const toComplementaryPalette: typeof generateComplementaryPalette;
119
+ const toComplementaryColor: typeof generateComplementaryColor;
120
+ const toAnalogousPalette: typeof generateAnalogousPalette;
121
+ const toAnalogousColor: typeof generateAnalogousColor;
122
+ const toTriadicPalette: typeof generateTriadicPalette;
123
+ const toTriadicColor: typeof generateTriadicColor;
124
+ const toSplitComplementaryColors: typeof generateSplitComplementaryColors;
125
+ const toSplitComplementaryColor1: typeof generateSplitComplementaryColor1;
126
+ const toSplitComplementaryColor2: typeof generateSplitComplementaryColor2;
127
+ const toTetradicColors: typeof generateTetradicColors;
128
+ const toTetradicColor1: typeof generateTetradicColor1;
129
+ const toTetradicColor3: typeof generateTetradicColor3;
130
+ }
131
+
132
+ /**
133
+ * Platform adapter interface for abstracting browser APIs.
134
+ * Allows ThemeObserver and ThemeGenerator to work in both browser and Node.js environments.
135
+ *
136
+ * @public
137
+ */
138
+ interface IPlatformAdapter {
139
+ /**
140
+ * Checks if media query matches (e.g., prefers-color-scheme).
141
+ */
142
+ matchMedia(query: string): boolean;
143
+ /**
144
+ * Sets an attribute on the document element.
145
+ */
146
+ setDocumentAttribute(name: string, value: string): void;
147
+ /**
148
+ * Gets an attribute from the document element.
149
+ */
150
+ getDocumentAttribute(name: string): string | null;
151
+ /**
152
+ * Observes changes to document element attributes.
153
+ */
154
+ observeDocumentAttributes(attributes: Array<string>, callback: (attributeName: string, newValue: string | null) => void): () => void;
155
+ }
156
+
157
+ /**
158
+ * Browser implementation of the platform adapter.
159
+ * Uses native DOM APIs (window, document, MutationObserver).
160
+ *
161
+ * @public
162
+ */
163
+ declare class BrowserPlatformAdapter implements IPlatformAdapter {
164
+ matchMedia(query: string): boolean;
165
+ setDocumentAttribute(name: string, value: string): void;
166
+ getDocumentAttribute(name: string): string | null;
167
+ observeDocumentAttributes(attributes: Array<string>, callback: (attributeName: string, newValue: string | null) => void): () => void;
168
+ }
169
+
170
+ /**
171
+ * Node.js implementation of the platform adapter.
172
+ * No-op implementation that doesn't crash but does nothing.
173
+ *
174
+ * @public
175
+ */
176
+ declare class NodePlatformAdapter implements IPlatformAdapter {
177
+ matchMedia(_query: string): boolean;
178
+ setDocumentAttribute(_name: string, _value: string): void;
179
+ getDocumentAttribute(_name: string): string | null;
180
+ observeDocumentAttributes(_attributes: Array<string>, _callback: (attributeName: string, newValue: string | null) => void): () => void;
181
+ }
182
+
183
+ /**
184
+ * Factory that automatically detects the environment and returns the appropriate adapter.
185
+ *
186
+ * @public
187
+ */
188
+ declare class PlatformAdapterFactory {
189
+ /**
190
+ * Creates the appropriate platform adapter based on the current environment.
191
+ * Automatically detects if running in browser or Node.js.
192
+ *
193
+ * @public
194
+ */
195
+ static create(): IPlatformAdapter;
196
+ }
197
+
3
198
  /**
4
199
  * @public
5
200
  */
@@ -287,7 +482,7 @@ interface IThemeTypographyFontType {
287
482
  *
288
483
  * @public
289
484
  */
290
- type ThemeTypographyTypeName = 'headline1' | 'headline2' | 'headline3' | 'headline4' | 'headline5' | 'headline6' | 'subtitle1' | 'subtitle2' | 'body1' | 'body2' | 'button' | 'caption' | 'overline';
485
+ type ThemeTypographyTypeName = 'headline1' | 'headline2' | 'headline3' | 'headline4' | 'headline5' | 'headline6' | 'subtitle1' | 'subtitle2' | 'body1' | 'body2' | 'supporting' | 'button' | 'caption' | 'overline';
291
486
  /**
292
487
  * Represents dynamic typography styles.
293
488
  *
@@ -401,6 +596,18 @@ interface IThemeMetadata {
401
596
  typographies: Array<string>;
402
597
  }
403
598
 
599
+ declare namespace CosmopolitanTheme {
600
+ const COSMOPOLITAN_THEME: ITheme;
601
+ const COSMOPOLITAN_THEME_PALETTES: string[];
602
+ const COSMOPOLITAN_THEME_PALETTE_VARIANTS: string[];
603
+ const COSMOPOLITAN_THEME_SCHEMES: string[];
604
+ const COSMOPOLITAN_THEME_SCHEME_VARIANTS: string[];
605
+ const COSMOPOLITAN_THEME_ELEVATION: string[];
606
+ const COSMOPOLITAN_THEME_ELEVATION_VARIANTS: string[];
607
+ const COSMOPOLITAN_THEME_TYPOGRAPHY: string[];
608
+ const COSMOPOLITAN_THEME_METADATA: IThemeMetadata;
609
+ }
610
+
404
611
  declare namespace JoyTheme {
405
612
  const JOY_THEME: ITheme;
406
613
  const JOY_THEME_PALETTES: string[];
@@ -425,209 +632,181 @@ declare namespace MemphisTheme {
425
632
  const MEMPHIS_THEME_METADATA: IThemeMetadata;
426
633
  }
427
634
 
428
- declare namespace CosmopolitanTheme {
429
- const COSMOPOLITAN_THEME: ITheme;
430
- const COSMOPOLITAN_THEME_PALETTES: string[];
431
- const COSMOPOLITAN_THEME_PALETTE_VARIANTS: string[];
432
- const COSMOPOLITAN_THEME_SCHEMES: string[];
433
- const COSMOPOLITAN_THEME_SCHEME_VARIANTS: string[];
434
- const COSMOPOLITAN_THEME_ELEVATION: string[];
435
- const COSMOPOLITAN_THEME_ELEVATION_VARIANTS: string[];
436
- const COSMOPOLITAN_THEME_TYPOGRAPHY: string[];
437
- const COSMOPOLITAN_THEME_METADATA: IThemeMetadata;
438
- }
439
-
440
- /**
441
- * @public
442
- */
443
- type CssAspectRatio = 'auto' | `${number}` | `${number}/${number}`;
444
635
  /**
636
+ * Strategy interface for theme-specific palette and scheme generation.
637
+ *
445
638
  * @public
446
639
  */
447
- declare namespace CssAspectRatio {
640
+ interface IThemeGeneratorStrategy {
448
641
  /**
449
- * @public
642
+ * Determines whether a color is within the expected luminance range for the given mode.
643
+ *
644
+ * @param color - The color to check
645
+ * @param mode - The color mode (dark or light)
646
+ * @returns True if the color is naturally compatible with the given mode
450
647
  */
451
- function isCssAspectRatio(value: unknown): value is CssAspectRatio;
648
+ isColorInModeSpectrum(color: CssColor, mode: Omit<ThemeMode, 'system'>): boolean;
649
+ /**
650
+ * Adapts a color to be compatible with the opposite mode by inverting its
651
+ * perceptual lightness.
652
+ *
653
+ * @remarks
654
+ * The inversion is symmetric (light ↔ dark), so the target mode does not
655
+ * need to be specified — the result always "flips" into the other spectrum.
656
+ *
657
+ * @param color - The color to adapt
658
+ * @returns The adapted color with inverted lightness
659
+ */
660
+ adaptColorToMode(color: CssColor): CssColor;
661
+ /**
662
+ * Generates a color palette for the theme.
663
+ *
664
+ * @param baseColor - The base color to generate the palette from
665
+ * @param mode - The color mode (dark or light)
666
+ * @returns The generated palette with all shades steps
667
+ */
668
+ generatePalette(baseColor: CssColor, mode: Omit<ThemeMode, 'system'>): Required<ThemePalette>;
669
+ /**
670
+ * Generates a color scheme for the theme.
671
+ *
672
+ * @param baseColor - The base color to generate the scheme from
673
+ * @param mode - The color mode (dark or light)
674
+ * @returns The generated scheme with semantic color roles
675
+ */
676
+ generateScheme(baseColor: CssColor, mode: Omit<ThemeMode, 'system'>): Required<ThemeScheme>;
452
677
  }
453
678
 
454
679
  /**
680
+ * Abstract theme generator strategy that operates in the **HSL** (Hue, Saturation, Lightness)
681
+ * color space.
682
+ *
683
+ * @remarks
684
+ * HSL is a cylindrical color model widely used in CSS and web design tooling.
685
+ * Unlike LCH it is not perceptually uniform, but it provides a familiar and
686
+ * lightweight alternative for palette generation.
687
+ *
688
+ * Concrete themes that prefer HSL-based generation extend this class.
689
+ *
455
690
  * @public
691
+ * @abstract
456
692
  */
457
- type CssTimeUnit = 's' | 'ms';
458
- /**
459
- * @public
460
- */
461
- type CssTime = `${string}${CssTimeUnit}` | number | 0;
462
- /**
463
- * @public
464
- */
465
- declare namespace CssTime {
693
+ declare abstract class HslThemeGeneratorStrategy implements IThemeGeneratorStrategy {
694
+ private static readonly _LIGHTNESS_THRESHOLD;
466
695
  /**
467
- * @public
468
- */
469
- function isCssTime(value: unknown): value is CssTime;
470
- }
471
-
472
- /**
473
- * Platform adapter interface for abstracting browser APIs.
474
- * Allows ThemeObserver and ThemeGenerator to work in both browser and Node.js environments.
475
- *
476
- * @public
477
- */
478
- interface IPlatformAdapter {
479
- /**
480
- * Checks if media query matches (e.g., prefers-color-scheme).
481
- */
482
- matchMedia(query: string): boolean;
483
- /**
484
- * Sets an attribute on the document element.
485
- */
486
- setDocumentAttribute(name: string, value: string): void;
487
- /**
488
- * Gets an attribute from the document element.
489
- */
490
- getDocumentAttribute(name: string): string | null;
491
- /**
492
- * Observes changes to document element attributes.
493
- */
494
- observeDocumentAttributes(attributes: Array<string>, callback: (attributeName: string, newValue: string | null) => void): () => void;
495
- }
496
-
497
- /**
498
- * Observer for applying themes.
499
- *
500
- * @public
501
- */
502
- declare class ThemeObserver {
503
- private readonly _themeChanged;
504
- private readonly _themeModeChanged;
505
- private readonly _platformAdapter;
506
- private _currentTheme;
507
- private _currentThemeMode;
508
- private _unsubscribe?;
509
- /**
510
- * Constructs a new instance of the `ThemeObserver` class.
696
+ * Determines whether a color naturally belongs to the given mode's HSL lightness range.
697
+ *
698
+ * @remarks
699
+ * A color with HSL lightness > 0.5 is considered "light"; ≤ 0.5 is considered "dark".
511
700
  *
512
- * @param platformAdapter - Optional platform adapter. Auto-detects if not provided.
513
701
  * @public
702
+ * @param color - The color to check
703
+ * @param mode - The target color mode ('dark' | 'light')
704
+ * @returns `true` if the color is naturally compatible with the given mode
514
705
  */
515
- constructor(platformAdapter?: IPlatformAdapter);
706
+ isColorInModeSpectrum(color: CssColor, mode: 'dark' | 'light'): boolean;
516
707
  /**
517
- * Fires when the theme changes.
708
+ * Adapts a color to the opposite mode by symmetrically inverting its HSL lightness
709
+ * (`L → 1 - L`) while preserving hue and saturation.
710
+ *
711
+ * @remarks
712
+ * The inversion is symmetric: a light color becomes dark and vice-versa, regardless
713
+ * of the direction. Therefore no target mode parameter is required.
714
+ *
715
+ * The inverted lightness is clamped to [0.05, 0.95] to avoid pure black / pure white.
716
+ * Subclasses may override this method for theme-specific post-processing.
518
717
  *
519
718
  * @public
520
- * @readonly
719
+ * @param color - The color to adapt
720
+ * @returns The adapted color with inverted lightness
521
721
  */
522
- get themeChanged(): IEventEmitter<string>;
722
+ adaptColorToMode(color: CssColor): CssColor;
523
723
  /**
524
- * Fires when the theme mode changes.
724
+ * Generates a palette of shades based on a base/accent color using HSL interpolation.
525
725
  *
526
726
  * @public
527
- * @readonly
727
+ * @param baseColor - The base/accent color (e.g. "#3498db")
728
+ * @param mode - 'light' or 'dark' mode: determines how light or dark the palette extremes are.
729
+ * @returns The generated theme palette with shade steps 0–900
528
730
  */
529
- get themeModeChanged(): IEventEmitter<ThemeMode>;
731
+ generatePalette(baseColor: CssColor, mode: 'light' | 'dark'): Required<ThemePalette>;
530
732
  /**
531
- * Applies the given theme and theme mode to the document.
733
+ * Generates a semantic color scheme for UI usage, based on the generated palette.
532
734
  *
533
735
  * @public
534
- * @param theme - The theme to apply (joy, cosmopolitan or memphis).
535
- * @param themeMode - The theme mode to apply.
736
+ * @param baseColor - The base/accent color
737
+ * @param mode - 'light' or 'dark'
738
+ * @returns The generated theme scheme with semantic color roles
536
739
  */
537
- applyTheme(theme: string, themeMode: ThemeModeWithSystem): void;
538
- dispose(): void;
539
- private observe;
540
- }
541
- /**
542
- * @public
543
- */
544
- declare class ThemeObserverServiceLocator {
545
- private static _current;
546
- static get current(): ThemeObserver;
547
- static isSet(): boolean;
548
- static set(current: ThemeObserver): void;
740
+ generateScheme(baseColor: CssColor, mode: 'light' | 'dark'): Required<ThemeScheme>;
549
741
  }
550
742
 
551
743
  /**
744
+ * Abstract theme generator strategy that operates in the **LCH** (Luminance, Chroma, Hue)
745
+ * perceptual color space.
746
+ *
747
+ * @remarks
748
+ * LCH is a perceptually uniform color space where `L*` (lightness 0–100) maps linearly
749
+ * to how humans perceive brightness. This makes it ideal for reliable mode detection
750
+ * and color adaptation.
751
+ *
752
+ * Concrete themes (Joy, Memphis, Cosmopolitan, …) extend this class to inherit
753
+ * the shared color-science logic and only override behavior where their visual
754
+ * language demands it.
755
+ *
552
756
  * @public
757
+ * @abstract
553
758
  */
554
- declare class ThemeGenerator {
555
- private readonly _strategies;
556
- private readonly _platformAdapter;
557
- /**
558
- * @public
559
- * @param platformAdapter - Optional platform adapter. Auto-detects if not provided.
560
- */
561
- constructor(platformAdapter?: IPlatformAdapter);
759
+ declare abstract class LchThemeGeneratorStrategy implements IThemeGeneratorStrategy {
760
+ private static readonly _LUMINANCE_THRESHOLD;
562
761
  /**
563
- * Generates a theme palette.
762
+ * Determines whether a color naturally belongs to the given mode's luminance range.
564
763
  *
565
- * @public
566
- * @param themeName The name of the theme.
567
- * @param baseColor The base color (typically a 500 level shade).
568
- * @param mode The theme mode ('dark', 'light', or 'system').
569
- * @returns The generated theme palette.
570
- */
571
- generatePalette(themeName: string, baseColor: CssColor, mode: ThemeMode): ThemePalette;
572
- /**
573
- * Generates a theme scheme.
764
+ * @remarks
765
+ * Uses WCAG relative luminance (0 = black, 1 = white).
766
+ * A color with luminance > 0.5 is considered "light"; ≤ 0.5 is considered "dark".
574
767
  *
575
768
  * @public
576
- * @param themeName The name of the theme.
577
- * @param baseColor The base color (typically a background level shade).
578
- * @param mode The theme mode ('dark', 'light', or 'system').
579
- * @returns The generated theme scheme.
769
+ * @param color - The color to check
770
+ * @param mode - The target color mode ('dark' | 'light')
771
+ * @returns `true` if the color is naturally compatible with the given mode
580
772
  */
581
- generateScheme(themeName: string, baseColor: CssColor, mode: ThemeMode): ThemeScheme;
773
+ isColorInModeSpectrum(color: CssColor, mode: 'dark' | 'light'): boolean;
582
774
  /**
583
- * Resolves the theme mode, converting 'system' to 'dark' or 'light' based on platform settings.
775
+ * Adapts a color to the opposite mode by symmetrically inverting its perceptual
776
+ * lightness in the LCH color space (`L* → 100 - L*`) while preserving hue and chroma.
584
777
  *
585
- * @private
586
- * @param mode The theme mode to resolve.
587
- * @returns The resolved theme mode.
588
- */
589
- private resolveMode;
590
- /**
591
- * Gets the theme generator strategy for the specified theme name.
778
+ * @remarks
779
+ * The inversion is symmetric: a light color becomes dark and vice-versa, regardless
780
+ * of the direction. Therefore no target mode parameter is required.
592
781
  *
593
- * @private
594
- * @param themeName The name of the theme.
595
- * @returns The theme generator strategy.
782
+ * The inverted lightness is clamped to [5, 95] to avoid pure black / pure white,
783
+ * which cannot carry chromatic information.
784
+ * Subclasses may override this method to apply theme-specific post-processing
785
+ * (e.g., chroma reduction for muted palettes).
786
+ *
787
+ * @public
788
+ * @param color - The color to adapt
789
+ * @returns The adapted color with inverted lightness
596
790
  */
597
- private getStrategy;
598
- }
599
- /**
600
- * @public
601
- */
602
- declare class ThemeGeneratorServiceLocator {
603
- private static _current;
604
- static get current(): ThemeGenerator;
605
- static isSet(): boolean;
606
- static set(current: ThemeGenerator): void;
607
- }
608
-
609
- /**
610
- * Strategy interface for theme-specific palette and scheme generation.
611
- *
612
- * @public
613
- */
614
- interface IThemeGeneratorStrategy {
791
+ adaptColorToMode(color: CssColor): CssColor;
615
792
  /**
616
- * Generates a color palette for the theme.
793
+ * Generates a color palette from a base color for the given mode.
617
794
  *
618
- * @param baseColor - The base color to generate the palette from
619
- * @param mode - The color mode (dark or light)
620
- * @returns The generated palette
795
+ * @public
796
+ * @param baseColor - The base/accent color
797
+ * @param mode - 'light' or 'dark' mode
798
+ * @returns The generated theme palette with shade steps 0–900
621
799
  */
622
- generatePalette(baseColor: CssColor, mode: Omit<ThemeMode, 'system'>): ThemePalette;
800
+ generatePalette(baseColor: CssColor, mode: 'dark' | 'light'): Required<ThemePalette>;
623
801
  /**
624
- * Generates a color scheme for the theme.
802
+ * Generates a semantic color scheme based on a base color and mode.
625
803
  *
626
- * @param baseColor - The base color to generate the scheme from
627
- * @param mode - The color mode (dark or light)
628
- * @returns The generated scheme
804
+ * @public
805
+ * @param baseColor - The base/accent color
806
+ * @param mode - 'light' or 'dark' mode
807
+ * @returns The generated theme scheme with semantic color roles
629
808
  */
630
- generateScheme(baseColor: CssColor, mode: Omit<ThemeMode, 'system'>): ThemeScheme;
809
+ generateScheme(baseColor: CssColor, mode: 'dark' | 'light'): Required<ThemeScheme>;
631
810
  }
632
811
 
633
812
  /**
@@ -638,49 +817,59 @@ interface IThemeGeneratorStrategy {
638
817
  type ThemeGeneratorFactoryFn = () => IThemeGeneratorStrategy;
639
818
 
640
819
  /**
641
- * Material Design theme generator strategy.
820
+ * Cosmopolitan theme generator strategy.
821
+ *
822
+ * @remarks
823
+ * Extends {@link LchThemeGeneratorStrategy} with a muted, desaturated aesthetic
824
+ * that defines the Cosmopolitan visual language. Overrides only where the default
825
+ * LCH behavior needs adjustment; all other behavior is inherited.
642
826
  *
643
827
  * @public
644
828
  */
645
- declare class MaterialThemeGeneratorStrategy implements IThemeGeneratorStrategy {
646
- constructor();
829
+ declare class CosmopolitanThemeGeneratorStrategy extends LchThemeGeneratorStrategy {
830
+ private static readonly _CHROMA_REDUCTION_FACTOR;
647
831
  /**
648
- * Generates a color palette for the Material theme.
832
+ * Adapts a color to the target mode by inverting its perceptual lightness (LCH L*)
833
+ * with a slight chroma reduction for the Cosmopolitan's muted aesthetic.
649
834
  *
835
+ * @override
650
836
  * @public
651
- * @param baseColor The base/accent color.
652
- * @param mode 'light' or 'dark' mode.
653
- * @returns The generated theme palette.
837
+ * @param color - The color to adapt
838
+ * @returns The adapted color with inverted lightness and reduced chroma
654
839
  */
655
- generatePalette(baseColor: CssColor, mode: 'dark' | 'light'): ThemePalette;
840
+ adaptColorToMode(color: CssColor): CssColor;
656
841
  /**
657
- * Generates a semantic color scheme for Material theme usage, based on the generated palette.
842
+ * Generates a color palette with Cosmopolitan-specific dark-mode mixing.
658
843
  *
844
+ * @remarks
845
+ * Light mode uses the standard LCH base class implementation.
846
+ * Dark mode uses a simplified three-anchor approach (steps 0, 100, 500)
847
+ * to produce the flat, muted dark palette that defines Cosmopolitan.
848
+ *
849
+ * @override
659
850
  * @public
660
- * @param baseColor The base/accent color.
661
- * @param mode 'light' or 'dark' mode.
662
- * @returns The generated theme scheme.
851
+ * @param baseColor - The base/accent color
852
+ * @param mode - 'light' or 'dark' mode
853
+ * @returns The generated theme palette with shade steps 0–900
663
854
  */
664
- generateScheme(baseColor: CssColor, mode: 'dark' | 'light'): ThemeScheme;
855
+ generatePalette(baseColor: CssColor, mode: 'dark' | 'light'): Required<ThemePalette>;
665
856
  }
666
857
  /**
667
- * Generates a Material theme generator strategy.
858
+ * Generates a Cosmopolitan theme generator strategy.
668
859
  *
669
860
  * @public
670
861
  */
671
- declare function createMaterialTheme(): ThemeGeneratorFactoryFn;
862
+ declare function createCosmopolitanTheme(): ThemeGeneratorFactoryFn;
672
863
 
673
864
  /**
674
- * Joy UI theme generator strategy.
675
- * Uses the same generation logic as Material Design.
865
+ * Joy theme generator strategy.
866
+ *
867
+ * @remarks
868
+ * Extends {@link LchThemeGeneratorStrategy} without customization.
676
869
  *
677
870
  * @public
678
871
  */
679
- declare class JoyThemeGeneratorStrategy implements IThemeGeneratorStrategy {
680
- private readonly _materialStrategy;
681
- constructor();
682
- generatePalette(baseColor: CssColor, mode: 'dark' | 'light'): ThemePalette;
683
- generateScheme(baseColor: CssColor, mode: 'dark' | 'light'): ThemeScheme;
872
+ declare class JoyThemeGeneratorStrategy extends LchThemeGeneratorStrategy {
684
873
  }
685
874
  /**
686
875
  * Generates a Joy theme generator strategy.
@@ -691,15 +880,13 @@ declare function createJoyTheme(): ThemeGeneratorFactoryFn;
691
880
 
692
881
  /**
693
882
  * Memphis theme generator strategy.
694
- * Uses the same generation logic as Material Design.
883
+ *
884
+ * @remarks
885
+ * Extends {@link LchThemeGeneratorStrategy} without customization.
695
886
  *
696
887
  * @public
697
888
  */
698
- declare class MemphisThemeGeneratorStrategy implements IThemeGeneratorStrategy {
699
- private readonly _materialStrategy;
700
- constructor();
701
- generatePalette(baseColor: CssColor, mode: 'dark' | 'light'): ThemePalette;
702
- generateScheme(baseColor: CssColor, mode: 'dark' | 'light'): ThemeScheme;
889
+ declare class MemphisThemeGeneratorStrategy extends LchThemeGeneratorStrategy {
703
890
  }
704
891
  /**
705
892
  * Generates a Memphis theme generator strategy.
@@ -709,241 +896,207 @@ declare class MemphisThemeGeneratorStrategy implements IThemeGeneratorStrategy {
709
896
  declare function createMemphisTheme(): ThemeGeneratorFactoryFn;
710
897
 
711
898
  /**
712
- * Cosmopolitan theme generator strategy.
899
+ * Central facade for generating theme palettes and color schemes.
713
900
  *
714
- * @public
715
- */
716
- declare class CosmopolitanThemeGeneratorStrategy implements IThemeGeneratorStrategy {
717
- private readonly _materialStrategy;
718
- constructor();
719
- generatePalette(baseColor: CssColor, mode: 'dark' | 'light'): ThemePalette;
720
- generateScheme(baseColor: CssColor, mode: 'dark' | 'light'): ThemeScheme;
721
- }
722
- /**
723
- * Generates a Cosmopolitan theme generator strategy.
901
+ * @remarks
902
+ * Accepts any base color with any mode and autonomously ensures compatibility
903
+ * before delegating to the resolved {@link IThemeGeneratorStrategy}.
904
+ * The `'system'` mode is resolved to `'dark'` or `'light'` via the
905
+ * {@link IPlatformAdapter}.
724
906
  *
725
907
  * @public
726
908
  */
727
- declare function createCosmopolitanTheme(): ThemeGeneratorFactoryFn;
728
-
729
- /**
730
- * Tailwind-like strategy.
731
- *
732
- * Generates a color palette with the following shade steps:
733
- * 50, 100, 200, 300, 400, 500, 600, 700, 800, 900.
734
- *
735
- * Each returned color is a hex string (CssColor).
736
- */
737
- declare class TailwindThemeGeneratorStrategy implements IThemeGeneratorStrategy {
909
+ declare class ThemeGenerator {
910
+ private readonly _strategies;
911
+ private readonly _platformAdapter;
912
+ /**
913
+ * @public
914
+ * @param platformAdapter - Optional platform adapter. Auto-detects if not provided.
915
+ */
916
+ constructor(platformAdapter?: IPlatformAdapter);
738
917
  /**
739
- * Generates a palette of shades based on a base/accent color.
918
+ * Generates a complete theme palette (shades 0–900) for the given theme.
740
919
  *
741
- * @param baseColor - The base/accent color (e.g. "#3498db")
742
- * @param mode - 'light' or 'dark' mode: determines how light or dark the palette extremes are.
743
- * @returns An IThemePalette mapping each shade step to a hex color.
920
+ * @remarks
921
+ * 1. If `mode` is `'system'`, it is resolved to `'dark'` or `'light'` via the
922
+ * platform adapter's `prefers-color-scheme` media query.
923
+ * 2. The base color is forwarded as-is to the theme-specific strategy which
924
+ * produces 11 shade steps from lightest (0) to darkest (900).
925
+ *
926
+ * No automatic color adaptation is performed. Callers who need mode-compatible
927
+ * colors can use {@link IThemeGeneratorStrategy.isColorInModeSpectrum} and
928
+ * {@link IThemeGeneratorStrategy.adaptColorToMode} explicitly before calling
929
+ * this method.
744
930
  *
745
- * Example (light mode, baseColor = blue-ish):
746
- * {
747
- * "50": "#f5faff",
748
- * "100": "#e1f3ff",
749
- * ...
750
- * "500": "#3498db",
751
- * ...
752
- * "900": "#0a2d4b"
753
- * }
931
+ * @public
932
+ * @param themeName - The name of the theme (`'joy'`, `'memphis'`, `'cosmopolitan'`).
933
+ * @param baseColor - The base accent color (any valid CSS color value).
934
+ * @param mode - The target mode (`'dark'`, `'light'`, or `'system'`).
935
+ * @returns A fully populated palette with shade keys `0`–`900`.
936
+ * @throws Error if `themeName` is not a registered theme.
754
937
  */
755
- generatePalette(baseColor: CssColor, mode: 'light' | 'dark'): ThemePalette;
938
+ generatePalette(themeName: string, baseColor: CssColor, mode: ThemeMode): Required<ThemePalette>;
756
939
  /**
757
- * Generates a semantic color scheme for UI usage, based on the generated palette.
940
+ * Generates a semantic color scheme (surface, foreground, highlight, …) for the given theme.
758
941
  *
759
- * @param baseColor - The base/accent color
760
- * @param mode - 'light' or 'dark'
761
- * @returns An scheme with semantic color roles.
942
+ * @remarks
943
+ * 1. If `mode` is `'system'`, it is resolved to `'dark'` or `'light'` via the
944
+ * platform adapter's `prefers-color-scheme` media query.
945
+ * 2. The base color is forwarded as-is to the theme-specific strategy which
946
+ * maps it to semantic roles such as `surface`, `foreground`, `highlight`,
947
+ * `contrast`, `disabled`, etc.
948
+ *
949
+ * No automatic color adaptation is performed. Callers who need mode-compatible
950
+ * colors can use {@link IThemeGeneratorStrategy.isColorInModeSpectrum} and
951
+ * {@link IThemeGeneratorStrategy.adaptColorToMode} explicitly before calling
952
+ * this method.
953
+ *
954
+ * @public
955
+ * @param themeName - The name of the theme (`'joy'`, `'memphis'`, `'cosmopolitan'`).
956
+ * @param baseColor - The base background color (any valid CSS color value).
957
+ * @param mode - The target mode (`'dark'`, `'light'`, or `'system'`).
958
+ * @returns A fully populated scheme with all semantic color roles.
959
+ * @throws Error if `themeName` is not a registered theme.
960
+ */
961
+ generateScheme(themeName: string, baseColor: CssColor, mode: ThemeMode): Required<ThemeScheme>;
962
+ /**
963
+ * Resolves the theme mode, converting 'system' to 'dark' or 'light' based on platform settings.
964
+ *
965
+ * @private
966
+ * @param mode The theme mode to resolve.
967
+ * @returns The resolved theme mode.
968
+ */
969
+ private resolveMode;
970
+ /**
971
+ * Gets the theme generator strategy for the specified theme name.
762
972
  *
763
- * Returned keys:
764
- * - background → shade "50"
765
- * - foreground → shade "900"
766
- * - primary → shade "500"
767
- * - accent → shade "700"
768
- * - muted → shade "300"
973
+ * @private
974
+ * @param themeName The name of the theme ('joy', 'memphis', 'cosmopolitan').
975
+ * @returns The theme generator strategy.
769
976
  */
770
- generateScheme(baseColor: CssColor, mode: 'light' | 'dark'): ThemeScheme;
977
+ private getStrategy;
771
978
  }
772
979
  /**
773
- * Generates a Tailwind theme generator strategy.
980
+ * Global service locator for the singleton {@link ThemeGenerator} instance.
774
981
  *
775
- * @public
776
- */
777
- declare function createTailwindTheme(): ThemeGeneratorFactoryFn;
778
-
779
- /**
780
- * Browser implementation of the platform adapter.
781
- * Uses native DOM APIs (window, document, MutationObserver).
982
+ * @remarks
983
+ * A default instance is created automatically at module load time.
984
+ * Call {@link ThemeGeneratorServiceLocator.set | set} to replace it (e.g. in tests
985
+ * or SSR environments where a custom {@link IPlatformAdapter} is needed).
782
986
  *
783
987
  * @public
784
988
  */
785
- declare class BrowserPlatformAdapter implements IPlatformAdapter {
786
- matchMedia(query: string): boolean;
787
- setDocumentAttribute(name: string, value: string): void;
788
- getDocumentAttribute(name: string): string | null;
789
- observeDocumentAttributes(attributes: Array<string>, callback: (attributeName: string, newValue: string | null) => void): () => void;
989
+ declare class ThemeGeneratorServiceLocator {
990
+ private static _current;
991
+ static get current(): ThemeGenerator;
992
+ static isSet(): boolean;
993
+ static set(current: ThemeGenerator): void;
790
994
  }
791
995
 
792
996
  /**
793
- * Node.js implementation of the platform adapter.
794
- * No-op implementation that doesn't crash but does nothing.
997
+ * Reactive observer that applies and tracks the active theme on the document.
795
998
  *
796
- * @public
797
- */
798
- declare class NodePlatformAdapter implements IPlatformAdapter {
799
- matchMedia(_query: string): boolean;
800
- setDocumentAttribute(_name: string, _value: string): void;
801
- getDocumentAttribute(_name: string): string | null;
802
- observeDocumentAttributes(_attributes: Array<string>, _callback: (attributeName: string, newValue: string | null) => void): () => void;
803
- }
804
-
805
- /**
806
- * Factory that automatically detects the environment and returns the appropriate adapter.
999
+ * @remarks
1000
+ * Manages the `theme` and `theme-mode` document attributes and emits events
1001
+ * when either changes. The `'system'` mode is resolved via the
1002
+ * {@link IPlatformAdapter}.
807
1003
  *
808
1004
  * @public
809
1005
  */
810
- declare class PlatformAdapterFactory {
1006
+ declare class ThemeObserver {
1007
+ private readonly _themeChanged;
1008
+ private readonly _themeModeChanged;
1009
+ private readonly _platformAdapter;
1010
+ private _currentTheme;
1011
+ private _currentThemeMode;
1012
+ private _unsubscribe?;
811
1013
  /**
812
- * Creates the appropriate platform adapter based on the current environment.
813
- * Automatically detects if running in browser or Node.js.
1014
+ * Constructs a new instance of the `ThemeObserver` class.
814
1015
  *
1016
+ * @param platformAdapter - Optional platform adapter. Auto-detects if not provided.
815
1017
  * @public
816
1018
  */
817
- static create(): IPlatformAdapter;
1019
+ constructor(platformAdapter?: IPlatformAdapter);
1020
+ /**
1021
+ * Fires when the theme changes.
1022
+ *
1023
+ * @public
1024
+ * @readonly
1025
+ */
1026
+ get themeChanged(): IEventEmitter<string>;
1027
+ /**
1028
+ * Fires when the theme mode changes.
1029
+ *
1030
+ * @public
1031
+ * @readonly
1032
+ */
1033
+ get themeModeChanged(): IEventEmitter<ThemeMode>;
1034
+ /**
1035
+ * Applies the given theme and theme mode to the document.
1036
+ *
1037
+ * @public
1038
+ * @param theme - The theme to apply (joy, cosmopolitan or memphis).
1039
+ * @param themeMode - The theme mode to apply.
1040
+ */
1041
+ applyTheme(theme: string, themeMode: ThemeModeWithSystem): void;
1042
+ /**
1043
+ * Stops observing document attribute changes and releases the underlying listener.
1044
+ *
1045
+ * @remarks
1046
+ * Safe to call multiple times — subsequent calls are no-ops.
1047
+ *
1048
+ * @public
1049
+ */
1050
+ dispose(): void;
1051
+ private observe;
818
1052
  }
819
-
820
- /**
821
- * @public
822
- */
823
- declare function darken(hex: string, factor: number): string;
824
- /**
825
- * @public
826
- */
827
- declare function lighten(hex: string, factor: number): string;
828
-
829
- /**
830
- * Generate an analogous color palette
831
- * @param baseHex
832
- * @param adjustment
833
- * @returns
834
- */
835
- declare function generateAnalogousPalette(baseHex: string, adjustment: number): Record<string, string>;
836
- /**
837
- * Generate a single analogous color
838
- * @param baseHex
839
- * @param adjustment
840
- * @returns
841
- */
842
- declare function generateAnalogousColor(baseHex: string, adjustment: number): string;
843
-
844
- /**
845
- * Generates a complementary color palette based on the given base color.
846
- * @param baseHex
847
- * @returns
848
- */
849
- declare function generateComplementaryPalette(baseHex: string): Record<string, string>;
850
- /**
851
- * Generates a single complementary color based on the given base color.
852
- * @param baseHex
853
- * @returns
854
- */
855
- declare function generateComplementaryColor(baseHex: string): string;
856
-
857
- /**
858
- * Generates a material color palette based on the given hex color.
859
- * @param hexColor
860
- * @returns
861
- */
862
- declare function generateMaterialPalette(hexColor: string): Record<string, string>;
863
-
864
1053
  /**
865
- * Generates split-complementary colors based on the given base color.
866
- * Split-complementary uses two colors adjacent to the complement (150° and 210°).
1054
+ * Global service locator for the singleton {@link ThemeObserver} instance.
1055
+ *
1056
+ * @remarks
1057
+ * A default instance is created automatically at module load time.
1058
+ * Call {@link ThemeObserverServiceLocator.set | set} to replace it (e.g. in tests
1059
+ * or SSR environments where a custom {@link IPlatformAdapter} is needed).
867
1060
  *
868
- * @param baseHex - The base color in hex format.
869
- * @returns An array of two split-complementary colors.
870
1061
  * @public
871
1062
  */
872
- declare function generateSplitComplementaryColors(baseHex: string): [string, string];
1063
+ declare class ThemeObserverServiceLocator {
1064
+ private static _current;
1065
+ static get current(): ThemeObserver;
1066
+ static isSet(): boolean;
1067
+ static set(current: ThemeObserver): void;
1068
+ }
1069
+
873
1070
  /**
874
- * Generates the first split-complementary color (150° from base).
875
- *
876
- * @param baseHex - The base color in hex format.
877
- * @returns The first split-complementary color.
878
1071
  * @public
879
1072
  */
880
- declare function generateSplitComplementaryColor1(baseHex: string): string;
1073
+ type CssAspectRatio = 'auto' | `${number}` | `${number}/${number}`;
881
1074
  /**
882
- * Generates the second split-complementary color (210° from base).
883
- *
884
- * @param baseHex - The base color in hex format.
885
- * @returns The second split-complementary color.
886
1075
  * @public
887
1076
  */
888
- declare function generateSplitComplementaryColor2(baseHex: string): string;
1077
+ declare namespace CssAspectRatio {
1078
+ /**
1079
+ * @public
1080
+ */
1081
+ function isCssAspectRatio(value: unknown): value is CssAspectRatio;
1082
+ }
889
1083
 
890
1084
  /**
891
- * Generates tetradic (square) colors based on the given base color.
892
- * Tetradic uses four colors evenly spaced around the color wheel (90° apart).
893
- *
894
- * @param baseHex - The base color in hex format.
895
- * @returns An array of three tetradic colors (excluding the base).
896
1085
  * @public
897
1086
  */
898
- declare function generateTetradicColors(baseHex: string): [string, string, string];
1087
+ type CssTimeUnit = 's' | 'ms';
899
1088
  /**
900
- * Generates the first tetradic color (90° from base).
901
- *
902
- * @param baseHex - The base color in hex format.
903
- * @returns The first tetradic color.
904
1089
  * @public
905
1090
  */
906
- declare function generateTetradicColor1(baseHex: string): string;
1091
+ type CssTime = `${string}${CssTimeUnit}` | number | 0;
907
1092
  /**
908
- * Generates the third tetradic color (270° from base).
909
- *
910
- * @param baseHex - The base color in hex format.
911
- * @returns The third tetradic color.
912
1093
  * @public
913
1094
  */
914
- declare function generateTetradicColor3(baseHex: string): string;
915
-
916
- /**
917
- * Generate a triadic color palette
918
- * @param baseHex
919
- * @param adjustment
920
- * @returns
921
- */
922
- declare function generateTriadicPalette(baseHex: string, adjustment: number): Record<string, string>;
923
- /**
924
- * Generate a single triadic color
925
- * @param baseHex
926
- * @param adjustment
927
- * @returns
928
- */
929
- declare function generateTriadicColor(baseHex: string, adjustment: number): string;
930
-
931
- declare namespace Colors {
932
- const toDarken: typeof darken;
933
- const toLighten: typeof lighten;
934
- const toMaterialPalette: typeof generateMaterialPalette;
935
- const toComplementaryPalette: typeof generateComplementaryPalette;
936
- const toComplementaryColor: typeof generateComplementaryColor;
937
- const toAnalogousPalette: typeof generateAnalogousPalette;
938
- const toAnalogousColor: typeof generateAnalogousColor;
939
- const toTriadicPalette: typeof generateTriadicPalette;
940
- const toTriadicColor: typeof generateTriadicColor;
941
- const toSplitComplementaryColors: typeof generateSplitComplementaryColors;
942
- const toSplitComplementaryColor1: typeof generateSplitComplementaryColor1;
943
- const toSplitComplementaryColor2: typeof generateSplitComplementaryColor2;
944
- const toTetradicColors: typeof generateTetradicColors;
945
- const toTetradicColor1: typeof generateTetradicColor1;
946
- const toTetradicColor3: typeof generateTetradicColor3;
1095
+ declare namespace CssTime {
1096
+ /**
1097
+ * @public
1098
+ */
1099
+ function isCssTime(value: unknown): value is CssTime;
947
1100
  }
948
1101
 
949
- export { BrowserPlatformAdapter, Colors, CosmopolitanTheme, CosmopolitanThemeGeneratorStrategy, CssAspectRatio, CssColor, type CssHEXColor, CssLength, type CssLengthUnit, type CssNameColor, type CssNumber, type CssRGBAColor, type CssRGBColor, CssShadow, type CssShadowSingle, CssTime, type CssTimeUnit, type IPlatformAdapter, ITheme, type IThemeElevation, type IThemeGeneratorStrategy, type IThemeLayout, type IThemeMetadata, type IThemeTypographyFontType, JoyTheme, JoyThemeGeneratorStrategy, MaterialThemeGeneratorStrategy, MemphisTheme, MemphisThemeGeneratorStrategy, NodePlatformAdapter, PlatformAdapterFactory, THEME_MODES, TailwindThemeGeneratorStrategy, ThemeGenerator, ThemeGeneratorServiceLocator, type ThemeMode, ThemeObserver, ThemeObserverServiceLocator, ThemePalette, type ThemeRoleName, ThemeScheme, type ThemeSchemeRole, type ThemeSemantic, type ThemeSemanticName, type ThemeShadeName, type ThemeStateName, type ThemeTypography, type ThemeTypographyTypeName, createCosmopolitanTheme, createJoyTheme, createMaterialTheme, createMemphisTheme, createTailwindTheme };
1102
+ export { BrowserPlatformAdapter, Colors, CosmopolitanTheme, CosmopolitanThemeGeneratorStrategy, CssAspectRatio, CssColor, type CssHEXColor, CssLength, type CssLengthUnit, type CssNameColor, type CssNumber, type CssRGBAColor, type CssRGBColor, CssShadow, type CssShadowSingle, CssTime, type CssTimeUnit, HslThemeGeneratorStrategy, type IPlatformAdapter, ITheme, type IThemeElevation, type IThemeGeneratorStrategy, type IThemeLayout, type IThemeMetadata, type IThemeTypographyFontType, JoyTheme, JoyThemeGeneratorStrategy, LchThemeGeneratorStrategy, MemphisTheme, MemphisThemeGeneratorStrategy, NodePlatformAdapter, PlatformAdapterFactory, THEME_MODES, ThemeGenerator, ThemeGeneratorServiceLocator, type ThemeMode, ThemeObserver, ThemeObserverServiceLocator, ThemePalette, type ThemeRoleName, ThemeScheme, type ThemeSchemeRole, type ThemeSemantic, type ThemeSemanticName, type ThemeShadeName, type ThemeStateName, type ThemeTypography, type ThemeTypographyTypeName, createCosmopolitanTheme, createJoyTheme, createMemphisTheme };