@ponchia/ui 0.4.1 → 0.5.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +230 -8
  2. package/MIGRATIONS.json +92 -0
  3. package/README.md +9 -6
  4. package/annotations/index.d.ts +280 -0
  5. package/annotations/index.js +522 -0
  6. package/behaviors/carousel.js +197 -0
  7. package/behaviors/combobox.js +195 -0
  8. package/behaviors/command.js +187 -0
  9. package/behaviors/connectors.js +96 -0
  10. package/behaviors/crosshair.js +58 -0
  11. package/behaviors/dialog.js +73 -0
  12. package/behaviors/disclosure.js +25 -0
  13. package/behaviors/dismissible.js +24 -0
  14. package/behaviors/forms.js +158 -0
  15. package/behaviors/glyph.js +109 -0
  16. package/behaviors/index.d.ts +79 -0
  17. package/behaviors/index.js +18 -1409
  18. package/behaviors/internal.js +50 -0
  19. package/behaviors/legend.js +46 -0
  20. package/behaviors/menu.js +46 -0
  21. package/behaviors/popover.js +108 -0
  22. package/behaviors/spotlight.js +53 -0
  23. package/behaviors/table.js +109 -0
  24. package/behaviors/tabs.js +103 -0
  25. package/behaviors/theme.js +82 -0
  26. package/behaviors/toast.js +152 -0
  27. package/classes/index.d.ts +280 -2
  28. package/classes/index.js +313 -2
  29. package/connectors/index.d.ts +71 -0
  30. package/connectors/index.js +179 -0
  31. package/css/analytical.css +21 -0
  32. package/css/annotations.css +292 -0
  33. package/css/command.css +97 -0
  34. package/css/connectors.css +93 -0
  35. package/css/crosshair.css +100 -0
  36. package/css/feedback.css +51 -0
  37. package/css/fonts.css +11 -7
  38. package/css/generated.css +117 -0
  39. package/css/legend.css +268 -0
  40. package/css/marks.css +144 -0
  41. package/css/primitives.css +18 -0
  42. package/css/report.css +12 -31
  43. package/css/selection.css +46 -0
  44. package/css/sources.css +179 -0
  45. package/css/spotlight.css +104 -0
  46. package/css/state.css +121 -0
  47. package/css/tokens.css +25 -37
  48. package/css/workbench.css +83 -0
  49. package/dist/bronto.css +1 -1
  50. package/dist/css/analytical.css +1 -0
  51. package/dist/css/annotations.css +1 -0
  52. package/dist/css/command.css +1 -0
  53. package/dist/css/connectors.css +1 -0
  54. package/dist/css/crosshair.css +1 -0
  55. package/dist/css/feedback.css +1 -1
  56. package/dist/css/fonts.css +1 -1
  57. package/dist/css/generated.css +1 -0
  58. package/dist/css/legend.css +1 -0
  59. package/dist/css/marks.css +1 -0
  60. package/dist/css/primitives.css +1 -1
  61. package/dist/css/report.css +1 -1
  62. package/dist/css/selection.css +1 -0
  63. package/dist/css/sources.css +1 -0
  64. package/dist/css/spotlight.css +1 -0
  65. package/dist/css/state.css +1 -0
  66. package/dist/css/workbench.css +1 -0
  67. package/docs/adr/0003-theme-model.md +7 -4
  68. package/docs/annotations.md +345 -0
  69. package/docs/architecture.md +202 -0
  70. package/docs/command.md +95 -0
  71. package/docs/connectors.md +91 -0
  72. package/docs/crosshair.md +63 -0
  73. package/docs/generated.md +91 -0
  74. package/docs/legends.md +168 -0
  75. package/docs/marks.md +86 -0
  76. package/docs/reference.md +309 -3
  77. package/docs/reporting.md +49 -14
  78. package/docs/selection.md +40 -0
  79. package/docs/sources.md +110 -0
  80. package/docs/spotlight.md +78 -0
  81. package/docs/stability.md +16 -1
  82. package/docs/state.md +85 -0
  83. package/docs/usage.md +22 -0
  84. package/docs/workbench.md +72 -0
  85. package/fonts/doto-400.woff2 +0 -0
  86. package/fonts/doto-500.woff2 +0 -0
  87. package/fonts/doto-600.woff2 +0 -0
  88. package/fonts/doto-700.woff2 +0 -0
  89. package/fonts/doto-800.woff2 +0 -0
  90. package/fonts/doto-900.woff2 +0 -0
  91. package/llms.txt +229 -6
  92. package/package.json +69 -4
  93. package/qwik/index.d.ts +5 -0
  94. package/qwik/index.js +20 -0
  95. package/react/index.d.ts +5 -0
  96. package/react/index.js +10 -0
  97. package/solid/index.d.ts +5 -0
  98. package/solid/index.js +10 -0
  99. package/tokens/index.js +9 -5
  100. package/fonts/doto-400.ttf +0 -0
  101. package/fonts/doto-500.ttf +0 -0
  102. package/fonts/doto-600.ttf +0 -0
  103. package/fonts/doto-700.ttf +0 -0
  104. package/fonts/doto-800.ttf +0 -0
  105. package/fonts/doto-900.ttf +0 -0
@@ -0,0 +1,152 @@
1
+ import { hasDom, noop } from './internal.js';
2
+
3
+ // First-toast deferral queue. The very first toast on a brand-new stack
4
+ // is appended next frame so AT observes the empty aria-live region
5
+ // before its first child. Any further toasts created *before* that frame
6
+ // flushes are queued behind it so call order (FIFO) is preserved instead
7
+ // of a synchronous later toast jumping ahead of the deferred first one.
8
+ const toastQueue = [];
9
+
10
+ let toastFlushScheduled = false;
11
+
12
+ function toastStack(isAssertive) {
13
+ const stackSel = isAssertive
14
+ ? '.ui-toast-stack--assertive'
15
+ : '.ui-toast-stack:not(.ui-toast-stack--assertive)';
16
+ let stack = document.querySelector(stackSel);
17
+ const fresh = !stack;
18
+ if (!stack) {
19
+ stack = document.createElement('div');
20
+ stack.className = isAssertive ? 'ui-toast-stack ui-toast-stack--assertive' : 'ui-toast-stack';
21
+ stack.setAttribute('aria-live', isAssertive ? 'assertive' : 'polite');
22
+ if (isAssertive) stack.setAttribute('role', 'alert');
23
+ document.body.appendChild(stack);
24
+ }
25
+ return { stack, fresh };
26
+ }
27
+
28
+ function enqueueToast(place, freshStack) {
29
+ const canDefer = typeof requestAnimationFrame === 'function';
30
+ if (freshStack && canDefer) {
31
+ toastQueue.push(place);
32
+ toastFlushScheduled = true;
33
+ requestAnimationFrame(() => {
34
+ toastFlushScheduled = false;
35
+ for (const fn of toastQueue.splice(0)) fn();
36
+ });
37
+ } else if (toastFlushScheduled) {
38
+ toastQueue.push(place);
39
+ } else {
40
+ place();
41
+ }
42
+ }
43
+
44
+ function toastElement(message, { tone, title }) {
45
+ const el = document.createElement('div');
46
+ el.className = tone ? `ui-toast ui-toast--${tone}` : 'ui-toast';
47
+ // No per-item role: the stack itself is the live region; a nested
48
+ // live region risks double announcement in some SRs.
49
+ if (title) {
50
+ const t = document.createElement('p');
51
+ t.className = 'ui-toast__title';
52
+ t.textContent = title;
53
+ el.appendChild(t);
54
+ }
55
+ const body = document.createElement('div');
56
+ body.textContent = message;
57
+ el.appendChild(body);
58
+ return el;
59
+ }
60
+
61
+ // Remove a toast, animating its exit when — and only when — a transition
62
+ // is actually in effect. Detached nodes, reduced-motion, and the no-CSS
63
+ // test/SSR env all resolve to instant removal, so the dismiss contract
64
+ // (toast gone now, the aria-live stack stays resident) is unchanged there;
65
+ // a real browser with motion gets the CSS `.is-leaving` fade-out, with a
66
+ // timeout fallback so an interrupted/never-firing transitionend can't strand
67
+ // a toast in the live region.
68
+ function removeToast(el) {
69
+ const reduce =
70
+ typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
71
+ const cs =
72
+ !reduce && el.isConnected && typeof getComputedStyle === 'function'
73
+ ? getComputedStyle(el)
74
+ : null;
75
+ const dur = cs ? parseFloat(cs.transitionDuration) || 0 : 0;
76
+ if (dur <= 0) {
77
+ el.remove();
78
+ return;
79
+ }
80
+ el.classList.add('is-leaving');
81
+ let done = false;
82
+ const finish = () => {
83
+ if (done) return;
84
+ done = true;
85
+ el.remove();
86
+ };
87
+ el.addEventListener('transitionend', finish, { once: true });
88
+ const timer = setTimeout(finish, dur * 1000 + 120);
89
+ timer?.unref?.(); // don't keep a Node test process alive
90
+ }
91
+
92
+ function addToastClose(el, dismiss) {
93
+ const close = document.createElement('button');
94
+ close.type = 'button';
95
+ close.className = 'ui-toast__close';
96
+ close.setAttribute('aria-label', 'Dismiss');
97
+ close.addEventListener('click', dismiss);
98
+ el.appendChild(close);
99
+ }
100
+
101
+ /**
102
+ * Push a transient toast into a shared, screen-anchored stack. The stack
103
+ * is the `aria-live="polite"` region: it is created once, appended to
104
+ * <body>, and **kept resident even when empty** so the live region is
105
+ * always present before content is inserted (a freshly created region
106
+ * that receives its first child in the same tick is not reliably
107
+ * announced by VoiceOver/NVDA). On first creation the empty region is
108
+ * inserted and the toast is appended on the next frame for the same
109
+ * reason. `tone` is accent/success/warning/danger/info; `title` is an
110
+ * optional uppercase label; `duration` ms before auto-dismiss (0 keeps
111
+ * it until dismissed). Returns a function that dismisses the toast
112
+ * early. SSR-safe (no-op).
113
+ */
114
+ export function toast(message, { tone, title, duration = 4000, assertive, closable } = {}) {
115
+ if (!hasDom()) return noop;
116
+ // Errors must interrupt: danger toasts (or an explicit `assertive`)
117
+ // go to a SEPARATE assertive region so they announce immediately,
118
+ // while status toasts stay polite. Two regions — not a per-item
119
+ // role=alert nested in a polite parent — avoids the double
120
+ // announcement that nesting causes in some screen readers.
121
+ const isAssertive = assertive ?? tone === 'danger';
122
+ const { stack, fresh: freshStack } = toastStack(isAssertive);
123
+ const el = toastElement(message, { tone, title });
124
+ // Append after a frame the *first* time so the empty live region is
125
+ // observed by AT before its first child arrives; once the region has
126
+ // been observed, later toasts append synchronously.
127
+ let dismissed = false;
128
+ // `dismissed` guard: a toast dismissed before its frame (e.g.
129
+ // duration:0 + immediate dismiss) must NOT be resurrected into the
130
+ // persistent aria-live region.
131
+ const place = () => {
132
+ if (!dismissed) stack.appendChild(el);
133
+ };
134
+ enqueueToast(place, freshStack);
135
+
136
+ let timer;
137
+ const dismiss = () => {
138
+ if (dismissed) return;
139
+ dismissed = true;
140
+ if (timer) clearTimeout(timer);
141
+ removeToast(el);
142
+ // The stack is a persistent live region — never removed on drain, so
143
+ // the next toast does not recreate (and thus mis-announce) it.
144
+ };
145
+ // A sticky toast (duration:0) is unusable without a manual close, so
146
+ // it gets a dismiss affordance by default; any toast can opt in via
147
+ // `closable`. The button carries no text node (glyph is a CSS
148
+ // ::before) so the toast's announced/textContent stays the message.
149
+ if (closable ?? duration === 0) addToastClose(el, dismiss);
150
+ if (duration > 0) timer = setTimeout(dismiss, duration);
151
+ return dismiss;
152
+ }
@@ -254,8 +254,6 @@ export declare const cls: {
254
254
  readonly reportAppendix: 'ui-report__appendix';
255
255
  readonly reportFootnotes: 'ui-report__footnotes';
256
256
  readonly chart: 'ui-chart';
257
- readonly chartLegend: 'ui-chart__legend';
258
- readonly chartSwatch: 'ui-chart__swatch';
259
257
  readonly chartCaption: 'ui-chart__caption';
260
258
  readonly chartPlot: 'ui-chart__plot';
261
259
  readonly chartBar: 'ui-chart__bar';
@@ -263,6 +261,177 @@ export declare const cls: {
263
261
  readonly chartTrack: 'ui-chart__track';
264
262
  readonly chartFill: 'ui-chart__fill';
265
263
  readonly chartFallback: 'ui-chart__fallback';
264
+ readonly legend: 'ui-legend';
265
+ readonly legendVertical: 'ui-legend--vertical';
266
+ readonly legendCompact: 'ui-legend--compact';
267
+ readonly legendGradient: 'ui-legend--gradient';
268
+ readonly legendDiverging: 'ui-legend--diverging';
269
+ readonly legendThreshold: 'ui-legend--threshold';
270
+ readonly legendWithValues: 'ui-legend--with-values';
271
+ readonly legendInteractive: 'ui-legend--interactive';
272
+ readonly legendTitle: 'ui-legend__title';
273
+ readonly legendItem: 'ui-legend__item';
274
+ readonly legendSwatch: 'ui-legend__swatch';
275
+ readonly legendSwatchCircle: 'ui-legend__swatch--circle';
276
+ readonly legendSwatchLine: 'ui-legend__swatch--line';
277
+ readonly legendSwatch1: 'ui-legend__swatch--1';
278
+ readonly legendSwatch2: 'ui-legend__swatch--2';
279
+ readonly legendSwatch3: 'ui-legend__swatch--3';
280
+ readonly legendSwatch4: 'ui-legend__swatch--4';
281
+ readonly legendSwatch5: 'ui-legend__swatch--5';
282
+ readonly legendSwatch6: 'ui-legend__swatch--6';
283
+ readonly legendSwatch7: 'ui-legend__swatch--7';
284
+ readonly legendSwatch8: 'ui-legend__swatch--8';
285
+ readonly legendSymbol: 'ui-legend__symbol';
286
+ readonly legendLabel: 'ui-legend__label';
287
+ readonly legendValue: 'ui-legend__value';
288
+ readonly legendCaption: 'ui-legend__caption';
289
+ readonly legendTrack: 'ui-legend__track';
290
+ readonly legendTicks: 'ui-legend__ticks';
291
+ readonly legendTick: 'ui-legend__tick';
292
+ readonly annotation: 'ui-annotation';
293
+ readonly annotationSubject: 'ui-annotation__subject';
294
+ readonly annotationConnector: 'ui-annotation__connector';
295
+ readonly annotationConnectorEnd: 'ui-annotation__connector-end';
296
+ readonly annotationNote: 'ui-annotation__note';
297
+ readonly annotationNoteLine: 'ui-annotation__note-line';
298
+ readonly annotationTitle: 'ui-annotation__title';
299
+ readonly annotationLabel: 'ui-annotation__label';
300
+ readonly annotationBadge: 'ui-annotation__badge';
301
+ readonly annotationLabelVariant: 'ui-annotation--label';
302
+ readonly annotationCallout: 'ui-annotation--callout';
303
+ readonly annotationElbow: 'ui-annotation--elbow';
304
+ readonly annotationCurve: 'ui-annotation--curve';
305
+ readonly annotationCircle: 'ui-annotation--circle';
306
+ readonly annotationRect: 'ui-annotation--rect';
307
+ readonly annotationThreshold: 'ui-annotation--threshold';
308
+ readonly annotationBadgeVariant: 'ui-annotation--badge';
309
+ readonly annotationBracket: 'ui-annotation--bracket';
310
+ readonly annotationBand: 'ui-annotation--band';
311
+ readonly annotationSlope: 'ui-annotation--slope';
312
+ readonly annotationCompare: 'ui-annotation--compare';
313
+ readonly annotationCluster: 'ui-annotation--cluster';
314
+ readonly annotationAxis: 'ui-annotation--axis';
315
+ readonly annotationTimeline: 'ui-annotation--timeline';
316
+ readonly annotationEvidence: 'ui-annotation--evidence';
317
+ readonly annotationAccent: 'ui-annotation--accent';
318
+ readonly annotationMuted: 'ui-annotation--muted';
319
+ readonly annotationSuccess: 'ui-annotation--success';
320
+ readonly annotationWarning: 'ui-annotation--warning';
321
+ readonly annotationDanger: 'ui-annotation--danger';
322
+ readonly annotationInfo: 'ui-annotation--info';
323
+ readonly annotationDraw: 'ui-annotation--draw';
324
+ readonly annotationPulse: 'ui-annotation--pulse';
325
+ readonly annotationReveal: 'ui-annotation--reveal';
326
+ readonly annotationFocus: 'ui-annotation--focus';
327
+ readonly mark: 'ui-mark';
328
+ readonly markAccent: 'ui-mark--accent';
329
+ readonly markSuccess: 'ui-mark--success';
330
+ readonly markWarning: 'ui-mark--warning';
331
+ readonly markDanger: 'ui-mark--danger';
332
+ readonly markInfo: 'ui-mark--info';
333
+ readonly markMuted: 'ui-mark--muted';
334
+ readonly markUnderline: 'ui-mark--underline';
335
+ readonly markBox: 'ui-mark--box';
336
+ readonly markStrike: 'ui-mark--strike';
337
+ readonly markDraw: 'ui-mark--draw';
338
+ readonly bracketNote: 'ui-bracket-note';
339
+ readonly bracketNoteLabel: 'ui-bracket-note__label';
340
+ readonly bracketNoteAccent: 'ui-bracket-note--accent';
341
+ readonly bracketNoteWarning: 'ui-bracket-note--warning';
342
+ readonly bracketNoteDanger: 'ui-bracket-note--danger';
343
+ readonly bracketNoteInfo: 'ui-bracket-note--info';
344
+ readonly connector: 'ui-connector';
345
+ readonly connectorPath: 'ui-connector__path';
346
+ readonly connectorEnd: 'ui-connector__end';
347
+ readonly connectorDashed: 'ui-connector--dashed';
348
+ readonly connectorAccent: 'ui-connector--accent';
349
+ readonly connectorMuted: 'ui-connector--muted';
350
+ readonly connectorSuccess: 'ui-connector--success';
351
+ readonly connectorWarning: 'ui-connector--warning';
352
+ readonly connectorDanger: 'ui-connector--danger';
353
+ readonly connectorInfo: 'ui-connector--info';
354
+ readonly connectorDraw: 'ui-connector--draw';
355
+ readonly spotlight: 'ui-spotlight';
356
+ readonly spotlightHole: 'ui-spotlight__hole';
357
+ readonly spotlightRing: 'ui-spotlight--ring';
358
+ readonly tourNote: 'ui-tour-note';
359
+ readonly tourNoteStep: 'ui-tour-note__step';
360
+ readonly tourNoteTitle: 'ui-tour-note__title';
361
+ readonly tourNoteBody: 'ui-tour-note__body';
362
+ readonly tourNoteActions: 'ui-tour-note__actions';
363
+ readonly crosshair: 'ui-crosshair';
364
+ readonly crosshairMuted: 'ui-crosshair--muted';
365
+ readonly crosshairLine: 'ui-crosshair__line';
366
+ readonly crosshairLineX: 'ui-crosshair__line--x';
367
+ readonly crosshairLineY: 'ui-crosshair__line--y';
368
+ readonly crosshairBadge: 'ui-crosshair__badge';
369
+ readonly readout: 'ui-readout';
370
+ readonly sel: 'ui-sel';
371
+ readonly selOn: 'ui-sel--on';
372
+ readonly selOff: 'ui-sel--off';
373
+ readonly selMaybe: 'ui-sel--maybe';
374
+ readonly citation: 'ui-citation';
375
+ readonly citationChip: 'ui-citation--chip';
376
+ readonly sourceList: 'ui-source-list';
377
+ readonly sourceListItem: 'ui-source-list__item';
378
+ readonly sourceCard: 'ui-source-card';
379
+ readonly sourceCardTitle: 'ui-source-card__title';
380
+ readonly sourceCardOrigin: 'ui-source-card__origin';
381
+ readonly sourceCardTime: 'ui-source-card__time';
382
+ readonly sourceCardExcerpt: 'ui-source-card__excerpt';
383
+ readonly sourceCardActions: 'ui-source-card__actions';
384
+ readonly provenance: 'ui-provenance';
385
+ readonly provenanceItem: 'ui-provenance__item';
386
+ readonly srcVerified: 'ui-src--verified';
387
+ readonly srcUnverified: 'ui-src--unverified';
388
+ readonly srcGenerated: 'ui-src--generated';
389
+ readonly srcReviewed: 'ui-src--reviewed';
390
+ readonly srcStale: 'ui-src--stale';
391
+ readonly srcConflict: 'ui-src--conflict';
392
+ readonly state: 'ui-state';
393
+ readonly stateLabel: 'ui-state__label';
394
+ readonly stateDetail: 'ui-state__detail';
395
+ readonly stateBusy: 'ui-state--busy';
396
+ readonly stateSaving: 'ui-state--saving';
397
+ readonly stateSaved: 'ui-state--saved';
398
+ readonly stateQueued: 'ui-state--queued';
399
+ readonly stateOffline: 'ui-state--offline';
400
+ readonly stateStale: 'ui-state--stale';
401
+ readonly stateConflict: 'ui-state--conflict';
402
+ readonly stateError: 'ui-state--error';
403
+ readonly stateLocked: 'ui-state--locked';
404
+ readonly stateReviewed: 'ui-state--reviewed';
405
+ readonly stateNeedsReview: 'ui-state--needs-review';
406
+ readonly syncbar: 'ui-syncbar';
407
+ readonly generated: 'ui-generated';
408
+ readonly generatedLabel: 'ui-generated__label';
409
+ readonly originLabel: 'ui-origin-label';
410
+ readonly originLabelAi: 'ui-origin-label--ai';
411
+ readonly reasoning: 'ui-reasoning';
412
+ readonly reasoningBody: 'ui-reasoning__body';
413
+ readonly toolLog: 'ui-tool-log';
414
+ readonly toolCall: 'ui-tool-call';
415
+ readonly toolCallName: 'ui-tool-call__name';
416
+ readonly toolCallStatus: 'ui-tool-call__status';
417
+ readonly toolCallBody: 'ui-tool-call__body';
418
+ readonly inspector: 'ui-inspector';
419
+ readonly inspectorHeader: 'ui-inspector__header';
420
+ readonly inspectorBody: 'ui-inspector__body';
421
+ readonly property: 'ui-property';
422
+ readonly propertyLabel: 'ui-property__label';
423
+ readonly propertyValue: 'ui-property__value';
424
+ readonly selectionbar: 'ui-selectionbar';
425
+ readonly selectionbarCount: 'ui-selectionbar__count';
426
+ readonly selectionbarActions: 'ui-selectionbar__actions';
427
+ readonly command: 'ui-command';
428
+ readonly commandInput: 'ui-command__input';
429
+ readonly commandList: 'ui-command__list';
430
+ readonly commandGroup: 'ui-command__group';
431
+ readonly commandItem: 'ui-command__item';
432
+ readonly commandShortcut: 'ui-command__shortcut';
433
+ readonly commandMeta: 'ui-command__meta';
434
+ readonly commandEmpty: 'ui-command__empty';
266
435
  readonly printOnly: 'ui-print-only';
267
436
  readonly screenOnly: 'ui-screen-only';
268
437
  readonly breakBefore: 'ui-break-before';
@@ -270,6 +439,8 @@ export declare const cls: {
270
439
  readonly keep: 'ui-keep';
271
440
  readonly printExact: 'ui-print-exact';
272
441
  readonly kbd: 'ui-kbd';
442
+ readonly shortcut: 'ui-shortcut';
443
+ readonly shortcutSep: 'ui-shortcut__sep';
273
444
  readonly display: 'ui-display';
274
445
  readonly mono: 'ui-mono';
275
446
  readonly muted: 'ui-muted';
@@ -414,6 +585,98 @@ export interface InputIconOpts {
414
585
  /** Place the icon at the inline-end instead of the start. */
415
586
  end?: boolean;
416
587
  }
588
+ export interface LegendOpts {
589
+ /** Stack entries vertically instead of the wrapping inline row. */
590
+ orient?: 'vertical';
591
+ /** Continuous colour ramp (`gradient`) or binned `threshold` key. Omit for the categorical default. */
592
+ type?: 'gradient' | 'threshold';
593
+ /** Use the 7-stop diverging ramp instead of the sequential one (gradient type). */
594
+ diverging?: boolean;
595
+ compact?: boolean;
596
+ /** Align a trailing `__value` column across rows. */
597
+ withValues?: boolean;
598
+ /** Entries are `<button aria-pressed>` toggles (pair with behaviors/legend.js). */
599
+ interactive?: boolean;
600
+ }
601
+ export interface LegendItemOpts {
602
+ /** Host-set inactive state. Equivalent to `[aria-pressed="false"]` on an interactive entry. */
603
+ inactive?: boolean;
604
+ }
605
+ export interface LegendSwatchOpts {
606
+ /** Categorical palette series 1–8 — sets the matching `--chart-N` colour. */
607
+ series?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
608
+ shape?: 'circle' | 'line';
609
+ }
610
+ export interface AnnotationOpts {
611
+ variant?: 'label' | 'callout' | 'elbow' | 'curve' | 'circle' | 'rect' | 'threshold' | 'badge' | 'bracket' | 'band' | 'slope' | 'compare' | 'cluster' | 'axis' | 'timeline' | 'evidence';
612
+ tone?: 'accent' | 'muted' | 'success' | 'warning' | 'danger' | 'info';
613
+ motion?: 'draw' | 'pulse' | 'reveal' | 'focus';
614
+ }
615
+ export interface MarkOpts {
616
+ /** How the mark is drawn. Omit for the highlight fill. */
617
+ style?: 'underline' | 'box' | 'strike';
618
+ /** `accent` is the rationed accent; status tones for status-bearing emphasis; `muted` for de-emphasis. */
619
+ tone?: 'accent' | 'success' | 'warning' | 'danger' | 'info' | 'muted';
620
+ /** Draw-on highlight sweep (respects `prefers-reduced-motion`). */
621
+ motion?: 'draw';
622
+ }
623
+ export interface BracketNoteOpts {
624
+ tone?: 'accent' | 'warning' | 'danger' | 'info';
625
+ }
626
+ export interface ConnectorOpts {
627
+ tone?: 'accent' | 'muted' | 'success' | 'warning' | 'danger' | 'info';
628
+ dashed?: boolean;
629
+ /** Stroke the line in once (respects `prefers-reduced-motion`). */
630
+ motion?: 'draw';
631
+ }
632
+ export interface SpotlightOpts {
633
+ /** Add a ring around the cutout. */
634
+ ring?: boolean;
635
+ }
636
+ export interface CrosshairOpts {
637
+ /** A subtler, neutral crosshair instead of the accent. */
638
+ muted?: boolean;
639
+ }
640
+ export interface SelOpts {
641
+ /** Selection emphasis: `on` (selected), `off` (excluded), `maybe` (live-brush candidate). */
642
+ state?: 'on' | 'off' | 'maybe';
643
+ }
644
+ /** Trust state for the source/citation/provenance layer. Pair with an author-written label — never colour alone. */
645
+ export type SrcState = 'verified' | 'unverified' | 'generated' | 'reviewed' | 'stale' | 'conflict';
646
+ export interface CitationOpts {
647
+ /** Render as a named-source pill (leading tone dot) instead of an inline `[n]` reference. */
648
+ chip?: boolean;
649
+ state?: SrcState;
650
+ }
651
+ export interface SourceOpts {
652
+ /** Sets the source card's tone border. */
653
+ state?: SrcState;
654
+ }
655
+ export interface ProvenanceOpts {
656
+ /** Sets the provenance item's tone dot. */
657
+ state?: SrcState;
658
+ }
659
+ /** Canonical lifecycle state — sets the tone; pair with the canonical label (see docs/state.md). */
660
+ export type LifecycleState =
661
+ | 'saving'
662
+ | 'saved'
663
+ | 'queued'
664
+ | 'offline'
665
+ | 'stale'
666
+ | 'conflict'
667
+ | 'error'
668
+ | 'locked'
669
+ | 'reviewed'
670
+ | 'needs-review';
671
+ export interface StateOpts {
672
+ state?: LifecycleState;
673
+ /** Pulse the indicator for an in-progress state (saving / syncing / retrying). Reduced-motion-safe. */
674
+ busy?: boolean;
675
+ }
676
+ export interface OriginLabelOpts {
677
+ /** Accent-tint the label for AI/model-generated origin (vs a neutral tag). */
678
+ ai?: boolean;
679
+ }
417
680
 
418
681
  export interface Ui {
419
682
  button(opts?: ButtonOpts): string;
@@ -442,6 +705,21 @@ export interface Ui {
442
705
  container(opts?: ContainerOpts): string;
443
706
  tag(opts?: TagOpts): string;
444
707
  inputIcon(opts?: InputIconOpts): string;
708
+ legend(opts?: LegendOpts): string;
709
+ legendItem(opts?: LegendItemOpts): string;
710
+ legendSwatch(opts?: LegendSwatchOpts): string;
711
+ annotation(opts?: AnnotationOpts): string;
712
+ mark(opts?: MarkOpts): string;
713
+ bracketNote(opts?: BracketNoteOpts): string;
714
+ connector(opts?: ConnectorOpts): string;
715
+ spotlight(opts?: SpotlightOpts): string;
716
+ crosshair(opts?: CrosshairOpts): string;
717
+ sel(opts?: SelOpts): string;
718
+ citation(opts?: CitationOpts): string;
719
+ source(opts?: SourceOpts): string;
720
+ provenance(opts?: ProvenanceOpts): string;
721
+ state(opts?: StateOpts): string;
722
+ originLabel(opts?: OriginLabelOpts): string;
445
723
  }
446
724
 
447
725
  export declare const ui: Ui;