@ponchia/ui 0.6.7 → 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 +70 -0
- package/README.md +3 -3
- 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 -35
- 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 +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 +67 -0
- package/behaviors/glyph.d.ts.map +1 -1
- package/behaviors/glyph.js +17 -2
- package/behaviors/inert.js +3 -2
- package/behaviors/internal.d.ts.map +1 -1
- package/behaviors/internal.js +2 -1
- 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 +89 -9
- 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.map +1 -1
- package/behaviors/table.js +103 -11
- 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 +25 -5
- package/classes/index.d.ts +15 -2
- package/classes/index.js +0 -1
- package/connectors/index.d.ts +39 -6
- package/connectors/index.d.ts.map +1 -1
- package/connectors/index.js +67 -9
- package/css/annotations.css +12 -0
- package/css/crosshair.css +27 -2
- package/css/feedback.css +2 -30
- package/css/navigation.css +12 -0
- 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 +12 -1
- package/docs/architecture.md +46 -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/migrations/0.2-to-0.3.md +1 -1
- package/docs/package-contract.md +5 -5
- package/docs/reporting.md +23 -12
- package/docs/stability.md +18 -2
- package/docs/theming.md +2 -2
- package/docs/usage.md +16 -2
- package/docs/vega.md +4 -4
- package/llms.txt +10 -5
- package/package.json +20 -4
- package/svelte/index.d.ts +71 -45
- package/svelte/index.d.ts.map +1 -1
- package/svelte/index.js +29 -2
- package/vue/index.d.ts +42 -5
- package/vue/index.d.ts.map +1 -1
- package/vue/index.js +32 -1
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"}
|
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.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,CAyO3C"}
|
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
|
|
@@ -41,18 +41,97 @@ 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 (it was unset until the
|
|
102
|
+
// first click — C10).
|
|
103
|
+
for (const sort of table.querySelectorAll('.ui-table__sort')) {
|
|
104
|
+
rememberSorterState(sort);
|
|
105
|
+
if (sort.tagName === 'BUTTON' && !sort.hasAttribute('type')) sort.type = 'button';
|
|
106
|
+
const th = sort.closest('th');
|
|
107
|
+
rememberHeaderState(th);
|
|
108
|
+
if (th && !th.hasAttribute('aria-sort')) th.setAttribute('aria-sort', 'none');
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const rememberTableState = () => {
|
|
112
|
+
const rowOrder = [...tbody.rows];
|
|
113
|
+
rowOrder.forEach(rememberRowState);
|
|
114
|
+
seedSorters();
|
|
115
|
+
const allBox = table.querySelector('[data-bronto-select-all]');
|
|
116
|
+
rememberCheckboxState(allBox);
|
|
117
|
+
table.querySelectorAll('[data-bronto-select]').forEach(rememberCheckboxState);
|
|
118
|
+
return { rowOrder };
|
|
119
|
+
};
|
|
120
|
+
const restoreTableState = (state) => {
|
|
121
|
+
for (const sorter of sorters) restoreAttrs(sorter, sortStates.get(sorter));
|
|
122
|
+
for (const th of headers) restoreAttrs(th, headerStates.get(th));
|
|
123
|
+
for (const row of rows) restoreAttrs(row, rowStates.get(row));
|
|
124
|
+
for (const box of checkboxes) {
|
|
125
|
+
const boxState = checkboxStates.get(box);
|
|
126
|
+
if (!boxState) continue;
|
|
127
|
+
box.checked = boxState.checked;
|
|
128
|
+
box.indeterminate = boxState.indeterminate;
|
|
129
|
+
}
|
|
130
|
+
const ordered = state.rowOrder.filter((row) => row.parentElement === tbody);
|
|
131
|
+
const orderedSet = new Set(ordered);
|
|
132
|
+
const extras = [...tbody.rows].filter((row) => !orderedSet.has(row));
|
|
133
|
+
tbody.append(...ordered, ...extras);
|
|
134
|
+
};
|
|
56
135
|
|
|
57
136
|
const colIndex = (th) => [...th.parentElement.children].indexOf(th);
|
|
58
137
|
const cellText = (row, i) => row.children[i]?.textContent.trim() ?? '';
|
|
@@ -95,8 +174,10 @@ export function initTableSort({ root } = {}) {
|
|
|
95
174
|
// Reset the OTHER sortable headers to `none` (not removed) so they keep
|
|
96
175
|
// announcing sortability; only previously-sortable headers carry aria-sort.
|
|
97
176
|
headers.forEach((h) => {
|
|
177
|
+
rememberHeaderState(h);
|
|
98
178
|
if (h !== th && h.hasAttribute('aria-sort')) h.setAttribute('aria-sort', 'none');
|
|
99
179
|
});
|
|
180
|
+
rememberHeaderState(th);
|
|
100
181
|
th.setAttribute('aria-sort', dir);
|
|
101
182
|
const i = colIndex(th);
|
|
102
183
|
const sign = dir === 'ascending' ? 1 : -1;
|
|
@@ -121,6 +202,7 @@ export function initTableSort({ root } = {}) {
|
|
|
121
202
|
const boxes = rowBoxes();
|
|
122
203
|
const on = boxes.filter((b) => b.checked).length;
|
|
123
204
|
if (allBox) {
|
|
205
|
+
rememberCheckboxState(allBox);
|
|
124
206
|
allBox.checked = on > 0 && on === boxes.length;
|
|
125
207
|
allBox.indeterminate = on > 0 && on < boxes.length;
|
|
126
208
|
}
|
|
@@ -129,8 +211,12 @@ export function initTableSort({ root } = {}) {
|
|
|
129
211
|
);
|
|
130
212
|
};
|
|
131
213
|
const markRow = (box) => {
|
|
214
|
+
rememberCheckboxState(box);
|
|
132
215
|
const tr = box.closest('tr');
|
|
133
|
-
if (tr)
|
|
216
|
+
if (tr) {
|
|
217
|
+
rememberRowState(tr);
|
|
218
|
+
tr.setAttribute('aria-selected', String(box.checked));
|
|
219
|
+
}
|
|
134
220
|
};
|
|
135
221
|
|
|
136
222
|
const onClick = (e) => {
|
|
@@ -138,8 +224,9 @@ export function initTableSort({ root } = {}) {
|
|
|
138
224
|
// keyboard-operable and carries the `::after` sort glyph. The bare
|
|
139
225
|
// `th[data-sort]` path was mouse-only with no affordance, so it is gone
|
|
140
226
|
// (C10); `data-sort="num"` is still read from the button or its th.
|
|
141
|
-
const sorter = e.target
|
|
227
|
+
const sorter = closestSafe(e.target, '.ui-table__sort');
|
|
142
228
|
if (sorter && table.contains(sorter)) {
|
|
229
|
+
rememberSorterState(sorter);
|
|
143
230
|
const th = sorter.closest('th');
|
|
144
231
|
const numeric =
|
|
145
232
|
(sorter.getAttribute('data-sort') || th.getAttribute('data-sort')) === 'num' ||
|
|
@@ -150,23 +237,28 @@ export function initTableSort({ root } = {}) {
|
|
|
150
237
|
const onChange = (e) => {
|
|
151
238
|
const t = e.target;
|
|
152
239
|
if (t.matches?.('[data-bronto-select-all]')) {
|
|
240
|
+
rememberCheckboxState(t);
|
|
153
241
|
rowBoxes().forEach((b) => {
|
|
242
|
+
rememberCheckboxState(b);
|
|
154
243
|
b.checked = t.checked;
|
|
155
244
|
markRow(b);
|
|
156
245
|
});
|
|
157
246
|
syncAll();
|
|
158
247
|
} else if (t.matches?.('[data-bronto-select]')) {
|
|
248
|
+
rememberCheckboxState(t);
|
|
159
249
|
markRow(t);
|
|
160
250
|
syncAll();
|
|
161
251
|
}
|
|
162
252
|
};
|
|
163
253
|
|
|
164
254
|
const bound = bindOnce(table, 'tableSort', () => {
|
|
255
|
+
const state = rememberTableState();
|
|
165
256
|
table.addEventListener('click', onClick);
|
|
166
257
|
table.addEventListener('change', onChange);
|
|
167
258
|
return () => {
|
|
168
259
|
table.removeEventListener('click', onClick);
|
|
169
260
|
table.removeEventListener('change', onChange);
|
|
261
|
+
restoreTableState(state);
|
|
170
262
|
};
|
|
171
263
|
});
|
|
172
264
|
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"}
|