@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.
- package/CHANGELOG.md +129 -4
- package/README.md +4 -4
- package/annotations/index.d.ts.map +1 -1
- package/annotations/index.js +26 -9
- package/behaviors/carousel.d.ts.map +1 -1
- package/behaviors/carousel.js +145 -49
- package/behaviors/combobox.d.ts.map +1 -1
- package/behaviors/combobox.js +220 -92
- 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 +131 -32
- 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 +24 -9
- 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 +211 -140
- package/behaviors/glyph.d.ts.map +1 -1
- package/behaviors/glyph.js +172 -132
- package/behaviors/inert.d.ts +1 -1
- package/behaviors/inert.d.ts.map +1 -1
- package/behaviors/inert.js +4 -3
- package/behaviors/internal.d.ts.map +1 -1
- package/behaviors/internal.js +4 -3
- package/behaviors/legend.d.ts +0 -5
- package/behaviors/legend.d.ts.map +1 -1
- package/behaviors/legend.js +45 -13
- 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 +94 -14
- package/behaviors/sources.d.ts.map +1 -1
- package/behaviors/sources.js +14 -2
- package/behaviors/splitter.d.ts.map +1 -1
- package/behaviors/splitter.js +149 -110
- package/behaviors/spotlight.d.ts.map +1 -1
- package/behaviors/spotlight.js +28 -2
- package/behaviors/table.d.ts +1 -1
- package/behaviors/table.d.ts.map +1 -1
- package/behaviors/table.js +108 -17
- package/behaviors/tabs.d.ts.map +1 -1
- package/behaviors/tabs.js +84 -20
- package/behaviors/theme.d.ts.map +1 -1
- package/behaviors/theme.js +25 -5
- package/behaviors/toast.js +5 -5
- package/classes/index.d.ts +15 -2
- package/classes/index.js +48 -35
- package/connectors/index.d.ts +41 -8
- package/connectors/index.d.ts.map +1 -1
- package/connectors/index.js +74 -19
- package/css/annotations.css +12 -0
- package/css/app.css +3 -4
- package/css/base.css +1 -1
- package/css/content.css +3 -3
- package/css/crosshair.css +27 -2
- package/css/disclosure.css +3 -3
- package/css/dots.css +4 -4
- package/css/feedback.css +8 -37
- package/css/forms.css +9 -12
- package/css/legend.css +1 -1
- package/css/marks.css +1 -1
- package/css/motion.css +6 -6
- package/css/navigation.css +12 -0
- package/css/overlay.css +5 -7
- package/css/primitives.css +14 -16
- package/css/sidenote.css +2 -2
- package/css/table.css +2 -2
- package/css/tokens.css +16 -0
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -1
- package/dist/css/annotations.css +1 -1
- package/dist/css/crosshair.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/navigation.css +1 -1
- package/dist/css/report-kit.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/docs/adr/0001-color-system.md +3 -2
- package/docs/annotations.md +21 -1
- package/docs/architecture.md +74 -13
- package/docs/command.md +4 -1
- package/docs/connectors.md +16 -0
- package/docs/crosshair.md +1 -1
- package/docs/dots.md +4 -1
- package/docs/glyphs.md +11 -0
- package/docs/interop/react-flow.md +89 -0
- package/docs/migrations/0.2-to-0.3.md +1 -1
- package/docs/package-contract.md +7 -5
- package/docs/reporting.md +23 -12
- package/docs/stability.md +85 -9
- package/docs/theming.md +2 -2
- package/docs/usage.md +16 -2
- package/docs/vega.md +4 -4
- package/glyphs/glyphs.js +43 -33
- package/llms.txt +19 -8
- package/package.json +23 -4
- package/schemas/report-claims.v1.schema.json +1 -1
- package/svelte/index.d.ts +71 -45
- package/svelte/index.d.ts.map +1 -1
- package/svelte/index.js +29 -2
- package/tokens/index.js +2 -2
- package/vue/index.d.ts +42 -5
- package/vue/index.d.ts.map +1 -1
- package/vue/index.js +32 -1
package/behaviors/modal.js
CHANGED
|
@@ -1,4 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasDom,
|
|
3
|
+
resolveHost,
|
|
4
|
+
noop,
|
|
5
|
+
bindOnce,
|
|
6
|
+
collectHosts,
|
|
7
|
+
focusInto,
|
|
8
|
+
closestSafe,
|
|
9
|
+
} from './internal.js';
|
|
10
|
+
|
|
11
|
+
function insideOpenPopover(target, modal) {
|
|
12
|
+
const classPanel = closestSafe(target, '.ui-popover.is-open');
|
|
13
|
+
if (classPanel && modal.contains(classPanel)) return true;
|
|
14
|
+
|
|
15
|
+
const nativePanel = closestSafe(target, '[popover]');
|
|
16
|
+
if (!nativePanel || !modal.contains(nativePanel)) return false;
|
|
17
|
+
try {
|
|
18
|
+
return nativePanel.matches(':popover-open');
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const activeModals = [];
|
|
25
|
+
|
|
26
|
+
const snapshotAttrs = (el, names) => {
|
|
27
|
+
const attrs = {};
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
attrs[name] = {
|
|
30
|
+
had: el.hasAttribute(name),
|
|
31
|
+
value: el.getAttribute(name),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return attrs;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const restoreAttrs = (el, attrs) => {
|
|
38
|
+
for (const [name, state] of Object.entries(attrs)) {
|
|
39
|
+
if (state.had) el.setAttribute(name, state.value);
|
|
40
|
+
else el.removeAttribute(name);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const pushActiveModal = (modal) => {
|
|
45
|
+
const index = activeModals.indexOf(modal);
|
|
46
|
+
if (index !== -1) activeModals.splice(index, 1);
|
|
47
|
+
activeModals.push(modal);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const removeActiveModal = (modal) => {
|
|
51
|
+
const index = activeModals.indexOf(modal);
|
|
52
|
+
if (index !== -1) activeModals.splice(index, 1);
|
|
53
|
+
};
|
|
2
54
|
|
|
3
55
|
/**
|
|
4
56
|
* @typedef {object} ModalCloseDetail
|
|
@@ -45,22 +97,6 @@ export function initModal({ root } = {}) {
|
|
|
45
97
|
let opener = null;
|
|
46
98
|
let inerted = [];
|
|
47
99
|
|
|
48
|
-
// A controlled modal must announce AS a modal dialog, not a generic group —
|
|
49
|
-
// parity with initPopover. Apply a dialog role + aria-modal (unless the
|
|
50
|
-
// author set a role), and dev-warn on a missing accessible name since we
|
|
51
|
-
// can't invent a good one. (component audit C13.)
|
|
52
|
-
if (!modal.hasAttribute('role')) modal.setAttribute('role', 'dialog');
|
|
53
|
-
if (!modal.hasAttribute('aria-modal')) modal.setAttribute('aria-modal', 'true');
|
|
54
|
-
const named =
|
|
55
|
-
modal.hasAttribute('aria-label') ||
|
|
56
|
-
modal.hasAttribute('aria-labelledby') ||
|
|
57
|
-
modal.hasAttribute('title');
|
|
58
|
-
if (!named && typeof console !== 'undefined') {
|
|
59
|
-
console.warn(
|
|
60
|
-
`[bronto] initModal(): a [data-bronto-modal] has no accessible name — add aria-label or aria-labelledby so it is announced as a named dialog.`,
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
100
|
// Inert every sibling at each ancestor level up to <body>: the rest of the
|
|
65
101
|
// page becomes non-focusable/non-interactive while the modal subtree stays
|
|
66
102
|
// live. Skip already-inert nodes so release() can't un-inert something the
|
|
@@ -68,6 +104,7 @@ export function initModal({ root } = {}) {
|
|
|
68
104
|
const trap = () => {
|
|
69
105
|
if (opener) return; // already trapped
|
|
70
106
|
opener = document.activeElement;
|
|
107
|
+
pushActiveModal(modal);
|
|
71
108
|
let el = modal;
|
|
72
109
|
while (el && el.parentElement && el !== document.body) {
|
|
73
110
|
for (const sib of el.parentElement.children) {
|
|
@@ -83,6 +120,7 @@ export function initModal({ root } = {}) {
|
|
|
83
120
|
|
|
84
121
|
const release = () => {
|
|
85
122
|
if (!opener) return;
|
|
123
|
+
removeActiveModal(modal);
|
|
86
124
|
for (const el of inerted) el.inert = false;
|
|
87
125
|
inerted = [];
|
|
88
126
|
const back = opener;
|
|
@@ -94,6 +132,8 @@ export function initModal({ root } = {}) {
|
|
|
94
132
|
|
|
95
133
|
const onKey = (e) => {
|
|
96
134
|
if (e.key === 'Escape' && opener) {
|
|
135
|
+
if (activeModals.at(-1) !== modal) return;
|
|
136
|
+
if (insideOpenPopover(e.target, modal)) return;
|
|
97
137
|
modal.dispatchEvent(
|
|
98
138
|
new CustomEvent('bronto:modal:close', {
|
|
99
139
|
detail: { reason: 'escape' },
|
|
@@ -104,10 +144,27 @@ export function initModal({ root } = {}) {
|
|
|
104
144
|
}
|
|
105
145
|
};
|
|
106
146
|
|
|
107
|
-
const observer = typeof MutationObserver === 'function' ? new MutationObserver(sync) : null;
|
|
108
|
-
|
|
109
147
|
cleanups.push(
|
|
110
148
|
bindOnce(modal, 'modal', () => {
|
|
149
|
+
const attrs = snapshotAttrs(modal, ['role', 'aria-modal', 'tabindex']);
|
|
150
|
+
|
|
151
|
+
// A controlled modal must announce AS a modal dialog, not a generic group —
|
|
152
|
+
// parity with initPopover. Apply a dialog role + aria-modal (unless the
|
|
153
|
+
// author set a role), and dev-warn on a missing accessible name since we
|
|
154
|
+
// can't invent a good one.
|
|
155
|
+
if (!modal.hasAttribute('role')) modal.setAttribute('role', 'dialog');
|
|
156
|
+
if (!modal.hasAttribute('aria-modal')) modal.setAttribute('aria-modal', 'true');
|
|
157
|
+
const named =
|
|
158
|
+
modal.hasAttribute('aria-label') ||
|
|
159
|
+
modal.hasAttribute('aria-labelledby') ||
|
|
160
|
+
modal.hasAttribute('title');
|
|
161
|
+
if (!named && typeof console !== 'undefined') {
|
|
162
|
+
console.warn(
|
|
163
|
+
`[bronto] initModal(): a [data-bronto-modal] has no accessible name — add aria-label or aria-labelledby so it is announced as a named dialog.`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const observer = typeof MutationObserver === 'function' ? new MutationObserver(sync) : null;
|
|
111
168
|
observer?.observe(modal, { attributes: true, attributeFilter: ['class'] });
|
|
112
169
|
document.addEventListener('keydown', onKey, true);
|
|
113
170
|
if (modal.classList.contains('is-open')) trap(); // already open at init
|
|
@@ -115,6 +172,7 @@ export function initModal({ root } = {}) {
|
|
|
115
172
|
observer?.disconnect();
|
|
116
173
|
document.removeEventListener('keydown', onKey, true);
|
|
117
174
|
release();
|
|
175
|
+
restoreAttrs(modal, attrs);
|
|
118
176
|
};
|
|
119
177
|
}),
|
|
120
178
|
);
|
package/behaviors/popover.d.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Collision-aware popover, dependency-free. A `[data-bronto-popover]`
|
|
3
3
|
* trigger toggles the `.ui-popover` panel whose id it names. The panel
|
|
4
4
|
* is placed under the trigger and **flips above** when it would
|
|
5
|
-
* overflow the viewport, with its inline edge clamped on-screen
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* overflow the viewport, with its inline edge clamped on-screen and tall
|
|
6
|
+
* panels constrained to scroll inside the viewport — the thing the CSS-only
|
|
7
|
+
* tooltip can't do near edges / inside scroll containers. If the panel has
|
|
8
|
+
* the native `popover` attribute and the
|
|
8
9
|
* Popover API is available it is shown in the top layer (never
|
|
9
10
|
* clipped); otherwise an `.is-open` class is toggled. Manages
|
|
10
11
|
* `aria-expanded` / `aria-controls`, closes on Escape and outside
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["popover.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["popover.js"],"names":[],"mappings":"AAuCA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,uCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAkM3C"}
|
package/behaviors/popover.js
CHANGED
|
@@ -1,12 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasDom,
|
|
3
|
+
resolveHost,
|
|
4
|
+
noop,
|
|
5
|
+
bindOnce,
|
|
6
|
+
byIdInHost,
|
|
7
|
+
focusInto,
|
|
8
|
+
collectHosts,
|
|
9
|
+
closestSafe,
|
|
10
|
+
} from './internal.js';
|
|
11
|
+
|
|
12
|
+
const snapshotAttrs = (el, names) => {
|
|
13
|
+
const attrs = {};
|
|
14
|
+
for (const name of names) {
|
|
15
|
+
attrs[name] = {
|
|
16
|
+
had: el.hasAttribute(name),
|
|
17
|
+
value: el.getAttribute(name),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return attrs;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const restoreAttrs = (el, attrs) => {
|
|
24
|
+
for (const [name, state] of Object.entries(attrs)) {
|
|
25
|
+
if (state.had) el.setAttribute(name, state.value);
|
|
26
|
+
else el.removeAttribute(name);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const snapshotStyle = (el, names) => {
|
|
31
|
+
const styles = {};
|
|
32
|
+
for (const name of names) styles[name] = el.style[name];
|
|
33
|
+
return styles;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const restoreStyle = (el, styles) => {
|
|
37
|
+
for (const [name, value] of Object.entries(styles)) el.style[name] = value;
|
|
38
|
+
};
|
|
2
39
|
|
|
3
40
|
/**
|
|
4
41
|
* Collision-aware popover, dependency-free. A `[data-bronto-popover]`
|
|
5
42
|
* trigger toggles the `.ui-popover` panel whose id it names. The panel
|
|
6
43
|
* is placed under the trigger and **flips above** when it would
|
|
7
|
-
* overflow the viewport, with its inline edge clamped on-screen
|
|
8
|
-
*
|
|
9
|
-
*
|
|
44
|
+
* overflow the viewport, with its inline edge clamped on-screen and tall
|
|
45
|
+
* panels constrained to scroll inside the viewport — the thing the CSS-only
|
|
46
|
+
* tooltip can't do near edges / inside scroll containers. If the panel has
|
|
47
|
+
* the native `popover` attribute and the
|
|
10
48
|
* Popover API is available it is shown in the top layer (never
|
|
11
49
|
* clipped); otherwise an `.is-open` class is toggled. Manages
|
|
12
50
|
* `aria-expanded` / `aria-controls`, closes on Escape and outside
|
|
@@ -34,19 +72,48 @@ export function initPopover({ root } = {}) {
|
|
|
34
72
|
const GAP = 8;
|
|
35
73
|
let openPanel = null;
|
|
36
74
|
let openTrigger = null;
|
|
75
|
+
const triggerStates = new Map();
|
|
76
|
+
const panelStates = new Map();
|
|
77
|
+
|
|
78
|
+
const rememberTrigger = (trigger) => {
|
|
79
|
+
if (!triggerStates.has(trigger)) {
|
|
80
|
+
triggerStates.set(
|
|
81
|
+
trigger,
|
|
82
|
+
snapshotAttrs(trigger, ['aria-haspopup', 'aria-controls', 'aria-expanded']),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const rememberPanel = (panel) => {
|
|
88
|
+
if (!panelStates.has(panel)) {
|
|
89
|
+
panelStates.set(panel, {
|
|
90
|
+
attrs: snapshotAttrs(panel, ['role', 'tabindex']),
|
|
91
|
+
open: panel.classList.contains('is-open'),
|
|
92
|
+
style: snapshotStyle(panel, ['maxBlockSize', 'top', 'left']),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
37
96
|
|
|
38
|
-
// The trigger advertises `aria-haspopup="dialog"`, so the open panel must
|
|
39
|
-
// dialog: a role, an accessible name, and focus moved into it
|
|
40
|
-
// shared `focusInto` in internal.js.
|
|
97
|
+
// The trigger advertises `aria-haspopup="dialog"`, so the open panel must be
|
|
98
|
+
// a dialog: a role, an accessible name, and focus moved into it. See the
|
|
99
|
+
// shared `focusInto` helper in internal.js.
|
|
41
100
|
|
|
42
101
|
const place = (trigger, panel) => {
|
|
43
102
|
const r = trigger.getBoundingClientRect();
|
|
103
|
+
panel.style.maxBlockSize = 'none';
|
|
44
104
|
const pw = panel.offsetWidth;
|
|
45
|
-
const ph = panel.offsetHeight;
|
|
105
|
+
const ph = Math.max(panel.offsetHeight, panel.scrollHeight);
|
|
46
106
|
const vw = view?.innerWidth ?? 0;
|
|
47
107
|
const vh = view?.innerHeight ?? 0;
|
|
48
|
-
|
|
49
|
-
|
|
108
|
+
const maxHeight = Math.max(0, vh - GAP * 2);
|
|
109
|
+
const below = Math.max(0, vh - r.bottom - GAP * 2);
|
|
110
|
+
const above = Math.max(0, r.top - GAP * 2);
|
|
111
|
+
const placeAbove = ph > below && above > below;
|
|
112
|
+
const available = placeAbove ? above : below;
|
|
113
|
+
const height = Math.min(ph, available || maxHeight);
|
|
114
|
+
panel.style.maxBlockSize = `${height}px`;
|
|
115
|
+
let top = placeAbove ? r.top - GAP - height : r.bottom + GAP;
|
|
116
|
+
if (vh) top = Math.max(GAP, Math.min(top, vh - height - GAP));
|
|
50
117
|
let left = r.left;
|
|
51
118
|
if (vw) left = Math.max(GAP, Math.min(left, vw - pw - GAP));
|
|
52
119
|
panel.style.top = `${Math.max(GAP, top)}px`;
|
|
@@ -77,9 +144,11 @@ export function initPopover({ root } = {}) {
|
|
|
77
144
|
|
|
78
145
|
const open = (trigger, panel) => {
|
|
79
146
|
close();
|
|
147
|
+
rememberTrigger(trigger);
|
|
148
|
+
rememberPanel(panel);
|
|
80
149
|
// Live up to the advertised `aria-haspopup="dialog"`: give the panel a
|
|
81
150
|
// dialog role (unless the author set one) so AT announces it as the promised
|
|
82
|
-
// dialog rather than a generic group
|
|
151
|
+
// dialog rather than a generic group.
|
|
83
152
|
if (!panel.hasAttribute('role')) panel.setAttribute('role', 'dialog');
|
|
84
153
|
trigger.setAttribute('aria-controls', panel.id);
|
|
85
154
|
trigger.setAttribute('aria-expanded', 'true');
|
|
@@ -99,7 +168,7 @@ export function initPopover({ root } = {}) {
|
|
|
99
168
|
};
|
|
100
169
|
|
|
101
170
|
const onClick = (e) => {
|
|
102
|
-
const trigger = e.target
|
|
171
|
+
const trigger = closestSafe(e.target, '[data-bronto-popover]');
|
|
103
172
|
if (trigger && host.contains(trigger)) {
|
|
104
173
|
const panel = byIdInHost(host, trigger.getAttribute('data-bronto-popover'));
|
|
105
174
|
if (!panel) return;
|
|
@@ -133,14 +202,16 @@ export function initPopover({ root } = {}) {
|
|
|
133
202
|
// never routes through close(), so aria-expanded would otherwise go stale).
|
|
134
203
|
const seedTeardowns = [];
|
|
135
204
|
const seed = () => {
|
|
136
|
-
for (const trigger of host
|
|
205
|
+
for (const trigger of collectHosts(host, '[data-bronto-popover]')) {
|
|
137
206
|
const panel = byIdInHost(host, trigger.getAttribute('data-bronto-popover'));
|
|
138
207
|
if (!panel) continue;
|
|
208
|
+
rememberTrigger(trigger);
|
|
209
|
+
rememberPanel(panel);
|
|
139
210
|
if (!trigger.hasAttribute('aria-haspopup')) trigger.setAttribute('aria-haspopup', 'dialog');
|
|
140
211
|
trigger.setAttribute('aria-controls', panel.id);
|
|
141
212
|
if (!trigger.hasAttribute('aria-expanded')) trigger.setAttribute('aria-expanded', 'false');
|
|
142
213
|
// A dialog with no accessible name is announced as just "dialog". We can't
|
|
143
|
-
// invent a good name, so warn the author at dev time
|
|
214
|
+
// invent a good name, so warn the author at dev time.
|
|
144
215
|
const named =
|
|
145
216
|
panel.hasAttribute('aria-label') ||
|
|
146
217
|
panel.hasAttribute('aria-labelledby') ||
|
|
@@ -169,7 +240,16 @@ export function initPopover({ root } = {}) {
|
|
|
169
240
|
view?.addEventListener('scroll', onReflow, true);
|
|
170
241
|
view?.addEventListener('resize', onReflow);
|
|
171
242
|
return () => {
|
|
243
|
+
close();
|
|
172
244
|
for (const t of seedTeardowns.splice(0)) t();
|
|
245
|
+
for (const [trigger, attrs] of triggerStates) restoreAttrs(trigger, attrs);
|
|
246
|
+
triggerStates.clear();
|
|
247
|
+
for (const [panel, state] of panelStates) {
|
|
248
|
+
restoreAttrs(panel, state.attrs);
|
|
249
|
+
panel.classList.toggle('is-open', state.open);
|
|
250
|
+
restoreStyle(panel, state.style);
|
|
251
|
+
}
|
|
252
|
+
panelStates.clear();
|
|
173
253
|
document.removeEventListener('click', onClick);
|
|
174
254
|
document.removeEventListener('keydown', onKey);
|
|
175
255
|
view?.removeEventListener('scroll', onReflow, true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["sources.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["sources.js"],"names":[],"mappings":"AA4CA;;;;;;;;;;;GAWG;AACH,uCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAmH3C;;;;;QA5Ja,MAAM;;;;cACN,OAAO;;;;YACP,OAAO"}
|
package/behaviors/sources.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
byIdInHost,
|
|
7
7
|
collectHosts,
|
|
8
8
|
scrollIntoViewSafe,
|
|
9
|
+
closestSafe,
|
|
9
10
|
} from './internal.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -64,6 +65,7 @@ export function initSources({ root } = {}) {
|
|
|
64
65
|
for (const island of islands) {
|
|
65
66
|
const timers = new Set();
|
|
66
67
|
const seeded = [];
|
|
68
|
+
const activeSources = new Set();
|
|
67
69
|
|
|
68
70
|
const targetFor = (ref) => {
|
|
69
71
|
const id = sourceId(ref);
|
|
@@ -101,17 +103,25 @@ export function initSources({ root } = {}) {
|
|
|
101
103
|
}
|
|
102
104
|
};
|
|
103
105
|
|
|
106
|
+
const clearGeneratedActive = () => {
|
|
107
|
+
for (const source of activeSources) source.classList.remove(ACTIVE);
|
|
108
|
+
activeSources.clear();
|
|
109
|
+
};
|
|
110
|
+
|
|
104
111
|
const focusSource = (ref, source) => {
|
|
105
112
|
for (const card of island.querySelectorAll(`.${ACTIVE}`)) card.classList.remove(ACTIVE);
|
|
113
|
+
clearGeneratedActive();
|
|
106
114
|
for (const timer of timers) clearTimeout(timer);
|
|
107
115
|
timers.clear();
|
|
108
116
|
|
|
109
117
|
source.classList.add(ACTIVE);
|
|
118
|
+
activeSources.add(source);
|
|
110
119
|
source.focus?.({ preventScroll: true });
|
|
111
120
|
scrollIntoViewSafe(source);
|
|
112
121
|
|
|
113
122
|
const timer = setTimeout(() => {
|
|
114
123
|
source.classList.remove(ACTIVE);
|
|
124
|
+
activeSources.delete(source);
|
|
115
125
|
timers.delete(timer);
|
|
116
126
|
}, 1600);
|
|
117
127
|
timers.add(timer);
|
|
@@ -125,7 +135,7 @@ export function initSources({ root } = {}) {
|
|
|
125
135
|
};
|
|
126
136
|
|
|
127
137
|
const onClick = (e) => {
|
|
128
|
-
const ref = e.target
|
|
138
|
+
const ref = closestSafe(e.target, REF_SELECTOR);
|
|
129
139
|
if (!ref || !island.contains(ref)) return;
|
|
130
140
|
const source = targetFor(ref);
|
|
131
141
|
if (!source) return;
|
|
@@ -134,12 +144,14 @@ export function initSources({ root } = {}) {
|
|
|
134
144
|
};
|
|
135
145
|
|
|
136
146
|
const cleanup = bindOnce(island, 'sources', () => {
|
|
147
|
+
const activeState = Array.from(island.querySelectorAll(`.${ACTIVE}`));
|
|
137
148
|
seed();
|
|
138
149
|
island.addEventListener('click', onClick);
|
|
139
150
|
return () => {
|
|
140
151
|
island.removeEventListener('click', onClick);
|
|
141
152
|
for (const timer of timers) clearTimeout(timer);
|
|
142
153
|
timers.clear();
|
|
154
|
+
clearGeneratedActive();
|
|
143
155
|
for (const item of seeded.splice(0)) {
|
|
144
156
|
if (item.hadDescribedBy) item.ref.setAttribute('aria-describedby', item.describedBy);
|
|
145
157
|
else item.ref.removeAttribute('aria-describedby');
|
|
@@ -147,7 +159,7 @@ export function initSources({ root } = {}) {
|
|
|
147
159
|
else item.ref.removeAttribute('title');
|
|
148
160
|
if (item.source && item.hadTabindex === false) item.source.removeAttribute('tabindex');
|
|
149
161
|
}
|
|
150
|
-
for (const
|
|
162
|
+
for (const source of activeState) source.classList.add(ACTIVE);
|
|
151
163
|
};
|
|
152
164
|
});
|
|
153
165
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"splitter.d.ts","sourceRoot":"","sources":["splitter.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"splitter.d.ts","sourceRoot":"","sources":["splitter.js"],"names":[],"mappings":"AAwNA;;;;;;;;;;;;;GAaG;AACH,wCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAU3C;;;;;WAlOa,MAAM;;;;iBACN,UAAU,GAAG,YAAY"}
|