@ponchia/ui 0.6.0 → 0.6.4

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 (162) hide show
  1. package/CHANGELOG.md +82 -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 +21 -0
  33. package/behaviors/glyph.d.ts.map +1 -0
  34. package/behaviors/glyph.js +82 -4
  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 +747 -15
  72. package/classes/index.d.ts +118 -3
  73. package/classes/index.js +264 -66
  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 +246 -9
  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 +43 -4
  92. package/css/sidenote.css +67 -0
  93. package/css/skins.css +9 -0
  94. package/css/spark.css +76 -0
  95. package/css/table.css +16 -3
  96. package/css/term.css +110 -0
  97. package/css/textref.css +63 -0
  98. package/css/toc.css +91 -0
  99. package/css/tokens.css +14 -1
  100. package/css/tree.css +134 -0
  101. package/dist/bronto.css +1 -1
  102. package/dist/css/analytical.css +1 -1
  103. package/dist/css/app.css +1 -1
  104. package/dist/css/bullet.css +1 -0
  105. package/dist/css/code.css +1 -0
  106. package/dist/css/content.css +1 -1
  107. package/dist/css/crosshair.css +1 -1
  108. package/dist/css/diff.css +1 -0
  109. package/dist/css/disclosure.css +1 -1
  110. package/dist/css/dots.css +1 -1
  111. package/dist/css/feedback.css +1 -1
  112. package/dist/css/forms.css +1 -1
  113. package/dist/css/legend.css +1 -1
  114. package/dist/css/motion.css +1 -1
  115. package/dist/css/overlay.css +1 -1
  116. package/dist/css/primitives.css +1 -1
  117. package/dist/css/report.css +1 -1
  118. package/dist/css/sidenote.css +1 -0
  119. package/dist/css/skins.css +1 -1
  120. package/dist/css/spark.css +1 -0
  121. package/dist/css/table.css +1 -1
  122. package/dist/css/term.css +1 -0
  123. package/dist/css/textref.css +1 -0
  124. package/dist/css/toc.css +1 -0
  125. package/dist/css/tokens.css +1 -1
  126. package/dist/css/tree.css +1 -0
  127. package/docs/annotations.md +39 -0
  128. package/docs/architecture.md +2 -3
  129. package/docs/bullet.md +78 -0
  130. package/docs/code.md +76 -0
  131. package/docs/d2.md +4 -3
  132. package/docs/diff.md +146 -0
  133. package/docs/dots.md +146 -0
  134. package/docs/glyphs.md +114 -0
  135. package/docs/legends.md +8 -4
  136. package/docs/mermaid.md +21 -4
  137. package/docs/reference.md +168 -8
  138. package/docs/reporting.md +49 -17
  139. package/docs/sidenote.md +64 -0
  140. package/docs/spark.md +78 -0
  141. package/docs/stability.md +1 -0
  142. package/docs/term.md +81 -0
  143. package/docs/textref.md +78 -0
  144. package/docs/theming.md +44 -5
  145. package/docs/toc.md +83 -0
  146. package/docs/tree.md +74 -0
  147. package/docs/usage.md +264 -23
  148. package/docs/vega.md +22 -3
  149. package/glyphs/glyphs.d.ts +61 -0
  150. package/glyphs/glyphs.js +600 -31
  151. package/llms.txt +169 -15
  152. package/package.json +51 -7
  153. package/qwik/index.d.ts +4 -2
  154. package/qwik/index.d.ts.map +1 -1
  155. package/qwik/index.js +10 -0
  156. package/react/index.d.ts +4 -2
  157. package/react/index.d.ts.map +1 -1
  158. package/react/index.js +6 -0
  159. package/solid/index.d.ts +6 -2
  160. package/solid/index.d.ts.map +1 -1
  161. package/solid/index.js +6 -0
  162. package/tokens/skins.js +22 -9
@@ -1,5 +1,13 @@
1
1
  import { hasDom, resolveHost, noop, bindOnce, collectHosts } from './internal.js';
2
2
 
3
+ /**
4
+ * @typedef {object} CrosshairMoveDetail
5
+ * @property {number} x Pointer x within the plot, in pixels.
6
+ * @property {number} y Pointer y within the plot, in pixels.
7
+ * @property {number} fx Pointer x as a 0..1 fraction of the plot width.
8
+ * @property {number} fy Pointer y as a 0..1 fraction of the plot height.
9
+ */
10
+
3
11
  /**
4
12
  * Track the pointer over a plot and drive a crosshair. Each
5
13
  * `[data-bronto-crosshair]` is the plot; it contains a `.ui-crosshair` overlay.
@@ -11,6 +19,9 @@ import { hasDom, resolveHost, noop, bindOnce, collectHosts } from './internal.js
11
19
  * Bronto reports WHERE the pointer is — it does not find the nearest datum or
12
20
  * map pixels to data values (that needs the host's scales). SSR-safe,
13
21
  * idempotent per plot; returns a cleanup function.
22
+ *
23
+ * @param {import('./internal.js').DelegateOpts} [opts]
24
+ * @returns {import('./internal.js').Cleanup}
14
25
  */
15
26
  export function initCrosshair({ root } = {}) {
16
27
  if (!hasDom()) return noop;
@@ -28,7 +39,14 @@ export function initCrosshair({ root } = {}) {
28
39
  if (!r.width || !r.height) return;
29
40
  const x = e.clientX - r.left;
30
41
  const y = e.clientY - r.top;
31
- overlay.style.setProperty('--crosshair-x', `${x}px`);
42
+ // The CSS positions the vertical rule / readout with a *logical* inset
43
+ // (inset-inline-start), so --crosshair-x must be the distance from the
44
+ // inline-start edge — the physical left in LTR, the physical right in RTL.
45
+ // Emitting the physical x instead made the RTL rule land off-plot. The
46
+ // public `detail.x`/`fx` stay physical-from-left so host scale-mapping
47
+ // keeps one stable coordinate space regardless of direction.
48
+ const rtl = getComputedStyle(plot).direction === 'rtl';
49
+ overlay.style.setProperty('--crosshair-x', `${rtl ? r.right - e.clientX : x}px`);
32
50
  overlay.style.setProperty('--crosshair-y', `${y}px`);
33
51
  overlay.classList.add('is-active');
34
52
  plot.dispatchEvent(
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Wire native <dialog> open/close glue (the one bit <dialog> can't do
3
+ * declaratively). Click `[data-bronto-open="dialogId"]` calls
4
+ * `showModal()` on `#dialogId`; click `[data-bronto-close]` closes the
5
+ * nearest enclosing <dialog>. Clicking the backdrop of a dialog that has
6
+ * `[data-bronto-dialog-light]` closes it too. On open the trigger is
7
+ * remembered and focus is returned to it on *every* close path (Esc,
8
+ * close button, backdrop light-dismiss, programmatic) via the native
9
+ * `close` event, so keyboard/SR users are never dropped at `<body>`.
10
+ * SSR-safe and idempotent; returns cleanup.
11
+ *
12
+ * `root` scopes delegated triggers (default `document`). Controlled targets are
13
+ * resolved root-first, then document-wide, so scoped islands win duplicate-id
14
+ * conflicts without breaking body/portal-mounted overlays.
15
+ *
16
+ * @param {import('./internal.js').DelegateOpts} [opts]
17
+ * @returns {import('./internal.js').Cleanup}
18
+ */
19
+ export function initDialog({ root }?: import("./internal.js").DelegateOpts): import("./internal.js").Cleanup;
20
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["dialog.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,sCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA0D3C"}
@@ -14,6 +14,9 @@ import { hasDom, resolveHost, noop, bindOnce, byIdInHost } from './internal.js';
14
14
  * `root` scopes delegated triggers (default `document`). Controlled targets are
15
15
  * resolved root-first, then document-wide, so scoped islands win duplicate-id
16
16
  * conflicts without breaking body/portal-mounted overlays.
17
+ *
18
+ * @param {import('./internal.js').DelegateOpts} [opts]
19
+ * @returns {import('./internal.js').Cleanup}
17
20
  */
18
21
  export function initDialog({ root } = {}) {
19
22
  if (!hasDom()) return noop;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Disclosure: a `[data-bronto-disclosure]` trigger toggles the element
3
+ * referenced by its `aria-controls` id, keeping `aria-expanded` and the
4
+ * panel's `hidden` attribute in sync.
5
+ *
6
+ * @param {import('./internal.js').DelegateOpts} [opts]
7
+ * @returns {import('./internal.js').Cleanup}
8
+ */
9
+ export function initDisclosure({ root }?: import("./internal.js").DelegateOpts): import("./internal.js").Cleanup;
10
+ //# sourceMappingURL=disclosure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["disclosure.js"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,0CAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAoB3C"}
@@ -4,6 +4,9 @@ import { hasDom, resolveHost, noop, bindOnce, byIdInHost } from './internal.js';
4
4
  * Disclosure: a `[data-bronto-disclosure]` trigger toggles the element
5
5
  * referenced by its `aria-controls` id, keeping `aria-expanded` and the
6
6
  * panel's `hidden` attribute in sync.
7
+ *
8
+ * @param {import('./internal.js').DelegateOpts} [opts]
9
+ * @returns {import('./internal.js').Cleanup}
7
10
  */
8
11
  export function initDisclosure({ root } = {}) {
9
12
  if (!hasDom()) return noop;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Click on `[data-bronto-dismiss]` removes the nearest ancestor matching
3
+ * `[data-bronto-dismissible]` (or the selector given as the attribute
4
+ * value). Emits a cancelable `bronto:dismiss` event first.
5
+ *
6
+ * @param {import('./internal.js').DelegateOpts} [opts]
7
+ * @returns {import('./internal.js').Cleanup}
8
+ */
9
+ export function dismissible({ root }?: import("./internal.js").DelegateOpts): import("./internal.js").Cleanup;
10
+ //# sourceMappingURL=dismissible.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dismissible.d.ts","sourceRoot":"","sources":["dismissible.js"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,uCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAmB3C"}
@@ -4,6 +4,9 @@ import { hasDom, resolveHost, noop, bindOnce, closestSafe } from './internal.js'
4
4
  * Click on `[data-bronto-dismiss]` removes the nearest ancestor matching
5
5
  * `[data-bronto-dismissible]` (or the selector given as the attribute
6
6
  * value). Emits a cancelable `bronto:dismiss` event first.
7
+ *
8
+ * @param {import('./internal.js').DelegateOpts} [opts]
9
+ * @returns {import('./internal.js').Cleanup}
7
10
  */
8
11
  export function dismissible({ root } = {}) {
9
12
  if (!hasDom()) return noop;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Accessible form validation glue for `<form data-bronto-validate>`.
3
+ * Progressive enhancement over the native Constraint Validation API —
4
+ * the framework already ships the `[aria-invalid]` / `.ui-hint--error`
5
+ * styling; this wires the a11y plumbing every consumer would otherwise
6
+ * re-implement (and usually get wrong):
7
+ *
8
+ * - suppresses the native error bubbles (`form.noValidate`),
9
+ * - on blur and on submit sets `aria-invalid` and writes the browser's
10
+ * `validationMessage` into the field's error slot
11
+ * (`[data-bronto-error]` inside the `.ui-field`, falling back to a
12
+ * `.ui-hint`), linked via `aria-describedby`. When it falls back to a
13
+ * `.ui-hint` the original help text is snapshotted and restored once the
14
+ * field is valid again (so the error does not eat the help permanently); a
15
+ * dedicated empty `[data-bronto-error]` node is still the recommended slot,
16
+ * - on an invalid submit, fills the form's
17
+ * `[data-bronto-error-summary]` (a `.ui-error-summary`) with
18
+ * in-page links to each bad field, focuses it, and blocks submit.
19
+ *
20
+ * Pure enhancement: with JS off the form still submits and the browser
21
+ * validates natively. SSR-safe, idempotent; returns a cleanup function.
22
+ *
23
+ * @param {import('./internal.js').DelegateOpts} [opts]
24
+ * @returns {import('./internal.js').Cleanup}
25
+ */
26
+ export function initFormValidation({ root }?: import("./internal.js").DelegateOpts): import("./internal.js").Cleanup;
27
+ //# sourceMappingURL=forms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["forms.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,8CAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA6K3C"}
@@ -21,6 +21,9 @@ import { hasDom, resolveHost, noop, bindOnce, nextFieldUid, collectHosts } from
21
21
  *
22
22
  * Pure enhancement: with JS off the form still submits and the browser
23
23
  * validates natively. SSR-safe, idempotent; returns a cleanup function.
24
+ *
25
+ * @param {import('./internal.js').DelegateOpts} [opts]
26
+ * @returns {import('./internal.js').Cleanup}
24
27
  */
25
28
  export function initFormValidation({ root } = {}) {
26
29
  if (!hasDom()) return noop;
@@ -68,16 +71,26 @@ export function initFormValidation({ root } = {}) {
68
71
  if (!control.willValidate) return true;
69
72
  const ok = control.validity.valid;
70
73
  const slot = slotFor(control);
71
- const isHint = slot?.classList.contains('ui-hint');
74
+ // Decide the slot TYPE by the `[data-bronto-error]` attribute, NOT the
75
+ // `.ui-hint` class: the canonical markup is `<p class="ui-hint"
76
+ // data-bronto-error>`, which carries BOTH. Keying off `.ui-hint` sent that
77
+ // dedicated error node down the help-hint branch, which never unlink()s — so
78
+ // the field kept a dangling aria-describedby to an empty error node after it
79
+ // was fixed (component-audit C6). Only a *borrowed* plain `.ui-hint` (a help
80
+ // slot with no dedicated error node) snapshots/restores its help text and
81
+ // stays linked in the valid state.
82
+ const dedicated = !!slot?.matches?.('[data-bronto-error]');
83
+ const hasHintClass = !!slot?.classList.contains('ui-hint');
84
+ const borrowedHint = hasHintClass && !dedicated;
72
85
  if (ok) {
73
86
  control.removeAttribute('aria-invalid');
74
87
  if (slot) {
75
- if (isHint) {
88
+ if (hasHintClass) slot.classList.remove('ui-hint--error');
89
+ if (borrowedHint) {
76
90
  // Restore the snapshotted help text (or clear if there was none); a
77
91
  // help-bearing hint stays linked via aria-describedby (it describes
78
92
  // the field in the valid state too).
79
93
  slot.textContent = hintHelp.get(slot) ?? '';
80
- slot.classList.remove('ui-hint--error');
81
94
  } else {
82
95
  // Dedicated error node: clear it and drop the now-stale describedby
83
96
  // so AT doesn't announce an empty error association.
@@ -88,9 +101,9 @@ export function initFormValidation({ root } = {}) {
88
101
  } else {
89
102
  control.setAttribute('aria-invalid', 'true');
90
103
  if (slot) {
91
- if (isHint && !hintHelp.has(slot)) hintHelp.set(slot, slot.textContent);
104
+ if (borrowedHint && !hintHelp.has(slot)) hintHelp.set(slot, slot.textContent);
92
105
  slot.textContent = control.validationMessage;
93
- if (isHint) slot.classList.add('ui-hint--error');
106
+ if (hasHintClass) slot.classList.add('ui-hint--error');
94
107
  link(control, slot);
95
108
  }
96
109
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Expand `[data-bronto-glyph="name"]` placeholders into a `.ui-dotmatrix`
3
+ * grid of GLYPH_SIZE² cells — the DOM counterpart to renderGlyph() from
4
+ * `@ponchia/ui/glyphs`, for when you'd rather drop a placeholder than inline
5
+ * the markup. Decorative by default (`aria-hidden`); add
6
+ * `data-bronto-glyph-label` to expose it as `role="img"`. An unknown glyph
7
+ * name is left untouched. Idempotent (skips an already-expanded host); the
8
+ * returned cleanup removes the cells and restores the original attributes.
9
+ *
10
+ * `data-bronto-glyph-render="mask"` takes the cheap one-node path instead:
11
+ * the host becomes a single `.ui-icon` masked by the glyph (no GLYPH_SIZE²
12
+ * cells), inheriting `currentColor` and scaling with the text — the DOM
13
+ * counterpart to renderGlyph's `render: 'mask'`, for an icon in every table
14
+ * row where 256 cells per glyph is too heavy. `data-bronto-glyph-size` sets
15
+ * `--icon-size`. The cell-mode attributes (solid/anim) don't apply.
16
+ *
17
+ * @param {import('./internal.js').DelegateOpts} [opts]
18
+ * @returns {import('./internal.js').Cleanup}
19
+ */
20
+ export function initDotGlyph({ root }?: import("./internal.js").DelegateOpts): import("./internal.js").Cleanup;
21
+ //# sourceMappingURL=glyph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["glyph.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAyJ3C"}
@@ -1,11 +1,18 @@
1
1
  import { hasDom, resolveHost, noop, collectHosts } from './internal.js';
2
- import { GLYPH_SIZE, glyphCells } from '../glyphs/glyphs.js';
2
+ import { GLYPH_SIZE, glyphCells, glyphMask } from '../glyphs/glyphs.js';
3
3
 
4
4
  function restoreAttr(el, name, prev) {
5
5
  if (prev === null) el.removeAttribute(name);
6
6
  else el.setAttribute(name, prev);
7
7
  }
8
8
 
9
+ // `dot`/`gap`/`size` land in inline CSS, so allow only length/calc syntax —
10
+ // drop anything with a `;`/`{` that could open a second declaration (mirrors
11
+ // glyphs.js cssLen). Used for the mask path's --icon-size.
12
+ function cssLen(v) {
13
+ return v && /^[\w.%+\-*/()\s,]+$/.test(v) ? v : '';
14
+ }
15
+
9
16
  /**
10
17
  * Expand `[data-bronto-glyph="name"]` placeholders into a `.ui-dotmatrix`
11
18
  * grid of GLYPH_SIZE² cells — the DOM counterpart to renderGlyph() from
@@ -14,6 +21,16 @@ function restoreAttr(el, name, prev) {
14
21
  * `data-bronto-glyph-label` to expose it as `role="img"`. An unknown glyph
15
22
  * name is left untouched. Idempotent (skips an already-expanded host); the
16
23
  * returned cleanup removes the cells and restores the original attributes.
24
+ *
25
+ * `data-bronto-glyph-render="mask"` takes the cheap one-node path instead:
26
+ * the host becomes a single `.ui-icon` masked by the glyph (no GLYPH_SIZE²
27
+ * cells), inheriting `currentColor` and scaling with the text — the DOM
28
+ * counterpart to renderGlyph's `render: 'mask'`, for an icon in every table
29
+ * row where 256 cells per glyph is too heavy. `data-bronto-glyph-size` sets
30
+ * `--icon-size`. The cell-mode attributes (solid/anim) don't apply.
31
+ *
32
+ * @param {import('./internal.js').DelegateOpts} [opts]
33
+ * @returns {import('./internal.js').Cleanup}
17
34
  */
18
35
  export function initDotGlyph({ root } = {}) {
19
36
  if (!hasDom()) return noop;
@@ -23,14 +40,54 @@ export function initDotGlyph({ root } = {}) {
23
40
  const cleanups = [];
24
41
 
25
42
  for (const el of els) {
43
+ const name = el.getAttribute('data-bronto-glyph');
44
+ const label = el.getAttribute('data-bronto-glyph-label');
45
+
46
+ // One-node mask path — the icon-at-scale counterpart to the 256-cell grid.
47
+ if (el.getAttribute('data-bronto-glyph-render') === 'mask') {
48
+ if (el.classList.contains('ui-icon') && el.style.getPropertyValue('--icon-mask')) continue;
49
+ const mask = glyphMask(name);
50
+ if (!mask) continue; // unknown glyph — leave the placeholder as-is
51
+ const hadIcon = el.classList.contains('ui-icon');
52
+ const hadMask = el.style.getPropertyValue('--icon-mask');
53
+ const hadSize = el.style.getPropertyValue('--icon-size');
54
+ const hadAriaHiddenM = el.getAttribute('aria-hidden');
55
+ const hadRoleM = el.getAttribute('role');
56
+ const hadAriaLabelM = el.getAttribute('aria-label');
57
+ const sizeM = cssLen(el.getAttribute('data-bronto-glyph-size'));
58
+
59
+ el.classList.add('ui-icon');
60
+ el.style.setProperty('--icon-mask', mask);
61
+ if (sizeM) el.style.setProperty('--icon-size', sizeM);
62
+ if (label) {
63
+ el.setAttribute('role', 'img');
64
+ el.setAttribute('aria-label', label);
65
+ el.removeAttribute('aria-hidden');
66
+ } else {
67
+ el.setAttribute('aria-hidden', 'true');
68
+ }
69
+
70
+ cleanups.push(() => {
71
+ if (!hadIcon) el.classList.remove('ui-icon');
72
+ if (hadMask) el.style.setProperty('--icon-mask', hadMask);
73
+ else el.style.removeProperty('--icon-mask');
74
+ if (sizeM && !hadSize) el.style.removeProperty('--icon-size');
75
+ else if (hadSize) el.style.setProperty('--icon-size', hadSize);
76
+ restoreAttr(el, 'aria-hidden', hadAriaHiddenM);
77
+ restoreAttr(el, 'role', hadRoleM);
78
+ restoreAttr(el, 'aria-label', hadAriaLabelM);
79
+ if (el.getAttribute('class') === '') el.removeAttribute('class');
80
+ if (el.getAttribute('style') === '') el.removeAttribute('style');
81
+ });
82
+ continue;
83
+ }
84
+
26
85
  // Scope to DIRECT-child cells (the ones we append) — so a placeholder that
27
86
  // legitimately nests its own .ui-dotmatrix is neither mis-read as already
28
87
  // expanded here nor have its inner cells removed by cleanup below.
29
88
  if (el.querySelector(':scope > .ui-dotmatrix__cell')) continue; // already expanded
30
- const cells = glyphCells(el.getAttribute('data-bronto-glyph'));
89
+ const cells = glyphCells(name);
31
90
  if (!cells.length) continue; // unknown glyph — leave the placeholder as-is
32
-
33
- const label = el.getAttribute('data-bronto-glyph-label');
34
91
  // `data-bronto-glyph-solid` → square, gapless pixel glyph (legible small),
35
92
  // the DOM counterpart to renderGlyph's `solid` option. Implies glyph-only.
36
93
  const solid = el.hasAttribute('data-bronto-glyph-solid');
@@ -59,6 +116,25 @@ export function initDotGlyph({ root } = {}) {
59
116
  el.style.setProperty('--dotmatrix-dot-radius', '0');
60
117
  el.style.setProperty('--dotmatrix-gap', '0');
61
118
  }
119
+ // Without a track size the grid cells default to `1fr`, so the 16×16 matrix
120
+ // balloons to fill its container (full-bleed) — asymmetric with the mask
121
+ // path's safe 1em. If the author set no `--dotmatrix-dot` (inline OR via the
122
+ // cascade), default it to an intrinsic icon scale so a forgotten size
123
+ // degrades to ~icon, not full-bleed. (component audit C9.)
124
+ const authoredDot =
125
+ el.style.getPropertyValue('--dotmatrix-dot') ||
126
+ (typeof getComputedStyle === 'function'
127
+ ? getComputedStyle(el).getPropertyValue('--dotmatrix-dot').trim()
128
+ : '');
129
+ const setDefaultDot = !authoredDot;
130
+ let setDefaultGap = false;
131
+ if (setDefaultDot) {
132
+ el.style.setProperty('--dotmatrix-dot', '0.08em');
133
+ if (!solid && !hadGap) {
134
+ el.style.setProperty('--dotmatrix-gap', '0.02em'); // tight, so it reads as one glyph
135
+ setDefaultGap = true;
136
+ }
137
+ }
62
138
  if (label) {
63
139
  el.setAttribute('role', 'img');
64
140
  el.setAttribute('aria-label', label);
@@ -93,6 +169,8 @@ export function initDotGlyph({ root } = {}) {
93
169
  if (hadGap) el.style.setProperty('--dotmatrix-gap', hadGap);
94
170
  else el.style.removeProperty('--dotmatrix-gap');
95
171
  }
172
+ if (setDefaultDot) el.style.removeProperty('--dotmatrix-dot');
173
+ if (setDefaultGap) el.style.removeProperty('--dotmatrix-gap');
96
174
  if (hadCols) el.style.setProperty('--dotmatrix-cols', hadCols);
97
175
  else el.style.removeProperty('--dotmatrix-cols');
98
176
  restoreAttr(el, 'aria-hidden', hadAriaHidden);
@@ -1,237 +1,31 @@
1
- /** @ponchia/ui optional, framework-agnostic behaviors. */
2
-
3
- /** Cleanup function returned by every initializer. */
4
- export type Cleanup = () => void;
5
-
6
- export interface ThemeStorageOpts {
7
- /** localStorage key for the persisted theme. Default: "bronto-theme". */
8
- storageKey?: string;
9
- }
10
-
11
- export interface ApplyThemeOpts extends ThemeStorageOpts {
12
- /** Element to set `data-theme` on. Default: <html>. */
13
- root?: Element;
14
- }
15
-
16
- export interface DelegateOpts {
17
- /** Event-delegation root; also scopes which controls are queried. Default: document. */
18
- root?: Document | Element;
19
- }
20
-
21
- /** `bronto:themechange` CustomEvent detail. */
22
- export interface ThemeChangeDetail {
23
- theme: 'light' | 'dark';
24
- }
25
-
26
- /** Apply the persisted theme to <html data-theme>. Call before paint. */
27
- export declare function applyStoredTheme(opts?: ApplyThemeOpts): void;
28
-
29
- /**
30
- * Wire `[data-bronto-theme-toggle]` controls. Theme is always applied to
31
- * <html>; `root` only scopes delegation/queried controls. Dispatches
32
- * `bronto:themechange` on <html>. Returns a cleanup function.
33
- */
34
- export declare function initThemeToggle(opts?: ThemeStorageOpts & DelegateOpts): Cleanup;
35
-
36
- /** Wire `[data-bronto-dismiss]` controls. Returns a cleanup function. */
37
- export declare function dismissible(opts?: DelegateOpts): Cleanup;
38
-
39
- /** Wire `[data-bronto-disclosure]` triggers. Returns a cleanup function. */
40
- export declare function initDisclosure(opts?: DelegateOpts): Cleanup;
41
-
42
- /**
43
- * Close affordances (Escape, outside-click, close-on-activate) for a
44
- * native `<details data-bronto-menu>` dropdown holding a `.ui-menu`.
45
- * Not a full ARIA menu by design. Returns a cleanup function.
46
- */
47
- export declare function initMenu(opts?: DelegateOpts): Cleanup;
48
-
49
- /**
50
- * Accessible validation glue for `<form data-bronto-validate>`:
51
- * progressive enhancement over the Constraint Validation API. Sets
52
- * `aria-invalid`, writes `validationMessage` into the field's
53
- * `[data-bronto-error]` / `.ui-hint` slot (linked via
54
- * `aria-describedby`), and on invalid submit fills the form's
55
- * `[data-bronto-error-summary]` with focusable links and blocks submit.
56
- * Works without JS (native validation). Returns a cleanup function.
57
- */
58
- export declare function initFormValidation(opts?: DelegateOpts): Cleanup;
59
-
60
- /**
61
- * Editable combobox with a filtered listbox popup (WAI-ARIA APG
62
- * pattern), dependency-free and CSS-anchored. Wires
63
- * `[data-bronto-combobox]` (input `role=combobox` +
64
- * `.ui-combobox__list` of `role=option`): ids, `aria-expanded` /
65
- * `aria-controls` / `aria-activedescendant`, type-to-filter, full
66
- * keyboard, pointer select, outside-click close. Emits `bronto:change`
67
- * ({ detail: { value } }) on selection. SSR-safe, idempotent per
68
- * instance. Returns a cleanup function.
69
- */
70
- export declare function initCombobox(opts?: DelegateOpts): Cleanup;
71
-
72
- /**
73
- * Collision-aware popover, dependency-free. A `[data-bronto-popover]`
74
- * trigger toggles the `.ui-popover` panel it names; the panel flips
75
- * above when it would overflow the viewport and its inline edge is
76
- * clamped on-screen. Uses the native top layer when the panel has
77
- * `popover` and the Popover API exists, else an `.is-open` class.
78
- * Manages `aria-expanded`/`aria-controls`, Escape + outside-click
79
- * close, scroll/resize reposition. Returns a cleanup function.
80
- */
81
- export declare function initPopover(opts?: DelegateOpts): Cleanup;
82
-
83
- /**
84
- * Client-side sortable + selectable data table for
85
- * `[data-bronto-sortable]`. Header `.ui-table__sort` / `th[data-sort]`
86
- * cycles `aria-sort` and reorders the tbody (numeric- or
87
- * locale-string-aware); `[data-bronto-select-all]` toggles
88
- * `[data-bronto-select]` rows + `aria-selected` with synced
89
- * checked/indeterminate state. Emits `bronto:selectionchange`
90
- * ({ detail: { count } }). SSR-safe, idempotent per table. Returns a
91
- * cleanup function.
92
- */
93
- export declare function initTableSort(opts?: DelegateOpts): Cleanup;
94
-
95
- /**
96
- * Wire `[data-bronto-tabs]` groups with the WAI-ARIA Tabs keyboard
97
- * pattern (roving tabindex, Arrow/Home/End, aria-selected, panel sync).
98
- * Returns a cleanup function.
99
- */
100
- export declare function initTabs(opts?: DelegateOpts): Cleanup;
101
-
102
- /**
103
- * Wire native <dialog> open/close glue: `[data-bronto-open="id"]`,
104
- * `[data-bronto-close]`, and backdrop light-dismiss for dialogs marked
105
- * `[data-bronto-dialog-light]`. `root` scopes delegated controls; dialog ids
106
- * resolve root-first, then document-wide for body/portal-mounted overlays.
107
- * Returns a cleanup function.
108
- */
109
- export declare function initDialog(opts?: DelegateOpts): Cleanup;
110
-
111
- /**
112
- * Image carousel / gallery built on CSS scroll-snap (touch/trackpad swipe
113
- * is the browser's). Wires `[data-bronto-carousel]`: prev/next
114
- * (`[data-bronto-carousel-prev|next]`), keyboard (Arrow/Home/End on the
115
- * focused `.ui-carousel__viewport`), a `.ui-carousel__thumb` strip with
116
- * `aria-current` sync, the `.ui-carousel__status` counter, and ARIA. Keeps
117
- * a JS index in sync with the scroll position both ways (via
118
- * IntersectionObserver where available). `data-bronto-carousel-loop` wraps
119
- * at the ends; `data-bronto-carousel-label` names the region. A
120
- * full-screen lightbox is the same markup inside a native
121
- * `<dialog class="ui-lightbox">` opened by `initDialog` (focus-trap/Escape
122
- * come from the dialog). Emits `bronto:change` ({ detail: { index } }).
123
- * SSR-safe, idempotent per carousel. Returns a cleanup function.
124
- */
125
- export declare function initCarousel(opts?: DelegateOpts): Cleanup;
126
-
127
- export interface ToastOpts {
128
- /** Status tone — maps to `ui-toast--<tone>`. */
129
- tone?: 'accent' | 'success' | 'warning' | 'danger' | 'info';
130
- /** Optional uppercase label rendered above the message. */
131
- title?: string;
132
- /** Auto-dismiss delay in ms. 0 keeps it until dismissed. Default: 4000. */
133
- duration?: number;
134
- /**
135
- * Route to the assertive live region so AT interrupts immediately.
136
- * Defaults to `true` when `tone === 'danger'`.
137
- */
138
- assertive?: boolean;
139
- /** Render a dismiss button on the toast. */
140
- closable?: boolean;
141
- }
142
-
143
- /**
144
- * Push a transient toast into a shared, body-anchored stack. Returns a
145
- * function that dismisses it early. No-op (returns noop) without a DOM.
146
- */
147
- export declare function toast(message: string, opts?: ToastOpts): Cleanup;
148
-
149
- /**
150
- * Expand `[data-bronto-glyph="name"]` placeholders into a `.ui-dotmatrix`
151
- * grid of cells — the DOM counterpart to `renderGlyph` from
152
- * `@ponchia/ui/glyphs`. Decorative by default (`aria-hidden`); add
153
- * `data-bronto-glyph-label` to expose it as `role="img"`. Unknown glyph names
154
- * are left untouched. SSR-safe, idempotent (skips an already-expanded host).
155
- * Returns a cleanup that removes the cells and restores the original
156
- * attributes.
157
- */
158
- export declare function initDotGlyph(opts?: DelegateOpts): Cleanup;
159
-
160
- /** `bronto:legend:toggle` CustomEvent detail. `series` is the entry's
161
- * `data-series`, or its 0-based index when unset. `active` is the new state
162
- * (`true` ⇒ series shown). */
163
- export interface LegendToggleDetail {
164
- series: string | number;
165
- active: boolean;
166
- }
167
-
168
- /**
169
- * Wire `[data-bronto-legend]` interactive legends. Each `.ui-legend__item` is a
170
- * `<button aria-pressed>`; activating it flips `aria-pressed`, toggles
171
- * `.is-inactive`, and dispatches `bronto:legend:toggle`
172
- * ({@link LegendToggleDetail}) on the legend. Bronto owns the control + its
173
- * state only — the host hides its own series and owns any `aria-live`
174
- * announcement (`aria-pressed="true"` ⇒ series shown). SSR-safe, idempotent per
175
- * host. Returns a cleanup function.
176
- */
177
- export declare function initLegend(opts?: DelegateOpts): Cleanup;
178
-
179
- /**
180
- * Draw + keep leader lines in sync. Each `[data-bronto-connector]` is a
181
- * `.ui-connector` SVG overlaying a positioned container; `data-from`/`data-to`
182
- * are the ids of the elements to connect (with optional `data-shape`,
183
- * `data-from-side`/`data-to-side`, `data-end`). Computes geometry via the
184
- * `@ponchia/ui/connectors` helpers and redraws on resize/scroll. Bronto owns no
185
- * layout. SSR-safe, idempotent per host; returns a cleanup that disconnects
186
- * observers/listeners. Re-run after adding/removing connectors.
187
- */
188
- export declare function initConnectors(opts?: DelegateOpts): Cleanup;
189
-
190
- /**
191
- * Position a spotlight cutout over a target. Each `[data-bronto-spotlight]` is a
192
- * `.ui-spotlight` overlay; `data-target` is the id of the element to highlight.
193
- * Sets `--spot-x/y/w/h` and re-places on resize/scroll and when `data-target`
194
- * changes. NOT a tour engine — the host owns step order/advancing/visibility.
195
- * SSR-safe, idempotent per host; returns a cleanup function.
196
- */
197
- export declare function initSpotlight(opts?: DelegateOpts): Cleanup;
198
-
199
- /** `bronto:crosshair:move` CustomEvent detail — pointer position over the plot
200
- * in pixels and as 0..1 fractions. Bronto reports where; mapping to data is
201
- * the host's. */
202
- export interface CrosshairMoveDetail {
203
- x: number;
204
- y: number;
205
- fx: number;
206
- fy: number;
207
- }
208
-
209
- /**
210
- * Track the pointer over `[data-bronto-crosshair]` plots and drive a contained
211
- * `.ui-crosshair` overlay: sets `--crosshair-x/y` (px), marks `.is-active`, and
212
- * dispatches `bronto:crosshair:move` ({@link CrosshairMoveDetail}) /
213
- * `bronto:crosshair:leave`. Reports the pointer position only — it does not find
214
- * the nearest datum or map pixels to data. SSR-safe, idempotent per plot;
215
- * returns a cleanup function.
216
- */
217
- export declare function initCrosshair(opts?: DelegateOpts): Cleanup;
218
-
219
- /** `bronto:command:select` CustomEvent detail — the chosen command's value and
220
- * visible label. The host executes it; Bronto only filters and navigates. */
221
- export interface CommandSelectDetail {
222
- value: string;
223
- label: string;
224
- }
225
-
226
- /**
227
- * Filter + keyboard-navigate a DOM-authored command list inside
228
- * `[data-bronto-command]` (the `.ui-command` shell). Owns ids,
229
- * `role=combobox/listbox/option`, `aria-activedescendant`, a roving active item,
230
- * substring filtering (hiding empty groups), full keyboard
231
- * (Down/Up/Home/End/Enter/Escape), and pointer select. Emits
232
- * `bronto:command:select` ({@link CommandSelectDetail}) on choose and
233
- * `bronto:command:close` on Escape; the host owns the action registry, routing,
234
- * and execution. No global Cmd/Ctrl+K. SSR-safe, idempotent per instance;
235
- * returns a cleanup function.
236
- */
237
- export declare function initCommand(opts?: DelegateOpts): Cleanup;
1
+ export { dismissible } from "./dismissible.js";
2
+ export { initDisabledGuard } from "./inert.js";
3
+ export { initTabs } from "./tabs.js";
4
+ export { initDialog } from "./dialog.js";
5
+ export { initModal } from "./modal.js";
6
+ export { toast } from "./toast.js";
7
+ export { initDisclosure } from "./disclosure.js";
8
+ export { initMenu } from "./menu.js";
9
+ export { initFormValidation } from "./forms.js";
10
+ export { initCombobox } from "./combobox.js";
11
+ export { initPopover } from "./popover.js";
12
+ export { initTableSort } from "./table.js";
13
+ export { initCarousel } from "./carousel.js";
14
+ export { initDotGlyph } from "./glyph.js";
15
+ export { initLegend } from "./legend.js";
16
+ export { initConnectors } from "./connectors.js";
17
+ export { initSpotlight } from "./spotlight.js";
18
+ export { initCrosshair } from "./crosshair.js";
19
+ export { initCommand } from "./command.js";
20
+ export type Cleanup = import("./internal.js").Cleanup;
21
+ export type DelegateOpts = import("./internal.js").DelegateOpts;
22
+ export type ThemeStorageOpts = import("./theme.js").ThemeStorageOpts;
23
+ export type ApplyThemeOpts = import("./theme.js").ApplyThemeOpts;
24
+ export type ThemeChangeDetail = import("./theme.js").ThemeChangeDetail;
25
+ export type ToastOpts = import("./toast.js").ToastOpts;
26
+ export type ModalCloseDetail = import("./modal.js").ModalCloseDetail;
27
+ export type LegendToggleDetail = import("./legend.js").LegendToggleDetail;
28
+ export type CrosshairMoveDetail = import("./crosshair.js").CrosshairMoveDetail;
29
+ export type CommandSelectDetail = import("./command.js").CommandSelectDetail;
30
+ export { applyStoredTheme, initThemeToggle } from "./theme.js";
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;sBAmBa,OAAO,eAAe,EAAE,OAAO;2BAC/B,OAAO,eAAe,EAAE,YAAY;+BACpC,OAAO,YAAY,EAAE,gBAAgB;6BACrC,OAAO,YAAY,EAAE,cAAc;gCACnC,OAAO,YAAY,EAAE,iBAAiB;wBACtC,OAAO,YAAY,EAAE,SAAS;+BAC9B,OAAO,YAAY,EAAE,gBAAgB;iCACrC,OAAO,aAAa,EAAE,kBAAkB;kCACxC,OAAO,gBAAgB,EAAE,mBAAmB;kCAC5C,OAAO,cAAc,EAAE,mBAAmB"}