@oxyhq/bloom 0.83.0 → 0.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/design-tokens/index.js +14 -0
- package/lib/commonjs/design-tokens/index.js.map +1 -1
- package/lib/commonjs/theme/color-policy.js +25 -3
- package/lib/commonjs/theme/color-policy.js.map +1 -1
- package/lib/commonjs/theme/color-presets.js +10 -9
- package/lib/commonjs/theme/color-presets.js.map +1 -1
- package/lib/module/design-tokens/index.js +19 -0
- package/lib/module/design-tokens/index.js.map +1 -1
- package/lib/module/theme/color-policy.js +25 -3
- package/lib/module/theme/color-policy.js.map +1 -1
- package/lib/module/theme/color-presets.js +10 -9
- package/lib/module/theme/color-presets.js.map +1 -1
- package/lib/typescript/commonjs/design-tokens/index.d.ts +6 -0
- package/lib/typescript/commonjs/design-tokens/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/color-policy.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/color-presets.d.ts +12 -0
- package/lib/typescript/commonjs/theme/color-presets.d.ts.map +1 -1
- package/lib/typescript/module/design-tokens/index.d.ts +6 -0
- package/lib/typescript/module/design-tokens/index.d.ts.map +1 -1
- package/lib/typescript/module/theme/color-policy.d.ts.map +1 -1
- package/lib/typescript/module/theme/color-presets.d.ts +12 -0
- package/lib/typescript/module/theme/color-presets.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/design-tokens.test.ts +115 -2
- package/src/__tests__/theme.test.ts +2 -2
- package/src/design-tokens/index.ts +21 -0
- package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +290 -290
- package/src/theme/__tests__/__snapshots__/visual-gallery.test.tsx.snap +154 -154
- package/src/theme/__tests__/policy-legibility.test.ts +24 -11
- package/src/theme/color-policy.ts +32 -3
- package/src/theme/color-presets.ts +20 -8
|
@@ -3,73 +3,73 @@
|
|
|
3
3
|
exports[`theme.colors snapshot for all presets (catches unintended palette shifts) 1`] = `
|
|
4
4
|
{
|
|
5
5
|
"blue/dark": {
|
|
6
|
-
"background": "rgb(
|
|
7
|
-
"backgroundSecondary": "rgb(
|
|
8
|
-
"backgroundTertiary": "rgb(
|
|
9
|
-
"border": "rgb(
|
|
10
|
-
"borderLight": "rgb(
|
|
11
|
-
"card": "rgb(
|
|
12
|
-
"contrast50": "rgb(
|
|
6
|
+
"background": "rgb(8 15 22)",
|
|
7
|
+
"backgroundSecondary": "rgb(21 28 36)",
|
|
8
|
+
"backgroundTertiary": "rgb(25 32 40)",
|
|
9
|
+
"border": "rgb(62 72 82)",
|
|
10
|
+
"borderLight": "rgb(62 72 82)",
|
|
11
|
+
"card": "rgb(25 32 40)",
|
|
12
|
+
"contrast50": "rgb(36 43 51)",
|
|
13
13
|
"error": "rgb(209 45 50)",
|
|
14
|
-
"icon": "rgb(
|
|
15
|
-
"iconActive": "rgb(0
|
|
14
|
+
"icon": "rgb(190 199 212)",
|
|
15
|
+
"iconActive": "rgb(0 123 194)",
|
|
16
16
|
"info": "rgb(33 112 228)",
|
|
17
17
|
"negative": "rgb(255 180 171)",
|
|
18
18
|
"negativeForeground": "rgb(105 0 5)",
|
|
19
19
|
"negativeSubtle": "rgba(239, 68, 68, 0.24)",
|
|
20
20
|
"negativeSubtleForeground": "rgb(255 179 173)",
|
|
21
21
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
22
|
-
"primary": "rgb(0
|
|
23
|
-
"primaryDark": "rgb(
|
|
22
|
+
"primary": "rgb(0 123 194)",
|
|
23
|
+
"primaryDark": "rgb(8 15 22)",
|
|
24
24
|
"primaryForeground": "rgb(255 255 255)",
|
|
25
|
-
"primaryLight": "rgb(
|
|
26
|
-
"primarySubtle": "rgba(
|
|
27
|
-
"primarySubtleForeground": "rgb(
|
|
28
|
-
"secondary": "rgb(
|
|
25
|
+
"primaryLight": "rgb(21 28 36)",
|
|
26
|
+
"primarySubtle": "rgba(0, 151, 237, 0.24)",
|
|
27
|
+
"primarySubtleForeground": "rgb(207 229 255)",
|
|
28
|
+
"secondary": "rgb(213 57 42)",
|
|
29
29
|
"secondaryForeground": "rgb(255 255 255)",
|
|
30
30
|
"shadow": "rgba(0, 0, 0, 0.3)",
|
|
31
31
|
"success": "rgb(0 135 92)",
|
|
32
|
-
"tertiary": "rgb(
|
|
32
|
+
"tertiary": "rgb(252 220 0)",
|
|
33
33
|
"tertiaryForeground": "rgb(0 0 0)",
|
|
34
|
-
"text": "rgb(
|
|
35
|
-
"textSecondary": "rgb(
|
|
36
|
-
"textTertiary": "rgb(
|
|
37
|
-
"tint": "rgb(0
|
|
34
|
+
"text": "rgb(220 227 238)",
|
|
35
|
+
"textSecondary": "rgb(190 199 212)",
|
|
36
|
+
"textTertiary": "rgb(136 146 158)",
|
|
37
|
+
"tint": "rgb(0 123 194)",
|
|
38
38
|
"warning": "rgb(165 104 0)",
|
|
39
39
|
},
|
|
40
40
|
"blue/light": {
|
|
41
|
-
"background": "rgb(
|
|
42
|
-
"backgroundSecondary": "rgb(
|
|
43
|
-
"backgroundTertiary": "rgb(
|
|
44
|
-
"border": "rgb(
|
|
45
|
-
"borderLight": "rgb(
|
|
41
|
+
"background": "rgb(237 244 255)",
|
|
42
|
+
"backgroundSecondary": "rgb(237 244 255)",
|
|
43
|
+
"backgroundTertiary": "rgb(232 238 249)",
|
|
44
|
+
"border": "rgb(190 199 212)",
|
|
45
|
+
"borderLight": "rgb(190 199 212)",
|
|
46
46
|
"card": "rgb(255 255 255)",
|
|
47
|
-
"contrast50": "rgb(
|
|
47
|
+
"contrast50": "rgb(226 233 244)",
|
|
48
48
|
"error": "rgb(191 31 39)",
|
|
49
|
-
"icon": "rgb(
|
|
50
|
-
"iconActive": "rgb(0
|
|
49
|
+
"icon": "rgb(62 72 82)",
|
|
50
|
+
"iconActive": "rgb(0 110 175)",
|
|
51
51
|
"info": "rgb(0 100 213)",
|
|
52
52
|
"negative": "rgb(186 26 26)",
|
|
53
53
|
"negativeForeground": "rgb(255 255 255)",
|
|
54
54
|
"negativeSubtle": "rgba(239, 68, 68, 0.13)",
|
|
55
55
|
"negativeSubtleForeground": "rgb(167 55 53)",
|
|
56
56
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
57
|
-
"primary": "rgb(0
|
|
58
|
-
"primaryDark": "rgb(
|
|
57
|
+
"primary": "rgb(0 110 175)",
|
|
58
|
+
"primaryDark": "rgb(237 244 255)",
|
|
59
59
|
"primaryForeground": "rgb(255 255 255)",
|
|
60
|
-
"primaryLight": "rgb(
|
|
61
|
-
"primarySubtle": "rgba(
|
|
62
|
-
"primarySubtleForeground": "rgb(0
|
|
63
|
-
"secondary": "rgb(
|
|
60
|
+
"primaryLight": "rgb(237 244 255)",
|
|
61
|
+
"primarySubtle": "rgba(0, 151, 237, 0.13)",
|
|
62
|
+
"primarySubtleForeground": "rgb(0 74 120)",
|
|
63
|
+
"secondary": "rgb(195 44 32)",
|
|
64
64
|
"secondaryForeground": "rgb(255 255 255)",
|
|
65
65
|
"shadow": "rgba(0, 0, 0, 0.1)",
|
|
66
66
|
"success": "rgb(0 121 82)",
|
|
67
|
-
"tertiary": "rgb(
|
|
67
|
+
"tertiary": "rgb(121 105 0)",
|
|
68
68
|
"tertiaryForeground": "rgb(255 255 255)",
|
|
69
|
-
"text": "rgb(
|
|
70
|
-
"textSecondary": "rgb(
|
|
71
|
-
"textTertiary": "rgb(
|
|
72
|
-
"tint": "rgb(0
|
|
69
|
+
"text": "rgb(21 28 36)",
|
|
70
|
+
"textSecondary": "rgb(62 72 82)",
|
|
71
|
+
"textTertiary": "rgb(111 120 132)",
|
|
72
|
+
"tint": "rgb(0 110 175)",
|
|
73
73
|
"warning": "rgb(148 93 0)",
|
|
74
74
|
},
|
|
75
75
|
"brown/dark": {
|
|
@@ -493,73 +493,73 @@ exports[`theme.colors snapshot for all presets (catches unintended palette shift
|
|
|
493
493
|
"warning": "rgb(148 93 0)",
|
|
494
494
|
},
|
|
495
495
|
"orange/dark": {
|
|
496
|
-
"background": "rgb(
|
|
497
|
-
"backgroundSecondary": "rgb(
|
|
498
|
-
"backgroundTertiary": "rgb(
|
|
499
|
-
"border": "rgb(
|
|
500
|
-
"borderLight": "rgb(
|
|
501
|
-
"card": "rgb(
|
|
502
|
-
"contrast50": "rgb(
|
|
496
|
+
"background": "rgb(23 11 5)",
|
|
497
|
+
"backgroundSecondary": "rgb(38 25 16)",
|
|
498
|
+
"backgroundTertiary": "rgb(42 28 20)",
|
|
499
|
+
"border": "rgb(87 66 55)",
|
|
500
|
+
"borderLight": "rgb(87 66 55)",
|
|
501
|
+
"card": "rgb(42 28 20)",
|
|
502
|
+
"contrast50": "rgb(54 39 30)",
|
|
503
503
|
"error": "rgb(209 45 50)",
|
|
504
|
-
"icon": "rgb(
|
|
505
|
-
"iconActive": "rgb(
|
|
504
|
+
"icon": "rgb(222 193 177)",
|
|
505
|
+
"iconActive": "rgb(189 89 0)",
|
|
506
506
|
"info": "rgb(33 112 228)",
|
|
507
507
|
"negative": "rgb(255 180 171)",
|
|
508
508
|
"negativeForeground": "rgb(105 0 5)",
|
|
509
509
|
"negativeSubtle": "rgba(239, 68, 68, 0.24)",
|
|
510
510
|
"negativeSubtleForeground": "rgb(255 179 173)",
|
|
511
511
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
512
|
-
"primary": "rgb(
|
|
513
|
-
"primaryDark": "rgb(
|
|
512
|
+
"primary": "rgb(189 89 0)",
|
|
513
|
+
"primaryDark": "rgb(23 11 5)",
|
|
514
514
|
"primaryForeground": "rgb(255 255 255)",
|
|
515
|
-
"primaryLight": "rgb(
|
|
516
|
-
"primarySubtle": "rgba(
|
|
517
|
-
"primarySubtleForeground": "rgb(255 219
|
|
518
|
-
"secondary": "rgb(0
|
|
519
|
-
"secondaryForeground": "rgb(
|
|
515
|
+
"primaryLight": "rgb(38 25 16)",
|
|
516
|
+
"primarySubtle": "rgba(231, 110, 0, 0.24)",
|
|
517
|
+
"primarySubtleForeground": "rgb(255 219 200)",
|
|
518
|
+
"secondary": "rgb(0 248 254)",
|
|
519
|
+
"secondaryForeground": "rgb(0 0 0)",
|
|
520
520
|
"shadow": "rgba(0, 0, 0, 0.3)",
|
|
521
521
|
"success": "rgb(0 135 92)",
|
|
522
|
-
"tertiary": "rgb(
|
|
523
|
-
"tertiaryForeground": "rgb(
|
|
524
|
-
"text": "rgb(
|
|
525
|
-
"textSecondary": "rgb(
|
|
526
|
-
"textTertiary": "rgb(
|
|
527
|
-
"tint": "rgb(
|
|
522
|
+
"tertiary": "rgb(80 79 255)",
|
|
523
|
+
"tertiaryForeground": "rgb(255 255 255)",
|
|
524
|
+
"text": "rgb(248 221 208)",
|
|
525
|
+
"textSecondary": "rgb(222 193 177)",
|
|
526
|
+
"textTertiary": "rgb(166 139 125)",
|
|
527
|
+
"tint": "rgb(189 89 0)",
|
|
528
528
|
"warning": "rgb(165 104 0)",
|
|
529
529
|
},
|
|
530
530
|
"orange/light": {
|
|
531
|
-
"background": "rgb(255 241
|
|
532
|
-
"backgroundSecondary": "rgb(255 241
|
|
533
|
-
"backgroundTertiary": "rgb(255
|
|
534
|
-
"border": "rgb(
|
|
535
|
-
"borderLight": "rgb(
|
|
531
|
+
"background": "rgb(255 241 234)",
|
|
532
|
+
"backgroundSecondary": "rgb(255 241 234)",
|
|
533
|
+
"backgroundTertiary": "rgb(255 234 223)",
|
|
534
|
+
"border": "rgb(222 193 177)",
|
|
535
|
+
"borderLight": "rgb(222 193 177)",
|
|
536
536
|
"card": "rgb(255 255 255)",
|
|
537
|
-
"contrast50": "rgb(
|
|
537
|
+
"contrast50": "rgb(254 227 213)",
|
|
538
538
|
"error": "rgb(191 31 39)",
|
|
539
|
-
"icon": "rgb(
|
|
540
|
-
"iconActive": "rgb(
|
|
539
|
+
"icon": "rgb(87 66 55)",
|
|
540
|
+
"iconActive": "rgb(170 79 0)",
|
|
541
541
|
"info": "rgb(0 100 213)",
|
|
542
542
|
"negative": "rgb(186 26 26)",
|
|
543
543
|
"negativeForeground": "rgb(255 255 255)",
|
|
544
544
|
"negativeSubtle": "rgba(239, 68, 68, 0.13)",
|
|
545
545
|
"negativeSubtleForeground": "rgb(167 55 53)",
|
|
546
546
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
547
|
-
"primary": "rgb(
|
|
548
|
-
"primaryDark": "rgb(255 241
|
|
547
|
+
"primary": "rgb(170 79 0)",
|
|
548
|
+
"primaryDark": "rgb(255 241 234)",
|
|
549
549
|
"primaryForeground": "rgb(255 255 255)",
|
|
550
|
-
"primaryLight": "rgb(255 241
|
|
551
|
-
"primarySubtle": "rgba(
|
|
552
|
-
"primarySubtleForeground": "rgb(
|
|
553
|
-
"secondary": "rgb(0
|
|
550
|
+
"primaryLight": "rgb(255 241 234)",
|
|
551
|
+
"primarySubtle": "rgba(231, 110, 0, 0.13)",
|
|
552
|
+
"primarySubtleForeground": "rgb(117 52 0)",
|
|
553
|
+
"secondary": "rgb(0 119 122)",
|
|
554
554
|
"secondaryForeground": "rgb(255 255 255)",
|
|
555
555
|
"shadow": "rgba(0, 0, 0, 0.1)",
|
|
556
556
|
"success": "rgb(0 121 82)",
|
|
557
|
-
"tertiary": "rgb(
|
|
557
|
+
"tertiary": "rgb(65 62 247)",
|
|
558
558
|
"tertiaryForeground": "rgb(255 255 255)",
|
|
559
|
-
"text": "rgb(
|
|
560
|
-
"textSecondary": "rgb(
|
|
561
|
-
"textTertiary": "rgb(
|
|
562
|
-
"tint": "rgb(
|
|
559
|
+
"text": "rgb(38 25 16)",
|
|
560
|
+
"textSecondary": "rgb(87 66 55)",
|
|
561
|
+
"textTertiary": "rgb(139 114 100)",
|
|
562
|
+
"tint": "rgb(170 79 0)",
|
|
563
563
|
"warning": "rgb(148 93 0)",
|
|
564
564
|
},
|
|
565
565
|
"oxy/dark": {
|
|
@@ -703,73 +703,73 @@ exports[`theme.colors snapshot for all presets (catches unintended palette shift
|
|
|
703
703
|
"warning": "rgb(148 93 0)",
|
|
704
704
|
},
|
|
705
705
|
"pink/dark": {
|
|
706
|
-
"background": "rgb(23 11
|
|
706
|
+
"background": "rgb(23 11 14)",
|
|
707
707
|
"backgroundSecondary": "rgb(38 24 27)",
|
|
708
708
|
"backgroundTertiary": "rgb(42 28 31)",
|
|
709
|
-
"border": "rgb(
|
|
710
|
-
"borderLight": "rgb(
|
|
709
|
+
"border": "rgb(86 65 70)",
|
|
710
|
+
"borderLight": "rgb(86 65 70)",
|
|
711
711
|
"card": "rgb(42 28 31)",
|
|
712
|
-
"contrast50": "rgb(53 38
|
|
712
|
+
"contrast50": "rgb(53 38 42)",
|
|
713
713
|
"error": "rgb(209 45 50)",
|
|
714
|
-
"icon": "rgb(
|
|
715
|
-
"iconActive": "rgb(
|
|
714
|
+
"icon": "rgb(220 191 197)",
|
|
715
|
+
"iconActive": "rgb(230 0 116)",
|
|
716
716
|
"info": "rgb(33 112 228)",
|
|
717
717
|
"negative": "rgb(255 180 171)",
|
|
718
718
|
"negativeForeground": "rgb(105 0 5)",
|
|
719
719
|
"negativeSubtle": "rgba(239, 68, 68, 0.24)",
|
|
720
720
|
"negativeSubtleForeground": "rgb(255 179 173)",
|
|
721
721
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
722
|
-
"primary": "rgb(
|
|
723
|
-
"primaryDark": "rgb(23 11
|
|
722
|
+
"primary": "rgb(230 0 116)",
|
|
723
|
+
"primaryDark": "rgb(23 11 14)",
|
|
724
724
|
"primaryForeground": "rgb(255 255 255)",
|
|
725
725
|
"primaryLight": "rgb(38 24 27)",
|
|
726
|
-
"primarySubtle": "rgba(255,
|
|
727
|
-
"primarySubtleForeground": "rgb(255 217
|
|
728
|
-
"secondary": "rgb(
|
|
726
|
+
"primarySubtle": "rgba(255, 74, 143, 0.24)",
|
|
727
|
+
"primarySubtleForeground": "rgb(255 217 225)",
|
|
728
|
+
"secondary": "rgb(12 227 255)",
|
|
729
729
|
"secondaryForeground": "rgb(0 0 0)",
|
|
730
730
|
"shadow": "rgba(0, 0, 0, 0.3)",
|
|
731
731
|
"success": "rgb(0 135 92)",
|
|
732
|
-
"tertiary": "rgb(
|
|
732
|
+
"tertiary": "rgb(116 245 95)",
|
|
733
733
|
"tertiaryForeground": "rgb(0 0 0)",
|
|
734
|
-
"text": "rgb(
|
|
735
|
-
"textSecondary": "rgb(
|
|
736
|
-
"textTertiary": "rgb(
|
|
737
|
-
"tint": "rgb(
|
|
734
|
+
"text": "rgb(246 220 225)",
|
|
735
|
+
"textSecondary": "rgb(220 191 197)",
|
|
736
|
+
"textTertiary": "rgb(164 138 144)",
|
|
737
|
+
"tint": "rgb(230 0 116)",
|
|
738
738
|
"warning": "rgb(165 104 0)",
|
|
739
739
|
},
|
|
740
740
|
"pink/light": {
|
|
741
|
-
"background": "rgb(255 240
|
|
742
|
-
"backgroundSecondary": "rgb(255 240
|
|
743
|
-
"backgroundTertiary": "rgb(255
|
|
744
|
-
"border": "rgb(
|
|
745
|
-
"borderLight": "rgb(
|
|
741
|
+
"background": "rgb(255 240 242)",
|
|
742
|
+
"backgroundSecondary": "rgb(255 240 242)",
|
|
743
|
+
"backgroundTertiary": "rgb(255 232 236)",
|
|
744
|
+
"border": "rgb(220 191 197)",
|
|
745
|
+
"borderLight": "rgb(220 191 197)",
|
|
746
746
|
"card": "rgb(255 255 255)",
|
|
747
|
-
"contrast50": "rgb(252 226
|
|
747
|
+
"contrast50": "rgb(252 226 231)",
|
|
748
748
|
"error": "rgb(191 31 39)",
|
|
749
|
-
"icon": "rgb(
|
|
750
|
-
"iconActive": "rgb(
|
|
749
|
+
"icon": "rgb(86 65 70)",
|
|
750
|
+
"iconActive": "rgb(207 0 103)",
|
|
751
751
|
"info": "rgb(0 100 213)",
|
|
752
752
|
"negative": "rgb(186 26 26)",
|
|
753
753
|
"negativeForeground": "rgb(255 255 255)",
|
|
754
754
|
"negativeSubtle": "rgba(239, 68, 68, 0.13)",
|
|
755
755
|
"negativeSubtleForeground": "rgb(167 55 53)",
|
|
756
756
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
757
|
-
"primary": "rgb(
|
|
758
|
-
"primaryDark": "rgb(255 240
|
|
757
|
+
"primary": "rgb(207 0 103)",
|
|
758
|
+
"primaryDark": "rgb(255 240 242)",
|
|
759
759
|
"primaryForeground": "rgb(255 255 255)",
|
|
760
|
-
"primaryLight": "rgb(255 240
|
|
761
|
-
"primarySubtle": "rgba(255,
|
|
762
|
-
"primarySubtleForeground": "rgb(
|
|
763
|
-
"secondary": "rgb(0 116
|
|
760
|
+
"primaryLight": "rgb(255 240 242)",
|
|
761
|
+
"primarySubtle": "rgba(255, 74, 143, 0.13)",
|
|
762
|
+
"primarySubtleForeground": "rgb(143 0 69)",
|
|
763
|
+
"secondary": "rgb(0 116 131)",
|
|
764
764
|
"secondaryForeground": "rgb(255 255 255)",
|
|
765
765
|
"shadow": "rgba(0, 0, 0, 0.1)",
|
|
766
766
|
"success": "rgb(0 121 82)",
|
|
767
|
-
"tertiary": "rgb(
|
|
767
|
+
"tertiary": "rgb(0 123 0)",
|
|
768
768
|
"tertiaryForeground": "rgb(255 255 255)",
|
|
769
769
|
"text": "rgb(38 24 27)",
|
|
770
|
-
"textSecondary": "rgb(
|
|
771
|
-
"textTertiary": "rgb(
|
|
772
|
-
"tint": "rgb(
|
|
770
|
+
"textSecondary": "rgb(86 65 70)",
|
|
771
|
+
"textTertiary": "rgb(137 113 118)",
|
|
772
|
+
"tint": "rgb(207 0 103)",
|
|
773
773
|
"warning": "rgb(148 93 0)",
|
|
774
774
|
},
|
|
775
775
|
"pumpkin/dark": {
|
|
@@ -1193,73 +1193,73 @@ exports[`theme.colors snapshot for all presets (catches unintended palette shift
|
|
|
1193
1193
|
"warning": "rgb(148 93 0)",
|
|
1194
1194
|
},
|
|
1195
1195
|
"yellow/dark": {
|
|
1196
|
-
"background": "rgb(
|
|
1197
|
-
"backgroundSecondary": "rgb(
|
|
1198
|
-
"backgroundTertiary": "rgb(
|
|
1199
|
-
"border": "rgb(
|
|
1200
|
-
"borderLight": "rgb(
|
|
1201
|
-
"card": "rgb(
|
|
1202
|
-
"contrast50": "rgb(46 42
|
|
1196
|
+
"background": "rgb(18 14 3)",
|
|
1197
|
+
"backgroundSecondary": "rgb(32 27 13)",
|
|
1198
|
+
"backgroundTertiary": "rgb(36 31 17)",
|
|
1199
|
+
"border": "rgb(77 70 50)",
|
|
1200
|
+
"borderLight": "rgb(77 70 50)",
|
|
1201
|
+
"card": "rgb(36 31 17)",
|
|
1202
|
+
"contrast50": "rgb(46 42 26)",
|
|
1203
1203
|
"error": "rgb(209 45 50)",
|
|
1204
|
-
"icon": "rgb(
|
|
1205
|
-
"iconActive": "rgb(
|
|
1204
|
+
"icon": "rgb(208 198 171)",
|
|
1205
|
+
"iconActive": "rgb(140 116 0)",
|
|
1206
1206
|
"info": "rgb(33 112 228)",
|
|
1207
1207
|
"negative": "rgb(255 180 171)",
|
|
1208
1208
|
"negativeForeground": "rgb(105 0 5)",
|
|
1209
1209
|
"negativeSubtle": "rgba(239, 68, 68, 0.24)",
|
|
1210
1210
|
"negativeSubtleForeground": "rgb(255 179 173)",
|
|
1211
1211
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
1212
|
-
"primary": "rgb(
|
|
1213
|
-
"primaryDark": "rgb(
|
|
1214
|
-
"primaryForeground": "rgb(
|
|
1215
|
-
"primaryLight": "rgb(
|
|
1216
|
-
"primarySubtle": "rgba(
|
|
1217
|
-
"primarySubtleForeground": "rgb(255
|
|
1218
|
-
"secondary": "rgb(0
|
|
1212
|
+
"primary": "rgb(140 116 0)",
|
|
1213
|
+
"primaryDark": "rgb(18 14 3)",
|
|
1214
|
+
"primaryForeground": "rgb(255 255 255)",
|
|
1215
|
+
"primaryLight": "rgb(32 27 13)",
|
|
1216
|
+
"primarySubtle": "rgba(172, 142, 0, 0.24)",
|
|
1217
|
+
"primarySubtleForeground": "rgb(255 225 119)",
|
|
1218
|
+
"secondary": "rgb(0 125 188)",
|
|
1219
1219
|
"secondaryForeground": "rgb(255 255 255)",
|
|
1220
1220
|
"shadow": "rgba(0, 0, 0, 0.3)",
|
|
1221
1221
|
"success": "rgb(0 135 92)",
|
|
1222
|
-
"tertiary": "rgb(
|
|
1222
|
+
"tertiary": "rgb(143 66 246)",
|
|
1223
1223
|
"tertiaryForeground": "rgb(255 255 255)",
|
|
1224
|
-
"text": "rgb(
|
|
1225
|
-
"textSecondary": "rgb(
|
|
1226
|
-
"textTertiary": "rgb(
|
|
1227
|
-
"tint": "rgb(
|
|
1224
|
+
"text": "rgb(236 226 202)",
|
|
1225
|
+
"textSecondary": "rgb(208 198 171)",
|
|
1226
|
+
"textTertiary": "rgb(153 144 119)",
|
|
1227
|
+
"tint": "rgb(140 116 0)",
|
|
1228
1228
|
"warning": "rgb(165 104 0)",
|
|
1229
1229
|
},
|
|
1230
1230
|
"yellow/light": {
|
|
1231
|
-
"background": "rgb(
|
|
1232
|
-
"backgroundSecondary": "rgb(
|
|
1233
|
-
"backgroundTertiary": "rgb(
|
|
1234
|
-
"border": "rgb(
|
|
1235
|
-
"borderLight": "rgb(
|
|
1231
|
+
"background": "rgb(253 243 219)",
|
|
1232
|
+
"backgroundSecondary": "rgb(253 243 219)",
|
|
1233
|
+
"backgroundTertiary": "rgb(247 237 213)",
|
|
1234
|
+
"border": "rgb(208 198 171)",
|
|
1235
|
+
"borderLight": "rgb(208 198 171)",
|
|
1236
1236
|
"card": "rgb(255 255 255)",
|
|
1237
|
-
"contrast50": "rgb(
|
|
1237
|
+
"contrast50": "rgb(241 231 208)",
|
|
1238
1238
|
"error": "rgb(191 31 39)",
|
|
1239
|
-
"icon": "rgb(
|
|
1240
|
-
"iconActive": "rgb(
|
|
1239
|
+
"icon": "rgb(77 70 50)",
|
|
1240
|
+
"iconActive": "rgb(126 103 0)",
|
|
1241
1241
|
"info": "rgb(0 100 213)",
|
|
1242
1242
|
"negative": "rgb(186 26 26)",
|
|
1243
1243
|
"negativeForeground": "rgb(255 255 255)",
|
|
1244
1244
|
"negativeSubtle": "rgba(239, 68, 68, 0.13)",
|
|
1245
1245
|
"negativeSubtleForeground": "rgb(167 55 53)",
|
|
1246
1246
|
"overlay": "rgba(0, 0, 0, 0.5)",
|
|
1247
|
-
"primary": "rgb(
|
|
1248
|
-
"primaryDark": "rgb(
|
|
1247
|
+
"primary": "rgb(126 103 0)",
|
|
1248
|
+
"primaryDark": "rgb(253 243 219)",
|
|
1249
1249
|
"primaryForeground": "rgb(255 255 255)",
|
|
1250
|
-
"primaryLight": "rgb(
|
|
1251
|
-
"primarySubtle": "rgba(
|
|
1252
|
-
"primarySubtleForeground": "rgb(
|
|
1253
|
-
"secondary": "rgb(0
|
|
1250
|
+
"primaryLight": "rgb(253 243 219)",
|
|
1251
|
+
"primarySubtle": "rgba(172, 142, 0, 0.13)",
|
|
1252
|
+
"primarySubtleForeground": "rgb(85 69 0)",
|
|
1253
|
+
"secondary": "rgb(0 112 169)",
|
|
1254
1254
|
"secondaryForeground": "rgb(255 255 255)",
|
|
1255
1255
|
"shadow": "rgba(0, 0, 0, 0.1)",
|
|
1256
1256
|
"success": "rgb(0 121 82)",
|
|
1257
|
-
"tertiary": "rgb(
|
|
1257
|
+
"tertiary": "rgb(130 50 232)",
|
|
1258
1258
|
"tertiaryForeground": "rgb(255 255 255)",
|
|
1259
|
-
"text": "rgb(
|
|
1260
|
-
"textSecondary": "rgb(
|
|
1261
|
-
"textTertiary": "rgb(
|
|
1262
|
-
"tint": "rgb(
|
|
1259
|
+
"text": "rgb(32 27 13)",
|
|
1260
|
+
"textSecondary": "rgb(77 70 50)",
|
|
1261
|
+
"textTertiary": "rgb(127 119 95)",
|
|
1262
|
+
"tint": "rgb(126 103 0)",
|
|
1263
1263
|
"warning": "rgb(148 93 0)",
|
|
1264
1264
|
},
|
|
1265
1265
|
}
|
|
@@ -156,19 +156,32 @@ describe('colour policy legibility', () => {
|
|
|
156
156
|
// to carry white, which is what makes faircoin a deep green there and a
|
|
157
157
|
// bright lime in dark rather than the same pale smear twice.
|
|
158
158
|
expect(getResolvedTokens(preset, 'light')['--primary-foreground']).toBe('rgb(255 255 255)');
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
const config = APP_COLOR_PRESETS[preset];
|
|
160
|
+
const carriesWhite =
|
|
161
|
+
getResolvedTokens(preset, 'dark')['--primary-foreground'] === 'rgb(255 255 255)';
|
|
162
|
+
|
|
163
|
+
// A DECLARED white label is absolute — it is the brand overriding the
|
|
164
|
+
// budget, so no seed tone excuses a black one.
|
|
165
|
+
if (config.label === 'white') {
|
|
166
|
+
expect({ preset, carriesWhite }).toEqual({ preset, carriesWhite: true });
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
(carriesWhite ? white : black).push(Hct.fromInt(argbFromHex(config.hex)).tone);
|
|
164
170
|
}
|
|
165
171
|
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
+
// For everything that does NOT declare a label, dark's split is decided by
|
|
173
|
+
// the seed's own lightness and nothing else: a seed already too light to come
|
|
174
|
+
// down within the budget keeps its tone and takes a black label. So that
|
|
175
|
+
// partition must be ORDERED — every black-label seed lighter than every
|
|
176
|
+
// white-label one. Counting them instead (an "at most N take black" slack)
|
|
177
|
+
// says nothing about WHICH, passes while the rule inverts, and needs
|
|
178
|
+
// re-tuning by hand every time a preset is added.
|
|
179
|
+
//
|
|
180
|
+
// The declared ones are excluded rather than folded in because they falsify
|
|
181
|
+
// the ordering ON PURPOSE: `yellow` (seed tone 86) comes down to a deep gold
|
|
182
|
+
// while `peach` (80) stays bright, so a single ordered partition over all of
|
|
183
|
+
// them cannot hold — and reading that failure as a policy bug is exactly the
|
|
184
|
+
// wrong conclusion.
|
|
172
185
|
expect(black.length).toBeGreaterThan(0);
|
|
173
186
|
expect(white.length).toBeGreaterThan(0);
|
|
174
187
|
expect(Math.min(...black)).toBeGreaterThan(Math.max(...white));
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* is that rule applied to one more role.
|
|
24
24
|
*/
|
|
25
25
|
import { argbFromHex, type RoleColors } from './color-engine';
|
|
26
|
+
import { APP_COLOR_PRESETS, HEX_TO_APP_COLOR } from './color-presets';
|
|
26
27
|
import { Hct } from './color-engine/hct';
|
|
27
28
|
import { TonalPalette } from './color-engine/tonal-palette';
|
|
28
29
|
import { blueFromArgb, greenFromArgb, redFromArgb } from './color-engine/color-utils';
|
|
@@ -246,6 +247,22 @@ function vividHueNear(hue: number): number {
|
|
|
246
247
|
return bestChroma - baseChroma >= VIVID_SNAP_MIN_GAIN ? bestHue : hue;
|
|
247
248
|
}
|
|
248
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Whether the seed IS a built-in brand that declares a white label.
|
|
252
|
+
*
|
|
253
|
+
* Derived from the hex rather than passed in, and that is the point: a named
|
|
254
|
+
* preset is a fixed seed fed through this same policy, so
|
|
255
|
+
* `buildSeedScopeVars({ seed: preset.hex })` has to reproduce the preset exactly
|
|
256
|
+
* — a contract the seed-scope and build-theme-from-seed parity suites assert for
|
|
257
|
+
* every preset in both modes. Threading the declaration as a parameter satisfied
|
|
258
|
+
* only the caller that knew about it and silently gave every other path a
|
|
259
|
+
* different yellow.
|
|
260
|
+
*/
|
|
261
|
+
function declaresWhiteLabel(seedHex: string): boolean {
|
|
262
|
+
const name = HEX_TO_APP_COLOR[seedHex.toLowerCase()];
|
|
263
|
+
return name !== undefined && APP_COLOR_PRESETS[name].label === 'white';
|
|
264
|
+
}
|
|
265
|
+
|
|
249
266
|
/**
|
|
250
267
|
* The most vivid tone a palette reaches while a WHITE label still clears AA on
|
|
251
268
|
* it — searched per HUE instead of assumed.
|
|
@@ -299,7 +316,12 @@ function vividLegibleTone(palette: TonalPalette): number {
|
|
|
299
316
|
* why 11 of the 13 chromatic presets carry white and exactly the two light ones
|
|
300
317
|
* do not. (`mono` sits outside this rule — see MONOCHROME_FILL_TONE.)
|
|
301
318
|
*/
|
|
302
|
-
function whiteLabelTone(
|
|
319
|
+
function whiteLabelTone(
|
|
320
|
+
palette: TonalPalette,
|
|
321
|
+
seedTone: number,
|
|
322
|
+
isDark: boolean,
|
|
323
|
+
forceWhite: boolean,
|
|
324
|
+
): number {
|
|
303
325
|
// LIGHT: every fill comes down, no exemption. On a near-white page a bright
|
|
304
326
|
// colour has nothing to read against — a lime at its own tone 90 is a pale
|
|
305
327
|
// smear there, indistinguishable from the same colour in dark, which is not a
|
|
@@ -309,7 +331,14 @@ function whiteLabelTone(palette: TonalPalette, seedTone: number, isDark: boolean
|
|
|
309
331
|
// DARK: the budget applies. Most brands come down to where white fits, but a
|
|
310
332
|
// seed that is already light cannot without ceasing to be itself, so it keeps
|
|
311
333
|
// its own tone and takes a black label. That is the eleven-and-two pattern.
|
|
312
|
-
|
|
334
|
+
// A brand that DECLARES a white label forgoes the exemption outright: it comes
|
|
335
|
+
// down to where white fits, exactly as it does in light. Without this the
|
|
336
|
+
// budget is the only voice, and it answers by seed lightness alone — which
|
|
337
|
+
// cannot separate a yellow that wants to be a deep gold from a lime that wants
|
|
338
|
+
// to stay bright.
|
|
339
|
+
const candidate = forceWhite
|
|
340
|
+
? vividLegibleTone(palette)
|
|
341
|
+
: Math.max(vividLegibleTone(palette), seedTone - TONE_BUDGET);
|
|
313
342
|
return contrastOf(palette.tone(candidate), true) >= AA
|
|
314
343
|
? candidate
|
|
315
344
|
: Math.max(seedTone, DARK_SEED_FLOOR);
|
|
@@ -410,7 +439,7 @@ export function buildPolicyTokens(
|
|
|
410
439
|
brandPalette,
|
|
411
440
|
monochrome
|
|
412
441
|
? (isDark ? MONOCHROME_FILL_TONE.dark : MONOCHROME_FILL_TONE.light)
|
|
413
|
-
: whiteLabelTone(brandPalette, seed.tone, isDark),
|
|
442
|
+
: whiteLabelTone(brandPalette, seed.tone, isDark, declaresWhiteLabel(seedHex)),
|
|
414
443
|
);
|
|
415
444
|
|
|
416
445
|
const tokens: PolicyTokens = {
|
|
@@ -65,6 +65,18 @@ export interface AppColorPreset {
|
|
|
65
65
|
* {@link AppColorPreset.secondaryHex} for the tertiary palette.
|
|
66
66
|
*/
|
|
67
67
|
tertiaryHex?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Force the fill to a tone a WHITE label fits, in BOTH modes — overriding the
|
|
70
|
+
* budget that otherwise lets an already-light seed keep its own tone in dark
|
|
71
|
+
* and take a black label.
|
|
72
|
+
*
|
|
73
|
+
* It has to be declared, because it cannot be derived: `yellow` (seed tone 86)
|
|
74
|
+
* wants to come down to a deep gold with white on it, and `faircoin` (tone 90)
|
|
75
|
+
* wants to stay a bright lime with black on it. Two seeds four tones apart,
|
|
76
|
+
* opposite answers — nothing in the hex distinguishes them, only what the brand
|
|
77
|
+
* is for.
|
|
78
|
+
*/
|
|
79
|
+
label?: 'white';
|
|
68
80
|
/**
|
|
69
81
|
* Who may pick this preset. Absent = everyone. Bloom only DECLARES the gate;
|
|
70
82
|
* whether a given viewer satisfies it is the consuming app's question, since
|
|
@@ -85,14 +97,14 @@ export const APP_COLOR_NAMES: readonly AppColorName[] = ['teal', 'blue', 'green'
|
|
|
85
97
|
|
|
86
98
|
export const HEX_TO_APP_COLOR: Record<string, AppColorName> = {
|
|
87
99
|
'#005c67': 'teal',
|
|
88
|
-
'#
|
|
100
|
+
'#1d9bf0': 'blue',
|
|
89
101
|
'#10b981': 'green',
|
|
90
|
-
'#
|
|
102
|
+
'#ffd400': 'yellow',
|
|
91
103
|
'#ef4444': 'red',
|
|
92
104
|
'#b866ff': 'purple',
|
|
93
|
-
'#
|
|
105
|
+
'#f91880': 'pink',
|
|
94
106
|
'#03a9f4': 'sky',
|
|
95
|
-
'#
|
|
107
|
+
'#ff7a00': 'orange',
|
|
96
108
|
'#14b8a6': 'mint',
|
|
97
109
|
'#c46ede': 'oxy',
|
|
98
110
|
'#9ffb50': 'faircoin',
|
|
@@ -116,12 +128,12 @@ export function hexToAppColorName(hex: string): AppColorName {
|
|
|
116
128
|
*/
|
|
117
129
|
export const APP_COLOR_PRESETS: Record<AppColorName, AppColorPreset> = {
|
|
118
130
|
teal: { name: 'teal', hex: '#005c67', variant: 'vivid' },
|
|
119
|
-
blue: { name: 'blue', hex: '#
|
|
131
|
+
blue: { name: 'blue', hex: '#1d9bf0', variant: 'vivid' },
|
|
120
132
|
green: { name: 'green', hex: '#10b981', variant: 'vivid' },
|
|
121
|
-
yellow: { name: 'yellow', hex: '#
|
|
133
|
+
yellow: { name: 'yellow', hex: '#ffd400', variant: 'vivid', label: 'white' },
|
|
122
134
|
red: { name: 'red', hex: '#ef4444', variant: 'vivid' },
|
|
123
135
|
purple: { name: 'purple', hex: '#b866ff', variant: 'vivid' },
|
|
124
|
-
pink: { name: 'pink', hex: '#
|
|
136
|
+
pink: { name: 'pink', hex: '#f91880', variant: 'vivid' },
|
|
125
137
|
sky: { name: 'sky', hex: '#03a9f4', variant: 'vivid' },
|
|
126
138
|
// Deliberately NOT Tailwind's orange-500 (`#f97316`). That seed sits at HCT hue
|
|
127
139
|
// 46, which reads as orange only because it is also light: at hue 46 the sRGB
|
|
@@ -129,7 +141,7 @@ export const APP_COLOR_PRESETS: Record<AppColorName, AppColorPreset> = {
|
|
|
129
141
|
// the brand fill resolved to `rgb(177 76 0)` — a brown. Hue 34 carries a chroma
|
|
130
142
|
// of 84 at that same tone, with the same white label and the same contrast
|
|
131
143
|
// headroom, so the fill reads as orange instead of paying for the hue twice.
|
|
132
|
-
orange: { name: 'orange', hex: '#
|
|
144
|
+
orange: { name: 'orange', hex: '#ff7a00', variant: 'vivid' },
|
|
133
145
|
mint: { name: 'mint', hex: '#14b8a6', variant: 'vivid' },
|
|
134
146
|
oxy: { name: 'oxy', hex: '#c46ede', variant: 'vivid', gate: 'handle' },
|
|
135
147
|
faircoin: { name: 'faircoin', hex: '#9ffb50', variant: 'vivid', gate: 'handle' },
|