@ponchia/ui 0.6.6 → 0.6.8
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.
- package/CHANGELOG.md +175 -6
- package/README.md +38 -25
- package/annotations/index.d.ts.map +1 -1
- package/annotations/index.js +21 -3
- package/behaviors/carousel.d.ts.map +1 -1
- package/behaviors/carousel.js +91 -32
- package/behaviors/combobox.d.ts.map +1 -1
- package/behaviors/combobox.js +117 -43
- package/behaviors/command.d.ts.map +1 -1
- package/behaviors/command.js +74 -14
- package/behaviors/connectors.d.ts.map +1 -1
- package/behaviors/connectors.js +92 -9
- package/behaviors/crosshair.d.ts.map +1 -1
- package/behaviors/crosshair.js +47 -1
- package/behaviors/dialog.d.ts.map +1 -1
- package/behaviors/dialog.js +37 -16
- package/behaviors/disclosure.d.ts.map +1 -1
- package/behaviors/disclosure.js +33 -3
- package/behaviors/dismissible.d.ts.map +1 -1
- package/behaviors/dismissible.js +3 -2
- package/behaviors/forms.d.ts.map +1 -1
- package/behaviors/forms.js +78 -5
- package/behaviors/glyph.d.ts.map +1 -1
- package/behaviors/glyph.js +17 -2
- package/behaviors/index.d.ts +2 -0
- package/behaviors/index.d.ts.map +1 -1
- package/behaviors/index.js +2 -0
- package/behaviors/inert.js +3 -2
- package/behaviors/internal.d.ts +2 -1
- package/behaviors/internal.d.ts.map +1 -1
- package/behaviors/internal.js +25 -4
- package/behaviors/legend.d.ts +0 -5
- package/behaviors/legend.d.ts.map +1 -1
- package/behaviors/legend.js +78 -14
- package/behaviors/menu.d.ts.map +1 -1
- package/behaviors/menu.js +13 -8
- package/behaviors/modal.d.ts.map +1 -1
- package/behaviors/modal.js +77 -19
- package/behaviors/popover.d.ts +4 -3
- package/behaviors/popover.d.ts.map +1 -1
- package/behaviors/popover.js +89 -9
- package/behaviors/sources.d.ts.map +1 -1
- package/behaviors/sources.js +14 -2
- package/behaviors/splitter.d.ts +26 -0
- package/behaviors/splitter.d.ts.map +1 -0
- package/behaviors/splitter.js +239 -0
- package/behaviors/spotlight.d.ts.map +1 -1
- package/behaviors/spotlight.js +28 -2
- package/behaviors/table.d.ts.map +1 -1
- package/behaviors/table.js +105 -13
- package/behaviors/tabs.d.ts.map +1 -1
- package/behaviors/tabs.js +82 -18
- package/behaviors/theme.d.ts.map +1 -1
- package/behaviors/theme.js +26 -6
- package/classes/classes.json +230 -4
- package/classes/index.d.ts +64 -3
- package/classes/index.js +56 -2
- package/classes/vscode.css-custom-data.json +1 -1
- package/connectors/index.d.ts +39 -6
- package/connectors/index.d.ts.map +1 -1
- package/connectors/index.js +67 -9
- package/css/analytical.css +3 -1
- package/css/annotations.css +12 -0
- package/css/app.css +4 -4
- package/css/clamp.css +92 -0
- package/css/crosshair.css +27 -2
- package/css/feedback.css +2 -30
- package/css/figure.css +102 -0
- package/css/highlights.css +50 -0
- package/css/interval.css +90 -0
- package/css/navigation.css +12 -0
- package/css/primitives.css +2 -3
- package/css/report-kit.css +38 -0
- package/css/report.css +23 -4
- package/css/sidenote.css +12 -2
- package/css/site.css +2 -1
- package/css/sources.css +5 -0
- package/css/state.css +120 -1
- package/css/table.css +4 -0
- package/css/tokens.css +25 -9
- package/css/workbench.css +101 -8
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -1
- package/dist/css/annotations.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/clamp.css +1 -0
- package/dist/css/crosshair.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/figure.css +1 -0
- package/dist/css/highlights.css +1 -0
- package/dist/css/interval.css +1 -0
- package/dist/css/navigation.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report-kit.css +1 -0
- package/dist/css/report.css +1 -1
- package/dist/css/sidenote.css +1 -1
- package/dist/css/site.css +1 -1
- package/dist/css/sources.css +1 -1
- package/dist/css/state.css +1 -1
- package/dist/css/table.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -1
- package/docs/adr/0001-color-system.md +3 -2
- package/docs/adr/0002-scope-and-2026-baseline.md +1 -1
- package/docs/annotations.md +12 -1
- package/docs/architecture.md +105 -48
- package/docs/clamp.md +49 -0
- package/docs/command.md +4 -1
- package/docs/connectors.md +16 -0
- package/docs/contrast.md +34 -24
- package/docs/crosshair.md +1 -1
- package/docs/d2.md +37 -0
- package/docs/dots.md +4 -1
- package/docs/figure.md +71 -0
- package/docs/frontier-primitives.md +25 -24
- package/docs/glyphs.md +11 -0
- package/docs/highlights.md +52 -0
- package/docs/interop/tailwind.md +148 -0
- package/docs/interval.md +55 -0
- package/docs/legends.md +3 -2
- package/docs/mermaid.md +6 -0
- package/docs/migrations/0.2-to-0.3.md +80 -0
- package/docs/migrations/0.3-to-0.4.md +48 -0
- package/docs/migrations/0.4-to-0.5.md +96 -0
- package/docs/migrations/0.5-to-0.6.md +82 -0
- package/docs/package-contract.md +44 -6
- package/docs/reference.md +78 -5
- package/docs/reporting.md +126 -60
- package/docs/sidenote.md +7 -1
- package/docs/sources.md +1 -1
- package/docs/stability.md +23 -5
- package/docs/state.md +67 -10
- package/docs/theming.md +12 -4
- package/docs/usage.md +47 -13
- package/docs/vega.md +4 -4
- package/docs/workbench.md +59 -18
- package/llms.txt +89 -16
- package/package.json +82 -6
- package/qwik/index.d.ts +1 -0
- package/qwik/index.d.ts.map +1 -1
- package/qwik/index.js +26 -21
- package/react/index.d.ts +1 -0
- package/react/index.d.ts.map +1 -1
- package/react/index.js +4 -1
- package/schemas/report-claims.v1.schema.json +137 -0
- package/solid/index.d.ts +2 -0
- package/solid/index.d.ts.map +1 -1
- package/solid/index.js +3 -0
- package/svelte/index.d.ts +114 -0
- package/svelte/index.d.ts.map +1 -0
- package/svelte/index.js +193 -0
- package/tailwind.css +87 -0
- package/tokens/figma.variables.json +2241 -0
- package/tokens/index.js +1 -1
- package/tokens/index.json +2 -2
- package/tokens/resolved.json +3 -3
- package/tokens/tokens.dtcg.json +1 -1
- package/vue/index.d.ts +116 -0
- package/vue/index.d.ts.map +1 -0
- package/vue/index.js +228 -0
package/behaviors/disclosure.js
CHANGED
|
@@ -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
|
|
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 () =>
|
|
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,
|
|
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"}
|
package/behaviors/dismissible.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
};
|
package/behaviors/forms.d.ts.map
CHANGED
|
@@ -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,
|
|
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,CAsP3C"}
|
package/behaviors/forms.js
CHANGED
|
@@ -29,6 +29,59 @@ export function initFormValidation({ root } = {}) {
|
|
|
29
29
|
if (!hasDom()) return noop;
|
|
30
30
|
const host = resolveHost(root);
|
|
31
31
|
if (!host) return noop;
|
|
32
|
+
let priorNoValidate = new Map();
|
|
33
|
+
let controlState = new Map();
|
|
34
|
+
let slotState = new Map();
|
|
35
|
+
let summaryState = new Map();
|
|
36
|
+
|
|
37
|
+
const suppressNativeValidation = (form) => {
|
|
38
|
+
if (!priorNoValidate.has(form)) priorNoValidate.set(form, form.noValidate);
|
|
39
|
+
form.noValidate = true;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const snapshotAttrs = (el, names) => {
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const name of names) {
|
|
45
|
+
out[name] = {
|
|
46
|
+
had: el.hasAttribute(name),
|
|
47
|
+
value: el.getAttribute(name),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const restoreAttrs = (el, attrs) => {
|
|
54
|
+
for (const [name, attr] of Object.entries(attrs)) {
|
|
55
|
+
if (attr.had) el.setAttribute(name, attr.value);
|
|
56
|
+
else el.removeAttribute(name);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const rememberControl = (control) => {
|
|
61
|
+
if (!controlState.has(control)) {
|
|
62
|
+
controlState.set(control, snapshotAttrs(control, ['aria-invalid', 'aria-describedby', 'id']));
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const rememberSlot = (slot) => {
|
|
67
|
+
if (!slotState.has(slot)) {
|
|
68
|
+
slotState.set(slot, {
|
|
69
|
+
attrs: snapshotAttrs(slot, ['id']),
|
|
70
|
+
text: slot.textContent,
|
|
71
|
+
hadErrorClass: slot.classList.contains('ui-hint--error'),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const rememberSummary = (summary) => {
|
|
77
|
+
if (!summaryState.has(summary)) {
|
|
78
|
+
summaryState.set(summary, {
|
|
79
|
+
attrs: snapshotAttrs(summary, ['role', 'tabindex']),
|
|
80
|
+
children: [...summary.childNodes],
|
|
81
|
+
hidden: summary.hidden,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
32
85
|
|
|
33
86
|
const ensureId = (el, prefix) => {
|
|
34
87
|
if (!el.id) el.id = `${prefix}-${nextFieldUid()}`;
|
|
@@ -69,8 +122,10 @@ export function initFormValidation({ root } = {}) {
|
|
|
69
122
|
|
|
70
123
|
const validateField = (control) => {
|
|
71
124
|
if (!control.willValidate) return true;
|
|
125
|
+
rememberControl(control);
|
|
72
126
|
const ok = control.validity.valid;
|
|
73
127
|
const slot = slotFor(control);
|
|
128
|
+
if (slot) rememberSlot(slot);
|
|
74
129
|
// Decide the slot TYPE by the `[data-bronto-error]` attribute, NOT the
|
|
75
130
|
// `.ui-hint` class: the canonical markup is `<p class="ui-hint"
|
|
76
131
|
// data-bronto-error>`, which carries BOTH. Keying off `.ui-hint` sent that
|
|
@@ -118,6 +173,7 @@ export function initFormValidation({ root } = {}) {
|
|
|
118
173
|
const refreshSummary = (form, invalid) => {
|
|
119
174
|
const summary = form.querySelector('[data-bronto-error-summary]');
|
|
120
175
|
if (!summary) return;
|
|
176
|
+
rememberSummary(summary);
|
|
121
177
|
if (!invalid.length) {
|
|
122
178
|
summary.hidden = true;
|
|
123
179
|
summary.replaceChildren();
|
|
@@ -150,7 +206,7 @@ export function initFormValidation({ root } = {}) {
|
|
|
150
206
|
const onSubmit = (e) => {
|
|
151
207
|
const form = e.target.closest?.('[data-bronto-validate]');
|
|
152
208
|
if (!form) return;
|
|
153
|
-
form
|
|
209
|
+
suppressNativeValidation(form);
|
|
154
210
|
const invalid = controlsOf(form).filter((c) => !validateField(c));
|
|
155
211
|
refreshSummary(form, invalid);
|
|
156
212
|
if (invalid.length) {
|
|
@@ -165,7 +221,7 @@ export function initFormValidation({ root } = {}) {
|
|
|
165
221
|
if (!control.willValidate) return;
|
|
166
222
|
const form = control.closest?.('[data-bronto-validate]');
|
|
167
223
|
if (!form) return;
|
|
168
|
-
form
|
|
224
|
+
suppressNativeValidation(form);
|
|
169
225
|
validateField(control);
|
|
170
226
|
const summary = form.querySelector('[data-bronto-error-summary]');
|
|
171
227
|
if (summary && !summary.hidden)
|
|
@@ -183,10 +239,12 @@ export function initFormValidation({ root } = {}) {
|
|
|
183
239
|
// summary — contradicting the documented contract. (Forms added
|
|
184
240
|
// after init are still covered by the in-handler set.)
|
|
185
241
|
const forms = collectHosts(host, '[data-bronto-validate]');
|
|
186
|
-
|
|
242
|
+
priorNoValidate = new Map();
|
|
243
|
+
controlState = new Map();
|
|
244
|
+
slotState = new Map();
|
|
245
|
+
summaryState = new Map();
|
|
187
246
|
for (const f of forms) {
|
|
188
|
-
|
|
189
|
-
f.noValidate = true;
|
|
247
|
+
suppressNativeValidation(f);
|
|
190
248
|
}
|
|
191
249
|
host.addEventListener('submit', onSubmit, true);
|
|
192
250
|
host.addEventListener('focusout', onBlur);
|
|
@@ -194,6 +252,21 @@ export function initFormValidation({ root } = {}) {
|
|
|
194
252
|
host.removeEventListener('submit', onSubmit, true);
|
|
195
253
|
host.removeEventListener('focusout', onBlur);
|
|
196
254
|
for (const [f, v] of priorNoValidate) f.noValidate = v;
|
|
255
|
+
priorNoValidate.clear();
|
|
256
|
+
for (const [summary, state] of summaryState) {
|
|
257
|
+
summary.replaceChildren(...state.children);
|
|
258
|
+
summary.hidden = state.hidden;
|
|
259
|
+
restoreAttrs(summary, state.attrs);
|
|
260
|
+
}
|
|
261
|
+
summaryState.clear();
|
|
262
|
+
for (const [slot, state] of slotState) {
|
|
263
|
+
slot.textContent = state.text;
|
|
264
|
+
slot.classList.toggle('ui-hint--error', state.hadErrorClass);
|
|
265
|
+
restoreAttrs(slot, state.attrs);
|
|
266
|
+
}
|
|
267
|
+
slotState.clear();
|
|
268
|
+
for (const [control, attrs] of controlState) restoreAttrs(control, attrs);
|
|
269
|
+
controlState.clear();
|
|
197
270
|
};
|
|
198
271
|
});
|
|
199
272
|
}
|
package/behaviors/glyph.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["glyph.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["glyph.js"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA0J3C"}
|
package/behaviors/glyph.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { hasDom, resolveHost, noop, collectHosts } from './internal.js';
|
|
2
2
|
import { GLYPH_SIZE, glyphCells, glyphMask } from '../glyphs/glyphs.js';
|
|
3
3
|
|
|
4
|
+
const GLYPH_CLEANUP = Symbol('bronto-glyph-cleanup');
|
|
5
|
+
|
|
4
6
|
function restoreAttr(el, name, prev) {
|
|
5
7
|
if (prev === null) el.removeAttribute(name);
|
|
6
8
|
else el.setAttribute(name, prev);
|
|
7
9
|
}
|
|
8
10
|
|
|
11
|
+
function rememberCleanup(el, cleanups, cleanup) {
|
|
12
|
+
let done = false;
|
|
13
|
+
const wrapped = () => {
|
|
14
|
+
if (done) return;
|
|
15
|
+
done = true;
|
|
16
|
+
cleanup();
|
|
17
|
+
if (el[GLYPH_CLEANUP] === wrapped) delete el[GLYPH_CLEANUP];
|
|
18
|
+
};
|
|
19
|
+
el[GLYPH_CLEANUP] = wrapped;
|
|
20
|
+
cleanups.push(wrapped);
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
// `dot`/`gap`/`size` land in inline CSS, so allow only length/calc syntax —
|
|
10
24
|
// drop anything with a `;`/`{` that could open a second declaration (mirrors
|
|
11
25
|
// glyphs.js cssLen). Used for the mask path's --icon-size.
|
|
@@ -40,6 +54,7 @@ export function initDotGlyph({ root } = {}) {
|
|
|
40
54
|
const cleanups = [];
|
|
41
55
|
|
|
42
56
|
for (const el of els) {
|
|
57
|
+
el[GLYPH_CLEANUP]?.();
|
|
43
58
|
const name = el.getAttribute('data-bronto-glyph');
|
|
44
59
|
const label = el.getAttribute('data-bronto-glyph-label');
|
|
45
60
|
|
|
@@ -67,7 +82,7 @@ export function initDotGlyph({ root } = {}) {
|
|
|
67
82
|
el.setAttribute('aria-hidden', 'true');
|
|
68
83
|
}
|
|
69
84
|
|
|
70
|
-
cleanups
|
|
85
|
+
rememberCleanup(el, cleanups, () => {
|
|
71
86
|
if (!hadIcon) el.classList.remove('ui-icon');
|
|
72
87
|
if (hadMask) el.style.setProperty('--icon-mask', hadMask);
|
|
73
88
|
else el.style.removeProperty('--icon-mask');
|
|
@@ -159,7 +174,7 @@ export function initDotGlyph({ root } = {}) {
|
|
|
159
174
|
});
|
|
160
175
|
el.appendChild(frag);
|
|
161
176
|
|
|
162
|
-
cleanups
|
|
177
|
+
rememberCleanup(el, cleanups, () => {
|
|
163
178
|
el.querySelectorAll(':scope > .ui-dotmatrix__cell').forEach((n) => n.remove());
|
|
164
179
|
if (!hadMatrix) el.classList.remove('ui-dotmatrix');
|
|
165
180
|
if (animClass && !hadAnimClass) el.classList.remove(animClass);
|
package/behaviors/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export { initSpotlight } from "./spotlight.js";
|
|
|
18
18
|
export { initCrosshair } from "./crosshair.js";
|
|
19
19
|
export { initCommand } from "./command.js";
|
|
20
20
|
export { initSources } from "./sources.js";
|
|
21
|
+
export { initSplitter } from "./splitter.js";
|
|
21
22
|
export type Cleanup = import("./internal.js").Cleanup;
|
|
22
23
|
export type DelegateOpts = import("./internal.js").DelegateOpts;
|
|
23
24
|
export type ThemeStorageOpts = import("./theme.js").ThemeStorageOpts;
|
|
@@ -29,5 +30,6 @@ export type LegendToggleDetail = import("./legend.js").LegendToggleDetail;
|
|
|
29
30
|
export type CrosshairMoveDetail = import("./crosshair.js").CrosshairMoveDetail;
|
|
30
31
|
export type CommandSelectDetail = import("./command.js").CommandSelectDetail;
|
|
31
32
|
export type SourceFocusDetail = import("./sources.js").SourceFocusDetail;
|
|
33
|
+
export type SplitterResizeDetail = import("./splitter.js").SplitterResizeDetail;
|
|
32
34
|
export { applyStoredTheme, initThemeToggle } from "./theme.js";
|
|
33
35
|
//# sourceMappingURL=index.d.ts.map
|
package/behaviors/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"
|
|
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;gCAC1C,OAAO,cAAc,EAAE,iBAAiB;mCACxC,OAAO,eAAe,EAAE,oBAAoB"}
|
package/behaviors/index.js
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* @typedef {import('./crosshair.js').CrosshairMoveDetail} CrosshairMoveDetail
|
|
29
29
|
* @typedef {import('./command.js').CommandSelectDetail} CommandSelectDetail
|
|
30
30
|
* @typedef {import('./sources.js').SourceFocusDetail} SourceFocusDetail
|
|
31
|
+
* @typedef {import('./splitter.js').SplitterResizeDetail} SplitterResizeDetail
|
|
31
32
|
*/
|
|
32
33
|
export { applyStoredTheme, initThemeToggle } from './theme.js';
|
|
33
34
|
export { dismissible } from './dismissible.js';
|
|
@@ -50,3 +51,4 @@ export { initSpotlight } from './spotlight.js';
|
|
|
50
51
|
export { initCrosshair } from './crosshair.js';
|
|
51
52
|
export { initCommand } from './command.js';
|
|
52
53
|
export { initSources } from './sources.js';
|
|
54
|
+
export { initSplitter } from './splitter.js';
|
package/behaviors/inert.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasDom, resolveHost, noop, bindOnce } from './internal.js';
|
|
1
|
+
import { hasDom, resolveHost, noop, bindOnce, closestSafe } from './internal.js';
|
|
2
2
|
|
|
3
3
|
const DISABLED = '[aria-disabled="true"]';
|
|
4
4
|
|
|
@@ -25,9 +25,10 @@ export function initDisabledGuard({ root } = {}) {
|
|
|
25
25
|
const host = resolveHost(root);
|
|
26
26
|
if (!host) return noop;
|
|
27
27
|
const block = (e) => {
|
|
28
|
-
const el = e.target
|
|
28
|
+
const el = closestSafe(e.target, DISABLED);
|
|
29
29
|
if (el && host.contains(el)) {
|
|
30
30
|
e.preventDefault();
|
|
31
|
+
e.stopImmediatePropagation?.();
|
|
31
32
|
e.stopPropagation();
|
|
32
33
|
}
|
|
33
34
|
};
|
package/behaviors/internal.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ export type Cleanup = () => void;
|
|
|
19
19
|
export type DelegateOpts = {
|
|
20
20
|
/**
|
|
21
21
|
* Event-delegation root; also scopes which controls are queried. Default: `document`.
|
|
22
|
+
* `null` means a scope was requested but is not ready yet, so the behavior no-ops.
|
|
22
23
|
*/
|
|
23
|
-
root?: Document | Element | undefined;
|
|
24
|
+
root?: Document | Element | null | undefined;
|
|
24
25
|
};
|
|
25
26
|
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["internal.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["internal.js"],"names":[],"mappings":"AAiDA,iEAIC;AAeD,sEAUC;AAED,oDAQC;AAED,yDAOC;AAMD,8DAIC;AAID;;SAMC;AAUD,gDAQC;AAMD,+DAKC;AAlIM,6BAAqB;AAErB,kCAAoD;AAyCpD,uCAAqC;;;;;sBArD/B,MAAM,IAAI"}
|
package/behaviors/internal.js
CHANGED
|
@@ -9,16 +9,34 @@
|
|
|
9
9
|
* behavior's listeners/observers.
|
|
10
10
|
*
|
|
11
11
|
* @typedef {object} DelegateOpts
|
|
12
|
-
* @property {Document | Element} [root]
|
|
12
|
+
* @property {Document | Element | null} [root]
|
|
13
13
|
* Event-delegation root; also scopes which controls are queried. Default: `document`.
|
|
14
|
+
* `null` means a scope was requested but is not ready yet, so the behavior no-ops.
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
export const noop = () => {};
|
|
17
18
|
|
|
18
19
|
export const hasDom = () => typeof document !== 'undefined';
|
|
19
20
|
|
|
21
|
+
function isDelegationHost(value) {
|
|
22
|
+
if (!value || typeof value !== 'object') return false;
|
|
23
|
+
if (value.nodeType === 9) {
|
|
24
|
+
return (
|
|
25
|
+
typeof value.addEventListener === 'function' && typeof value.querySelectorAll === 'function'
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
if (value.nodeType === 1) {
|
|
29
|
+
return (
|
|
30
|
+
typeof value.addEventListener === 'function' &&
|
|
31
|
+
typeof value.matches === 'function' &&
|
|
32
|
+
typeof value.querySelectorAll === 'function'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
// Resolve the delegation host from an init call's `root` option, distinguishing
|
|
21
|
-
//
|
|
39
|
+
// cases so an unattached/null root never silently widens to whole-document
|
|
22
40
|
// delegation (the "scoped island hijacks every control" foot-gun):
|
|
23
41
|
// • root absent/undefined → no scope requested → delegate from `fallback`
|
|
24
42
|
// (default `document`). This is the intended global-wiring path.
|
|
@@ -26,11 +44,13 @@ export const hasDom = () => typeof document !== 'undefined';
|
|
|
26
44
|
// framework ref still null at mount). Return null so the caller no-ops
|
|
27
45
|
// instead of hijacking the whole document.
|
|
28
46
|
// • root is an element → use it.
|
|
47
|
+
// • root is anything else → no-op; the public contract is Document | Element.
|
|
29
48
|
// The bindings (@ponchia/ui/{react,solid,qwik}) emit `root: null` for the
|
|
30
49
|
// not-ready case precisely so this distinction survives across the boundary.
|
|
31
50
|
export function resolveHost(root, fallback = document) {
|
|
32
51
|
if (root === null) return null;
|
|
33
|
-
|
|
52
|
+
if (root === undefined) return isDelegationHost(fallback) ? fallback : null;
|
|
53
|
+
return isDelegationHost(root) ? root : null;
|
|
34
54
|
}
|
|
35
55
|
|
|
36
56
|
// Monotonic counter for auto-minted field / list ids, shared across
|
|
@@ -70,7 +90,8 @@ export function byIdInHost(host, id) {
|
|
|
70
90
|
|
|
71
91
|
export function closestSafe(el, selector) {
|
|
72
92
|
try {
|
|
73
|
-
|
|
93
|
+
const start = el?.nodeType === 1 ? el : el?.parentElement;
|
|
94
|
+
return start?.closest?.(selector) ?? null;
|
|
74
95
|
} catch {
|
|
75
96
|
return null;
|
|
76
97
|
}
|
package/behaviors/legend.d.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {object} LegendToggleDetail
|
|
3
|
-
* @property {string | number} series The entry's `data-series`, or its 0-based index when unset.
|
|
4
|
-
* @property {boolean} active The new state (`true` ⇒ series shown).
|
|
5
|
-
*/
|
|
6
1
|
/**
|
|
7
2
|
* Wire `[data-bronto-legend]` interactive legends. Each entry is a
|
|
8
3
|
* `.ui-legend__item` authored as a `<button aria-pressed>`; clicking it (or
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legend.d.ts","sourceRoot":"","sources":["legend.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"legend.d.ts","sourceRoot":"","sources":["legend.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;GAiBG;AACH,sCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAiH3C;;;;;YAvIa,MAAM,GAAG,MAAM;;;;YACf,OAAO"}
|
package/behaviors/legend.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasDom, resolveHost, noop, bindOnce } from './internal.js';
|
|
1
|
+
import { hasDom, resolveHost, noop, bindOnce, collectHosts, closestSafe } from './internal.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @typedef {object} LegendToggleDetail
|
|
@@ -6,6 +6,8 @@ import { hasDom, resolveHost, noop, bindOnce } from './internal.js';
|
|
|
6
6
|
* @property {boolean} active The new state (`true` ⇒ series shown).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
const handledEvents = new WeakSet();
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Wire `[data-bronto-legend]` interactive legends. Each entry is a
|
|
11
13
|
* `.ui-legend__item` authored as a `<button aria-pressed>`; clicking it (or
|
|
@@ -28,16 +30,40 @@ export function initLegend({ root } = {}) {
|
|
|
28
30
|
if (!hasDom()) return noop;
|
|
29
31
|
const host = resolveHost(root);
|
|
30
32
|
if (!host) return noop;
|
|
33
|
+
const snapshotAttrs = (el, names) => {
|
|
34
|
+
const attrs = {};
|
|
35
|
+
for (const name of names) {
|
|
36
|
+
attrs[name] = {
|
|
37
|
+
had: el.hasAttribute(name),
|
|
38
|
+
value: el.getAttribute(name),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return attrs;
|
|
42
|
+
};
|
|
43
|
+
const restoreAttrs = (el, attrs) => {
|
|
44
|
+
for (const [name, state] of Object.entries(attrs)) {
|
|
45
|
+
if (state.had) el.setAttribute(name, state.value);
|
|
46
|
+
else el.removeAttribute(name);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const directItems = (legend) =>
|
|
50
|
+
[...legend.querySelectorAll('.ui-legend__item')].filter(
|
|
51
|
+
(el) => el.closest('[data-bronto-legend]') === legend,
|
|
52
|
+
);
|
|
31
53
|
const isButton = (el) => el.tagName === 'BUTTON' || el.getAttribute('role') === 'button';
|
|
32
|
-
const
|
|
33
|
-
const item = e.target.closest('.ui-legend__item');
|
|
54
|
+
const legendFor = (item) => {
|
|
34
55
|
if (!item || !host.contains(item)) return;
|
|
35
56
|
const legend = item.closest('[data-bronto-legend]');
|
|
36
57
|
if (!legend || !host.contains(legend)) return;
|
|
58
|
+
return legend;
|
|
59
|
+
};
|
|
60
|
+
const toggle = (item) => {
|
|
61
|
+
const legend = legendFor(item);
|
|
62
|
+
if (!legend) return false;
|
|
37
63
|
// The contract requires a real `<button>` (keyboard-operable, focusable). A
|
|
38
|
-
// non-button item is mouse-only
|
|
39
|
-
//
|
|
40
|
-
if (!isButton(item)) return;
|
|
64
|
+
// non-button item is mouse-only unless role=button is keyboard-normalized
|
|
65
|
+
// below — refuse anything else rather than ship a pointer-only control.
|
|
66
|
+
if (!isButton(item)) return false;
|
|
41
67
|
const active = item.getAttribute('aria-pressed') !== 'false';
|
|
42
68
|
const next = !active;
|
|
43
69
|
item.setAttribute('aria-pressed', String(next));
|
|
@@ -53,24 +79,62 @@ export function initLegend({ root } = {}) {
|
|
|
53
79
|
detail: { series: item.dataset.series ?? items.indexOf(item), active: next },
|
|
54
80
|
}),
|
|
55
81
|
);
|
|
82
|
+
return true;
|
|
83
|
+
};
|
|
84
|
+
const onClick = (e) => {
|
|
85
|
+
if (handledEvents.has(e)) return;
|
|
86
|
+
if (toggle(closestSafe(e.target, '.ui-legend__item'))) handledEvents.add(e);
|
|
87
|
+
};
|
|
88
|
+
const onKey = (e) => {
|
|
89
|
+
if (handledEvents.has(e)) return;
|
|
90
|
+
if (e.key !== 'Enter' && e.key !== ' ') return;
|
|
91
|
+
const item = closestSafe(e.target, '.ui-legend__item');
|
|
92
|
+
if (!item || item.tagName === 'BUTTON' || item.getAttribute('role') !== 'button') return;
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
if (toggle(item)) handledEvents.add(e);
|
|
56
95
|
};
|
|
57
96
|
return bindOnce(host, 'legend', () => {
|
|
58
|
-
//
|
|
59
|
-
//
|
|
97
|
+
// Normalize role=button entries and warn once per unsupported non-button
|
|
98
|
+
// item present at bind. A real <button> remains the recommended markup.
|
|
99
|
+
const legends = collectHosts(host, '[data-bronto-legend]');
|
|
100
|
+
const itemStates = [];
|
|
101
|
+
for (const legend of legends) {
|
|
102
|
+
for (const el of directItems(legend)) {
|
|
103
|
+
itemStates.push({
|
|
104
|
+
el,
|
|
105
|
+
attrs: snapshotAttrs(el, ['type', 'tabindex', 'aria-pressed']),
|
|
106
|
+
inactive: el.classList.contains('is-inactive'),
|
|
107
|
+
});
|
|
108
|
+
if (el.tagName === 'BUTTON' && !el.hasAttribute('type')) el.setAttribute('type', 'button');
|
|
109
|
+
if (
|
|
110
|
+
el.tagName !== 'BUTTON' &&
|
|
111
|
+
el.getAttribute('role') === 'button' &&
|
|
112
|
+
!el.hasAttribute('tabindex')
|
|
113
|
+
) {
|
|
114
|
+
el.tabIndex = 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
60
118
|
if (typeof console !== 'undefined') {
|
|
61
|
-
for (const legend of
|
|
62
|
-
const stray =
|
|
63
|
-
(el) => el.closest('[data-bronto-legend]') === legend && !isButton(el),
|
|
64
|
-
);
|
|
119
|
+
for (const legend of legends) {
|
|
120
|
+
const stray = directItems(legend).some((el) => !isButton(el));
|
|
65
121
|
if (stray) {
|
|
66
122
|
console.warn(
|
|
67
|
-
'[bronto] initLegend(): interactive legend entries must be <button>
|
|
123
|
+
'[bronto] initLegend(): interactive legend entries must be <button> or role="button" — unsupported .ui-legend__item controls are ignored.',
|
|
68
124
|
);
|
|
69
125
|
break;
|
|
70
126
|
}
|
|
71
127
|
}
|
|
72
128
|
}
|
|
73
129
|
host.addEventListener('click', onClick);
|
|
74
|
-
|
|
130
|
+
host.addEventListener('keydown', onKey);
|
|
131
|
+
return () => {
|
|
132
|
+
host.removeEventListener('click', onClick);
|
|
133
|
+
host.removeEventListener('keydown', onKey);
|
|
134
|
+
for (const state of itemStates) {
|
|
135
|
+
restoreAttrs(state.el, state.attrs);
|
|
136
|
+
state.el.classList.toggle('is-inactive', state.inactive);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
75
139
|
});
|
|
76
140
|
}
|
package/behaviors/menu.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["menu.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,oCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["menu.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,oCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAwC3C"}
|
package/behaviors/menu.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasDom, resolveHost, noop, bindOnce } from './internal.js';
|
|
1
|
+
import { hasDom, resolveHost, noop, bindOnce, closestSafe, collectHosts } from './internal.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Dropdown-menu close affordances for a native `<details data-bronto-menu>`
|
|
@@ -18,32 +18,37 @@ export function initMenu({ root } = {}) {
|
|
|
18
18
|
if (!hasDom()) return noop;
|
|
19
19
|
const host = resolveHost(root);
|
|
20
20
|
if (!host) return noop;
|
|
21
|
-
const
|
|
21
|
+
const doc = host.nodeType === 9 ? host : host.ownerDocument || document;
|
|
22
|
+
const openMenus = () => collectHosts(host, '[data-bronto-menu][open]');
|
|
22
23
|
const shut = (menu) => {
|
|
23
24
|
if (!menu || !menu.open) return;
|
|
24
25
|
menu.open = false;
|
|
25
26
|
menu.querySelector('summary')?.focus();
|
|
26
27
|
};
|
|
27
28
|
const onClick = (e) => {
|
|
28
|
-
const
|
|
29
|
+
const target = e.target;
|
|
30
|
+
const menu = closestSafe(target, '[data-bronto-menu]');
|
|
29
31
|
// Activate an item → close its menu (and return focus to summary).
|
|
30
|
-
if (menu &&
|
|
32
|
+
if (menu && host.contains(menu) && closestSafe(target, '.ui-menu__item')) {
|
|
31
33
|
shut(menu);
|
|
32
34
|
return;
|
|
33
35
|
}
|
|
34
36
|
// Click outside any open menu → close them all (no focus move).
|
|
35
|
-
for (const m of openMenus()) if (!m.contains(
|
|
37
|
+
for (const m of openMenus()) if (!m.contains(target)) m.open = false;
|
|
36
38
|
};
|
|
37
39
|
const onKey = (e) => {
|
|
38
40
|
if (e.key !== 'Escape') return;
|
|
39
|
-
const menu = e.target
|
|
41
|
+
const menu = closestSafe(e.target, '[data-bronto-menu][open]') || openMenus()[0];
|
|
42
|
+
if (!menu) return;
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
e.stopPropagation();
|
|
40
45
|
shut(menu);
|
|
41
46
|
};
|
|
42
47
|
return bindOnce(host, 'menu', () => {
|
|
43
|
-
|
|
48
|
+
doc.addEventListener('click', onClick);
|
|
44
49
|
host.addEventListener('keydown', onKey);
|
|
45
50
|
return () => {
|
|
46
|
-
|
|
51
|
+
doc.removeEventListener('click', onClick);
|
|
47
52
|
host.removeEventListener('keydown', onKey);
|
|
48
53
|
};
|
|
49
54
|
});
|
package/behaviors/modal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["modal.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["modal.js"],"names":[],"mappings":"AAsDA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA+F3C;;;;;YA7Ha,QAAQ"}
|