@ponchia/ui 0.5.0 → 0.6.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 (196) hide show
  1. package/CHANGELOG.md +386 -4
  2. package/MIGRATIONS.json +14 -0
  3. package/README.md +29 -6
  4. package/annotations/index.d.ts +398 -276
  5. package/annotations/index.d.ts.map +1 -0
  6. package/annotations/index.js +350 -77
  7. package/behaviors/carousel.d.ts +28 -0
  8. package/behaviors/carousel.d.ts.map +1 -0
  9. package/behaviors/carousel.js +20 -16
  10. package/behaviors/combobox.d.ts +40 -0
  11. package/behaviors/combobox.d.ts.map +1 -0
  12. package/behaviors/combobox.js +111 -29
  13. package/behaviors/command.d.ts +41 -0
  14. package/behaviors/command.d.ts.map +1 -0
  15. package/behaviors/command.js +27 -15
  16. package/behaviors/connectors.d.ts +17 -0
  17. package/behaviors/connectors.d.ts.map +1 -0
  18. package/behaviors/connectors.js +7 -5
  19. package/behaviors/crosshair.d.ts +42 -0
  20. package/behaviors/crosshair.d.ts.map +1 -0
  21. package/behaviors/crosshair.js +23 -6
  22. package/behaviors/dialog.d.ts +20 -0
  23. package/behaviors/dialog.d.ts.map +1 -0
  24. package/behaviors/dialog.js +6 -2
  25. package/behaviors/disclosure.d.ts +10 -0
  26. package/behaviors/disclosure.d.ts.map +1 -0
  27. package/behaviors/disclosure.js +6 -2
  28. package/behaviors/dismissible.d.ts +10 -0
  29. package/behaviors/dismissible.d.ts.map +1 -0
  30. package/behaviors/dismissible.js +6 -2
  31. package/behaviors/forms.d.ts +27 -0
  32. package/behaviors/forms.d.ts.map +1 -0
  33. package/behaviors/forms.js +54 -13
  34. package/behaviors/glyph.d.ts +14 -0
  35. package/behaviors/glyph.d.ts.map +1 -0
  36. package/behaviors/glyph.js +28 -5
  37. package/behaviors/index.d.ts +31 -237
  38. package/behaviors/index.d.ts.map +1 -0
  39. package/behaviors/index.js +17 -0
  40. package/behaviors/inert.d.ts +20 -0
  41. package/behaviors/inert.d.ts.map +1 -0
  42. package/behaviors/inert.js +46 -0
  43. package/behaviors/internal.d.ts +25 -0
  44. package/behaviors/internal.d.ts.map +1 -0
  45. package/behaviors/internal.js +77 -1
  46. package/behaviors/legend.d.ts +35 -0
  47. package/behaviors/legend.d.ts.map +1 -0
  48. package/behaviors/legend.js +32 -2
  49. package/behaviors/menu.d.ts +16 -0
  50. package/behaviors/menu.d.ts.map +1 -0
  51. package/behaviors/menu.js +6 -2
  52. package/behaviors/modal.d.ts +41 -0
  53. package/behaviors/modal.d.ts.map +1 -0
  54. package/behaviors/modal.js +124 -0
  55. package/behaviors/popover.d.ts +28 -0
  56. package/behaviors/popover.d.ts.map +1 -0
  57. package/behaviors/popover.js +78 -7
  58. package/behaviors/spotlight.d.ts +17 -0
  59. package/behaviors/spotlight.d.ts.map +1 -0
  60. package/behaviors/spotlight.js +7 -5
  61. package/behaviors/table.d.ts +36 -0
  62. package/behaviors/table.d.ts.map +1 -0
  63. package/behaviors/table.js +84 -17
  64. package/behaviors/tabs.d.ts +20 -0
  65. package/behaviors/tabs.d.ts.map +1 -0
  66. package/behaviors/tabs.js +17 -14
  67. package/behaviors/theme.d.ts +54 -0
  68. package/behaviors/theme.d.ts.map +1 -0
  69. package/behaviors/theme.js +22 -3
  70. package/behaviors/toast.d.ts +49 -0
  71. package/behaviors/toast.d.ts.map +1 -0
  72. package/behaviors/toast.js +47 -3
  73. package/classes/classes.json +2527 -0
  74. package/classes/index.d.ts +134 -15
  75. package/classes/index.js +280 -80
  76. package/classes/vscode.css-custom-data.json +12 -0
  77. package/connectors/index.d.ts +201 -69
  78. package/connectors/index.d.ts.map +1 -0
  79. package/connectors/index.js +142 -25
  80. package/css/app.css +69 -13
  81. package/css/base.css +15 -10
  82. package/css/bullet.css +108 -0
  83. package/css/code.css +98 -0
  84. package/css/connectors.css +17 -0
  85. package/css/content.css +22 -3
  86. package/css/crosshair.css +7 -7
  87. package/css/dataviz.css +5 -1
  88. package/css/diff.css +153 -0
  89. package/css/disclosure.css +53 -7
  90. package/css/dots.css +94 -7
  91. package/css/feedback.css +97 -7
  92. package/css/forms.css +113 -4
  93. package/css/legend.css +16 -9
  94. package/css/marks.css +38 -8
  95. package/css/motion.css +98 -53
  96. package/css/navigation.css +7 -0
  97. package/css/overlay.css +90 -3
  98. package/css/primitives.css +158 -13
  99. package/css/report.css +73 -56
  100. package/css/sidenote.css +67 -0
  101. package/css/site.css +16 -2
  102. package/css/sources.css +43 -1
  103. package/css/spark.css +62 -0
  104. package/css/spotlight.css +1 -1
  105. package/css/table.css +9 -2
  106. package/css/term.css +110 -0
  107. package/css/textref.css +63 -0
  108. package/css/toc.css +91 -0
  109. package/css/tokens.css +49 -1
  110. package/css/tree.css +134 -0
  111. package/css/workbench.css +1 -1
  112. package/dist/bronto.css +1 -1
  113. package/dist/css/analytical.css +1 -1
  114. package/dist/css/app.css +1 -1
  115. package/dist/css/base.css +1 -1
  116. package/dist/css/bullet.css +1 -0
  117. package/dist/css/code.css +1 -0
  118. package/dist/css/connectors.css +1 -1
  119. package/dist/css/content.css +1 -1
  120. package/dist/css/crosshair.css +1 -1
  121. package/dist/css/diff.css +1 -0
  122. package/dist/css/disclosure.css +1 -1
  123. package/dist/css/dots.css +1 -1
  124. package/dist/css/feedback.css +1 -1
  125. package/dist/css/forms.css +1 -1
  126. package/dist/css/legend.css +1 -1
  127. package/dist/css/marks.css +1 -1
  128. package/dist/css/motion.css +1 -1
  129. package/dist/css/navigation.css +1 -1
  130. package/dist/css/overlay.css +1 -1
  131. package/dist/css/primitives.css +1 -1
  132. package/dist/css/report.css +1 -1
  133. package/dist/css/sidenote.css +1 -0
  134. package/dist/css/site.css +1 -1
  135. package/dist/css/sources.css +1 -1
  136. package/dist/css/spark.css +1 -0
  137. package/dist/css/spotlight.css +1 -1
  138. package/dist/css/table.css +1 -1
  139. package/dist/css/term.css +1 -0
  140. package/dist/css/textref.css +1 -0
  141. package/dist/css/toc.css +1 -0
  142. package/dist/css/tokens.css +1 -1
  143. package/dist/css/tree.css +1 -0
  144. package/dist/css/workbench.css +1 -1
  145. package/docs/adr/0003-theme-model.md +1 -1
  146. package/docs/annotations.md +133 -14
  147. package/docs/architecture.md +49 -6
  148. package/docs/bullet.md +78 -0
  149. package/docs/code.md +76 -0
  150. package/docs/contrast.md +116 -92
  151. package/docs/d2.md +196 -0
  152. package/docs/diff.md +146 -0
  153. package/docs/legends.md +23 -3
  154. package/docs/marks.md +9 -2
  155. package/docs/mermaid.md +169 -0
  156. package/docs/reference.md +201 -26
  157. package/docs/reporting.md +416 -57
  158. package/docs/sidenote.md +64 -0
  159. package/docs/sources.md +27 -0
  160. package/docs/spark.md +78 -0
  161. package/docs/stability.md +10 -2
  162. package/docs/term.md +81 -0
  163. package/docs/textref.md +78 -0
  164. package/docs/theming.md +44 -5
  165. package/docs/toc.md +83 -0
  166. package/docs/tree.md +74 -0
  167. package/docs/usage.md +354 -16
  168. package/docs/vega.md +244 -0
  169. package/docs/workbench.md +7 -1
  170. package/glyphs/glyphs.js +13 -5
  171. package/llms.txt +285 -14
  172. package/package.json +95 -17
  173. package/qwik/index.d.ts +44 -59
  174. package/qwik/index.d.ts.map +1 -0
  175. package/qwik/index.js +65 -3
  176. package/react/index.d.ts +41 -61
  177. package/react/index.d.ts.map +1 -0
  178. package/react/index.js +63 -3
  179. package/solid/index.d.ts +68 -61
  180. package/solid/index.d.ts.map +1 -0
  181. package/solid/index.js +66 -3
  182. package/tokens/d2.d.ts +38 -0
  183. package/tokens/d2.js +71 -0
  184. package/tokens/d2.json +43 -0
  185. package/tokens/index.d.ts +5 -5
  186. package/tokens/index.js +15 -1
  187. package/tokens/index.json +9 -0
  188. package/tokens/mermaid.d.ts +23 -0
  189. package/tokens/mermaid.js +181 -0
  190. package/tokens/mermaid.json +163 -0
  191. package/tokens/resolved.json +45 -1
  192. package/tokens/skins.js +3 -2
  193. package/tokens/tokens.dtcg.json +26 -0
  194. package/tokens/vega.d.ts +34 -0
  195. package/tokens/vega.js +155 -0
  196. package/tokens/vega.json +179 -0
package/classes/index.js CHANGED
@@ -38,6 +38,11 @@ export const cls = Object.freeze({
38
38
  numPos: 'ui-num--pos',
39
39
  numNeg: 'ui-num--neg',
40
40
  numMuted: 'ui-num--muted',
41
+ delta: 'ui-delta',
42
+ deltaUp: 'ui-delta--up',
43
+ deltaDown: 'ui-delta--down',
44
+ deltaFlat: 'ui-delta--flat',
45
+ deltaInvert: 'ui-delta--invert',
41
46
  badge: 'ui-badge',
42
47
  badgeAccent: 'ui-badge--accent',
43
48
  badgeSuccess: 'ui-badge--success',
@@ -106,7 +111,7 @@ export const cls = Object.freeze({
106
111
  alert: 'ui-alert',
107
112
  alertTitle: 'ui-alert__title',
108
113
  alertBody: 'ui-alert__body',
109
- alertDismiss: 'ui-alert__dismiss',
114
+ alertClose: 'ui-alert__close',
110
115
  alertAccent: 'ui-alert--accent',
111
116
  alertSuccess: 'ui-alert--success',
112
117
  alertWarning: 'ui-alert--warning',
@@ -130,10 +135,14 @@ export const cls = Object.freeze({
130
135
  progressIndeterminate: 'ui-progress--indeterminate',
131
136
  meter: 'ui-meter',
132
137
  meterFill: 'ui-meter__fill',
138
+ meterRow: 'ui-meter__row',
139
+ meterLabel: 'ui-meter__label',
140
+ meterValue: 'ui-meter__value',
133
141
  meterAccent: 'ui-meter--accent',
134
142
  meterSuccess: 'ui-meter--success',
135
143
  meterWarning: 'ui-meter--warning',
136
144
  meterDanger: 'ui-meter--danger',
145
+ meterInfo: 'ui-meter--info',
137
146
  steps: 'ui-steps',
138
147
  stepsItem: 'ui-steps__item',
139
148
  stepsItemDone: 'ui-steps__item--done',
@@ -191,12 +200,13 @@ export const cls = Object.freeze({
191
200
  tableComfortable: 'ui-table--comfortable',
192
201
  tableLined: 'ui-table--lined',
193
202
  tableWrap: 'ui-table-wrap',
203
+ // Loading state goes on the WRAP, so the modifier is named for the wrap (C19).
204
+ tableLoading: 'ui-table-wrap--loading',
194
205
  tableEmpty: 'ui-table__empty',
195
206
  tableSort: 'ui-table__sort',
196
207
  tableSelect: 'ui-table__select',
197
208
  tableToolbar: 'ui-table__toolbar',
198
209
  tableSelectable: 'ui-table--selectable',
199
- tableLoading: 'ui-table--loading',
200
210
  // shell / layout
201
211
  panel: 'ui-panel',
202
212
  panelHead: 'ui-panel__head',
@@ -251,7 +261,7 @@ export const cls = Object.freeze({
251
261
  reportNumbered: 'ui-report--numbered',
252
262
  reportCover: 'ui-report__cover',
253
263
  reportCoverCompact: 'ui-report__cover--compact',
254
- reportHeader: 'ui-report__header',
264
+ reportHead: 'ui-report__head',
255
265
  reportTitle: 'ui-report__title',
256
266
  reportSubtitle: 'ui-report__subtitle',
257
267
  reportMeta: 'ui-report__meta',
@@ -267,14 +277,10 @@ export const cls = Object.freeze({
267
277
  reportSources: 'ui-report__sources',
268
278
  reportAppendix: 'ui-report__appendix',
269
279
  reportFootnotes: 'ui-report__footnotes',
270
- chart: 'ui-chart',
271
- chartCaption: 'ui-chart__caption',
272
- chartPlot: 'ui-chart__plot',
273
- chartBar: 'ui-chart__bar',
274
- chartLabel: 'ui-chart__label',
275
- chartTrack: 'ui-chart__track',
276
- chartFill: 'ui-chart__fill',
277
- chartFallback: 'ui-chart__fallback',
280
+ compare: 'ui-compare',
281
+ compare2up: 'ui-compare--2up',
282
+ compareCol: 'ui-compare__col',
283
+ compareHead: 'ui-compare__head',
278
284
  // legend (standalone data keys — css/legend.css)
279
285
  legend: 'ui-legend',
280
286
  legendVertical: 'ui-legend--vertical',
@@ -354,6 +360,7 @@ export const cls = Object.freeze({
354
360
  bracketNote: 'ui-bracket-note',
355
361
  bracketNoteLabel: 'ui-bracket-note__label',
356
362
  bracketNoteAccent: 'ui-bracket-note--accent',
363
+ bracketNoteSuccess: 'ui-bracket-note--success',
357
364
  bracketNoteWarning: 'ui-bracket-note--warning',
358
365
  bracketNoteDanger: 'ui-bracket-note--danger',
359
366
  bracketNoteInfo: 'ui-bracket-note--info',
@@ -404,12 +411,71 @@ export const cls = Object.freeze({
404
411
  sourceCardActions: 'ui-source-card__actions',
405
412
  provenance: 'ui-provenance',
406
413
  provenanceItem: 'ui-provenance__item',
414
+ src: 'ui-src',
407
415
  srcVerified: 'ui-src--verified',
408
416
  srcUnverified: 'ui-src--unverified',
409
417
  srcGenerated: 'ui-src--generated',
410
418
  srcReviewed: 'ui-src--reviewed',
411
419
  srcStale: 'ui-src--stale',
412
420
  srcConflict: 'ui-src--conflict',
421
+ // diff — line/row change-review grammar (css/diff.css)
422
+ diff: 'ui-diff',
423
+ diffSplit: 'ui-diff--split',
424
+ diffPane: 'ui-diff__pane',
425
+ diffHunk: 'ui-diff__hunk',
426
+ diffHead: 'ui-diff__head',
427
+ diffRow: 'ui-diff__row',
428
+ diffRowAdd: 'ui-diff__row--add',
429
+ diffRowRemove: 'ui-diff__row--remove',
430
+ diffRowContext: 'ui-diff__row--context',
431
+ diffLn: 'ui-diff__ln',
432
+ diffCode: 'ui-diff__code',
433
+ // code — fenced-code evidence chrome (css/code.css)
434
+ code: 'ui-code',
435
+ codeNumbered: 'ui-code--numbered',
436
+ codeHead: 'ui-code__head',
437
+ codeBody: 'ui-code__body',
438
+ codeLine: 'ui-code__line',
439
+ codeLineAdd: 'ui-code__line--add',
440
+ codeLineRemove: 'ui-code__line--remove',
441
+ codeLineHl: 'ui-code__line--hl',
442
+ // spark — inline datawords / microcharts (css/spark.css)
443
+ spark: 'ui-spark',
444
+ sparkBar: 'ui-spark__bar',
445
+ sparkBarAccent: 'ui-spark__bar--accent',
446
+ sparkBarPos: 'ui-spark__bar--pos',
447
+ sparkBarNeg: 'ui-spark__bar--neg',
448
+ // sidenote — Tufte margin notes (css/sidenote.css)
449
+ sidenote: 'ui-sidenote',
450
+ marginnote: 'ui-marginnote',
451
+ sidenoteRef: 'ui-sidenote__ref',
452
+ // textref — deep-link-to-cited-text provenance link (css/textref.css)
453
+ textref: 'ui-textref',
454
+ // bullet — Stephen-Few bullet graph: measure vs target vs bands (css/bullet.css)
455
+ bullet: 'ui-bullet',
456
+ bulletMeasure: 'ui-bullet__measure',
457
+ bulletMeasureAccent: 'ui-bullet__measure--accent',
458
+ bulletMeasurePos: 'ui-bullet__measure--pos',
459
+ bulletMeasureNeg: 'ui-bullet__measure--neg',
460
+ bulletTarget: 'ui-bullet__target',
461
+ bulletLabel: 'ui-bullet__label',
462
+ // term — inline glossary term + definition popover + glossary <dl> (css/term.css)
463
+ term: 'ui-term',
464
+ def: 'ui-def',
465
+ glossary: 'ui-glossary',
466
+ glossaryTerm: 'ui-glossary__term',
467
+ glossaryDef: 'ui-glossary__def',
468
+ // toc — scrollspy table-of-contents rail (css/toc.css)
469
+ toc: 'ui-toc',
470
+ tocTitle: 'ui-toc__title',
471
+ tocList: 'ui-toc__list',
472
+ tocLink: 'ui-toc__link',
473
+ // tree — hierarchy outline on nested <details> (css/tree.css)
474
+ tree: 'ui-tree',
475
+ treeBranch: 'ui-tree__branch',
476
+ treeLeaf: 'ui-tree__leaf',
477
+ treeSummary: 'ui-tree__summary',
478
+ treeLabel: 'ui-tree__label',
413
479
  // lifecycle / system state (css/state.css)
414
480
  state: 'ui-state',
415
481
  stateLabel: 'ui-state__label',
@@ -440,7 +506,7 @@ export const cls = Object.freeze({
440
506
  toolCallBody: 'ui-tool-call__body',
441
507
  // workbench — inspector / property / selection bar (css/workbench.css)
442
508
  inspector: 'ui-inspector',
443
- inspectorHeader: 'ui-inspector__header',
509
+ inspectorHead: 'ui-inspector__head',
444
510
  inspectorBody: 'ui-inspector__body',
445
511
  property: 'ui-property',
446
512
  propertyLabel: 'ui-property__label',
@@ -490,7 +556,6 @@ export const cls = Object.freeze({
490
556
  appShellFull: 'ui-app-shell--full',
491
557
  appRail: 'ui-app-rail',
492
558
  appRailBrand: 'ui-app-rail__brand',
493
- appRailToggle: 'ui-app-rail__toggle',
494
559
  appRailFoot: 'ui-app-rail__foot',
495
560
  appRailAccount: 'ui-app-rail__account',
496
561
  appTopbar: 'ui-app-topbar',
@@ -543,14 +608,105 @@ const stateTone = (state) =>
543
608
  })[state] || '';
544
609
 
545
610
  // Trust-state → tone class, shared by the source/citation/provenance recipes.
611
+ // Object-literal lookup to match stateTone above (shorter, greppable, one idiom).
546
612
  const srcTone = (state) =>
547
- (state === 'verified' && cls.srcVerified) ||
548
- (state === 'unverified' && cls.srcUnverified) ||
549
- (state === 'generated' && cls.srcGenerated) ||
550
- (state === 'reviewed' && cls.srcReviewed) ||
551
- (state === 'stale' && cls.srcStale) ||
552
- (state === 'conflict' && cls.srcConflict) ||
553
- '';
613
+ ({
614
+ verified: cls.srcVerified,
615
+ unverified: cls.srcUnverified,
616
+ generated: cls.srcGenerated,
617
+ reviewed: cls.srcReviewed,
618
+ stale: cls.srcStale,
619
+ conflict: cls.srcConflict,
620
+ })[state] || '';
621
+
622
+ // Component tone → modifier class. Same object-literal idiom as srcTone/stateTone
623
+ // (still grep-by-class-name; the modifier set differs per component). (Q9.)
624
+ //
625
+ // The set differs PER COMPONENT on purpose — `muted` is a badge/num tone, not an
626
+ // alert/toast/meter/dot one — so a caller extrapolating a universal tone (e.g.
627
+ // `ui.alert({ tone: 'muted' })`) used to get a silent no-op: a bare, untoned
628
+ // element with no signal that the tone was dropped. Warn at dev time instead, so
629
+ // that "validates-but-no-ops" trap is loud rather than invisible. An omitted tone
630
+ // is fine (returns no modifier). (component audit C12.)
631
+ const toneClass = (component, map, tone) => {
632
+ if (tone == null) return '';
633
+ const hit = map[tone];
634
+ if (!hit && typeof console !== 'undefined') {
635
+ console.warn(
636
+ `[bronto] ui.${component}(): "${tone}" is not a ${component} tone (use one of: ${Object.keys(map).join(', ')}).`,
637
+ );
638
+ }
639
+ return hit || '';
640
+ };
641
+
642
+ const badgeTone = (tone) =>
643
+ toneClass(
644
+ 'badge',
645
+ {
646
+ accent: cls.badgeAccent,
647
+ success: cls.badgeSuccess,
648
+ warning: cls.badgeWarning,
649
+ danger: cls.badgeDanger,
650
+ info: cls.badgeInfo,
651
+ muted: cls.badgeMuted,
652
+ },
653
+ tone,
654
+ );
655
+
656
+ const numTone = (tone) =>
657
+ toneClass('num', { pos: cls.numPos, neg: cls.numNeg, muted: cls.numMuted }, tone);
658
+
659
+ const dotTone = (tone) =>
660
+ toneClass(
661
+ 'dot',
662
+ {
663
+ accent: cls.dotAccent,
664
+ success: cls.dotSuccess,
665
+ warning: cls.dotWarning,
666
+ danger: cls.dotDanger,
667
+ info: cls.dotInfo,
668
+ },
669
+ tone,
670
+ );
671
+
672
+ const alertTone = (tone) =>
673
+ toneClass(
674
+ 'alert',
675
+ {
676
+ accent: cls.alertAccent,
677
+ success: cls.alertSuccess,
678
+ warning: cls.alertWarning,
679
+ danger: cls.alertDanger,
680
+ info: cls.alertInfo,
681
+ },
682
+ tone,
683
+ );
684
+
685
+ const toastTone = (tone) =>
686
+ toneClass(
687
+ 'toast',
688
+ {
689
+ accent: cls.toastAccent,
690
+ success: cls.toastSuccess,
691
+ warning: cls.toastWarning,
692
+ danger: cls.toastDanger,
693
+ info: cls.toastInfo,
694
+ },
695
+ tone,
696
+ );
697
+
698
+ const meterTone = (tone) =>
699
+ toneClass(
700
+ 'meter',
701
+ {
702
+ accent: cls.meterAccent,
703
+ success: cls.meterSuccess,
704
+ warning: cls.meterWarning,
705
+ danger: cls.meterDanger,
706
+ info: cls.meterInfo,
707
+ },
708
+ tone,
709
+ );
554
710
 
555
711
  export const ui = {
556
712
  button: ({ variant, icon, size } = {}) =>
@@ -565,36 +721,20 @@ export const ui = {
565
721
  ),
566
722
  card: ({ accent, interactive } = {}) =>
567
723
  j(cls.card, accent && cls.cardAccent, interactive && cls.cardInteractive),
568
- badge: ({ tone, dot } = {}) =>
569
- j(
570
- cls.badge,
571
- tone === 'accent' && cls.badgeAccent,
572
- tone === 'success' && cls.badgeSuccess,
573
- tone === 'warning' && cls.badgeWarning,
574
- tone === 'danger' && cls.badgeDanger,
575
- tone === 'info' && cls.badgeInfo,
576
- tone === 'muted' && cls.badgeMuted,
577
- dot && cls.badgeDot,
578
- ),
579
- num: ({ tone } = {}) =>
724
+ badge: ({ tone, dot } = {}) => j(cls.badge, badgeTone(tone), dot && cls.badgeDot),
725
+ num: ({ tone } = {}) => j(cls.num, numTone(tone)),
726
+ delta: ({ dir, invert } = {}) =>
580
727
  j(
581
- cls.num,
582
- tone === 'pos' && cls.numPos,
583
- tone === 'neg' && cls.numNeg,
584
- tone === 'muted' && cls.numMuted,
728
+ cls.delta,
729
+ dir === 'up' && cls.deltaUp,
730
+ dir === 'down' && cls.deltaDown,
731
+ dir === 'flat' && cls.deltaFlat,
732
+ invert && cls.deltaInvert,
585
733
  ),
734
+ compare: ({ cols } = {}) => j(cls.compare, cols === 2 && cls.compare2up),
586
735
  chip: ({ accent } = {}) => j(cls.chip, accent && cls.chipAccent),
587
736
  link: ({ arrow, cta } = {}) => j(cls.link, arrow && cls.linkArrow, cta && cls.linkCta),
588
- dot: ({ tone, live } = {}) =>
589
- j(
590
- cls.dot,
591
- tone === 'accent' && cls.dotAccent,
592
- tone === 'success' && cls.dotSuccess,
593
- tone === 'warning' && cls.dotWarning,
594
- tone === 'danger' && cls.dotDanger,
595
- tone === 'info' && cls.dotInfo,
596
- live && cls.dotLive,
597
- ),
737
+ dot: ({ tone, live } = {}) => j(cls.dot, dotTone(tone), live && cls.dotLive),
598
738
  dotgrid: ({ accent, dense } = {}) =>
599
739
  j(cls.dotgrid, accent && cls.dotgridAccent, dense && cls.dotgridDense),
600
740
  table: ({ density, lined } = {}) =>
@@ -608,33 +748,10 @@ export const ui = {
608
748
  hint: ({ error } = {}) => j(cls.hint, error && cls.hintError),
609
749
  cluster: ({ between } = {}) => j(cls.cluster, between && cls.clusterBetween),
610
750
  stagger: ({ auto } = {}) => j(cls.stagger, auto && cls.staggerAuto),
611
- alert: ({ tone } = {}) =>
612
- j(
613
- cls.alert,
614
- tone === 'accent' && cls.alertAccent,
615
- tone === 'success' && cls.alertSuccess,
616
- tone === 'warning' && cls.alertWarning,
617
- tone === 'danger' && cls.alertDanger,
618
- tone === 'info' && cls.alertInfo,
619
- ),
620
- toast: ({ tone } = {}) =>
621
- j(
622
- cls.toast,
623
- tone === 'accent' && cls.toastAccent,
624
- tone === 'success' && cls.toastSuccess,
625
- tone === 'warning' && cls.toastWarning,
626
- tone === 'danger' && cls.toastDanger,
627
- tone === 'info' && cls.toastInfo,
628
- ),
751
+ alert: ({ tone } = {}) => j(cls.alert, alertTone(tone)),
752
+ toast: ({ tone } = {}) => j(cls.toast, toastTone(tone)),
629
753
  progress: ({ indeterminate } = {}) => j(cls.progress, indeterminate && cls.progressIndeterminate),
630
- meter: ({ tone } = {}) =>
631
- j(
632
- cls.meter,
633
- tone === 'accent' && cls.meterAccent,
634
- tone === 'success' && cls.meterSuccess,
635
- tone === 'warning' && cls.meterWarning,
636
- tone === 'danger' && cls.meterDanger,
637
- ),
754
+ meter: ({ tone } = {}) => j(cls.meter, meterTone(tone)),
638
755
  dotspinner: ({ size } = {}) =>
639
756
  j(cls.dotspinner, size === 'sm' && cls.dotspinnerSm, size === 'lg' && cls.dotspinnerLg),
640
757
  dotbar: ({ indeterminate } = {}) => j(cls.dotbar, indeterminate && cls.dotbarIndeterminate),
@@ -662,14 +779,9 @@ export const ui = {
662
779
  legendSwatch: ({ series, shape } = {}) =>
663
780
  j(
664
781
  cls.legendSwatch,
665
- series === 1 && cls.legendSwatch1,
666
- series === 2 && cls.legendSwatch2,
667
- series === 3 && cls.legendSwatch3,
668
- series === 4 && cls.legendSwatch4,
669
- series === 5 && cls.legendSwatch5,
670
- series === 6 && cls.legendSwatch6,
671
- series === 7 && cls.legendSwatch7,
672
- series === 8 && cls.legendSwatch8,
782
+ // Series 1–8 map to ui-legend__swatch--N; the explicit bounds-check keeps a
783
+ // 0/9/non-integer from coining a class the stylesheet never defines. (Q9.)
784
+ Number.isInteger(series) && series >= 1 && series <= 8 && cls[`legendSwatch${series}`],
673
785
  shape === 'circle' && cls.legendSwatchCircle,
674
786
  shape === 'line' && cls.legendSwatchLine,
675
787
  ),
@@ -721,6 +833,7 @@ export const ui = {
721
833
  j(
722
834
  cls.bracketNote,
723
835
  tone === 'accent' && cls.bracketNoteAccent,
836
+ tone === 'success' && cls.bracketNoteSuccess,
724
837
  tone === 'warning' && cls.bracketNoteWarning,
725
838
  tone === 'danger' && cls.bracketNoteDanger,
726
839
  tone === 'info' && cls.bracketNoteInfo,
@@ -749,8 +862,95 @@ export const ui = {
749
862
  citation: ({ chip, state } = {}) => j(cls.citation, chip && cls.citationChip, srcTone(state)),
750
863
  source: ({ state } = {}) => j(cls.sourceCard, srcTone(state)),
751
864
  provenance: ({ state } = {}) => j(cls.provenance, srcTone(state)),
865
+ diff: ({ split } = {}) => j(cls.diff, split && cls.diffSplit),
866
+ diffRow: ({ change } = {}) =>
867
+ j(
868
+ cls.diffRow,
869
+ change === 'add' && cls.diffRowAdd,
870
+ change === 'remove' && cls.diffRowRemove,
871
+ change === 'context' && cls.diffRowContext,
872
+ ),
873
+ code: ({ numbered } = {}) => j(cls.code, numbered && cls.codeNumbered),
874
+ codeLine: ({ change } = {}) =>
875
+ j(
876
+ cls.codeLine,
877
+ change === 'add' && cls.codeLineAdd,
878
+ change === 'remove' && cls.codeLineRemove,
879
+ change === 'hl' && cls.codeLineHl,
880
+ ),
881
+ sparkBar: ({ tone } = {}) =>
882
+ j(
883
+ cls.sparkBar,
884
+ tone === 'accent' && cls.sparkBarAccent,
885
+ tone === 'pos' && cls.sparkBarPos,
886
+ tone === 'neg' && cls.sparkBarNeg,
887
+ ),
888
+ bulletMeasure: ({ tone } = {}) =>
889
+ j(
890
+ cls.bulletMeasure,
891
+ tone === 'accent' && cls.bulletMeasureAccent,
892
+ tone === 'pos' && cls.bulletMeasurePos,
893
+ tone === 'neg' && cls.bulletMeasureNeg,
894
+ ),
752
895
  state: ({ state, busy } = {}) => j(cls.state, stateTone(state), busy && cls.stateBusy),
753
896
  originLabel: ({ ai } = {}) => j(cls.originLabel, ai && cls.originLabelAi),
754
897
  };
755
898
 
899
+ // Attribute + style bundle for the data-bearing fills (`ui-meter`/`ui-progress`).
900
+ // The class string alone paints a 0-width, unannounced bar: the fill width is a
901
+ // UNITLESS `--value` (0–100) and AT needs role + aria-valuenow/min/max. This sets
902
+ // the painted value and its announced value together so they can't drift, and
903
+ // normalizes an arbitrary {min,max} to the 0–100 `--value` the CSS expects while
904
+ // keeping aria-valuenow in the caller's real units. (component audit C8.)
905
+ // `busyWhenIndeterminate` — a progressbar advertises aria-busy when its value is
906
+ // unknown; a meter is never indeterminate so it passes false. (Kept a boolean
907
+ // flag rather than testing the role string, so check:recipe-types doesn't read it
908
+ // as a recipe option literal.)
909
+ const valueAttrs = (role, value, min, max, busyWhenIndeterminate) => {
910
+ const lo = Number(min);
911
+ const hi = Number(max);
912
+ const raw = Number(value);
913
+ // Indeterminate: an omitted/unknown value (attrs.progress() with no argument).
914
+ // ARIA requires aria-valuenow be OMITTED here — emitting 0 announces "0%",
915
+ // indistinguishable from a real stalled-at-zero bar. A progressbar instead
916
+ // advertises aria-busy; a meter has no indeterminate state, so a non-finite
917
+ // value there is a caller error we still fail safe on by omitting the
918
+ // misleading 0. Pair with `ui.progress({ indeterminate: true })` for the CSS
919
+ // sweep. (component audit C9.)
920
+ if (!Number.isFinite(raw)) {
921
+ return busyWhenIndeterminate ? { role, 'aria-busy': 'true' } : { role };
922
+ }
923
+ const now = Math.min(hi, Math.max(lo, raw));
924
+ const pct = hi > lo ? ((now - lo) / (hi - lo)) * 100 : 0;
925
+ return {
926
+ role,
927
+ 'aria-valuenow': now,
928
+ 'aria-valuemin': lo,
929
+ 'aria-valuemax': hi,
930
+ style: { '--value': Math.round(pct * 100) / 100 },
931
+ };
932
+ };
933
+
934
+ /**
935
+ * ARIA + style bundles for the value-bearing fills. Spread onto the host:
936
+ * <div class={ui.meter({ tone: 'warning' })} {...attrs.meter(72)}>
937
+ * <span class={cls.meterFill} />
938
+ * </div>
939
+ * `value` is in your own units; pass `{ min, max }` (default 0–100) and the
940
+ * `--value` width is normalized for you. Call `attrs.progress()` with no value
941
+ * for an indeterminate bar (omits aria-valuenow, sets aria-busy). (audit C9.)
942
+ *
943
+ * `attrs.dotbar(value)` is the segmented analogue of `attrs.progress`: a
944
+ * determinate `.ui-dotbar` carries the same progress data as `.ui-progress` but,
945
+ * without this, was eight empty `<span>`s to AT (the segments are decorative —
946
+ * mark them `aria-hidden`). Same progressbar role + aria-valuenow/min/max;
947
+ * call with no value for the indeterminate sweep. (component audit C10.)
948
+ */
949
+ export const attrs = Object.freeze({
950
+ meter: (value, { min = 0, max = 100 } = {}) => valueAttrs('meter', value, min, max, false),
951
+ progress: (value, { min = 0, max = 100 } = {}) =>
952
+ valueAttrs('progressbar', value, min, max, true),
953
+ dotbar: (value, { min = 0, max = 100 } = {}) => valueAttrs('progressbar', value, min, max, true),
954
+ });
955
+
756
956
  export default ui;
@@ -141,6 +141,14 @@
141
141
  "name": "--display",
142
142
  "description": "Global scale token. Value: `var(--dot-font)`"
143
143
  },
144
+ {
145
+ "name": "--display-weight",
146
+ "description": "Global scale token. Value: `700`"
147
+ },
148
+ {
149
+ "name": "--display-weight-strong",
150
+ "description": "Global scale token. Value: `800`"
151
+ },
144
152
  {
145
153
  "name": "--dot-font",
146
154
  "description": "Global scale token. Value: `'Doto', var(--mono)`"
@@ -213,6 +221,10 @@
213
221
  "name": "--mono",
214
222
  "description": "Global scale token. Value: `'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace`"
215
223
  },
224
+ {
225
+ "name": "--on-accent",
226
+ "description": "Theme token. Light: `var(--button-text)` · Dark: `var(--button-text)`"
227
+ },
216
228
  {
217
229
  "name": "--panel",
218
230
  "description": "Theme token. Light: `#ffffff` · Dark: `#1c1c1c`"