sibujs 1.5.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs +332 -121
- package/dist/browser.d.cts +5 -0
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +6 -6
- package/dist/build.cjs +1049 -344
- package/dist/build.js +15 -13
- package/dist/cdn.global.js +17 -16
- package/dist/chunk-2RA7SHDA.js +65 -0
- package/dist/chunk-2UPRY23K.js +80 -0
- package/dist/{chunk-BMPL52BF.js → chunk-3DZP6OIT.js} +118 -66
- package/dist/chunk-3JHCYHWN.js +125 -0
- package/dist/{chunk-CZUGLNJS.js → chunk-45YP72ZQ.js} +3 -3
- package/dist/{chunk-JCDUJN2F.js → chunk-AMK2TYNW.js} +490 -153
- package/dist/{chunk-NHUC2QWH.js → chunk-CWBVQML6.js} +1 -1
- package/dist/{chunk-XHK6BDAJ.js → chunk-DRUZZAK4.js} +25 -8
- package/dist/{chunk-RJ46C3CS.js → chunk-GWWURC5M.js} +71 -20
- package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
- package/dist/{chunk-2BYQDGN3.js → chunk-KGYT6UO6.js} +234 -63
- package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
- package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
- package/dist/{chunk-XUEEGU5O.js → chunk-NASX6ST2.js} +16 -4
- package/dist/{chunk-VQDZK23A.js → chunk-O6EFQ3KT.js} +181 -66
- package/dist/{chunk-BGN5ZMP4.js → chunk-OJ3P4ECI.js} +14 -2
- package/dist/chunk-ON5MMR2J.js +1327 -0
- package/dist/{chunk-SFKNRVCU.js → chunk-P2HSJDDN.js} +135 -79
- package/dist/chunk-QO3WC6FS.js +384 -0
- package/dist/{chunk-WZSPOOER.js → chunk-RDTDJCAB.js} +8 -5
- package/dist/{chunk-7GRNSCFT.js → chunk-TH2ILCYW.js} +312 -185
- package/dist/chunk-UCS6AMJ7.js +79 -0
- package/dist/{chunk-VAPYJN4X.js → chunk-V6C4FADE.js} +93 -23
- package/dist/{chunk-OUZZEE4S.js → chunk-WANSMF2L.js} +17 -11
- package/dist/{chunk-23VV7YD3.js → chunk-WIPZPFBQ.js} +25 -30
- package/dist/chunk-WZA53FXU.js +149 -0
- package/dist/{chunk-BGTHZHJ5.js → chunk-ZAQSMOED.js} +188 -44
- package/dist/{customElement-BL3Uo8dL.d.cts → customElement-CPfIrbvg.d.cts} +14 -10
- package/dist/{customElement-BL3Uo8dL.d.ts → customElement-CPfIrbvg.d.ts} +14 -10
- package/dist/data.cjs +536 -151
- package/dist/data.d.cts +20 -2
- package/dist/data.d.ts +20 -2
- package/dist/data.js +11 -9
- package/dist/devtools.cjs +613 -266
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +12 -6
- package/dist/ecosystem.cjs +602 -197
- package/dist/ecosystem.d.cts +9 -7
- package/dist/ecosystem.d.ts +9 -7
- package/dist/ecosystem.js +12 -11
- package/dist/extras.cjs +3500 -1608
- package/dist/extras.d.cts +9 -9
- package/dist/extras.d.ts +9 -9
- package/dist/extras.js +58 -45
- package/dist/index.cjs +1055 -344
- package/dist/index.d.cts +85 -8
- package/dist/index.d.ts +85 -8
- package/dist/index.js +32 -16
- package/dist/{introspect-BumjnBKr.d.cts → introspect-2TOlQ7oa.d.cts} +25 -3
- package/dist/{introspect-CZrlcaYy.d.ts → introspect-DnIpHQQz.d.ts} +25 -3
- package/dist/motion.cjs +122 -63
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +450 -110
- package/dist/patterns.d.cts +11 -12
- package/dist/patterns.d.ts +11 -12
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +373 -149
- package/dist/performance.d.cts +23 -16
- package/dist/performance.d.ts +23 -16
- package/dist/performance.js +13 -8
- package/dist/plugin-D30wlGW5.d.cts +71 -0
- package/dist/plugin-D30wlGW5.d.ts +71 -0
- package/dist/plugins.cjs +729 -301
- package/dist/plugins.d.cts +10 -3
- package/dist/plugins.d.ts +10 -3
- package/dist/plugins.js +106 -38
- package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
- package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
- package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
- package/dist/ssr.cjs +736 -274
- package/dist/ssr.d.cts +26 -6
- package/dist/ssr.d.ts +26 -6
- package/dist/ssr.js +12 -11
- package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.cts} +9 -1
- package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.ts} +9 -1
- package/dist/testing.cjs +303 -76
- package/dist/testing.d.cts +17 -4
- package/dist/testing.d.ts +17 -4
- package/dist/testing.js +100 -44
- package/dist/ui.cjs +589 -178
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +20 -17
- package/dist/widgets.cjs +1103 -146
- package/dist/widgets.d.cts +104 -2
- package/dist/widgets.d.ts +104 -2
- package/dist/widgets.js +9 -7
- package/package.json +8 -2
- package/dist/chunk-32DY64NT.js +0 -282
- package/dist/chunk-3AIRKM3B.js +0 -1263
- package/dist/chunk-3ARAQO7B.js +0 -398
- package/dist/chunk-3CRQALYP.js +0 -877
- package/dist/chunk-4EI4AG32.js +0 -482
- package/dist/chunk-4MYMUBRS.js +0 -21
- package/dist/chunk-5ZYQ6KDD.js +0 -154
- package/dist/chunk-6BMPXPUW.js +0 -26
- package/dist/chunk-6HLLIF3K.js +0 -398
- package/dist/chunk-6LSNVCS2.js +0 -937
- package/dist/chunk-6SA3QQES.js +0 -61
- package/dist/chunk-77L6NL3X.js +0 -1097
- package/dist/chunk-7BF6TK55.js +0 -1097
- package/dist/chunk-7TQKR4PP.js +0 -294
- package/dist/chunk-7V26P53V.js +0 -712
- package/dist/chunk-AZ3ISID5.js +0 -298
- package/dist/chunk-B7SWRFUT.js +0 -332
- package/dist/chunk-BTU3TJDS.js +0 -365
- package/dist/chunk-BW3WT46K.js +0 -937
- package/dist/chunk-C6KFWOFV.js +0 -616
- package/dist/chunk-CHF5OHIA.js +0 -61
- package/dist/chunk-CHJ27IGK.js +0 -26
- package/dist/chunk-CMBFNA7L.js +0 -27
- package/dist/chunk-DAHRH4ON.js +0 -331
- package/dist/chunk-DKOHBI74.js +0 -924
- package/dist/chunk-DTCOOBMX.js +0 -725
- package/dist/chunk-EBGIRKQY.js +0 -616
- package/dist/chunk-EUZND3CB.js +0 -27
- package/dist/chunk-EVCZO745.js +0 -365
- package/dist/chunk-EWFVA3TJ.js +0 -282
- package/dist/chunk-F3FA4F32.js +0 -292
- package/dist/chunk-FGOEVHY3.js +0 -60
- package/dist/chunk-G3BOQPVO.js +0 -365
- package/dist/chunk-GCOK2LC3.js +0 -282
- package/dist/chunk-GJPXRJ45.js +0 -37
- package/dist/chunk-HGMJFBC7.js +0 -654
- package/dist/chunk-JAKHTMQU.js +0 -1000
- package/dist/chunk-JCI5M6U6.js +0 -956
- package/dist/chunk-K4G4ZQNR.js +0 -286
- package/dist/chunk-K5ZUMYVS.js +0 -89
- package/dist/chunk-KQPDEVVS.js +0 -398
- package/dist/chunk-L6JRBDNS.js +0 -60
- package/dist/chunk-LA6KQEDU.js +0 -712
- package/dist/chunk-MB6QFH3I.js +0 -2776
- package/dist/chunk-MDVXJWFN.js +0 -304
- package/dist/chunk-MEZVEBPN.js +0 -2008
- package/dist/chunk-MK4ERFYL.js +0 -2249
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-MQ5GOYPH.js +0 -2249
- package/dist/chunk-MYRV7VDM.js +0 -742
- package/dist/chunk-N6IZB6KJ.js +0 -567
- package/dist/chunk-NEKUBFPT.js +0 -60
- package/dist/chunk-NMRUZALC.js +0 -1097
- package/dist/chunk-NYVAC6P5.js +0 -37
- package/dist/chunk-NZIIMDWI.js +0 -84
- package/dist/chunk-OF7UZIVB.js +0 -725
- package/dist/chunk-P3XWXJZU.js +0 -282
- package/dist/chunk-P6W3STU4.js +0 -2249
- package/dist/chunk-PBHF5WKN.js +0 -616
- package/dist/chunk-PDZQY43A.js +0 -616
- package/dist/chunk-PTQJDMRT.js +0 -146
- package/dist/chunk-PZEGYCF5.js +0 -61
- package/dist/chunk-QBMDLBU2.js +0 -975
- package/dist/chunk-QWZG56ET.js +0 -2744
- package/dist/chunk-RQGQSLQK.js +0 -725
- package/dist/chunk-SDLZDHKP.js +0 -107
- package/dist/chunk-TDGZL5CU.js +0 -365
- package/dist/chunk-TNQWPPE6.js +0 -37
- package/dist/chunk-TSOKIX5Z.js +0 -654
- package/dist/chunk-UHNL42EF.js +0 -2730
- package/dist/chunk-UNXCEF6S.js +0 -21
- package/dist/chunk-V2XTI523.js +0 -347
- package/dist/chunk-VAU366PN.js +0 -2241
- package/dist/chunk-VMVDTCXB.js +0 -712
- package/dist/chunk-VQNQZCWJ.js +0 -61
- package/dist/chunk-VRW3FULF.js +0 -725
- package/dist/chunk-WADYRCO2.js +0 -304
- package/dist/chunk-WILQZRO4.js +0 -282
- package/dist/chunk-WR5D4EGH.js +0 -26
- package/dist/chunk-WUHJISPP.js +0 -298
- package/dist/chunk-XYU6TZOW.js +0 -182
- package/dist/chunk-Y6GP4QGG.js +0 -276
- package/dist/chunk-YECR7UIA.js +0 -347
- package/dist/chunk-YUTWTI4B.js +0 -654
- package/dist/chunk-Z65KYU7I.js +0 -26
- package/dist/chunk-Z6POF5YC.js +0 -975
- package/dist/chunk-ZBJP6WFL.js +0 -482
- package/dist/chunk-ZD6OAMTH.js +0 -277
- package/dist/chunk-ZWKZCBO6.js +0 -317
- package/dist/contracts-DDrwxvJ-.d.cts +0 -245
- package/dist/contracts-DDrwxvJ-.d.ts +0 -245
- package/dist/contracts-DOrhwbke.d.cts +0 -245
- package/dist/contracts-DOrhwbke.d.ts +0 -245
- package/dist/contracts-xo5ckdRP.d.cts +0 -240
- package/dist/contracts-xo5ckdRP.d.ts +0 -240
- package/dist/customElement-BKQfbSZQ.d.cts +0 -262
- package/dist/customElement-BKQfbSZQ.d.ts +0 -262
- package/dist/customElement-D2DJp_xn.d.cts +0 -313
- package/dist/customElement-D2DJp_xn.d.ts +0 -313
- package/dist/customElement-yz8uyk-0.d.cts +0 -308
- package/dist/customElement-yz8uyk-0.d.ts +0 -308
- package/dist/introspect-Cb0zgpi2.d.cts +0 -477
- package/dist/introspect-Y2xNXGSf.d.ts +0 -477
- package/dist/plugin-Bek4RhJY.d.cts +0 -43
- package/dist/plugin-Bek4RhJY.d.ts +0 -43
- package/dist/ssr-3RXHP5ES.js +0 -38
- package/dist/ssr-6GIMY5MX.js +0 -38
- package/dist/ssr-BA6sxxUd.d.cts +0 -135
- package/dist/ssr-BA6sxxUd.d.ts +0 -135
- package/dist/ssr-WKUPVSSK.js +0 -36
- package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
- package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
package/dist/widgets.cjs
CHANGED
|
@@ -39,26 +39,39 @@ function isDev() {
|
|
|
39
39
|
var _isDev = isDev();
|
|
40
40
|
function devAssert(condition, message) {
|
|
41
41
|
if (_isDev && !condition) {
|
|
42
|
-
throw new Error(`[
|
|
42
|
+
throw new Error(`[SibuJS] ${message}`);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
function devWarn(message) {
|
|
46
46
|
if (_isDev) {
|
|
47
|
-
console.warn(`[
|
|
47
|
+
console.warn(`[SibuJS] ${message}`);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// src/reactivity/track.ts
|
|
52
52
|
var _isDev2 = isDev();
|
|
53
|
-
var
|
|
54
|
-
var
|
|
53
|
+
var STACK_INITIAL = 32;
|
|
54
|
+
var STACK_SHRINK_THRESHOLD = 128;
|
|
55
|
+
var subscriberStack = new Array(STACK_INITIAL);
|
|
56
|
+
var stackCapacity = STACK_INITIAL;
|
|
55
57
|
var stackTop = -1;
|
|
56
58
|
var currentSubscriber = null;
|
|
57
|
-
var signalSubscribers = /* @__PURE__ */ new WeakMap();
|
|
58
59
|
var SUBS = "__s";
|
|
60
|
+
function syncFastPath(signal2, subs) {
|
|
61
|
+
const size = subs.size;
|
|
62
|
+
if (size === 0) {
|
|
63
|
+
signal2.__f = void 0;
|
|
64
|
+
delete signal2[SUBS];
|
|
65
|
+
} else if (size === 1) {
|
|
66
|
+
signal2.__f = subs.values().next().value;
|
|
67
|
+
} else {
|
|
68
|
+
signal2.__f = void 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
59
71
|
var notifyDepth = 0;
|
|
60
72
|
var pendingQueue = [];
|
|
61
73
|
var pendingSet = /* @__PURE__ */ new Set();
|
|
74
|
+
var propagateStack = [];
|
|
62
75
|
function safeInvoke(sub) {
|
|
63
76
|
try {
|
|
64
77
|
sub();
|
|
@@ -67,6 +80,47 @@ function safeInvoke(sub) {
|
|
|
67
80
|
}
|
|
68
81
|
}
|
|
69
82
|
var trackingSuspended = false;
|
|
83
|
+
var subscriberEpochCounter = 0;
|
|
84
|
+
function retrack(effectFn, subscriber) {
|
|
85
|
+
const prev = currentSubscriber;
|
|
86
|
+
currentSubscriber = subscriber;
|
|
87
|
+
const sub = subscriber;
|
|
88
|
+
const epoch = ++subscriberEpochCounter;
|
|
89
|
+
sub._epoch = epoch;
|
|
90
|
+
try {
|
|
91
|
+
effectFn();
|
|
92
|
+
} finally {
|
|
93
|
+
currentSubscriber = prev;
|
|
94
|
+
pruneStaleDeps(sub, epoch);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function pruneStaleDeps(sub, currentEpoch) {
|
|
98
|
+
if (sub._dep !== void 0) {
|
|
99
|
+
if (sub._depEpoch !== currentEpoch) {
|
|
100
|
+
const sig = sub._dep;
|
|
101
|
+
const subs = sig[SUBS];
|
|
102
|
+
if (subs?.delete(sub)) syncFastPath(sig, subs);
|
|
103
|
+
sub._dep = void 0;
|
|
104
|
+
sub._depEpoch = void 0;
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const deps = sub._deps;
|
|
109
|
+
if (!deps || deps.size === 0) return;
|
|
110
|
+
let stales;
|
|
111
|
+
for (const [signal2, epoch] of deps) {
|
|
112
|
+
if (epoch !== currentEpoch) {
|
|
113
|
+
(stales ?? (stales = [])).push(signal2);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!stales) return;
|
|
117
|
+
for (const signal2 of stales) {
|
|
118
|
+
deps.delete(signal2);
|
|
119
|
+
const sig = signal2;
|
|
120
|
+
const subs = sig[SUBS];
|
|
121
|
+
if (subs?.delete(sub)) syncFastPath(sig, subs);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
70
124
|
function track(effectFn, subscriber) {
|
|
71
125
|
if (!subscriber) subscriber = effectFn;
|
|
72
126
|
cleanup(subscriber);
|
|
@@ -82,37 +136,49 @@ function track(effectFn, subscriber) {
|
|
|
82
136
|
} finally {
|
|
83
137
|
stackTop--;
|
|
84
138
|
currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
|
|
139
|
+
if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
|
|
140
|
+
stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
|
|
141
|
+
subscriberStack.length = stackCapacity;
|
|
142
|
+
}
|
|
85
143
|
}
|
|
86
144
|
return () => cleanup(subscriber);
|
|
87
145
|
}
|
|
88
146
|
function recordDependency(signal2) {
|
|
89
147
|
if (!currentSubscriber) return;
|
|
90
148
|
const sub = currentSubscriber;
|
|
91
|
-
|
|
149
|
+
const epoch = sub._epoch;
|
|
150
|
+
if (sub._dep === signal2) {
|
|
151
|
+
sub._depEpoch = epoch;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
92
154
|
const deps = sub._deps;
|
|
93
155
|
if (deps) {
|
|
94
|
-
|
|
95
|
-
deps.add(signal2);
|
|
156
|
+
deps.set(signal2, epoch);
|
|
96
157
|
} else if (sub._dep !== void 0) {
|
|
97
|
-
const
|
|
98
|
-
set
|
|
99
|
-
set
|
|
100
|
-
sub._deps =
|
|
158
|
+
const map = /* @__PURE__ */ new Map();
|
|
159
|
+
map.set(sub._dep, sub._depEpoch);
|
|
160
|
+
map.set(signal2, epoch);
|
|
161
|
+
sub._deps = map;
|
|
101
162
|
sub._dep = void 0;
|
|
163
|
+
sub._depEpoch = void 0;
|
|
102
164
|
} else {
|
|
103
165
|
sub._dep = signal2;
|
|
166
|
+
sub._depEpoch = epoch;
|
|
104
167
|
}
|
|
105
|
-
|
|
168
|
+
const sig = signal2;
|
|
169
|
+
let subs = sig[SUBS];
|
|
106
170
|
if (!subs) {
|
|
107
171
|
subs = /* @__PURE__ */ new Set();
|
|
108
|
-
|
|
109
|
-
signal2[SUBS] = subs;
|
|
172
|
+
sig[SUBS] = subs;
|
|
110
173
|
}
|
|
174
|
+
const prevSize = subs.size;
|
|
111
175
|
subs.add(currentSubscriber);
|
|
112
|
-
if (subs.size
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
176
|
+
if (subs.size !== prevSize) {
|
|
177
|
+
if (subs.size === 1) {
|
|
178
|
+
sig.__f = currentSubscriber;
|
|
179
|
+
} else if (sig.__f !== void 0) {
|
|
180
|
+
sig.__f = void 0;
|
|
181
|
+
}
|
|
116
182
|
}
|
|
117
183
|
}
|
|
118
184
|
function queueSignalNotification(signal2) {
|
|
@@ -127,66 +193,102 @@ function queueSignalNotification(signal2) {
|
|
|
127
193
|
}
|
|
128
194
|
}
|
|
129
195
|
}
|
|
130
|
-
var
|
|
196
|
+
var maxSubscriberRepeats = 50;
|
|
197
|
+
var maxDrainIterations = 1e6;
|
|
198
|
+
var drainEpoch = 0;
|
|
199
|
+
function tickRepeat(sub) {
|
|
200
|
+
const s = sub;
|
|
201
|
+
if (s._runEpoch !== drainEpoch) {
|
|
202
|
+
s._runEpoch = drainEpoch;
|
|
203
|
+
s._runs = 1;
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return ++s._runs > maxSubscriberRepeats;
|
|
207
|
+
}
|
|
208
|
+
function cycleError(sub) {
|
|
209
|
+
if (typeof console !== "undefined") {
|
|
210
|
+
const name = sub.__name ?? "<unnamed>";
|
|
211
|
+
console.error(
|
|
212
|
+
`[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function absoluteDrainError() {
|
|
217
|
+
if (typeof console !== "undefined") {
|
|
218
|
+
console.error(
|
|
219
|
+
`[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function drainQueue() {
|
|
224
|
+
let i = 0;
|
|
225
|
+
while (i < pendingQueue.length) {
|
|
226
|
+
if (i >= maxDrainIterations) {
|
|
227
|
+
absoluteDrainError();
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
const sub = pendingQueue[i++];
|
|
231
|
+
if (tickRepeat(sub)) {
|
|
232
|
+
cycleError(sub);
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
pendingSet.delete(sub);
|
|
236
|
+
safeInvoke(sub);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
131
239
|
function drainNotificationQueue() {
|
|
132
240
|
if (notifyDepth > 0) return;
|
|
133
241
|
notifyDepth++;
|
|
242
|
+
drainEpoch++;
|
|
134
243
|
try {
|
|
135
|
-
|
|
136
|
-
while (i < pendingQueue.length) {
|
|
137
|
-
if (i >= MAX_DRAIN_ITERATIONS) {
|
|
138
|
-
if (typeof console !== "undefined") {
|
|
139
|
-
console.error(
|
|
140
|
-
`[SibuJS] Notification queue exceeded ${MAX_DRAIN_ITERATIONS} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
safeInvoke(pendingQueue[i]);
|
|
146
|
-
i++;
|
|
147
|
-
}
|
|
244
|
+
drainQueue();
|
|
148
245
|
} finally {
|
|
149
|
-
pendingQueue.length = 0;
|
|
150
|
-
pendingSet.clear();
|
|
151
246
|
notifyDepth--;
|
|
247
|
+
if (notifyDepth === 0) {
|
|
248
|
+
pendingQueue.length = 0;
|
|
249
|
+
pendingSet.clear();
|
|
250
|
+
}
|
|
152
251
|
}
|
|
153
252
|
}
|
|
154
253
|
function propagateDirty(sub) {
|
|
155
254
|
sub();
|
|
156
|
-
|
|
157
|
-
|
|
255
|
+
const rootSig = sub._sig;
|
|
256
|
+
if (!rootSig) return;
|
|
257
|
+
const stack = propagateStack;
|
|
258
|
+
const baseLen = stack.length;
|
|
259
|
+
stack.push(rootSig);
|
|
260
|
+
while (stack.length > baseLen) {
|
|
261
|
+
const sig = stack.pop();
|
|
158
262
|
const first = sig.__f;
|
|
159
263
|
if (first) {
|
|
160
264
|
if (first._c) {
|
|
161
265
|
const nSig = first._sig;
|
|
162
|
-
nSig._d
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (!pendingSet.has(first)) {
|
|
266
|
+
if (!nSig._d) {
|
|
267
|
+
nSig._d = true;
|
|
268
|
+
stack.push(nSig);
|
|
269
|
+
}
|
|
270
|
+
} else if (!pendingSet.has(first)) {
|
|
167
271
|
pendingSet.add(first);
|
|
168
272
|
pendingQueue.push(first);
|
|
169
273
|
}
|
|
170
|
-
|
|
274
|
+
continue;
|
|
171
275
|
}
|
|
172
276
|
const subs = sig[SUBS];
|
|
173
|
-
if (!subs)
|
|
174
|
-
let nextSig;
|
|
277
|
+
if (!subs) continue;
|
|
175
278
|
for (const s of subs) {
|
|
176
279
|
if (s._c) {
|
|
177
|
-
s();
|
|
178
280
|
const nSig = s._sig;
|
|
179
|
-
if (nSig && !
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
281
|
+
if (nSig && !nSig._d) {
|
|
282
|
+
nSig._d = true;
|
|
283
|
+
stack.push(nSig);
|
|
284
|
+
} else if (!nSig) {
|
|
285
|
+
s();
|
|
183
286
|
}
|
|
184
287
|
} else if (!pendingSet.has(s)) {
|
|
185
288
|
pendingSet.add(s);
|
|
186
289
|
pendingQueue.push(s);
|
|
187
290
|
}
|
|
188
291
|
}
|
|
189
|
-
sig = nextSig;
|
|
190
292
|
}
|
|
191
293
|
}
|
|
192
294
|
function notifySubscribers(signal2) {
|
|
@@ -202,21 +304,22 @@ function notifySubscribers(signal2) {
|
|
|
202
304
|
return;
|
|
203
305
|
}
|
|
204
306
|
notifyDepth++;
|
|
307
|
+
drainEpoch++;
|
|
205
308
|
try {
|
|
206
309
|
if (first._c) {
|
|
207
310
|
propagateDirty(first);
|
|
311
|
+
} else if (tickRepeat(first)) {
|
|
312
|
+
cycleError(first);
|
|
208
313
|
} else {
|
|
209
314
|
safeInvoke(first);
|
|
210
315
|
}
|
|
211
|
-
|
|
212
|
-
while (i < pendingQueue.length) {
|
|
213
|
-
safeInvoke(pendingQueue[i]);
|
|
214
|
-
i++;
|
|
215
|
-
}
|
|
316
|
+
drainQueue();
|
|
216
317
|
} finally {
|
|
217
|
-
pendingQueue.length = 0;
|
|
218
|
-
pendingSet.clear();
|
|
219
318
|
notifyDepth--;
|
|
319
|
+
if (notifyDepth === 0) {
|
|
320
|
+
pendingQueue.length = 0;
|
|
321
|
+
pendingSet.clear();
|
|
322
|
+
}
|
|
220
323
|
}
|
|
221
324
|
return;
|
|
222
325
|
}
|
|
@@ -234,57 +337,45 @@ function notifySubscribers(signal2) {
|
|
|
234
337
|
return;
|
|
235
338
|
}
|
|
236
339
|
notifyDepth++;
|
|
340
|
+
drainEpoch++;
|
|
237
341
|
try {
|
|
238
|
-
let directCount = 0;
|
|
239
342
|
for (const sub of subs) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
for (let i2 = 0; i2 < directCount; i2++) {
|
|
248
|
-
if (!pendingQueue[i2]._c) {
|
|
249
|
-
if (!pendingSet.has(pendingQueue[i2])) {
|
|
250
|
-
safeInvoke(pendingQueue[i2]);
|
|
251
|
-
}
|
|
343
|
+
if (sub._c) {
|
|
344
|
+
propagateDirty(sub);
|
|
345
|
+
} else if (!pendingSet.has(sub)) {
|
|
346
|
+
pendingSet.add(sub);
|
|
347
|
+
pendingQueue.push(sub);
|
|
252
348
|
}
|
|
253
349
|
}
|
|
254
|
-
|
|
255
|
-
while (i < pendingQueue.length) {
|
|
256
|
-
safeInvoke(pendingQueue[i]);
|
|
257
|
-
i++;
|
|
258
|
-
}
|
|
350
|
+
drainQueue();
|
|
259
351
|
} finally {
|
|
260
|
-
pendingQueue.length = 0;
|
|
261
|
-
pendingSet.clear();
|
|
262
352
|
notifyDepth--;
|
|
353
|
+
if (notifyDepth === 0) {
|
|
354
|
+
pendingQueue.length = 0;
|
|
355
|
+
pendingSet.clear();
|
|
356
|
+
}
|
|
263
357
|
}
|
|
264
358
|
}
|
|
265
359
|
function cleanup(subscriber) {
|
|
266
360
|
const sub = subscriber;
|
|
267
361
|
const singleDep = sub._dep;
|
|
268
362
|
if (singleDep !== void 0) {
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
singleDep.__f = void 0;
|
|
274
|
-
}
|
|
363
|
+
const sig = singleDep;
|
|
364
|
+
const subs = sig[SUBS];
|
|
365
|
+
if (subs?.delete(subscriber)) {
|
|
366
|
+
syncFastPath(sig, subs);
|
|
275
367
|
}
|
|
276
368
|
sub._dep = void 0;
|
|
369
|
+
sub._depEpoch = void 0;
|
|
277
370
|
return;
|
|
278
371
|
}
|
|
279
372
|
const deps = sub._deps;
|
|
280
373
|
if (!deps || deps.size === 0) return;
|
|
281
|
-
for (const signal2 of deps) {
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
signal2.__f = void 0;
|
|
287
|
-
}
|
|
374
|
+
for (const signal2 of deps.keys()) {
|
|
375
|
+
const sig = signal2;
|
|
376
|
+
const subs = sig[SUBS];
|
|
377
|
+
if (subs?.delete(subscriber)) {
|
|
378
|
+
syncFastPath(sig, subs);
|
|
288
379
|
}
|
|
289
380
|
}
|
|
290
381
|
deps.clear();
|
|
@@ -294,6 +385,7 @@ function cleanup(subscriber) {
|
|
|
294
385
|
function derived(getter, options) {
|
|
295
386
|
devAssert(typeof getter === "function", "derived: argument must be a getter function.");
|
|
296
387
|
const debugName = options?.name;
|
|
388
|
+
const equals = options?.equals;
|
|
297
389
|
const cs = {};
|
|
298
390
|
cs._d = false;
|
|
299
391
|
cs._g = getter;
|
|
@@ -304,8 +396,14 @@ function derived(getter, options) {
|
|
|
304
396
|
markDirty._c = 1;
|
|
305
397
|
markDirty._sig = cs;
|
|
306
398
|
track(() => {
|
|
307
|
-
|
|
308
|
-
|
|
399
|
+
let threw = true;
|
|
400
|
+
try {
|
|
401
|
+
cs._v = getter();
|
|
402
|
+
cs._d = false;
|
|
403
|
+
threw = false;
|
|
404
|
+
} finally {
|
|
405
|
+
if (threw) cs._d = true;
|
|
406
|
+
}
|
|
309
407
|
}, markDirty);
|
|
310
408
|
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
311
409
|
let evaluating = false;
|
|
@@ -318,11 +416,16 @@ function derived(getter, options) {
|
|
|
318
416
|
if (trackingSuspended) {
|
|
319
417
|
if (cs._d) {
|
|
320
418
|
evaluating = true;
|
|
419
|
+
let threw = true;
|
|
321
420
|
try {
|
|
322
|
-
|
|
323
|
-
|
|
421
|
+
retrack(() => {
|
|
422
|
+
cs._v = getter();
|
|
423
|
+
cs._d = false;
|
|
424
|
+
threw = false;
|
|
425
|
+
}, markDirty);
|
|
324
426
|
} finally {
|
|
325
427
|
evaluating = false;
|
|
428
|
+
if (threw) cs._d = true;
|
|
326
429
|
}
|
|
327
430
|
}
|
|
328
431
|
return cs._v;
|
|
@@ -331,13 +434,17 @@ function derived(getter, options) {
|
|
|
331
434
|
if (cs._d) {
|
|
332
435
|
const oldValue = cs._v;
|
|
333
436
|
evaluating = true;
|
|
437
|
+
let threw = true;
|
|
334
438
|
try {
|
|
335
|
-
|
|
439
|
+
retrack(() => {
|
|
440
|
+
const next = getter();
|
|
441
|
+
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
336
442
|
cs._d = false;
|
|
337
|
-
|
|
443
|
+
threw = false;
|
|
338
444
|
}, markDirty);
|
|
339
445
|
} finally {
|
|
340
446
|
evaluating = false;
|
|
447
|
+
if (threw) cs._d = true;
|
|
341
448
|
}
|
|
342
449
|
if (hook && oldValue !== cs._v) {
|
|
343
450
|
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
@@ -354,6 +461,149 @@ function derived(getter, options) {
|
|
|
354
461
|
return computedGetter;
|
|
355
462
|
}
|
|
356
463
|
|
|
464
|
+
// src/core/ssr-context.ts
|
|
465
|
+
var als = null;
|
|
466
|
+
try {
|
|
467
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
468
|
+
const req = Function("return typeof require==='function'?require:null")();
|
|
469
|
+
if (req) {
|
|
470
|
+
const mod = req("node:async_hooks");
|
|
471
|
+
als = new mod.AsyncLocalStorage();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
als = null;
|
|
476
|
+
}
|
|
477
|
+
var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
|
|
478
|
+
function getSSRStore() {
|
|
479
|
+
if (als) {
|
|
480
|
+
const s = als.getStore();
|
|
481
|
+
if (s) return s;
|
|
482
|
+
}
|
|
483
|
+
return fallbackStore;
|
|
484
|
+
}
|
|
485
|
+
function isSSR() {
|
|
486
|
+
return getSSRStore().ssr;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/core/signals/effect.ts
|
|
490
|
+
var _g = globalThis;
|
|
491
|
+
function effect(effectFn, options) {
|
|
492
|
+
devAssert(typeof effectFn === "function", "effect: argument must be a function.");
|
|
493
|
+
if (isSSR()) return () => {
|
|
494
|
+
};
|
|
495
|
+
const onError = options?.onError;
|
|
496
|
+
let userCleanups = [];
|
|
497
|
+
const onCleanup = (fn) => {
|
|
498
|
+
userCleanups.push(fn);
|
|
499
|
+
};
|
|
500
|
+
const runUserCleanups = () => {
|
|
501
|
+
if (userCleanups.length === 0) return;
|
|
502
|
+
const list = userCleanups;
|
|
503
|
+
userCleanups = [];
|
|
504
|
+
for (let i = list.length - 1; i >= 0; i--) {
|
|
505
|
+
try {
|
|
506
|
+
list[i]();
|
|
507
|
+
} catch (err) {
|
|
508
|
+
if (typeof console !== "undefined") {
|
|
509
|
+
console.warn("[SibuJS effect] onCleanup threw:", err);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
const invokeBody = () => effectFn(onCleanup);
|
|
515
|
+
const wrappedFn = onError ? () => {
|
|
516
|
+
try {
|
|
517
|
+
invokeBody();
|
|
518
|
+
} catch (err) {
|
|
519
|
+
onError(err);
|
|
520
|
+
}
|
|
521
|
+
} : invokeBody;
|
|
522
|
+
let cleanupHandle = () => {
|
|
523
|
+
};
|
|
524
|
+
let running = false;
|
|
525
|
+
let rerunPending = false;
|
|
526
|
+
const MAX_RERUNS = 100;
|
|
527
|
+
const subscriber = () => {
|
|
528
|
+
if (running) {
|
|
529
|
+
rerunPending = true;
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
running = true;
|
|
533
|
+
try {
|
|
534
|
+
let reruns = 0;
|
|
535
|
+
do {
|
|
536
|
+
rerunPending = false;
|
|
537
|
+
runUserCleanups();
|
|
538
|
+
cleanupHandle();
|
|
539
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
540
|
+
if (++reruns > MAX_RERUNS) {
|
|
541
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
542
|
+
console.error(
|
|
543
|
+
`[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
rerunPending = false;
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
} while (rerunPending);
|
|
550
|
+
} finally {
|
|
551
|
+
running = false;
|
|
552
|
+
rerunPending = false;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
running = true;
|
|
556
|
+
try {
|
|
557
|
+
let reruns = 0;
|
|
558
|
+
do {
|
|
559
|
+
rerunPending = false;
|
|
560
|
+
runUserCleanups();
|
|
561
|
+
cleanupHandle();
|
|
562
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
563
|
+
if (++reruns > MAX_RERUNS) {
|
|
564
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
565
|
+
console.error(
|
|
566
|
+
`[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
rerunPending = false;
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
} while (rerunPending);
|
|
573
|
+
} finally {
|
|
574
|
+
running = false;
|
|
575
|
+
rerunPending = false;
|
|
576
|
+
}
|
|
577
|
+
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
578
|
+
if (hook) hook.emit("effect:create", { effectFn });
|
|
579
|
+
let disposed = false;
|
|
580
|
+
return () => {
|
|
581
|
+
if (disposed) return;
|
|
582
|
+
disposed = true;
|
|
583
|
+
const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
584
|
+
if (h) {
|
|
585
|
+
try {
|
|
586
|
+
h.emit("effect:destroy", { effectFn });
|
|
587
|
+
} catch {
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
try {
|
|
591
|
+
runUserCleanups();
|
|
592
|
+
} catch (err) {
|
|
593
|
+
if (typeof console !== "undefined") {
|
|
594
|
+
console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
try {
|
|
598
|
+
cleanupHandle();
|
|
599
|
+
} catch (err) {
|
|
600
|
+
if (typeof console !== "undefined") {
|
|
601
|
+
console.warn("[SibuJS effect] dispose threw:", err);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
357
607
|
// src/reactivity/batch.ts
|
|
358
608
|
var batchDepth = 0;
|
|
359
609
|
var pendingSignals = /* @__PURE__ */ new Set();
|
|
@@ -374,15 +624,18 @@ function enqueueBatchedSignal(signal2) {
|
|
|
374
624
|
return true;
|
|
375
625
|
}
|
|
376
626
|
function flushBatch() {
|
|
377
|
-
|
|
378
|
-
|
|
627
|
+
try {
|
|
628
|
+
for (const signal2 of pendingSignals) {
|
|
629
|
+
queueSignalNotification(signal2);
|
|
630
|
+
}
|
|
631
|
+
} finally {
|
|
632
|
+
pendingSignals.clear();
|
|
379
633
|
}
|
|
380
|
-
pendingSignals.clear();
|
|
381
634
|
drainNotificationQueue();
|
|
382
635
|
}
|
|
383
636
|
|
|
384
637
|
// src/core/signals/signal.ts
|
|
385
|
-
var
|
|
638
|
+
var _g2 = globalThis;
|
|
386
639
|
var _isDev3 = isDev();
|
|
387
640
|
function signal(initial, options) {
|
|
388
641
|
const state = { value: initial };
|
|
@@ -403,7 +656,7 @@ function signal(initial, options) {
|
|
|
403
656
|
if (_isDev3) {
|
|
404
657
|
const oldValue = state.value;
|
|
405
658
|
state.value = newValue;
|
|
406
|
-
const hook =
|
|
659
|
+
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
407
660
|
if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
|
|
408
661
|
} else {
|
|
409
662
|
state.value = newValue;
|
|
@@ -413,18 +666,12 @@ function signal(initial, options) {
|
|
|
413
666
|
}
|
|
414
667
|
}
|
|
415
668
|
if (_isDev3) {
|
|
416
|
-
const hook =
|
|
669
|
+
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
417
670
|
if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
|
|
418
671
|
}
|
|
419
672
|
return [get, set];
|
|
420
673
|
}
|
|
421
674
|
|
|
422
|
-
// src/core/ssr-context.ts
|
|
423
|
-
var ssrMode = false;
|
|
424
|
-
function isSSR() {
|
|
425
|
-
return ssrMode;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
675
|
// src/core/signals/watch.ts
|
|
429
676
|
function watch(getter, callback) {
|
|
430
677
|
devAssert(typeof getter === "function", "watch: first argument must be a getter function.");
|
|
@@ -450,6 +697,8 @@ function watch(getter, callback) {
|
|
|
450
697
|
}
|
|
451
698
|
|
|
452
699
|
// src/widgets/Combobox.ts
|
|
700
|
+
var comboboxIdCounter = 0;
|
|
701
|
+
var boundComboboxes = /* @__PURE__ */ new WeakMap();
|
|
453
702
|
function combobox(options) {
|
|
454
703
|
const { items, filterFn, itemToString } = options;
|
|
455
704
|
const defaultFilterFn = (item, q) => {
|
|
@@ -506,6 +755,92 @@ function combobox(options) {
|
|
|
506
755
|
function close() {
|
|
507
756
|
setIsOpen(false);
|
|
508
757
|
}
|
|
758
|
+
function bind(els) {
|
|
759
|
+
const existing = boundComboboxes.get(els.input);
|
|
760
|
+
if (existing) return existing;
|
|
761
|
+
const listboxId = `sibu-combobox-listbox-${++comboboxIdCounter}`;
|
|
762
|
+
els.listbox.id = listboxId;
|
|
763
|
+
els.listbox.setAttribute("role", "listbox");
|
|
764
|
+
els.input.setAttribute("role", "combobox");
|
|
765
|
+
els.input.setAttribute("aria-autocomplete", "list");
|
|
766
|
+
els.input.setAttribute("aria-controls", listboxId);
|
|
767
|
+
const fxTeardown = effect(() => {
|
|
768
|
+
const open2 = isOpen();
|
|
769
|
+
els.input.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
770
|
+
els.listbox.hidden = !open2;
|
|
771
|
+
const idx = highlightedIndex();
|
|
772
|
+
const filtered = filteredItems();
|
|
773
|
+
let activeId = "";
|
|
774
|
+
for (let i = 0; i < filtered.length; i++) {
|
|
775
|
+
const optEl = els.option(filtered[i], i);
|
|
776
|
+
if (!optEl) continue;
|
|
777
|
+
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
778
|
+
optEl.setAttribute("role", "option");
|
|
779
|
+
const isHighlighted = i === idx;
|
|
780
|
+
optEl.setAttribute("aria-selected", isHighlighted ? "true" : "false");
|
|
781
|
+
if (isHighlighted) activeId = optEl.id;
|
|
782
|
+
}
|
|
783
|
+
if (activeId) els.input.setAttribute("aria-activedescendant", activeId);
|
|
784
|
+
else els.input.removeAttribute("aria-activedescendant");
|
|
785
|
+
});
|
|
786
|
+
const onInput = () => {
|
|
787
|
+
setQuery(els.input.value);
|
|
788
|
+
open();
|
|
789
|
+
};
|
|
790
|
+
const onKey = (e) => {
|
|
791
|
+
if (e.key === "ArrowDown") {
|
|
792
|
+
e.preventDefault();
|
|
793
|
+
if (!isOpen()) open();
|
|
794
|
+
highlightNext();
|
|
795
|
+
} else if (e.key === "ArrowUp") {
|
|
796
|
+
e.preventDefault();
|
|
797
|
+
if (!isOpen()) open();
|
|
798
|
+
highlightPrev();
|
|
799
|
+
} else if (e.key === "Enter") {
|
|
800
|
+
if (highlightedIndex() >= 0) {
|
|
801
|
+
e.preventDefault();
|
|
802
|
+
selectHighlighted();
|
|
803
|
+
}
|
|
804
|
+
} else if (e.key === "Escape") {
|
|
805
|
+
e.preventDefault();
|
|
806
|
+
close();
|
|
807
|
+
} else if (e.key === "Home") {
|
|
808
|
+
e.preventDefault();
|
|
809
|
+
if (filteredItems().length > 0) setHighlightedIndex(0);
|
|
810
|
+
} else if (e.key === "End") {
|
|
811
|
+
e.preventDefault();
|
|
812
|
+
const len = filteredItems().length;
|
|
813
|
+
if (len > 0) setHighlightedIndex(len - 1);
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
let blurTimer = null;
|
|
817
|
+
const onFocus = () => open();
|
|
818
|
+
const onBlur = () => {
|
|
819
|
+
if (blurTimer !== null) clearTimeout(blurTimer);
|
|
820
|
+
blurTimer = setTimeout(() => {
|
|
821
|
+
blurTimer = null;
|
|
822
|
+
if (document.activeElement !== els.input) close();
|
|
823
|
+
}, 100);
|
|
824
|
+
};
|
|
825
|
+
els.input.addEventListener("input", onInput);
|
|
826
|
+
els.input.addEventListener("keydown", onKey);
|
|
827
|
+
els.input.addEventListener("focus", onFocus);
|
|
828
|
+
els.input.addEventListener("blur", onBlur);
|
|
829
|
+
const teardown = () => {
|
|
830
|
+
boundComboboxes.delete(els.input);
|
|
831
|
+
fxTeardown();
|
|
832
|
+
els.input.removeEventListener("input", onInput);
|
|
833
|
+
els.input.removeEventListener("keydown", onKey);
|
|
834
|
+
els.input.removeEventListener("focus", onFocus);
|
|
835
|
+
els.input.removeEventListener("blur", onBlur);
|
|
836
|
+
if (blurTimer !== null) {
|
|
837
|
+
clearTimeout(blurTimer);
|
|
838
|
+
blurTimer = null;
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
boundComboboxes.set(els.input, teardown);
|
|
842
|
+
return teardown;
|
|
843
|
+
}
|
|
509
844
|
return {
|
|
510
845
|
query,
|
|
511
846
|
setQuery,
|
|
@@ -518,11 +853,13 @@ function combobox(options) {
|
|
|
518
853
|
selectHighlighted,
|
|
519
854
|
isOpen,
|
|
520
855
|
open,
|
|
521
|
-
close
|
|
856
|
+
close,
|
|
857
|
+
bind
|
|
522
858
|
};
|
|
523
859
|
}
|
|
524
860
|
|
|
525
861
|
// src/widgets/Tabs.ts
|
|
862
|
+
var boundTablists = /* @__PURE__ */ new WeakMap();
|
|
526
863
|
function tabs(options) {
|
|
527
864
|
const { tabs: tabDefs, defaultTab } = options;
|
|
528
865
|
const initialTab = defaultTab ?? tabDefs.find((t) => !t.disabled)?.id ?? tabDefs[0]?.id ?? "";
|
|
@@ -569,6 +906,118 @@ function tabs(options) {
|
|
|
569
906
|
function isActive(id) {
|
|
570
907
|
return activeTab() === id;
|
|
571
908
|
}
|
|
909
|
+
function bind(els) {
|
|
910
|
+
const existing = boundTablists.get(els.tablist);
|
|
911
|
+
if (existing) return existing;
|
|
912
|
+
const restore = [];
|
|
913
|
+
const prevTablistRole = els.tablist.getAttribute("role");
|
|
914
|
+
els.tablist.setAttribute("role", "tablist");
|
|
915
|
+
restore.push(() => {
|
|
916
|
+
if (prevTablistRole === null) els.tablist.removeAttribute("role");
|
|
917
|
+
else els.tablist.setAttribute("role", prevTablistRole);
|
|
918
|
+
});
|
|
919
|
+
for (const def of tabDefs) {
|
|
920
|
+
const tabEl = els.tabs[def.id];
|
|
921
|
+
if (!tabEl) continue;
|
|
922
|
+
const prevRole = tabEl.getAttribute("role");
|
|
923
|
+
const prevId = tabEl.id;
|
|
924
|
+
const prevDisabled = tabEl.getAttribute("aria-disabled");
|
|
925
|
+
const prevControls = tabEl.getAttribute("aria-controls");
|
|
926
|
+
tabEl.setAttribute("role", "tab");
|
|
927
|
+
tabEl.setAttribute("id", `sibu-tab-${def.id}`);
|
|
928
|
+
if (def.disabled) tabEl.setAttribute("aria-disabled", "true");
|
|
929
|
+
const panelEl = els.panels?.[def.id];
|
|
930
|
+
let prevPanelRole = null;
|
|
931
|
+
let prevPanelId = "";
|
|
932
|
+
let prevPanelLabelledBy = null;
|
|
933
|
+
if (panelEl) {
|
|
934
|
+
prevPanelRole = panelEl.getAttribute("role");
|
|
935
|
+
prevPanelId = panelEl.id;
|
|
936
|
+
prevPanelLabelledBy = panelEl.getAttribute("aria-labelledby");
|
|
937
|
+
panelEl.setAttribute("role", "tabpanel");
|
|
938
|
+
panelEl.setAttribute("id", `sibu-tabpanel-${def.id}`);
|
|
939
|
+
panelEl.setAttribute("aria-labelledby", `sibu-tab-${def.id}`);
|
|
940
|
+
tabEl.setAttribute("aria-controls", `sibu-tabpanel-${def.id}`);
|
|
941
|
+
}
|
|
942
|
+
restore.push(() => {
|
|
943
|
+
if (prevRole === null) tabEl.removeAttribute("role");
|
|
944
|
+
else tabEl.setAttribute("role", prevRole);
|
|
945
|
+
if (prevId === "") tabEl.removeAttribute("id");
|
|
946
|
+
else tabEl.id = prevId;
|
|
947
|
+
if (prevDisabled === null) tabEl.removeAttribute("aria-disabled");
|
|
948
|
+
else tabEl.setAttribute("aria-disabled", prevDisabled);
|
|
949
|
+
if (prevControls === null) tabEl.removeAttribute("aria-controls");
|
|
950
|
+
else tabEl.setAttribute("aria-controls", prevControls);
|
|
951
|
+
tabEl.removeAttribute("aria-selected");
|
|
952
|
+
tabEl.removeAttribute("tabindex");
|
|
953
|
+
if (panelEl) {
|
|
954
|
+
if (prevPanelRole === null) panelEl.removeAttribute("role");
|
|
955
|
+
else panelEl.setAttribute("role", prevPanelRole);
|
|
956
|
+
if (prevPanelId === "") panelEl.removeAttribute("id");
|
|
957
|
+
else panelEl.id = prevPanelId;
|
|
958
|
+
if (prevPanelLabelledBy === null) panelEl.removeAttribute("aria-labelledby");
|
|
959
|
+
else panelEl.setAttribute("aria-labelledby", prevPanelLabelledBy);
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
const fxTeardown = effect(() => {
|
|
964
|
+
const active = activeTab();
|
|
965
|
+
for (const def of tabDefs) {
|
|
966
|
+
const tabEl = els.tabs[def.id];
|
|
967
|
+
if (!tabEl) continue;
|
|
968
|
+
const isAct = def.id === active;
|
|
969
|
+
tabEl.setAttribute("aria-selected", isAct ? "true" : "false");
|
|
970
|
+
tabEl.tabIndex = isAct ? 0 : -1;
|
|
971
|
+
const panelEl = els.panels?.[def.id];
|
|
972
|
+
if (panelEl) panelEl.hidden = !isAct;
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
const onKey = (e) => {
|
|
976
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
977
|
+
e.preventDefault();
|
|
978
|
+
nextTab();
|
|
979
|
+
els.tabs[activeTab()]?.focus();
|
|
980
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
981
|
+
e.preventDefault();
|
|
982
|
+
prevTab();
|
|
983
|
+
els.tabs[activeTab()]?.focus();
|
|
984
|
+
} else if (e.key === "Home") {
|
|
985
|
+
e.preventDefault();
|
|
986
|
+
const first = tabDefs.find((t) => !t.disabled);
|
|
987
|
+
if (first) {
|
|
988
|
+
setActiveTabState(first.id);
|
|
989
|
+
els.tabs[first.id]?.focus();
|
|
990
|
+
}
|
|
991
|
+
} else if (e.key === "End") {
|
|
992
|
+
e.preventDefault();
|
|
993
|
+
for (let i = tabDefs.length - 1; i >= 0; i--) {
|
|
994
|
+
if (!tabDefs[i].disabled) {
|
|
995
|
+
setActiveTabState(tabDefs[i].id);
|
|
996
|
+
els.tabs[tabDefs[i].id]?.focus();
|
|
997
|
+
break;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
els.tablist.addEventListener("keydown", onKey);
|
|
1003
|
+
const clickHandlers = [];
|
|
1004
|
+
for (const def of tabDefs) {
|
|
1005
|
+
const tabEl = els.tabs[def.id];
|
|
1006
|
+
if (!tabEl) continue;
|
|
1007
|
+
const fn = () => setActiveTab(def.id);
|
|
1008
|
+
tabEl.addEventListener("click", fn);
|
|
1009
|
+
clickHandlers.push({ el: tabEl, fn });
|
|
1010
|
+
}
|
|
1011
|
+
const teardown = () => {
|
|
1012
|
+
boundTablists.delete(els.tablist);
|
|
1013
|
+
fxTeardown();
|
|
1014
|
+
els.tablist.removeEventListener("keydown", onKey);
|
|
1015
|
+
for (const { el, fn } of clickHandlers) el.removeEventListener("click", fn);
|
|
1016
|
+
for (const r of restore) r();
|
|
1017
|
+
};
|
|
1018
|
+
boundTablists.set(els.tablist, teardown);
|
|
1019
|
+
return teardown;
|
|
1020
|
+
}
|
|
572
1021
|
return {
|
|
573
1022
|
activeTab,
|
|
574
1023
|
setActiveTab,
|
|
@@ -576,11 +1025,13 @@ function tabs(options) {
|
|
|
576
1025
|
nextTab,
|
|
577
1026
|
prevTab,
|
|
578
1027
|
/** Reactive check — use inside class/nodes bindings for per-tab reactivity */
|
|
579
|
-
isActive
|
|
1028
|
+
isActive,
|
|
1029
|
+
bind
|
|
580
1030
|
};
|
|
581
1031
|
}
|
|
582
1032
|
|
|
583
1033
|
// src/widgets/Accordion.ts
|
|
1034
|
+
var boundAccordions = /* @__PURE__ */ new WeakMap();
|
|
584
1035
|
function accordion(options) {
|
|
585
1036
|
const { items: itemDefs, multiple = false, defaultExpanded = [] } = options;
|
|
586
1037
|
const [expandedIds, setExpandedIds] = signal(new Set(defaultExpanded));
|
|
@@ -627,6 +1078,86 @@ function accordion(options) {
|
|
|
627
1078
|
function isExpanded(id) {
|
|
628
1079
|
return expandedIds().has(id);
|
|
629
1080
|
}
|
|
1081
|
+
function bind(els) {
|
|
1082
|
+
const idempotencyKey = els.root ?? (itemDefs.length > 0 ? els.triggers[itemDefs[0].id] : void 0);
|
|
1083
|
+
if (idempotencyKey) {
|
|
1084
|
+
const existing = boundAccordions.get(idempotencyKey);
|
|
1085
|
+
if (existing) return existing;
|
|
1086
|
+
}
|
|
1087
|
+
const restore = [];
|
|
1088
|
+
for (const item of itemDefs) {
|
|
1089
|
+
const trig = els.triggers[item.id];
|
|
1090
|
+
const panel = els.panels[item.id];
|
|
1091
|
+
if (!trig) continue;
|
|
1092
|
+
const prevTrigId = trig.id;
|
|
1093
|
+
const prevTrigControls = trig.getAttribute("aria-controls");
|
|
1094
|
+
trig.id = `sibu-accordion-trigger-${item.id}`;
|
|
1095
|
+
let prevPanelRole = null;
|
|
1096
|
+
let prevPanelId = "";
|
|
1097
|
+
let prevPanelLabelledBy = null;
|
|
1098
|
+
if (panel) {
|
|
1099
|
+
prevPanelRole = panel.getAttribute("role");
|
|
1100
|
+
prevPanelId = panel.id;
|
|
1101
|
+
prevPanelLabelledBy = panel.getAttribute("aria-labelledby");
|
|
1102
|
+
panel.setAttribute("role", "region");
|
|
1103
|
+
panel.id = `sibu-accordion-panel-${item.id}`;
|
|
1104
|
+
panel.setAttribute("aria-labelledby", trig.id);
|
|
1105
|
+
trig.setAttribute("aria-controls", panel.id);
|
|
1106
|
+
}
|
|
1107
|
+
restore.push(() => {
|
|
1108
|
+
if (prevTrigId === "") trig.removeAttribute("id");
|
|
1109
|
+
else trig.id = prevTrigId;
|
|
1110
|
+
if (prevTrigControls === null) trig.removeAttribute("aria-controls");
|
|
1111
|
+
else trig.setAttribute("aria-controls", prevTrigControls);
|
|
1112
|
+
trig.removeAttribute("aria-expanded");
|
|
1113
|
+
if (panel) {
|
|
1114
|
+
if (prevPanelRole === null) panel.removeAttribute("role");
|
|
1115
|
+
else panel.setAttribute("role", prevPanelRole);
|
|
1116
|
+
if (prevPanelId === "") panel.removeAttribute("id");
|
|
1117
|
+
else panel.id = prevPanelId;
|
|
1118
|
+
if (prevPanelLabelledBy === null) panel.removeAttribute("aria-labelledby");
|
|
1119
|
+
else panel.setAttribute("aria-labelledby", prevPanelLabelledBy);
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
const fxTeardown = effect(() => {
|
|
1124
|
+
const ids = expandedIds();
|
|
1125
|
+
for (const item of itemDefs) {
|
|
1126
|
+
const trig = els.triggers[item.id];
|
|
1127
|
+
const panel = els.panels[item.id];
|
|
1128
|
+
if (!trig) continue;
|
|
1129
|
+
const expanded = ids.has(item.id);
|
|
1130
|
+
trig.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
1131
|
+
if (panel) panel.hidden = !expanded;
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
const handlers = [];
|
|
1135
|
+
for (const item of itemDefs) {
|
|
1136
|
+
const trig = els.triggers[item.id];
|
|
1137
|
+
if (!trig) continue;
|
|
1138
|
+
const click = () => toggle(item.id);
|
|
1139
|
+
const key = (e) => {
|
|
1140
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1141
|
+
e.preventDefault();
|
|
1142
|
+
toggle(item.id);
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
trig.addEventListener("click", click);
|
|
1146
|
+
trig.addEventListener("keydown", key);
|
|
1147
|
+
handlers.push({ el: trig, click, key });
|
|
1148
|
+
}
|
|
1149
|
+
const teardown = () => {
|
|
1150
|
+
if (idempotencyKey) boundAccordions.delete(idempotencyKey);
|
|
1151
|
+
fxTeardown();
|
|
1152
|
+
for (const { el, click, key } of handlers) {
|
|
1153
|
+
el.removeEventListener("click", click);
|
|
1154
|
+
el.removeEventListener("keydown", key);
|
|
1155
|
+
}
|
|
1156
|
+
for (const r of restore) r();
|
|
1157
|
+
};
|
|
1158
|
+
if (idempotencyKey) boundAccordions.set(idempotencyKey, teardown);
|
|
1159
|
+
return teardown;
|
|
1160
|
+
}
|
|
630
1161
|
return {
|
|
631
1162
|
items,
|
|
632
1163
|
toggle,
|
|
@@ -635,11 +1166,14 @@ function accordion(options) {
|
|
|
635
1166
|
expandAll,
|
|
636
1167
|
collapseAll,
|
|
637
1168
|
/** Reactive check — use inside class/nodes bindings for per-item reactivity */
|
|
638
|
-
isExpanded
|
|
1169
|
+
isExpanded,
|
|
1170
|
+
bind
|
|
639
1171
|
};
|
|
640
1172
|
}
|
|
641
1173
|
|
|
642
1174
|
// src/widgets/Popover.ts
|
|
1175
|
+
var popoverIdCounter = 0;
|
|
1176
|
+
var boundPopovers = /* @__PURE__ */ new WeakMap();
|
|
643
1177
|
function popover() {
|
|
644
1178
|
const [isOpen, setIsOpen] = signal(false);
|
|
645
1179
|
function open() {
|
|
@@ -651,12 +1185,88 @@ function popover() {
|
|
|
651
1185
|
function toggle() {
|
|
652
1186
|
setIsOpen((prev) => !prev);
|
|
653
1187
|
}
|
|
654
|
-
|
|
1188
|
+
function bind(els) {
|
|
1189
|
+
const existing = boundPopovers.get(els.trigger);
|
|
1190
|
+
if (existing) return existing;
|
|
1191
|
+
const id = `sibu-popover-${++popoverIdCounter}`;
|
|
1192
|
+
const prevPopoverRole = els.popover.getAttribute("role");
|
|
1193
|
+
const prevPopoverId = els.popover.id;
|
|
1194
|
+
const prevLabelledBy = els.popover.getAttribute("aria-labelledby");
|
|
1195
|
+
const prevTriggerHaspopup = els.trigger.getAttribute("aria-haspopup");
|
|
1196
|
+
const prevTriggerControls = els.trigger.getAttribute("aria-controls");
|
|
1197
|
+
els.popover.setAttribute("role", "dialog");
|
|
1198
|
+
els.popover.id = id;
|
|
1199
|
+
els.trigger.setAttribute("aria-haspopup", "dialog");
|
|
1200
|
+
els.trigger.setAttribute("aria-controls", id);
|
|
1201
|
+
let assignedLabelId = null;
|
|
1202
|
+
if (els.labelledBy) {
|
|
1203
|
+
if (!els.labelledBy.id) {
|
|
1204
|
+
els.labelledBy.id = `${id}-label`;
|
|
1205
|
+
assignedLabelId = els.labelledBy.id;
|
|
1206
|
+
}
|
|
1207
|
+
els.popover.setAttribute("aria-labelledby", els.labelledBy.id);
|
|
1208
|
+
}
|
|
1209
|
+
const fxTeardown = effect(() => {
|
|
1210
|
+
const open2 = isOpen();
|
|
1211
|
+
els.trigger.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
1212
|
+
els.popover.hidden = !open2;
|
|
1213
|
+
});
|
|
1214
|
+
const onTriggerClick = (e) => {
|
|
1215
|
+
e.preventDefault();
|
|
1216
|
+
toggle();
|
|
1217
|
+
};
|
|
1218
|
+
const onKey = (e) => {
|
|
1219
|
+
if (e.key === "Escape" && isOpen()) {
|
|
1220
|
+
e.stopPropagation();
|
|
1221
|
+
close();
|
|
1222
|
+
els.trigger.focus();
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
const onDocPointer = (e) => {
|
|
1226
|
+
if (!isOpen()) return;
|
|
1227
|
+
const t = e.target;
|
|
1228
|
+
if (!t) return;
|
|
1229
|
+
if (els.trigger.contains(t) || els.popover.contains(t)) return;
|
|
1230
|
+
close();
|
|
1231
|
+
};
|
|
1232
|
+
els.trigger.addEventListener("click", onTriggerClick);
|
|
1233
|
+
els.popover.addEventListener("keydown", onKey);
|
|
1234
|
+
els.trigger.addEventListener("keydown", onKey);
|
|
1235
|
+
document.addEventListener("pointerdown", onDocPointer);
|
|
1236
|
+
const teardown = () => {
|
|
1237
|
+
boundPopovers.delete(els.trigger);
|
|
1238
|
+
fxTeardown();
|
|
1239
|
+
els.trigger.removeEventListener("click", onTriggerClick);
|
|
1240
|
+
els.popover.removeEventListener("keydown", onKey);
|
|
1241
|
+
els.trigger.removeEventListener("keydown", onKey);
|
|
1242
|
+
document.removeEventListener("pointerdown", onDocPointer);
|
|
1243
|
+
if (prevPopoverRole === null) els.popover.removeAttribute("role");
|
|
1244
|
+
else els.popover.setAttribute("role", prevPopoverRole);
|
|
1245
|
+
if (prevPopoverId === "") els.popover.removeAttribute("id");
|
|
1246
|
+
else els.popover.id = prevPopoverId;
|
|
1247
|
+
if (prevLabelledBy === null) els.popover.removeAttribute("aria-labelledby");
|
|
1248
|
+
else els.popover.setAttribute("aria-labelledby", prevLabelledBy);
|
|
1249
|
+
if (assignedLabelId && els.labelledBy?.id === assignedLabelId) {
|
|
1250
|
+
els.labelledBy.removeAttribute("id");
|
|
1251
|
+
}
|
|
1252
|
+
if (prevTriggerHaspopup === null) els.trigger.removeAttribute("aria-haspopup");
|
|
1253
|
+
else els.trigger.setAttribute("aria-haspopup", prevTriggerHaspopup);
|
|
1254
|
+
if (prevTriggerControls === null) els.trigger.removeAttribute("aria-controls");
|
|
1255
|
+
else els.trigger.setAttribute("aria-controls", prevTriggerControls);
|
|
1256
|
+
els.trigger.removeAttribute("aria-expanded");
|
|
1257
|
+
};
|
|
1258
|
+
boundPopovers.set(els.trigger, teardown);
|
|
1259
|
+
return teardown;
|
|
1260
|
+
}
|
|
1261
|
+
return { isOpen, open, close, toggle, bind };
|
|
655
1262
|
}
|
|
656
1263
|
|
|
657
1264
|
// src/widgets/Select.ts
|
|
1265
|
+
var selectIdCounter = 0;
|
|
1266
|
+
var boundSelects = /* @__PURE__ */ new WeakMap();
|
|
658
1267
|
function select(options) {
|
|
659
|
-
const { items, multiple = false } = options;
|
|
1268
|
+
const { items, multiple = false, itemToString, isDisabled } = options;
|
|
1269
|
+
const isItemDisabled = isDisabled ?? (() => false);
|
|
660
1270
|
const [selectedItems, setSelectedItems] = signal([]);
|
|
661
1271
|
const [isOpen, setIsOpen] = signal(false);
|
|
662
1272
|
const [highlightedIndex, setHighlightedIndex] = signal(-1);
|
|
@@ -665,6 +1275,7 @@ function select(options) {
|
|
|
665
1275
|
return sel.length > 0 ? sel[sel.length - 1] : null;
|
|
666
1276
|
});
|
|
667
1277
|
function select2(item) {
|
|
1278
|
+
if (isItemDisabled(item)) return;
|
|
668
1279
|
if (multiple) {
|
|
669
1280
|
setSelectedItems((prev) => {
|
|
670
1281
|
if (prev.includes(item)) return prev;
|
|
@@ -696,18 +1307,28 @@ function select(options) {
|
|
|
696
1307
|
function close() {
|
|
697
1308
|
setIsOpen(false);
|
|
698
1309
|
}
|
|
1310
|
+
function nextEnabled(from, dir) {
|
|
1311
|
+
const len = items.length;
|
|
1312
|
+
if (len === 0) return -1;
|
|
1313
|
+
let i = from;
|
|
1314
|
+
for (let n = 0; n < len; n++) {
|
|
1315
|
+
i = (i + dir + len) % len;
|
|
1316
|
+
if (!isItemDisabled(items[i])) return i;
|
|
1317
|
+
}
|
|
1318
|
+
return -1;
|
|
1319
|
+
}
|
|
699
1320
|
function highlightNext() {
|
|
700
1321
|
if (items.length === 0) return;
|
|
701
1322
|
setHighlightedIndex((prev) => {
|
|
702
|
-
const
|
|
703
|
-
return
|
|
1323
|
+
const n = nextEnabled(prev < 0 ? -1 : prev, 1);
|
|
1324
|
+
return n === -1 ? prev : n;
|
|
704
1325
|
});
|
|
705
1326
|
}
|
|
706
1327
|
function highlightPrev() {
|
|
707
1328
|
if (items.length === 0) return;
|
|
708
1329
|
setHighlightedIndex((prev) => {
|
|
709
|
-
const
|
|
710
|
-
return
|
|
1330
|
+
const n = nextEnabled(prev < 0 ? items.length : prev, -1);
|
|
1331
|
+
return n === -1 ? prev : n;
|
|
711
1332
|
});
|
|
712
1333
|
}
|
|
713
1334
|
function selectHighlighted() {
|
|
@@ -719,6 +1340,73 @@ function select(options) {
|
|
|
719
1340
|
function clear() {
|
|
720
1341
|
setSelectedItems([]);
|
|
721
1342
|
}
|
|
1343
|
+
function bind(els) {
|
|
1344
|
+
const existing = boundSelects.get(els.listbox);
|
|
1345
|
+
if (existing) return existing;
|
|
1346
|
+
const listboxId = `sibu-select-${++selectIdCounter}`;
|
|
1347
|
+
els.listbox.id = listboxId;
|
|
1348
|
+
els.listbox.setAttribute("role", "listbox");
|
|
1349
|
+
els.listbox.setAttribute("aria-multiselectable", multiple ? "true" : "false");
|
|
1350
|
+
if (els.listbox.tabIndex < 0) els.listbox.tabIndex = 0;
|
|
1351
|
+
const toStr = els.itemToString ?? itemToString ?? ((it) => String(it));
|
|
1352
|
+
const fxTeardown = effect(() => {
|
|
1353
|
+
const idx = highlightedIndex();
|
|
1354
|
+
const sel = selectedItems();
|
|
1355
|
+
let activeId = "";
|
|
1356
|
+
for (let i = 0; i < items.length; i++) {
|
|
1357
|
+
const optEl = els.option(items[i], i);
|
|
1358
|
+
if (!optEl) continue;
|
|
1359
|
+
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
1360
|
+
optEl.setAttribute("role", "option");
|
|
1361
|
+
optEl.setAttribute("aria-selected", sel.includes(items[i]) ? "true" : "false");
|
|
1362
|
+
if (isItemDisabled(items[i])) optEl.setAttribute("aria-disabled", "true");
|
|
1363
|
+
else optEl.removeAttribute("aria-disabled");
|
|
1364
|
+
if (i === idx) activeId = optEl.id;
|
|
1365
|
+
}
|
|
1366
|
+
if (activeId) els.listbox.setAttribute("aria-activedescendant", activeId);
|
|
1367
|
+
else els.listbox.removeAttribute("aria-activedescendant");
|
|
1368
|
+
});
|
|
1369
|
+
let typeBuffer = "";
|
|
1370
|
+
let typeTimer = null;
|
|
1371
|
+
const onKey = (e) => {
|
|
1372
|
+
if (e.key === "ArrowDown") {
|
|
1373
|
+
e.preventDefault();
|
|
1374
|
+
highlightNext();
|
|
1375
|
+
} else if (e.key === "ArrowUp") {
|
|
1376
|
+
e.preventDefault();
|
|
1377
|
+
highlightPrev();
|
|
1378
|
+
} else if (e.key === "Home") {
|
|
1379
|
+
e.preventDefault();
|
|
1380
|
+
if (items.length > 0) setHighlightedIndex(0);
|
|
1381
|
+
} else if (e.key === "End") {
|
|
1382
|
+
e.preventDefault();
|
|
1383
|
+
if (items.length > 0) setHighlightedIndex(items.length - 1);
|
|
1384
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
1385
|
+
if (highlightedIndex() >= 0) {
|
|
1386
|
+
e.preventDefault();
|
|
1387
|
+
selectHighlighted();
|
|
1388
|
+
}
|
|
1389
|
+
} else if (e.key.length === 1 && /\S/.test(e.key)) {
|
|
1390
|
+
typeBuffer += e.key.toLowerCase();
|
|
1391
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
1392
|
+
typeTimer = setTimeout(() => {
|
|
1393
|
+
typeBuffer = "";
|
|
1394
|
+
typeTimer = null;
|
|
1395
|
+
}, 500);
|
|
1396
|
+
const found = items.findIndex((it) => !isItemDisabled(it) && toStr(it).toLowerCase().startsWith(typeBuffer));
|
|
1397
|
+
if (found !== -1) setHighlightedIndex(found);
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
els.listbox.addEventListener("keydown", onKey);
|
|
1401
|
+
const teardown = () => {
|
|
1402
|
+
boundSelects.delete(els.listbox);
|
|
1403
|
+
fxTeardown();
|
|
1404
|
+
els.listbox.removeEventListener("keydown", onKey);
|
|
1405
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
1406
|
+
};
|
|
1407
|
+
boundSelects.set(els.listbox, teardown);
|
|
1408
|
+
return teardown;
|
|
1409
|
+
}
|
|
722
1410
|
return {
|
|
723
1411
|
selectedItems,
|
|
724
1412
|
selectedItem,
|
|
@@ -733,21 +1421,28 @@ function select(options) {
|
|
|
733
1421
|
highlightNext,
|
|
734
1422
|
highlightPrev,
|
|
735
1423
|
selectHighlighted,
|
|
736
|
-
clear
|
|
1424
|
+
clear,
|
|
1425
|
+
bind
|
|
737
1426
|
};
|
|
738
1427
|
}
|
|
739
1428
|
|
|
740
1429
|
// src/widgets/Tooltip.ts
|
|
1430
|
+
var tooltipIdCounter = 0;
|
|
1431
|
+
var boundTriggers = /* @__PURE__ */ new WeakMap();
|
|
741
1432
|
function tooltip(options) {
|
|
742
1433
|
const delay = options?.delay ?? 0;
|
|
1434
|
+
const hideDelay = options?.hideDelay ?? 100;
|
|
743
1435
|
const [isVisible, setIsVisible] = signal(false);
|
|
744
1436
|
const [content, setContent] = signal("");
|
|
745
1437
|
let delayTimer = null;
|
|
1438
|
+
let hideTimer = null;
|
|
746
1439
|
function show() {
|
|
1440
|
+
if (hideTimer !== null) {
|
|
1441
|
+
clearTimeout(hideTimer);
|
|
1442
|
+
hideTimer = null;
|
|
1443
|
+
}
|
|
747
1444
|
if (delay > 0) {
|
|
748
|
-
if (delayTimer !== null)
|
|
749
|
-
clearTimeout(delayTimer);
|
|
750
|
-
}
|
|
1445
|
+
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
751
1446
|
delayTimer = setTimeout(() => {
|
|
752
1447
|
setIsVisible(true);
|
|
753
1448
|
delayTimer = null;
|
|
@@ -763,10 +1458,82 @@ function tooltip(options) {
|
|
|
763
1458
|
}
|
|
764
1459
|
setIsVisible(false);
|
|
765
1460
|
}
|
|
766
|
-
|
|
1461
|
+
function scheduleHide() {
|
|
1462
|
+
if (delayTimer !== null) {
|
|
1463
|
+
clearTimeout(delayTimer);
|
|
1464
|
+
delayTimer = null;
|
|
1465
|
+
}
|
|
1466
|
+
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
1467
|
+
hideTimer = setTimeout(() => {
|
|
1468
|
+
hideTimer = null;
|
|
1469
|
+
setIsVisible(false);
|
|
1470
|
+
}, hideDelay);
|
|
1471
|
+
}
|
|
1472
|
+
function bind(els) {
|
|
1473
|
+
const existing = boundTriggers.get(els.trigger);
|
|
1474
|
+
if (existing) return existing;
|
|
1475
|
+
const id = `sibu-tooltip-${++tooltipIdCounter}`;
|
|
1476
|
+
els.tooltip.setAttribute("role", "tooltip");
|
|
1477
|
+
els.tooltip.id = id;
|
|
1478
|
+
const prevDescribedBy = els.trigger.getAttribute("aria-describedby");
|
|
1479
|
+
els.trigger.setAttribute("aria-describedby", prevDescribedBy ? `${prevDescribedBy} ${id}` : id);
|
|
1480
|
+
const fxTeardown = effect(() => {
|
|
1481
|
+
els.tooltip.hidden = !isVisible();
|
|
1482
|
+
});
|
|
1483
|
+
const onTriggerEnter = () => show();
|
|
1484
|
+
const onTriggerLeave = () => scheduleHide();
|
|
1485
|
+
const onTooltipEnter = () => {
|
|
1486
|
+
if (hideTimer !== null) {
|
|
1487
|
+
clearTimeout(hideTimer);
|
|
1488
|
+
hideTimer = null;
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
const onTooltipLeave = () => scheduleHide();
|
|
1492
|
+
const onFocus = () => show();
|
|
1493
|
+
const onBlur = () => hide();
|
|
1494
|
+
const onKey = (e) => {
|
|
1495
|
+
if (e.key === "Escape" && isVisible()) {
|
|
1496
|
+
e.stopPropagation();
|
|
1497
|
+
hide();
|
|
1498
|
+
}
|
|
1499
|
+
};
|
|
1500
|
+
els.trigger.addEventListener("pointerenter", onTriggerEnter);
|
|
1501
|
+
els.trigger.addEventListener("pointerleave", onTriggerLeave);
|
|
1502
|
+
els.trigger.addEventListener("focus", onFocus);
|
|
1503
|
+
els.trigger.addEventListener("blur", onBlur);
|
|
1504
|
+
els.trigger.addEventListener("keydown", onKey);
|
|
1505
|
+
els.tooltip.addEventListener("pointerenter", onTooltipEnter);
|
|
1506
|
+
els.tooltip.addEventListener("pointerleave", onTooltipLeave);
|
|
1507
|
+
const teardown = () => {
|
|
1508
|
+
boundTriggers.delete(els.trigger);
|
|
1509
|
+
fxTeardown();
|
|
1510
|
+
els.trigger.removeEventListener("pointerenter", onTriggerEnter);
|
|
1511
|
+
els.trigger.removeEventListener("pointerleave", onTriggerLeave);
|
|
1512
|
+
els.trigger.removeEventListener("focus", onFocus);
|
|
1513
|
+
els.trigger.removeEventListener("blur", onBlur);
|
|
1514
|
+
els.trigger.removeEventListener("keydown", onKey);
|
|
1515
|
+
els.tooltip.removeEventListener("pointerenter", onTooltipEnter);
|
|
1516
|
+
els.tooltip.removeEventListener("pointerleave", onTooltipLeave);
|
|
1517
|
+
const cur = els.trigger.getAttribute("aria-describedby");
|
|
1518
|
+
if (cur) {
|
|
1519
|
+
const remaining = cur.split(/\s+/).filter((part) => part && part !== id);
|
|
1520
|
+
if (remaining.length > 0) els.trigger.setAttribute("aria-describedby", remaining.join(" "));
|
|
1521
|
+
else els.trigger.removeAttribute("aria-describedby");
|
|
1522
|
+
} else if (prevDescribedBy) {
|
|
1523
|
+
els.trigger.setAttribute("aria-describedby", prevDescribedBy);
|
|
1524
|
+
}
|
|
1525
|
+
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
1526
|
+
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
1527
|
+
};
|
|
1528
|
+
boundTriggers.set(els.trigger, teardown);
|
|
1529
|
+
return teardown;
|
|
1530
|
+
}
|
|
1531
|
+
return { isVisible, show, hide, content, setContent, bind };
|
|
767
1532
|
}
|
|
768
1533
|
|
|
769
1534
|
// src/widgets/FileUpload.ts
|
|
1535
|
+
var fileUploadIdCounter = 0;
|
|
1536
|
+
var boundFileUploads = /* @__PURE__ */ new WeakMap();
|
|
770
1537
|
function fileUpload(options) {
|
|
771
1538
|
const accept = options?.accept;
|
|
772
1539
|
const multiple = options?.multiple ?? false;
|
|
@@ -834,6 +1601,107 @@ function fileUpload(options) {
|
|
|
834
1601
|
setErrors([]);
|
|
835
1602
|
});
|
|
836
1603
|
}
|
|
1604
|
+
function bind(els) {
|
|
1605
|
+
const existing = boundFileUploads.get(els.input);
|
|
1606
|
+
if (existing) return existing;
|
|
1607
|
+
const id = `sibu-fileupload-${++fileUploadIdCounter}`;
|
|
1608
|
+
const restore = [];
|
|
1609
|
+
if (accept) els.input.accept = accept;
|
|
1610
|
+
els.input.multiple = multiple;
|
|
1611
|
+
let hintId = null;
|
|
1612
|
+
if (els.hint) {
|
|
1613
|
+
const assignedHintId = !els.hint.id;
|
|
1614
|
+
if (assignedHintId) els.hint.id = `${id}-hint`;
|
|
1615
|
+
hintId = els.hint.id;
|
|
1616
|
+
const prev = els.input.getAttribute("aria-describedby");
|
|
1617
|
+
els.input.setAttribute("aria-describedby", prev ? `${prev} ${hintId}` : hintId);
|
|
1618
|
+
restore.push(() => {
|
|
1619
|
+
const cur = els.input.getAttribute("aria-describedby");
|
|
1620
|
+
if (cur) {
|
|
1621
|
+
const parts = cur.split(/\s+/).filter((p) => p && p !== hintId);
|
|
1622
|
+
if (parts.length > 0) els.input.setAttribute("aria-describedby", parts.join(" "));
|
|
1623
|
+
else els.input.removeAttribute("aria-describedby");
|
|
1624
|
+
}
|
|
1625
|
+
if (assignedHintId && els.hint && els.hint.id === hintId) els.hint.removeAttribute("id");
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
if (els.errorRegion) {
|
|
1629
|
+
const prevRole = els.errorRegion.getAttribute("role");
|
|
1630
|
+
const prevLive = els.errorRegion.getAttribute("aria-live");
|
|
1631
|
+
els.errorRegion.setAttribute("role", "status");
|
|
1632
|
+
els.errorRegion.setAttribute("aria-live", "polite");
|
|
1633
|
+
restore.push(() => {
|
|
1634
|
+
if (prevRole === null) els.errorRegion.removeAttribute("role");
|
|
1635
|
+
else els.errorRegion.setAttribute("role", prevRole);
|
|
1636
|
+
if (prevLive === null) els.errorRegion.removeAttribute("aria-live");
|
|
1637
|
+
else els.errorRegion.setAttribute("aria-live", prevLive);
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
if (els.dropZone) {
|
|
1641
|
+
const prevDzRole = els.dropZone.getAttribute("role");
|
|
1642
|
+
const prevDzLabel = els.dropZone.getAttribute("aria-label");
|
|
1643
|
+
const prevDzTabindex = els.dropZone.hasAttribute("tabindex") ? els.dropZone.getAttribute("tabindex") : null;
|
|
1644
|
+
els.dropZone.setAttribute("role", "button");
|
|
1645
|
+
els.dropZone.setAttribute("aria-label", "File drop zone \u2014 click or press Enter to browse");
|
|
1646
|
+
if (els.dropZone.tabIndex < 0) els.dropZone.tabIndex = 0;
|
|
1647
|
+
restore.push(() => {
|
|
1648
|
+
if (prevDzRole === null) els.dropZone.removeAttribute("role");
|
|
1649
|
+
else els.dropZone.setAttribute("role", prevDzRole);
|
|
1650
|
+
if (prevDzLabel === null) els.dropZone.removeAttribute("aria-label");
|
|
1651
|
+
else els.dropZone.setAttribute("aria-label", prevDzLabel);
|
|
1652
|
+
if (prevDzTabindex === null) els.dropZone.removeAttribute("tabindex");
|
|
1653
|
+
else els.dropZone.setAttribute("tabindex", prevDzTabindex);
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
const fxTeardown = effect(() => {
|
|
1657
|
+
const errs = errors();
|
|
1658
|
+
if (els.errorRegion) els.errorRegion.textContent = errs.join(". ");
|
|
1659
|
+
if (els.dropZone) els.dropZone.setAttribute("data-drag-over", isDragOver() ? "true" : "false");
|
|
1660
|
+
});
|
|
1661
|
+
const onChange = () => {
|
|
1662
|
+
if (els.input.files) addFiles(els.input.files);
|
|
1663
|
+
};
|
|
1664
|
+
const onDropClick = () => els.input.click();
|
|
1665
|
+
const onDropKey = (e) => {
|
|
1666
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1667
|
+
e.preventDefault();
|
|
1668
|
+
els.input.click();
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
const onDragOver = (e) => {
|
|
1672
|
+
e.preventDefault();
|
|
1673
|
+
setDragOver(true);
|
|
1674
|
+
};
|
|
1675
|
+
const onDragLeave = () => setDragOver(false);
|
|
1676
|
+
const onDrop = (e) => {
|
|
1677
|
+
e.preventDefault();
|
|
1678
|
+
setDragOver(false);
|
|
1679
|
+
if (e.dataTransfer?.files) addFiles(e.dataTransfer.files);
|
|
1680
|
+
};
|
|
1681
|
+
els.input.addEventListener("change", onChange);
|
|
1682
|
+
if (els.dropZone) {
|
|
1683
|
+
els.dropZone.addEventListener("click", onDropClick);
|
|
1684
|
+
els.dropZone.addEventListener("keydown", onDropKey);
|
|
1685
|
+
els.dropZone.addEventListener("dragover", onDragOver);
|
|
1686
|
+
els.dropZone.addEventListener("dragleave", onDragLeave);
|
|
1687
|
+
els.dropZone.addEventListener("drop", onDrop);
|
|
1688
|
+
}
|
|
1689
|
+
const teardown = () => {
|
|
1690
|
+
boundFileUploads.delete(els.input);
|
|
1691
|
+
fxTeardown();
|
|
1692
|
+
els.input.removeEventListener("change", onChange);
|
|
1693
|
+
if (els.dropZone) {
|
|
1694
|
+
els.dropZone.removeEventListener("click", onDropClick);
|
|
1695
|
+
els.dropZone.removeEventListener("keydown", onDropKey);
|
|
1696
|
+
els.dropZone.removeEventListener("dragover", onDragOver);
|
|
1697
|
+
els.dropZone.removeEventListener("dragleave", onDragLeave);
|
|
1698
|
+
els.dropZone.removeEventListener("drop", onDrop);
|
|
1699
|
+
}
|
|
1700
|
+
for (const r of restore) r();
|
|
1701
|
+
};
|
|
1702
|
+
boundFileUploads.set(els.input, teardown);
|
|
1703
|
+
return teardown;
|
|
1704
|
+
}
|
|
837
1705
|
return {
|
|
838
1706
|
files,
|
|
839
1707
|
addFiles,
|
|
@@ -841,14 +1709,36 @@ function fileUpload(options) {
|
|
|
841
1709
|
clear,
|
|
842
1710
|
errors,
|
|
843
1711
|
isDragOver,
|
|
844
|
-
setDragOver
|
|
1712
|
+
setDragOver,
|
|
1713
|
+
bind
|
|
845
1714
|
};
|
|
846
1715
|
}
|
|
847
1716
|
|
|
1717
|
+
// src/utils/sanitize.ts
|
|
1718
|
+
function stripHtml(html) {
|
|
1719
|
+
return String(html).replace(/<[^>]*>/g, "");
|
|
1720
|
+
}
|
|
1721
|
+
|
|
848
1722
|
// src/widgets/contentEditable.ts
|
|
849
1723
|
function contentEditable() {
|
|
850
|
-
const [content,
|
|
1724
|
+
const [content, setContentInternal] = signal("");
|
|
851
1725
|
const [isFocused, setFocused] = signal(false);
|
|
1726
|
+
function setContent(input) {
|
|
1727
|
+
if (typeof input === "string") {
|
|
1728
|
+
setContentInternal(input);
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
if (typeof input.text === "string") {
|
|
1732
|
+
setContentInternal(input.text);
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
if (typeof input.html === "string") {
|
|
1736
|
+
const shouldSanitize = input.sanitize !== false;
|
|
1737
|
+
setContentInternal(shouldSanitize ? stripHtml(input.html) : input.html);
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
setContentInternal("");
|
|
1741
|
+
}
|
|
852
1742
|
function wrapSelection(tagName) {
|
|
853
1743
|
if (typeof window === "undefined") return;
|
|
854
1744
|
const selection = window.getSelection();
|
|
@@ -925,6 +1815,7 @@ function contentEditable() {
|
|
|
925
1815
|
}
|
|
926
1816
|
|
|
927
1817
|
// src/widgets/datePicker.ts
|
|
1818
|
+
var boundDatePickers = /* @__PURE__ */ new WeakMap();
|
|
928
1819
|
function datePicker(options) {
|
|
929
1820
|
const minDate = options?.minDate;
|
|
930
1821
|
const maxDate = options?.maxDate;
|
|
@@ -948,33 +1839,20 @@ function datePicker(options) {
|
|
|
948
1839
|
setSelectedDate(date);
|
|
949
1840
|
}
|
|
950
1841
|
}
|
|
1842
|
+
function shiftMonth(prev, delta) {
|
|
1843
|
+
return new Date(prev.getFullYear(), prev.getMonth() + delta, 1);
|
|
1844
|
+
}
|
|
951
1845
|
function nextMonth() {
|
|
952
|
-
setViewDate((prev) =>
|
|
953
|
-
const next = new Date(prev);
|
|
954
|
-
next.setMonth(next.getMonth() + 1);
|
|
955
|
-
return next;
|
|
956
|
-
});
|
|
1846
|
+
setViewDate((prev) => shiftMonth(prev, 1));
|
|
957
1847
|
}
|
|
958
1848
|
function prevMonth() {
|
|
959
|
-
setViewDate((prev) =>
|
|
960
|
-
const next = new Date(prev);
|
|
961
|
-
next.setMonth(next.getMonth() - 1);
|
|
962
|
-
return next;
|
|
963
|
-
});
|
|
1849
|
+
setViewDate((prev) => shiftMonth(prev, -1));
|
|
964
1850
|
}
|
|
965
1851
|
function nextYear() {
|
|
966
|
-
setViewDate((prev) =>
|
|
967
|
-
const next = new Date(prev);
|
|
968
|
-
next.setFullYear(next.getFullYear() + 1);
|
|
969
|
-
return next;
|
|
970
|
-
});
|
|
1852
|
+
setViewDate((prev) => new Date(prev.getFullYear() + 1, prev.getMonth(), 1));
|
|
971
1853
|
}
|
|
972
1854
|
function prevYear() {
|
|
973
|
-
setViewDate((prev) =>
|
|
974
|
-
const next = new Date(prev);
|
|
975
|
-
next.setFullYear(next.getFullYear() - 1);
|
|
976
|
-
return next;
|
|
977
|
-
});
|
|
1855
|
+
setViewDate((prev) => new Date(prev.getFullYear() - 1, prev.getMonth(), 1));
|
|
978
1856
|
}
|
|
979
1857
|
const daysInMonth = derived(() => {
|
|
980
1858
|
const vd = viewDate();
|
|
@@ -1039,8 +1917,87 @@ function datePicker(options) {
|
|
|
1039
1917
|
daysInMonth,
|
|
1040
1918
|
isDateDisabled,
|
|
1041
1919
|
/** Reactive check — use inside class bindings for per-day reactivity */
|
|
1042
|
-
isSelected
|
|
1920
|
+
isSelected,
|
|
1921
|
+
bind
|
|
1043
1922
|
};
|
|
1923
|
+
function bind(els) {
|
|
1924
|
+
const existing = boundDatePickers.get(els.grid);
|
|
1925
|
+
if (existing) return existing;
|
|
1926
|
+
els.grid.setAttribute("role", "grid");
|
|
1927
|
+
if (els.grid.tabIndex < 0) els.grid.tabIndex = 0;
|
|
1928
|
+
const fxTeardown = effect(() => {
|
|
1929
|
+
const sel = selectedDate();
|
|
1930
|
+
const view = viewDate();
|
|
1931
|
+
const days = daysInMonth();
|
|
1932
|
+
for (const d of days) {
|
|
1933
|
+
const cell = els.cell(d.date);
|
|
1934
|
+
if (!cell) continue;
|
|
1935
|
+
cell.setAttribute("role", "gridcell");
|
|
1936
|
+
cell.setAttribute("aria-selected", sel && isSameCalendarDay(sel, d.date) ? "true" : "false");
|
|
1937
|
+
if (d.isDisabled) cell.setAttribute("aria-disabled", "true");
|
|
1938
|
+
else cell.removeAttribute("aria-disabled");
|
|
1939
|
+
cell.tabIndex = isSameCalendarDay(view, d.date) ? 0 : -1;
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
function isSameCalendarDay(a, b) {
|
|
1943
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1944
|
+
}
|
|
1945
|
+
function shiftDays(delta) {
|
|
1946
|
+
setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth(), prev.getDate() + delta));
|
|
1947
|
+
}
|
|
1948
|
+
const onKey = (e) => {
|
|
1949
|
+
switch (e.key) {
|
|
1950
|
+
case "ArrowLeft":
|
|
1951
|
+
e.preventDefault();
|
|
1952
|
+
shiftDays(-1);
|
|
1953
|
+
break;
|
|
1954
|
+
case "ArrowRight":
|
|
1955
|
+
e.preventDefault();
|
|
1956
|
+
shiftDays(1);
|
|
1957
|
+
break;
|
|
1958
|
+
case "ArrowUp":
|
|
1959
|
+
e.preventDefault();
|
|
1960
|
+
shiftDays(-7);
|
|
1961
|
+
break;
|
|
1962
|
+
case "ArrowDown":
|
|
1963
|
+
e.preventDefault();
|
|
1964
|
+
shiftDays(7);
|
|
1965
|
+
break;
|
|
1966
|
+
case "Home":
|
|
1967
|
+
e.preventDefault();
|
|
1968
|
+
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() - p.getDay()));
|
|
1969
|
+
break;
|
|
1970
|
+
case "End": {
|
|
1971
|
+
e.preventDefault();
|
|
1972
|
+
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() + (6 - p.getDay())));
|
|
1973
|
+
break;
|
|
1974
|
+
}
|
|
1975
|
+
case "PageUp":
|
|
1976
|
+
e.preventDefault();
|
|
1977
|
+
if (e.shiftKey) prevYear();
|
|
1978
|
+
else prevMonth();
|
|
1979
|
+
break;
|
|
1980
|
+
case "PageDown":
|
|
1981
|
+
e.preventDefault();
|
|
1982
|
+
if (e.shiftKey) nextYear();
|
|
1983
|
+
else nextMonth();
|
|
1984
|
+
break;
|
|
1985
|
+
case "Enter":
|
|
1986
|
+
case " ":
|
|
1987
|
+
e.preventDefault();
|
|
1988
|
+
select2(viewDate());
|
|
1989
|
+
break;
|
|
1990
|
+
}
|
|
1991
|
+
};
|
|
1992
|
+
els.grid.addEventListener("keydown", onKey);
|
|
1993
|
+
const teardown = () => {
|
|
1994
|
+
boundDatePickers.delete(els.grid);
|
|
1995
|
+
fxTeardown();
|
|
1996
|
+
els.grid.removeEventListener("keydown", onKey);
|
|
1997
|
+
};
|
|
1998
|
+
boundDatePickers.set(els.grid, teardown);
|
|
1999
|
+
return teardown;
|
|
2000
|
+
}
|
|
1044
2001
|
}
|
|
1045
2002
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1046
2003
|
0 && (module.exports = {
|