sibujs 4.4.0 → 4.6.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/README.md +11 -0
- package/dist/browser.cjs +339 -130
- package/dist/browser.d.cts +61 -16
- package/dist/browser.d.ts +61 -16
- package/dist/browser.js +8 -6
- package/dist/build.cjs +273 -82
- package/dist/build.js +15 -16
- package/dist/cdn.dev.global.js +12 -12
- package/dist/cdn.full.dev.global.js +11 -11
- package/dist/cdn.full.global.js +10 -10
- package/dist/cdn.global.js +12 -12
- package/dist/{chunk-IXKSNWV5.js → chunk-2INLLLMZ.js} +1 -1
- package/dist/chunk-3ISI6ACU.js +44 -0
- package/dist/{chunk-VCTAEPSB.js → chunk-47M47FOM.js} +11 -3
- package/dist/chunk-5HZXGZ6T.js +24 -0
- package/dist/{chunk-KKLW7YWL.js → chunk-5MT6SJ3P.js} +275 -144
- package/dist/{chunk-3BTTCZ5J.js → chunk-5Q4R7HCL.js} +42 -4
- package/dist/{chunk-ADM46X22.js → chunk-7GQCWFOE.js} +157 -61
- package/dist/{chunk-4Z3SPQ67.js → chunk-7NCARGJW.js} +16 -8
- package/dist/{chunk-5DXA2J44.js → chunk-7XHATCIH.js} +5 -2
- package/dist/{chunk-LQFGQNMV.js → chunk-AIF3Z2T7.js} +302 -39
- package/dist/{chunk-UCALUKB5.js → chunk-BAAG6ZTI.js} +98 -29
- package/dist/{chunk-NVNJH22U.js → chunk-D33YTSX5.js} +2 -2
- package/dist/{chunk-M2F7TZHH.js → chunk-DKGBBKOF.js} +136 -80
- package/dist/{chunk-NIOYEGBQ.js → chunk-HURREPU2.js} +27 -13
- package/dist/{chunk-HFCOH2GN.js → chunk-HYXDKS4N.js} +153 -110
- package/dist/chunk-J6FW5TV6.js +233 -0
- package/dist/{chunk-36S2YPP4.js → chunk-JSXPZCET.js} +1 -1
- package/dist/chunk-NYNYSPK7.js +318 -0
- package/dist/{chunk-HQSEH5F6.js → chunk-ORMZXBKQ.js} +108 -45
- package/dist/{chunk-LYVUX7NT.js → chunk-OXUY2A6L.js} +287 -130
- package/dist/{chunk-6GSIXTWX.js → chunk-PK6FK2G2.js} +187 -66
- package/dist/{chunk-W2EQ7X2L.js → chunk-QE4TTDU3.js} +47 -9
- package/dist/{chunk-XLO7SLIX.js → chunk-SXXVZMKZ.js} +262 -70
- package/dist/{chunk-R25EFXXC.js → chunk-TUCPL2HB.js} +3 -3
- package/dist/{chunk-RR7M3FHM.js → chunk-UZQ6ALFS.js} +3 -3
- package/dist/{chunk-PNIRUQ4C.js → chunk-VVWPJ543.js} +6 -8
- package/dist/{chunk-7GIHSAWB.js → chunk-XC4MEKGA.js} +3 -3
- package/dist/{chunk-SKPTERHP.js → chunk-XRRZKZYX.js} +55 -31
- package/dist/{contracts-DBdg9J_a.d.cts → contracts-DRIuclVT.d.cts} +10 -2
- package/dist/{contracts-DBdg9J_a.d.ts → contracts-DRIuclVT.d.ts} +10 -2
- package/dist/{customElement-CNZxEB9G.d.ts → customElement-MmInOW1U.d.cts} +59 -10
- package/dist/{customElement-CNZxEB9G.d.cts → customElement-MmInOW1U.d.ts} +59 -10
- package/dist/data.cjs +293 -125
- package/dist/data.d.cts +47 -9
- package/dist/data.d.ts +47 -9
- package/dist/data.js +12 -9
- package/dist/devtools.cjs +121 -58
- package/dist/devtools.js +7 -8
- package/dist/dispose-GEIG2KOF.js +28 -0
- package/dist/ecosystem.cjs +391 -112
- package/dist/ecosystem.d.cts +31 -7
- package/dist/ecosystem.d.ts +31 -7
- package/dist/ecosystem.js +12 -12
- package/dist/extras.cjs +2250 -879
- package/dist/extras.d.cts +10 -9
- package/dist/extras.d.ts +10 -9
- package/dist/extras.js +39 -28
- package/dist/index.cjs +273 -82
- package/dist/index.d.cts +44 -154
- package/dist/index.d.ts +44 -154
- package/dist/index.js +24 -27
- package/dist/motion.cjs +137 -42
- package/dist/motion.js +5 -5
- package/dist/patterns.cjs +397 -48
- package/dist/patterns.d.cts +32 -9
- package/dist/patterns.d.ts +32 -9
- package/dist/patterns.js +8 -8
- package/dist/performance.cjs +338 -217
- package/dist/performance.d.cts +2 -2
- package/dist/performance.d.ts +2 -2
- package/dist/performance.js +8 -9
- package/dist/plugin-DVgSnTfK.d.cts +112 -0
- package/dist/plugin-DVgSnTfK.d.ts +112 -0
- package/dist/plugins.cjs +587 -203
- package/dist/plugins.d.cts +3 -3
- package/dist/plugins.d.ts +3 -3
- package/dist/plugins.js +35 -23
- package/dist/signal-EotCj4hS.d.cts +110 -0
- package/dist/signal-EotCj4hS.d.ts +110 -0
- package/dist/{ssr-BiPRdZ6n.d.cts → ssr-Bli9XRW5.d.cts} +5 -0
- package/dist/{ssr-BiPRdZ6n.d.ts → ssr-Bli9XRW5.d.ts} +5 -0
- package/dist/{ssr-Y7XOEPEN.js → ssr-XOTUASDO.js} +4 -5
- package/dist/ssr.cjs +214 -73
- package/dist/ssr.d.cts +9 -3
- package/dist/ssr.d.ts +9 -3
- package/dist/ssr.js +11 -12
- package/dist/{startup-BMpaiMhP.d.ts → startup-BLfSeL15.d.cts} +73 -22
- package/dist/{startup-BMpaiMhP.d.cts → startup-BLfSeL15.d.ts} +73 -22
- package/dist/tagFactory-DFstCLQV.d.cts +117 -0
- package/dist/tagFactory-DkaNVUNV.d.ts +117 -0
- package/dist/testing.cjs +2481 -2153
- package/dist/testing.d.cts +56 -5
- package/dist/testing.d.ts +56 -5
- package/dist/testing.js +580 -307
- package/dist/ui.cjs +798 -328
- package/dist/ui.d.cts +40 -7
- package/dist/ui.d.ts +40 -7
- package/dist/ui.js +151 -56
- package/dist/widgets.cjs +319 -285
- package/dist/widgets.js +9 -10
- package/package.json +2 -2
- package/dist/chunk-2WLZ6757.js +0 -149
- package/dist/chunk-7NBDXVHS.js +0 -60
- package/dist/chunk-CCSJMTRN.js +0 -15
- package/dist/chunk-QKRPLZ2V.js +0 -108
- package/dist/chunk-WWV3SJ3L.js +0 -131
- package/dist/dispose-46BOMMQJ.js +0 -19
- package/dist/plugin-D30wlGW5.d.cts +0 -71
- package/dist/plugin-D30wlGW5.d.ts +0 -71
- package/dist/tagFactory-Bzupt4Pj.d.cts +0 -55
- package/dist/tagFactory-Bzupt4Pj.d.ts +0 -55
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
watch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UZQ6ALFS.js";
|
|
4
4
|
import {
|
|
5
|
-
createId
|
|
6
|
-
|
|
5
|
+
createId,
|
|
6
|
+
domBinding,
|
|
7
|
+
idSegment
|
|
8
|
+
} from "./chunk-3ISI6ACU.js";
|
|
7
9
|
import {
|
|
8
10
|
derived
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QE4TTDU3.js";
|
|
10
12
|
import {
|
|
11
13
|
stripHtml
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import {
|
|
14
|
-
effect
|
|
15
|
-
} from "./chunk-7GIHSAWB.js";
|
|
14
|
+
} from "./chunk-2INLLLMZ.js";
|
|
16
15
|
import {
|
|
17
16
|
batch,
|
|
18
17
|
signal
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-D33YTSX5.js";
|
|
20
19
|
|
|
21
20
|
// src/widgets/Combobox.ts
|
|
22
21
|
var boundComboboxes = /* @__PURE__ */ new WeakMap();
|
|
@@ -91,7 +90,7 @@ function combobox(options) {
|
|
|
91
90
|
els.input.setAttribute("role", "combobox");
|
|
92
91
|
els.input.setAttribute("aria-autocomplete", "list");
|
|
93
92
|
els.input.setAttribute("aria-controls", listboxId);
|
|
94
|
-
const fxTeardown =
|
|
93
|
+
const fxTeardown = domBinding(() => {
|
|
95
94
|
const open2 = isOpen();
|
|
96
95
|
els.input.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
97
96
|
els.listbox.hidden = !open2;
|
|
@@ -109,7 +108,7 @@ function combobox(options) {
|
|
|
109
108
|
}
|
|
110
109
|
if (activeId) els.input.setAttribute("aria-activedescendant", activeId);
|
|
111
110
|
else els.input.removeAttribute("aria-activedescendant");
|
|
112
|
-
});
|
|
111
|
+
}, els.input);
|
|
113
112
|
const onInput = () => {
|
|
114
113
|
setQuery(els.input.value);
|
|
115
114
|
open();
|
|
@@ -157,8 +156,11 @@ function combobox(options) {
|
|
|
157
156
|
els.input.addEventListener("focus", onFocus);
|
|
158
157
|
els.input.addEventListener("blur", onBlur);
|
|
159
158
|
els.listbox.addEventListener("mousedown", onListboxPointerDown);
|
|
159
|
+
let tornDown = false;
|
|
160
160
|
const teardown = () => {
|
|
161
|
-
|
|
161
|
+
if (tornDown) return;
|
|
162
|
+
tornDown = true;
|
|
163
|
+
if (boundComboboxes.get(els.input) === teardown) boundComboboxes.delete(els.input);
|
|
162
164
|
fxTeardown();
|
|
163
165
|
els.input.removeEventListener("input", onInput);
|
|
164
166
|
els.input.removeEventListener("keydown", onKey);
|
|
@@ -203,11 +205,23 @@ function combobox(options) {
|
|
|
203
205
|
};
|
|
204
206
|
}
|
|
205
207
|
|
|
208
|
+
// src/widgets/attributeSnapshot.ts
|
|
209
|
+
function snapshotAttributes(el, names) {
|
|
210
|
+
const previous = names.map((name) => [name, el.getAttribute(name)]);
|
|
211
|
+
return () => {
|
|
212
|
+
for (const [name, value] of previous) {
|
|
213
|
+
if (value === null) el.removeAttribute(name);
|
|
214
|
+
else el.setAttribute(name, value);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
206
219
|
// src/widgets/Tabs.ts
|
|
207
220
|
var boundTablists = /* @__PURE__ */ new WeakMap();
|
|
208
221
|
function tabs(options) {
|
|
209
222
|
const { tabs: tabDefs, defaultTab } = options;
|
|
210
|
-
const
|
|
223
|
+
const firstEnabled = tabDefs.find((t) => !t.disabled)?.id ?? "";
|
|
224
|
+
const initialTab = defaultTab !== void 0 && tabDefs.some((t) => t.id === defaultTab && !t.disabled) ? defaultTab : firstEnabled;
|
|
211
225
|
const [activeTab, setActiveTabState] = signal(initialTab);
|
|
212
226
|
function setActiveTab(id) {
|
|
213
227
|
const tab = tabDefs.find((t) => t.id === id);
|
|
@@ -254,58 +268,29 @@ function tabs(options) {
|
|
|
254
268
|
function bind(els) {
|
|
255
269
|
const existing = boundTablists.get(els.tablist);
|
|
256
270
|
if (existing) return existing;
|
|
257
|
-
const restore = [];
|
|
258
|
-
const prevTablistRole = els.tablist.getAttribute("role");
|
|
271
|
+
const restore = [snapshotAttributes(els.tablist, ["role"])];
|
|
259
272
|
els.tablist.setAttribute("role", "tablist");
|
|
260
|
-
|
|
261
|
-
if (prevTablistRole === null) els.tablist.removeAttribute("role");
|
|
262
|
-
else els.tablist.setAttribute("role", prevTablistRole);
|
|
263
|
-
});
|
|
273
|
+
const idPrefix = createId("sibu-tabs");
|
|
264
274
|
for (const def of tabDefs) {
|
|
265
275
|
const tabEl = els.tabs[def.id];
|
|
266
276
|
if (!tabEl) continue;
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const prevControls = tabEl.getAttribute("aria-controls");
|
|
277
|
+
restore.push(
|
|
278
|
+
snapshotAttributes(tabEl, ["role", "id", "aria-disabled", "aria-controls", "aria-selected", "tabindex"])
|
|
279
|
+
);
|
|
271
280
|
tabEl.setAttribute("role", "tab");
|
|
272
|
-
tabEl.
|
|
281
|
+
if (!tabEl.id) tabEl.id = `${idPrefix}-tab-${idSegment(def.id)}`;
|
|
273
282
|
if (def.disabled) tabEl.setAttribute("aria-disabled", "true");
|
|
283
|
+
else tabEl.removeAttribute("aria-disabled");
|
|
274
284
|
const panelEl = els.panels?.[def.id];
|
|
275
|
-
let prevPanelRole = null;
|
|
276
|
-
let prevPanelId = "";
|
|
277
|
-
let prevPanelLabelledBy = null;
|
|
278
285
|
if (panelEl) {
|
|
279
|
-
|
|
280
|
-
prevPanelId = panelEl.id;
|
|
281
|
-
prevPanelLabelledBy = panelEl.getAttribute("aria-labelledby");
|
|
286
|
+
restore.push(snapshotAttributes(panelEl, ["role", "id", "aria-labelledby", "hidden"]));
|
|
282
287
|
panelEl.setAttribute("role", "tabpanel");
|
|
283
|
-
panelEl.
|
|
284
|
-
panelEl.setAttribute("aria-labelledby",
|
|
285
|
-
tabEl.setAttribute("aria-controls",
|
|
288
|
+
if (!panelEl.id) panelEl.id = `${idPrefix}-panel-${idSegment(def.id)}`;
|
|
289
|
+
panelEl.setAttribute("aria-labelledby", tabEl.id);
|
|
290
|
+
tabEl.setAttribute("aria-controls", panelEl.id);
|
|
286
291
|
}
|
|
287
|
-
restore.push(() => {
|
|
288
|
-
if (prevRole === null) tabEl.removeAttribute("role");
|
|
289
|
-
else tabEl.setAttribute("role", prevRole);
|
|
290
|
-
if (prevId === "") tabEl.removeAttribute("id");
|
|
291
|
-
else tabEl.id = prevId;
|
|
292
|
-
if (prevDisabled === null) tabEl.removeAttribute("aria-disabled");
|
|
293
|
-
else tabEl.setAttribute("aria-disabled", prevDisabled);
|
|
294
|
-
if (prevControls === null) tabEl.removeAttribute("aria-controls");
|
|
295
|
-
else tabEl.setAttribute("aria-controls", prevControls);
|
|
296
|
-
tabEl.removeAttribute("aria-selected");
|
|
297
|
-
tabEl.removeAttribute("tabindex");
|
|
298
|
-
if (panelEl) {
|
|
299
|
-
if (prevPanelRole === null) panelEl.removeAttribute("role");
|
|
300
|
-
else panelEl.setAttribute("role", prevPanelRole);
|
|
301
|
-
if (prevPanelId === "") panelEl.removeAttribute("id");
|
|
302
|
-
else panelEl.id = prevPanelId;
|
|
303
|
-
if (prevPanelLabelledBy === null) panelEl.removeAttribute("aria-labelledby");
|
|
304
|
-
else panelEl.setAttribute("aria-labelledby", prevPanelLabelledBy);
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
292
|
}
|
|
308
|
-
const fxTeardown =
|
|
293
|
+
const fxTeardown = domBinding(() => {
|
|
309
294
|
const active = activeTab();
|
|
310
295
|
for (const def of tabDefs) {
|
|
311
296
|
const tabEl = els.tabs[def.id];
|
|
@@ -316,7 +301,7 @@ function tabs(options) {
|
|
|
316
301
|
const panelEl = els.panels?.[def.id];
|
|
317
302
|
if (panelEl) panelEl.hidden = !isAct;
|
|
318
303
|
}
|
|
319
|
-
});
|
|
304
|
+
}, els.tablist);
|
|
320
305
|
const onKey = (e) => {
|
|
321
306
|
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
322
307
|
e.preventDefault();
|
|
@@ -353,7 +338,10 @@ function tabs(options) {
|
|
|
353
338
|
tabEl.addEventListener("click", fn);
|
|
354
339
|
clickHandlers.push({ el: tabEl, fn });
|
|
355
340
|
}
|
|
341
|
+
let tornDown = false;
|
|
356
342
|
const teardown = () => {
|
|
343
|
+
if (tornDown) return;
|
|
344
|
+
tornDown = true;
|
|
357
345
|
boundTablists.delete(els.tablist);
|
|
358
346
|
fxTeardown();
|
|
359
347
|
els.tablist.removeEventListener("keydown", onKey);
|
|
@@ -379,7 +367,10 @@ function tabs(options) {
|
|
|
379
367
|
var boundAccordions = /* @__PURE__ */ new WeakMap();
|
|
380
368
|
function accordion(options) {
|
|
381
369
|
const { items: itemDefs, multiple = false, defaultExpanded = [] } = options;
|
|
382
|
-
const
|
|
370
|
+
const knownIds = new Set(itemDefs.map((item) => item.id));
|
|
371
|
+
const validDefaults = defaultExpanded.filter((id) => knownIds.has(id));
|
|
372
|
+
const initialExpanded = multiple ? validDefaults : validDefaults.slice(0, 1);
|
|
373
|
+
const [expandedIds, setExpandedIds] = signal(new Set(initialExpanded));
|
|
383
374
|
const items = derived(
|
|
384
375
|
() => itemDefs.map((item) => ({
|
|
385
376
|
...item,
|
|
@@ -430,42 +421,22 @@ function accordion(options) {
|
|
|
430
421
|
if (existing) return existing;
|
|
431
422
|
}
|
|
432
423
|
const restore = [];
|
|
424
|
+
const idPrefix = createId("sibu-accordion");
|
|
433
425
|
for (const item of itemDefs) {
|
|
434
426
|
const trig = els.triggers[item.id];
|
|
435
427
|
const panel = els.panels[item.id];
|
|
436
428
|
if (!trig) continue;
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
trig.id = `sibu-accordion-trigger-${item.id}`;
|
|
440
|
-
let prevPanelRole = null;
|
|
441
|
-
let prevPanelId = "";
|
|
442
|
-
let prevPanelLabelledBy = null;
|
|
429
|
+
restore.push(snapshotAttributes(trig, ["id", "aria-controls", "aria-expanded"]));
|
|
430
|
+
if (!trig.id) trig.id = `${idPrefix}-trigger-${idSegment(item.id)}`;
|
|
443
431
|
if (panel) {
|
|
444
|
-
|
|
445
|
-
prevPanelId = panel.id;
|
|
446
|
-
prevPanelLabelledBy = panel.getAttribute("aria-labelledby");
|
|
432
|
+
restore.push(snapshotAttributes(panel, ["role", "id", "aria-labelledby", "hidden"]));
|
|
447
433
|
panel.setAttribute("role", "region");
|
|
448
|
-
panel.id =
|
|
434
|
+
if (!panel.id) panel.id = `${idPrefix}-panel-${idSegment(item.id)}`;
|
|
449
435
|
panel.setAttribute("aria-labelledby", trig.id);
|
|
450
436
|
trig.setAttribute("aria-controls", panel.id);
|
|
451
437
|
}
|
|
452
|
-
restore.push(() => {
|
|
453
|
-
if (prevTrigId === "") trig.removeAttribute("id");
|
|
454
|
-
else trig.id = prevTrigId;
|
|
455
|
-
if (prevTrigControls === null) trig.removeAttribute("aria-controls");
|
|
456
|
-
else trig.setAttribute("aria-controls", prevTrigControls);
|
|
457
|
-
trig.removeAttribute("aria-expanded");
|
|
458
|
-
if (panel) {
|
|
459
|
-
if (prevPanelRole === null) panel.removeAttribute("role");
|
|
460
|
-
else panel.setAttribute("role", prevPanelRole);
|
|
461
|
-
if (prevPanelId === "") panel.removeAttribute("id");
|
|
462
|
-
else panel.id = prevPanelId;
|
|
463
|
-
if (prevPanelLabelledBy === null) panel.removeAttribute("aria-labelledby");
|
|
464
|
-
else panel.setAttribute("aria-labelledby", prevPanelLabelledBy);
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
438
|
}
|
|
468
|
-
const fxTeardown =
|
|
439
|
+
const fxTeardown = domBinding(() => {
|
|
469
440
|
const ids = expandedIds();
|
|
470
441
|
for (const item of itemDefs) {
|
|
471
442
|
const trig = els.triggers[item.id];
|
|
@@ -475,7 +446,7 @@ function accordion(options) {
|
|
|
475
446
|
trig.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
476
447
|
if (panel) panel.hidden = !expanded;
|
|
477
448
|
}
|
|
478
|
-
});
|
|
449
|
+
}, idempotencyKey);
|
|
479
450
|
const handlers = [];
|
|
480
451
|
for (const item of itemDefs) {
|
|
481
452
|
const trig = els.triggers[item.id];
|
|
@@ -491,7 +462,10 @@ function accordion(options) {
|
|
|
491
462
|
trig.addEventListener("keydown", key);
|
|
492
463
|
handlers.push({ el: trig, click, key });
|
|
493
464
|
}
|
|
465
|
+
let tornDown = false;
|
|
494
466
|
const teardown = () => {
|
|
467
|
+
if (tornDown) return;
|
|
468
|
+
tornDown = true;
|
|
495
469
|
if (idempotencyKey) boundAccordions.delete(idempotencyKey);
|
|
496
470
|
fxTeardown();
|
|
497
471
|
for (const { el, click, key } of handlers) {
|
|
@@ -550,11 +524,11 @@ function popover() {
|
|
|
550
524
|
}
|
|
551
525
|
els.popover.setAttribute("aria-labelledby", els.labelledBy.id);
|
|
552
526
|
}
|
|
553
|
-
const fxTeardown =
|
|
527
|
+
const fxTeardown = domBinding(() => {
|
|
554
528
|
const open2 = isOpen();
|
|
555
529
|
els.trigger.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
556
530
|
els.popover.hidden = !open2;
|
|
557
|
-
});
|
|
531
|
+
}, els.trigger);
|
|
558
532
|
const onTriggerClick = (e) => {
|
|
559
533
|
e.preventDefault();
|
|
560
534
|
toggle();
|
|
@@ -577,8 +551,11 @@ function popover() {
|
|
|
577
551
|
els.popover.addEventListener("keydown", onKey);
|
|
578
552
|
els.trigger.addEventListener("keydown", onKey);
|
|
579
553
|
document.addEventListener("pointerdown", onDocPointer);
|
|
554
|
+
let tornDown = false;
|
|
580
555
|
const teardown = () => {
|
|
581
|
-
|
|
556
|
+
if (tornDown) return;
|
|
557
|
+
tornDown = true;
|
|
558
|
+
if (boundPopovers.get(els.trigger) === teardown) boundPopovers.delete(els.trigger);
|
|
582
559
|
fxTeardown();
|
|
583
560
|
els.trigger.removeEventListener("click", onTriggerClick);
|
|
584
561
|
els.popover.removeEventListener("keydown", onKey);
|
|
@@ -696,7 +673,7 @@ function select(options) {
|
|
|
696
673
|
els.listbox.setAttribute("aria-multiselectable", multiple ? "true" : "false");
|
|
697
674
|
if (els.listbox.tabIndex < 0) els.listbox.tabIndex = 0;
|
|
698
675
|
const toStr = els.itemToString ?? itemToString ?? ((it) => String(it));
|
|
699
|
-
const fxTeardown =
|
|
676
|
+
const fxTeardown = domBinding(() => {
|
|
700
677
|
const idx = highlightedIndex();
|
|
701
678
|
const sel = selectedItems();
|
|
702
679
|
let activeId = "";
|
|
@@ -706,13 +683,14 @@ function select(options) {
|
|
|
706
683
|
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
707
684
|
optEl.setAttribute("role", "option");
|
|
708
685
|
optEl.setAttribute("aria-selected", sel.includes(items[i]) ? "true" : "false");
|
|
709
|
-
|
|
686
|
+
const disabled = isItemDisabled(items[i]);
|
|
687
|
+
if (disabled) optEl.setAttribute("aria-disabled", "true");
|
|
710
688
|
else optEl.removeAttribute("aria-disabled");
|
|
711
|
-
if (i === idx) activeId = optEl.id;
|
|
689
|
+
if (i === idx && !disabled) activeId = optEl.id;
|
|
712
690
|
}
|
|
713
691
|
if (activeId) els.listbox.setAttribute("aria-activedescendant", activeId);
|
|
714
692
|
else els.listbox.removeAttribute("aria-activedescendant");
|
|
715
|
-
});
|
|
693
|
+
}, els.listbox);
|
|
716
694
|
let typeBuffer = "";
|
|
717
695
|
let typeTimer = null;
|
|
718
696
|
const onKey = (e) => {
|
|
@@ -724,10 +702,12 @@ function select(options) {
|
|
|
724
702
|
highlightPrev();
|
|
725
703
|
} else if (e.key === "Home") {
|
|
726
704
|
e.preventDefault();
|
|
727
|
-
|
|
705
|
+
const first = nextEnabled(-1, 1);
|
|
706
|
+
if (first !== -1) setHighlightedIndex(first);
|
|
728
707
|
} else if (e.key === "End") {
|
|
729
708
|
e.preventDefault();
|
|
730
|
-
|
|
709
|
+
const last = nextEnabled(items.length, -1);
|
|
710
|
+
if (last !== -1) setHighlightedIndex(last);
|
|
731
711
|
} else if (e.key === "Enter" || e.key === " ") {
|
|
732
712
|
if (highlightedIndex() >= 0) {
|
|
733
713
|
e.preventDefault();
|
|
@@ -745,8 +725,11 @@ function select(options) {
|
|
|
745
725
|
}
|
|
746
726
|
};
|
|
747
727
|
els.listbox.addEventListener("keydown", onKey);
|
|
728
|
+
let tornDown = false;
|
|
748
729
|
const teardown = () => {
|
|
749
|
-
|
|
730
|
+
if (tornDown) return;
|
|
731
|
+
tornDown = true;
|
|
732
|
+
if (boundSelects.get(els.listbox) === teardown) boundSelects.delete(els.listbox);
|
|
750
733
|
fxTeardown();
|
|
751
734
|
els.listbox.removeEventListener("keydown", onKey);
|
|
752
735
|
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
@@ -832,9 +815,9 @@ function tooltip(options) {
|
|
|
832
815
|
els.tooltip.id = id;
|
|
833
816
|
const prevDescribedBy = els.trigger.getAttribute("aria-describedby");
|
|
834
817
|
els.trigger.setAttribute("aria-describedby", prevDescribedBy ? `${prevDescribedBy} ${id}` : id);
|
|
835
|
-
const fxTeardown =
|
|
818
|
+
const fxTeardown = domBinding(() => {
|
|
836
819
|
els.tooltip.hidden = !isVisible();
|
|
837
|
-
});
|
|
820
|
+
}, els.trigger);
|
|
838
821
|
const onTriggerEnter = () => show();
|
|
839
822
|
const onTriggerLeave = () => scheduleHide();
|
|
840
823
|
const onTooltipEnter = () => {
|
|
@@ -859,8 +842,11 @@ function tooltip(options) {
|
|
|
859
842
|
els.trigger.addEventListener("keydown", onKey);
|
|
860
843
|
els.tooltip.addEventListener("pointerenter", onTooltipEnter);
|
|
861
844
|
els.tooltip.addEventListener("pointerleave", onTooltipLeave);
|
|
845
|
+
let tornDown = false;
|
|
862
846
|
const teardown = () => {
|
|
863
|
-
|
|
847
|
+
if (tornDown) return;
|
|
848
|
+
tornDown = true;
|
|
849
|
+
if (boundTriggers.get(els.trigger) === teardown) boundTriggers.delete(els.trigger);
|
|
864
850
|
fxTeardown();
|
|
865
851
|
els.trigger.removeEventListener("pointerenter", onTriggerEnter);
|
|
866
852
|
els.trigger.removeEventListener("pointerleave", onTriggerLeave);
|
|
@@ -898,7 +884,8 @@ function fileUpload(options) {
|
|
|
898
884
|
const [isDragOver, setDragOver] = signal(false);
|
|
899
885
|
function isAccepted(file) {
|
|
900
886
|
if (!accept) return true;
|
|
901
|
-
const acceptedTypes = accept.split(",").map((t) => t.trim().toLowerCase());
|
|
887
|
+
const acceptedTypes = accept.split(",").map((t) => t.trim().toLowerCase()).filter((t) => t.length > 0);
|
|
888
|
+
if (acceptedTypes.length === 0) return true;
|
|
902
889
|
const fileName = file.name.toLowerCase();
|
|
903
890
|
const fileType = file.type.toLowerCase();
|
|
904
891
|
return acceptedTypes.some((pattern) => {
|
|
@@ -927,16 +914,17 @@ function fileUpload(options) {
|
|
|
927
914
|
}
|
|
928
915
|
validFiles.push(file);
|
|
929
916
|
}
|
|
917
|
+
const committed = multiple ? validFiles : validFiles.slice(-1);
|
|
930
918
|
batch(() => {
|
|
931
919
|
setErrors(newErrors);
|
|
932
|
-
if (
|
|
920
|
+
if (committed.length > 0) {
|
|
933
921
|
if (multiple) {
|
|
934
|
-
setFiles((prev) => [...prev, ...
|
|
922
|
+
setFiles((prev) => [...prev, ...committed]);
|
|
935
923
|
} else {
|
|
936
|
-
setFiles(
|
|
924
|
+
setFiles(committed);
|
|
937
925
|
}
|
|
938
926
|
if (onFiles) {
|
|
939
|
-
onFiles(
|
|
927
|
+
onFiles(committed);
|
|
940
928
|
}
|
|
941
929
|
}
|
|
942
930
|
});
|
|
@@ -960,8 +948,15 @@ function fileUpload(options) {
|
|
|
960
948
|
if (existing) return existing;
|
|
961
949
|
const id = createId("sibu-fileupload");
|
|
962
950
|
const restore = [];
|
|
951
|
+
const prevAccept = els.input.getAttribute("accept");
|
|
952
|
+
const prevMultiple = els.input.hasAttribute("multiple");
|
|
963
953
|
if (accept) els.input.accept = accept;
|
|
964
954
|
els.input.multiple = multiple;
|
|
955
|
+
restore.push(() => {
|
|
956
|
+
if (prevAccept === null) els.input.removeAttribute("accept");
|
|
957
|
+
else els.input.setAttribute("accept", prevAccept);
|
|
958
|
+
els.input.multiple = prevMultiple;
|
|
959
|
+
});
|
|
965
960
|
let hintId = null;
|
|
966
961
|
if (els.hint) {
|
|
967
962
|
const assignedHintId = !els.hint.id;
|
|
@@ -982,6 +977,7 @@ function fileUpload(options) {
|
|
|
982
977
|
if (els.errorRegion) {
|
|
983
978
|
const prevRole = els.errorRegion.getAttribute("role");
|
|
984
979
|
const prevLive = els.errorRegion.getAttribute("aria-live");
|
|
980
|
+
const prevText = els.errorRegion.textContent;
|
|
985
981
|
els.errorRegion.setAttribute("role", "status");
|
|
986
982
|
els.errorRegion.setAttribute("aria-live", "polite");
|
|
987
983
|
restore.push(() => {
|
|
@@ -989,12 +985,14 @@ function fileUpload(options) {
|
|
|
989
985
|
else els.errorRegion.setAttribute("role", prevRole);
|
|
990
986
|
if (prevLive === null) els.errorRegion.removeAttribute("aria-live");
|
|
991
987
|
else els.errorRegion.setAttribute("aria-live", prevLive);
|
|
988
|
+
els.errorRegion.textContent = prevText;
|
|
992
989
|
});
|
|
993
990
|
}
|
|
994
991
|
if (els.dropZone) {
|
|
995
992
|
const prevDzRole = els.dropZone.getAttribute("role");
|
|
996
993
|
const prevDzLabel = els.dropZone.getAttribute("aria-label");
|
|
997
994
|
const prevDzTabindex = els.dropZone.hasAttribute("tabindex") ? els.dropZone.getAttribute("tabindex") : null;
|
|
995
|
+
const prevDzDragOver = els.dropZone.getAttribute("data-drag-over");
|
|
998
996
|
els.dropZone.setAttribute("role", "button");
|
|
999
997
|
els.dropZone.setAttribute("aria-label", "File drop zone \u2014 click or press Enter to browse");
|
|
1000
998
|
if (els.dropZone.tabIndex < 0) els.dropZone.tabIndex = 0;
|
|
@@ -1005,13 +1003,15 @@ function fileUpload(options) {
|
|
|
1005
1003
|
else els.dropZone.setAttribute("aria-label", prevDzLabel);
|
|
1006
1004
|
if (prevDzTabindex === null) els.dropZone.removeAttribute("tabindex");
|
|
1007
1005
|
else els.dropZone.setAttribute("tabindex", prevDzTabindex);
|
|
1006
|
+
if (prevDzDragOver === null) els.dropZone.removeAttribute("data-drag-over");
|
|
1007
|
+
else els.dropZone.setAttribute("data-drag-over", prevDzDragOver);
|
|
1008
1008
|
});
|
|
1009
1009
|
}
|
|
1010
|
-
const fxTeardown =
|
|
1010
|
+
const fxTeardown = domBinding(() => {
|
|
1011
1011
|
const errs = errors();
|
|
1012
1012
|
if (els.errorRegion) els.errorRegion.textContent = errs.join(". ");
|
|
1013
1013
|
if (els.dropZone) els.dropZone.setAttribute("data-drag-over", isDragOver() ? "true" : "false");
|
|
1014
|
-
});
|
|
1014
|
+
}, els.input);
|
|
1015
1015
|
const onChange = () => {
|
|
1016
1016
|
if (els.input.files) addFiles(els.input.files);
|
|
1017
1017
|
};
|
|
@@ -1040,7 +1040,10 @@ function fileUpload(options) {
|
|
|
1040
1040
|
els.dropZone.addEventListener("dragleave", onDragLeave);
|
|
1041
1041
|
els.dropZone.addEventListener("drop", onDrop);
|
|
1042
1042
|
}
|
|
1043
|
+
let tornDown = false;
|
|
1043
1044
|
const teardown = () => {
|
|
1045
|
+
if (tornDown) return;
|
|
1046
|
+
tornDown = true;
|
|
1044
1047
|
boundFileUploads.delete(els.input);
|
|
1045
1048
|
fxTeardown();
|
|
1046
1049
|
els.input.removeEventListener("change", onChange);
|
|
@@ -1069,12 +1072,15 @@ function fileUpload(options) {
|
|
|
1069
1072
|
}
|
|
1070
1073
|
|
|
1071
1074
|
// src/widgets/contentEditable.ts
|
|
1075
|
+
function toInertText(html) {
|
|
1076
|
+
return stripHtml(String(html)).replace(/<(?=[a-z!/?])/gi, "<");
|
|
1077
|
+
}
|
|
1072
1078
|
function contentEditable(element) {
|
|
1073
1079
|
const [content, setContentInternal] = signal("");
|
|
1074
1080
|
const [isFocused, setFocused] = signal(false);
|
|
1075
1081
|
function setContent(input) {
|
|
1076
1082
|
if (typeof input === "string") {
|
|
1077
|
-
setContentInternal(input);
|
|
1083
|
+
setContentInternal(toInertText(input));
|
|
1078
1084
|
return;
|
|
1079
1085
|
}
|
|
1080
1086
|
if (typeof input.text === "string") {
|
|
@@ -1083,7 +1089,7 @@ function contentEditable(element) {
|
|
|
1083
1089
|
}
|
|
1084
1090
|
if (typeof input.html === "string") {
|
|
1085
1091
|
const shouldSanitize = input.sanitize !== false;
|
|
1086
|
-
setContentInternal(shouldSanitize ?
|
|
1092
|
+
setContentInternal(shouldSanitize ? toInertText(input.html) : input.html);
|
|
1087
1093
|
return;
|
|
1088
1094
|
}
|
|
1089
1095
|
setContentInternal("");
|
|
@@ -1095,7 +1101,7 @@ function contentEditable(element) {
|
|
|
1095
1101
|
const range = selection.getRangeAt(0);
|
|
1096
1102
|
if (element && !element.contains(range.commonAncestorContainer)) return;
|
|
1097
1103
|
const ancestor = range.commonAncestorContainer;
|
|
1098
|
-
const existingWrap =
|
|
1104
|
+
const existingWrap = findWrapperWithinEditor(
|
|
1099
1105
|
ancestor instanceof HTMLElement ? ancestor : ancestor.parentElement,
|
|
1100
1106
|
tagName
|
|
1101
1107
|
);
|
|
@@ -1136,14 +1142,19 @@ function contentEditable(element) {
|
|
|
1136
1142
|
selection.addRange(newRange);
|
|
1137
1143
|
}
|
|
1138
1144
|
}
|
|
1139
|
-
function
|
|
1145
|
+
function findWrapperWithinEditor(el, tagName) {
|
|
1140
1146
|
const upper = tagName.toUpperCase();
|
|
1141
1147
|
while (el) {
|
|
1148
|
+
if (el === element || isEditingHost(el)) return null;
|
|
1142
1149
|
if (el.tagName === upper) return el;
|
|
1143
1150
|
el = el.parentElement;
|
|
1144
1151
|
}
|
|
1145
1152
|
return null;
|
|
1146
1153
|
}
|
|
1154
|
+
function isEditingHost(el) {
|
|
1155
|
+
const attr = el.getAttribute("contenteditable");
|
|
1156
|
+
return attr !== null && attr.toLowerCase() !== "false";
|
|
1157
|
+
}
|
|
1147
1158
|
function bold() {
|
|
1148
1159
|
wrapSelection("strong");
|
|
1149
1160
|
}
|
|
@@ -1279,15 +1290,36 @@ function datePicker(options) {
|
|
|
1279
1290
|
els.grid.setAttribute("role", "grid");
|
|
1280
1291
|
if (els.grid.tabIndex < 0) els.grid.tabIndex = 0;
|
|
1281
1292
|
let pendingFocus = false;
|
|
1282
|
-
const
|
|
1293
|
+
const touchedCells = /* @__PURE__ */ new Map();
|
|
1294
|
+
const restoreAttr = (el, name, value) => {
|
|
1295
|
+
if (value === null) el.removeAttribute(name);
|
|
1296
|
+
else el.setAttribute(name, value);
|
|
1297
|
+
};
|
|
1298
|
+
const restoreCell = (cell, snap) => {
|
|
1299
|
+
restoreAttr(cell, "role", snap.role);
|
|
1300
|
+
restoreAttr(cell, "aria-selected", snap.selected);
|
|
1301
|
+
restoreAttr(cell, "aria-disabled", snap.disabled);
|
|
1302
|
+
restoreAttr(cell, "tabindex", snap.tabindex);
|
|
1303
|
+
};
|
|
1304
|
+
const fxTeardown = domBinding(() => {
|
|
1283
1305
|
const sel = selectedDate();
|
|
1284
1306
|
const view = viewDate();
|
|
1285
1307
|
const days = daysInMonth();
|
|
1286
1308
|
els.grid.setAttribute("aria-label", view.toLocaleDateString(void 0, { month: "long", year: "numeric" }));
|
|
1287
1309
|
let viewCell = null;
|
|
1310
|
+
const displayed = /* @__PURE__ */ new Set();
|
|
1288
1311
|
for (const d of days) {
|
|
1289
1312
|
const cell = els.cell(d.date);
|
|
1290
1313
|
if (!cell) continue;
|
|
1314
|
+
displayed.add(cell);
|
|
1315
|
+
if (!touchedCells.has(cell)) {
|
|
1316
|
+
touchedCells.set(cell, {
|
|
1317
|
+
role: cell.getAttribute("role"),
|
|
1318
|
+
selected: cell.getAttribute("aria-selected"),
|
|
1319
|
+
disabled: cell.getAttribute("aria-disabled"),
|
|
1320
|
+
tabindex: cell.getAttribute("tabindex")
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1291
1323
|
cell.setAttribute("role", "gridcell");
|
|
1292
1324
|
cell.setAttribute("aria-selected", sel && isSameCalendarDay(sel, d.date) ? "true" : "false");
|
|
1293
1325
|
if (d.isDisabled) cell.setAttribute("aria-disabled", "true");
|
|
@@ -1296,11 +1328,17 @@ function datePicker(options) {
|
|
|
1296
1328
|
cell.tabIndex = isView ? 0 : -1;
|
|
1297
1329
|
if (isView) viewCell = cell;
|
|
1298
1330
|
}
|
|
1331
|
+
for (const [cell, snap] of touchedCells) {
|
|
1332
|
+
if (!displayed.has(cell)) {
|
|
1333
|
+
restoreCell(cell, snap);
|
|
1334
|
+
touchedCells.delete(cell);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1299
1337
|
if (pendingFocus && viewCell && typeof viewCell.focus === "function") {
|
|
1300
1338
|
pendingFocus = false;
|
|
1301
1339
|
viewCell.focus();
|
|
1302
1340
|
}
|
|
1303
|
-
});
|
|
1341
|
+
}, els.grid);
|
|
1304
1342
|
function isSameCalendarDay(a, b) {
|
|
1305
1343
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1306
1344
|
}
|
|
@@ -1355,8 +1393,11 @@ function datePicker(options) {
|
|
|
1355
1393
|
}
|
|
1356
1394
|
};
|
|
1357
1395
|
els.grid.addEventListener("keydown", onKey);
|
|
1396
|
+
let tornDown = false;
|
|
1358
1397
|
const teardown = () => {
|
|
1359
|
-
|
|
1398
|
+
if (tornDown) return;
|
|
1399
|
+
tornDown = true;
|
|
1400
|
+
if (boundDatePickers.get(els.grid) === teardown) boundDatePickers.delete(els.grid);
|
|
1360
1401
|
fxTeardown();
|
|
1361
1402
|
els.grid.removeEventListener("keydown", onKey);
|
|
1362
1403
|
if (prevGridRole === null) els.grid.removeAttribute("role");
|
|
@@ -1365,6 +1406,8 @@ function datePicker(options) {
|
|
|
1365
1406
|
else els.grid.setAttribute("tabindex", prevGridTabIndex);
|
|
1366
1407
|
if (prevGridLabel === null) els.grid.removeAttribute("aria-label");
|
|
1367
1408
|
else els.grid.setAttribute("aria-label", prevGridLabel);
|
|
1409
|
+
for (const [cell, snap] of touchedCells) restoreCell(cell, snap);
|
|
1410
|
+
touchedCells.clear();
|
|
1368
1411
|
};
|
|
1369
1412
|
boundDatePickers.set(els.grid, teardown);
|
|
1370
1413
|
return teardown;
|