@ponchia/ui 0.6.7 → 0.6.9

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 (111) hide show
  1. package/CHANGELOG.md +129 -4
  2. package/README.md +4 -4
  3. package/annotations/index.d.ts.map +1 -1
  4. package/annotations/index.js +26 -9
  5. package/behaviors/carousel.d.ts.map +1 -1
  6. package/behaviors/carousel.js +145 -49
  7. package/behaviors/combobox.d.ts.map +1 -1
  8. package/behaviors/combobox.js +220 -92
  9. package/behaviors/command.d.ts.map +1 -1
  10. package/behaviors/command.js +74 -14
  11. package/behaviors/connectors.d.ts.map +1 -1
  12. package/behaviors/connectors.js +131 -32
  13. package/behaviors/crosshair.d.ts.map +1 -1
  14. package/behaviors/crosshair.js +47 -1
  15. package/behaviors/dialog.d.ts.map +1 -1
  16. package/behaviors/dialog.js +24 -9
  17. package/behaviors/disclosure.d.ts.map +1 -1
  18. package/behaviors/disclosure.js +33 -3
  19. package/behaviors/dismissible.d.ts.map +1 -1
  20. package/behaviors/dismissible.js +3 -2
  21. package/behaviors/forms.d.ts.map +1 -1
  22. package/behaviors/forms.js +211 -140
  23. package/behaviors/glyph.d.ts.map +1 -1
  24. package/behaviors/glyph.js +172 -132
  25. package/behaviors/inert.d.ts +1 -1
  26. package/behaviors/inert.d.ts.map +1 -1
  27. package/behaviors/inert.js +4 -3
  28. package/behaviors/internal.d.ts.map +1 -1
  29. package/behaviors/internal.js +4 -3
  30. package/behaviors/legend.d.ts +0 -5
  31. package/behaviors/legend.d.ts.map +1 -1
  32. package/behaviors/legend.js +45 -13
  33. package/behaviors/menu.d.ts.map +1 -1
  34. package/behaviors/menu.js +13 -8
  35. package/behaviors/modal.d.ts.map +1 -1
  36. package/behaviors/modal.js +77 -19
  37. package/behaviors/popover.d.ts +4 -3
  38. package/behaviors/popover.d.ts.map +1 -1
  39. package/behaviors/popover.js +94 -14
  40. package/behaviors/sources.d.ts.map +1 -1
  41. package/behaviors/sources.js +14 -2
  42. package/behaviors/splitter.d.ts.map +1 -1
  43. package/behaviors/splitter.js +149 -110
  44. package/behaviors/spotlight.d.ts.map +1 -1
  45. package/behaviors/spotlight.js +28 -2
  46. package/behaviors/table.d.ts +1 -1
  47. package/behaviors/table.d.ts.map +1 -1
  48. package/behaviors/table.js +108 -17
  49. package/behaviors/tabs.d.ts.map +1 -1
  50. package/behaviors/tabs.js +84 -20
  51. package/behaviors/theme.d.ts.map +1 -1
  52. package/behaviors/theme.js +25 -5
  53. package/behaviors/toast.js +5 -5
  54. package/classes/index.d.ts +15 -2
  55. package/classes/index.js +48 -35
  56. package/connectors/index.d.ts +41 -8
  57. package/connectors/index.d.ts.map +1 -1
  58. package/connectors/index.js +74 -19
  59. package/css/annotations.css +12 -0
  60. package/css/app.css +3 -4
  61. package/css/base.css +1 -1
  62. package/css/content.css +3 -3
  63. package/css/crosshair.css +27 -2
  64. package/css/disclosure.css +3 -3
  65. package/css/dots.css +4 -4
  66. package/css/feedback.css +8 -37
  67. package/css/forms.css +9 -12
  68. package/css/legend.css +1 -1
  69. package/css/marks.css +1 -1
  70. package/css/motion.css +6 -6
  71. package/css/navigation.css +12 -0
  72. package/css/overlay.css +5 -7
  73. package/css/primitives.css +14 -16
  74. package/css/sidenote.css +2 -2
  75. package/css/table.css +2 -2
  76. package/css/tokens.css +16 -0
  77. package/dist/bronto.css +1 -1
  78. package/dist/css/analytical.css +1 -1
  79. package/dist/css/annotations.css +1 -1
  80. package/dist/css/crosshair.css +1 -1
  81. package/dist/css/feedback.css +1 -1
  82. package/dist/css/navigation.css +1 -1
  83. package/dist/css/report-kit.css +1 -1
  84. package/dist/css/tokens.css +1 -1
  85. package/docs/adr/0001-color-system.md +3 -2
  86. package/docs/annotations.md +21 -1
  87. package/docs/architecture.md +74 -13
  88. package/docs/command.md +4 -1
  89. package/docs/connectors.md +16 -0
  90. package/docs/crosshair.md +1 -1
  91. package/docs/dots.md +4 -1
  92. package/docs/glyphs.md +11 -0
  93. package/docs/interop/react-flow.md +89 -0
  94. package/docs/migrations/0.2-to-0.3.md +1 -1
  95. package/docs/package-contract.md +7 -5
  96. package/docs/reporting.md +23 -12
  97. package/docs/stability.md +85 -9
  98. package/docs/theming.md +2 -2
  99. package/docs/usage.md +16 -2
  100. package/docs/vega.md +4 -4
  101. package/glyphs/glyphs.js +43 -33
  102. package/llms.txt +19 -8
  103. package/package.json +23 -4
  104. package/schemas/report-claims.v1.schema.json +1 -1
  105. package/svelte/index.d.ts +71 -45
  106. package/svelte/index.d.ts.map +1 -1
  107. package/svelte/index.js +29 -2
  108. package/tokens/index.js +2 -2
  109. package/vue/index.d.ts +42 -5
  110. package/vue/index.d.ts.map +1 -1
  111. package/vue/index.js +32 -1
@@ -2,6 +2,80 @@ import { hasDom, resolveHost, noop, bindOnce, byIdInHost, collectHosts } from '.
2
2
  import { connectRects, arrowHead, dotMark } from '../connectors/index.js';
3
3
 
4
4
  const SVGNS = 'http://www.w3.org/2000/svg';
5
+ const NORMALIZED_PATH_LENGTH = '1';
6
+ const END_DOT_RADIUS = 3;
7
+ const END_ARROW_SIZE = 8;
8
+
9
+ const snapshotAttrs = (el) =>
10
+ Array.from(el.attributes, ({ name, value }) => ({
11
+ name,
12
+ value,
13
+ }));
14
+
15
+ const restoreAttrs = (el, attrs) => {
16
+ for (const { name } of Array.from(el.attributes)) el.removeAttribute(name);
17
+ for (const { name, value } of attrs) el.setAttribute(name, value);
18
+ };
19
+
20
+ const snapshotPart = (svg, selector) => {
21
+ const node = svg.querySelector(selector);
22
+ if (!node) return { node: null };
23
+ return {
24
+ node,
25
+ attrs: snapshotAttrs(node),
26
+ parent: node.parentNode,
27
+ nextSibling: node.nextSibling,
28
+ textContent: node.textContent,
29
+ };
30
+ };
31
+
32
+ const restorePart = (svg, selector, state) => {
33
+ if (!state.node) {
34
+ svg.querySelector(selector)?.remove();
35
+ return;
36
+ }
37
+
38
+ const parent = state.parent || svg;
39
+ if (state.node.parentNode !== parent) {
40
+ const before = state.nextSibling?.parentNode === parent ? state.nextSibling : null;
41
+ parent.insertBefore(state.node, before);
42
+ }
43
+ restoreAttrs(state.node, state.attrs);
44
+ state.node.textContent = state.textContent;
45
+ };
46
+
47
+ const upsertConnectorPart = (svg, selector, className) => {
48
+ let part = svg.querySelector(selector);
49
+ if (part) return part;
50
+ part = document.createElementNS(SVGNS, 'path');
51
+ part.setAttribute('class', className);
52
+ svg.appendChild(part);
53
+ return part;
54
+ };
55
+
56
+ const syncDrawPathLength = (svg, path) => {
57
+ // pathLength normalises the draw animation, but it would also reframe a
58
+ // dashed line's user-unit dasharray — so only set it for draw connectors.
59
+ if (svg.classList.contains('ui-connector--draw')) {
60
+ path.setAttribute('pathLength', NORMALIZED_PATH_LENGTH);
61
+ } else {
62
+ path.removeAttribute('pathLength');
63
+ }
64
+ };
65
+
66
+ const syncConnectorEnd = (svg, end, angle) => {
67
+ const kind = svg.dataset.end || 'arrow';
68
+ const cap = svg.querySelector('.ui-connector__end');
69
+ if (kind === 'none') {
70
+ cap?.remove();
71
+ return;
72
+ }
73
+ const next = cap || upsertConnectorPart(svg, '.ui-connector__end', 'ui-connector__end');
74
+ next.setAttribute(
75
+ 'd',
76
+ kind === 'dot' ? dotMark(end, END_DOT_RADIUS) : arrowHead(end, angle, END_ARROW_SIZE),
77
+ );
78
+ };
5
79
 
6
80
  /**
7
81
  * Draw + keep leader lines in sync. Each `[data-bronto-connector]` is an
@@ -22,58 +96,79 @@ export function initConnectors({ root } = {}) {
22
96
  if (!hasDom()) return noop;
23
97
  const host = resolveHost(root);
24
98
  if (!host) return noop;
25
- const connectors = collectHosts(host, '[data-bronto-connector]');
26
- if (!connectors.length) return noop;
99
+
100
+ const fallbackRect = (svg, el) => {
101
+ const origin = svg.getBoundingClientRect();
102
+ const r = el.getBoundingClientRect();
103
+ const scaleX = origin.width ? (svg.clientWidth || origin.width) / origin.width : 1;
104
+ const scaleY = origin.height ? (svg.clientHeight || origin.height) / origin.height : 1;
105
+ return {
106
+ x: (r.left - origin.left) * scaleX,
107
+ y: (r.top - origin.top) * scaleY,
108
+ width: r.width * scaleX,
109
+ height: r.height * scaleY,
110
+ };
111
+ };
112
+
113
+ const rectInSvg = (svg, el) => {
114
+ const r = el.getBoundingClientRect();
115
+ const matrix = svg.getScreenCTM?.();
116
+ const view = svg.ownerDocument?.defaultView;
117
+ const Point = view?.DOMPoint;
118
+ if (!matrix || !Point) return fallbackRect(svg, el);
119
+
120
+ try {
121
+ const inverse = matrix.inverse();
122
+ const corners = [
123
+ new Point(r.left, r.top),
124
+ new Point(r.right, r.top),
125
+ new Point(r.right, r.bottom),
126
+ new Point(r.left, r.bottom),
127
+ ].map((point) => point.matrixTransform(inverse));
128
+ const xs = corners.map((point) => point.x);
129
+ const ys = corners.map((point) => point.y);
130
+ const left = Math.min(...xs);
131
+ const right = Math.max(...xs);
132
+ const top = Math.min(...ys);
133
+ const bottom = Math.max(...ys);
134
+ return { x: left, y: top, width: right - left, height: bottom - top };
135
+ } catch {
136
+ return fallbackRect(svg, el);
137
+ }
138
+ };
27
139
 
28
140
  const draw = () => {
141
+ const connectors = collectHosts(host, '[data-bronto-connector]');
29
142
  for (const svg of connectors) {
30
143
  const from = byIdInHost(host, svg.dataset.from);
31
144
  const to = byIdInHost(host, svg.dataset.to);
32
145
  if (!from || !to) continue;
33
- const o = svg.getBoundingClientRect();
34
- const rel = (el) => {
35
- const r = el.getBoundingClientRect();
36
- return { x: r.left - o.left, y: r.top - o.top, width: r.width, height: r.height };
37
- };
38
146
  const {
39
147
  d,
40
148
  to: end,
41
149
  angle,
42
150
  } = connectRects({
43
- fromRect: rel(from),
44
- toRect: rel(to),
151
+ fromRect: rectInSvg(svg, from),
152
+ toRect: rectInSvg(svg, to),
45
153
  shape: svg.dataset.shape || 'straight',
46
154
  fromSide: svg.dataset.fromSide || undefined,
47
155
  toSide: svg.dataset.toSide || undefined,
48
156
  });
49
- let path = svg.querySelector('.ui-connector__path');
50
- if (!path) {
51
- path = document.createElementNS(SVGNS, 'path');
52
- path.setAttribute('class', 'ui-connector__path');
53
- svg.appendChild(path);
54
- }
157
+ const path = upsertConnectorPart(svg, '.ui-connector__path', 'ui-connector__path');
55
158
  path.setAttribute('d', d);
56
- // pathLength="1" normalises the draw animation, but it would also reframe
57
- // a dashed line's user-unit dasharray — so only set it for draw connectors.
58
- if (svg.classList.contains('ui-connector--draw')) path.setAttribute('pathLength', '1');
59
- else path.removeAttribute('pathLength');
60
-
61
- const kind = svg.dataset.end || 'arrow';
62
- let cap = svg.querySelector('.ui-connector__end');
63
- if (kind === 'none') {
64
- cap?.remove();
65
- continue;
66
- }
67
- if (!cap) {
68
- cap = document.createElementNS(SVGNS, 'path');
69
- cap.setAttribute('class', 'ui-connector__end');
70
- svg.appendChild(cap);
71
- }
72
- cap.setAttribute('d', kind === 'dot' ? dotMark(end, 3) : arrowHead(end, angle, 8));
159
+ syncDrawPathLength(svg, path);
160
+ syncConnectorEnd(svg, end, angle);
73
161
  }
74
162
  };
75
163
 
76
164
  return bindOnce(host, 'connectors', () => {
165
+ const connectors = collectHosts(host, '[data-bronto-connector]');
166
+ if (!connectors.length) return noop;
167
+ const states = connectors.map((svg) => ({
168
+ svg,
169
+ path: snapshotPart(svg, '.ui-connector__path'),
170
+ end: snapshotPart(svg, '.ui-connector__end'),
171
+ }));
77
172
  draw();
78
173
  const view = host.defaultView || host.ownerDocument?.defaultView || null;
79
174
  const RO = view?.ResizeObserver;
@@ -93,6 +188,10 @@ export function initConnectors({ root } = {}) {
93
188
  ro?.disconnect();
94
189
  view?.removeEventListener('resize', draw);
95
190
  view?.removeEventListener('scroll', draw, true);
191
+ for (const state of states) {
192
+ restorePart(state.svg, '.ui-connector__path', state.path);
193
+ restorePart(state.svg, '.ui-connector__end', state.end);
194
+ }
96
195
  };
97
196
  });
98
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"crosshair.d.ts","sourceRoot":"","sources":["crosshair.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AACH,yCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAmD3C;;;;;OAtEa,MAAM;;;;OACN,MAAM;;;;QACN,MAAM;;;;QACN,MAAM"}
1
+ {"version":3,"file":"crosshair.d.ts","sourceRoot":"","sources":["crosshair.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AACH,yCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAiG3C;;;;;OApHa,MAAM;;;;OACN,MAAM;;;;QACN,MAAM;;;;QACN,MAAM"}
@@ -33,8 +33,49 @@ export function initCrosshair({ root } = {}) {
33
33
  const cleanups = [];
34
34
  for (const plot of plots) {
35
35
  const overlay = plot.querySelector('.ui-crosshair');
36
- if (!overlay) continue;
36
+ let overlayState = null;
37
+ const rememberOverlay = () => {
38
+ if (!overlay || overlayState) return;
39
+ overlayState = {
40
+ active: overlay.classList.contains('is-active'),
41
+ x: {
42
+ value: overlay.style.getPropertyValue('--crosshair-x'),
43
+ priority: overlay.style.getPropertyPriority('--crosshair-x'),
44
+ },
45
+ y: {
46
+ value: overlay.style.getPropertyValue('--crosshair-y'),
47
+ priority: overlay.style.getPropertyPriority('--crosshair-y'),
48
+ },
49
+ inline: {
50
+ had: overlay.hasAttribute('data-readout-inline'),
51
+ value: overlay.getAttribute('data-readout-inline'),
52
+ },
53
+ block: {
54
+ had: overlay.hasAttribute('data-readout-block'),
55
+ value: overlay.getAttribute('data-readout-block'),
56
+ },
57
+ };
58
+ };
59
+ const restoreData = (name, state) => {
60
+ if (state.had) overlay.setAttribute(name, state.value);
61
+ else overlay.removeAttribute(name);
62
+ };
63
+ const restoreOverlay = () => {
64
+ if (!overlay || !overlayState) return;
65
+ overlay.classList.toggle('is-active', overlayState.active);
66
+ if (overlayState.x.value)
67
+ overlay.style.setProperty('--crosshair-x', overlayState.x.value, overlayState.x.priority);
68
+ else overlay.style.removeProperty('--crosshair-x');
69
+ if (overlayState.y.value)
70
+ overlay.style.setProperty('--crosshair-y', overlayState.y.value, overlayState.y.priority);
71
+ else overlay.style.removeProperty('--crosshair-y');
72
+ restoreData('data-readout-inline', overlayState.inline);
73
+ restoreData('data-readout-block', overlayState.block);
74
+ overlayState = null;
75
+ };
37
76
  const onMove = (e) => {
77
+ if (!overlay) return;
78
+ rememberOverlay();
38
79
  const r = plot.getBoundingClientRect();
39
80
  if (!r.width || !r.height) return;
40
81
  const x = e.clientX - r.left;
@@ -48,6 +89,8 @@ export function initCrosshair({ root } = {}) {
48
89
  const rtl = getComputedStyle(plot).direction === 'rtl';
49
90
  overlay.style.setProperty('--crosshair-x', `${rtl ? r.right - e.clientX : x}px`);
50
91
  overlay.style.setProperty('--crosshair-y', `${y}px`);
92
+ overlay.dataset.readoutInline = x / r.width > 0.5 ? 'before' : 'after';
93
+ overlay.dataset.readoutBlock = y / r.height > 0.5 ? 'above' : 'below';
51
94
  overlay.classList.add('is-active');
52
95
  plot.dispatchEvent(
53
96
  new CustomEvent('bronto:crosshair:move', {
@@ -57,16 +100,19 @@ export function initCrosshair({ root } = {}) {
57
100
  );
58
101
  };
59
102
  const onLeave = () => {
103
+ if (!overlay) return;
60
104
  overlay.classList.remove('is-active');
61
105
  plot.dispatchEvent(new CustomEvent('bronto:crosshair:leave', { bubbles: true }));
62
106
  };
63
107
  cleanups.push(
64
108
  bindOnce(plot, 'crosshair', () => {
109
+ if (!overlay) return noop;
65
110
  plot.addEventListener('pointermove', onMove);
66
111
  plot.addEventListener('pointerleave', onLeave);
67
112
  return () => {
68
113
  plot.removeEventListener('pointermove', onMove);
69
114
  plot.removeEventListener('pointerleave', onLeave);
115
+ restoreOverlay();
70
116
  };
71
117
  }),
72
118
  );
@@ -1 +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,CAgE3C"}
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,CA+E3C"}
@@ -28,20 +28,32 @@ export function initDialog({ root } = {}) {
28
28
 
29
29
  const openFrom = (opener) => {
30
30
  const dlg = byIdInHost(host, opener.getAttribute('data-bronto-open'));
31
- if (!dlg || typeof dlg.showModal !== 'function' || dlg.open) return;
32
- managedDialogs.add(dlg);
31
+ if (!dlg || typeof dlg.showModal !== 'function' || dlg.open) return false;
32
+ const previous = focusRestorers.get(dlg);
33
+ if (previous) {
34
+ dlg.removeEventListener('close', previous);
35
+ focusRestorers.delete(dlg);
36
+ }
33
37
  const restoreFocus = () => {
34
38
  focusRestorers.delete(dlg);
35
39
  if (opener.isConnected && typeof opener.focus === 'function') opener.focus();
36
40
  };
41
+ try {
42
+ dlg.showModal();
43
+ } catch {
44
+ return false;
45
+ }
46
+ managedDialogs.add(dlg);
37
47
  focusRestorers.set(dlg, restoreFocus);
38
48
  dlg.addEventListener('close', restoreFocus, { once: true });
39
- dlg.showModal();
49
+ return true;
40
50
  };
41
51
 
42
52
  const closeFrom = (closer) => {
43
53
  const dlg = closer.closest('dialog');
44
- if (dlg && dlg.open && canManageDialog(dlg, closer)) dlg.close();
54
+ if (!dlg || !dlg.open || !canManageDialog(dlg, closer)) return false;
55
+ dlg.close();
56
+ return true;
45
57
  };
46
58
 
47
59
  const lightDismiss = (dlg) => {
@@ -52,23 +64,26 @@ export function initDialog({ root } = {}) {
52
64
  canManageDialog(dlg, dlg)
53
65
  ) {
54
66
  dlg.close();
67
+ return true;
55
68
  }
69
+ return false;
56
70
  };
57
71
 
58
72
  const onClick = (e) => {
59
- const opener = e.target.closest('[data-bronto-open]');
73
+ const target = e.target;
74
+ const opener = target?.closest?.('[data-bronto-open]');
60
75
  if (opener && host.contains(opener)) {
61
- openFrom(opener);
76
+ if (openFrom(opener)) e.preventDefault();
62
77
  return;
63
78
  }
64
- const closer = e.target.closest('[data-bronto-close]');
79
+ const closer = target?.closest?.('[data-bronto-close]');
65
80
  if (closer) {
66
- closeFrom(closer);
81
+ if (closeFrom(closer)) e.preventDefault();
67
82
  return;
68
83
  }
69
84
  // Light-dismiss: a click whose target is the <dialog> itself is the
70
85
  // backdrop (content sits in child elements).
71
- lightDismiss(e.target);
86
+ if (lightDismiss(target)) e.preventDefault();
72
87
  };
73
88
  return bindOnce(host, 'dialog', () => {
74
89
  document.addEventListener('click', onClick);
@@ -1 +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"}
1
+ {"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["disclosure.js"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,0CAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAwC3C"}
@@ -1,4 +1,14 @@
1
- import { hasDom, resolveHost, noop, bindOnce, byIdInHost } from './internal.js';
1
+ import { hasDom, resolveHost, noop, bindOnce, byIdInHost, closestSafe } from './internal.js';
2
+
3
+ const snapshotAttr = (el, name) => ({
4
+ had: el.hasAttribute(name),
5
+ value: el.getAttribute(name),
6
+ });
7
+
8
+ const restoreAttr = (el, name, state) => {
9
+ if (state.had) el.setAttribute(name, state.value);
10
+ else el.removeAttribute(name);
11
+ };
2
12
 
3
13
  /**
4
14
  * Disclosure: a `[data-bronto-disclosure]` trigger toggles the element
@@ -12,18 +22,38 @@ export function initDisclosure({ root } = {}) {
12
22
  if (!hasDom()) return noop;
13
23
  const host = resolveHost(root);
14
24
  if (!host) return noop;
25
+ const triggerStates = new Map();
26
+ const panelStates = new Map();
27
+
28
+ const remember = (trigger, panel) => {
29
+ if (!triggerStates.has(trigger)) {
30
+ triggerStates.set(trigger, snapshotAttr(trigger, 'aria-expanded'));
31
+ }
32
+ if (!panelStates.has(panel)) {
33
+ panelStates.set(panel, snapshotAttr(panel, 'hidden'));
34
+ }
35
+ };
36
+
15
37
  const onClick = (e) => {
16
- const trigger = e.target.closest('[data-bronto-disclosure]');
38
+ const trigger = closestSafe(e.target, '[data-bronto-disclosure]');
17
39
  if (!trigger || !host.contains(trigger)) return;
18
40
  const id = trigger.getAttribute('aria-controls');
19
41
  const panel = byIdInHost(host, id);
20
42
  if (!panel) return;
43
+ e.preventDefault();
44
+ remember(trigger, panel);
21
45
  const open = trigger.getAttribute('aria-expanded') === 'true';
22
46
  trigger.setAttribute('aria-expanded', String(!open));
23
47
  panel.hidden = open;
24
48
  };
25
49
  return bindOnce(host, 'disclosure', () => {
26
50
  host.addEventListener('click', onClick);
27
- return () => host.removeEventListener('click', onClick);
51
+ return () => {
52
+ host.removeEventListener('click', onClick);
53
+ for (const [trigger, state] of triggerStates) restoreAttr(trigger, 'aria-expanded', state);
54
+ triggerStates.clear();
55
+ for (const [panel, state] of panelStates) restoreAttr(panel, 'hidden', state);
56
+ panelStates.clear();
57
+ };
28
58
  });
29
59
  }
@@ -1 +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"}
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,CAoB3C"}
@@ -13,11 +13,12 @@ export function dismissible({ root } = {}) {
13
13
  const host = resolveHost(root);
14
14
  if (!host) return noop;
15
15
  const onClick = (e) => {
16
- const btn = e.target.closest('[data-bronto-dismiss]');
16
+ const btn = closestSafe(e.target, '[data-bronto-dismiss]');
17
17
  if (!btn || !host.contains(btn)) return;
18
18
  const sel = btn.getAttribute('data-bronto-dismiss');
19
- const target = sel ? closestSafe(btn, sel) : btn.closest('[data-bronto-dismissible]');
19
+ const target = sel ? closestSafe(btn, sel) : closestSafe(btn, '[data-bronto-dismissible]');
20
20
  if (!target) return;
21
+ e.preventDefault();
21
22
  const ev = new CustomEvent('bronto:dismiss', { bubbles: true, cancelable: true });
22
23
  if (target.dispatchEvent(ev)) target.remove();
23
24
  };
@@ -1 +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,CAmL3C"}
1
+ {"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["forms.js"],"names":[],"mappings":"AAiMA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,8CAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA2D3C"}