@oxyhq/bloom 1.0.2 → 1.0.3

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.
Files changed (28) hide show
  1. package/docs/button.mdx +19 -17
  2. package/docs/design-tokens.mdx +12 -10
  3. package/lib/commonjs/design-tokens/tokens.json +11040 -0
  4. package/lib/commonjs/theme/color-policy.js +1 -1
  5. package/lib/commonjs/theme/color-presets.js +331 -1
  6. package/lib/commonjs/theme/color-presets.js.map +1 -1
  7. package/lib/commonjs/theme/glass-colors.js +22 -19
  8. package/lib/commonjs/theme/glass-colors.js.map +1 -1
  9. package/lib/module/design-tokens/tokens.json +11040 -0
  10. package/lib/module/theme/color-policy.js +1 -1
  11. package/lib/module/theme/color-presets.js +331 -1
  12. package/lib/module/theme/color-presets.js.map +1 -1
  13. package/lib/module/theme/glass-colors.js +22 -19
  14. package/lib/module/theme/glass-colors.js.map +1 -1
  15. package/lib/typescript/commonjs/theme/color-presets.d.ts +331 -1
  16. package/lib/typescript/commonjs/theme/color-presets.d.ts.map +1 -1
  17. package/lib/typescript/commonjs/theme/glass-colors.d.ts +22 -19
  18. package/lib/typescript/commonjs/theme/glass-colors.d.ts.map +1 -1
  19. package/lib/typescript/module/theme/color-presets.d.ts +331 -1
  20. package/lib/typescript/module/theme/color-presets.d.ts.map +1 -1
  21. package/lib/typescript/module/theme/glass-colors.d.ts +22 -19
  22. package/lib/typescript/module/theme/glass-colors.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/design-tokens/tokens.json +11040 -0
  25. package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +3600 -0
  26. package/src/theme/color-policy.ts +1 -1
  27. package/src/theme/color-presets.ts +361 -1
  28. package/src/theme/glass-colors.ts +22 -19
@@ -162,7 +162,7 @@ const SUBTLE_ALPHA = { light: 0.13, dark: 0.24 } as const;
162
162
  * every rung of Bloom's surface stack was invisible against its neighbour, and
163
163
  * the thirteen components that carry meaning ONLY in the step between two
164
164
  * surfaces (a heatmap's empty cell, a filled card, a progress track, a hover
165
- * row, a skeleton) read as nothing at all. Measured across all 34 presets, 4
165
+ * row, a skeleton) read as nothing at all. Measured across all 64 presets, 4
166
166
  * tones is ~2.4 ΔE00 and is the first spacing where every pair separates.
167
167
  *
168
168
  * `--background` is deliberately NOT in here: the page keeps the tone it
@@ -404,6 +404,366 @@ const COLOR_PRESET_SOURCES = [
404
404
  pairing: 'curated',
405
405
  featured: true,
406
406
  },
407
+ {
408
+ name: 'forest-fire',
409
+ displayName: 'Forest + Crimson + Marigold',
410
+ family: 'botanical',
411
+ description: 'Deep forest identity, crimson support and a hard marigold action signal.',
412
+ hex: '#075c35',
413
+ secondaryHex: '#9a153d',
414
+ tertiaryHex: '#ffb400',
415
+ variant: 'vivid',
416
+ pairing: 'curated',
417
+ featured: true,
418
+ },
419
+ {
420
+ name: 'malachite-rush',
421
+ displayName: 'Malachite + Copper + Cobalt',
422
+ family: 'botanical',
423
+ description: 'Mineral green identity backed by copper and finished with a cobalt action.',
424
+ hex: '#008a55',
425
+ secondaryHex: '#b74b12',
426
+ tertiaryHex: '#1e55e6',
427
+ variant: 'vivid',
428
+ pairing: 'curated',
429
+ featured: true,
430
+ },
431
+ {
432
+ name: 'moss-voltage',
433
+ displayName: 'Moss + Petrol + Electric Purple',
434
+ family: 'botanical',
435
+ description: 'Dense moss and petrol structure cut by a saturated electric-purple action.',
436
+ hex: '#556b0b',
437
+ secondaryHex: '#006f7a',
438
+ tertiaryHex: '#c000be',
439
+ variant: 'vivid',
440
+ pairing: 'curated',
441
+ featured: true,
442
+ },
443
+ {
444
+ name: 'viridian-orbit',
445
+ displayName: 'Viridian + Purple + Safety Orange',
446
+ family: 'botanical',
447
+ description: 'Cool viridian identity with purple support and an unmistakable orange action.',
448
+ hex: '#006b57',
449
+ secondaryHex: '#6a1fd2',
450
+ tertiaryHex: '#ff8a00',
451
+ variant: 'vivid',
452
+ pairing: 'curated',
453
+ featured: true,
454
+ },
455
+ {
456
+ name: 'acid-canopy',
457
+ displayName: 'Acid Canopy + Cobalt + Magenta',
458
+ family: 'botanical',
459
+ description: 'Acid olive identity balanced by cobalt support and a clear magenta action.',
460
+ hex: '#5c7f00',
461
+ secondaryHex: '#0047d9',
462
+ tertiaryHex: '#e500a4',
463
+ variant: 'vivid',
464
+ pairing: 'curated',
465
+ featured: true,
466
+ },
467
+ {
468
+ name: 'pacific-flare',
469
+ displayName: 'Pacific + Ochre + Blue Violet',
470
+ family: 'ocean',
471
+ description: 'Deep Pacific blue with ochre support and a blue-violet action.',
472
+ hex: '#006487',
473
+ secondaryHex: '#c76b00',
474
+ tertiaryHex: '#4c34e8',
475
+ variant: 'vivid',
476
+ pairing: 'curated',
477
+ featured: true,
478
+ },
479
+ {
480
+ name: 'reef-pulse',
481
+ displayName: 'Reef + Burnt Orange + Raspberry',
482
+ family: 'ocean',
483
+ description: 'Saturated reef identity, burnt-orange support and a raspberry action pulse.',
484
+ hex: '#007d8a',
485
+ secondaryHex: '#ef6c00',
486
+ tertiaryHex: '#d80073',
487
+ variant: 'vivid',
488
+ pairing: 'curated',
489
+ featured: true,
490
+ },
491
+ {
492
+ name: 'electric-tide',
493
+ displayName: 'Electric Blue + Violet + Acid Lime',
494
+ family: 'ocean',
495
+ description: 'Electric-blue identity with violet depth and a high-voltage lime action.',
496
+ hex: '#005be7',
497
+ secondaryHex: '#6b20c8',
498
+ tertiaryHex: '#76c900',
499
+ variant: 'vivid',
500
+ pairing: 'curated',
501
+ featured: true,
502
+ },
503
+ {
504
+ name: 'arctic-signal',
505
+ displayName: 'Arctic Cyan + Navy + Fuchsia',
506
+ family: 'ocean',
507
+ description: 'Crisp cyan identity anchored by navy with a decisive fuchsia action.',
508
+ hex: '#0089a8',
509
+ secondaryHex: '#123a78',
510
+ tertiaryHex: '#d6008f',
511
+ variant: 'vivid',
512
+ pairing: 'curated',
513
+ featured: true,
514
+ },
515
+ {
516
+ name: 'ultramarine-gold',
517
+ displayName: 'Ultramarine + Rust + Gold',
518
+ family: 'ocean',
519
+ description: 'Dense ultramarine identity with earthen rust support and a true-gold action.',
520
+ hex: '#273bc6',
521
+ secondaryHex: '#a83b13',
522
+ tertiaryHex: '#f5b700',
523
+ variant: 'vivid',
524
+ pairing: 'curated',
525
+ featured: true,
526
+ },
527
+ {
528
+ name: 'midnight-citrus',
529
+ displayName: 'Midnight Indigo + Teal + Citrus',
530
+ family: 'ocean',
531
+ description: 'Midnight indigo and teal create depth while citrus owns the primary action.',
532
+ hex: '#29267d',
533
+ secondaryHex: '#00867a',
534
+ tertiaryHex: '#ff7200',
535
+ variant: 'vivid',
536
+ pairing: 'curated',
537
+ featured: true,
538
+ },
539
+ {
540
+ name: 'persimmon-wave',
541
+ displayName: 'Persimmon + Marine + Sun Yellow',
542
+ family: 'sunset',
543
+ description: 'Persimmon identity with marine support and a saturated sun-yellow action.',
544
+ hex: '#c83a12',
545
+ secondaryHex: '#003f75',
546
+ tertiaryHex: '#f5cf00',
547
+ variant: 'vivid',
548
+ pairing: 'curated',
549
+ featured: true,
550
+ },
551
+ {
552
+ name: 'solar-flux',
553
+ displayName: 'Solar Orange + Magenta + Deep Cyan',
554
+ family: 'sunset',
555
+ description: 'Solar orange identity grounded by magenta with a strong deep-cyan action.',
556
+ hex: '#d95800',
557
+ secondaryHex: '#b00078',
558
+ tertiaryHex: '#008ca5',
559
+ variant: 'vivid',
560
+ pairing: 'curated',
561
+ featured: true,
562
+ },
563
+ {
564
+ name: 'paprika-current',
565
+ displayName: 'Paprika + Olive + Turquoise',
566
+ family: 'sunset',
567
+ description: 'Paprika identity, grounded olive support and a clean turquoise action.',
568
+ hex: '#a83216',
569
+ secondaryHex: '#657000',
570
+ tertiaryHex: '#00a1a8',
571
+ variant: 'vivid',
572
+ pairing: 'curated',
573
+ featured: true,
574
+ },
575
+ {
576
+ name: 'crimson-spark',
577
+ displayName: 'Crimson + Teal + Electric Lime',
578
+ family: 'sunset',
579
+ description: 'Crimson identity with teal support and an electric-lime action spark.',
580
+ hex: '#b70d36',
581
+ secondaryHex: '#007a83',
582
+ tertiaryHex: '#9bd300',
583
+ variant: 'vivid',
584
+ pairing: 'curated',
585
+ featured: true,
586
+ },
587
+ {
588
+ name: 'flamenco-sun',
589
+ displayName: 'Flamenco Red + Emerald + Sunbeam',
590
+ family: 'sunset',
591
+ description: 'Flamenco-red identity supported by emerald and punctuated by a sunbeam action.',
592
+ hex: '#d51f2d',
593
+ secondaryHex: '#007663',
594
+ tertiaryHex: '#ffc000',
595
+ variant: 'vivid',
596
+ pairing: 'curated',
597
+ featured: true,
598
+ },
599
+ {
600
+ name: 'saffron-depth',
601
+ displayName: 'Saffron + Aubergine + Royal Blue',
602
+ family: 'sunset',
603
+ description: 'Deep saffron identity with aubergine support and a royal-blue action.',
604
+ hex: '#a86400',
605
+ secondaryHex: '#67145d',
606
+ tertiaryHex: '#165dd8',
607
+ variant: 'vivid',
608
+ pairing: 'curated',
609
+ featured: true,
610
+ },
611
+ {
612
+ name: 'clay-current',
613
+ displayName: 'Clay + Gold + Fuchsia',
614
+ family: 'earth',
615
+ description: 'Burnt-clay identity with deep-gold support and a saturated fuchsia action.',
616
+ hex: '#9a3f1d',
617
+ secondaryHex: '#b56a00',
618
+ tertiaryHex: '#c900a5',
619
+ variant: 'vivid',
620
+ pairing: 'curated',
621
+ featured: true,
622
+ },
623
+ {
624
+ name: 'bronze-neon',
625
+ displayName: 'Bronze + Emerald + Neon Berry',
626
+ family: 'earth',
627
+ description: 'Bronze identity offset by emerald support and a neon-berry action.',
628
+ hex: '#875000',
629
+ secondaryHex: '#17603a',
630
+ tertiaryHex: '#df007e',
631
+ variant: 'vivid',
632
+ pairing: 'curated',
633
+ featured: true,
634
+ },
635
+ {
636
+ name: 'copper-field',
637
+ displayName: 'Copper + Emerald + Royal Blue',
638
+ family: 'earth',
639
+ description: 'Copper identity, emerald support and a crisp royal-blue action.',
640
+ hex: '#a94d12',
641
+ secondaryHex: '#00734f',
642
+ tertiaryHex: '#2354d8',
643
+ variant: 'vivid',
644
+ pairing: 'curated',
645
+ featured: true,
646
+ },
647
+ {
648
+ name: 'umber-signal',
649
+ displayName: 'Umber + Ocean Cyan + Signal Gold',
650
+ family: 'earth',
651
+ description: 'Dark umber identity with ocean-cyan support and a signal-gold action.',
652
+ hex: '#693916',
653
+ secondaryHex: '#00889b',
654
+ tertiaryHex: '#f3b300',
655
+ variant: 'vivid',
656
+ pairing: 'curated',
657
+ featured: true,
658
+ },
659
+ {
660
+ name: 'amethyst-current',
661
+ displayName: 'Amethyst + Ochre + Emerald',
662
+ family: 'jewel',
663
+ description: 'Amethyst identity with ochre support and a saturated emerald action.',
664
+ hex: '#6d1db8',
665
+ secondaryHex: '#b87500',
666
+ tertiaryHex: '#00a85a',
667
+ variant: 'vivid',
668
+ pairing: 'curated',
669
+ featured: true,
670
+ },
671
+ {
672
+ name: 'ruby-current',
673
+ displayName: 'Ruby + Violet + Turquoise',
674
+ family: 'jewel',
675
+ description: 'Ruby identity backed by violet support and focused by a turquoise action.',
676
+ hex: '#a90032',
677
+ secondaryHex: '#6632b5',
678
+ tertiaryHex: '#00a99d',
679
+ variant: 'vivid',
680
+ pairing: 'curated',
681
+ featured: true,
682
+ },
683
+ {
684
+ name: 'orchid-flare',
685
+ displayName: 'Orchid + Burnt Orange + Cyan',
686
+ family: 'jewel',
687
+ description: 'Saturated orchid identity with burnt-orange support and a cyan action.',
688
+ hex: '#a70086',
689
+ secondaryHex: '#d45a00',
690
+ tertiaryHex: '#00a6b8',
691
+ variant: 'vivid',
692
+ pairing: 'curated',
693
+ featured: true,
694
+ },
695
+ {
696
+ name: 'garnet-acid',
697
+ displayName: 'Garnet + Indigo + Acid Lime',
698
+ family: 'jewel',
699
+ description: 'Dark garnet identity, indigo support and a high-chroma acid-lime action.',
700
+ hex: '#7d1538',
701
+ secondaryHex: '#2839a8',
702
+ tertiaryHex: '#88c900',
703
+ variant: 'vivid',
704
+ pairing: 'curated',
705
+ featured: true,
706
+ },
707
+ {
708
+ name: 'indigo-ember',
709
+ displayName: 'Indigo + Ember + Turquoise',
710
+ family: 'jewel',
711
+ description: 'Indigo identity with ember support and a direct turquoise action.',
712
+ hex: '#4130a8',
713
+ secondaryHex: '#a54216',
714
+ tertiaryHex: '#00a58c',
715
+ variant: 'vivid',
716
+ pairing: 'curated',
717
+ featured: true,
718
+ },
719
+ {
720
+ name: 'raspberry-gold',
721
+ displayName: 'Raspberry + Antique Gold + Cobalt',
722
+ family: 'jewel',
723
+ description: 'Raspberry identity with antique-gold support and a concentrated cobalt action.',
724
+ hex: '#b00063',
725
+ secondaryHex: '#b98600',
726
+ tertiaryHex: '#195fe8',
727
+ variant: 'vivid',
728
+ pairing: 'curated',
729
+ featured: true,
730
+ },
731
+ {
732
+ name: 'ink-orange',
733
+ displayName: 'Ink + Purple + Safety Orange',
734
+ family: 'neutral',
735
+ description: 'Blue-black ink identity with purple support and a safety-orange action.',
736
+ hex: '#202f44',
737
+ secondaryHex: '#7d3fb2',
738
+ tertiaryHex: '#f25b16',
739
+ variant: 'vivid',
740
+ pairing: 'curated',
741
+ featured: true,
742
+ },
743
+ {
744
+ name: 'charcoal-lime',
745
+ displayName: 'Charcoal + Cobalt + Electric Lime',
746
+ family: 'neutral',
747
+ description: 'Charcoal identity gives cobalt structure and electric lime room to command.',
748
+ hex: '#303a35',
749
+ secondaryHex: '#205bd2',
750
+ tertiaryHex: '#86ce00',
751
+ variant: 'vivid',
752
+ pairing: 'curated',
753
+ featured: true,
754
+ },
755
+ {
756
+ name: 'pewter-current',
757
+ displayName: 'Pewter + Purple + Turquoise',
758
+ family: 'neutral',
759
+ description: 'Cool pewter identity with purple support and a saturated turquoise action.',
760
+ hex: '#47515b',
761
+ secondaryHex: '#6b27b6',
762
+ tertiaryHex: '#00a88f',
763
+ variant: 'vivid',
764
+ pairing: 'curated',
765
+ featured: true,
766
+ },
407
767
  ] as const satisfies readonly ColorPresetSource[];
408
768
 
409
769
  /** Preset identifiers are inferred from the authored registry, never repeated. */
@@ -469,7 +829,7 @@ export function hexToAppColorName(hex: string): AppColorName {
469
829
  return HEX_TO_APP_COLOR[hex.toLowerCase()] ?? 'teal';
470
830
  }
471
831
 
472
- /** The sixteen approved paired directions in the permanent Mention playground. */
832
+ /** The approved paired directions in the permanent Mention playground. */
473
833
  export const COLOR_PLAYGROUND_NAMES: readonly AppColorName[] = COLOR_PRESET_REGISTRY
474
834
  .filter(({ featured }) => featured)
475
835
  .map(({ name }) => name);
@@ -89,22 +89,24 @@ import { withAlpha } from './color-utils';
89
89
  *
90
90
  * The 15% that bleeds through moves the pane TOWARD the surface under it, and
91
91
  * in light mode that means lighter — which is the direction a white label can
92
- * least afford. Measured over 34 presets x 2 modes x 5 Bloom surfaces:
93
- *
94
- * `Button` primary 38 of 340 rows fall below WCAG AA, in the band
95
- * 4.17..4.49, ALL of them in LIGHT mode, across fourteen
96
- * presets (blue, faircoin, green, lagoon, lavender, mint,
97
- * olive, orange, pine, plum, pumpkin, rose, sky, yellow).
98
- * `Button` destructive 0 of 340. Worst 5.32.
99
- *
100
- * As a SOLID fill all 680 Button rows pass. The original 18 presets retain
101
- * their exact 30/180 shipped failure set; all eight added failures belong to
102
- * the new recipes. A browser helper briefly reported 45 only because it parsed
103
- * the structured `GLASS_SHEEN.bottom` stop as CSS; that was measurement drift,
104
- * never the shipped oracle and never a threshold being relaxed.
92
+ * least afford. Measured over 64 presets x 2 modes x 5 Bloom surfaces:
93
+ *
94
+ * `Button` primary 73 of 640 rows fall below WCAG AA, in the band
95
+ * 4.17..4.50, ALL of them in LIGHT mode, across 27
96
+ * presets (acid-canopy, arctic-signal, blue, bronze-neon,
97
+ * clay-current, copper-field, electric-tide, faircoin,
98
+ * green, lagoon, lavender, malachite-rush,
99
+ * midnight-citrus, mint, olive, orange, pacific-flare,
100
+ * pine, plum, pumpkin, reef-pulse, rose, saffron-depth,
101
+ * sky, solar-flux, viridian-orbit, yellow).
102
+ * `Button` destructive 0 of 640. Worst 5.32.
103
+ *
104
+ * As a SOLID fill all 1280 Button rows pass. The 1.0.1 catalog retains its exact
105
+ * 38/340 failure set (including the original 18 presets' 30/180); the 30 new
106
+ * three-seed combinations add 35/300 and do not worsen the 4.17 floor.
105
107
  *
106
108
  * The alpha at which the failures reach zero is **0.89** (worst 4.52), and the
107
- * curve between is steep: 0.86 -> 25 rows, 0.87 -> 14, 0.88 -> 5, 0.89 -> 0.
109
+ * curve between is steep: 0.86 -> 49 rows, 0.87 -> 26, 0.88 -> 8, 0.89 -> 0.
108
110
  * So AA compliance costs four hundredths of alpha. 0.85 is kept because it is
109
111
  * the reference's own value and matching the reference is the requirement;
110
112
  * `glass-colors.test.ts` pins the compromise as an EXACT failure count and an
@@ -240,7 +242,7 @@ export interface GlassColors {
240
242
  * `colors.negative`, `colors.success` — rather than a tone name, because the
241
243
  * caller is the only one who knows which token its variant means. `Button`'s
242
244
  * `destructive` is `colors.negative` (the engine's error ROLE) and not
243
- * `colors.error` (the fixed status seed): measured, those two differ in all 68
245
+ * `colors.error` (the fixed status seed): measured, those two differ in all 128
244
246
  * preset x mode combinations and by as much as `rgb(255 180 171)` against
245
247
  * `rgb(209 45 50)` on `teal`/dark, so a tone vocabulary here would have
246
248
  * silently repainted every destructive button on the way past.
@@ -256,10 +258,11 @@ export interface GlassColors {
256
258
  * `colors.text` and that was correct THEN: a pane that is three-quarters
257
259
  * backdrop takes its luminance from the page, so it needed the page's reading
258
260
  * colour. At 0.85 the pane is the fill, so it takes the fill's own label: on
259
- * the complete 2040-row matrix (34 presets x 2 modes x 6 tones x 5 surfaces),
260
- * `colors.text` fails AA on 1714 rows (worst 1.21) against the on-fill token's
261
- * 305 (worst 4.17). Neither count is permanent; the gate re-measures and pins
262
- * both on every alpha or surface change.
261
+ * the complete 3840-row matrix (64 presets x 2 modes x 6 tones x 5 surfaces),
262
+ * `colors.text` fails AA on 3232 rows (worst 1.21) against the on-fill token's
263
+ * 577 (worst 4.17). The 1.0.1 baseline remains 1714/2040 versus 305/2040;
264
+ * the 30 additions contribute 1518/1800 versus 272/1800. The gate re-measures
265
+ * and pins both on every alpha or surface change.
263
266
  */
264
267
  export function resolveGlassColors(fill: string): GlassColors {
265
268
  return {