@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/splitter.js
CHANGED
|
@@ -44,122 +44,159 @@ const dispatchResize = (splitter, detail) => {
|
|
|
44
44
|
);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
+
const snapshotAttrs = (el, names) => {
|
|
48
|
+
const out = {};
|
|
49
|
+
for (const name of names) {
|
|
50
|
+
out[name] = {
|
|
51
|
+
had: el.hasAttribute(name),
|
|
52
|
+
value: el.getAttribute(name),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const restoreAttrs = (el, attrs) => {
|
|
59
|
+
for (const [name, attr] of Object.entries(attrs)) {
|
|
60
|
+
if (attr.had) el.setAttribute(name, attr.value);
|
|
61
|
+
else el.removeAttribute(name);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const snapshotStyleProp = (el, name) => ({
|
|
66
|
+
value: el.style.getPropertyValue(name),
|
|
67
|
+
priority: el.style.getPropertyPriority(name),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const restoreStyleProp = (el, name, prop) => {
|
|
71
|
+
if (prop.value) el.style.setProperty(name, prop.value, prop.priority);
|
|
72
|
+
else el.style.removeProperty(name);
|
|
73
|
+
};
|
|
74
|
+
|
|
47
75
|
function wireSplitter(splitter) {
|
|
48
76
|
const handle = splitter.querySelector(HANDLE_SELECTOR);
|
|
49
77
|
if (!handle) return noop;
|
|
50
78
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (!
|
|
81
|
-
if (orientation
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
handle.
|
|
79
|
+
return bindOnce(splitter, 'splitter', () => {
|
|
80
|
+
const handleAttrs = snapshotAttrs(handle, [
|
|
81
|
+
'role',
|
|
82
|
+
'tabindex',
|
|
83
|
+
'aria-orientation',
|
|
84
|
+
'aria-valuemin',
|
|
85
|
+
'aria-valuemax',
|
|
86
|
+
'aria-valuenow',
|
|
87
|
+
]);
|
|
88
|
+
const splitterPos = snapshotStyleProp(splitter, '--splitter-pos');
|
|
89
|
+
const orientation = readOrientation(splitter, handle);
|
|
90
|
+
const min = num(handle.getAttribute('aria-valuemin'), DEFAULT_MIN);
|
|
91
|
+
const max = Math.max(min, num(handle.getAttribute('aria-valuemax'), DEFAULT_MAX));
|
|
92
|
+
let value = clamp(
|
|
93
|
+
num(handle.getAttribute('aria-valuenow'), num(readCssValue(splitter), DEFAULT_VALUE)),
|
|
94
|
+
min,
|
|
95
|
+
max,
|
|
96
|
+
);
|
|
97
|
+
let activePointer = null;
|
|
98
|
+
|
|
99
|
+
const apply = (next, { emit = true } = {}) => {
|
|
100
|
+
value = clamp(next, min, max);
|
|
101
|
+
const label = fmt(value);
|
|
102
|
+
splitter.style.setProperty('--splitter-pos', `${label}%`);
|
|
103
|
+
handle.setAttribute('aria-valuenow', label);
|
|
104
|
+
if (emit) dispatchResize(splitter, { value, orientation });
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
if (!handle.hasAttribute('role')) handle.setAttribute('role', 'separator');
|
|
108
|
+
if (!handle.hasAttribute('tabindex')) handle.tabIndex = 0;
|
|
109
|
+
if (!handle.hasAttribute('aria-orientation'))
|
|
110
|
+
handle.setAttribute('aria-orientation', orientation);
|
|
111
|
+
if (!handle.hasAttribute('aria-valuemin')) handle.setAttribute('aria-valuemin', fmt(min));
|
|
112
|
+
if (!handle.hasAttribute('aria-valuemax')) handle.setAttribute('aria-valuemax', fmt(max));
|
|
113
|
+
apply(value, { emit: false });
|
|
114
|
+
|
|
115
|
+
const fromPointer = (event) => {
|
|
116
|
+
const rect = splitter.getBoundingClientRect();
|
|
117
|
+
const size = orientation === 'horizontal' ? rect.height : rect.width;
|
|
118
|
+
if (!size) return value;
|
|
119
|
+
if (orientation === 'horizontal') {
|
|
120
|
+
return ((event.clientY - rect.top) / size) * 100;
|
|
121
|
+
}
|
|
122
|
+
const view = getView(splitter);
|
|
123
|
+
const dir = view?.getComputedStyle?.(splitter).direction;
|
|
124
|
+
const x = dir === 'rtl' ? rect.right - event.clientX : event.clientX - rect.left;
|
|
125
|
+
return (x / size) * 100;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const capturePointer = (pointerId) => {
|
|
129
|
+
if (pointerId === undefined || pointerId === null) return;
|
|
130
|
+
try {
|
|
131
|
+
handle.setPointerCapture?.(pointerId);
|
|
132
|
+
} catch {
|
|
133
|
+
/* Pointer capture is an affordance; drag still works through document listeners. */
|
|
104
134
|
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
next
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
event.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const releasePointer = (pointerId = activePointer) => {
|
|
138
|
+
if (pointerId === undefined || pointerId === null) return;
|
|
139
|
+
try {
|
|
140
|
+
if (!handle.hasPointerCapture || handle.hasPointerCapture(pointerId)) {
|
|
141
|
+
handle.releasePointerCapture?.(pointerId);
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
/* The element may have been removed or capture may already be gone. */
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const onKeydown = (event) => {
|
|
149
|
+
let next = value;
|
|
150
|
+
if (event.key === 'Home') next = min;
|
|
151
|
+
else if (event.key === 'End') next = max;
|
|
152
|
+
else if (event.key === 'PageUp') next += LARGE_STEP;
|
|
153
|
+
else if (event.key === 'PageDown') next -= LARGE_STEP;
|
|
154
|
+
else if (event.key === 'ArrowRight' || event.key === 'ArrowDown')
|
|
155
|
+
next += event.shiftKey ? LARGE_STEP : STEP;
|
|
156
|
+
else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp')
|
|
157
|
+
next -= event.shiftKey ? LARGE_STEP : STEP;
|
|
158
|
+
else return;
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
apply(next);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const onPointerMove = (event) => {
|
|
164
|
+
if (
|
|
165
|
+
activePointer !== null &&
|
|
166
|
+
event.pointerId !== undefined &&
|
|
167
|
+
event.pointerId !== activePointer
|
|
168
|
+
)
|
|
169
|
+
return;
|
|
170
|
+
apply(fromPointer(event));
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const onPointerUp = (event) => {
|
|
174
|
+
if (
|
|
175
|
+
activePointer !== null &&
|
|
176
|
+
event.pointerId !== undefined &&
|
|
177
|
+
event.pointerId !== activePointer
|
|
178
|
+
)
|
|
179
|
+
return;
|
|
180
|
+
releasePointer(event.pointerId);
|
|
181
|
+
activePointer = null;
|
|
182
|
+
handle.classList.remove('is-active');
|
|
183
|
+
splitter.ownerDocument.removeEventListener('pointermove', onPointerMove);
|
|
184
|
+
splitter.ownerDocument.removeEventListener('pointerup', onPointerUp);
|
|
185
|
+
splitter.ownerDocument.removeEventListener('pointercancel', onPointerUp);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const onPointerDown = (event) => {
|
|
189
|
+
if (event.button !== undefined && event.button !== 0) return;
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
activePointer = event.pointerId ?? null;
|
|
192
|
+
capturePointer(activePointer);
|
|
193
|
+
handle.classList.add('is-active');
|
|
194
|
+
apply(fromPointer(event));
|
|
195
|
+
splitter.ownerDocument.addEventListener('pointermove', onPointerMove);
|
|
196
|
+
splitter.ownerDocument.addEventListener('pointerup', onPointerUp);
|
|
197
|
+
splitter.ownerDocument.addEventListener('pointercancel', onPointerUp);
|
|
198
|
+
};
|
|
161
199
|
|
|
162
|
-
return bindOnce(splitter, 'splitter', () => {
|
|
163
200
|
handle.addEventListener('keydown', onKeydown);
|
|
164
201
|
handle.addEventListener('pointerdown', onPointerDown);
|
|
165
202
|
return () => {
|
|
@@ -171,6 +208,8 @@ function wireSplitter(splitter) {
|
|
|
171
208
|
releasePointer();
|
|
172
209
|
handle.classList.remove('is-active');
|
|
173
210
|
activePointer = null;
|
|
211
|
+
restoreAttrs(handle, handleAttrs);
|
|
212
|
+
restoreStyleProp(splitter, '--splitter-pos', splitterPos);
|
|
174
213
|
};
|
|
175
214
|
});
|
|
176
215
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spotlight.d.ts","sourceRoot":"","sources":["spotlight.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spotlight.d.ts","sourceRoot":"","sources":["spotlight.js"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;GAcG;AACH,yCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA6C3C"}
|
package/behaviors/spotlight.js
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { hasDom, resolveHost, noop, bindOnce, byIdInHost, collectHosts } from './internal.js';
|
|
2
2
|
|
|
3
|
+
const SPOT_PROPS = ['--spot-x', '--spot-y', '--spot-w', '--spot-h'];
|
|
4
|
+
|
|
5
|
+
const snapshotSpotProps = (spot) =>
|
|
6
|
+
Object.fromEntries(
|
|
7
|
+
SPOT_PROPS.map((name) => [
|
|
8
|
+
name,
|
|
9
|
+
{
|
|
10
|
+
value: spot.style.getPropertyValue(name),
|
|
11
|
+
priority: spot.style.getPropertyPriority(name),
|
|
12
|
+
},
|
|
13
|
+
]),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const restoreSpotProps = (spot, props) => {
|
|
17
|
+
for (const [name, prop] of Object.entries(props)) {
|
|
18
|
+
if (prop.value) spot.style.setProperty(name, prop.value, prop.priority);
|
|
19
|
+
else spot.style.removeProperty(name);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
3
23
|
/**
|
|
4
24
|
* Position a spotlight cutout over a target element. Each
|
|
5
25
|
* `[data-bronto-spotlight]` is a `.ui-spotlight` overlay; `data-target` is the
|
|
@@ -19,10 +39,9 @@ export function initSpotlight({ root } = {}) {
|
|
|
19
39
|
if (!hasDom()) return noop;
|
|
20
40
|
const host = resolveHost(root);
|
|
21
41
|
if (!host) return noop;
|
|
22
|
-
const spots = collectHosts(host, '[data-bronto-spotlight]');
|
|
23
|
-
if (!spots.length) return noop;
|
|
24
42
|
|
|
25
43
|
const place = () => {
|
|
44
|
+
const spots = collectHosts(host, '[data-bronto-spotlight]');
|
|
26
45
|
for (const spot of spots) {
|
|
27
46
|
const target = byIdInHost(host, spot.dataset.target);
|
|
28
47
|
if (!target) continue;
|
|
@@ -35,6 +54,12 @@ export function initSpotlight({ root } = {}) {
|
|
|
35
54
|
};
|
|
36
55
|
|
|
37
56
|
return bindOnce(host, 'spotlight', () => {
|
|
57
|
+
const spots = collectHosts(host, '[data-bronto-spotlight]');
|
|
58
|
+
if (!spots.length) return noop;
|
|
59
|
+
const states = spots.map((spot) => ({
|
|
60
|
+
spot,
|
|
61
|
+
props: snapshotSpotProps(spot),
|
|
62
|
+
}));
|
|
38
63
|
place();
|
|
39
64
|
const view = host.defaultView || host.ownerDocument?.defaultView || null;
|
|
40
65
|
const MO = view?.MutationObserver;
|
|
@@ -50,6 +75,7 @@ export function initSpotlight({ root } = {}) {
|
|
|
50
75
|
mo?.disconnect();
|
|
51
76
|
view?.removeEventListener('resize', place);
|
|
52
77
|
view?.removeEventListener('scroll', place, true);
|
|
78
|
+
for (const state of states) restoreSpotProps(state.spot, state.props);
|
|
53
79
|
};
|
|
54
80
|
});
|
|
55
81
|
}
|
package/behaviors/table.d.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* canonical number in a `data-sort-value` attribute on the cell. That escape
|
|
28
28
|
* hatch wins over the parsed text and accepts either a dot ("3.5") or a single
|
|
29
29
|
* decimal comma ("3,5"). It is a client-side convenience sorter, not a data
|
|
30
|
-
* grid.
|
|
30
|
+
* grid.
|
|
31
31
|
*
|
|
32
32
|
* @param {import('./internal.js').DelegateOpts} [opts]
|
|
33
33
|
* @returns {import('./internal.js').Cleanup}
|
package/behaviors/table.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["table.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,yCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["table.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,yCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAwO3C"}
|
package/behaviors/table.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasDom, resolveHost, noop, bindOnce, collectHosts } from './internal.js';
|
|
1
|
+
import { hasDom, resolveHost, noop, bindOnce, collectHosts, closestSafe } from './internal.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Client-side sortable + selectable data table. Wires
|
|
@@ -29,7 +29,7 @@ import { hasDom, resolveHost, noop, bindOnce, collectHosts } from './internal.js
|
|
|
29
29
|
* canonical number in a `data-sort-value` attribute on the cell. That escape
|
|
30
30
|
* hatch wins over the parsed text and accepts either a dot ("3.5") or a single
|
|
31
31
|
* decimal comma ("3,5"). It is a client-side convenience sorter, not a data
|
|
32
|
-
* grid.
|
|
32
|
+
* grid.
|
|
33
33
|
*
|
|
34
34
|
* @param {import('./internal.js').DelegateOpts} [opts]
|
|
35
35
|
* @returns {import('./internal.js').Cleanup}
|
|
@@ -41,18 +41,96 @@ export function initTableSort({ root } = {}) {
|
|
|
41
41
|
const tables = collectHosts(host, '[data-bronto-sortable]');
|
|
42
42
|
const cleanups = [];
|
|
43
43
|
|
|
44
|
+
const snapshotAttrs = (el, names) => {
|
|
45
|
+
const out = {};
|
|
46
|
+
for (const name of names) {
|
|
47
|
+
out[name] = {
|
|
48
|
+
had: el.hasAttribute(name),
|
|
49
|
+
value: el.getAttribute(name),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const restoreAttrs = (el, attrs) => {
|
|
56
|
+
for (const [name, attr] of Object.entries(attrs)) {
|
|
57
|
+
if (attr.had) el.setAttribute(name, attr.value);
|
|
58
|
+
else el.removeAttribute(name);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
44
62
|
for (const table of tables) {
|
|
45
63
|
const tbody = table.tBodies[0];
|
|
46
64
|
if (!tbody) continue;
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
const headerStates = new WeakMap();
|
|
67
|
+
const headers = [];
|
|
68
|
+
const sortStates = new WeakMap();
|
|
69
|
+
const sorters = [];
|
|
70
|
+
const rowStates = new WeakMap();
|
|
71
|
+
const rows = [];
|
|
72
|
+
const checkboxStates = new WeakMap();
|
|
73
|
+
const checkboxes = [];
|
|
74
|
+
|
|
75
|
+
const rememberHeaderState = (th) => {
|
|
76
|
+
if (!th || headerStates.has(th)) return;
|
|
77
|
+
headerStates.set(th, snapshotAttrs(th, ['aria-sort']));
|
|
78
|
+
headers.push(th);
|
|
79
|
+
};
|
|
80
|
+
const rememberSorterState = (sorter) => {
|
|
81
|
+
if (!sorter || sortStates.has(sorter)) return;
|
|
82
|
+
sortStates.set(sorter, snapshotAttrs(sorter, ['type']));
|
|
83
|
+
sorters.push(sorter);
|
|
84
|
+
};
|
|
85
|
+
const rememberRowState = (row) => {
|
|
86
|
+
if (!row || rowStates.has(row)) return;
|
|
87
|
+
rowStates.set(row, snapshotAttrs(row, ['aria-selected']));
|
|
88
|
+
rows.push(row);
|
|
89
|
+
};
|
|
90
|
+
const rememberCheckboxState = (box) => {
|
|
91
|
+
if (!box || checkboxStates.has(box)) return;
|
|
92
|
+
checkboxStates.set(box, {
|
|
93
|
+
checked: box.checked,
|
|
94
|
+
indeterminate: box.indeterminate,
|
|
95
|
+
});
|
|
96
|
+
checkboxes.push(box);
|
|
97
|
+
rememberRowState(box.closest?.('tr'));
|
|
98
|
+
};
|
|
99
|
+
const seedSorters = () => {
|
|
100
|
+
// Seed the resting `aria-sort="none"` on every sortable header so AT
|
|
101
|
+
// announces the column as sortable from the start.
|
|
102
|
+
for (const sort of table.querySelectorAll('.ui-table__sort')) {
|
|
103
|
+
rememberSorterState(sort);
|
|
104
|
+
if (sort.tagName === 'BUTTON' && !sort.hasAttribute('type')) sort.type = 'button';
|
|
105
|
+
const th = sort.closest('th');
|
|
106
|
+
rememberHeaderState(th);
|
|
107
|
+
if (th && !th.hasAttribute('aria-sort')) th.setAttribute('aria-sort', 'none');
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const rememberTableState = () => {
|
|
111
|
+
const rowOrder = [...tbody.rows];
|
|
112
|
+
rowOrder.forEach(rememberRowState);
|
|
113
|
+
seedSorters();
|
|
114
|
+
const allBox = table.querySelector('[data-bronto-select-all]');
|
|
115
|
+
rememberCheckboxState(allBox);
|
|
116
|
+
table.querySelectorAll('[data-bronto-select]').forEach(rememberCheckboxState);
|
|
117
|
+
return { rowOrder };
|
|
118
|
+
};
|
|
119
|
+
const restoreTableState = (state) => {
|
|
120
|
+
for (const sorter of sorters) restoreAttrs(sorter, sortStates.get(sorter));
|
|
121
|
+
for (const th of headers) restoreAttrs(th, headerStates.get(th));
|
|
122
|
+
for (const row of rows) restoreAttrs(row, rowStates.get(row));
|
|
123
|
+
for (const box of checkboxes) {
|
|
124
|
+
const boxState = checkboxStates.get(box);
|
|
125
|
+
if (!boxState) continue;
|
|
126
|
+
box.checked = boxState.checked;
|
|
127
|
+
box.indeterminate = boxState.indeterminate;
|
|
128
|
+
}
|
|
129
|
+
const ordered = state.rowOrder.filter((row) => row.parentElement === tbody);
|
|
130
|
+
const orderedSet = new Set(ordered);
|
|
131
|
+
const extras = [...tbody.rows].filter((row) => !orderedSet.has(row));
|
|
132
|
+
tbody.append(...ordered, ...extras);
|
|
133
|
+
};
|
|
56
134
|
|
|
57
135
|
const colIndex = (th) => [...th.parentElement.children].indexOf(th);
|
|
58
136
|
const cellText = (row, i) => row.children[i]?.textContent.trim() ?? '';
|
|
@@ -60,7 +138,7 @@ export function initTableSort({ root } = {}) {
|
|
|
60
138
|
// authoritative escape hatch; otherwise normalize the display text so the
|
|
61
139
|
// sign survives (U+2212 / en-em dashes → minus, accounting parens →
|
|
62
140
|
// negative) and `,` grouping is dropped. Returns 0 for unparseable cells so
|
|
63
|
-
// they cluster rather than scatter.
|
|
141
|
+
// they cluster rather than scatter.
|
|
64
142
|
const cellNum = (row, i) => {
|
|
65
143
|
const cell = row.children[i];
|
|
66
144
|
const explicit = cell?.getAttribute?.('data-sort-value');
|
|
@@ -95,13 +173,15 @@ export function initTableSort({ root } = {}) {
|
|
|
95
173
|
// Reset the OTHER sortable headers to `none` (not removed) so they keep
|
|
96
174
|
// announcing sortability; only previously-sortable headers carry aria-sort.
|
|
97
175
|
headers.forEach((h) => {
|
|
176
|
+
rememberHeaderState(h);
|
|
98
177
|
if (h !== th && h.hasAttribute('aria-sort')) h.setAttribute('aria-sort', 'none');
|
|
99
178
|
});
|
|
179
|
+
rememberHeaderState(th);
|
|
100
180
|
th.setAttribute('aria-sort', dir);
|
|
101
181
|
const i = colIndex(th);
|
|
102
182
|
const sign = dir === 'ascending' ? 1 : -1;
|
|
103
|
-
// Empty/sentinel rows sort out of the data set
|
|
104
|
-
// or after a sort they float above the real rows
|
|
183
|
+
// Empty/sentinel rows sort out of the data set and must re-append last,
|
|
184
|
+
// or after a sort they float above the real rows.
|
|
105
185
|
const emptyRows = [...tbody.rows].filter((r) => r.classList.contains('ui-table__empty'));
|
|
106
186
|
const rows = [...tbody.rows].filter((r) => !r.classList.contains('ui-table__empty'));
|
|
107
187
|
rows.sort((a, b) => {
|
|
@@ -121,6 +201,7 @@ export function initTableSort({ root } = {}) {
|
|
|
121
201
|
const boxes = rowBoxes();
|
|
122
202
|
const on = boxes.filter((b) => b.checked).length;
|
|
123
203
|
if (allBox) {
|
|
204
|
+
rememberCheckboxState(allBox);
|
|
124
205
|
allBox.checked = on > 0 && on === boxes.length;
|
|
125
206
|
allBox.indeterminate = on > 0 && on < boxes.length;
|
|
126
207
|
}
|
|
@@ -129,17 +210,22 @@ export function initTableSort({ root } = {}) {
|
|
|
129
210
|
);
|
|
130
211
|
};
|
|
131
212
|
const markRow = (box) => {
|
|
213
|
+
rememberCheckboxState(box);
|
|
132
214
|
const tr = box.closest('tr');
|
|
133
|
-
if (tr)
|
|
215
|
+
if (tr) {
|
|
216
|
+
rememberRowState(tr);
|
|
217
|
+
tr.setAttribute('aria-selected', String(box.checked));
|
|
218
|
+
}
|
|
134
219
|
};
|
|
135
220
|
|
|
136
221
|
const onClick = (e) => {
|
|
137
222
|
// Only the focusable `.ui-table__sort` button is a sort trigger — it is
|
|
138
223
|
// keyboard-operable and carries the `::after` sort glyph. The bare
|
|
139
|
-
// `th[data-sort]` path was mouse-only with no affordance, so it is gone
|
|
140
|
-
//
|
|
141
|
-
const sorter = e.target
|
|
224
|
+
// `th[data-sort]` path was mouse-only with no affordance, so it is gone;
|
|
225
|
+
// `data-sort="num"` is still read from the button or its th.
|
|
226
|
+
const sorter = closestSafe(e.target, '.ui-table__sort');
|
|
142
227
|
if (sorter && table.contains(sorter)) {
|
|
228
|
+
rememberSorterState(sorter);
|
|
143
229
|
const th = sorter.closest('th');
|
|
144
230
|
const numeric =
|
|
145
231
|
(sorter.getAttribute('data-sort') || th.getAttribute('data-sort')) === 'num' ||
|
|
@@ -150,23 +236,28 @@ export function initTableSort({ root } = {}) {
|
|
|
150
236
|
const onChange = (e) => {
|
|
151
237
|
const t = e.target;
|
|
152
238
|
if (t.matches?.('[data-bronto-select-all]')) {
|
|
239
|
+
rememberCheckboxState(t);
|
|
153
240
|
rowBoxes().forEach((b) => {
|
|
241
|
+
rememberCheckboxState(b);
|
|
154
242
|
b.checked = t.checked;
|
|
155
243
|
markRow(b);
|
|
156
244
|
});
|
|
157
245
|
syncAll();
|
|
158
246
|
} else if (t.matches?.('[data-bronto-select]')) {
|
|
247
|
+
rememberCheckboxState(t);
|
|
159
248
|
markRow(t);
|
|
160
249
|
syncAll();
|
|
161
250
|
}
|
|
162
251
|
};
|
|
163
252
|
|
|
164
253
|
const bound = bindOnce(table, 'tableSort', () => {
|
|
254
|
+
const state = rememberTableState();
|
|
165
255
|
table.addEventListener('click', onClick);
|
|
166
256
|
table.addEventListener('change', onChange);
|
|
167
257
|
return () => {
|
|
168
258
|
table.removeEventListener('click', onClick);
|
|
169
259
|
table.removeEventListener('change', onChange);
|
|
260
|
+
restoreTableState(state);
|
|
170
261
|
};
|
|
171
262
|
});
|
|
172
263
|
cleanups.push(bound);
|
package/behaviors/tabs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["tabs.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["tabs.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;GAiBG;AACH,oCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CA+I3C"}
|