@allxsmith/bestax-bulma 5.36.1 → 5.37.0
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/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/components/EmptyState.js +2 -2
- package/dist/esm/components/Timeline.js +5 -5
- package/dist/esm/components/Timeline.js.map +1 -1
- package/dist/esm/components/TreeView.js +192 -0
- package/dist/esm/components/TreeView.js.map +1 -0
- package/dist/esm/helpers/typeahead.js +82 -0
- package/dist/esm/helpers/typeahead.js.map +1 -0
- package/dist/esm/helpers/useMenuKeys.js +8 -58
- package/dist/esm/helpers/useMenuKeys.js.map +1 -1
- package/dist/esm/helpers/useTreeView.js +380 -0
- package/dist/esm/helpers/useTreeView.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +1945 -1368
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/TreeView.d.ts +115 -0
- package/dist/types/helpers/typeahead.d.ts +41 -0
- package/dist/types/helpers/useMenuKeys.d.ts +1 -2
- package/dist/types/helpers/useTreeView.d.ts +88 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types-cjs/components/TreeView.d.ts +115 -0
- package/dist/types-cjs/helpers/typeahead.d.ts +41 -0
- package/dist/types-cjs/helpers/useMenuKeys.d.ts +1 -2
- package/dist/types-cjs/helpers/useTreeView.d.ts +88 -0
- package/dist/types-cjs/index.d.ts +1 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +1 -1
- package/src/scss/components/_index.scss +1 -0
- package/src/scss/components/_treeview.scss +252 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
import { useRef, useReducer, useState, useCallback } from 'react';
|
|
3
|
+
import { useClientLayoutEffect } from './useClientLayoutEffect.js';
|
|
4
|
+
import { getActiveElementInTree } from './shadowDom.js';
|
|
5
|
+
import { useTypeahead, typeaheadMatch, typeaheadText } from './typeahead.js';
|
|
6
|
+
|
|
7
|
+
// INTERNAL: deliberately not exported from src/index.ts.
|
|
8
|
+
/**
|
|
9
|
+
* What Enter, Space and a click on the row do in each mode, from the tables
|
|
10
|
+
* in #1096. `open` opens or closes a parent and does nothing on a leaf. A
|
|
11
|
+
* click on the chevron only ever opens or closes.
|
|
12
|
+
*/
|
|
13
|
+
const MODES = {
|
|
14
|
+
none: { enter: ['open'], space: ['open'], click: ['open'] },
|
|
15
|
+
single: { enter: ['select'], space: ['select'], click: ['select', 'open'] },
|
|
16
|
+
checkbox: { enter: ['open'], space: ['check'], click: ['check'] },
|
|
17
|
+
};
|
|
18
|
+
/** Left and Right, swapped for a right-to-left page. */
|
|
19
|
+
const MIRRORED = {
|
|
20
|
+
ArrowLeft: 'ArrowRight',
|
|
21
|
+
ArrowRight: 'ArrowLeft',
|
|
22
|
+
};
|
|
23
|
+
/** An IME is composing, so the key belongs to it (`keyCode` 229 is Safari's word for it). */
|
|
24
|
+
const isComposing$2 = (event) => event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229;
|
|
25
|
+
/** The registry's items on the page, in document order. */
|
|
26
|
+
const shownIn = (tree, { values }) => Array.from(tree.querySelectorAll('[role="treeitem"]')).filter(element => values.has(element));
|
|
27
|
+
/** The item an item on the page sits in: its group's `<li>`, or none at the top. */
|
|
28
|
+
function parentItemOf(element) {
|
|
29
|
+
const group = element.parentElement;
|
|
30
|
+
return group.getAttribute('role') === 'group' ? group.parentElement : null;
|
|
31
|
+
}
|
|
32
|
+
/** The values of the items an item on the page is in, from the top. */
|
|
33
|
+
function pathOf(element, { values }) {
|
|
34
|
+
const path = [];
|
|
35
|
+
for (let at = parentItemOf(element); at; at = parentItemOf(at)) {
|
|
36
|
+
path.unshift(values.get(at));
|
|
37
|
+
}
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Every known item's check state, by the rules in #1096:
|
|
42
|
+
*
|
|
43
|
+
* - a disabled item is checked only when its own value is listed;
|
|
44
|
+
* - an enabled item with no enabled items anywhere under it is checked when
|
|
45
|
+
* it, or any item above it, is listed;
|
|
46
|
+
* - any other enabled item follows the items of that second kind in its
|
|
47
|
+
* branch: checked when they all are, unchecked when none is, mixed between.
|
|
48
|
+
*
|
|
49
|
+
* Also returns the items of the second kind, which are what a toggle sets.
|
|
50
|
+
*/
|
|
51
|
+
function readChecks(records, listed) {
|
|
52
|
+
const kids = new Map();
|
|
53
|
+
records.forEach(({ parent }, value) => {
|
|
54
|
+
kids.set(parent, [...(kids.get(parent) ?? []), value]);
|
|
55
|
+
});
|
|
56
|
+
const states = new Map();
|
|
57
|
+
const ends = [];
|
|
58
|
+
// How many enabled ends the branch holds, and how many are checked.
|
|
59
|
+
const visit = (value, above) => {
|
|
60
|
+
const marked = above || listed.has(value);
|
|
61
|
+
let total = 0;
|
|
62
|
+
let on = 0;
|
|
63
|
+
for (const kid of kids.get(value) ?? []) {
|
|
64
|
+
const [t, o] = visit(kid, marked);
|
|
65
|
+
total += t;
|
|
66
|
+
on += o;
|
|
67
|
+
}
|
|
68
|
+
if (records.get(value).disabled) {
|
|
69
|
+
states.set(value, listed.has(value));
|
|
70
|
+
return [total, on];
|
|
71
|
+
}
|
|
72
|
+
if (total === 0) {
|
|
73
|
+
states.set(value, marked);
|
|
74
|
+
ends.push(value);
|
|
75
|
+
return [1, marked ? 1 : 0];
|
|
76
|
+
}
|
|
77
|
+
states.set(value, on === total ? true : on > 0 && 'mixed');
|
|
78
|
+
return [total, on];
|
|
79
|
+
};
|
|
80
|
+
for (const top of kids.get(null) ?? [])
|
|
81
|
+
visit(top, false);
|
|
82
|
+
return { states, ends };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The list a toggle of `value` leaves: it and every enabled item under it
|
|
86
|
+
* take the opposite of its state (a mixed one checks), and the rest is read
|
|
87
|
+
* back by the rules. That's every item that shows checked, parents
|
|
88
|
+
* included, plus any listed value no item has.
|
|
89
|
+
*/
|
|
90
|
+
function toggledList(records, list, value) {
|
|
91
|
+
const { states, ends } = readChecks(records, new Set(list));
|
|
92
|
+
const to = states.get(value) !== true;
|
|
93
|
+
// An end was reached from the top, so everything above it is known.
|
|
94
|
+
const under = (end) => {
|
|
95
|
+
for (let at = end; at !== null;) {
|
|
96
|
+
if (at === value)
|
|
97
|
+
return true;
|
|
98
|
+
at = records.get(at).parent;
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
};
|
|
102
|
+
const seed = new Set(ends.filter(end => (under(end) ? to : states.get(end) === true)));
|
|
103
|
+
records.forEach(({ disabled }, item) => {
|
|
104
|
+
if (disabled && states.get(item) === true)
|
|
105
|
+
seed.add(item);
|
|
106
|
+
});
|
|
107
|
+
const after = readChecks(records, seed).states;
|
|
108
|
+
return [
|
|
109
|
+
...Array.from(after)
|
|
110
|
+
.filter(([, state]) => state === true)
|
|
111
|
+
.map(([item]) => item),
|
|
112
|
+
...list.filter(item => !records.has(item)),
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
/** A value the caller holds, or one this hook holds when the caller doesn't. */
|
|
116
|
+
function useControlled(controlled, initial) {
|
|
117
|
+
const [own, setOwn] = useState(initial);
|
|
118
|
+
const isControlled = controlled !== undefined;
|
|
119
|
+
const set = (next) => {
|
|
120
|
+
if (!isControlled)
|
|
121
|
+
setOwn(next);
|
|
122
|
+
};
|
|
123
|
+
return [isControlled ? controlled : own, set];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The open state, the selection, the keys, the tab stop and the registry of
|
|
127
|
+
* a TreeView (#1096). Focus moves for real, with a roving tabindex, rather
|
|
128
|
+
* than through `aria-activedescendant`.
|
|
129
|
+
*
|
|
130
|
+
* Every item registers its value, its parent and whether it's disabled from
|
|
131
|
+
* a layout effect. In a checkbox tree a closed item's children still render
|
|
132
|
+
* and register while drawing nothing, so the registry knows every item and a
|
|
133
|
+
* check reaches all of them. The keys read the items on the page, in
|
|
134
|
+
* document order, each time they need them.
|
|
135
|
+
*
|
|
136
|
+
* @function useTreeView
|
|
137
|
+
* @param options - The TreeView's props.
|
|
138
|
+
* @returns The state and handlers the root and its items wire up.
|
|
139
|
+
*/
|
|
140
|
+
function useTreeView(options) {
|
|
141
|
+
// An own key only, so a name every object inherits, like `toString`, is a
|
|
142
|
+
// mode the tree doesn't know too.
|
|
143
|
+
const mode = Object.prototype.hasOwnProperty.call(MODES, options.mode)
|
|
144
|
+
? options.mode
|
|
145
|
+
: 'none';
|
|
146
|
+
const actions = MODES[mode];
|
|
147
|
+
const [expanded, setExpanded] = useControlled(options.expanded, options.defaultExpanded);
|
|
148
|
+
const [selection, setSelection] = useControlled(options.selected, options.defaultSelected);
|
|
149
|
+
const [checkedList, setChecked] = useControlled(options.checked, options.defaultChecked);
|
|
150
|
+
// Each is read in its own mode only.
|
|
151
|
+
const selected = mode === 'single' ? selection : null;
|
|
152
|
+
const listed = new Set(mode === 'checkbox' ? checkedList : []);
|
|
153
|
+
const treeRef = useRef(null);
|
|
154
|
+
const registryRef = useRef({
|
|
155
|
+
records: new Map(),
|
|
156
|
+
elements: new Map(),
|
|
157
|
+
values: new WeakMap(),
|
|
158
|
+
});
|
|
159
|
+
// Items register from their own effects, so they ask for a render to be read.
|
|
160
|
+
const [, refresh] = useReducer((n) => n + 1, 0);
|
|
161
|
+
const typeahead = useTypeahead();
|
|
162
|
+
// The item with focus, and where the stop rests while focus is elsewhere:
|
|
163
|
+
// `undefined` until the tree has mounted. With the values above it, for
|
|
164
|
+
// when it goes away.
|
|
165
|
+
const [focused, setFocused] = useState(null);
|
|
166
|
+
const [resting, setResting] = useState();
|
|
167
|
+
const restingPathRef = useRef([]);
|
|
168
|
+
// The values above an item that left the page with focus in it.
|
|
169
|
+
const lostRef = useRef(null);
|
|
170
|
+
const { records } = registryRef.current;
|
|
171
|
+
const checks = mode === 'checkbox'
|
|
172
|
+
? // eslint-disable-next-line react-hooks/refs -- read in render on purpose: items write the registry from their layout effects and then ask for this render with `refresh`
|
|
173
|
+
readChecks(records, listed).states
|
|
174
|
+
: undefined;
|
|
175
|
+
const tabStop = focused ?? (resting === undefined ? selected : resting);
|
|
176
|
+
const isOpen = (value) => expanded.includes(value);
|
|
177
|
+
const stateOf = (value, path, disabled) => {
|
|
178
|
+
if (mode === 'single') {
|
|
179
|
+
return disabled ? {} : { selected: value === selected };
|
|
180
|
+
}
|
|
181
|
+
if (checks) {
|
|
182
|
+
// Until the items register, a value stands for its branch, and a
|
|
183
|
+
// parent can't know it's mixed.
|
|
184
|
+
const fromList = listed.has(value) || (!disabled && path.some(v => listed.has(v)));
|
|
185
|
+
return { checked: checks.get(value) ?? fromList };
|
|
186
|
+
}
|
|
187
|
+
return {};
|
|
188
|
+
};
|
|
189
|
+
const changeOpen = (next) => {
|
|
190
|
+
setExpanded(next);
|
|
191
|
+
options.onExpandedChange?.(next);
|
|
192
|
+
};
|
|
193
|
+
const run = {
|
|
194
|
+
open: ({ value, isParent, open }) => {
|
|
195
|
+
if (isParent) {
|
|
196
|
+
changeOpen(open ? expanded.filter(v => v !== value) : [...expanded, value]);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
select: ({ value }) => {
|
|
200
|
+
if (value === selected)
|
|
201
|
+
return;
|
|
202
|
+
setSelection(value);
|
|
203
|
+
options.onSelectedChange?.(value);
|
|
204
|
+
},
|
|
205
|
+
check: ({ value }) => {
|
|
206
|
+
const next = toggledList(records, checkedList, value);
|
|
207
|
+
setChecked(next);
|
|
208
|
+
options.onCheckedChange?.(next);
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
/** Disabled items are never selected, checked, opened or closed. */
|
|
212
|
+
const act = (item, list) => {
|
|
213
|
+
if (!item.disabled)
|
|
214
|
+
list.forEach(action => run[action](item));
|
|
215
|
+
};
|
|
216
|
+
// After every render, put the stop where it belongs. While focus is in
|
|
217
|
+
// the tree it's the focused item. Otherwise it's the selected item, or the
|
|
218
|
+
// first checked one on the page, and failing that it stays where it was.
|
|
219
|
+
// An item that goes away hands it to its nearest ancestor on the page, or
|
|
220
|
+
// to the first item, and focus goes with it if it had focus.
|
|
221
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- after every render on purpose: it reads the page, and sets state only when what it reads has changed
|
|
222
|
+
useClientLayoutEffect(() => {
|
|
223
|
+
const tree = treeRef.current;
|
|
224
|
+
const registry = registryRef.current;
|
|
225
|
+
// Each item's element is read off the page with its value, rather than
|
|
226
|
+
// out of `elements`, which holds one element per value: two items
|
|
227
|
+
// sharing a value, which they shouldn't, can leave it without one the
|
|
228
|
+
// page still has.
|
|
229
|
+
const shown = shownIn(tree, registry);
|
|
230
|
+
const onPage = shown.map(element => registry.values.get(element));
|
|
231
|
+
const elementOf = (value) => shown[onPage.indexOf(value)];
|
|
232
|
+
const isShown = (value) => value != null && onPage.includes(value);
|
|
233
|
+
const heir = (path) => [...path].reverse().find(isShown) ?? onPage[0] ?? null;
|
|
234
|
+
const lost = lostRef.current;
|
|
235
|
+
lostRef.current = null;
|
|
236
|
+
if (lost && !tree.contains(getActiveElementInTree(tree))) {
|
|
237
|
+
const to = heir(lost);
|
|
238
|
+
if (to)
|
|
239
|
+
elementOf(to).focus();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (focused !== null && !isShown(focused))
|
|
243
|
+
setFocused(null);
|
|
244
|
+
const preferred = onPage.find(value => value === selected || checks?.get(value) === true);
|
|
245
|
+
const next = preferred ?? (isShown(resting) ? resting : heir(restingPathRef.current));
|
|
246
|
+
if (next !== resting) {
|
|
247
|
+
setResting(next);
|
|
248
|
+
restingPathRef.current = next ? pathOf(elementOf(next), registry) : [];
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
const register = useCallback((value, record) => {
|
|
252
|
+
const { records: known } = registryRef.current;
|
|
253
|
+
known.set(value, record);
|
|
254
|
+
refresh();
|
|
255
|
+
return () => {
|
|
256
|
+
if (known.get(value) !== record)
|
|
257
|
+
return;
|
|
258
|
+
known.delete(value);
|
|
259
|
+
refresh();
|
|
260
|
+
};
|
|
261
|
+
}, []);
|
|
262
|
+
const setElement = useCallback((value, element) => {
|
|
263
|
+
const registry = registryRef.current;
|
|
264
|
+
if (element) {
|
|
265
|
+
registry.elements.set(value, element);
|
|
266
|
+
registry.values.set(element, value);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const gone = registry.elements.get(value);
|
|
270
|
+
if (!gone)
|
|
271
|
+
return;
|
|
272
|
+
// The ref lets go before the element leaves the page, so it can still
|
|
273
|
+
// say whether focus was in it, and where it sat.
|
|
274
|
+
if (!lostRef.current && gone.contains(getActiveElementInTree(gone))) {
|
|
275
|
+
lostRef.current = [...pathOf(gone, registry), value];
|
|
276
|
+
}
|
|
277
|
+
registry.elements.delete(value);
|
|
278
|
+
}, []);
|
|
279
|
+
const onFocus = (value, element) => {
|
|
280
|
+
setFocused(value);
|
|
281
|
+
setResting(value);
|
|
282
|
+
restingPathRef.current = pathOf(element, registryRef.current);
|
|
283
|
+
};
|
|
284
|
+
const onBlur = () => setFocused(null);
|
|
285
|
+
const onKeyDown = (event, item) => {
|
|
286
|
+
const element = event.currentTarget;
|
|
287
|
+
// A key on an item inside this one bubbles here too, and is its own.
|
|
288
|
+
if (event.target !== element ||
|
|
289
|
+
event.defaultPrevented ||
|
|
290
|
+
event.altKey ||
|
|
291
|
+
event.ctrlKey ||
|
|
292
|
+
event.metaKey ||
|
|
293
|
+
isComposing$2(event)) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const registry = registryRef.current;
|
|
297
|
+
const items = shownIn(treeRef.current, registry);
|
|
298
|
+
const at = items.indexOf(element);
|
|
299
|
+
const rtl = getComputedStyle(element).direction === 'rtl';
|
|
300
|
+
const key = (rtl && MIRRORED[event.key]) || event.key;
|
|
301
|
+
switch (key) {
|
|
302
|
+
case 'ArrowDown':
|
|
303
|
+
items[at + 1]?.focus();
|
|
304
|
+
break;
|
|
305
|
+
case 'ArrowUp':
|
|
306
|
+
items[at - 1]?.focus();
|
|
307
|
+
break;
|
|
308
|
+
case 'Home':
|
|
309
|
+
items[0].focus();
|
|
310
|
+
break;
|
|
311
|
+
case 'End':
|
|
312
|
+
items[items.length - 1].focus();
|
|
313
|
+
break;
|
|
314
|
+
case 'ArrowRight': {
|
|
315
|
+
const next = items[at + 1];
|
|
316
|
+
if (!item.open)
|
|
317
|
+
act(item, ['open']);
|
|
318
|
+
else if (next && parentItemOf(next) === element)
|
|
319
|
+
next.focus();
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case 'ArrowLeft':
|
|
323
|
+
if (item.open && !item.disabled)
|
|
324
|
+
act(item, ['open']);
|
|
325
|
+
else
|
|
326
|
+
parentItemOf(element)?.focus();
|
|
327
|
+
break;
|
|
328
|
+
// A held key acts once.
|
|
329
|
+
case 'Enter':
|
|
330
|
+
if (!event.repeat)
|
|
331
|
+
act(item, actions.enter);
|
|
332
|
+
break;
|
|
333
|
+
case ' ':
|
|
334
|
+
if (!event.repeat)
|
|
335
|
+
act(item, actions.space);
|
|
336
|
+
break;
|
|
337
|
+
case '*': {
|
|
338
|
+
const closed = [];
|
|
339
|
+
registry.records.forEach((record, value) => {
|
|
340
|
+
if (record.parent === item.parent &&
|
|
341
|
+
record.isParent &&
|
|
342
|
+
!record.disabled &&
|
|
343
|
+
!expanded.includes(value)) {
|
|
344
|
+
closed.push(value);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
if (closed.length)
|
|
348
|
+
changeOpen([...expanded, ...closed]);
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
default:
|
|
352
|
+
// Type-ahead takes a printable character. Anything else, Escape and
|
|
353
|
+
// Tab included, is left to whatever is around the tree.
|
|
354
|
+
if (event.key.length !== 1)
|
|
355
|
+
return;
|
|
356
|
+
typeaheadMatch(items, typeahead.type(event.key), at, el => typeaheadText(el.firstElementChild))?.focus();
|
|
357
|
+
}
|
|
358
|
+
event.preventDefault();
|
|
359
|
+
};
|
|
360
|
+
const onClick = (element, item, onToggle) => {
|
|
361
|
+
element.focus();
|
|
362
|
+
act(item, onToggle ? ['open'] : actions.click);
|
|
363
|
+
};
|
|
364
|
+
return {
|
|
365
|
+
treeRef,
|
|
366
|
+
rendersClosed: mode === 'checkbox',
|
|
367
|
+
tabStop,
|
|
368
|
+
isOpen,
|
|
369
|
+
stateOf,
|
|
370
|
+
register,
|
|
371
|
+
setElement,
|
|
372
|
+
onFocus,
|
|
373
|
+
onBlur,
|
|
374
|
+
onKeyDown,
|
|
375
|
+
onClick,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export { useTreeView };
|
|
380
|
+
//# sourceMappingURL=useTreeView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTreeView.js","sources":["../../../src/helpers/useTreeView.ts"],"sourcesContent":["// INTERNAL: deliberately not exported from src/index.ts.\nimport { useCallback, useReducer, useRef, useState } from 'react';\nimport type React from 'react';\nimport type { TreeViewSelectionMode } from '../components/TreeView';\nimport { useClientLayoutEffect } from './useClientLayoutEffect';\nimport { getActiveElementInTree } from './shadowDom';\nimport { typeaheadMatch, typeaheadText, useTypeahead } from './typeahead';\n\n/** What an item tells the tree about itself when it registers. */\nexport interface TreeViewItemRecord {\n /** The value of the item it's in, or `null` at the top. */\n parent: string | null;\n disabled: boolean;\n /** It has children, or `hasChildren` says it will. */\n isParent: boolean;\n}\n\n/** An item as a key or a click on it sees it. */\nexport interface TreeViewItemInfo extends TreeViewItemRecord {\n value: string;\n open: boolean;\n}\n\n/** A box's state: checked, unchecked or mixed. */\nexport type TreeViewCheckState = boolean | 'mixed';\n\n/**\n * What an item shows of the selection: `selected` in a `single` tree,\n * `checked` in a `checkbox` tree, and neither with `none`.\n */\nexport interface TreeViewItemState {\n selected?: boolean;\n checked?: TreeViewCheckState;\n}\n\ntype Action = 'open' | 'select' | 'check';\n\n/**\n * What Enter, Space and a click on the row do in each mode, from the tables\n * in #1096. `open` opens or closes a parent and does nothing on a leaf. A\n * click on the chevron only ever opens or closes.\n */\nconst MODES: Record<\n TreeViewSelectionMode,\n { enter: Action[]; space: Action[]; click: Action[] }\n> = {\n none: { enter: ['open'], space: ['open'], click: ['open'] },\n single: { enter: ['select'], space: ['select'], click: ['select', 'open'] },\n checkbox: { enter: ['open'], space: ['check'], click: ['check'] },\n};\n\n/** Left and Right, swapped for a right-to-left page. */\nconst MIRRORED: Record<string, string> = {\n ArrowLeft: 'ArrowRight',\n ArrowRight: 'ArrowLeft',\n};\n\n/** An IME is composing, so the key belongs to it (`keyCode` 229 is Safari's word for it). */\nconst isComposing = (event: React.KeyboardEvent): boolean =>\n event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229;\n\n/** The items a tree knows, and their elements while they're on the page. */\ninterface Registry {\n records: Map<string, TreeViewItemRecord>;\n // By value, for an item whose ref lets go, which hands over no element.\n elements: Map<string, HTMLLIElement>;\n // Weak, so an element that leaves the page needn't be forgotten by hand.\n values: WeakMap<Element, string>;\n}\n\n/** The registry's items on the page, in document order. */\nconst shownIn = (tree: Element, { values }: Registry): HTMLElement[] =>\n Array.from(tree.querySelectorAll<HTMLElement>('[role=\"treeitem\"]')).filter(\n element => values.has(element)\n );\n\n/** The item an item on the page sits in: its group's `<li>`, or none at the top. */\nfunction parentItemOf(element: Element): HTMLElement | null {\n const group = element.parentElement!;\n return group.getAttribute('role') === 'group' ? group.parentElement : null;\n}\n\n/** The values of the items an item on the page is in, from the top. */\nfunction pathOf(element: Element, { values }: Registry): string[] {\n const path: string[] = [];\n for (let at = parentItemOf(element); at; at = parentItemOf(at)) {\n path.unshift(values.get(at)!);\n }\n return path;\n}\n\n/**\n * Every known item's check state, by the rules in #1096:\n *\n * - a disabled item is checked only when its own value is listed;\n * - an enabled item with no enabled items anywhere under it is checked when\n * it, or any item above it, is listed;\n * - any other enabled item follows the items of that second kind in its\n * branch: checked when they all are, unchecked when none is, mixed between.\n *\n * Also returns the items of the second kind, which are what a toggle sets.\n */\nfunction readChecks(\n records: Map<string, TreeViewItemRecord>,\n listed: Set<string>\n): { states: Map<string, TreeViewCheckState>; ends: string[] } {\n const kids = new Map<string | null, string[]>();\n records.forEach(({ parent }, value) => {\n kids.set(parent, [...(kids.get(parent) ?? []), value]);\n });\n const states = new Map<string, TreeViewCheckState>();\n const ends: string[] = [];\n // How many enabled ends the branch holds, and how many are checked.\n const visit = (value: string, above: boolean): [number, number] => {\n const marked = above || listed.has(value);\n let total = 0;\n let on = 0;\n for (const kid of kids.get(value) ?? []) {\n const [t, o] = visit(kid, marked);\n total += t;\n on += o;\n }\n if (records.get(value)!.disabled) {\n states.set(value, listed.has(value));\n return [total, on];\n }\n if (total === 0) {\n states.set(value, marked);\n ends.push(value);\n return [1, marked ? 1 : 0];\n }\n states.set(value, on === total ? true : on > 0 && 'mixed');\n return [total, on];\n };\n for (const top of kids.get(null) ?? []) visit(top, false);\n return { states, ends };\n}\n\n/**\n * The list a toggle of `value` leaves: it and every enabled item under it\n * take the opposite of its state (a mixed one checks), and the rest is read\n * back by the rules. That's every item that shows checked, parents\n * included, plus any listed value no item has.\n */\nfunction toggledList(\n records: Map<string, TreeViewItemRecord>,\n list: string[],\n value: string\n): string[] {\n const { states, ends } = readChecks(records, new Set(list));\n const to = states.get(value) !== true;\n // An end was reached from the top, so everything above it is known.\n const under = (end: string) => {\n for (let at: string | null = end; at !== null;) {\n if (at === value) return true;\n at = records.get(at)!.parent;\n }\n return false;\n };\n const seed = new Set(\n ends.filter(end => (under(end) ? to : states.get(end) === true))\n );\n records.forEach(({ disabled }, item) => {\n if (disabled && states.get(item) === true) seed.add(item);\n });\n const after = readChecks(records, seed).states;\n return [\n ...Array.from(after)\n .filter(([, state]) => state === true)\n .map(([item]) => item),\n ...list.filter(item => !records.has(item)),\n ];\n}\n\n/** A value the caller holds, or one this hook holds when the caller doesn't. */\nfunction useControlled<T>(controlled: T | undefined, initial: T) {\n const [own, setOwn] = useState(initial);\n const isControlled = controlled !== undefined;\n const set = (next: T) => {\n if (!isControlled) setOwn(next);\n };\n return [isControlled ? controlled : own, set] as const;\n}\n\n/** Options for `useTreeView`: the TreeView's own props. */\nexport interface TreeViewOptions {\n mode: TreeViewSelectionMode;\n selected?: string | null;\n defaultSelected: string | null;\n onSelectedChange?: (value: string) => void;\n checked?: string[];\n defaultChecked: string[];\n onCheckedChange?: (checked: string[]) => void;\n expanded?: string[];\n defaultExpanded: string[];\n onExpandedChange?: (expanded: string[]) => void;\n}\n\n/** What `useTreeView` hands the root and its items. */\nexport interface TreeViewEngine {\n /** For the `<ul role=\"tree\">`. */\n treeRef: React.MutableRefObject<HTMLUListElement | null>;\n /**\n * Whether a closed item still renders its children, drawing nothing, so a\n * check knows everything under it. Only a checkbox tree needs to.\n */\n rendersClosed: boolean;\n /** The item that holds `tabIndex={0}`. */\n tabStop: string | null;\n isOpen: (value: string) => boolean;\n /**\n * What the item shows of the selection. `path` is the values of the items\n * above it, which decide its box until the items have registered, as on\n * the server.\n */\n stateOf: (\n value: string,\n path: string[],\n disabled: boolean\n ) => TreeViewItemState;\n /** Records an item from its layout effect. Returns the function that forgets it. */\n register: (value: string, record: TreeViewItemRecord) => () => void;\n /** For each item's `<li>` ref: records it, and notices focus leaving with it. */\n setElement: (value: string, element: HTMLLIElement | null) => void;\n /** Focus arrived on the item's own `<li>`. */\n onFocus: (value: string, element: HTMLLIElement) => void;\n /** Focus left the item's own `<li>`. */\n onBlur: () => void;\n /** A key on the item's `<li>`, after its own `onKeyDown`. */\n onKeyDown: (\n event: React.KeyboardEvent<HTMLLIElement>,\n item: TreeViewItemInfo\n ) => void;\n /**\n * A click on the item's row, or with `onToggle` on its chevron. Focus and\n * the tab stop move to the item.\n */\n onClick: (\n element: HTMLLIElement,\n item: TreeViewItemInfo,\n onToggle: boolean\n ) => void;\n}\n\n/**\n * The open state, the selection, the keys, the tab stop and the registry of\n * a TreeView (#1096). Focus moves for real, with a roving tabindex, rather\n * than through `aria-activedescendant`.\n *\n * Every item registers its value, its parent and whether it's disabled from\n * a layout effect. In a checkbox tree a closed item's children still render\n * and register while drawing nothing, so the registry knows every item and a\n * check reaches all of them. The keys read the items on the page, in\n * document order, each time they need them.\n *\n * @function useTreeView\n * @param options - The TreeView's props.\n * @returns The state and handlers the root and its items wire up.\n */\nexport function useTreeView(options: TreeViewOptions): TreeViewEngine {\n // An own key only, so a name every object inherits, like `toString`, is a\n // mode the tree doesn't know too.\n const mode = Object.prototype.hasOwnProperty.call(MODES, options.mode)\n ? options.mode\n : 'none';\n const actions = MODES[mode];\n\n const [expanded, setExpanded] = useControlled(\n options.expanded,\n options.defaultExpanded\n );\n const [selection, setSelection] = useControlled(\n options.selected,\n options.defaultSelected\n );\n const [checkedList, setChecked] = useControlled(\n options.checked,\n options.defaultChecked\n );\n // Each is read in its own mode only.\n const selected = mode === 'single' ? selection : null;\n const listed = new Set(mode === 'checkbox' ? checkedList : []);\n\n const treeRef = useRef<HTMLUListElement | null>(null);\n const registryRef = useRef<Registry>({\n records: new Map(),\n elements: new Map(),\n values: new WeakMap(),\n });\n // Items register from their own effects, so they ask for a render to be read.\n const [, refresh] = useReducer((n: number) => n + 1, 0);\n const typeahead = useTypeahead();\n\n // The item with focus, and where the stop rests while focus is elsewhere:\n // `undefined` until the tree has mounted. With the values above it, for\n // when it goes away.\n const [focused, setFocused] = useState<string | null>(null);\n const [resting, setResting] = useState<string | null | undefined>();\n const restingPathRef = useRef<string[]>([]);\n // The values above an item that left the page with focus in it.\n const lostRef = useRef<string[] | null>(null);\n\n const { records } = registryRef.current;\n const checks =\n mode === 'checkbox'\n ? // eslint-disable-next-line react-hooks/refs -- read in render on purpose: items write the registry from their layout effects and then ask for this render with `refresh`\n readChecks(records, listed).states\n : undefined;\n const tabStop = focused ?? (resting === undefined ? selected : resting);\n\n const isOpen = (value: string) => expanded.includes(value);\n\n const stateOf = (\n value: string,\n path: string[],\n disabled: boolean\n ): TreeViewItemState => {\n if (mode === 'single') {\n return disabled ? {} : { selected: value === selected };\n }\n if (checks) {\n // Until the items register, a value stands for its branch, and a\n // parent can't know it's mixed.\n const fromList =\n listed.has(value) || (!disabled && path.some(v => listed.has(v)));\n return { checked: checks.get(value) ?? fromList };\n }\n return {};\n };\n\n const changeOpen = (next: string[]) => {\n setExpanded(next);\n options.onExpandedChange?.(next);\n };\n\n const run: Record<Action, (item: TreeViewItemInfo) => void> = {\n open: ({ value, isParent, open }) => {\n if (isParent) {\n changeOpen(\n open ? expanded.filter(v => v !== value) : [...expanded, value]\n );\n }\n },\n select: ({ value }) => {\n if (value === selected) return;\n setSelection(value);\n options.onSelectedChange?.(value);\n },\n check: ({ value }) => {\n const next = toggledList(records, checkedList, value);\n setChecked(next);\n options.onCheckedChange?.(next);\n },\n };\n\n /** Disabled items are never selected, checked, opened or closed. */\n const act = (item: TreeViewItemInfo, list: Action[]) => {\n if (!item.disabled) list.forEach(action => run[action](item));\n };\n\n // After every render, put the stop where it belongs. While focus is in\n // the tree it's the focused item. Otherwise it's the selected item, or the\n // first checked one on the page, and failing that it stays where it was.\n // An item that goes away hands it to its nearest ancestor on the page, or\n // to the first item, and focus goes with it if it had focus.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- after every render on purpose: it reads the page, and sets state only when what it reads has changed\n useClientLayoutEffect(() => {\n const tree = treeRef.current!;\n const registry = registryRef.current;\n // Each item's element is read off the page with its value, rather than\n // out of `elements`, which holds one element per value: two items\n // sharing a value, which they shouldn't, can leave it without one the\n // page still has.\n const shown = shownIn(tree, registry);\n const onPage = shown.map(element => registry.values.get(element)!);\n const elementOf = (value: string) => shown[onPage.indexOf(value)];\n const isShown = (value: string | null | undefined): value is string =>\n value != null && onPage.includes(value);\n const heir = (path: string[]) =>\n [...path].reverse().find(isShown) ?? onPage[0] ?? null;\n\n const lost = lostRef.current;\n lostRef.current = null;\n if (lost && !tree.contains(getActiveElementInTree(tree))) {\n const to = heir(lost);\n if (to) elementOf(to).focus();\n return;\n }\n if (focused !== null && !isShown(focused)) setFocused(null);\n\n const preferred = onPage.find(\n value => value === selected || checks?.get(value) === true\n );\n const next =\n preferred ?? (isShown(resting) ? resting : heir(restingPathRef.current));\n if (next !== resting) {\n setResting(next);\n restingPathRef.current = next ? pathOf(elementOf(next), registry) : [];\n }\n });\n\n const register = useCallback((value: string, record: TreeViewItemRecord) => {\n const { records: known } = registryRef.current;\n known.set(value, record);\n refresh();\n return () => {\n if (known.get(value) !== record) return;\n known.delete(value);\n refresh();\n };\n }, []);\n\n const setElement = useCallback(\n (value: string, element: HTMLLIElement | null) => {\n const registry = registryRef.current;\n if (element) {\n registry.elements.set(value, element);\n registry.values.set(element, value);\n return;\n }\n const gone = registry.elements.get(value);\n if (!gone) return;\n // The ref lets go before the element leaves the page, so it can still\n // say whether focus was in it, and where it sat.\n if (!lostRef.current && gone.contains(getActiveElementInTree(gone))) {\n lostRef.current = [...pathOf(gone, registry), value];\n }\n registry.elements.delete(value);\n },\n []\n );\n\n const onFocus = (value: string, element: HTMLLIElement) => {\n setFocused(value);\n setResting(value);\n restingPathRef.current = pathOf(element, registryRef.current);\n };\n\n const onBlur = () => setFocused(null);\n\n const onKeyDown = (\n event: React.KeyboardEvent<HTMLLIElement>,\n item: TreeViewItemInfo\n ) => {\n const element = event.currentTarget;\n // A key on an item inside this one bubbles here too, and is its own.\n if (\n event.target !== element ||\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n isComposing(event)\n ) {\n return;\n }\n const registry = registryRef.current;\n const items = shownIn(treeRef.current!, registry);\n const at = items.indexOf(element);\n const rtl = getComputedStyle(element).direction === 'rtl';\n const key = (rtl && MIRRORED[event.key]) || event.key;\n\n switch (key) {\n case 'ArrowDown':\n items[at + 1]?.focus();\n break;\n case 'ArrowUp':\n items[at - 1]?.focus();\n break;\n case 'Home':\n items[0].focus();\n break;\n case 'End':\n items[items.length - 1].focus();\n break;\n case 'ArrowRight': {\n const next = items[at + 1];\n if (!item.open) act(item, ['open']);\n else if (next && parentItemOf(next) === element) next.focus();\n break;\n }\n case 'ArrowLeft':\n if (item.open && !item.disabled) act(item, ['open']);\n else parentItemOf(element)?.focus();\n break;\n // A held key acts once.\n case 'Enter':\n if (!event.repeat) act(item, actions.enter);\n break;\n case ' ':\n if (!event.repeat) act(item, actions.space);\n break;\n case '*': {\n const closed: string[] = [];\n registry.records.forEach((record, value) => {\n if (\n record.parent === item.parent &&\n record.isParent &&\n !record.disabled &&\n !expanded.includes(value)\n ) {\n closed.push(value);\n }\n });\n if (closed.length) changeOpen([...expanded, ...closed]);\n break;\n }\n default:\n // Type-ahead takes a printable character. Anything else, Escape and\n // Tab included, is left to whatever is around the tree.\n if (event.key.length !== 1) return;\n typeaheadMatch(items, typeahead.type(event.key), at, el =>\n typeaheadText(el.firstElementChild!)\n )?.focus();\n }\n event.preventDefault();\n };\n\n const onClick = (\n element: HTMLLIElement,\n item: TreeViewItemInfo,\n onToggle: boolean\n ) => {\n element.focus();\n act(item, onToggle ? ['open'] : actions.click);\n };\n\n return {\n treeRef,\n rendersClosed: mode === 'checkbox',\n tabStop,\n isOpen,\n stateOf,\n register,\n setElement,\n onFocus,\n onBlur,\n onKeyDown,\n onClick,\n };\n}\n"],"names":["isComposing"],"mappings":";;;;;;AAAA;AAqCA;;;;AAIG;AACH,MAAM,KAAK,GAGP;AACF,IAAA,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;IAC3D,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC3E,IAAA,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE;CAClE;AAED;AACA,MAAM,QAAQ,GAA2B;AACvC,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,UAAU,EAAE,WAAW;CACxB;AAED;AACA,MAAMA,aAAW,GAAG,CAAC,KAA0B,KAC7C,KAAK,CAAC,WAAW,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,KAAK,GAAG;AAWpE;AACA,MAAM,OAAO,GAAG,CAAC,IAAa,EAAE,EAAE,MAAM,EAAY,KAClD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAc,mBAAmB,CAAC,CAAC,CAAC,MAAM,CACxE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAC/B;AAEH;AACA,SAAS,YAAY,CAAC,OAAgB,EAAA;AACpC,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,aAAc;AACpC,IAAA,OAAO,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,OAAO,GAAG,KAAK,CAAC,aAAa,GAAG,IAAI;AAC5E;AAEA;AACA,SAAS,MAAM,CAAC,OAAgB,EAAE,EAAE,MAAM,EAAY,EAAA;IACpD,MAAM,IAAI,GAAa,EAAE;AACzB,IAAA,KAAK,IAAI,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC,EAAE;QAC9D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;IAC/B;AACA,IAAA,OAAO,IAAI;AACb;AAEA;;;;;;;;;;AAUG;AACH,SAAS,UAAU,CACjB,OAAwC,EACxC,MAAmB,EAAA;AAEnB,IAAA,MAAM,IAAI,GAAG,IAAI,GAAG,EAA2B;IAC/C,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,KAAI;QACpC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;AACxD,IAAA,CAAC,CAAC;AACF,IAAA,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B;IACpD,MAAM,IAAI,GAAa,EAAE;;AAEzB,IAAA,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,KAAc,KAAsB;QAChE,MAAM,MAAM,GAAG,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;QACzC,IAAI,KAAK,GAAG,CAAC;QACb,IAAI,EAAE,GAAG,CAAC;AACV,QAAA,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE;AACvC,YAAA,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC;YACjC,KAAK,IAAI,CAAC;YACV,EAAE,IAAI,CAAC;QACT;QACA,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,QAAQ,EAAE;AAChC,YAAA,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACpC,YAAA,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACpB;AACA,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;AACf,YAAA,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;AACzB,YAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AAChB,YAAA,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B;QACA,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,KAAK,GAAG,IAAI,GAAG,EAAE,GAAG,CAAC,IAAI,OAAO,CAAC;AAC1D,QAAA,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;AACpB,IAAA,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;AAAE,QAAA,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC;AACzD,IAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;AACzB;AAEA;;;;;AAKG;AACH,SAAS,WAAW,CAClB,OAAwC,EACxC,IAAc,EACd,KAAa,EAAA;AAEb,IAAA,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI;;AAErC,IAAA,MAAM,KAAK,GAAG,CAAC,GAAW,KAAI;QAC5B,KAAK,IAAI,EAAE,GAAkB,GAAG,EAAE,EAAE,KAAK,IAAI,GAAG;YAC9C,IAAI,EAAE,KAAK,KAAK;AAAE,gBAAA,OAAO,IAAI;YAC7B,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,MAAM;QAC9B;AACA,QAAA,OAAO,KAAK;AACd,IAAA,CAAC;AACD,IAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAClB,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CACjE;IACD,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,KAAI;QACrC,IAAI,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI;AAAE,YAAA,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3D,IAAA,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM;IAC9C,OAAO;AACL,QAAA,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK;AAChB,aAAA,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,IAAI;aACpC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;AACxB,QAAA,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;KAC3C;AACH;AAEA;AACA,SAAS,aAAa,CAAI,UAAyB,EAAE,OAAU,EAAA;IAC7D,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;AACvC,IAAA,MAAM,YAAY,GAAG,UAAU,KAAK,SAAS;AAC7C,IAAA,MAAM,GAAG,GAAG,CAAC,IAAO,KAAI;AACtB,QAAA,IAAI,CAAC,YAAY;YAAE,MAAM,CAAC,IAAI,CAAC;AACjC,IAAA,CAAC;AACD,IAAA,OAAO,CAAC,YAAY,GAAG,UAAU,GAAG,GAAG,EAAE,GAAG,CAAU;AACxD;AA8DA;;;;;;;;;;;;;;AAcG;AACG,SAAU,WAAW,CAAC,OAAwB,EAAA;;;AAGlD,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI;UACjE,OAAO,CAAC;UACR,MAAM;AACV,IAAA,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC;AAE3B,IAAA,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,aAAa,CAC3C,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,eAAe,CACxB;AACD,IAAA,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,aAAa,CAC7C,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,eAAe,CACxB;AACD,IAAA,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,GAAG,aAAa,CAC7C,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,cAAc,CACvB;;AAED,IAAA,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ,GAAG,SAAS,GAAG,IAAI;AACrD,IAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,GAAG,WAAW,GAAG,EAAE,CAAC;AAE9D,IAAA,MAAM,OAAO,GAAG,MAAM,CAA0B,IAAI,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,CAAW;QACnC,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,QAAQ,EAAE,IAAI,GAAG,EAAE;QACnB,MAAM,EAAE,IAAI,OAAO,EAAE;AACtB,KAAA,CAAC;;AAEF,IAAA,MAAM,GAAG,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,CAAS,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACvD,IAAA,MAAM,SAAS,GAAG,YAAY,EAAE;;;;IAKhC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC;IAC3D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,EAA6B;AACnE,IAAA,MAAM,cAAc,GAAG,MAAM,CAAW,EAAE,CAAC;;AAE3C,IAAA,MAAM,OAAO,GAAG,MAAM,CAAkB,IAAI,CAAC;AAE7C,IAAA,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO;AACvC,IAAA,MAAM,MAAM,GACV,IAAI,KAAK;AACP;AACE,YAAA,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;UAC5B,SAAS;AACf,IAAA,MAAM,OAAO,GAAG,OAAO,KAAK,OAAO,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvE,IAAA,MAAM,MAAM,GAAG,CAAC,KAAa,KAAK,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;IAE1D,MAAM,OAAO,GAAG,CACd,KAAa,EACb,IAAc,EACd,QAAiB,KACI;AACrB,QAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;AACrB,YAAA,OAAO,QAAQ,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,KAAK,QAAQ,EAAE;QACzD;QACA,IAAI,MAAM,EAAE;;;AAGV,YAAA,MAAM,QAAQ,GACZ,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,YAAA,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,QAAQ,EAAE;QACnD;AACA,QAAA,OAAO,EAAE;AACX,IAAA,CAAC;AAED,IAAA,MAAM,UAAU,GAAG,CAAC,IAAc,KAAI;QACpC,WAAW,CAAC,IAAI,CAAC;AACjB,QAAA,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;AAClC,IAAA,CAAC;AAED,IAAA,MAAM,GAAG,GAAqD;QAC5D,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAI;YAClC,IAAI,QAAQ,EAAE;gBACZ,UAAU,CACR,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAChE;YACH;QACF,CAAC;AACD,QAAA,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAI;YACpB,IAAI,KAAK,KAAK,QAAQ;gBAAE;YACxB,YAAY,CAAC,KAAK,CAAC;AACnB,YAAA,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC;QACnC,CAAC;AACD,QAAA,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,KAAI;YACnB,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC;YACrD,UAAU,CAAC,IAAI,CAAC;AAChB,YAAA,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;QACjC,CAAC;KACF;;AAGD,IAAA,MAAM,GAAG,GAAG,CAAC,IAAsB,EAAE,IAAc,KAAI;QACrD,IAAI,CAAC,IAAI,CAAC,QAAQ;AAAE,YAAA,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,IAAA,CAAC;;;;;;;IAQD,qBAAqB,CAAC,MAAK;AACzB,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,OAAQ;AAC7B,QAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO;;;;;QAKpC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;AACrC,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;AAClE,QAAA,MAAM,SAAS,GAAG,CAAC,KAAa,KAAK,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACjE,QAAA,MAAM,OAAO,GAAG,CAAC,KAAgC,KAC/C,KAAK,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,IAAc,KAC1B,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI;AAExD,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO;AAC5B,QAAA,OAAO,CAAC,OAAO,GAAG,IAAI;AACtB,QAAA,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,EAAE;AACxD,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;AACrB,YAAA,IAAI,EAAE;AAAE,gBAAA,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE;YAC7B;QACF;QACA,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,UAAU,CAAC,IAAI,CAAC;QAE3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAC3B,KAAK,IAAI,KAAK,KAAK,QAAQ,IAAI,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAC3D;QACD,MAAM,IAAI,GACR,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AAC1E,QAAA,IAAI,IAAI,KAAK,OAAO,EAAE;YACpB,UAAU,CAAC,IAAI,CAAC;YAChB,cAAc,CAAC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,GAAG,EAAE;QACxE;AACF,IAAA,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,KAAa,EAAE,MAA0B,KAAI;QACzE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,OAAO;AAC9C,QAAA,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;AACxB,QAAA,OAAO,EAAE;AACT,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM;gBAAE;AACjC,YAAA,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AACnB,YAAA,OAAO,EAAE;AACX,QAAA,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;IAEN,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,KAAa,EAAE,OAA6B,KAAI;AAC/C,QAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO;QACpC,IAAI,OAAO,EAAE;YACX,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC;YACrC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC;YACnC;QACF;QACA,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACzC,QAAA,IAAI,CAAC,IAAI;YAAE;;;AAGX,QAAA,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,EAAE;AACnE,YAAA,OAAO,CAAC,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACtD;AACA,QAAA,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;IACjC,CAAC,EACD,EAAE,CACH;AAED,IAAA,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,OAAsB,KAAI;QACxD,UAAU,CAAC,KAAK,CAAC;QACjB,UAAU,CAAC,KAAK,CAAC;QACjB,cAAc,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC;AAC/D,IAAA,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC;AAErC,IAAA,MAAM,SAAS,GAAG,CAChB,KAAyC,EACzC,IAAsB,KACpB;AACF,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa;;AAEnC,QAAA,IACE,KAAK,CAAC,MAAM,KAAK,OAAO;AACxB,YAAA,KAAK,CAAC,gBAAgB;AACtB,YAAA,KAAK,CAAC,MAAM;AACZ,YAAA,KAAK,CAAC,OAAO;AACb,YAAA,KAAK,CAAC,OAAO;AACb,YAAAA,aAAW,CAAC,KAAK,CAAC,EAClB;YACA;QACF;AACA,QAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAQ,EAAE,QAAQ,CAAC;QACjD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QACjC,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,SAAS,KAAK,KAAK;AACzD,QAAA,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG;QAErD,QAAQ,GAAG;AACT,YAAA,KAAK,WAAW;gBACd,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE;gBACtB;AACF,YAAA,KAAK,SAAS;gBACZ,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE;gBACtB;AACF,YAAA,KAAK,MAAM;AACT,gBAAA,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;gBAChB;AACF,YAAA,KAAK,KAAK;gBACR,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;gBAC/B;YACF,KAAK,YAAY,EAAE;gBACjB,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,IAAI;AAAE,oBAAA,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;AAC9B,qBAAA,IAAI,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,OAAO;oBAAE,IAAI,CAAC,KAAK,EAAE;gBAC7D;YACF;AACA,YAAA,KAAK,WAAW;AACd,gBAAA,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ;AAAE,oBAAA,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;;AAC/C,oBAAA,YAAY,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE;gBACnC;;AAEF,YAAA,KAAK,OAAO;gBACV,IAAI,CAAC,KAAK,CAAC,MAAM;AAAE,oBAAA,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;gBAC3C;AACF,YAAA,KAAK,GAAG;gBACN,IAAI,CAAC,KAAK,CAAC,MAAM;AAAE,oBAAA,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;gBAC3C;YACF,KAAK,GAAG,EAAE;gBACR,MAAM,MAAM,GAAa,EAAE;gBAC3B,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,KAAI;AACzC,oBAAA,IACE,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;AAC7B,wBAAA,MAAM,CAAC,QAAQ;wBACf,CAAC,MAAM,CAAC,QAAQ;AAChB,wBAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EACzB;AACA,wBAAA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;oBACpB;AACF,gBAAA,CAAC,CAAC;gBACF,IAAI,MAAM,CAAC,MAAM;oBAAE,UAAU,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,CAAC;gBACvD;YACF;AACA,YAAA;;;AAGE,gBAAA,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC;oBAAE;AAC5B,gBAAA,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,IACrD,aAAa,CAAC,EAAE,CAAC,iBAAkB,CAAC,CACrC,EAAE,KAAK,EAAE;;QAEd,KAAK,CAAC,cAAc,EAAE;AACxB,IAAA,CAAC;IAED,MAAM,OAAO,GAAG,CACd,OAAsB,EACtB,IAAsB,EACtB,QAAiB,KACf;QACF,OAAO,CAAC,KAAK,EAAE;AACf,QAAA,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;AAChD,IAAA,CAAC;IAED,OAAO;QACL,OAAO;QACP,aAAa,EAAE,IAAI,KAAK,UAAU;QAClC,OAAO;QACP,MAAM;QACN,OAAO;QACP,QAAQ;QACR,UAAU;QACV,OAAO;QACP,MAAM;QACN,SAAS;QACT,OAAO;KACR;AACH;;"}
|