sibujs 4.12.0 → 4.13.1
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/browser.cjs +71 -18
- package/dist/browser.js +4 -4
- package/dist/build.cjs +6618 -6178
- package/dist/build.d.cts +554 -415
- package/dist/build.d.ts +554 -415
- package/dist/build.js +2091 -1735
- package/dist/cdn.dev.global.js +12 -12
- package/dist/cdn.full.dev.global.js +13 -13
- package/dist/cdn.full.global.js +12 -12
- package/dist/cdn.global.js +12 -12
- package/dist/{chunk-WFRQ6D7H.js → chunk-22OPSWMF.js} +1 -1
- package/dist/{chunk-ZJCHY2IB.js → chunk-2NC56RGY.js} +1 -1
- package/dist/{chunk-NB7TFSJE.js → chunk-2O6JJCUR.js} +4 -4
- package/dist/{chunk-B2Y5BJSP.js → chunk-4UTGDVSA.js} +70 -16
- package/dist/{chunk-NAVLCP4S.js → chunk-5RIBLY2N.js} +4 -4
- package/dist/{chunk-T5O2CUHV.js → chunk-5XUGJM3J.js} +1 -1
- package/dist/{chunk-HXT2RNH5.js → chunk-ADZHPN2B.js} +1 -1
- package/dist/chunk-B36ADEIR.js +21 -0
- package/dist/{chunk-DFZL3AX7.js → chunk-C73VBPEF.js} +9 -5
- package/dist/{chunk-WH4U2VUE.js → chunk-CPQKWCJ2.js} +13 -5
- package/dist/{chunk-LEUEKK4G.js → chunk-EU7T7EB3.js} +2 -2
- package/dist/{chunk-QLG5IK7F.js → chunk-G3Z2FEBR.js} +4 -4
- package/dist/{chunk-ZPY2UAKM.js → chunk-J4X7ICH4.js} +3 -3
- package/dist/{chunk-XX4BRMWF.js → chunk-K4LNUT5L.js} +1 -1
- package/dist/{chunk-CI4W6XAU.js → chunk-KC62VURU.js} +3 -3
- package/dist/chunk-N5TBYXHW.js +17 -0
- package/dist/{chunk-653KGQS2.js → chunk-OIKD7YDY.js} +2 -2
- package/dist/{chunk-LYTUTXQP.js → chunk-PBJYCE2Z.js} +46 -4
- package/dist/{chunk-EMB5PG7V.js → chunk-QC3NP47A.js} +1 -1
- package/dist/{chunk-IHA62NGJ.js → chunk-QKFVMIAV.js} +1 -1
- package/dist/{chunk-LXBMVGVB.js → chunk-QZ47OZ25.js} +3 -3
- package/dist/{chunk-ZTYCCBU3.js → chunk-VFPLWUT7.js} +44 -26
- package/dist/{chunk-RK7EPQPG.js → chunk-YFTBCCVH.js} +1 -1
- package/dist/data.cjs +71 -18
- package/dist/data.js +5 -5
- package/dist/datePicker-DxuxWpgF.d.cts +285 -0
- package/dist/datePicker-DxuxWpgF.d.ts +285 -0
- package/dist/devtools.cjs +71 -18
- package/dist/devtools.js +4 -4
- package/dist/ecosystem.cjs +82 -21
- package/dist/ecosystem.js +7 -7
- package/dist/extras.cjs +131 -23
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +21 -20
- package/dist/index.cjs +115 -37
- package/dist/index.d.cts +59 -5
- package/dist/index.d.ts +59 -5
- package/dist/index.js +10 -10
- package/dist/motion.cjs +69 -16
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +71 -18
- package/dist/patterns.js +5 -5
- package/dist/performance.cjs +69 -16
- package/dist/performance.js +4 -4
- package/dist/plugins.cjs +1421 -996
- package/dist/plugins.d.cts +132 -3
- package/dist/plugins.d.ts +132 -3
- package/dist/plugins.js +262 -11
- package/dist/routeMiddleware-B1sp4P7a.d.ts +688 -0
- package/dist/routeMiddleware-CedQTsLK.d.cts +688 -0
- package/dist/ssr.cjs +3607 -3524
- package/dist/ssr.d.cts +20 -671
- package/dist/ssr.d.ts +20 -671
- package/dist/ssr.js +15 -7
- package/dist/testing.cjs +71 -18
- package/dist/testing.js +2 -2
- package/dist/ui.cjs +78 -18
- package/dist/ui.js +8 -7
- package/dist/widgets.cjs +1352 -952
- package/dist/widgets.d.cts +100 -268
- package/dist/widgets.d.ts +100 -268
- package/dist/widgets.js +316 -7
- package/package.json +9 -1
package/dist/widgets.cjs
CHANGED
|
@@ -25,10 +25,13 @@ __export(widgets_exports, {
|
|
|
25
25
|
contentEditable: () => contentEditable,
|
|
26
26
|
datePicker: () => datePicker,
|
|
27
27
|
fileUpload: () => fileUpload,
|
|
28
|
+
isWidgetKeyEvent: () => isWidgetKeyEvent,
|
|
28
29
|
popover: () => popover,
|
|
29
30
|
select: () => select,
|
|
31
|
+
selectMenu: () => selectMenu,
|
|
30
32
|
tabs: () => tabs,
|
|
31
|
-
tooltip: () => tooltip
|
|
33
|
+
tooltip: () => tooltip,
|
|
34
|
+
widgetKeyOwner: () => widgetKeyOwner
|
|
32
35
|
});
|
|
33
36
|
module.exports = __toCommonJS(widgets_exports);
|
|
34
37
|
|
|
@@ -380,6 +383,7 @@ function bindOwnerScope(fn) {
|
|
|
380
383
|
if (scope === null) return fn;
|
|
381
384
|
return (...args) => runWithOwnerScope(scope, () => fn(...args));
|
|
382
385
|
}
|
|
386
|
+
var currentStructOwner = null;
|
|
383
387
|
var subscriberEpochCounter = 0;
|
|
384
388
|
function retrack(effectFn, subscriber) {
|
|
385
389
|
const prev = currentSubscriber;
|
|
@@ -399,6 +403,9 @@ function retrack(effectFn, subscriber) {
|
|
|
399
403
|
if (prevScope !== null && !sub._epoch && sub._scope === void 0) sub._scope = prevScope;
|
|
400
404
|
const scope = sub._scope === void 0 ? null : sub._scope;
|
|
401
405
|
if (scope !== prevScope) currentOwnerScope = scope;
|
|
406
|
+
const prevStructOwner = currentStructOwner;
|
|
407
|
+
if (prevStructOwner !== null && !sub._epoch && !sub._c && sub._owner == null) sub._owner = prevStructOwner;
|
|
408
|
+
if (sub._tok != null) currentStructOwner = sub._tok;
|
|
402
409
|
const epoch = ++subscriberEpochCounter;
|
|
403
410
|
sub._epoch = epoch;
|
|
404
411
|
sub._structDirty = false;
|
|
@@ -412,6 +419,7 @@ function retrack(effectFn, subscriber) {
|
|
|
412
419
|
} finally {
|
|
413
420
|
currentSubscriber = prev;
|
|
414
421
|
currentOwnerScope = prevScope;
|
|
422
|
+
currentStructOwner = prevStructOwner;
|
|
415
423
|
if (savedDepth !== 0) {
|
|
416
424
|
suspendDepth = savedDepth;
|
|
417
425
|
suspendSavedSub = savedSuspendSub;
|
|
@@ -468,7 +476,25 @@ function track(effectFn, subscriber) {
|
|
|
468
476
|
}
|
|
469
477
|
return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
|
|
470
478
|
}
|
|
471
|
-
function reactiveBinding(commit, ownerNode) {
|
|
479
|
+
function reactiveBinding(commit, ownerNode, structural) {
|
|
480
|
+
return createBinding(commit, ownerNode, structural === true)._dispose;
|
|
481
|
+
}
|
|
482
|
+
function structuralBinding(commit, ownerNode) {
|
|
483
|
+
const sub = createBinding(commit, ownerNode, true);
|
|
484
|
+
return {
|
|
485
|
+
stop: sub._dispose,
|
|
486
|
+
run: (fn) => {
|
|
487
|
+
const prev = currentStructOwner;
|
|
488
|
+
currentStructOwner = sub._tok ?? null;
|
|
489
|
+
try {
|
|
490
|
+
return fn();
|
|
491
|
+
} finally {
|
|
492
|
+
currentStructOwner = prev;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function createBinding(commit, ownerNode, structural) {
|
|
472
498
|
const run = () => {
|
|
473
499
|
const s = subscriber;
|
|
474
500
|
if (s._disposed || s._reentrant) return;
|
|
@@ -491,19 +517,25 @@ function reactiveBinding(commit, ownerNode) {
|
|
|
491
517
|
subscriber._disposed = false;
|
|
492
518
|
subscriber._errorPhase = "binding";
|
|
493
519
|
subscriber._errorNode = ownerNode;
|
|
520
|
+
subscriber._tok = null;
|
|
521
|
+
subscriber._owner = null;
|
|
522
|
+
if (structural) subscriber._tok = { sub: subscriber };
|
|
494
523
|
try {
|
|
495
524
|
run();
|
|
496
525
|
} catch (err) {
|
|
497
526
|
subscriber._disposed = true;
|
|
498
527
|
subscriber._errorNode = void 0;
|
|
528
|
+
if (subscriber._tok != null) subscriber._tok.sub = null;
|
|
499
529
|
cleanup(subscriber);
|
|
500
530
|
throw err;
|
|
501
531
|
}
|
|
502
|
-
|
|
532
|
+
subscriber._dispose = () => {
|
|
503
533
|
subscriber._disposed = true;
|
|
504
534
|
subscriber._errorNode = void 0;
|
|
535
|
+
if (subscriber._tok != null) subscriber._tok.sub = null;
|
|
505
536
|
cleanup(subscriber);
|
|
506
|
-
}
|
|
537
|
+
};
|
|
538
|
+
return subscriber;
|
|
507
539
|
}
|
|
508
540
|
function recordDependency(signal2) {
|
|
509
541
|
if (!currentSubscriber) return;
|
|
@@ -527,6 +559,7 @@ function recordDependency(signal2) {
|
|
|
527
559
|
}
|
|
528
560
|
function cleanup(subscriber) {
|
|
529
561
|
const sub = subscriber;
|
|
562
|
+
if (sub._owner != null) sub._owner = null;
|
|
530
563
|
let node = sub.depsHead ?? null;
|
|
531
564
|
sub.depsHead = null;
|
|
532
565
|
sub.depsTail = null;
|
|
@@ -586,20 +619,41 @@ function drainQueue() {
|
|
|
586
619
|
break;
|
|
587
620
|
}
|
|
588
621
|
const sub = pendingQueue[i++];
|
|
589
|
-
pendingSet.delete(sub);
|
|
590
|
-
if (
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
622
|
+
if (!pendingSet.delete(sub)) continue;
|
|
623
|
+
if (sub._owner != null && pendingSet.size > 0) {
|
|
624
|
+
runPendingOwners(sub);
|
|
625
|
+
if (pendingSet.has(sub)) continue;
|
|
626
|
+
}
|
|
627
|
+
runQueued(sub);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function runPendingOwners(sub) {
|
|
631
|
+
for (; ; ) {
|
|
632
|
+
let outer = null;
|
|
633
|
+
for (let t = sub._owner ?? null; t !== null; ) {
|
|
634
|
+
const o = t.sub;
|
|
635
|
+
if (o === null) break;
|
|
636
|
+
if (pendingSet.has(o)) outer = o;
|
|
637
|
+
t = o._owner ?? null;
|
|
638
|
+
}
|
|
639
|
+
if (outer === null) return;
|
|
640
|
+
pendingSet.delete(outer);
|
|
641
|
+
runQueued(outer);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
function runQueued(sub) {
|
|
645
|
+
if (quarantined.size > 0 && quarantined.has(sub)) return;
|
|
646
|
+
if (sub._hasComputedDep === true && !depsChanged(sub)) return;
|
|
647
|
+
if (tickRepeat(sub)) {
|
|
648
|
+
cycleError(sub);
|
|
649
|
+
quarantined.add(sub);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const pushed = beginDisposerCapture(sub._cap ?? null);
|
|
653
|
+
try {
|
|
654
|
+
safeInvoke(sub);
|
|
655
|
+
} finally {
|
|
656
|
+
if (pushed) endDisposerCapture();
|
|
603
657
|
}
|
|
604
658
|
}
|
|
605
659
|
function drainNotificationQueue() {
|
|
@@ -735,7 +789,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
735
789
|
}
|
|
736
790
|
|
|
737
791
|
// src/reactivity/track.ts
|
|
738
|
-
var _runtimeVersion = true ? "4.
|
|
792
|
+
var _runtimeVersion = true ? "4.13.1" : "dev";
|
|
739
793
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
740
794
|
function resolveReactiveApi() {
|
|
741
795
|
const g = globalThis;
|
|
@@ -770,6 +824,7 @@ function resolveReactiveApi() {
|
|
|
770
824
|
getOwnerScope,
|
|
771
825
|
runWithOwnerScope,
|
|
772
826
|
bindOwnerScope,
|
|
827
|
+
structuralBinding,
|
|
773
828
|
version: _runtimeVersion
|
|
774
829
|
};
|
|
775
830
|
g[REGISTRY_KEY] = local;
|
|
@@ -796,6 +851,7 @@ var forEachSubscriber2 = API.forEachSubscriber;
|
|
|
796
851
|
var getOwnerScope2 = API.getOwnerScope ?? getOwnerScope;
|
|
797
852
|
var runWithOwnerScope2 = API.runWithOwnerScope ?? runWithOwnerScope;
|
|
798
853
|
var bindOwnerScope2 = API.bindOwnerScope ?? bindOwnerScope;
|
|
854
|
+
var structuralBinding2 = API.structuralBinding ?? ((commit, ownerNode) => ({ stop: API.reactiveBinding(commit, ownerNode), run: (fn) => fn() }));
|
|
799
855
|
|
|
800
856
|
// src/core/devtoolsHook.ts
|
|
801
857
|
function emitDevtools(hook, event, payload) {
|
|
@@ -1036,6 +1092,165 @@ function signal(initial, options) {
|
|
|
1036
1092
|
return [get, set];
|
|
1037
1093
|
}
|
|
1038
1094
|
|
|
1095
|
+
// src/reactivity/domBinding.ts
|
|
1096
|
+
function domBinding(commit, ownerNode) {
|
|
1097
|
+
if (isSSR()) return () => {
|
|
1098
|
+
};
|
|
1099
|
+
return reactiveBinding2(commit, ownerNode);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// src/widgets/attributeSnapshot.ts
|
|
1103
|
+
function snapshotAttributes(el, names) {
|
|
1104
|
+
const previous = names.map((name) => [name, el.getAttribute(name)]);
|
|
1105
|
+
return () => {
|
|
1106
|
+
for (const [name, value] of previous) {
|
|
1107
|
+
if (value === null) el.removeAttribute(name);
|
|
1108
|
+
else el.setAttribute(name, value);
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
// src/widgets/keyOwnership.ts
|
|
1114
|
+
var CLAIM = /* @__PURE__ */ Symbol.for("sibujs.widgetKey");
|
|
1115
|
+
function claimWidgetKey(event, widget) {
|
|
1116
|
+
event[CLAIM] = widget;
|
|
1117
|
+
}
|
|
1118
|
+
function isWidgetKeyEvent(event) {
|
|
1119
|
+
return event[CLAIM] !== void 0;
|
|
1120
|
+
}
|
|
1121
|
+
function widgetKeyOwner(event) {
|
|
1122
|
+
return event[CLAIM] ?? null;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// src/widgets/Accordion.ts
|
|
1126
|
+
var boundAccordions = /* @__PURE__ */ new WeakMap();
|
|
1127
|
+
function accordion(options) {
|
|
1128
|
+
const { items: itemDefs, multiple = false, defaultExpanded = [] } = options;
|
|
1129
|
+
const knownIds = new Set(itemDefs.map((item) => item.id));
|
|
1130
|
+
const validDefaults = defaultExpanded.filter((id) => knownIds.has(id));
|
|
1131
|
+
const initialExpanded = multiple ? validDefaults : validDefaults.slice(0, 1);
|
|
1132
|
+
const [expandedIds, setExpandedIds] = signal(new Set(initialExpanded));
|
|
1133
|
+
const items = derived(
|
|
1134
|
+
() => itemDefs.map((item) => ({
|
|
1135
|
+
...item,
|
|
1136
|
+
isExpanded: expandedIds().has(item.id)
|
|
1137
|
+
}))
|
|
1138
|
+
);
|
|
1139
|
+
function expand(id) {
|
|
1140
|
+
if (!itemDefs.some((item) => item.id === id)) return;
|
|
1141
|
+
if (multiple) {
|
|
1142
|
+
setExpandedIds((prev) => {
|
|
1143
|
+
const next = new Set(prev);
|
|
1144
|
+
next.add(id);
|
|
1145
|
+
return next;
|
|
1146
|
+
});
|
|
1147
|
+
} else {
|
|
1148
|
+
setExpandedIds(/* @__PURE__ */ new Set([id]));
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
function collapse(id) {
|
|
1152
|
+
setExpandedIds((prev) => {
|
|
1153
|
+
const next = new Set(prev);
|
|
1154
|
+
next.delete(id);
|
|
1155
|
+
return next;
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
function toggle(id) {
|
|
1159
|
+
if (expandedIds().has(id)) {
|
|
1160
|
+
collapse(id);
|
|
1161
|
+
} else {
|
|
1162
|
+
expand(id);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
function expandAll() {
|
|
1166
|
+
if (multiple) {
|
|
1167
|
+
setExpandedIds(new Set(itemDefs.map((item) => item.id)));
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
function collapseAll() {
|
|
1171
|
+
setExpandedIds(/* @__PURE__ */ new Set());
|
|
1172
|
+
}
|
|
1173
|
+
function isExpanded(id) {
|
|
1174
|
+
return expandedIds().has(id);
|
|
1175
|
+
}
|
|
1176
|
+
function bind(els) {
|
|
1177
|
+
const idempotencyKey = els.root ?? (itemDefs.length > 0 ? els.triggers[itemDefs[0].id] : void 0);
|
|
1178
|
+
if (idempotencyKey) {
|
|
1179
|
+
const existing = boundAccordions.get(idempotencyKey);
|
|
1180
|
+
if (existing) return existing;
|
|
1181
|
+
}
|
|
1182
|
+
const restore = [];
|
|
1183
|
+
const idPrefix = createId("sibu-accordion");
|
|
1184
|
+
for (const item of itemDefs) {
|
|
1185
|
+
const trig = els.triggers[item.id];
|
|
1186
|
+
const panel = els.panels[item.id];
|
|
1187
|
+
if (!trig) continue;
|
|
1188
|
+
restore.push(snapshotAttributes(trig, ["id", "aria-controls", "aria-expanded"]));
|
|
1189
|
+
if (!trig.id) trig.id = `${idPrefix}-trigger-${idSegment(item.id)}`;
|
|
1190
|
+
if (panel) {
|
|
1191
|
+
restore.push(snapshotAttributes(panel, ["role", "id", "aria-labelledby", "hidden"]));
|
|
1192
|
+
panel.setAttribute("role", "region");
|
|
1193
|
+
if (!panel.id) panel.id = `${idPrefix}-panel-${idSegment(item.id)}`;
|
|
1194
|
+
panel.setAttribute("aria-labelledby", trig.id);
|
|
1195
|
+
trig.setAttribute("aria-controls", panel.id);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
const fxTeardown = domBinding(() => {
|
|
1199
|
+
const ids = expandedIds();
|
|
1200
|
+
for (const item of itemDefs) {
|
|
1201
|
+
const trig = els.triggers[item.id];
|
|
1202
|
+
const panel = els.panels[item.id];
|
|
1203
|
+
if (!trig) continue;
|
|
1204
|
+
const expanded = ids.has(item.id);
|
|
1205
|
+
trig.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
1206
|
+
if (panel) panel.hidden = !expanded;
|
|
1207
|
+
}
|
|
1208
|
+
}, idempotencyKey);
|
|
1209
|
+
const handlers = [];
|
|
1210
|
+
for (const item of itemDefs) {
|
|
1211
|
+
const trig = els.triggers[item.id];
|
|
1212
|
+
if (!trig) continue;
|
|
1213
|
+
const click = () => toggle(item.id);
|
|
1214
|
+
const key = (e) => {
|
|
1215
|
+
if (isWidgetKeyEvent(e)) return;
|
|
1216
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1217
|
+
e.preventDefault();
|
|
1218
|
+
claimWidgetKey(e, "accordion");
|
|
1219
|
+
toggle(item.id);
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
trig.addEventListener("click", click);
|
|
1223
|
+
trig.addEventListener("keydown", key);
|
|
1224
|
+
handlers.push({ el: trig, click, key });
|
|
1225
|
+
}
|
|
1226
|
+
let tornDown = false;
|
|
1227
|
+
const teardown = () => {
|
|
1228
|
+
if (tornDown) return;
|
|
1229
|
+
tornDown = true;
|
|
1230
|
+
if (idempotencyKey) boundAccordions.delete(idempotencyKey);
|
|
1231
|
+
fxTeardown();
|
|
1232
|
+
for (const { el, click, key } of handlers) {
|
|
1233
|
+
el.removeEventListener("click", click);
|
|
1234
|
+
el.removeEventListener("keydown", key);
|
|
1235
|
+
}
|
|
1236
|
+
for (const r of restore) r();
|
|
1237
|
+
};
|
|
1238
|
+
if (idempotencyKey) boundAccordions.set(idempotencyKey, teardown);
|
|
1239
|
+
return teardown;
|
|
1240
|
+
}
|
|
1241
|
+
return {
|
|
1242
|
+
items,
|
|
1243
|
+
toggle,
|
|
1244
|
+
expand,
|
|
1245
|
+
collapse,
|
|
1246
|
+
expandAll,
|
|
1247
|
+
collapseAll,
|
|
1248
|
+
/** Reactive check — use inside class/nodes bindings for per-item reactivity */
|
|
1249
|
+
isExpanded,
|
|
1250
|
+
bind
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1039
1254
|
// src/core/signals/watch.ts
|
|
1040
1255
|
function watch(getter, callback) {
|
|
1041
1256
|
devAssert(typeof getter === "function", "watch: first argument must be a getter function.");
|
|
@@ -1066,13 +1281,6 @@ function watch(getter, callback) {
|
|
|
1066
1281
|
return teardown;
|
|
1067
1282
|
}
|
|
1068
1283
|
|
|
1069
|
-
// src/reactivity/domBinding.ts
|
|
1070
|
-
function domBinding(commit, ownerNode) {
|
|
1071
|
-
if (isSSR()) return () => {
|
|
1072
|
-
};
|
|
1073
|
-
return reactiveBinding2(commit, ownerNode);
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
1284
|
// src/widgets/Combobox.ts
|
|
1077
1285
|
var boundComboboxes = /* @__PURE__ */ new WeakMap();
|
|
1078
1286
|
function combobox(options) {
|
|
@@ -1170,27 +1378,34 @@ function combobox(options) {
|
|
|
1170
1378
|
open();
|
|
1171
1379
|
};
|
|
1172
1380
|
const onKey = (e) => {
|
|
1381
|
+
if (isWidgetKeyEvent(e)) return;
|
|
1173
1382
|
if (e.key === "ArrowDown") {
|
|
1174
1383
|
e.preventDefault();
|
|
1384
|
+
claimWidgetKey(e, "combobox");
|
|
1175
1385
|
if (!isOpen()) open();
|
|
1176
1386
|
highlightNext();
|
|
1177
1387
|
} else if (e.key === "ArrowUp") {
|
|
1178
1388
|
e.preventDefault();
|
|
1389
|
+
claimWidgetKey(e, "combobox");
|
|
1179
1390
|
if (!isOpen()) open();
|
|
1180
1391
|
highlightPrev();
|
|
1181
1392
|
} else if (e.key === "Enter") {
|
|
1182
1393
|
if (highlightedIndex() >= 0) {
|
|
1183
1394
|
e.preventDefault();
|
|
1395
|
+
claimWidgetKey(e, "combobox");
|
|
1184
1396
|
selectHighlighted();
|
|
1185
1397
|
}
|
|
1186
1398
|
} else if (e.key === "Escape") {
|
|
1187
1399
|
e.preventDefault();
|
|
1400
|
+
claimWidgetKey(e, "combobox");
|
|
1188
1401
|
close();
|
|
1189
1402
|
} else if (e.key === "Home") {
|
|
1190
1403
|
e.preventDefault();
|
|
1404
|
+
claimWidgetKey(e, "combobox");
|
|
1191
1405
|
if (filteredItems().length > 0) setHighlightedIndex(0);
|
|
1192
1406
|
} else if (e.key === "End") {
|
|
1193
1407
|
e.preventDefault();
|
|
1408
|
+
claimWidgetKey(e, "combobox");
|
|
1194
1409
|
const len = filteredItems().length;
|
|
1195
1410
|
if (len > 0) setHighlightedIndex(len - 1);
|
|
1196
1411
|
}
|
|
@@ -1261,671 +1476,375 @@ function combobox(options) {
|
|
|
1261
1476
|
};
|
|
1262
1477
|
}
|
|
1263
1478
|
|
|
1264
|
-
// src/
|
|
1265
|
-
function
|
|
1266
|
-
const
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1479
|
+
// src/utils/sanitize.ts
|
|
1480
|
+
function stripHtml(html) {
|
|
1481
|
+
const input = String(html);
|
|
1482
|
+
if (typeof DOMParser !== "undefined") {
|
|
1483
|
+
try {
|
|
1484
|
+
return new DOMParser().parseFromString(input, "text/html").body.textContent ?? "";
|
|
1485
|
+
} catch {
|
|
1271
1486
|
}
|
|
1272
|
-
}
|
|
1487
|
+
}
|
|
1488
|
+
let prev;
|
|
1489
|
+
let out = input;
|
|
1490
|
+
do {
|
|
1491
|
+
prev = out;
|
|
1492
|
+
out = out.replace(/<[^>]*>/g, "");
|
|
1493
|
+
} while (out !== prev);
|
|
1494
|
+
return out.replace(/<[^>]*$/, "");
|
|
1273
1495
|
}
|
|
1274
1496
|
|
|
1275
|
-
// src/widgets/
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
const
|
|
1281
|
-
const [
|
|
1282
|
-
function
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1497
|
+
// src/widgets/contentEditable.ts
|
|
1498
|
+
function toInertText(html) {
|
|
1499
|
+
return stripHtml(String(html)).replace(/<(?=[a-z!/?])/gi, "<");
|
|
1500
|
+
}
|
|
1501
|
+
function contentEditable(element) {
|
|
1502
|
+
const [content, setContentInternal] = signal("");
|
|
1503
|
+
const [isFocused, setFocused] = signal(false);
|
|
1504
|
+
function setContent(input) {
|
|
1505
|
+
if (typeof input === "string") {
|
|
1506
|
+
setContentInternal(toInertText(input));
|
|
1507
|
+
return;
|
|
1286
1508
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
...t,
|
|
1291
|
-
isActive: t.id === activeTab()
|
|
1292
|
-
}))
|
|
1293
|
-
);
|
|
1294
|
-
function findCurrentIndex() {
|
|
1295
|
-
return tabDefs.findIndex((t) => t.id === activeTab());
|
|
1296
|
-
}
|
|
1297
|
-
function nextTab() {
|
|
1298
|
-
const currentIdx = findCurrentIndex();
|
|
1299
|
-
const len = tabDefs.length;
|
|
1300
|
-
if (len === 0) return;
|
|
1301
|
-
for (let i = 1; i <= len; i++) {
|
|
1302
|
-
const candidate = tabDefs[(currentIdx + i) % len];
|
|
1303
|
-
if (!candidate.disabled) {
|
|
1304
|
-
setActiveTabState(candidate.id);
|
|
1305
|
-
return;
|
|
1306
|
-
}
|
|
1509
|
+
if (typeof input.text === "string") {
|
|
1510
|
+
setContentInternal(input.text);
|
|
1511
|
+
return;
|
|
1307
1512
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
if (len === 0) return;
|
|
1313
|
-
for (let i = 1; i <= len; i++) {
|
|
1314
|
-
const candidate = tabDefs[(currentIdx - i + len) % len];
|
|
1315
|
-
if (!candidate.disabled) {
|
|
1316
|
-
setActiveTabState(candidate.id);
|
|
1317
|
-
return;
|
|
1318
|
-
}
|
|
1513
|
+
if (typeof input.html === "string") {
|
|
1514
|
+
const shouldSanitize = input.sanitize !== false;
|
|
1515
|
+
setContentInternal(shouldSanitize ? toInertText(input.html) : input.html);
|
|
1516
|
+
return;
|
|
1319
1517
|
}
|
|
1518
|
+
setContentInternal("");
|
|
1320
1519
|
}
|
|
1321
|
-
function
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
const
|
|
1326
|
-
if (
|
|
1327
|
-
const
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
)
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
const panelEl = els.panels?.[def.id];
|
|
1341
|
-
if (panelEl) {
|
|
1342
|
-
restore.push(snapshotAttributes(panelEl, ["role", "id", "aria-labelledby", "hidden"]));
|
|
1343
|
-
panelEl.setAttribute("role", "tabpanel");
|
|
1344
|
-
if (!panelEl.id) panelEl.id = `${idPrefix}-panel-${idSegment(def.id)}`;
|
|
1345
|
-
panelEl.setAttribute("aria-labelledby", tabEl.id);
|
|
1346
|
-
tabEl.setAttribute("aria-controls", panelEl.id);
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
const fxTeardown = domBinding(() => {
|
|
1350
|
-
const active = activeTab();
|
|
1351
|
-
for (const def of tabDefs) {
|
|
1352
|
-
const tabEl = els.tabs[def.id];
|
|
1353
|
-
if (!tabEl) continue;
|
|
1354
|
-
const isAct = def.id === active;
|
|
1355
|
-
tabEl.setAttribute("aria-selected", isAct ? "true" : "false");
|
|
1356
|
-
tabEl.tabIndex = isAct ? 0 : -1;
|
|
1357
|
-
const panelEl = els.panels?.[def.id];
|
|
1358
|
-
if (panelEl) panelEl.hidden = !isAct;
|
|
1359
|
-
}
|
|
1360
|
-
}, els.tablist);
|
|
1361
|
-
const onKey = (e) => {
|
|
1362
|
-
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
1363
|
-
e.preventDefault();
|
|
1364
|
-
nextTab();
|
|
1365
|
-
els.tabs[activeTab()]?.focus();
|
|
1366
|
-
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
1367
|
-
e.preventDefault();
|
|
1368
|
-
prevTab();
|
|
1369
|
-
els.tabs[activeTab()]?.focus();
|
|
1370
|
-
} else if (e.key === "Home") {
|
|
1371
|
-
e.preventDefault();
|
|
1372
|
-
const first = tabDefs.find((t) => !t.disabled);
|
|
1373
|
-
if (first) {
|
|
1374
|
-
setActiveTabState(first.id);
|
|
1375
|
-
els.tabs[first.id]?.focus();
|
|
1520
|
+
function wrapSelection(tagName) {
|
|
1521
|
+
if (typeof window === "undefined") return;
|
|
1522
|
+
const selection = window.getSelection();
|
|
1523
|
+
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return;
|
|
1524
|
+
const range = selection.getRangeAt(0);
|
|
1525
|
+
if (element && !element.contains(range.commonAncestorContainer)) return;
|
|
1526
|
+
const ancestor = range.commonAncestorContainer;
|
|
1527
|
+
const existingWrap = findWrapperWithinEditor(
|
|
1528
|
+
ancestor instanceof HTMLElement ? ancestor : ancestor.parentElement,
|
|
1529
|
+
tagName
|
|
1530
|
+
);
|
|
1531
|
+
let targetNode = null;
|
|
1532
|
+
if (existingWrap) {
|
|
1533
|
+
const parent = existingWrap.parentNode;
|
|
1534
|
+
if (parent) {
|
|
1535
|
+
const firstChild = existingWrap.firstChild;
|
|
1536
|
+
const lastChild = existingWrap.lastChild;
|
|
1537
|
+
while (existingWrap.firstChild) {
|
|
1538
|
+
parent.insertBefore(existingWrap.firstChild, existingWrap);
|
|
1376
1539
|
}
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1540
|
+
parent.removeChild(existingWrap);
|
|
1541
|
+
if (firstChild && lastChild) {
|
|
1542
|
+
const newRange = document.createRange();
|
|
1543
|
+
newRange.setStartBefore(firstChild);
|
|
1544
|
+
newRange.setEndAfter(lastChild);
|
|
1545
|
+
selection.removeAllRanges();
|
|
1546
|
+
selection.addRange(newRange);
|
|
1547
|
+
return;
|
|
1385
1548
|
}
|
|
1386
1549
|
}
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1550
|
+
} else {
|
|
1551
|
+
const wrapper = document.createElement(tagName);
|
|
1552
|
+
try {
|
|
1553
|
+
range.surroundContents(wrapper);
|
|
1554
|
+
} catch {
|
|
1555
|
+
const fragment = range.extractContents();
|
|
1556
|
+
wrapper.appendChild(fragment);
|
|
1557
|
+
range.insertNode(wrapper);
|
|
1558
|
+
}
|
|
1559
|
+
targetNode = wrapper;
|
|
1560
|
+
}
|
|
1561
|
+
if (targetNode) {
|
|
1562
|
+
selection.removeAllRanges();
|
|
1563
|
+
const newRange = document.createRange();
|
|
1564
|
+
newRange.selectNodeContents(targetNode);
|
|
1565
|
+
selection.addRange(newRange);
|
|
1396
1566
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1567
|
+
}
|
|
1568
|
+
function findWrapperWithinEditor(el, tagName) {
|
|
1569
|
+
const upper = tagName.toUpperCase();
|
|
1570
|
+
while (el) {
|
|
1571
|
+
if (el === element || isEditingHost(el)) return null;
|
|
1572
|
+
if (el.tagName === upper) return el;
|
|
1573
|
+
el = el.parentElement;
|
|
1574
|
+
}
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
function isEditingHost(el) {
|
|
1578
|
+
const attr = el.getAttribute("contenteditable");
|
|
1579
|
+
return attr !== null && attr.toLowerCase() !== "false";
|
|
1580
|
+
}
|
|
1581
|
+
function bold() {
|
|
1582
|
+
wrapSelection("strong");
|
|
1583
|
+
}
|
|
1584
|
+
function italic() {
|
|
1585
|
+
wrapSelection("em");
|
|
1586
|
+
}
|
|
1587
|
+
function underline() {
|
|
1588
|
+
wrapSelection("u");
|
|
1409
1589
|
}
|
|
1410
1590
|
return {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
bind
|
|
1591
|
+
content,
|
|
1592
|
+
setContent,
|
|
1593
|
+
isFocused,
|
|
1594
|
+
setFocused,
|
|
1595
|
+
bold,
|
|
1596
|
+
italic,
|
|
1597
|
+
underline
|
|
1419
1598
|
};
|
|
1420
1599
|
}
|
|
1421
1600
|
|
|
1422
|
-
// src/widgets/
|
|
1423
|
-
var
|
|
1424
|
-
function
|
|
1425
|
-
const
|
|
1426
|
-
const
|
|
1427
|
-
const
|
|
1428
|
-
const
|
|
1429
|
-
const [
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
);
|
|
1436
|
-
function expand(id) {
|
|
1437
|
-
if (!itemDefs.some((item) => item.id === id)) return;
|
|
1438
|
-
if (multiple) {
|
|
1439
|
-
setExpandedIds((prev) => {
|
|
1440
|
-
const next = new Set(prev);
|
|
1441
|
-
next.add(id);
|
|
1442
|
-
return next;
|
|
1443
|
-
});
|
|
1444
|
-
} else {
|
|
1445
|
-
setExpandedIds(/* @__PURE__ */ new Set([id]));
|
|
1446
|
-
}
|
|
1601
|
+
// src/widgets/datePicker.ts
|
|
1602
|
+
var boundDatePickers = /* @__PURE__ */ new WeakMap();
|
|
1603
|
+
function datePicker(options) {
|
|
1604
|
+
const minDate = options?.minDate;
|
|
1605
|
+
const maxDate = options?.maxDate;
|
|
1606
|
+
const initialDate = options?.initialDate ?? null;
|
|
1607
|
+
const [selectedDate, setSelectedDate] = signal(initialDate);
|
|
1608
|
+
const [viewDate, setViewDate] = signal(initialDate ?? /* @__PURE__ */ new Date());
|
|
1609
|
+
function isDateDisabled(date) {
|
|
1610
|
+
const d = stripTime(date);
|
|
1611
|
+
if (minDate && d < stripTime(minDate)) return true;
|
|
1612
|
+
if (maxDate && d > stripTime(maxDate)) return true;
|
|
1613
|
+
return false;
|
|
1447
1614
|
}
|
|
1448
|
-
function
|
|
1449
|
-
|
|
1450
|
-
const next = new Set(prev);
|
|
1451
|
-
next.delete(id);
|
|
1452
|
-
return next;
|
|
1453
|
-
});
|
|
1615
|
+
function stripTime(d) {
|
|
1616
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
1454
1617
|
}
|
|
1455
|
-
function
|
|
1456
|
-
|
|
1457
|
-
collapse(id);
|
|
1458
|
-
} else {
|
|
1459
|
-
expand(id);
|
|
1460
|
-
}
|
|
1618
|
+
function sameDay(a, b) {
|
|
1619
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1461
1620
|
}
|
|
1462
|
-
function
|
|
1463
|
-
if (
|
|
1464
|
-
|
|
1621
|
+
function select2(date) {
|
|
1622
|
+
if (!isDateDisabled(date)) {
|
|
1623
|
+
setSelectedDate(date);
|
|
1465
1624
|
}
|
|
1466
1625
|
}
|
|
1467
|
-
function
|
|
1468
|
-
|
|
1626
|
+
function shiftMonth(prev, delta) {
|
|
1627
|
+
return new Date(prev.getFullYear(), prev.getMonth() + delta, 1);
|
|
1469
1628
|
}
|
|
1470
|
-
function
|
|
1471
|
-
|
|
1629
|
+
function nextMonth() {
|
|
1630
|
+
setViewDate((prev) => shiftMonth(prev, 1));
|
|
1472
1631
|
}
|
|
1473
|
-
function
|
|
1474
|
-
|
|
1475
|
-
if (idempotencyKey) {
|
|
1476
|
-
const existing = boundAccordions.get(idempotencyKey);
|
|
1477
|
-
if (existing) return existing;
|
|
1478
|
-
}
|
|
1479
|
-
const restore = [];
|
|
1480
|
-
const idPrefix = createId("sibu-accordion");
|
|
1481
|
-
for (const item of itemDefs) {
|
|
1482
|
-
const trig = els.triggers[item.id];
|
|
1483
|
-
const panel = els.panels[item.id];
|
|
1484
|
-
if (!trig) continue;
|
|
1485
|
-
restore.push(snapshotAttributes(trig, ["id", "aria-controls", "aria-expanded"]));
|
|
1486
|
-
if (!trig.id) trig.id = `${idPrefix}-trigger-${idSegment(item.id)}`;
|
|
1487
|
-
if (panel) {
|
|
1488
|
-
restore.push(snapshotAttributes(panel, ["role", "id", "aria-labelledby", "hidden"]));
|
|
1489
|
-
panel.setAttribute("role", "region");
|
|
1490
|
-
if (!panel.id) panel.id = `${idPrefix}-panel-${idSegment(item.id)}`;
|
|
1491
|
-
panel.setAttribute("aria-labelledby", trig.id);
|
|
1492
|
-
trig.setAttribute("aria-controls", panel.id);
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
const fxTeardown = domBinding(() => {
|
|
1496
|
-
const ids = expandedIds();
|
|
1497
|
-
for (const item of itemDefs) {
|
|
1498
|
-
const trig = els.triggers[item.id];
|
|
1499
|
-
const panel = els.panels[item.id];
|
|
1500
|
-
if (!trig) continue;
|
|
1501
|
-
const expanded = ids.has(item.id);
|
|
1502
|
-
trig.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
1503
|
-
if (panel) panel.hidden = !expanded;
|
|
1504
|
-
}
|
|
1505
|
-
}, idempotencyKey);
|
|
1506
|
-
const handlers = [];
|
|
1507
|
-
for (const item of itemDefs) {
|
|
1508
|
-
const trig = els.triggers[item.id];
|
|
1509
|
-
if (!trig) continue;
|
|
1510
|
-
const click = () => toggle(item.id);
|
|
1511
|
-
const key = (e) => {
|
|
1512
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
1513
|
-
e.preventDefault();
|
|
1514
|
-
toggle(item.id);
|
|
1515
|
-
}
|
|
1516
|
-
};
|
|
1517
|
-
trig.addEventListener("click", click);
|
|
1518
|
-
trig.addEventListener("keydown", key);
|
|
1519
|
-
handlers.push({ el: trig, click, key });
|
|
1520
|
-
}
|
|
1521
|
-
let tornDown = false;
|
|
1522
|
-
const teardown = () => {
|
|
1523
|
-
if (tornDown) return;
|
|
1524
|
-
tornDown = true;
|
|
1525
|
-
if (idempotencyKey) boundAccordions.delete(idempotencyKey);
|
|
1526
|
-
fxTeardown();
|
|
1527
|
-
for (const { el, click, key } of handlers) {
|
|
1528
|
-
el.removeEventListener("click", click);
|
|
1529
|
-
el.removeEventListener("keydown", key);
|
|
1530
|
-
}
|
|
1531
|
-
for (const r of restore) r();
|
|
1532
|
-
};
|
|
1533
|
-
if (idempotencyKey) boundAccordions.set(idempotencyKey, teardown);
|
|
1534
|
-
return teardown;
|
|
1535
|
-
}
|
|
1536
|
-
return {
|
|
1537
|
-
items,
|
|
1538
|
-
toggle,
|
|
1539
|
-
expand,
|
|
1540
|
-
collapse,
|
|
1541
|
-
expandAll,
|
|
1542
|
-
collapseAll,
|
|
1543
|
-
/** Reactive check — use inside class/nodes bindings for per-item reactivity */
|
|
1544
|
-
isExpanded,
|
|
1545
|
-
bind
|
|
1546
|
-
};
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
// src/widgets/Popover.ts
|
|
1550
|
-
var boundPopovers = /* @__PURE__ */ new WeakMap();
|
|
1551
|
-
function popover() {
|
|
1552
|
-
const [isOpen, setIsOpen] = signal(false);
|
|
1553
|
-
function open() {
|
|
1554
|
-
setIsOpen(true);
|
|
1555
|
-
}
|
|
1556
|
-
function close() {
|
|
1557
|
-
setIsOpen(false);
|
|
1632
|
+
function prevMonth() {
|
|
1633
|
+
setViewDate((prev) => shiftMonth(prev, -1));
|
|
1558
1634
|
}
|
|
1559
|
-
function
|
|
1560
|
-
|
|
1635
|
+
function nextYear() {
|
|
1636
|
+
setViewDate((prev) => new Date(prev.getFullYear() + 1, prev.getMonth(), 1));
|
|
1561
1637
|
}
|
|
1562
|
-
function
|
|
1563
|
-
|
|
1564
|
-
if (existing) return existing;
|
|
1565
|
-
const id = createId("sibu-popover");
|
|
1566
|
-
const prevPopoverRole = els.popover.getAttribute("role");
|
|
1567
|
-
const prevPopoverId = els.popover.id;
|
|
1568
|
-
const prevLabelledBy = els.popover.getAttribute("aria-labelledby");
|
|
1569
|
-
const prevTriggerHaspopup = els.trigger.getAttribute("aria-haspopup");
|
|
1570
|
-
const prevTriggerControls = els.trigger.getAttribute("aria-controls");
|
|
1571
|
-
els.popover.setAttribute("role", "dialog");
|
|
1572
|
-
els.popover.id = id;
|
|
1573
|
-
els.trigger.setAttribute("aria-haspopup", "dialog");
|
|
1574
|
-
els.trigger.setAttribute("aria-controls", id);
|
|
1575
|
-
let assignedLabelId = null;
|
|
1576
|
-
if (els.labelledBy) {
|
|
1577
|
-
if (!els.labelledBy.id) {
|
|
1578
|
-
els.labelledBy.id = `${id}-label`;
|
|
1579
|
-
assignedLabelId = els.labelledBy.id;
|
|
1580
|
-
}
|
|
1581
|
-
els.popover.setAttribute("aria-labelledby", els.labelledBy.id);
|
|
1582
|
-
}
|
|
1583
|
-
const fxTeardown = domBinding(() => {
|
|
1584
|
-
const open2 = isOpen();
|
|
1585
|
-
els.trigger.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
1586
|
-
els.popover.hidden = !open2;
|
|
1587
|
-
}, els.trigger);
|
|
1588
|
-
const onTriggerClick = (e) => {
|
|
1589
|
-
e.preventDefault();
|
|
1590
|
-
toggle();
|
|
1591
|
-
};
|
|
1592
|
-
const onKey = (e) => {
|
|
1593
|
-
if (e.key === "Escape" && isOpen()) {
|
|
1594
|
-
e.stopPropagation();
|
|
1595
|
-
close();
|
|
1596
|
-
els.trigger.focus();
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
const onDocPointer = (e) => {
|
|
1600
|
-
if (!isOpen()) return;
|
|
1601
|
-
const t = e.target;
|
|
1602
|
-
if (!t) return;
|
|
1603
|
-
if (els.trigger.contains(t) || els.popover.contains(t)) return;
|
|
1604
|
-
close();
|
|
1605
|
-
};
|
|
1606
|
-
els.trigger.addEventListener("click", onTriggerClick);
|
|
1607
|
-
els.popover.addEventListener("keydown", onKey);
|
|
1608
|
-
els.trigger.addEventListener("keydown", onKey);
|
|
1609
|
-
document.addEventListener("pointerdown", onDocPointer);
|
|
1610
|
-
let tornDown = false;
|
|
1611
|
-
const teardown = () => {
|
|
1612
|
-
if (tornDown) return;
|
|
1613
|
-
tornDown = true;
|
|
1614
|
-
if (boundPopovers.get(els.trigger) === teardown) boundPopovers.delete(els.trigger);
|
|
1615
|
-
fxTeardown();
|
|
1616
|
-
els.trigger.removeEventListener("click", onTriggerClick);
|
|
1617
|
-
els.popover.removeEventListener("keydown", onKey);
|
|
1618
|
-
els.trigger.removeEventListener("keydown", onKey);
|
|
1619
|
-
document.removeEventListener("pointerdown", onDocPointer);
|
|
1620
|
-
if (prevPopoverRole === null) els.popover.removeAttribute("role");
|
|
1621
|
-
else els.popover.setAttribute("role", prevPopoverRole);
|
|
1622
|
-
if (prevPopoverId === "") els.popover.removeAttribute("id");
|
|
1623
|
-
else els.popover.id = prevPopoverId;
|
|
1624
|
-
if (prevLabelledBy === null) els.popover.removeAttribute("aria-labelledby");
|
|
1625
|
-
else els.popover.setAttribute("aria-labelledby", prevLabelledBy);
|
|
1626
|
-
if (assignedLabelId && els.labelledBy?.id === assignedLabelId) {
|
|
1627
|
-
els.labelledBy.removeAttribute("id");
|
|
1628
|
-
}
|
|
1629
|
-
if (prevTriggerHaspopup === null) els.trigger.removeAttribute("aria-haspopup");
|
|
1630
|
-
else els.trigger.setAttribute("aria-haspopup", prevTriggerHaspopup);
|
|
1631
|
-
if (prevTriggerControls === null) els.trigger.removeAttribute("aria-controls");
|
|
1632
|
-
else els.trigger.setAttribute("aria-controls", prevTriggerControls);
|
|
1633
|
-
els.trigger.removeAttribute("aria-expanded");
|
|
1634
|
-
};
|
|
1635
|
-
boundPopovers.set(els.trigger, teardown);
|
|
1636
|
-
return teardown;
|
|
1638
|
+
function prevYear() {
|
|
1639
|
+
setViewDate((prev) => new Date(prev.getFullYear() - 1, prev.getMonth(), 1));
|
|
1637
1640
|
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
if (prev.includes(item)) return prev;
|
|
1658
|
-
return [...prev, item];
|
|
1659
|
-
});
|
|
1660
|
-
} else {
|
|
1661
|
-
batch(() => {
|
|
1662
|
-
setSelectedItems([item]);
|
|
1663
|
-
setIsOpen(false);
|
|
1641
|
+
const daysInMonth = derived(() => {
|
|
1642
|
+
const vd = viewDate();
|
|
1643
|
+
const year = vd.getFullYear();
|
|
1644
|
+
const month = vd.getMonth();
|
|
1645
|
+
const today = /* @__PURE__ */ new Date();
|
|
1646
|
+
const selected = selectedDate();
|
|
1647
|
+
const firstDay = new Date(year, month, 1);
|
|
1648
|
+
const startDow = firstDay.getDay();
|
|
1649
|
+
const lastDay = new Date(year, month + 1, 0);
|
|
1650
|
+
const totalDaysInMonth = lastDay.getDate();
|
|
1651
|
+
const days = [];
|
|
1652
|
+
for (let i = startDow - 1; i >= 0; i--) {
|
|
1653
|
+
const date = new Date(year, month, -i);
|
|
1654
|
+
days.push({
|
|
1655
|
+
date,
|
|
1656
|
+
isCurrentMonth: false,
|
|
1657
|
+
isToday: sameDay(date, today),
|
|
1658
|
+
isSelected: selected !== null && sameDay(date, selected),
|
|
1659
|
+
isDisabled: isDateDisabled(date)
|
|
1664
1660
|
});
|
|
1665
1661
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
function isSelected(item) {
|
|
1678
|
-
return selectedItems().includes(item);
|
|
1679
|
-
}
|
|
1680
|
-
function open() {
|
|
1681
|
-
setIsOpen(true);
|
|
1682
|
-
}
|
|
1683
|
-
function close() {
|
|
1684
|
-
setIsOpen(false);
|
|
1685
|
-
}
|
|
1686
|
-
function nextEnabled(from, dir) {
|
|
1687
|
-
const len = items.length;
|
|
1688
|
-
if (len === 0) return -1;
|
|
1689
|
-
let i = from;
|
|
1690
|
-
for (let n = 0; n < len; n++) {
|
|
1691
|
-
i = (i + dir + len) % len;
|
|
1692
|
-
if (!isItemDisabled(items[i])) return i;
|
|
1693
|
-
}
|
|
1694
|
-
return -1;
|
|
1695
|
-
}
|
|
1696
|
-
function highlightNext() {
|
|
1697
|
-
if (items.length === 0) return;
|
|
1698
|
-
setHighlightedIndex((prev) => {
|
|
1699
|
-
const n = nextEnabled(prev < 0 ? -1 : prev, 1);
|
|
1700
|
-
return n === -1 ? prev : n;
|
|
1701
|
-
});
|
|
1702
|
-
}
|
|
1703
|
-
function highlightPrev() {
|
|
1704
|
-
if (items.length === 0) return;
|
|
1705
|
-
setHighlightedIndex((prev) => {
|
|
1706
|
-
const n = nextEnabled(prev < 0 ? items.length : prev, -1);
|
|
1707
|
-
return n === -1 ? prev : n;
|
|
1708
|
-
});
|
|
1709
|
-
}
|
|
1710
|
-
function selectHighlighted() {
|
|
1711
|
-
const idx = highlightedIndex();
|
|
1712
|
-
if (idx >= 0 && idx < items.length) {
|
|
1713
|
-
select2(items[idx]);
|
|
1662
|
+
for (let d = 1; d <= totalDaysInMonth; d++) {
|
|
1663
|
+
const date = new Date(year, month, d);
|
|
1664
|
+
days.push({
|
|
1665
|
+
date,
|
|
1666
|
+
isCurrentMonth: true,
|
|
1667
|
+
isToday: sameDay(date, today),
|
|
1668
|
+
isSelected: selected !== null && sameDay(date, selected),
|
|
1669
|
+
isDisabled: isDateDisabled(date)
|
|
1670
|
+
});
|
|
1714
1671
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
els.listbox.id = listboxId;
|
|
1728
|
-
els.listbox.setAttribute("role", "listbox");
|
|
1729
|
-
els.listbox.setAttribute("aria-multiselectable", multiple ? "true" : "false");
|
|
1730
|
-
if (els.listbox.tabIndex < 0) els.listbox.tabIndex = 0;
|
|
1731
|
-
const toStr = els.itemToString ?? itemToString ?? ((it) => String(it));
|
|
1732
|
-
const fxTeardown = domBinding(() => {
|
|
1733
|
-
const idx = highlightedIndex();
|
|
1734
|
-
const sel = selectedItems();
|
|
1735
|
-
let activeId = "";
|
|
1736
|
-
for (let i = 0; i < items.length; i++) {
|
|
1737
|
-
const optEl = els.option(items[i], i);
|
|
1738
|
-
if (!optEl) continue;
|
|
1739
|
-
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
1740
|
-
optEl.setAttribute("role", "option");
|
|
1741
|
-
optEl.setAttribute("aria-selected", sel.includes(items[i]) ? "true" : "false");
|
|
1742
|
-
const disabled = isItemDisabled(items[i]);
|
|
1743
|
-
if (disabled) optEl.setAttribute("aria-disabled", "true");
|
|
1744
|
-
else optEl.removeAttribute("aria-disabled");
|
|
1745
|
-
if (i === idx && !disabled) activeId = optEl.id;
|
|
1746
|
-
}
|
|
1747
|
-
if (activeId) els.listbox.setAttribute("aria-activedescendant", activeId);
|
|
1748
|
-
else els.listbox.removeAttribute("aria-activedescendant");
|
|
1749
|
-
}, els.listbox);
|
|
1750
|
-
let typeBuffer = "";
|
|
1751
|
-
let typeTimer = null;
|
|
1752
|
-
const onKey = (e) => {
|
|
1753
|
-
if (e.key === "ArrowDown") {
|
|
1754
|
-
e.preventDefault();
|
|
1755
|
-
highlightNext();
|
|
1756
|
-
} else if (e.key === "ArrowUp") {
|
|
1757
|
-
e.preventDefault();
|
|
1758
|
-
highlightPrev();
|
|
1759
|
-
} else if (e.key === "Home") {
|
|
1760
|
-
e.preventDefault();
|
|
1761
|
-
const first = nextEnabled(-1, 1);
|
|
1762
|
-
if (first !== -1) setHighlightedIndex(first);
|
|
1763
|
-
} else if (e.key === "End") {
|
|
1764
|
-
e.preventDefault();
|
|
1765
|
-
const last = nextEnabled(items.length, -1);
|
|
1766
|
-
if (last !== -1) setHighlightedIndex(last);
|
|
1767
|
-
} else if (e.key === "Enter" || e.key === " ") {
|
|
1768
|
-
if (highlightedIndex() >= 0) {
|
|
1769
|
-
e.preventDefault();
|
|
1770
|
-
selectHighlighted();
|
|
1771
|
-
}
|
|
1772
|
-
} else if (e.key.length === 1 && /\S/.test(e.key)) {
|
|
1773
|
-
typeBuffer += e.key.toLowerCase();
|
|
1774
|
-
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
1775
|
-
typeTimer = setTimeout(() => {
|
|
1776
|
-
typeBuffer = "";
|
|
1777
|
-
typeTimer = null;
|
|
1778
|
-
}, 500);
|
|
1779
|
-
const found = items.findIndex((it) => !isItemDisabled(it) && toStr(it).toLowerCase().startsWith(typeBuffer));
|
|
1780
|
-
if (found !== -1) setHighlightedIndex(found);
|
|
1672
|
+
const remaining = days.length % 7;
|
|
1673
|
+
if (remaining > 0) {
|
|
1674
|
+
const trailingCount = 7 - remaining;
|
|
1675
|
+
for (let i = 1; i <= trailingCount; i++) {
|
|
1676
|
+
const date = new Date(year, month + 1, i);
|
|
1677
|
+
days.push({
|
|
1678
|
+
date,
|
|
1679
|
+
isCurrentMonth: false,
|
|
1680
|
+
isToday: sameDay(date, today),
|
|
1681
|
+
isSelected: selected !== null && sameDay(date, selected),
|
|
1682
|
+
isDisabled: isDateDisabled(date)
|
|
1683
|
+
});
|
|
1781
1684
|
}
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
if (boundSelects.get(els.listbox) === teardown) boundSelects.delete(els.listbox);
|
|
1789
|
-
fxTeardown();
|
|
1790
|
-
els.listbox.removeEventListener("keydown", onKey);
|
|
1791
|
-
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
1792
|
-
if (prevId === "") els.listbox.removeAttribute("id");
|
|
1793
|
-
else els.listbox.id = prevId;
|
|
1794
|
-
if (prevRole === null) els.listbox.removeAttribute("role");
|
|
1795
|
-
else els.listbox.setAttribute("role", prevRole);
|
|
1796
|
-
if (prevMultiselectable === null) els.listbox.removeAttribute("aria-multiselectable");
|
|
1797
|
-
else els.listbox.setAttribute("aria-multiselectable", prevMultiselectable);
|
|
1798
|
-
if (prevTabIndex === null) els.listbox.removeAttribute("tabindex");
|
|
1799
|
-
else els.listbox.setAttribute("tabindex", prevTabIndex);
|
|
1800
|
-
els.listbox.removeAttribute("aria-activedescendant");
|
|
1801
|
-
};
|
|
1802
|
-
boundSelects.set(els.listbox, teardown);
|
|
1803
|
-
return teardown;
|
|
1685
|
+
}
|
|
1686
|
+
return days;
|
|
1687
|
+
});
|
|
1688
|
+
function isSelected(date) {
|
|
1689
|
+
const sel = selectedDate();
|
|
1690
|
+
return sel !== null && sameDay(date, sel);
|
|
1804
1691
|
}
|
|
1805
1692
|
return {
|
|
1806
|
-
|
|
1807
|
-
selectedItem,
|
|
1693
|
+
selectedDate,
|
|
1808
1694
|
select: select2,
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
};
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
// src/widgets/Tooltip.ts
|
|
1825
|
-
var boundTriggers = /* @__PURE__ */ new WeakMap();
|
|
1826
|
-
function tooltip(options) {
|
|
1827
|
-
const delay = options?.delay ?? 0;
|
|
1828
|
-
const hideDelay = options?.hideDelay ?? 100;
|
|
1829
|
-
const [isVisible, setIsVisible] = signal(false);
|
|
1830
|
-
const [content, setContent] = signal("");
|
|
1831
|
-
let delayTimer = null;
|
|
1832
|
-
let hideTimer = null;
|
|
1833
|
-
function show() {
|
|
1834
|
-
if (hideTimer !== null) {
|
|
1835
|
-
clearTimeout(hideTimer);
|
|
1836
|
-
hideTimer = null;
|
|
1837
|
-
}
|
|
1838
|
-
if (delay > 0) {
|
|
1839
|
-
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
1840
|
-
delayTimer = setTimeout(() => {
|
|
1841
|
-
setIsVisible(true);
|
|
1842
|
-
delayTimer = null;
|
|
1843
|
-
}, delay);
|
|
1844
|
-
} else {
|
|
1845
|
-
setIsVisible(true);
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
function hide() {
|
|
1849
|
-
if (delayTimer !== null) {
|
|
1850
|
-
clearTimeout(delayTimer);
|
|
1851
|
-
delayTimer = null;
|
|
1852
|
-
}
|
|
1853
|
-
setIsVisible(false);
|
|
1854
|
-
}
|
|
1855
|
-
function scheduleHide() {
|
|
1856
|
-
if (delayTimer !== null) {
|
|
1857
|
-
clearTimeout(delayTimer);
|
|
1858
|
-
delayTimer = null;
|
|
1859
|
-
}
|
|
1860
|
-
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
1861
|
-
hideTimer = setTimeout(() => {
|
|
1862
|
-
hideTimer = null;
|
|
1863
|
-
setIsVisible(false);
|
|
1864
|
-
}, hideDelay);
|
|
1865
|
-
}
|
|
1695
|
+
viewDate,
|
|
1696
|
+
setViewDate,
|
|
1697
|
+
nextMonth,
|
|
1698
|
+
prevMonth,
|
|
1699
|
+
nextYear,
|
|
1700
|
+
prevYear,
|
|
1701
|
+
daysInMonth,
|
|
1702
|
+
isDateDisabled,
|
|
1703
|
+
/** Reactive check — use inside class bindings for per-day reactivity */
|
|
1704
|
+
isSelected,
|
|
1705
|
+
bind
|
|
1706
|
+
};
|
|
1866
1707
|
function bind(els) {
|
|
1867
|
-
const existing =
|
|
1708
|
+
const existing = boundDatePickers.get(els.grid);
|
|
1868
1709
|
if (existing) return existing;
|
|
1869
|
-
const
|
|
1870
|
-
els.
|
|
1871
|
-
els.
|
|
1872
|
-
|
|
1873
|
-
els.
|
|
1710
|
+
const prevGridRole = els.grid.getAttribute("role");
|
|
1711
|
+
const prevGridTabIndex = els.grid.getAttribute("tabindex");
|
|
1712
|
+
const prevGridLabel = els.grid.getAttribute("aria-label");
|
|
1713
|
+
els.grid.setAttribute("role", "grid");
|
|
1714
|
+
if (els.grid.tabIndex < 0) els.grid.tabIndex = 0;
|
|
1715
|
+
let pendingFocus = false;
|
|
1716
|
+
const touchedCells = /* @__PURE__ */ new Map();
|
|
1717
|
+
const restoreAttr = (el, name, value) => {
|
|
1718
|
+
if (value === null) el.removeAttribute(name);
|
|
1719
|
+
else el.setAttribute(name, value);
|
|
1720
|
+
};
|
|
1721
|
+
const restoreCell = (cell, snap) => {
|
|
1722
|
+
restoreAttr(cell, "role", snap.role);
|
|
1723
|
+
restoreAttr(cell, "aria-selected", snap.selected);
|
|
1724
|
+
restoreAttr(cell, "aria-disabled", snap.disabled);
|
|
1725
|
+
restoreAttr(cell, "tabindex", snap.tabindex);
|
|
1726
|
+
};
|
|
1874
1727
|
const fxTeardown = domBinding(() => {
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1728
|
+
const sel = selectedDate();
|
|
1729
|
+
const view = viewDate();
|
|
1730
|
+
const days = daysInMonth();
|
|
1731
|
+
els.grid.setAttribute("aria-label", view.toLocaleDateString(void 0, { month: "long", year: "numeric" }));
|
|
1732
|
+
let viewCell = null;
|
|
1733
|
+
const displayed = /* @__PURE__ */ new Set();
|
|
1734
|
+
for (const d of days) {
|
|
1735
|
+
const cell = els.cell(d.date);
|
|
1736
|
+
if (!cell) continue;
|
|
1737
|
+
displayed.add(cell);
|
|
1738
|
+
if (!touchedCells.has(cell)) {
|
|
1739
|
+
touchedCells.set(cell, {
|
|
1740
|
+
role: cell.getAttribute("role"),
|
|
1741
|
+
selected: cell.getAttribute("aria-selected"),
|
|
1742
|
+
disabled: cell.getAttribute("aria-disabled"),
|
|
1743
|
+
tabindex: cell.getAttribute("tabindex")
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
cell.setAttribute("role", "gridcell");
|
|
1747
|
+
cell.setAttribute("aria-selected", sel && isSameCalendarDay(sel, d.date) ? "true" : "false");
|
|
1748
|
+
if (d.isDisabled) cell.setAttribute("aria-disabled", "true");
|
|
1749
|
+
else cell.removeAttribute("aria-disabled");
|
|
1750
|
+
const isView = isSameCalendarDay(view, d.date);
|
|
1751
|
+
cell.tabIndex = isView ? 0 : -1;
|
|
1752
|
+
if (isView) viewCell = cell;
|
|
1883
1753
|
}
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1754
|
+
for (const [cell, snap] of touchedCells) {
|
|
1755
|
+
if (!displayed.has(cell)) {
|
|
1756
|
+
restoreCell(cell, snap);
|
|
1757
|
+
touchedCells.delete(cell);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
if (pendingFocus && viewCell && typeof viewCell.focus === "function") {
|
|
1761
|
+
pendingFocus = false;
|
|
1762
|
+
viewCell.focus();
|
|
1763
|
+
}
|
|
1764
|
+
}, els.grid);
|
|
1765
|
+
function isSameCalendarDay(a, b) {
|
|
1766
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1767
|
+
}
|
|
1768
|
+
function shiftDays(delta) {
|
|
1769
|
+
setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth(), prev.getDate() + delta));
|
|
1770
|
+
}
|
|
1888
1771
|
const onKey = (e) => {
|
|
1889
|
-
if (e
|
|
1890
|
-
|
|
1891
|
-
|
|
1772
|
+
if (isWidgetKeyEvent(e)) return;
|
|
1773
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Home" || e.key === "End" || e.key === "PageUp" || e.key === "PageDown") {
|
|
1774
|
+
pendingFocus = true;
|
|
1775
|
+
}
|
|
1776
|
+
switch (e.key) {
|
|
1777
|
+
case "ArrowLeft":
|
|
1778
|
+
e.preventDefault();
|
|
1779
|
+
claimWidgetKey(e, "datePicker");
|
|
1780
|
+
shiftDays(-1);
|
|
1781
|
+
break;
|
|
1782
|
+
case "ArrowRight":
|
|
1783
|
+
e.preventDefault();
|
|
1784
|
+
claimWidgetKey(e, "datePicker");
|
|
1785
|
+
shiftDays(1);
|
|
1786
|
+
break;
|
|
1787
|
+
case "ArrowUp":
|
|
1788
|
+
e.preventDefault();
|
|
1789
|
+
claimWidgetKey(e, "datePicker");
|
|
1790
|
+
shiftDays(-7);
|
|
1791
|
+
break;
|
|
1792
|
+
case "ArrowDown":
|
|
1793
|
+
e.preventDefault();
|
|
1794
|
+
claimWidgetKey(e, "datePicker");
|
|
1795
|
+
shiftDays(7);
|
|
1796
|
+
break;
|
|
1797
|
+
case "Home":
|
|
1798
|
+
e.preventDefault();
|
|
1799
|
+
claimWidgetKey(e, "datePicker");
|
|
1800
|
+
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() - p.getDay()));
|
|
1801
|
+
break;
|
|
1802
|
+
case "End": {
|
|
1803
|
+
e.preventDefault();
|
|
1804
|
+
claimWidgetKey(e, "datePicker");
|
|
1805
|
+
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() + (6 - p.getDay())));
|
|
1806
|
+
break;
|
|
1807
|
+
}
|
|
1808
|
+
case "PageUp":
|
|
1809
|
+
e.preventDefault();
|
|
1810
|
+
claimWidgetKey(e, "datePicker");
|
|
1811
|
+
if (e.shiftKey) prevYear();
|
|
1812
|
+
else prevMonth();
|
|
1813
|
+
break;
|
|
1814
|
+
case "PageDown":
|
|
1815
|
+
e.preventDefault();
|
|
1816
|
+
claimWidgetKey(e, "datePicker");
|
|
1817
|
+
if (e.shiftKey) nextYear();
|
|
1818
|
+
else nextMonth();
|
|
1819
|
+
break;
|
|
1820
|
+
case "Enter":
|
|
1821
|
+
case " ":
|
|
1822
|
+
e.preventDefault();
|
|
1823
|
+
claimWidgetKey(e, "datePicker");
|
|
1824
|
+
select2(viewDate());
|
|
1825
|
+
break;
|
|
1892
1826
|
}
|
|
1893
1827
|
};
|
|
1894
|
-
els.
|
|
1895
|
-
els.trigger.addEventListener("pointerleave", onTriggerLeave);
|
|
1896
|
-
els.trigger.addEventListener("focus", onFocus);
|
|
1897
|
-
els.trigger.addEventListener("blur", onBlur);
|
|
1898
|
-
els.trigger.addEventListener("keydown", onKey);
|
|
1899
|
-
els.tooltip.addEventListener("pointerenter", onTooltipEnter);
|
|
1900
|
-
els.tooltip.addEventListener("pointerleave", onTooltipLeave);
|
|
1828
|
+
els.grid.addEventListener("keydown", onKey);
|
|
1901
1829
|
let tornDown = false;
|
|
1902
1830
|
const teardown = () => {
|
|
1903
1831
|
if (tornDown) return;
|
|
1904
1832
|
tornDown = true;
|
|
1905
|
-
if (
|
|
1833
|
+
if (boundDatePickers.get(els.grid) === teardown) boundDatePickers.delete(els.grid);
|
|
1906
1834
|
fxTeardown();
|
|
1907
|
-
els.
|
|
1908
|
-
els.
|
|
1909
|
-
els.
|
|
1910
|
-
els.
|
|
1911
|
-
els.
|
|
1912
|
-
els.
|
|
1913
|
-
els.
|
|
1914
|
-
const
|
|
1915
|
-
|
|
1916
|
-
const remaining = cur.split(/\s+/).filter((part) => part && part !== id);
|
|
1917
|
-
if (remaining.length > 0) els.trigger.setAttribute("aria-describedby", remaining.join(" "));
|
|
1918
|
-
else els.trigger.removeAttribute("aria-describedby");
|
|
1919
|
-
} else if (prevDescribedBy) {
|
|
1920
|
-
els.trigger.setAttribute("aria-describedby", prevDescribedBy);
|
|
1921
|
-
}
|
|
1922
|
-
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
1923
|
-
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
1835
|
+
els.grid.removeEventListener("keydown", onKey);
|
|
1836
|
+
if (prevGridRole === null) els.grid.removeAttribute("role");
|
|
1837
|
+
else els.grid.setAttribute("role", prevGridRole);
|
|
1838
|
+
if (prevGridTabIndex === null) els.grid.removeAttribute("tabindex");
|
|
1839
|
+
else els.grid.setAttribute("tabindex", prevGridTabIndex);
|
|
1840
|
+
if (prevGridLabel === null) els.grid.removeAttribute("aria-label");
|
|
1841
|
+
else els.grid.setAttribute("aria-label", prevGridLabel);
|
|
1842
|
+
for (const [cell, snap] of touchedCells) restoreCell(cell, snap);
|
|
1843
|
+
touchedCells.clear();
|
|
1924
1844
|
};
|
|
1925
|
-
|
|
1845
|
+
boundDatePickers.set(els.grid, teardown);
|
|
1926
1846
|
return teardown;
|
|
1927
1847
|
}
|
|
1928
|
-
return { isVisible, show, hide, content, setContent, bind };
|
|
1929
1848
|
}
|
|
1930
1849
|
|
|
1931
1850
|
// src/widgets/FileUpload.ts
|
|
@@ -2073,8 +1992,10 @@ function fileUpload(options) {
|
|
|
2073
1992
|
};
|
|
2074
1993
|
const onDropClick = () => els.input.click();
|
|
2075
1994
|
const onDropKey = (e) => {
|
|
1995
|
+
if (isWidgetKeyEvent(e)) return;
|
|
2076
1996
|
if (e.key === "Enter" || e.key === " ") {
|
|
2077
1997
|
e.preventDefault();
|
|
1998
|
+
claimWidgetKey(e, "fileUpload");
|
|
2078
1999
|
els.input.click();
|
|
2079
2000
|
}
|
|
2080
2001
|
};
|
|
@@ -2127,365 +2048,841 @@ function fileUpload(options) {
|
|
|
2127
2048
|
};
|
|
2128
2049
|
}
|
|
2129
2050
|
|
|
2130
|
-
// src/
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2051
|
+
// src/widgets/Popover.ts
|
|
2052
|
+
var boundPopovers = /* @__PURE__ */ new WeakMap();
|
|
2053
|
+
function popover() {
|
|
2054
|
+
const [isOpen, setIsOpen] = signal(false);
|
|
2055
|
+
function open() {
|
|
2056
|
+
setIsOpen(true);
|
|
2057
|
+
}
|
|
2058
|
+
function close() {
|
|
2059
|
+
setIsOpen(false);
|
|
2060
|
+
}
|
|
2061
|
+
function toggle() {
|
|
2062
|
+
setIsOpen((prev) => !prev);
|
|
2063
|
+
}
|
|
2064
|
+
function bind(els) {
|
|
2065
|
+
const existing = boundPopovers.get(els.trigger);
|
|
2066
|
+
if (existing) return existing;
|
|
2067
|
+
const id = createId("sibu-popover");
|
|
2068
|
+
const prevPopoverRole = els.popover.getAttribute("role");
|
|
2069
|
+
const prevPopoverId = els.popover.id;
|
|
2070
|
+
const prevLabelledBy = els.popover.getAttribute("aria-labelledby");
|
|
2071
|
+
const prevTriggerHaspopup = els.trigger.getAttribute("aria-haspopup");
|
|
2072
|
+
const prevTriggerControls = els.trigger.getAttribute("aria-controls");
|
|
2073
|
+
els.popover.setAttribute("role", "dialog");
|
|
2074
|
+
els.popover.id = id;
|
|
2075
|
+
els.trigger.setAttribute("aria-haspopup", "dialog");
|
|
2076
|
+
els.trigger.setAttribute("aria-controls", id);
|
|
2077
|
+
let assignedLabelId = null;
|
|
2078
|
+
if (els.labelledBy) {
|
|
2079
|
+
if (!els.labelledBy.id) {
|
|
2080
|
+
els.labelledBy.id = `${id}-label`;
|
|
2081
|
+
assignedLabelId = els.labelledBy.id;
|
|
2082
|
+
}
|
|
2083
|
+
els.popover.setAttribute("aria-labelledby", els.labelledBy.id);
|
|
2137
2084
|
}
|
|
2085
|
+
const fxTeardown = domBinding(() => {
|
|
2086
|
+
const open2 = isOpen();
|
|
2087
|
+
els.trigger.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
2088
|
+
els.popover.hidden = !open2;
|
|
2089
|
+
}, els.trigger);
|
|
2090
|
+
const onTriggerClick = (e) => {
|
|
2091
|
+
e.preventDefault();
|
|
2092
|
+
toggle();
|
|
2093
|
+
};
|
|
2094
|
+
const onKey = (e) => {
|
|
2095
|
+
if (isWidgetKeyEvent(e)) return;
|
|
2096
|
+
if (e.key === "Escape" && isOpen()) {
|
|
2097
|
+
e.stopPropagation();
|
|
2098
|
+
claimWidgetKey(e, "popover");
|
|
2099
|
+
close();
|
|
2100
|
+
els.trigger.focus();
|
|
2101
|
+
}
|
|
2102
|
+
};
|
|
2103
|
+
const onDocPointer = (e) => {
|
|
2104
|
+
if (!isOpen()) return;
|
|
2105
|
+
const t = e.target;
|
|
2106
|
+
if (!t) return;
|
|
2107
|
+
if (els.trigger.contains(t) || els.popover.contains(t)) return;
|
|
2108
|
+
close();
|
|
2109
|
+
};
|
|
2110
|
+
els.trigger.addEventListener("click", onTriggerClick);
|
|
2111
|
+
els.popover.addEventListener("keydown", onKey);
|
|
2112
|
+
els.trigger.addEventListener("keydown", onKey);
|
|
2113
|
+
document.addEventListener("pointerdown", onDocPointer);
|
|
2114
|
+
let tornDown = false;
|
|
2115
|
+
const teardown = () => {
|
|
2116
|
+
if (tornDown) return;
|
|
2117
|
+
tornDown = true;
|
|
2118
|
+
if (boundPopovers.get(els.trigger) === teardown) boundPopovers.delete(els.trigger);
|
|
2119
|
+
fxTeardown();
|
|
2120
|
+
els.trigger.removeEventListener("click", onTriggerClick);
|
|
2121
|
+
els.popover.removeEventListener("keydown", onKey);
|
|
2122
|
+
els.trigger.removeEventListener("keydown", onKey);
|
|
2123
|
+
document.removeEventListener("pointerdown", onDocPointer);
|
|
2124
|
+
if (prevPopoverRole === null) els.popover.removeAttribute("role");
|
|
2125
|
+
else els.popover.setAttribute("role", prevPopoverRole);
|
|
2126
|
+
if (prevPopoverId === "") els.popover.removeAttribute("id");
|
|
2127
|
+
else els.popover.id = prevPopoverId;
|
|
2128
|
+
if (prevLabelledBy === null) els.popover.removeAttribute("aria-labelledby");
|
|
2129
|
+
else els.popover.setAttribute("aria-labelledby", prevLabelledBy);
|
|
2130
|
+
if (assignedLabelId && els.labelledBy?.id === assignedLabelId) {
|
|
2131
|
+
els.labelledBy.removeAttribute("id");
|
|
2132
|
+
}
|
|
2133
|
+
if (prevTriggerHaspopup === null) els.trigger.removeAttribute("aria-haspopup");
|
|
2134
|
+
else els.trigger.setAttribute("aria-haspopup", prevTriggerHaspopup);
|
|
2135
|
+
if (prevTriggerControls === null) els.trigger.removeAttribute("aria-controls");
|
|
2136
|
+
else els.trigger.setAttribute("aria-controls", prevTriggerControls);
|
|
2137
|
+
els.trigger.removeAttribute("aria-expanded");
|
|
2138
|
+
};
|
|
2139
|
+
boundPopovers.set(els.trigger, teardown);
|
|
2140
|
+
return teardown;
|
|
2138
2141
|
}
|
|
2139
|
-
|
|
2140
|
-
let out = input;
|
|
2141
|
-
do {
|
|
2142
|
-
prev = out;
|
|
2143
|
-
out = out.replace(/<[^>]*>/g, "");
|
|
2144
|
-
} while (out !== prev);
|
|
2145
|
-
return out.replace(/<[^>]*$/, "");
|
|
2142
|
+
return { isOpen, open, close, toggle, bind };
|
|
2146
2143
|
}
|
|
2147
2144
|
|
|
2148
|
-
// src/widgets/
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
const [
|
|
2154
|
-
const [
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2145
|
+
// src/widgets/Select.ts
|
|
2146
|
+
var boundSelects = /* @__PURE__ */ new WeakMap();
|
|
2147
|
+
function select(options) {
|
|
2148
|
+
const { items, multiple = false, itemToString, isDisabled } = options;
|
|
2149
|
+
const isItemDisabled = isDisabled ?? (() => false);
|
|
2150
|
+
const [selectedItems, setSelectedItems] = signal([]);
|
|
2151
|
+
const [isOpen, setIsOpen] = signal(false);
|
|
2152
|
+
const [highlightedIndex, setHighlightedIndex] = signal(-1);
|
|
2153
|
+
const selectedItem = derived(() => {
|
|
2154
|
+
const sel = selectedItems();
|
|
2155
|
+
return sel.length > 0 ? sel[sel.length - 1] : null;
|
|
2156
|
+
});
|
|
2157
|
+
function select2(item) {
|
|
2158
|
+
if (isItemDisabled(item)) return;
|
|
2159
|
+
if (multiple) {
|
|
2160
|
+
setSelectedItems((prev) => {
|
|
2161
|
+
if (prev.includes(item)) return prev;
|
|
2162
|
+
return [...prev, item];
|
|
2163
|
+
});
|
|
2164
|
+
} else {
|
|
2165
|
+
batch(() => {
|
|
2166
|
+
setSelectedItems([item]);
|
|
2167
|
+
setIsOpen(false);
|
|
2168
|
+
});
|
|
2168
2169
|
}
|
|
2169
|
-
setContentInternal("");
|
|
2170
2170
|
}
|
|
2171
|
-
function
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
const ancestor = range.commonAncestorContainer;
|
|
2178
|
-
const existingWrap = findWrapperWithinEditor(
|
|
2179
|
-
ancestor instanceof HTMLElement ? ancestor : ancestor.parentElement,
|
|
2180
|
-
tagName
|
|
2181
|
-
);
|
|
2182
|
-
let targetNode = null;
|
|
2183
|
-
if (existingWrap) {
|
|
2184
|
-
const parent = existingWrap.parentNode;
|
|
2185
|
-
if (parent) {
|
|
2186
|
-
const firstChild = existingWrap.firstChild;
|
|
2187
|
-
const lastChild = existingWrap.lastChild;
|
|
2188
|
-
while (existingWrap.firstChild) {
|
|
2189
|
-
parent.insertBefore(existingWrap.firstChild, existingWrap);
|
|
2190
|
-
}
|
|
2191
|
-
parent.removeChild(existingWrap);
|
|
2192
|
-
if (firstChild && lastChild) {
|
|
2193
|
-
const newRange = document.createRange();
|
|
2194
|
-
newRange.setStartBefore(firstChild);
|
|
2195
|
-
newRange.setEndAfter(lastChild);
|
|
2196
|
-
selection.removeAllRanges();
|
|
2197
|
-
selection.addRange(newRange);
|
|
2198
|
-
return;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2171
|
+
function deselect(item) {
|
|
2172
|
+
setSelectedItems((prev) => prev.filter((i) => i !== item));
|
|
2173
|
+
}
|
|
2174
|
+
function toggle(item) {
|
|
2175
|
+
if (selectedItems().includes(item)) {
|
|
2176
|
+
deselect(item);
|
|
2201
2177
|
} else {
|
|
2202
|
-
|
|
2203
|
-
try {
|
|
2204
|
-
range.surroundContents(wrapper);
|
|
2205
|
-
} catch {
|
|
2206
|
-
const fragment = range.extractContents();
|
|
2207
|
-
wrapper.appendChild(fragment);
|
|
2208
|
-
range.insertNode(wrapper);
|
|
2209
|
-
}
|
|
2210
|
-
targetNode = wrapper;
|
|
2211
|
-
}
|
|
2212
|
-
if (targetNode) {
|
|
2213
|
-
selection.removeAllRanges();
|
|
2214
|
-
const newRange = document.createRange();
|
|
2215
|
-
newRange.selectNodeContents(targetNode);
|
|
2216
|
-
selection.addRange(newRange);
|
|
2178
|
+
select2(item);
|
|
2217
2179
|
}
|
|
2218
2180
|
}
|
|
2219
|
-
function
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2181
|
+
function isSelected(item) {
|
|
2182
|
+
return selectedItems().includes(item);
|
|
2183
|
+
}
|
|
2184
|
+
function open() {
|
|
2185
|
+
setIsOpen(true);
|
|
2186
|
+
}
|
|
2187
|
+
function close() {
|
|
2188
|
+
setIsOpen(false);
|
|
2189
|
+
}
|
|
2190
|
+
function nextEnabled(from, dir) {
|
|
2191
|
+
const len = items.length;
|
|
2192
|
+
if (len === 0) return -1;
|
|
2193
|
+
let i = from;
|
|
2194
|
+
for (let n = 0; n < len; n++) {
|
|
2195
|
+
i = (i + dir + len) % len;
|
|
2196
|
+
if (!isItemDisabled(items[i])) return i;
|
|
2225
2197
|
}
|
|
2226
|
-
return
|
|
2198
|
+
return -1;
|
|
2227
2199
|
}
|
|
2228
|
-
function
|
|
2229
|
-
|
|
2230
|
-
|
|
2200
|
+
function highlightNext() {
|
|
2201
|
+
if (items.length === 0) return;
|
|
2202
|
+
setHighlightedIndex((prev) => {
|
|
2203
|
+
const n = nextEnabled(prev < 0 ? -1 : prev, 1);
|
|
2204
|
+
return n === -1 ? prev : n;
|
|
2205
|
+
});
|
|
2231
2206
|
}
|
|
2232
|
-
function
|
|
2233
|
-
|
|
2207
|
+
function highlightPrev() {
|
|
2208
|
+
if (items.length === 0) return;
|
|
2209
|
+
setHighlightedIndex((prev) => {
|
|
2210
|
+
const n = nextEnabled(prev < 0 ? items.length : prev, -1);
|
|
2211
|
+
return n === -1 ? prev : n;
|
|
2212
|
+
});
|
|
2234
2213
|
}
|
|
2235
|
-
function
|
|
2236
|
-
|
|
2214
|
+
function selectHighlighted() {
|
|
2215
|
+
const idx = highlightedIndex();
|
|
2216
|
+
if (idx >= 0 && idx < items.length) {
|
|
2217
|
+
select2(items[idx]);
|
|
2218
|
+
}
|
|
2237
2219
|
}
|
|
2238
|
-
function
|
|
2239
|
-
|
|
2220
|
+
function clear() {
|
|
2221
|
+
setSelectedItems([]);
|
|
2222
|
+
}
|
|
2223
|
+
function bind(els) {
|
|
2224
|
+
const existing = boundSelects.get(els.listbox);
|
|
2225
|
+
if (existing) return existing;
|
|
2226
|
+
const prevId = els.listbox.id;
|
|
2227
|
+
const prevRole = els.listbox.getAttribute("role");
|
|
2228
|
+
const prevMultiselectable = els.listbox.getAttribute("aria-multiselectable");
|
|
2229
|
+
const prevTabIndex = els.listbox.getAttribute("tabindex");
|
|
2230
|
+
const listboxId = createId("sibu-select");
|
|
2231
|
+
els.listbox.id = listboxId;
|
|
2232
|
+
els.listbox.setAttribute("role", "listbox");
|
|
2233
|
+
els.listbox.setAttribute("aria-multiselectable", multiple ? "true" : "false");
|
|
2234
|
+
if (els.listbox.tabIndex < 0) els.listbox.tabIndex = 0;
|
|
2235
|
+
const toStr = els.itemToString ?? itemToString ?? ((it) => String(it));
|
|
2236
|
+
const fxTeardown = domBinding(() => {
|
|
2237
|
+
const idx = highlightedIndex();
|
|
2238
|
+
const sel = selectedItems();
|
|
2239
|
+
let activeId = "";
|
|
2240
|
+
for (let i = 0; i < items.length; i++) {
|
|
2241
|
+
const optEl = els.option(items[i], i);
|
|
2242
|
+
if (!optEl) continue;
|
|
2243
|
+
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
2244
|
+
optEl.setAttribute("role", "option");
|
|
2245
|
+
optEl.setAttribute("aria-selected", sel.includes(items[i]) ? "true" : "false");
|
|
2246
|
+
const disabled = isItemDisabled(items[i]);
|
|
2247
|
+
if (disabled) optEl.setAttribute("aria-disabled", "true");
|
|
2248
|
+
else optEl.removeAttribute("aria-disabled");
|
|
2249
|
+
if (i === idx && !disabled) activeId = optEl.id;
|
|
2250
|
+
}
|
|
2251
|
+
if (activeId) els.listbox.setAttribute("aria-activedescendant", activeId);
|
|
2252
|
+
else els.listbox.removeAttribute("aria-activedescendant");
|
|
2253
|
+
}, els.listbox);
|
|
2254
|
+
let typeBuffer = "";
|
|
2255
|
+
let typeTimer = null;
|
|
2256
|
+
const onKey = (e) => {
|
|
2257
|
+
if (isWidgetKeyEvent(e)) return;
|
|
2258
|
+
if (e.key === "ArrowDown") {
|
|
2259
|
+
e.preventDefault();
|
|
2260
|
+
claimWidgetKey(e, "select");
|
|
2261
|
+
highlightNext();
|
|
2262
|
+
} else if (e.key === "ArrowUp") {
|
|
2263
|
+
e.preventDefault();
|
|
2264
|
+
claimWidgetKey(e, "select");
|
|
2265
|
+
highlightPrev();
|
|
2266
|
+
} else if (e.key === "Home") {
|
|
2267
|
+
e.preventDefault();
|
|
2268
|
+
claimWidgetKey(e, "select");
|
|
2269
|
+
const first = nextEnabled(-1, 1);
|
|
2270
|
+
if (first !== -1) setHighlightedIndex(first);
|
|
2271
|
+
} else if (e.key === "End") {
|
|
2272
|
+
e.preventDefault();
|
|
2273
|
+
claimWidgetKey(e, "select");
|
|
2274
|
+
const last = nextEnabled(items.length, -1);
|
|
2275
|
+
if (last !== -1) setHighlightedIndex(last);
|
|
2276
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
2277
|
+
if (highlightedIndex() >= 0) {
|
|
2278
|
+
e.preventDefault();
|
|
2279
|
+
claimWidgetKey(e, "select");
|
|
2280
|
+
selectHighlighted();
|
|
2281
|
+
}
|
|
2282
|
+
} else if (e.key.length === 1 && /\S/.test(e.key)) {
|
|
2283
|
+
claimWidgetKey(e, "select");
|
|
2284
|
+
typeBuffer += e.key.toLowerCase();
|
|
2285
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
2286
|
+
typeTimer = setTimeout(() => {
|
|
2287
|
+
typeBuffer = "";
|
|
2288
|
+
typeTimer = null;
|
|
2289
|
+
}, 500);
|
|
2290
|
+
const found = items.findIndex((it) => !isItemDisabled(it) && toStr(it).toLowerCase().startsWith(typeBuffer));
|
|
2291
|
+
if (found !== -1) setHighlightedIndex(found);
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
els.listbox.addEventListener("keydown", onKey);
|
|
2295
|
+
let tornDown = false;
|
|
2296
|
+
const teardown = () => {
|
|
2297
|
+
if (tornDown) return;
|
|
2298
|
+
tornDown = true;
|
|
2299
|
+
if (boundSelects.get(els.listbox) === teardown) boundSelects.delete(els.listbox);
|
|
2300
|
+
fxTeardown();
|
|
2301
|
+
els.listbox.removeEventListener("keydown", onKey);
|
|
2302
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
2303
|
+
if (prevId === "") els.listbox.removeAttribute("id");
|
|
2304
|
+
else els.listbox.id = prevId;
|
|
2305
|
+
if (prevRole === null) els.listbox.removeAttribute("role");
|
|
2306
|
+
else els.listbox.setAttribute("role", prevRole);
|
|
2307
|
+
if (prevMultiselectable === null) els.listbox.removeAttribute("aria-multiselectable");
|
|
2308
|
+
else els.listbox.setAttribute("aria-multiselectable", prevMultiselectable);
|
|
2309
|
+
if (prevTabIndex === null) els.listbox.removeAttribute("tabindex");
|
|
2310
|
+
else els.listbox.setAttribute("tabindex", prevTabIndex);
|
|
2311
|
+
els.listbox.removeAttribute("aria-activedescendant");
|
|
2312
|
+
};
|
|
2313
|
+
boundSelects.set(els.listbox, teardown);
|
|
2314
|
+
return teardown;
|
|
2240
2315
|
}
|
|
2241
2316
|
return {
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2317
|
+
selectedItems,
|
|
2318
|
+
selectedItem,
|
|
2319
|
+
select: select2,
|
|
2320
|
+
deselect,
|
|
2321
|
+
toggle,
|
|
2322
|
+
isSelected,
|
|
2323
|
+
isOpen,
|
|
2324
|
+
open,
|
|
2325
|
+
close,
|
|
2326
|
+
highlightedIndex,
|
|
2327
|
+
highlightNext,
|
|
2328
|
+
highlightPrev,
|
|
2329
|
+
selectHighlighted,
|
|
2330
|
+
clear,
|
|
2331
|
+
bind
|
|
2249
2332
|
};
|
|
2250
2333
|
}
|
|
2251
2334
|
|
|
2252
|
-
// src/widgets/
|
|
2253
|
-
var
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
const
|
|
2257
|
-
const
|
|
2258
|
-
const
|
|
2259
|
-
const
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2335
|
+
// src/widgets/selectMenu.ts
|
|
2336
|
+
var boundMenus = /* @__PURE__ */ new WeakMap();
|
|
2337
|
+
var OPTION_ATTRS = ["id", "role", "aria-selected", "aria-disabled"];
|
|
2338
|
+
function selectMenu(options) {
|
|
2339
|
+
const getItems = typeof options.items === "function" ? options.items : () => options.items;
|
|
2340
|
+
const toStr = options.itemToString ?? ((item) => String(item));
|
|
2341
|
+
const isDisabled = options.isDisabled ?? (() => false);
|
|
2342
|
+
const isEqual = options.isEqual ?? Object.is;
|
|
2343
|
+
const pageSize = Math.max(1, options.pageSize ?? 10);
|
|
2344
|
+
const [ownValue, setOwnValue] = signal(options.defaultValue ?? null);
|
|
2345
|
+
const readValue = options.value;
|
|
2346
|
+
const value = () => readValue ? readValue() ?? null : ownValue();
|
|
2347
|
+
const [isOpen, setIsOpen] = signal(false);
|
|
2348
|
+
const [active, setActiveIndex] = signal(-1);
|
|
2349
|
+
const enabledAt = (items, i) => i >= 0 && i < items.length && !isDisabled(items[i]);
|
|
2350
|
+
function enabledFrom(items, from, dir) {
|
|
2351
|
+
for (let i = from; i >= 0 && i < items.length; i += dir) if (!isDisabled(items[i])) return i;
|
|
2352
|
+
return -1;
|
|
2265
2353
|
}
|
|
2266
|
-
function
|
|
2267
|
-
|
|
2354
|
+
function selectedIndex(items) {
|
|
2355
|
+
const v = value();
|
|
2356
|
+
if (v === null) return -1;
|
|
2357
|
+
return items.findIndex((it) => isEqual(it, v));
|
|
2358
|
+
}
|
|
2359
|
+
function open(activeAt = "selected") {
|
|
2360
|
+
untracked2(() => {
|
|
2361
|
+
const items = getItems();
|
|
2362
|
+
let idx = -1;
|
|
2363
|
+
if (activeAt === "last") idx = enabledFrom(items, items.length - 1, -1);
|
|
2364
|
+
else if (activeAt === "first") idx = enabledFrom(items, 0, 1);
|
|
2365
|
+
else {
|
|
2366
|
+
const sel = selectedIndex(items);
|
|
2367
|
+
idx = enabledAt(items, sel) ? sel : enabledFrom(items, 0, 1);
|
|
2368
|
+
}
|
|
2369
|
+
batch(() => {
|
|
2370
|
+
setActiveIndex(idx);
|
|
2371
|
+
setIsOpen(true);
|
|
2372
|
+
});
|
|
2373
|
+
});
|
|
2268
2374
|
}
|
|
2269
|
-
function
|
|
2270
|
-
|
|
2375
|
+
function close() {
|
|
2376
|
+
setIsOpen(false);
|
|
2271
2377
|
}
|
|
2272
|
-
function
|
|
2273
|
-
if (
|
|
2274
|
-
|
|
2275
|
-
}
|
|
2378
|
+
function toggle() {
|
|
2379
|
+
if (untracked2(isOpen)) close();
|
|
2380
|
+
else open();
|
|
2276
2381
|
}
|
|
2277
|
-
function
|
|
2278
|
-
|
|
2382
|
+
function setActive(index) {
|
|
2383
|
+
if (enabledAt(untracked2(getItems), index)) setActiveIndex(index);
|
|
2279
2384
|
}
|
|
2280
|
-
function
|
|
2281
|
-
|
|
2385
|
+
function select2(item) {
|
|
2386
|
+
if (isDisabled(item)) return;
|
|
2387
|
+
batch(() => {
|
|
2388
|
+
if (!readValue) setOwnValue(() => item);
|
|
2389
|
+
setIsOpen(false);
|
|
2390
|
+
});
|
|
2391
|
+
options.onChange?.(item);
|
|
2282
2392
|
}
|
|
2283
|
-
function
|
|
2284
|
-
|
|
2393
|
+
function activeItem() {
|
|
2394
|
+
const items = getItems();
|
|
2395
|
+
const i = active();
|
|
2396
|
+
return i >= 0 && i < items.length ? items[i] : null;
|
|
2285
2397
|
}
|
|
2286
|
-
function
|
|
2287
|
-
|
|
2398
|
+
function bind(els) {
|
|
2399
|
+
const existing = boundMenus.get(els.trigger);
|
|
2400
|
+
if (existing) return existing;
|
|
2401
|
+
const { trigger, listbox } = els;
|
|
2402
|
+
const restoreTrigger = snapshotAttributes(trigger, [
|
|
2403
|
+
"role",
|
|
2404
|
+
"aria-haspopup",
|
|
2405
|
+
"aria-expanded",
|
|
2406
|
+
"aria-controls",
|
|
2407
|
+
"aria-activedescendant",
|
|
2408
|
+
"tabindex"
|
|
2409
|
+
]);
|
|
2410
|
+
const restoreListbox = snapshotAttributes(listbox, ["id", "role", "tabindex"]);
|
|
2411
|
+
const prevHidden = listbox.hidden;
|
|
2412
|
+
const optionRestores = /* @__PURE__ */ new Map();
|
|
2413
|
+
const generatedIds = /* @__PURE__ */ new WeakMap();
|
|
2414
|
+
let optionIndex = /* @__PURE__ */ new Map();
|
|
2415
|
+
const listboxId = listbox.id || createId("sibu-select-menu");
|
|
2416
|
+
listbox.id = listboxId;
|
|
2417
|
+
listbox.setAttribute("role", "listbox");
|
|
2418
|
+
listbox.tabIndex = -1;
|
|
2419
|
+
trigger.setAttribute("role", "combobox");
|
|
2420
|
+
trigger.setAttribute("aria-haspopup", "listbox");
|
|
2421
|
+
trigger.setAttribute("aria-controls", listboxId);
|
|
2422
|
+
if (trigger.tabIndex < 0) trigger.tabIndex = 0;
|
|
2423
|
+
const generatedIdFor = (el, taken) => {
|
|
2424
|
+
let id = generatedIds.get(el);
|
|
2425
|
+
while (id === void 0 || taken.has(id) || el.ownerDocument.getElementById(id) !== null) {
|
|
2426
|
+
id = createId(`${listboxId}-opt`);
|
|
2427
|
+
}
|
|
2428
|
+
generatedIds.set(el, id);
|
|
2429
|
+
return id;
|
|
2430
|
+
};
|
|
2431
|
+
let lastScrolled = null;
|
|
2432
|
+
const stopBinding = domBinding(() => {
|
|
2433
|
+
const items = getItems();
|
|
2434
|
+
const openNow = isOpen();
|
|
2435
|
+
const idx = active();
|
|
2436
|
+
const sel = value();
|
|
2437
|
+
trigger.setAttribute("aria-expanded", openNow ? "true" : "false");
|
|
2438
|
+
listbox.hidden = !openNow;
|
|
2439
|
+
const nextIndex = /* @__PURE__ */ new Map();
|
|
2440
|
+
let activeEl = null;
|
|
2441
|
+
const optionEls = [];
|
|
2442
|
+
const taken = /* @__PURE__ */ new Set();
|
|
2443
|
+
for (let i = 0; i < items.length; i++) {
|
|
2444
|
+
const el = els.option(items[i], i);
|
|
2445
|
+
optionEls.push(el);
|
|
2446
|
+
if (el?.id) taken.add(el.id);
|
|
2447
|
+
}
|
|
2448
|
+
for (let i = 0; i < items.length; i++) {
|
|
2449
|
+
const el = optionEls[i];
|
|
2450
|
+
if (!el) continue;
|
|
2451
|
+
if (!optionRestores.has(el)) optionRestores.set(el, snapshotAttributes(el, OPTION_ATTRS));
|
|
2452
|
+
nextIndex.set(el, i);
|
|
2453
|
+
if (!el.id) {
|
|
2454
|
+
el.id = generatedIdFor(el, taken);
|
|
2455
|
+
taken.add(el.id);
|
|
2456
|
+
}
|
|
2457
|
+
el.setAttribute("role", "option");
|
|
2458
|
+
el.setAttribute("aria-selected", sel !== null && isEqual(items[i], sel) ? "true" : "false");
|
|
2459
|
+
const disabled = isDisabled(items[i]);
|
|
2460
|
+
if (disabled) el.setAttribute("aria-disabled", "true");
|
|
2461
|
+
else el.removeAttribute("aria-disabled");
|
|
2462
|
+
if (i === idx && !disabled) activeEl = el;
|
|
2463
|
+
}
|
|
2464
|
+
for (const [el, restore] of optionRestores) {
|
|
2465
|
+
if (nextIndex.has(el)) continue;
|
|
2466
|
+
restore();
|
|
2467
|
+
optionRestores.delete(el);
|
|
2468
|
+
if (lastScrolled === el) lastScrolled = null;
|
|
2469
|
+
}
|
|
2470
|
+
optionIndex = nextIndex;
|
|
2471
|
+
if (openNow && activeEl) {
|
|
2472
|
+
trigger.setAttribute("aria-activedescendant", activeEl.id);
|
|
2473
|
+
if (activeEl !== lastScrolled) {
|
|
2474
|
+
activeEl.scrollIntoView?.({
|
|
2475
|
+
block: "nearest"
|
|
2476
|
+
});
|
|
2477
|
+
lastScrolled = activeEl;
|
|
2478
|
+
}
|
|
2479
|
+
} else {
|
|
2480
|
+
trigger.removeAttribute("aria-activedescendant");
|
|
2481
|
+
if (!openNow) lastScrolled = null;
|
|
2482
|
+
}
|
|
2483
|
+
}, trigger);
|
|
2484
|
+
let typeBuffer = "";
|
|
2485
|
+
let typeTimer = null;
|
|
2486
|
+
const typeahead = (char) => {
|
|
2487
|
+
typeBuffer += char.toLowerCase();
|
|
2488
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
2489
|
+
typeTimer = setTimeout(() => {
|
|
2490
|
+
typeBuffer = "";
|
|
2491
|
+
typeTimer = null;
|
|
2492
|
+
}, 500);
|
|
2493
|
+
const items = getItems();
|
|
2494
|
+
const n = items.length;
|
|
2495
|
+
if (n === 0) return;
|
|
2496
|
+
const start = untracked2(active);
|
|
2497
|
+
const repeated = typeBuffer.length > 1 && [...typeBuffer].every((c) => c === typeBuffer[0]);
|
|
2498
|
+
const needle = repeated ? typeBuffer[0] : typeBuffer;
|
|
2499
|
+
const offset = typeBuffer.length === 1 || repeated ? 1 : 0;
|
|
2500
|
+
for (let k = 0; k < n; k++) {
|
|
2501
|
+
const i = (Math.max(start, 0) + offset + k) % n;
|
|
2502
|
+
if (!isDisabled(items[i]) && toStr(items[i]).toLowerCase().startsWith(needle)) {
|
|
2503
|
+
setActiveIndex(i);
|
|
2504
|
+
return;
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
};
|
|
2508
|
+
const commitActive = () => {
|
|
2509
|
+
const item = untracked2(activeItem);
|
|
2510
|
+
if (item !== null && !isDisabled(item)) select2(item);
|
|
2511
|
+
else close();
|
|
2512
|
+
};
|
|
2513
|
+
const move = (delta) => {
|
|
2514
|
+
const items = getItems();
|
|
2515
|
+
const cur = untracked2(active);
|
|
2516
|
+
const dir = delta > 0 ? 1 : -1;
|
|
2517
|
+
const target = Math.min(items.length - 1, Math.max(0, cur + delta));
|
|
2518
|
+
let next = enabledFrom(items, target, dir);
|
|
2519
|
+
if (next === -1) next = enabledFrom(items, target, dir === 1 ? -1 : 1);
|
|
2520
|
+
if (next !== -1) setActiveIndex(next);
|
|
2521
|
+
};
|
|
2522
|
+
const onKey = (e) => {
|
|
2523
|
+
if (isWidgetKeyEvent(e) || e.ctrlKey || e.metaKey) return;
|
|
2524
|
+
const openNow = untracked2(isOpen);
|
|
2525
|
+
const key = e.key;
|
|
2526
|
+
let handled = true;
|
|
2527
|
+
if (!openNow) {
|
|
2528
|
+
if (key === "ArrowDown" || key === "ArrowUp" || key === "Enter" || key === " ") open();
|
|
2529
|
+
else if (key === "Home") open("first");
|
|
2530
|
+
else if (key === "End") open("last");
|
|
2531
|
+
else if (key.length === 1 && !e.altKey) {
|
|
2532
|
+
open();
|
|
2533
|
+
typeahead(key);
|
|
2534
|
+
} else handled = false;
|
|
2535
|
+
} else if (key === "ArrowDown" && !e.altKey) move(1);
|
|
2536
|
+
else if (key === "ArrowUp" && e.altKey) commitActive();
|
|
2537
|
+
else if (key === "ArrowUp") move(-1);
|
|
2538
|
+
else if (key === "Home") setActive(enabledFrom(getItems(), 0, 1));
|
|
2539
|
+
else if (key === "End") {
|
|
2540
|
+
const items = getItems();
|
|
2541
|
+
setActive(enabledFrom(items, items.length - 1, -1));
|
|
2542
|
+
} else if (key === "PageDown") move(pageSize);
|
|
2543
|
+
else if (key === "PageUp") move(-pageSize);
|
|
2544
|
+
else if (key === "Escape") close();
|
|
2545
|
+
else if (key === " " && typeBuffer !== "") typeahead(key);
|
|
2546
|
+
else if (key === "Enter" || key === " ") commitActive();
|
|
2547
|
+
else if (key === "Tab") {
|
|
2548
|
+
commitActive();
|
|
2549
|
+
handled = false;
|
|
2550
|
+
} else if (key.length === 1 && !e.altKey) typeahead(key);
|
|
2551
|
+
else handled = false;
|
|
2552
|
+
if (handled) {
|
|
2553
|
+
e.preventDefault();
|
|
2554
|
+
claimWidgetKey(e, "selectMenu");
|
|
2555
|
+
}
|
|
2556
|
+
};
|
|
2557
|
+
const onTriggerClick = () => toggle();
|
|
2558
|
+
const onListboxPointerDown = (e) => e.preventDefault();
|
|
2559
|
+
const optionFromEvent = (e) => {
|
|
2560
|
+
let node = e.target;
|
|
2561
|
+
while (node && node !== listbox) {
|
|
2562
|
+
const i = optionIndex.get(node);
|
|
2563
|
+
if (i !== void 0) return i;
|
|
2564
|
+
node = node.parentNode;
|
|
2565
|
+
}
|
|
2566
|
+
return -1;
|
|
2567
|
+
};
|
|
2568
|
+
const onListboxClick = (e) => {
|
|
2569
|
+
const i = optionFromEvent(e);
|
|
2570
|
+
if (i === -1) return;
|
|
2571
|
+
const item = getItems()[i];
|
|
2572
|
+
if (isDisabled(item)) return;
|
|
2573
|
+
select2(item);
|
|
2574
|
+
trigger.focus();
|
|
2575
|
+
};
|
|
2576
|
+
const onListboxPointerMove = (e) => {
|
|
2577
|
+
const i = optionFromEvent(e);
|
|
2578
|
+
if (i !== -1 && i !== untracked2(active)) setActive(i);
|
|
2579
|
+
};
|
|
2580
|
+
const onDocPointerDown = (e) => {
|
|
2581
|
+
if (!untracked2(isOpen)) return;
|
|
2582
|
+
const target = e.target;
|
|
2583
|
+
if (target && (trigger.contains(target) || listbox.contains(target))) return;
|
|
2584
|
+
close();
|
|
2585
|
+
};
|
|
2586
|
+
const onTriggerBlur = (e) => {
|
|
2587
|
+
if (!untracked2(isOpen)) return;
|
|
2588
|
+
const next = e.relatedTarget;
|
|
2589
|
+
if (next && listbox.contains(next)) return;
|
|
2590
|
+
close();
|
|
2591
|
+
};
|
|
2592
|
+
trigger.addEventListener("keydown", onKey);
|
|
2593
|
+
trigger.addEventListener("click", onTriggerClick);
|
|
2594
|
+
trigger.addEventListener("blur", onTriggerBlur);
|
|
2595
|
+
listbox.addEventListener("mousedown", onListboxPointerDown);
|
|
2596
|
+
listbox.addEventListener("click", onListboxClick);
|
|
2597
|
+
listbox.addEventListener("pointermove", onListboxPointerMove);
|
|
2598
|
+
const doc = trigger.ownerDocument;
|
|
2599
|
+
doc.addEventListener("pointerdown", onDocPointerDown, true);
|
|
2600
|
+
let tornDown = false;
|
|
2601
|
+
const teardown = () => {
|
|
2602
|
+
if (tornDown) return;
|
|
2603
|
+
tornDown = true;
|
|
2604
|
+
if (boundMenus.get(trigger) === teardown) boundMenus.delete(trigger);
|
|
2605
|
+
stopBinding();
|
|
2606
|
+
trigger.removeEventListener("keydown", onKey);
|
|
2607
|
+
trigger.removeEventListener("click", onTriggerClick);
|
|
2608
|
+
trigger.removeEventListener("blur", onTriggerBlur);
|
|
2609
|
+
listbox.removeEventListener("mousedown", onListboxPointerDown);
|
|
2610
|
+
listbox.removeEventListener("click", onListboxClick);
|
|
2611
|
+
listbox.removeEventListener("pointermove", onListboxPointerMove);
|
|
2612
|
+
doc.removeEventListener("pointerdown", onDocPointerDown, true);
|
|
2613
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
2614
|
+
for (const restore of optionRestores.values()) restore();
|
|
2615
|
+
optionRestores.clear();
|
|
2616
|
+
optionIndex.clear();
|
|
2617
|
+
restoreTrigger();
|
|
2618
|
+
restoreListbox();
|
|
2619
|
+
listbox.hidden = prevHidden;
|
|
2620
|
+
};
|
|
2621
|
+
boundMenus.set(trigger, teardown);
|
|
2622
|
+
return teardown;
|
|
2288
2623
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2624
|
+
return { value, isOpen, open, close, toggle, active, activeItem, setActive, select: select2, bind };
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
// src/widgets/Tabs.ts
|
|
2628
|
+
var boundTablists = /* @__PURE__ */ new WeakMap();
|
|
2629
|
+
function tabs(options) {
|
|
2630
|
+
const { tabs: tabDefs, defaultTab } = options;
|
|
2631
|
+
const firstEnabled = tabDefs.find((t) => !t.disabled)?.id ?? "";
|
|
2632
|
+
const initialTab = defaultTab !== void 0 && tabDefs.some((t) => t.id === defaultTab && !t.disabled) ? defaultTab : firstEnabled;
|
|
2633
|
+
const [activeTab, setActiveTabState] = signal(initialTab);
|
|
2634
|
+
function setActiveTab(id) {
|
|
2635
|
+
const tab = tabDefs.find((t) => t.id === id);
|
|
2636
|
+
if (tab && !tab.disabled) {
|
|
2637
|
+
setActiveTabState(id);
|
|
2638
|
+
}
|
|
2291
2639
|
}
|
|
2292
|
-
const
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
const
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
});
|
|
2640
|
+
const tabs2 = derived(
|
|
2641
|
+
() => tabDefs.map((t) => ({
|
|
2642
|
+
...t,
|
|
2643
|
+
isActive: t.id === activeTab()
|
|
2644
|
+
}))
|
|
2645
|
+
);
|
|
2646
|
+
function findCurrentIndex() {
|
|
2647
|
+
return tabDefs.findIndex((t) => t.id === activeTab());
|
|
2648
|
+
}
|
|
2649
|
+
function nextTab() {
|
|
2650
|
+
const currentIdx = findCurrentIndex();
|
|
2651
|
+
const len = tabDefs.length;
|
|
2652
|
+
if (len === 0) return;
|
|
2653
|
+
for (let i = 1; i <= len; i++) {
|
|
2654
|
+
const candidate = tabDefs[(currentIdx + i) % len];
|
|
2655
|
+
if (!candidate.disabled) {
|
|
2656
|
+
setActiveTabState(candidate.id);
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2312
2659
|
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2660
|
+
}
|
|
2661
|
+
function prevTab() {
|
|
2662
|
+
const currentIdx = findCurrentIndex();
|
|
2663
|
+
const len = tabDefs.length;
|
|
2664
|
+
if (len === 0) return;
|
|
2665
|
+
for (let i = 1; i <= len; i++) {
|
|
2666
|
+
const candidate = tabDefs[(currentIdx - i + len) % len];
|
|
2667
|
+
if (!candidate.disabled) {
|
|
2668
|
+
setActiveTabState(candidate.id);
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2322
2671
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2672
|
+
}
|
|
2673
|
+
function isActive(id) {
|
|
2674
|
+
return activeTab() === id;
|
|
2675
|
+
}
|
|
2676
|
+
function bind(els) {
|
|
2677
|
+
const existing = boundTablists.get(els.tablist);
|
|
2678
|
+
if (existing) return existing;
|
|
2679
|
+
const restore = [snapshotAttributes(els.tablist, ["role"])];
|
|
2680
|
+
els.tablist.setAttribute("role", "tablist");
|
|
2681
|
+
const idPrefix = createId("sibu-tabs");
|
|
2682
|
+
for (const def of tabDefs) {
|
|
2683
|
+
const tabEl = els.tabs[def.id];
|
|
2684
|
+
if (!tabEl) continue;
|
|
2685
|
+
restore.push(
|
|
2686
|
+
snapshotAttributes(tabEl, ["role", "id", "aria-disabled", "aria-controls", "aria-selected", "tabindex"])
|
|
2687
|
+
);
|
|
2688
|
+
tabEl.setAttribute("role", "tab");
|
|
2689
|
+
if (!tabEl.id) tabEl.id = `${idPrefix}-tab-${idSegment(def.id)}`;
|
|
2690
|
+
if (def.disabled) tabEl.setAttribute("aria-disabled", "true");
|
|
2691
|
+
else tabEl.removeAttribute("aria-disabled");
|
|
2692
|
+
const panelEl = els.panels?.[def.id];
|
|
2693
|
+
if (panelEl) {
|
|
2694
|
+
restore.push(snapshotAttributes(panelEl, ["role", "id", "aria-labelledby", "hidden"]));
|
|
2695
|
+
panelEl.setAttribute("role", "tabpanel");
|
|
2696
|
+
if (!panelEl.id) panelEl.id = `${idPrefix}-panel-${idSegment(def.id)}`;
|
|
2697
|
+
panelEl.setAttribute("aria-labelledby", tabEl.id);
|
|
2698
|
+
tabEl.setAttribute("aria-controls", panelEl.id);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
const fxTeardown = domBinding(() => {
|
|
2702
|
+
const active = activeTab();
|
|
2703
|
+
for (const def of tabDefs) {
|
|
2704
|
+
const tabEl = els.tabs[def.id];
|
|
2705
|
+
if (!tabEl) continue;
|
|
2706
|
+
const isAct = def.id === active;
|
|
2707
|
+
tabEl.setAttribute("aria-selected", isAct ? "true" : "false");
|
|
2708
|
+
tabEl.tabIndex = isAct ? 0 : -1;
|
|
2709
|
+
const panelEl = els.panels?.[def.id];
|
|
2710
|
+
if (panelEl) panelEl.hidden = !isAct;
|
|
2711
|
+
}
|
|
2712
|
+
}, els.tablist);
|
|
2713
|
+
const onKey = (e) => {
|
|
2714
|
+
if (isWidgetKeyEvent(e)) return;
|
|
2715
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
2716
|
+
e.preventDefault();
|
|
2717
|
+
claimWidgetKey(e, "tabs");
|
|
2718
|
+
nextTab();
|
|
2719
|
+
els.tabs[activeTab()]?.focus();
|
|
2720
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
2721
|
+
e.preventDefault();
|
|
2722
|
+
claimWidgetKey(e, "tabs");
|
|
2723
|
+
prevTab();
|
|
2724
|
+
els.tabs[activeTab()]?.focus();
|
|
2725
|
+
} else if (e.key === "Home") {
|
|
2726
|
+
e.preventDefault();
|
|
2727
|
+
claimWidgetKey(e, "tabs");
|
|
2728
|
+
const first = tabDefs.find((t) => !t.disabled);
|
|
2729
|
+
if (first) {
|
|
2730
|
+
setActiveTabState(first.id);
|
|
2731
|
+
els.tabs[first.id]?.focus();
|
|
2732
|
+
}
|
|
2733
|
+
} else if (e.key === "End") {
|
|
2734
|
+
e.preventDefault();
|
|
2735
|
+
claimWidgetKey(e, "tabs");
|
|
2736
|
+
for (let i = tabDefs.length - 1; i >= 0; i--) {
|
|
2737
|
+
if (!tabDefs[i].disabled) {
|
|
2738
|
+
setActiveTabState(tabDefs[i].id);
|
|
2739
|
+
els.tabs[tabDefs[i].id]?.focus();
|
|
2740
|
+
break;
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2335
2743
|
}
|
|
2744
|
+
};
|
|
2745
|
+
els.tablist.addEventListener("keydown", onKey);
|
|
2746
|
+
const clickHandlers = [];
|
|
2747
|
+
for (const def of tabDefs) {
|
|
2748
|
+
const tabEl = els.tabs[def.id];
|
|
2749
|
+
if (!tabEl) continue;
|
|
2750
|
+
const fn = () => setActiveTab(def.id);
|
|
2751
|
+
tabEl.addEventListener("click", fn);
|
|
2752
|
+
clickHandlers.push({ el: tabEl, fn });
|
|
2336
2753
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2754
|
+
let tornDown = false;
|
|
2755
|
+
const teardown = () => {
|
|
2756
|
+
if (tornDown) return;
|
|
2757
|
+
tornDown = true;
|
|
2758
|
+
boundTablists.delete(els.tablist);
|
|
2759
|
+
fxTeardown();
|
|
2760
|
+
els.tablist.removeEventListener("keydown", onKey);
|
|
2761
|
+
for (const { el, fn } of clickHandlers) el.removeEventListener("click", fn);
|
|
2762
|
+
for (const r of restore) r();
|
|
2763
|
+
};
|
|
2764
|
+
boundTablists.set(els.tablist, teardown);
|
|
2765
|
+
return teardown;
|
|
2342
2766
|
}
|
|
2343
2767
|
return {
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
prevYear,
|
|
2352
|
-
daysInMonth,
|
|
2353
|
-
isDateDisabled,
|
|
2354
|
-
/** Reactive check — use inside class bindings for per-day reactivity */
|
|
2355
|
-
isSelected,
|
|
2768
|
+
activeTab,
|
|
2769
|
+
setActiveTab,
|
|
2770
|
+
tabs: tabs2,
|
|
2771
|
+
nextTab,
|
|
2772
|
+
prevTab,
|
|
2773
|
+
/** Reactive check — use inside class/nodes bindings for per-tab reactivity */
|
|
2774
|
+
isActive,
|
|
2356
2775
|
bind
|
|
2357
2776
|
};
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
// src/widgets/Tooltip.ts
|
|
2780
|
+
var boundTriggers = /* @__PURE__ */ new WeakMap();
|
|
2781
|
+
function tooltip(options) {
|
|
2782
|
+
const delay = options?.delay ?? 0;
|
|
2783
|
+
const hideDelay = options?.hideDelay ?? 100;
|
|
2784
|
+
const [isVisible, setIsVisible] = signal(false);
|
|
2785
|
+
const [content, setContent] = signal("");
|
|
2786
|
+
let delayTimer = null;
|
|
2787
|
+
let hideTimer = null;
|
|
2788
|
+
function show() {
|
|
2789
|
+
if (hideTimer !== null) {
|
|
2790
|
+
clearTimeout(hideTimer);
|
|
2791
|
+
hideTimer = null;
|
|
2792
|
+
}
|
|
2793
|
+
if (delay > 0) {
|
|
2794
|
+
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
2795
|
+
delayTimer = setTimeout(() => {
|
|
2796
|
+
setIsVisible(true);
|
|
2797
|
+
delayTimer = null;
|
|
2798
|
+
}, delay);
|
|
2799
|
+
} else {
|
|
2800
|
+
setIsVisible(true);
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
function hide() {
|
|
2804
|
+
if (delayTimer !== null) {
|
|
2805
|
+
clearTimeout(delayTimer);
|
|
2806
|
+
delayTimer = null;
|
|
2807
|
+
}
|
|
2808
|
+
setIsVisible(false);
|
|
2809
|
+
}
|
|
2810
|
+
function scheduleHide() {
|
|
2811
|
+
if (delayTimer !== null) {
|
|
2812
|
+
clearTimeout(delayTimer);
|
|
2813
|
+
delayTimer = null;
|
|
2814
|
+
}
|
|
2815
|
+
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
2816
|
+
hideTimer = setTimeout(() => {
|
|
2817
|
+
hideTimer = null;
|
|
2818
|
+
setIsVisible(false);
|
|
2819
|
+
}, hideDelay);
|
|
2820
|
+
}
|
|
2358
2821
|
function bind(els) {
|
|
2359
|
-
const existing =
|
|
2822
|
+
const existing = boundTriggers.get(els.trigger);
|
|
2360
2823
|
if (existing) return existing;
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
els.
|
|
2365
|
-
|
|
2366
|
-
let pendingFocus = false;
|
|
2367
|
-
const touchedCells = /* @__PURE__ */ new Map();
|
|
2368
|
-
const restoreAttr = (el, name, value) => {
|
|
2369
|
-
if (value === null) el.removeAttribute(name);
|
|
2370
|
-
else el.setAttribute(name, value);
|
|
2371
|
-
};
|
|
2372
|
-
const restoreCell = (cell, snap) => {
|
|
2373
|
-
restoreAttr(cell, "role", snap.role);
|
|
2374
|
-
restoreAttr(cell, "aria-selected", snap.selected);
|
|
2375
|
-
restoreAttr(cell, "aria-disabled", snap.disabled);
|
|
2376
|
-
restoreAttr(cell, "tabindex", snap.tabindex);
|
|
2377
|
-
};
|
|
2824
|
+
const id = createId("sibu-tooltip");
|
|
2825
|
+
els.tooltip.setAttribute("role", "tooltip");
|
|
2826
|
+
els.tooltip.id = id;
|
|
2827
|
+
const prevDescribedBy = els.trigger.getAttribute("aria-describedby");
|
|
2828
|
+
els.trigger.setAttribute("aria-describedby", prevDescribedBy ? `${prevDescribedBy} ${id}` : id);
|
|
2378
2829
|
const fxTeardown = domBinding(() => {
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
if (!cell) continue;
|
|
2388
|
-
displayed.add(cell);
|
|
2389
|
-
if (!touchedCells.has(cell)) {
|
|
2390
|
-
touchedCells.set(cell, {
|
|
2391
|
-
role: cell.getAttribute("role"),
|
|
2392
|
-
selected: cell.getAttribute("aria-selected"),
|
|
2393
|
-
disabled: cell.getAttribute("aria-disabled"),
|
|
2394
|
-
tabindex: cell.getAttribute("tabindex")
|
|
2395
|
-
});
|
|
2396
|
-
}
|
|
2397
|
-
cell.setAttribute("role", "gridcell");
|
|
2398
|
-
cell.setAttribute("aria-selected", sel && isSameCalendarDay(sel, d.date) ? "true" : "false");
|
|
2399
|
-
if (d.isDisabled) cell.setAttribute("aria-disabled", "true");
|
|
2400
|
-
else cell.removeAttribute("aria-disabled");
|
|
2401
|
-
const isView = isSameCalendarDay(view, d.date);
|
|
2402
|
-
cell.tabIndex = isView ? 0 : -1;
|
|
2403
|
-
if (isView) viewCell = cell;
|
|
2404
|
-
}
|
|
2405
|
-
for (const [cell, snap] of touchedCells) {
|
|
2406
|
-
if (!displayed.has(cell)) {
|
|
2407
|
-
restoreCell(cell, snap);
|
|
2408
|
-
touchedCells.delete(cell);
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
if (pendingFocus && viewCell && typeof viewCell.focus === "function") {
|
|
2412
|
-
pendingFocus = false;
|
|
2413
|
-
viewCell.focus();
|
|
2830
|
+
els.tooltip.hidden = !isVisible();
|
|
2831
|
+
}, els.trigger);
|
|
2832
|
+
const onTriggerEnter = () => show();
|
|
2833
|
+
const onTriggerLeave = () => scheduleHide();
|
|
2834
|
+
const onTooltipEnter = () => {
|
|
2835
|
+
if (hideTimer !== null) {
|
|
2836
|
+
clearTimeout(hideTimer);
|
|
2837
|
+
hideTimer = null;
|
|
2414
2838
|
}
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
function shiftDays(delta) {
|
|
2420
|
-
setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth(), prev.getDate() + delta));
|
|
2421
|
-
}
|
|
2839
|
+
};
|
|
2840
|
+
const onTooltipLeave = () => scheduleHide();
|
|
2841
|
+
const onFocus = () => show();
|
|
2842
|
+
const onBlur = () => hide();
|
|
2422
2843
|
const onKey = (e) => {
|
|
2423
|
-
if (e
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
e.preventDefault();
|
|
2429
|
-
shiftDays(-1);
|
|
2430
|
-
break;
|
|
2431
|
-
case "ArrowRight":
|
|
2432
|
-
e.preventDefault();
|
|
2433
|
-
shiftDays(1);
|
|
2434
|
-
break;
|
|
2435
|
-
case "ArrowUp":
|
|
2436
|
-
e.preventDefault();
|
|
2437
|
-
shiftDays(-7);
|
|
2438
|
-
break;
|
|
2439
|
-
case "ArrowDown":
|
|
2440
|
-
e.preventDefault();
|
|
2441
|
-
shiftDays(7);
|
|
2442
|
-
break;
|
|
2443
|
-
case "Home":
|
|
2444
|
-
e.preventDefault();
|
|
2445
|
-
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() - p.getDay()));
|
|
2446
|
-
break;
|
|
2447
|
-
case "End": {
|
|
2448
|
-
e.preventDefault();
|
|
2449
|
-
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() + (6 - p.getDay())));
|
|
2450
|
-
break;
|
|
2451
|
-
}
|
|
2452
|
-
case "PageUp":
|
|
2453
|
-
e.preventDefault();
|
|
2454
|
-
if (e.shiftKey) prevYear();
|
|
2455
|
-
else prevMonth();
|
|
2456
|
-
break;
|
|
2457
|
-
case "PageDown":
|
|
2458
|
-
e.preventDefault();
|
|
2459
|
-
if (e.shiftKey) nextYear();
|
|
2460
|
-
else nextMonth();
|
|
2461
|
-
break;
|
|
2462
|
-
case "Enter":
|
|
2463
|
-
case " ":
|
|
2464
|
-
e.preventDefault();
|
|
2465
|
-
select2(viewDate());
|
|
2466
|
-
break;
|
|
2844
|
+
if (isWidgetKeyEvent(e)) return;
|
|
2845
|
+
if (e.key === "Escape" && isVisible()) {
|
|
2846
|
+
e.stopPropagation();
|
|
2847
|
+
claimWidgetKey(e, "tooltip");
|
|
2848
|
+
hide();
|
|
2467
2849
|
}
|
|
2468
2850
|
};
|
|
2469
|
-
els.
|
|
2851
|
+
els.trigger.addEventListener("pointerenter", onTriggerEnter);
|
|
2852
|
+
els.trigger.addEventListener("pointerleave", onTriggerLeave);
|
|
2853
|
+
els.trigger.addEventListener("focus", onFocus);
|
|
2854
|
+
els.trigger.addEventListener("blur", onBlur);
|
|
2855
|
+
els.trigger.addEventListener("keydown", onKey);
|
|
2856
|
+
els.tooltip.addEventListener("pointerenter", onTooltipEnter);
|
|
2857
|
+
els.tooltip.addEventListener("pointerleave", onTooltipLeave);
|
|
2470
2858
|
let tornDown = false;
|
|
2471
2859
|
const teardown = () => {
|
|
2472
2860
|
if (tornDown) return;
|
|
2473
2861
|
tornDown = true;
|
|
2474
|
-
if (
|
|
2862
|
+
if (boundTriggers.get(els.trigger) === teardown) boundTriggers.delete(els.trigger);
|
|
2475
2863
|
fxTeardown();
|
|
2476
|
-
els.
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2864
|
+
els.trigger.removeEventListener("pointerenter", onTriggerEnter);
|
|
2865
|
+
els.trigger.removeEventListener("pointerleave", onTriggerLeave);
|
|
2866
|
+
els.trigger.removeEventListener("focus", onFocus);
|
|
2867
|
+
els.trigger.removeEventListener("blur", onBlur);
|
|
2868
|
+
els.trigger.removeEventListener("keydown", onKey);
|
|
2869
|
+
els.tooltip.removeEventListener("pointerenter", onTooltipEnter);
|
|
2870
|
+
els.tooltip.removeEventListener("pointerleave", onTooltipLeave);
|
|
2871
|
+
const cur = els.trigger.getAttribute("aria-describedby");
|
|
2872
|
+
if (cur) {
|
|
2873
|
+
const remaining = cur.split(/\s+/).filter((part) => part && part !== id);
|
|
2874
|
+
if (remaining.length > 0) els.trigger.setAttribute("aria-describedby", remaining.join(" "));
|
|
2875
|
+
else els.trigger.removeAttribute("aria-describedby");
|
|
2876
|
+
} else if (prevDescribedBy) {
|
|
2877
|
+
els.trigger.setAttribute("aria-describedby", prevDescribedBy);
|
|
2878
|
+
}
|
|
2879
|
+
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
2880
|
+
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
2485
2881
|
};
|
|
2486
|
-
|
|
2882
|
+
boundTriggers.set(els.trigger, teardown);
|
|
2487
2883
|
return teardown;
|
|
2488
2884
|
}
|
|
2885
|
+
return { isVisible, show, hide, content, setContent, bind };
|
|
2489
2886
|
}
|
|
2490
2887
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2491
2888
|
0 && (module.exports = {
|
|
@@ -2494,8 +2891,11 @@ function datePicker(options) {
|
|
|
2494
2891
|
contentEditable,
|
|
2495
2892
|
datePicker,
|
|
2496
2893
|
fileUpload,
|
|
2894
|
+
isWidgetKeyEvent,
|
|
2497
2895
|
popover,
|
|
2498
2896
|
select,
|
|
2897
|
+
selectMenu,
|
|
2499
2898
|
tabs,
|
|
2500
|
-
tooltip
|
|
2899
|
+
tooltip,
|
|
2900
|
+
widgetKeyOwner
|
|
2501
2901
|
});
|