@ponchia/ui 0.6.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 (156) hide show
  1. package/CHANGELOG.md +64 -4
  2. package/README.md +1 -1
  3. package/annotations/index.d.ts.map +1 -1
  4. package/annotations/index.js +36 -33
  5. package/behaviors/carousel.d.ts +28 -0
  6. package/behaviors/carousel.d.ts.map +1 -0
  7. package/behaviors/carousel.js +3 -0
  8. package/behaviors/combobox.d.ts +40 -0
  9. package/behaviors/combobox.d.ts.map +1 -0
  10. package/behaviors/combobox.js +71 -20
  11. package/behaviors/command.d.ts +41 -0
  12. package/behaviors/command.d.ts.map +1 -0
  13. package/behaviors/command.js +9 -0
  14. package/behaviors/connectors.d.ts +17 -0
  15. package/behaviors/connectors.d.ts.map +1 -0
  16. package/behaviors/connectors.js +3 -0
  17. package/behaviors/crosshair.d.ts +42 -0
  18. package/behaviors/crosshair.d.ts.map +1 -0
  19. package/behaviors/crosshair.js +19 -1
  20. package/behaviors/dialog.d.ts +20 -0
  21. package/behaviors/dialog.d.ts.map +1 -0
  22. package/behaviors/dialog.js +3 -0
  23. package/behaviors/disclosure.d.ts +10 -0
  24. package/behaviors/disclosure.d.ts.map +1 -0
  25. package/behaviors/disclosure.js +3 -0
  26. package/behaviors/dismissible.d.ts +10 -0
  27. package/behaviors/dismissible.d.ts.map +1 -0
  28. package/behaviors/dismissible.js +3 -0
  29. package/behaviors/forms.d.ts +27 -0
  30. package/behaviors/forms.d.ts.map +1 -0
  31. package/behaviors/forms.js +18 -5
  32. package/behaviors/glyph.d.ts +14 -0
  33. package/behaviors/glyph.d.ts.map +1 -0
  34. package/behaviors/glyph.js +24 -0
  35. package/behaviors/index.d.ts +31 -237
  36. package/behaviors/index.d.ts.map +1 -0
  37. package/behaviors/index.js +17 -0
  38. package/behaviors/inert.d.ts +20 -0
  39. package/behaviors/inert.d.ts.map +1 -0
  40. package/behaviors/inert.js +46 -0
  41. package/behaviors/internal.d.ts +25 -0
  42. package/behaviors/internal.d.ts.map +1 -0
  43. package/behaviors/internal.js +30 -1
  44. package/behaviors/legend.d.ts +35 -0
  45. package/behaviors/legend.d.ts.map +1 -0
  46. package/behaviors/legend.js +9 -0
  47. package/behaviors/menu.d.ts +16 -0
  48. package/behaviors/menu.d.ts.map +1 -0
  49. package/behaviors/menu.js +3 -0
  50. package/behaviors/modal.d.ts +41 -0
  51. package/behaviors/modal.d.ts.map +1 -0
  52. package/behaviors/modal.js +124 -0
  53. package/behaviors/popover.d.ts +28 -0
  54. package/behaviors/popover.d.ts.map +1 -0
  55. package/behaviors/popover.js +17 -17
  56. package/behaviors/spotlight.d.ts +17 -0
  57. package/behaviors/spotlight.d.ts.map +1 -0
  58. package/behaviors/spotlight.js +3 -0
  59. package/behaviors/table.d.ts +36 -0
  60. package/behaviors/table.d.ts.map +1 -0
  61. package/behaviors/table.js +48 -8
  62. package/behaviors/tabs.d.ts +20 -0
  63. package/behaviors/tabs.d.ts.map +1 -0
  64. package/behaviors/tabs.js +3 -0
  65. package/behaviors/theme.d.ts +54 -0
  66. package/behaviors/theme.d.ts.map +1 -0
  67. package/behaviors/theme.js +17 -0
  68. package/behaviors/toast.d.ts +49 -0
  69. package/behaviors/toast.d.ts.map +1 -0
  70. package/behaviors/toast.js +34 -2
  71. package/classes/classes.json +683 -13
  72. package/classes/index.d.ts +106 -2
  73. package/classes/index.js +249 -65
  74. package/connectors/index.d.ts +12 -0
  75. package/connectors/index.d.ts.map +1 -1
  76. package/connectors/index.js +23 -2
  77. package/css/app.css +26 -0
  78. package/css/bullet.css +108 -0
  79. package/css/code.css +98 -0
  80. package/css/content.css +15 -2
  81. package/css/crosshair.css +7 -7
  82. package/css/diff.css +153 -0
  83. package/css/disclosure.css +18 -4
  84. package/css/dots.css +37 -7
  85. package/css/feedback.css +39 -7
  86. package/css/forms.css +71 -3
  87. package/css/legend.css +5 -2
  88. package/css/motion.css +79 -14
  89. package/css/overlay.css +59 -2
  90. package/css/primitives.css +67 -8
  91. package/css/report.css +40 -0
  92. package/css/sidenote.css +67 -0
  93. package/css/spark.css +62 -0
  94. package/css/table.css +9 -2
  95. package/css/term.css +110 -0
  96. package/css/textref.css +63 -0
  97. package/css/toc.css +91 -0
  98. package/css/tokens.css +14 -1
  99. package/css/tree.css +134 -0
  100. package/dist/bronto.css +1 -1
  101. package/dist/css/analytical.css +1 -1
  102. package/dist/css/app.css +1 -1
  103. package/dist/css/bullet.css +1 -0
  104. package/dist/css/code.css +1 -0
  105. package/dist/css/content.css +1 -1
  106. package/dist/css/crosshair.css +1 -1
  107. package/dist/css/diff.css +1 -0
  108. package/dist/css/disclosure.css +1 -1
  109. package/dist/css/dots.css +1 -1
  110. package/dist/css/feedback.css +1 -1
  111. package/dist/css/forms.css +1 -1
  112. package/dist/css/legend.css +1 -1
  113. package/dist/css/motion.css +1 -1
  114. package/dist/css/overlay.css +1 -1
  115. package/dist/css/primitives.css +1 -1
  116. package/dist/css/report.css +1 -1
  117. package/dist/css/sidenote.css +1 -0
  118. package/dist/css/spark.css +1 -0
  119. package/dist/css/table.css +1 -1
  120. package/dist/css/term.css +1 -0
  121. package/dist/css/textref.css +1 -0
  122. package/dist/css/toc.css +1 -0
  123. package/dist/css/tokens.css +1 -1
  124. package/dist/css/tree.css +1 -0
  125. package/docs/annotations.md +39 -0
  126. package/docs/architecture.md +2 -3
  127. package/docs/bullet.md +78 -0
  128. package/docs/code.md +76 -0
  129. package/docs/d2.md +4 -3
  130. package/docs/diff.md +146 -0
  131. package/docs/legends.md +8 -4
  132. package/docs/mermaid.md +21 -4
  133. package/docs/reference.md +127 -8
  134. package/docs/reporting.md +35 -14
  135. package/docs/sidenote.md +64 -0
  136. package/docs/spark.md +78 -0
  137. package/docs/stability.md +1 -0
  138. package/docs/term.md +81 -0
  139. package/docs/textref.md +78 -0
  140. package/docs/theming.md +44 -5
  141. package/docs/toc.md +83 -0
  142. package/docs/tree.md +74 -0
  143. package/docs/usage.md +264 -23
  144. package/docs/vega.md +22 -3
  145. package/glyphs/glyphs.js +7 -1
  146. package/llms.txt +159 -13
  147. package/package.json +47 -7
  148. package/qwik/index.d.ts +4 -2
  149. package/qwik/index.d.ts.map +1 -1
  150. package/qwik/index.js +10 -0
  151. package/react/index.d.ts +4 -2
  152. package/react/index.d.ts.map +1 -1
  153. package/react/index.js +6 -0
  154. package/solid/index.d.ts +6 -2
  155. package/solid/index.d.ts.map +1 -1
  156. package/solid/index.js +6 -0
@@ -104,7 +104,7 @@ export declare const cls: {
104
104
  readonly alert: 'ui-alert';
105
105
  readonly alertTitle: 'ui-alert__title';
106
106
  readonly alertBody: 'ui-alert__body';
107
- readonly alertDismiss: 'ui-alert__dismiss';
107
+ readonly alertClose: 'ui-alert__close';
108
108
  readonly alertAccent: 'ui-alert--accent';
109
109
  readonly alertSuccess: 'ui-alert--success';
110
110
  readonly alertWarning: 'ui-alert--warning';
@@ -128,6 +128,9 @@ export declare const cls: {
128
128
  readonly progressIndeterminate: 'ui-progress--indeterminate';
129
129
  readonly meter: 'ui-meter';
130
130
  readonly meterFill: 'ui-meter__fill';
131
+ readonly meterRow: 'ui-meter__row';
132
+ readonly meterLabel: 'ui-meter__label';
133
+ readonly meterValue: 'ui-meter__value';
131
134
  readonly meterAccent: 'ui-meter--accent';
132
135
  readonly meterSuccess: 'ui-meter--success';
133
136
  readonly meterWarning: 'ui-meter--warning';
@@ -187,12 +190,12 @@ export declare const cls: {
187
190
  readonly tableComfortable: 'ui-table--comfortable';
188
191
  readonly tableLined: 'ui-table--lined';
189
192
  readonly tableWrap: 'ui-table-wrap';
193
+ readonly tableLoading: 'ui-table-wrap--loading';
190
194
  readonly tableEmpty: 'ui-table__empty';
191
195
  readonly tableSort: 'ui-table__sort';
192
196
  readonly tableSelect: 'ui-table__select';
193
197
  readonly tableToolbar: 'ui-table__toolbar';
194
198
  readonly tableSelectable: 'ui-table--selectable';
195
- readonly tableLoading: 'ui-table--loading';
196
199
  readonly panel: 'ui-panel';
197
200
  readonly panelHead: 'ui-panel__head';
198
201
  readonly surface: 'ui-surface';
@@ -393,6 +396,55 @@ export declare const cls: {
393
396
  readonly srcReviewed: 'ui-src--reviewed';
394
397
  readonly srcStale: 'ui-src--stale';
395
398
  readonly srcConflict: 'ui-src--conflict';
399
+ readonly diff: 'ui-diff';
400
+ readonly diffSplit: 'ui-diff--split';
401
+ readonly diffPane: 'ui-diff__pane';
402
+ readonly diffHunk: 'ui-diff__hunk';
403
+ readonly diffHead: 'ui-diff__head';
404
+ readonly diffRow: 'ui-diff__row';
405
+ readonly diffRowAdd: 'ui-diff__row--add';
406
+ readonly diffRowRemove: 'ui-diff__row--remove';
407
+ readonly diffRowContext: 'ui-diff__row--context';
408
+ readonly diffLn: 'ui-diff__ln';
409
+ readonly diffCode: 'ui-diff__code';
410
+ readonly code: 'ui-code';
411
+ readonly codeNumbered: 'ui-code--numbered';
412
+ readonly codeHead: 'ui-code__head';
413
+ readonly codeBody: 'ui-code__body';
414
+ readonly codeLine: 'ui-code__line';
415
+ readonly codeLineAdd: 'ui-code__line--add';
416
+ readonly codeLineRemove: 'ui-code__line--remove';
417
+ readonly codeLineHl: 'ui-code__line--hl';
418
+ readonly spark: 'ui-spark';
419
+ readonly sparkBar: 'ui-spark__bar';
420
+ readonly sparkBarAccent: 'ui-spark__bar--accent';
421
+ readonly sparkBarPos: 'ui-spark__bar--pos';
422
+ readonly sparkBarNeg: 'ui-spark__bar--neg';
423
+ readonly sidenote: 'ui-sidenote';
424
+ readonly marginnote: 'ui-marginnote';
425
+ readonly sidenoteRef: 'ui-sidenote__ref';
426
+ readonly textref: 'ui-textref';
427
+ readonly bullet: 'ui-bullet';
428
+ readonly bulletMeasure: 'ui-bullet__measure';
429
+ readonly bulletMeasureAccent: 'ui-bullet__measure--accent';
430
+ readonly bulletMeasurePos: 'ui-bullet__measure--pos';
431
+ readonly bulletMeasureNeg: 'ui-bullet__measure--neg';
432
+ readonly bulletTarget: 'ui-bullet__target';
433
+ readonly bulletLabel: 'ui-bullet__label';
434
+ readonly term: 'ui-term';
435
+ readonly def: 'ui-def';
436
+ readonly glossary: 'ui-glossary';
437
+ readonly glossaryTerm: 'ui-glossary__term';
438
+ readonly glossaryDef: 'ui-glossary__def';
439
+ readonly toc: 'ui-toc';
440
+ readonly tocTitle: 'ui-toc__title';
441
+ readonly tocList: 'ui-toc__list';
442
+ readonly tocLink: 'ui-toc__link';
443
+ readonly tree: 'ui-tree';
444
+ readonly treeBranch: 'ui-tree__branch';
445
+ readonly treeLeaf: 'ui-tree__leaf';
446
+ readonly treeSummary: 'ui-tree__summary';
447
+ readonly treeLabel: 'ui-tree__label';
396
448
  readonly state: 'ui-state';
397
449
  readonly stateLabel: 'ui-state__label';
398
450
  readonly stateDetail: 'ui-state__detail';
@@ -690,6 +742,32 @@ export interface OriginLabelOpts {
690
742
  /** Accent-tint the label for AI/model-generated origin (vs a neutral tag). */
691
743
  ai?: boolean;
692
744
  }
745
+ export interface DiffOpts {
746
+ /** Two side-by-side `.ui-diff__pane` columns (old | new) instead of the unified view. */
747
+ split?: boolean;
748
+ }
749
+ export interface DiffRowOpts {
750
+ /** The host-classified change kind — sets the tint and the +/− gutter glyph. */
751
+ change?: 'add' | 'remove' | 'context';
752
+ }
753
+ export interface CodeOpts {
754
+ /** Show the line-number gutter (counts each `.ui-code__line`). */
755
+ numbered?: boolean;
756
+ }
757
+ export interface CodeLineOpts {
758
+ /** The host-classified line state — `hl` is a neutral highlight, not a change.
759
+ * `remove` matches `ui.diffRow`'s verb (was `del`) so the two change-review
760
+ * surfaces share one vocabulary. */
761
+ change?: 'add' | 'remove' | 'hl';
762
+ }
763
+ export interface SparkBarOpts {
764
+ /** Emphasise / tone a single bar. The meaning must still be in the spark's aria-label. */
765
+ tone?: 'accent' | 'pos' | 'neg';
766
+ }
767
+ export interface BulletMeasureOpts {
768
+ /** Emphasise / tone the measure bar. The meaning must still be in the bullet's aria-label. */
769
+ tone?: 'accent' | 'pos' | 'neg';
770
+ }
693
771
 
694
772
  export interface Ui {
695
773
  button(opts?: ButtonOpts): string;
@@ -733,9 +811,35 @@ export interface Ui {
733
811
  citation(opts?: CitationOpts): string;
734
812
  source(opts?: SourceOpts): string;
735
813
  provenance(opts?: ProvenanceOpts): string;
814
+ diff(opts?: DiffOpts): string;
815
+ diffRow(opts?: DiffRowOpts): string;
816
+ code(opts?: CodeOpts): string;
817
+ codeLine(opts?: CodeLineOpts): string;
818
+ sparkBar(opts?: SparkBarOpts): string;
819
+ bulletMeasure(opts?: BulletMeasureOpts): string;
736
820
  state(opts?: StateOpts): string;
737
821
  originLabel(opts?: OriginLabelOpts): string;
738
822
  }
739
823
 
740
824
  export declare const ui: Ui;
741
825
  export default ui;
826
+
827
+ /** Min/max for the value-bearing fills; defaults to 0–100. */
828
+ export interface ValueRangeOpts {
829
+ min?: number;
830
+ max?: number;
831
+ }
832
+ /** ARIA + style bundle to spread onto a `ui-meter`/`ui-progress` host. */
833
+ export interface ValueAttrs {
834
+ role: 'meter' | 'progressbar';
835
+ 'aria-valuenow': number;
836
+ 'aria-valuemin': number;
837
+ 'aria-valuemax': number;
838
+ style: { '--value': number };
839
+ }
840
+ export interface Attrs {
841
+ meter(value: number, opts?: ValueRangeOpts): ValueAttrs;
842
+ progress(value: number, opts?: ValueRangeOpts): ValueAttrs;
843
+ }
844
+ /** Set the painted value AND its ARIA together so they cannot drift. */
845
+ export declare const attrs: Attrs;
package/classes/index.js CHANGED
@@ -111,7 +111,7 @@ export const cls = Object.freeze({
111
111
  alert: 'ui-alert',
112
112
  alertTitle: 'ui-alert__title',
113
113
  alertBody: 'ui-alert__body',
114
- alertDismiss: 'ui-alert__dismiss',
114
+ alertClose: 'ui-alert__close',
115
115
  alertAccent: 'ui-alert--accent',
116
116
  alertSuccess: 'ui-alert--success',
117
117
  alertWarning: 'ui-alert--warning',
@@ -135,6 +135,9 @@ export const cls = Object.freeze({
135
135
  progressIndeterminate: 'ui-progress--indeterminate',
136
136
  meter: 'ui-meter',
137
137
  meterFill: 'ui-meter__fill',
138
+ meterRow: 'ui-meter__row',
139
+ meterLabel: 'ui-meter__label',
140
+ meterValue: 'ui-meter__value',
138
141
  meterAccent: 'ui-meter--accent',
139
142
  meterSuccess: 'ui-meter--success',
140
143
  meterWarning: 'ui-meter--warning',
@@ -197,12 +200,13 @@ export const cls = Object.freeze({
197
200
  tableComfortable: 'ui-table--comfortable',
198
201
  tableLined: 'ui-table--lined',
199
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',
200
205
  tableEmpty: 'ui-table__empty',
201
206
  tableSort: 'ui-table__sort',
202
207
  tableSelect: 'ui-table__select',
203
208
  tableToolbar: 'ui-table__toolbar',
204
209
  tableSelectable: 'ui-table--selectable',
205
- tableLoading: 'ui-table--loading',
206
210
  // shell / layout
207
211
  panel: 'ui-panel',
208
212
  panelHead: 'ui-panel__head',
@@ -414,6 +418,64 @@ export const cls = Object.freeze({
414
418
  srcReviewed: 'ui-src--reviewed',
415
419
  srcStale: 'ui-src--stale',
416
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',
417
479
  // lifecycle / system state (css/state.css)
418
480
  state: 'ui-state',
419
481
  stateLabel: 'ui-state__label',
@@ -557,6 +619,95 @@ const srcTone = (state) =>
557
619
  conflict: cls.srcConflict,
558
620
  })[state] || '';
559
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
+ );
710
+
560
711
  export const ui = {
561
712
  button: ({ variant, icon, size } = {}) =>
562
713
  j(
@@ -570,24 +721,8 @@ export const ui = {
570
721
  ),
571
722
  card: ({ accent, interactive } = {}) =>
572
723
  j(cls.card, accent && cls.cardAccent, interactive && cls.cardInteractive),
573
- badge: ({ tone, dot } = {}) =>
574
- j(
575
- cls.badge,
576
- tone === 'accent' && cls.badgeAccent,
577
- tone === 'success' && cls.badgeSuccess,
578
- tone === 'warning' && cls.badgeWarning,
579
- tone === 'danger' && cls.badgeDanger,
580
- tone === 'info' && cls.badgeInfo,
581
- tone === 'muted' && cls.badgeMuted,
582
- dot && cls.badgeDot,
583
- ),
584
- num: ({ tone } = {}) =>
585
- j(
586
- cls.num,
587
- tone === 'pos' && cls.numPos,
588
- tone === 'neg' && cls.numNeg,
589
- tone === 'muted' && cls.numMuted,
590
- ),
724
+ badge: ({ tone, dot } = {}) => j(cls.badge, badgeTone(tone), dot && cls.badgeDot),
725
+ num: ({ tone } = {}) => j(cls.num, numTone(tone)),
591
726
  delta: ({ dir, invert } = {}) =>
592
727
  j(
593
728
  cls.delta,
@@ -599,16 +734,7 @@ export const ui = {
599
734
  compare: ({ cols } = {}) => j(cls.compare, cols === 2 && cls.compare2up),
600
735
  chip: ({ accent } = {}) => j(cls.chip, accent && cls.chipAccent),
601
736
  link: ({ arrow, cta } = {}) => j(cls.link, arrow && cls.linkArrow, cta && cls.linkCta),
602
- dot: ({ tone, live } = {}) =>
603
- j(
604
- cls.dot,
605
- tone === 'accent' && cls.dotAccent,
606
- tone === 'success' && cls.dotSuccess,
607
- tone === 'warning' && cls.dotWarning,
608
- tone === 'danger' && cls.dotDanger,
609
- tone === 'info' && cls.dotInfo,
610
- live && cls.dotLive,
611
- ),
737
+ dot: ({ tone, live } = {}) => j(cls.dot, dotTone(tone), live && cls.dotLive),
612
738
  dotgrid: ({ accent, dense } = {}) =>
613
739
  j(cls.dotgrid, accent && cls.dotgridAccent, dense && cls.dotgridDense),
614
740
  table: ({ density, lined } = {}) =>
@@ -622,34 +748,10 @@ export const ui = {
622
748
  hint: ({ error } = {}) => j(cls.hint, error && cls.hintError),
623
749
  cluster: ({ between } = {}) => j(cls.cluster, between && cls.clusterBetween),
624
750
  stagger: ({ auto } = {}) => j(cls.stagger, auto && cls.staggerAuto),
625
- alert: ({ tone } = {}) =>
626
- j(
627
- cls.alert,
628
- tone === 'accent' && cls.alertAccent,
629
- tone === 'success' && cls.alertSuccess,
630
- tone === 'warning' && cls.alertWarning,
631
- tone === 'danger' && cls.alertDanger,
632
- tone === 'info' && cls.alertInfo,
633
- ),
634
- toast: ({ tone } = {}) =>
635
- j(
636
- cls.toast,
637
- tone === 'accent' && cls.toastAccent,
638
- tone === 'success' && cls.toastSuccess,
639
- tone === 'warning' && cls.toastWarning,
640
- tone === 'danger' && cls.toastDanger,
641
- tone === 'info' && cls.toastInfo,
642
- ),
751
+ alert: ({ tone } = {}) => j(cls.alert, alertTone(tone)),
752
+ toast: ({ tone } = {}) => j(cls.toast, toastTone(tone)),
643
753
  progress: ({ indeterminate } = {}) => j(cls.progress, indeterminate && cls.progressIndeterminate),
644
- meter: ({ tone } = {}) =>
645
- j(
646
- cls.meter,
647
- tone === 'accent' && cls.meterAccent,
648
- tone === 'success' && cls.meterSuccess,
649
- tone === 'warning' && cls.meterWarning,
650
- tone === 'danger' && cls.meterDanger,
651
- tone === 'info' && cls.meterInfo,
652
- ),
754
+ meter: ({ tone } = {}) => j(cls.meter, meterTone(tone)),
653
755
  dotspinner: ({ size } = {}) =>
654
756
  j(cls.dotspinner, size === 'sm' && cls.dotspinnerSm, size === 'lg' && cls.dotspinnerLg),
655
757
  dotbar: ({ indeterminate } = {}) => j(cls.dotbar, indeterminate && cls.dotbarIndeterminate),
@@ -677,14 +779,9 @@ export const ui = {
677
779
  legendSwatch: ({ series, shape } = {}) =>
678
780
  j(
679
781
  cls.legendSwatch,
680
- series === 1 && cls.legendSwatch1,
681
- series === 2 && cls.legendSwatch2,
682
- series === 3 && cls.legendSwatch3,
683
- series === 4 && cls.legendSwatch4,
684
- series === 5 && cls.legendSwatch5,
685
- series === 6 && cls.legendSwatch6,
686
- series === 7 && cls.legendSwatch7,
687
- 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}`],
688
785
  shape === 'circle' && cls.legendSwatchCircle,
689
786
  shape === 'line' && cls.legendSwatchLine,
690
787
  ),
@@ -765,8 +862,95 @@ export const ui = {
765
862
  citation: ({ chip, state } = {}) => j(cls.citation, chip && cls.citationChip, srcTone(state)),
766
863
  source: ({ state } = {}) => j(cls.sourceCard, srcTone(state)),
767
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
+ ),
768
895
  state: ({ state, busy } = {}) => j(cls.state, stateTone(state), busy && cls.stateBusy),
769
896
  originLabel: ({ ai } = {}) => j(cls.originLabel, ai && cls.originLabelAi),
770
897
  };
771
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
+
772
956
  export default ui;
@@ -1,5 +1,6 @@
1
1
  export function finite(name: any, value: any, fallback: any): any;
2
2
  export function dimension(name: any, value: any, fallback: any): any;
3
+ export function roundNumber(value: any): number;
3
4
  export function fmt(value: any): string;
4
5
  export function point(x: any, y: any): string;
5
6
  export function clamp(value: any, min: any, max: any): any;
@@ -67,6 +68,17 @@ export function arrowHead(p: Point, angle: number, size?: number, spread?: numbe
67
68
  * @returns {string}
68
69
  */
69
70
  export function dotMark(p: Point, radius?: number): string;
71
+ /**
72
+ * An axis-aligned rectangle path from its corners (callers derive the corners
73
+ * from a centre or a top-left as they need). Shared by the annotation
74
+ * rect/band and evidence-marker subjects. (code-quality audit Q5.)
75
+ * @param {number} left
76
+ * @param {number} top
77
+ * @param {number} right
78
+ * @param {number} bottom
79
+ * @returns {string}
80
+ */
81
+ export function rectPath(left: number, top: number, right: number, bottom: number): string;
70
82
  /**
71
83
  * Pick facing edges from the rects' relative centres.
72
84
  * @param {Rect} fromRect
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"AAkDA,kEAIC;AAED,qEAIC;AAED,wCAGC;AAED,8CAEC;AAID,2DAGC;AAED;;;;;GAKG;AACH,kCAJW,IAAI,SACJ,IAAI,GACF,KAAK,CAoBjB;AAED;;;;;GAKG;AACH,mCAJW,KAAK,MACL,KAAK,GACH,MAAM,CAOlB;AAED;;;;;GAKG;AACH,mCAJW,KAAK,MACL,KAAK,GACH,MAAM,CAOlB;AAED;;;;;;GAMG;AACH,gCALW,KAAK,MACL,KAAK,SACL;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACd,MAAM,CAgBlB;AAED;;;;;;GAMG;AACH,gCALW,KAAK,MACL,KAAK,SACL;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACpB,MAAM,CAclB;AAED;;;;GAIG;AACH,qCAHW,oBAAoB,GAClB,MAAM,CAOlB;AAED;;;;;;;;GAQG;AACH,6BAPW,KAAK,SACL,MAAM,SACN,MAAM,WACN,MAAM,GAEJ,MAAM,CAalB;AAED;;;;;GAKG;AACH,2BAJW,KAAK,WACL,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;GAKG;AACH,oCAJW,IAAI,UACJ,IAAI,GACF;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,IAAI,CAAA;CAAE,CAWpC;AAED;;;;;;;;GAQG;AACH,sCALW,KAAK,MACL,KAAK,UACL,cAAc,GACZ,MAAM,CAQlB;AAED;;;;;;GAMG;AACH,oCAHW,mBAAmB,GACjB,kBAAkB,CAW9B;AAlRD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAMH,wBAAyB,IAAI,CAAC;oBAhCjB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;mBACxB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;mBACvD,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ;6BAC9C,UAAU,GAAG,OAAO,GAAG,OAAO;;UAG7B,KAAK;QACL,KAAK;;;;;;;;;;;;cAML,IAAI;YACJ,IAAI;;;;;;;;;;;;;;OAQJ,MAAM;UACN,KAAK;QACL,KAAK;;;;WACL,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"AAkDA,kEAIC;AAED,qEAIC;AAKD,gDAGC;AAED,wCAEC;AAED,8CAEC;AAID,2DAGC;AAED;;;;;GAKG;AACH,kCAJW,IAAI,SACJ,IAAI,GACF,KAAK,CAoBjB;AAED;;;;;GAKG;AACH,mCAJW,KAAK,MACL,KAAK,GACH,MAAM,CAOlB;AAED;;;;;GAKG;AACH,mCAJW,KAAK,MACL,KAAK,GACH,MAAM,CAOlB;AAED;;;;;;GAMG;AACH,gCALW,KAAK,MACL,KAAK,SACL;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACd,MAAM,CAgBlB;AAED;;;;;;GAMG;AACH,gCALW,KAAK,MACL,KAAK,SACL;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACpB,MAAM,CAclB;AAED;;;;GAIG;AACH,qCAHW,oBAAoB,GAClB,MAAM,CAOlB;AAED;;;;;;;;GAQG;AACH,6BAPW,KAAK,SACL,MAAM,SACN,MAAM,WACN,MAAM,GAEJ,MAAM,CAalB;AAED;;;;;GAKG;AACH,2BAJW,KAAK,WACL,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;GASG;AACH,+BANW,MAAM,OACN,MAAM,SACN,MAAM,UACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,oCAJW,IAAI,UACJ,IAAI,GACF;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,IAAI,CAAA;CAAE,CAWpC;AAED;;;;;;;;GAQG;AACH,sCALW,KAAK,MACL,KAAK,UACL,cAAc,GACZ,MAAM,CAQlB;AAED;;;;;;GAMG;AACH,oCAHW,mBAAmB,GACjB,kBAAkB,CAW9B;AAvSD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAMH,wBAAyB,IAAI,CAAC;oBAhCjB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;mBACxB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;mBACvD,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ;6BAC9C,UAAU,GAAG,OAAO,GAAG,OAAO;;UAG7B,KAAK;QACL,KAAK;;;;;;;;;;;;cAML,IAAI;YACJ,IAAI;;;;;;;;;;;;;;OAQJ,MAAM;UACN,KAAK;QACL,KAAK;;;;WACL,MAAM"}
@@ -60,9 +60,16 @@ export function dimension(name, value, fallback) {
60
60
  return v;
61
61
  }
62
62
 
63
- export function fmt(value) {
63
+ // Round to PRECISION, normalising -0 → 0, and return the NUMBER (the numeric
64
+ // core `fmt` stringifies). Shared with the annotations layer for the rounded
65
+ // coordinates it echoes back to the host. (code-quality audit Q5.)
66
+ export function roundNumber(value) {
64
67
  const rounded = Math.round((Object.is(value, -0) ? 0 : value) * PRECISION) / PRECISION;
65
- return String(Object.is(rounded, -0) ? 0 : rounded);
68
+ return Object.is(rounded, -0) ? 0 : rounded;
69
+ }
70
+
71
+ export function fmt(value) {
72
+ return String(roundNumber(value));
66
73
  }
67
74
 
68
75
  export function point(x, y) {
@@ -222,6 +229,20 @@ export function dotMark(p, radius = 3) {
222
229
  )} 0 1 1 ${point(px, py - r)}Z`;
223
230
  }
224
231
 
232
+ /**
233
+ * An axis-aligned rectangle path from its corners (callers derive the corners
234
+ * from a centre or a top-left as they need). Shared by the annotation
235
+ * rect/band and evidence-marker subjects. (code-quality audit Q5.)
236
+ * @param {number} left
237
+ * @param {number} top
238
+ * @param {number} right
239
+ * @param {number} bottom
240
+ * @returns {string}
241
+ */
242
+ export function rectPath(left, top, right, bottom) {
243
+ return `M${point(left, top)}H${fmt(right)}V${fmt(bottom)}H${fmt(left)}Z`;
244
+ }
245
+
225
246
  /**
226
247
  * Pick facing edges from the rects' relative centres.
227
248
  * @param {Rect} fromRect
package/css/app.css CHANGED
@@ -118,6 +118,25 @@
118
118
  opacity: 1;
119
119
  }
120
120
 
121
+ /* Forced colours flatten var(--accent) (border + bg + text) to a single system
122
+ colour, so the active link collapses into its inactive siblings — only a
123
+ near-imperceptible tint/dot opacity delta survives, and current-page becomes
124
+ invisible to HCM users. Re-assert "current" on channels HCM preserves: a
125
+ Highlight start-border and marker dot, plus a NON-colour bold weight so the
126
+ cue does not rely on colour alone (WCAG 1.4.1). (component audit C8.) */
127
+ @media (forced-colors: active) {
128
+ .ui-app-nav a.is-active,
129
+ .ui-app-nav a[aria-current]:not([aria-current='false']) {
130
+ border-inline-start-color: Highlight;
131
+ font-weight: 700;
132
+ }
133
+
134
+ .ui-app-nav a.is-active::before,
135
+ .ui-app-nav a[aria-current]:not([aria-current='false'])::before {
136
+ background: Highlight;
137
+ }
138
+ }
139
+
121
140
  .ui-app-rail__foot {
122
141
  border-block-start: 1px solid var(--line);
123
142
  color: var(--text-dim);
@@ -253,6 +272,13 @@
253
272
  @media (max-width: 880px) {
254
273
  .ui-app-shell {
255
274
  grid-template-columns: minmax(0, 1fr);
275
+
276
+ /* The shell keeps `min-block-size: 100dvh`, so with two auto rows the default
277
+ `align-content: stretch` distributes the leftover viewport across BOTH
278
+ tracks — ballooning the horizontal rail to ~half the screen. Pin tracks to
279
+ their content and let the content row absorb the slack. (component audit C7.) */
280
+ align-content: start;
281
+ grid-template-rows: auto 1fr;
256
282
  }
257
283
 
258
284
  .ui-app-rail {