sibujs 1.5.0 → 2.0.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 +238 -69
- package/dist/browser.d.cts +5 -0
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +6 -6
- package/dist/build.cjs +916 -292
- 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-3JHCYHWN.js +125 -0
- package/dist/{chunk-VAPYJN4X.js → chunk-3LR7GLWQ.js} +93 -23
- package/dist/{chunk-RJ46C3CS.js → chunk-3NSGB5JN.js} +71 -20
- package/dist/{chunk-XUEEGU5O.js → chunk-52YJLLRO.js} +16 -4
- package/dist/{chunk-XHK6BDAJ.js → chunk-54EDRCEF.js} +25 -8
- package/dist/chunk-7JDB7I65.js +1327 -0
- package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
- package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
- package/dist/{chunk-BGN5ZMP4.js → chunk-GTBNNBJ6.js} +14 -2
- package/dist/chunk-HB24TBAF.js +121 -0
- package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
- package/dist/{chunk-BGTHZHJ5.js → chunk-JA6667UN.js} +188 -44
- package/dist/{chunk-7GRNSCFT.js → chunk-JXMMDLBY.js} +306 -183
- package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
- package/dist/{chunk-SFKNRVCU.js → chunk-KLRMB5ZS.js} +135 -79
- package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
- package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
- package/dist/{chunk-BMPL52BF.js → chunk-MIUAXB7K.js} +118 -66
- package/dist/{chunk-JCDUJN2F.js → chunk-ND2664SF.js} +486 -153
- package/dist/{chunk-VQDZK23A.js → chunk-O2MNQFLP.js} +181 -66
- package/dist/{chunk-NHUC2QWH.js → chunk-R73P76YZ.js} +1 -1
- package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
- package/dist/chunk-UCS6AMJ7.js +79 -0
- package/dist/{chunk-K4G4ZQNR.js → chunk-VLPPXTYG.js} +84 -38
- package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
- 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 +410 -99
- package/dist/data.d.cts +20 -2
- package/dist/data.d.ts +20 -2
- package/dist/data.js +11 -9
- package/dist/devtools.cjs +513 -223
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +12 -6
- package/dist/ecosystem.cjs +475 -144
- package/dist/ecosystem.d.cts +9 -7
- package/dist/ecosystem.d.ts +9 -7
- package/dist/ecosystem.js +12 -11
- package/dist/extras.cjs +3355 -1541
- package/dist/extras.d.cts +9 -9
- package/dist/extras.d.ts +9 -9
- package/dist/extras.js +58 -45
- package/dist/index.cjs +920 -292
- package/dist/index.d.cts +71 -8
- package/dist/index.d.ts +71 -8
- package/dist/index.js +28 -16
- package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
- package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
- package/dist/motion.cjs +77 -34
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +335 -69
- package/dist/patterns.d.cts +11 -12
- package/dist/patterns.d.ts +11 -12
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +279 -108
- 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 +635 -260
- 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 +642 -222
- 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 +252 -63
- package/dist/testing.d.cts +17 -4
- package/dist/testing.d.ts +17 -4
- package/dist/testing.js +100 -44
- package/dist/ui.cjs +463 -137
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +20 -17
- package/dist/widgets.cjs +977 -94
- 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-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,12 +39,12 @@ 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
|
|
|
@@ -54,11 +54,11 @@ var subscriberStack = new Array(32);
|
|
|
54
54
|
var stackCapacity = 32;
|
|
55
55
|
var stackTop = -1;
|
|
56
56
|
var currentSubscriber = null;
|
|
57
|
-
var signalSubscribers = /* @__PURE__ */ new WeakMap();
|
|
58
57
|
var SUBS = "__s";
|
|
59
58
|
var notifyDepth = 0;
|
|
60
59
|
var pendingQueue = [];
|
|
61
60
|
var pendingSet = /* @__PURE__ */ new Set();
|
|
61
|
+
var propagateStack = [];
|
|
62
62
|
function safeInvoke(sub) {
|
|
63
63
|
try {
|
|
64
64
|
sub();
|
|
@@ -67,6 +67,15 @@ function safeInvoke(sub) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
var trackingSuspended = false;
|
|
70
|
+
function retrack(effectFn, subscriber) {
|
|
71
|
+
const prev = currentSubscriber;
|
|
72
|
+
currentSubscriber = subscriber;
|
|
73
|
+
try {
|
|
74
|
+
effectFn();
|
|
75
|
+
} finally {
|
|
76
|
+
currentSubscriber = prev;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
70
79
|
function track(effectFn, subscriber) {
|
|
71
80
|
if (!subscriber) subscriber = effectFn;
|
|
72
81
|
cleanup(subscriber);
|
|
@@ -105,7 +114,6 @@ function recordDependency(signal2) {
|
|
|
105
114
|
let subs = signal2[SUBS];
|
|
106
115
|
if (!subs) {
|
|
107
116
|
subs = /* @__PURE__ */ new Set();
|
|
108
|
-
signalSubscribers.set(signal2, subs);
|
|
109
117
|
signal2[SUBS] = subs;
|
|
110
118
|
}
|
|
111
119
|
subs.add(currentSubscriber);
|
|
@@ -127,17 +135,17 @@ function queueSignalNotification(signal2) {
|
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
|
-
var
|
|
138
|
+
var maxDrainIterations = 1e5;
|
|
131
139
|
function drainNotificationQueue() {
|
|
132
140
|
if (notifyDepth > 0) return;
|
|
133
141
|
notifyDepth++;
|
|
134
142
|
try {
|
|
135
143
|
let i = 0;
|
|
136
144
|
while (i < pendingQueue.length) {
|
|
137
|
-
if (i >=
|
|
145
|
+
if (i >= maxDrainIterations) {
|
|
138
146
|
if (typeof console !== "undefined") {
|
|
139
147
|
console.error(
|
|
140
|
-
`[SibuJS] Notification queue exceeded ${
|
|
148
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
141
149
|
);
|
|
142
150
|
}
|
|
143
151
|
break;
|
|
@@ -146,47 +154,52 @@ function drainNotificationQueue() {
|
|
|
146
154
|
i++;
|
|
147
155
|
}
|
|
148
156
|
} finally {
|
|
149
|
-
pendingQueue.length = 0;
|
|
150
|
-
pendingSet.clear();
|
|
151
157
|
notifyDepth--;
|
|
158
|
+
if (notifyDepth === 0) {
|
|
159
|
+
pendingQueue.length = 0;
|
|
160
|
+
pendingSet.clear();
|
|
161
|
+
}
|
|
152
162
|
}
|
|
153
163
|
}
|
|
154
164
|
function propagateDirty(sub) {
|
|
155
165
|
sub();
|
|
156
|
-
|
|
157
|
-
|
|
166
|
+
const rootSig = sub._sig;
|
|
167
|
+
if (!rootSig) return;
|
|
168
|
+
const stack = propagateStack;
|
|
169
|
+
const baseLen = stack.length;
|
|
170
|
+
stack.push(rootSig);
|
|
171
|
+
while (stack.length > baseLen) {
|
|
172
|
+
const sig = stack.pop();
|
|
158
173
|
const first = sig.__f;
|
|
159
174
|
if (first) {
|
|
160
175
|
if (first._c) {
|
|
161
176
|
const nSig = first._sig;
|
|
162
|
-
nSig._d
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (!pendingSet.has(first)) {
|
|
177
|
+
if (!nSig._d) {
|
|
178
|
+
nSig._d = true;
|
|
179
|
+
stack.push(nSig);
|
|
180
|
+
}
|
|
181
|
+
} else if (!pendingSet.has(first)) {
|
|
167
182
|
pendingSet.add(first);
|
|
168
183
|
pendingQueue.push(first);
|
|
169
184
|
}
|
|
170
|
-
|
|
185
|
+
continue;
|
|
171
186
|
}
|
|
172
187
|
const subs = sig[SUBS];
|
|
173
|
-
if (!subs)
|
|
174
|
-
let nextSig;
|
|
188
|
+
if (!subs) continue;
|
|
175
189
|
for (const s of subs) {
|
|
176
190
|
if (s._c) {
|
|
177
|
-
s();
|
|
178
191
|
const nSig = s._sig;
|
|
179
|
-
if (nSig && !
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
if (nSig && !nSig._d) {
|
|
193
|
+
nSig._d = true;
|
|
194
|
+
stack.push(nSig);
|
|
195
|
+
} else if (!nSig) {
|
|
196
|
+
s();
|
|
183
197
|
}
|
|
184
198
|
} else if (!pendingSet.has(s)) {
|
|
185
199
|
pendingSet.add(s);
|
|
186
200
|
pendingQueue.push(s);
|
|
187
201
|
}
|
|
188
202
|
}
|
|
189
|
-
sig = nextSig;
|
|
190
203
|
}
|
|
191
204
|
}
|
|
192
205
|
function notifySubscribers(signal2) {
|
|
@@ -210,13 +223,23 @@ function notifySubscribers(signal2) {
|
|
|
210
223
|
}
|
|
211
224
|
let i = 0;
|
|
212
225
|
while (i < pendingQueue.length) {
|
|
226
|
+
if (i >= maxDrainIterations) {
|
|
227
|
+
if (typeof console !== "undefined") {
|
|
228
|
+
console.error(
|
|
229
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
213
234
|
safeInvoke(pendingQueue[i]);
|
|
214
235
|
i++;
|
|
215
236
|
}
|
|
216
237
|
} finally {
|
|
217
|
-
pendingQueue.length = 0;
|
|
218
|
-
pendingSet.clear();
|
|
219
238
|
notifyDepth--;
|
|
239
|
+
if (notifyDepth === 0) {
|
|
240
|
+
pendingQueue.length = 0;
|
|
241
|
+
pendingSet.clear();
|
|
242
|
+
}
|
|
220
243
|
}
|
|
221
244
|
return;
|
|
222
245
|
}
|
|
@@ -236,30 +259,48 @@ function notifySubscribers(signal2) {
|
|
|
236
259
|
notifyDepth++;
|
|
237
260
|
try {
|
|
238
261
|
let directCount = 0;
|
|
262
|
+
let hasComputedSub = false;
|
|
239
263
|
for (const sub of subs) {
|
|
264
|
+
if (sub._c) hasComputedSub = true;
|
|
240
265
|
pendingQueue[directCount++] = sub;
|
|
241
266
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
267
|
+
if (!hasComputedSub) {
|
|
268
|
+
for (let i2 = 0; i2 < directCount; i2++) {
|
|
269
|
+
safeInvoke(pendingQueue[i2]);
|
|
245
270
|
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
271
|
+
} else {
|
|
272
|
+
for (let i2 = 0; i2 < directCount; i2++) {
|
|
273
|
+
if (pendingQueue[i2]._c) {
|
|
274
|
+
propagateDirty(pendingQueue[i2]);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
for (let i2 = 0; i2 < directCount; i2++) {
|
|
278
|
+
const sub = pendingQueue[i2];
|
|
279
|
+
if (!sub._c && !pendingSet.has(sub)) {
|
|
280
|
+
pendingSet.add(sub);
|
|
281
|
+
safeInvoke(sub);
|
|
251
282
|
}
|
|
252
283
|
}
|
|
253
284
|
}
|
|
254
285
|
let i = directCount;
|
|
255
286
|
while (i < pendingQueue.length) {
|
|
287
|
+
if (i - directCount >= maxDrainIterations) {
|
|
288
|
+
if (typeof console !== "undefined") {
|
|
289
|
+
console.error(
|
|
290
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
256
295
|
safeInvoke(pendingQueue[i]);
|
|
257
296
|
i++;
|
|
258
297
|
}
|
|
259
298
|
} finally {
|
|
260
|
-
pendingQueue.length = 0;
|
|
261
|
-
pendingSet.clear();
|
|
262
299
|
notifyDepth--;
|
|
300
|
+
if (notifyDepth === 0) {
|
|
301
|
+
pendingQueue.length = 0;
|
|
302
|
+
pendingSet.clear();
|
|
303
|
+
}
|
|
263
304
|
}
|
|
264
305
|
}
|
|
265
306
|
function cleanup(subscriber) {
|
|
@@ -270,7 +311,9 @@ function cleanup(subscriber) {
|
|
|
270
311
|
if (subs) {
|
|
271
312
|
subs.delete(subscriber);
|
|
272
313
|
if (singleDep.__f === subscriber) {
|
|
273
|
-
singleDep.__f = void 0;
|
|
314
|
+
singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
315
|
+
} else if (subs.size === 1 && singleDep.__f === void 0) {
|
|
316
|
+
singleDep.__f = subs.values().next().value;
|
|
274
317
|
}
|
|
275
318
|
}
|
|
276
319
|
sub._dep = void 0;
|
|
@@ -283,7 +326,9 @@ function cleanup(subscriber) {
|
|
|
283
326
|
if (subs) {
|
|
284
327
|
subs.delete(subscriber);
|
|
285
328
|
if (signal2.__f === subscriber) {
|
|
286
|
-
signal2.__f = void 0;
|
|
329
|
+
signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
330
|
+
} else if (subs.size === 1 && signal2.__f === void 0) {
|
|
331
|
+
signal2.__f = subs.values().next().value;
|
|
287
332
|
}
|
|
288
333
|
}
|
|
289
334
|
}
|
|
@@ -294,6 +339,7 @@ function cleanup(subscriber) {
|
|
|
294
339
|
function derived(getter, options) {
|
|
295
340
|
devAssert(typeof getter === "function", "derived: argument must be a getter function.");
|
|
296
341
|
const debugName = options?.name;
|
|
342
|
+
const equals = options?.equals;
|
|
297
343
|
const cs = {};
|
|
298
344
|
cs._d = false;
|
|
299
345
|
cs._g = getter;
|
|
@@ -304,8 +350,14 @@ function derived(getter, options) {
|
|
|
304
350
|
markDirty._c = 1;
|
|
305
351
|
markDirty._sig = cs;
|
|
306
352
|
track(() => {
|
|
307
|
-
|
|
308
|
-
|
|
353
|
+
let threw = true;
|
|
354
|
+
try {
|
|
355
|
+
cs._v = getter();
|
|
356
|
+
cs._d = false;
|
|
357
|
+
threw = false;
|
|
358
|
+
} finally {
|
|
359
|
+
if (threw) cs._d = true;
|
|
360
|
+
}
|
|
309
361
|
}, markDirty);
|
|
310
362
|
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
311
363
|
let evaluating = false;
|
|
@@ -318,11 +370,16 @@ function derived(getter, options) {
|
|
|
318
370
|
if (trackingSuspended) {
|
|
319
371
|
if (cs._d) {
|
|
320
372
|
evaluating = true;
|
|
373
|
+
let threw = true;
|
|
321
374
|
try {
|
|
322
|
-
|
|
323
|
-
|
|
375
|
+
retrack(() => {
|
|
376
|
+
cs._v = getter();
|
|
377
|
+
cs._d = false;
|
|
378
|
+
threw = false;
|
|
379
|
+
}, markDirty);
|
|
324
380
|
} finally {
|
|
325
381
|
evaluating = false;
|
|
382
|
+
if (threw) cs._d = true;
|
|
326
383
|
}
|
|
327
384
|
}
|
|
328
385
|
return cs._v;
|
|
@@ -331,13 +388,17 @@ function derived(getter, options) {
|
|
|
331
388
|
if (cs._d) {
|
|
332
389
|
const oldValue = cs._v;
|
|
333
390
|
evaluating = true;
|
|
391
|
+
let threw = true;
|
|
334
392
|
try {
|
|
335
|
-
|
|
393
|
+
retrack(() => {
|
|
394
|
+
const next = getter();
|
|
395
|
+
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
336
396
|
cs._d = false;
|
|
337
|
-
|
|
397
|
+
threw = false;
|
|
338
398
|
}, markDirty);
|
|
339
399
|
} finally {
|
|
340
400
|
evaluating = false;
|
|
401
|
+
if (threw) cs._d = true;
|
|
341
402
|
}
|
|
342
403
|
if (hook && oldValue !== cs._v) {
|
|
343
404
|
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
@@ -354,6 +415,121 @@ function derived(getter, options) {
|
|
|
354
415
|
return computedGetter;
|
|
355
416
|
}
|
|
356
417
|
|
|
418
|
+
// src/core/ssr-context.ts
|
|
419
|
+
var als = null;
|
|
420
|
+
try {
|
|
421
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
422
|
+
const req = Function("return typeof require==='function'?require:null")();
|
|
423
|
+
if (req) {
|
|
424
|
+
const mod = req("node:async_hooks");
|
|
425
|
+
als = new mod.AsyncLocalStorage();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
} catch {
|
|
429
|
+
als = null;
|
|
430
|
+
}
|
|
431
|
+
var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
|
|
432
|
+
function getSSRStore() {
|
|
433
|
+
if (als) {
|
|
434
|
+
const s = als.getStore();
|
|
435
|
+
if (s) return s;
|
|
436
|
+
}
|
|
437
|
+
return fallbackStore;
|
|
438
|
+
}
|
|
439
|
+
function isSSR() {
|
|
440
|
+
return getSSRStore().ssr;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/core/signals/effect.ts
|
|
444
|
+
var _g = globalThis;
|
|
445
|
+
function effect(effectFn, options) {
|
|
446
|
+
devAssert(typeof effectFn === "function", "effect: argument must be a function.");
|
|
447
|
+
if (isSSR()) return () => {
|
|
448
|
+
};
|
|
449
|
+
const onError = options?.onError;
|
|
450
|
+
let userCleanups = [];
|
|
451
|
+
const onCleanup = (fn) => {
|
|
452
|
+
userCleanups.push(fn);
|
|
453
|
+
};
|
|
454
|
+
const runUserCleanups = () => {
|
|
455
|
+
if (userCleanups.length === 0) return;
|
|
456
|
+
const list = userCleanups;
|
|
457
|
+
userCleanups = [];
|
|
458
|
+
for (let i = list.length - 1; i >= 0; i--) {
|
|
459
|
+
try {
|
|
460
|
+
list[i]();
|
|
461
|
+
} catch (err) {
|
|
462
|
+
if (typeof console !== "undefined") {
|
|
463
|
+
console.warn("[SibuJS effect] onCleanup threw:", err);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
const invokeBody = () => effectFn(onCleanup);
|
|
469
|
+
const wrappedFn = onError ? () => {
|
|
470
|
+
try {
|
|
471
|
+
invokeBody();
|
|
472
|
+
} catch (err) {
|
|
473
|
+
onError(err);
|
|
474
|
+
}
|
|
475
|
+
} : invokeBody;
|
|
476
|
+
let cleanupHandle = () => {
|
|
477
|
+
};
|
|
478
|
+
let running = false;
|
|
479
|
+
const subscriber = () => {
|
|
480
|
+
if (running) {
|
|
481
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
482
|
+
console.warn(
|
|
483
|
+
"[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
running = true;
|
|
489
|
+
try {
|
|
490
|
+
runUserCleanups();
|
|
491
|
+
cleanupHandle();
|
|
492
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
493
|
+
} finally {
|
|
494
|
+
running = false;
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
running = true;
|
|
498
|
+
try {
|
|
499
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
500
|
+
} finally {
|
|
501
|
+
running = false;
|
|
502
|
+
}
|
|
503
|
+
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
504
|
+
if (hook) hook.emit("effect:create", { effectFn });
|
|
505
|
+
let disposed = false;
|
|
506
|
+
return () => {
|
|
507
|
+
if (disposed) return;
|
|
508
|
+
disposed = true;
|
|
509
|
+
const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
510
|
+
if (h) {
|
|
511
|
+
try {
|
|
512
|
+
h.emit("effect:destroy", { effectFn });
|
|
513
|
+
} catch {
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
try {
|
|
517
|
+
runUserCleanups();
|
|
518
|
+
} catch (err) {
|
|
519
|
+
if (typeof console !== "undefined") {
|
|
520
|
+
console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
try {
|
|
524
|
+
cleanupHandle();
|
|
525
|
+
} catch (err) {
|
|
526
|
+
if (typeof console !== "undefined") {
|
|
527
|
+
console.warn("[SibuJS effect] dispose threw:", err);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
357
533
|
// src/reactivity/batch.ts
|
|
358
534
|
var batchDepth = 0;
|
|
359
535
|
var pendingSignals = /* @__PURE__ */ new Set();
|
|
@@ -374,15 +550,18 @@ function enqueueBatchedSignal(signal2) {
|
|
|
374
550
|
return true;
|
|
375
551
|
}
|
|
376
552
|
function flushBatch() {
|
|
377
|
-
|
|
378
|
-
|
|
553
|
+
try {
|
|
554
|
+
for (const signal2 of pendingSignals) {
|
|
555
|
+
queueSignalNotification(signal2);
|
|
556
|
+
}
|
|
557
|
+
} finally {
|
|
558
|
+
pendingSignals.clear();
|
|
379
559
|
}
|
|
380
|
-
pendingSignals.clear();
|
|
381
560
|
drainNotificationQueue();
|
|
382
561
|
}
|
|
383
562
|
|
|
384
563
|
// src/core/signals/signal.ts
|
|
385
|
-
var
|
|
564
|
+
var _g2 = globalThis;
|
|
386
565
|
var _isDev3 = isDev();
|
|
387
566
|
function signal(initial, options) {
|
|
388
567
|
const state = { value: initial };
|
|
@@ -403,7 +582,7 @@ function signal(initial, options) {
|
|
|
403
582
|
if (_isDev3) {
|
|
404
583
|
const oldValue = state.value;
|
|
405
584
|
state.value = newValue;
|
|
406
|
-
const hook =
|
|
585
|
+
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
407
586
|
if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
|
|
408
587
|
} else {
|
|
409
588
|
state.value = newValue;
|
|
@@ -413,18 +592,12 @@ function signal(initial, options) {
|
|
|
413
592
|
}
|
|
414
593
|
}
|
|
415
594
|
if (_isDev3) {
|
|
416
|
-
const hook =
|
|
595
|
+
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
417
596
|
if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
|
|
418
597
|
}
|
|
419
598
|
return [get, set];
|
|
420
599
|
}
|
|
421
600
|
|
|
422
|
-
// src/core/ssr-context.ts
|
|
423
|
-
var ssrMode = false;
|
|
424
|
-
function isSSR() {
|
|
425
|
-
return ssrMode;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
601
|
// src/core/signals/watch.ts
|
|
429
602
|
function watch(getter, callback) {
|
|
430
603
|
devAssert(typeof getter === "function", "watch: first argument must be a getter function.");
|
|
@@ -450,6 +623,8 @@ function watch(getter, callback) {
|
|
|
450
623
|
}
|
|
451
624
|
|
|
452
625
|
// src/widgets/Combobox.ts
|
|
626
|
+
var comboboxIdCounter = 0;
|
|
627
|
+
var boundComboboxes = /* @__PURE__ */ new WeakMap();
|
|
453
628
|
function combobox(options) {
|
|
454
629
|
const { items, filterFn, itemToString } = options;
|
|
455
630
|
const defaultFilterFn = (item, q) => {
|
|
@@ -506,6 +681,92 @@ function combobox(options) {
|
|
|
506
681
|
function close() {
|
|
507
682
|
setIsOpen(false);
|
|
508
683
|
}
|
|
684
|
+
function bind(els) {
|
|
685
|
+
const existing = boundComboboxes.get(els.input);
|
|
686
|
+
if (existing) return existing;
|
|
687
|
+
const listboxId = `sibu-combobox-listbox-${++comboboxIdCounter}`;
|
|
688
|
+
els.listbox.id = listboxId;
|
|
689
|
+
els.listbox.setAttribute("role", "listbox");
|
|
690
|
+
els.input.setAttribute("role", "combobox");
|
|
691
|
+
els.input.setAttribute("aria-autocomplete", "list");
|
|
692
|
+
els.input.setAttribute("aria-controls", listboxId);
|
|
693
|
+
const fxTeardown = effect(() => {
|
|
694
|
+
const open2 = isOpen();
|
|
695
|
+
els.input.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
696
|
+
els.listbox.hidden = !open2;
|
|
697
|
+
const idx = highlightedIndex();
|
|
698
|
+
const filtered = filteredItems();
|
|
699
|
+
let activeId = "";
|
|
700
|
+
for (let i = 0; i < filtered.length; i++) {
|
|
701
|
+
const optEl = els.option(filtered[i], i);
|
|
702
|
+
if (!optEl) continue;
|
|
703
|
+
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
704
|
+
optEl.setAttribute("role", "option");
|
|
705
|
+
const isHighlighted = i === idx;
|
|
706
|
+
optEl.setAttribute("aria-selected", isHighlighted ? "true" : "false");
|
|
707
|
+
if (isHighlighted) activeId = optEl.id;
|
|
708
|
+
}
|
|
709
|
+
if (activeId) els.input.setAttribute("aria-activedescendant", activeId);
|
|
710
|
+
else els.input.removeAttribute("aria-activedescendant");
|
|
711
|
+
});
|
|
712
|
+
const onInput = () => {
|
|
713
|
+
setQuery(els.input.value);
|
|
714
|
+
open();
|
|
715
|
+
};
|
|
716
|
+
const onKey = (e) => {
|
|
717
|
+
if (e.key === "ArrowDown") {
|
|
718
|
+
e.preventDefault();
|
|
719
|
+
if (!isOpen()) open();
|
|
720
|
+
highlightNext();
|
|
721
|
+
} else if (e.key === "ArrowUp") {
|
|
722
|
+
e.preventDefault();
|
|
723
|
+
if (!isOpen()) open();
|
|
724
|
+
highlightPrev();
|
|
725
|
+
} else if (e.key === "Enter") {
|
|
726
|
+
if (highlightedIndex() >= 0) {
|
|
727
|
+
e.preventDefault();
|
|
728
|
+
selectHighlighted();
|
|
729
|
+
}
|
|
730
|
+
} else if (e.key === "Escape") {
|
|
731
|
+
e.preventDefault();
|
|
732
|
+
close();
|
|
733
|
+
} else if (e.key === "Home") {
|
|
734
|
+
e.preventDefault();
|
|
735
|
+
if (filteredItems().length > 0) setHighlightedIndex(0);
|
|
736
|
+
} else if (e.key === "End") {
|
|
737
|
+
e.preventDefault();
|
|
738
|
+
const len = filteredItems().length;
|
|
739
|
+
if (len > 0) setHighlightedIndex(len - 1);
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
let blurTimer = null;
|
|
743
|
+
const onFocus = () => open();
|
|
744
|
+
const onBlur = () => {
|
|
745
|
+
if (blurTimer !== null) clearTimeout(blurTimer);
|
|
746
|
+
blurTimer = setTimeout(() => {
|
|
747
|
+
blurTimer = null;
|
|
748
|
+
if (document.activeElement !== els.input) close();
|
|
749
|
+
}, 100);
|
|
750
|
+
};
|
|
751
|
+
els.input.addEventListener("input", onInput);
|
|
752
|
+
els.input.addEventListener("keydown", onKey);
|
|
753
|
+
els.input.addEventListener("focus", onFocus);
|
|
754
|
+
els.input.addEventListener("blur", onBlur);
|
|
755
|
+
const teardown = () => {
|
|
756
|
+
boundComboboxes.delete(els.input);
|
|
757
|
+
fxTeardown();
|
|
758
|
+
els.input.removeEventListener("input", onInput);
|
|
759
|
+
els.input.removeEventListener("keydown", onKey);
|
|
760
|
+
els.input.removeEventListener("focus", onFocus);
|
|
761
|
+
els.input.removeEventListener("blur", onBlur);
|
|
762
|
+
if (blurTimer !== null) {
|
|
763
|
+
clearTimeout(blurTimer);
|
|
764
|
+
blurTimer = null;
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
boundComboboxes.set(els.input, teardown);
|
|
768
|
+
return teardown;
|
|
769
|
+
}
|
|
509
770
|
return {
|
|
510
771
|
query,
|
|
511
772
|
setQuery,
|
|
@@ -518,11 +779,13 @@ function combobox(options) {
|
|
|
518
779
|
selectHighlighted,
|
|
519
780
|
isOpen,
|
|
520
781
|
open,
|
|
521
|
-
close
|
|
782
|
+
close,
|
|
783
|
+
bind
|
|
522
784
|
};
|
|
523
785
|
}
|
|
524
786
|
|
|
525
787
|
// src/widgets/Tabs.ts
|
|
788
|
+
var boundTablists = /* @__PURE__ */ new WeakMap();
|
|
526
789
|
function tabs(options) {
|
|
527
790
|
const { tabs: tabDefs, defaultTab } = options;
|
|
528
791
|
const initialTab = defaultTab ?? tabDefs.find((t) => !t.disabled)?.id ?? tabDefs[0]?.id ?? "";
|
|
@@ -569,6 +832,118 @@ function tabs(options) {
|
|
|
569
832
|
function isActive(id) {
|
|
570
833
|
return activeTab() === id;
|
|
571
834
|
}
|
|
835
|
+
function bind(els) {
|
|
836
|
+
const existing = boundTablists.get(els.tablist);
|
|
837
|
+
if (existing) return existing;
|
|
838
|
+
const restore = [];
|
|
839
|
+
const prevTablistRole = els.tablist.getAttribute("role");
|
|
840
|
+
els.tablist.setAttribute("role", "tablist");
|
|
841
|
+
restore.push(() => {
|
|
842
|
+
if (prevTablistRole === null) els.tablist.removeAttribute("role");
|
|
843
|
+
else els.tablist.setAttribute("role", prevTablistRole);
|
|
844
|
+
});
|
|
845
|
+
for (const def of tabDefs) {
|
|
846
|
+
const tabEl = els.tabs[def.id];
|
|
847
|
+
if (!tabEl) continue;
|
|
848
|
+
const prevRole = tabEl.getAttribute("role");
|
|
849
|
+
const prevId = tabEl.id;
|
|
850
|
+
const prevDisabled = tabEl.getAttribute("aria-disabled");
|
|
851
|
+
const prevControls = tabEl.getAttribute("aria-controls");
|
|
852
|
+
tabEl.setAttribute("role", "tab");
|
|
853
|
+
tabEl.setAttribute("id", `sibu-tab-${def.id}`);
|
|
854
|
+
if (def.disabled) tabEl.setAttribute("aria-disabled", "true");
|
|
855
|
+
const panelEl = els.panels?.[def.id];
|
|
856
|
+
let prevPanelRole = null;
|
|
857
|
+
let prevPanelId = "";
|
|
858
|
+
let prevPanelLabelledBy = null;
|
|
859
|
+
if (panelEl) {
|
|
860
|
+
prevPanelRole = panelEl.getAttribute("role");
|
|
861
|
+
prevPanelId = panelEl.id;
|
|
862
|
+
prevPanelLabelledBy = panelEl.getAttribute("aria-labelledby");
|
|
863
|
+
panelEl.setAttribute("role", "tabpanel");
|
|
864
|
+
panelEl.setAttribute("id", `sibu-tabpanel-${def.id}`);
|
|
865
|
+
panelEl.setAttribute("aria-labelledby", `sibu-tab-${def.id}`);
|
|
866
|
+
tabEl.setAttribute("aria-controls", `sibu-tabpanel-${def.id}`);
|
|
867
|
+
}
|
|
868
|
+
restore.push(() => {
|
|
869
|
+
if (prevRole === null) tabEl.removeAttribute("role");
|
|
870
|
+
else tabEl.setAttribute("role", prevRole);
|
|
871
|
+
if (prevId === "") tabEl.removeAttribute("id");
|
|
872
|
+
else tabEl.id = prevId;
|
|
873
|
+
if (prevDisabled === null) tabEl.removeAttribute("aria-disabled");
|
|
874
|
+
else tabEl.setAttribute("aria-disabled", prevDisabled);
|
|
875
|
+
if (prevControls === null) tabEl.removeAttribute("aria-controls");
|
|
876
|
+
else tabEl.setAttribute("aria-controls", prevControls);
|
|
877
|
+
tabEl.removeAttribute("aria-selected");
|
|
878
|
+
tabEl.removeAttribute("tabindex");
|
|
879
|
+
if (panelEl) {
|
|
880
|
+
if (prevPanelRole === null) panelEl.removeAttribute("role");
|
|
881
|
+
else panelEl.setAttribute("role", prevPanelRole);
|
|
882
|
+
if (prevPanelId === "") panelEl.removeAttribute("id");
|
|
883
|
+
else panelEl.id = prevPanelId;
|
|
884
|
+
if (prevPanelLabelledBy === null) panelEl.removeAttribute("aria-labelledby");
|
|
885
|
+
else panelEl.setAttribute("aria-labelledby", prevPanelLabelledBy);
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
const fxTeardown = effect(() => {
|
|
890
|
+
const active = activeTab();
|
|
891
|
+
for (const def of tabDefs) {
|
|
892
|
+
const tabEl = els.tabs[def.id];
|
|
893
|
+
if (!tabEl) continue;
|
|
894
|
+
const isAct = def.id === active;
|
|
895
|
+
tabEl.setAttribute("aria-selected", isAct ? "true" : "false");
|
|
896
|
+
tabEl.tabIndex = isAct ? 0 : -1;
|
|
897
|
+
const panelEl = els.panels?.[def.id];
|
|
898
|
+
if (panelEl) panelEl.hidden = !isAct;
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
const onKey = (e) => {
|
|
902
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
903
|
+
e.preventDefault();
|
|
904
|
+
nextTab();
|
|
905
|
+
els.tabs[activeTab()]?.focus();
|
|
906
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
907
|
+
e.preventDefault();
|
|
908
|
+
prevTab();
|
|
909
|
+
els.tabs[activeTab()]?.focus();
|
|
910
|
+
} else if (e.key === "Home") {
|
|
911
|
+
e.preventDefault();
|
|
912
|
+
const first = tabDefs.find((t) => !t.disabled);
|
|
913
|
+
if (first) {
|
|
914
|
+
setActiveTabState(first.id);
|
|
915
|
+
els.tabs[first.id]?.focus();
|
|
916
|
+
}
|
|
917
|
+
} else if (e.key === "End") {
|
|
918
|
+
e.preventDefault();
|
|
919
|
+
for (let i = tabDefs.length - 1; i >= 0; i--) {
|
|
920
|
+
if (!tabDefs[i].disabled) {
|
|
921
|
+
setActiveTabState(tabDefs[i].id);
|
|
922
|
+
els.tabs[tabDefs[i].id]?.focus();
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
els.tablist.addEventListener("keydown", onKey);
|
|
929
|
+
const clickHandlers = [];
|
|
930
|
+
for (const def of tabDefs) {
|
|
931
|
+
const tabEl = els.tabs[def.id];
|
|
932
|
+
if (!tabEl) continue;
|
|
933
|
+
const fn = () => setActiveTab(def.id);
|
|
934
|
+
tabEl.addEventListener("click", fn);
|
|
935
|
+
clickHandlers.push({ el: tabEl, fn });
|
|
936
|
+
}
|
|
937
|
+
const teardown = () => {
|
|
938
|
+
boundTablists.delete(els.tablist);
|
|
939
|
+
fxTeardown();
|
|
940
|
+
els.tablist.removeEventListener("keydown", onKey);
|
|
941
|
+
for (const { el, fn } of clickHandlers) el.removeEventListener("click", fn);
|
|
942
|
+
for (const r of restore) r();
|
|
943
|
+
};
|
|
944
|
+
boundTablists.set(els.tablist, teardown);
|
|
945
|
+
return teardown;
|
|
946
|
+
}
|
|
572
947
|
return {
|
|
573
948
|
activeTab,
|
|
574
949
|
setActiveTab,
|
|
@@ -576,11 +951,13 @@ function tabs(options) {
|
|
|
576
951
|
nextTab,
|
|
577
952
|
prevTab,
|
|
578
953
|
/** Reactive check — use inside class/nodes bindings for per-tab reactivity */
|
|
579
|
-
isActive
|
|
954
|
+
isActive,
|
|
955
|
+
bind
|
|
580
956
|
};
|
|
581
957
|
}
|
|
582
958
|
|
|
583
959
|
// src/widgets/Accordion.ts
|
|
960
|
+
var boundAccordions = /* @__PURE__ */ new WeakMap();
|
|
584
961
|
function accordion(options) {
|
|
585
962
|
const { items: itemDefs, multiple = false, defaultExpanded = [] } = options;
|
|
586
963
|
const [expandedIds, setExpandedIds] = signal(new Set(defaultExpanded));
|
|
@@ -627,6 +1004,86 @@ function accordion(options) {
|
|
|
627
1004
|
function isExpanded(id) {
|
|
628
1005
|
return expandedIds().has(id);
|
|
629
1006
|
}
|
|
1007
|
+
function bind(els) {
|
|
1008
|
+
const idempotencyKey = els.root ?? (itemDefs.length > 0 ? els.triggers[itemDefs[0].id] : void 0);
|
|
1009
|
+
if (idempotencyKey) {
|
|
1010
|
+
const existing = boundAccordions.get(idempotencyKey);
|
|
1011
|
+
if (existing) return existing;
|
|
1012
|
+
}
|
|
1013
|
+
const restore = [];
|
|
1014
|
+
for (const item of itemDefs) {
|
|
1015
|
+
const trig = els.triggers[item.id];
|
|
1016
|
+
const panel = els.panels[item.id];
|
|
1017
|
+
if (!trig) continue;
|
|
1018
|
+
const prevTrigId = trig.id;
|
|
1019
|
+
const prevTrigControls = trig.getAttribute("aria-controls");
|
|
1020
|
+
trig.id = `sibu-accordion-trigger-${item.id}`;
|
|
1021
|
+
let prevPanelRole = null;
|
|
1022
|
+
let prevPanelId = "";
|
|
1023
|
+
let prevPanelLabelledBy = null;
|
|
1024
|
+
if (panel) {
|
|
1025
|
+
prevPanelRole = panel.getAttribute("role");
|
|
1026
|
+
prevPanelId = panel.id;
|
|
1027
|
+
prevPanelLabelledBy = panel.getAttribute("aria-labelledby");
|
|
1028
|
+
panel.setAttribute("role", "region");
|
|
1029
|
+
panel.id = `sibu-accordion-panel-${item.id}`;
|
|
1030
|
+
panel.setAttribute("aria-labelledby", trig.id);
|
|
1031
|
+
trig.setAttribute("aria-controls", panel.id);
|
|
1032
|
+
}
|
|
1033
|
+
restore.push(() => {
|
|
1034
|
+
if (prevTrigId === "") trig.removeAttribute("id");
|
|
1035
|
+
else trig.id = prevTrigId;
|
|
1036
|
+
if (prevTrigControls === null) trig.removeAttribute("aria-controls");
|
|
1037
|
+
else trig.setAttribute("aria-controls", prevTrigControls);
|
|
1038
|
+
trig.removeAttribute("aria-expanded");
|
|
1039
|
+
if (panel) {
|
|
1040
|
+
if (prevPanelRole === null) panel.removeAttribute("role");
|
|
1041
|
+
else panel.setAttribute("role", prevPanelRole);
|
|
1042
|
+
if (prevPanelId === "") panel.removeAttribute("id");
|
|
1043
|
+
else panel.id = prevPanelId;
|
|
1044
|
+
if (prevPanelLabelledBy === null) panel.removeAttribute("aria-labelledby");
|
|
1045
|
+
else panel.setAttribute("aria-labelledby", prevPanelLabelledBy);
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
const fxTeardown = effect(() => {
|
|
1050
|
+
const ids = expandedIds();
|
|
1051
|
+
for (const item of itemDefs) {
|
|
1052
|
+
const trig = els.triggers[item.id];
|
|
1053
|
+
const panel = els.panels[item.id];
|
|
1054
|
+
if (!trig) continue;
|
|
1055
|
+
const expanded = ids.has(item.id);
|
|
1056
|
+
trig.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
1057
|
+
if (panel) panel.hidden = !expanded;
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
const handlers = [];
|
|
1061
|
+
for (const item of itemDefs) {
|
|
1062
|
+
const trig = els.triggers[item.id];
|
|
1063
|
+
if (!trig) continue;
|
|
1064
|
+
const click = () => toggle(item.id);
|
|
1065
|
+
const key = (e) => {
|
|
1066
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1067
|
+
e.preventDefault();
|
|
1068
|
+
toggle(item.id);
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
trig.addEventListener("click", click);
|
|
1072
|
+
trig.addEventListener("keydown", key);
|
|
1073
|
+
handlers.push({ el: trig, click, key });
|
|
1074
|
+
}
|
|
1075
|
+
const teardown = () => {
|
|
1076
|
+
if (idempotencyKey) boundAccordions.delete(idempotencyKey);
|
|
1077
|
+
fxTeardown();
|
|
1078
|
+
for (const { el, click, key } of handlers) {
|
|
1079
|
+
el.removeEventListener("click", click);
|
|
1080
|
+
el.removeEventListener("keydown", key);
|
|
1081
|
+
}
|
|
1082
|
+
for (const r of restore) r();
|
|
1083
|
+
};
|
|
1084
|
+
if (idempotencyKey) boundAccordions.set(idempotencyKey, teardown);
|
|
1085
|
+
return teardown;
|
|
1086
|
+
}
|
|
630
1087
|
return {
|
|
631
1088
|
items,
|
|
632
1089
|
toggle,
|
|
@@ -635,11 +1092,14 @@ function accordion(options) {
|
|
|
635
1092
|
expandAll,
|
|
636
1093
|
collapseAll,
|
|
637
1094
|
/** Reactive check — use inside class/nodes bindings for per-item reactivity */
|
|
638
|
-
isExpanded
|
|
1095
|
+
isExpanded,
|
|
1096
|
+
bind
|
|
639
1097
|
};
|
|
640
1098
|
}
|
|
641
1099
|
|
|
642
1100
|
// src/widgets/Popover.ts
|
|
1101
|
+
var popoverIdCounter = 0;
|
|
1102
|
+
var boundPopovers = /* @__PURE__ */ new WeakMap();
|
|
643
1103
|
function popover() {
|
|
644
1104
|
const [isOpen, setIsOpen] = signal(false);
|
|
645
1105
|
function open() {
|
|
@@ -651,12 +1111,88 @@ function popover() {
|
|
|
651
1111
|
function toggle() {
|
|
652
1112
|
setIsOpen((prev) => !prev);
|
|
653
1113
|
}
|
|
654
|
-
|
|
1114
|
+
function bind(els) {
|
|
1115
|
+
const existing = boundPopovers.get(els.trigger);
|
|
1116
|
+
if (existing) return existing;
|
|
1117
|
+
const id = `sibu-popover-${++popoverIdCounter}`;
|
|
1118
|
+
const prevPopoverRole = els.popover.getAttribute("role");
|
|
1119
|
+
const prevPopoverId = els.popover.id;
|
|
1120
|
+
const prevLabelledBy = els.popover.getAttribute("aria-labelledby");
|
|
1121
|
+
const prevTriggerHaspopup = els.trigger.getAttribute("aria-haspopup");
|
|
1122
|
+
const prevTriggerControls = els.trigger.getAttribute("aria-controls");
|
|
1123
|
+
els.popover.setAttribute("role", "dialog");
|
|
1124
|
+
els.popover.id = id;
|
|
1125
|
+
els.trigger.setAttribute("aria-haspopup", "dialog");
|
|
1126
|
+
els.trigger.setAttribute("aria-controls", id);
|
|
1127
|
+
let assignedLabelId = null;
|
|
1128
|
+
if (els.labelledBy) {
|
|
1129
|
+
if (!els.labelledBy.id) {
|
|
1130
|
+
els.labelledBy.id = `${id}-label`;
|
|
1131
|
+
assignedLabelId = els.labelledBy.id;
|
|
1132
|
+
}
|
|
1133
|
+
els.popover.setAttribute("aria-labelledby", els.labelledBy.id);
|
|
1134
|
+
}
|
|
1135
|
+
const fxTeardown = effect(() => {
|
|
1136
|
+
const open2 = isOpen();
|
|
1137
|
+
els.trigger.setAttribute("aria-expanded", open2 ? "true" : "false");
|
|
1138
|
+
els.popover.hidden = !open2;
|
|
1139
|
+
});
|
|
1140
|
+
const onTriggerClick = (e) => {
|
|
1141
|
+
e.preventDefault();
|
|
1142
|
+
toggle();
|
|
1143
|
+
};
|
|
1144
|
+
const onKey = (e) => {
|
|
1145
|
+
if (e.key === "Escape" && isOpen()) {
|
|
1146
|
+
e.stopPropagation();
|
|
1147
|
+
close();
|
|
1148
|
+
els.trigger.focus();
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
const onDocPointer = (e) => {
|
|
1152
|
+
if (!isOpen()) return;
|
|
1153
|
+
const t = e.target;
|
|
1154
|
+
if (!t) return;
|
|
1155
|
+
if (els.trigger.contains(t) || els.popover.contains(t)) return;
|
|
1156
|
+
close();
|
|
1157
|
+
};
|
|
1158
|
+
els.trigger.addEventListener("click", onTriggerClick);
|
|
1159
|
+
els.popover.addEventListener("keydown", onKey);
|
|
1160
|
+
els.trigger.addEventListener("keydown", onKey);
|
|
1161
|
+
document.addEventListener("pointerdown", onDocPointer);
|
|
1162
|
+
const teardown = () => {
|
|
1163
|
+
boundPopovers.delete(els.trigger);
|
|
1164
|
+
fxTeardown();
|
|
1165
|
+
els.trigger.removeEventListener("click", onTriggerClick);
|
|
1166
|
+
els.popover.removeEventListener("keydown", onKey);
|
|
1167
|
+
els.trigger.removeEventListener("keydown", onKey);
|
|
1168
|
+
document.removeEventListener("pointerdown", onDocPointer);
|
|
1169
|
+
if (prevPopoverRole === null) els.popover.removeAttribute("role");
|
|
1170
|
+
else els.popover.setAttribute("role", prevPopoverRole);
|
|
1171
|
+
if (prevPopoverId === "") els.popover.removeAttribute("id");
|
|
1172
|
+
else els.popover.id = prevPopoverId;
|
|
1173
|
+
if (prevLabelledBy === null) els.popover.removeAttribute("aria-labelledby");
|
|
1174
|
+
else els.popover.setAttribute("aria-labelledby", prevLabelledBy);
|
|
1175
|
+
if (assignedLabelId && els.labelledBy?.id === assignedLabelId) {
|
|
1176
|
+
els.labelledBy.removeAttribute("id");
|
|
1177
|
+
}
|
|
1178
|
+
if (prevTriggerHaspopup === null) els.trigger.removeAttribute("aria-haspopup");
|
|
1179
|
+
else els.trigger.setAttribute("aria-haspopup", prevTriggerHaspopup);
|
|
1180
|
+
if (prevTriggerControls === null) els.trigger.removeAttribute("aria-controls");
|
|
1181
|
+
else els.trigger.setAttribute("aria-controls", prevTriggerControls);
|
|
1182
|
+
els.trigger.removeAttribute("aria-expanded");
|
|
1183
|
+
};
|
|
1184
|
+
boundPopovers.set(els.trigger, teardown);
|
|
1185
|
+
return teardown;
|
|
1186
|
+
}
|
|
1187
|
+
return { isOpen, open, close, toggle, bind };
|
|
655
1188
|
}
|
|
656
1189
|
|
|
657
1190
|
// src/widgets/Select.ts
|
|
1191
|
+
var selectIdCounter = 0;
|
|
1192
|
+
var boundSelects = /* @__PURE__ */ new WeakMap();
|
|
658
1193
|
function select(options) {
|
|
659
|
-
const { items, multiple = false } = options;
|
|
1194
|
+
const { items, multiple = false, itemToString, isDisabled } = options;
|
|
1195
|
+
const isItemDisabled = isDisabled ?? (() => false);
|
|
660
1196
|
const [selectedItems, setSelectedItems] = signal([]);
|
|
661
1197
|
const [isOpen, setIsOpen] = signal(false);
|
|
662
1198
|
const [highlightedIndex, setHighlightedIndex] = signal(-1);
|
|
@@ -665,6 +1201,7 @@ function select(options) {
|
|
|
665
1201
|
return sel.length > 0 ? sel[sel.length - 1] : null;
|
|
666
1202
|
});
|
|
667
1203
|
function select2(item) {
|
|
1204
|
+
if (isItemDisabled(item)) return;
|
|
668
1205
|
if (multiple) {
|
|
669
1206
|
setSelectedItems((prev) => {
|
|
670
1207
|
if (prev.includes(item)) return prev;
|
|
@@ -696,18 +1233,28 @@ function select(options) {
|
|
|
696
1233
|
function close() {
|
|
697
1234
|
setIsOpen(false);
|
|
698
1235
|
}
|
|
1236
|
+
function nextEnabled(from, dir) {
|
|
1237
|
+
const len = items.length;
|
|
1238
|
+
if (len === 0) return -1;
|
|
1239
|
+
let i = from;
|
|
1240
|
+
for (let n = 0; n < len; n++) {
|
|
1241
|
+
i = (i + dir + len) % len;
|
|
1242
|
+
if (!isItemDisabled(items[i])) return i;
|
|
1243
|
+
}
|
|
1244
|
+
return -1;
|
|
1245
|
+
}
|
|
699
1246
|
function highlightNext() {
|
|
700
1247
|
if (items.length === 0) return;
|
|
701
1248
|
setHighlightedIndex((prev) => {
|
|
702
|
-
const
|
|
703
|
-
return
|
|
1249
|
+
const n = nextEnabled(prev < 0 ? -1 : prev, 1);
|
|
1250
|
+
return n === -1 ? prev : n;
|
|
704
1251
|
});
|
|
705
1252
|
}
|
|
706
1253
|
function highlightPrev() {
|
|
707
1254
|
if (items.length === 0) return;
|
|
708
1255
|
setHighlightedIndex((prev) => {
|
|
709
|
-
const
|
|
710
|
-
return
|
|
1256
|
+
const n = nextEnabled(prev < 0 ? items.length : prev, -1);
|
|
1257
|
+
return n === -1 ? prev : n;
|
|
711
1258
|
});
|
|
712
1259
|
}
|
|
713
1260
|
function selectHighlighted() {
|
|
@@ -719,6 +1266,73 @@ function select(options) {
|
|
|
719
1266
|
function clear() {
|
|
720
1267
|
setSelectedItems([]);
|
|
721
1268
|
}
|
|
1269
|
+
function bind(els) {
|
|
1270
|
+
const existing = boundSelects.get(els.listbox);
|
|
1271
|
+
if (existing) return existing;
|
|
1272
|
+
const listboxId = `sibu-select-${++selectIdCounter}`;
|
|
1273
|
+
els.listbox.id = listboxId;
|
|
1274
|
+
els.listbox.setAttribute("role", "listbox");
|
|
1275
|
+
els.listbox.setAttribute("aria-multiselectable", multiple ? "true" : "false");
|
|
1276
|
+
if (els.listbox.tabIndex < 0) els.listbox.tabIndex = 0;
|
|
1277
|
+
const toStr = els.itemToString ?? itemToString ?? ((it) => String(it));
|
|
1278
|
+
const fxTeardown = effect(() => {
|
|
1279
|
+
const idx = highlightedIndex();
|
|
1280
|
+
const sel = selectedItems();
|
|
1281
|
+
let activeId = "";
|
|
1282
|
+
for (let i = 0; i < items.length; i++) {
|
|
1283
|
+
const optEl = els.option(items[i], i);
|
|
1284
|
+
if (!optEl) continue;
|
|
1285
|
+
if (!optEl.id) optEl.id = `${listboxId}-opt-${i}`;
|
|
1286
|
+
optEl.setAttribute("role", "option");
|
|
1287
|
+
optEl.setAttribute("aria-selected", sel.includes(items[i]) ? "true" : "false");
|
|
1288
|
+
if (isItemDisabled(items[i])) optEl.setAttribute("aria-disabled", "true");
|
|
1289
|
+
else optEl.removeAttribute("aria-disabled");
|
|
1290
|
+
if (i === idx) activeId = optEl.id;
|
|
1291
|
+
}
|
|
1292
|
+
if (activeId) els.listbox.setAttribute("aria-activedescendant", activeId);
|
|
1293
|
+
else els.listbox.removeAttribute("aria-activedescendant");
|
|
1294
|
+
});
|
|
1295
|
+
let typeBuffer = "";
|
|
1296
|
+
let typeTimer = null;
|
|
1297
|
+
const onKey = (e) => {
|
|
1298
|
+
if (e.key === "ArrowDown") {
|
|
1299
|
+
e.preventDefault();
|
|
1300
|
+
highlightNext();
|
|
1301
|
+
} else if (e.key === "ArrowUp") {
|
|
1302
|
+
e.preventDefault();
|
|
1303
|
+
highlightPrev();
|
|
1304
|
+
} else if (e.key === "Home") {
|
|
1305
|
+
e.preventDefault();
|
|
1306
|
+
if (items.length > 0) setHighlightedIndex(0);
|
|
1307
|
+
} else if (e.key === "End") {
|
|
1308
|
+
e.preventDefault();
|
|
1309
|
+
if (items.length > 0) setHighlightedIndex(items.length - 1);
|
|
1310
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
1311
|
+
if (highlightedIndex() >= 0) {
|
|
1312
|
+
e.preventDefault();
|
|
1313
|
+
selectHighlighted();
|
|
1314
|
+
}
|
|
1315
|
+
} else if (e.key.length === 1 && /\S/.test(e.key)) {
|
|
1316
|
+
typeBuffer += e.key.toLowerCase();
|
|
1317
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
1318
|
+
typeTimer = setTimeout(() => {
|
|
1319
|
+
typeBuffer = "";
|
|
1320
|
+
typeTimer = null;
|
|
1321
|
+
}, 500);
|
|
1322
|
+
const found = items.findIndex((it) => !isItemDisabled(it) && toStr(it).toLowerCase().startsWith(typeBuffer));
|
|
1323
|
+
if (found !== -1) setHighlightedIndex(found);
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
els.listbox.addEventListener("keydown", onKey);
|
|
1327
|
+
const teardown = () => {
|
|
1328
|
+
boundSelects.delete(els.listbox);
|
|
1329
|
+
fxTeardown();
|
|
1330
|
+
els.listbox.removeEventListener("keydown", onKey);
|
|
1331
|
+
if (typeTimer !== null) clearTimeout(typeTimer);
|
|
1332
|
+
};
|
|
1333
|
+
boundSelects.set(els.listbox, teardown);
|
|
1334
|
+
return teardown;
|
|
1335
|
+
}
|
|
722
1336
|
return {
|
|
723
1337
|
selectedItems,
|
|
724
1338
|
selectedItem,
|
|
@@ -733,21 +1347,28 @@ function select(options) {
|
|
|
733
1347
|
highlightNext,
|
|
734
1348
|
highlightPrev,
|
|
735
1349
|
selectHighlighted,
|
|
736
|
-
clear
|
|
1350
|
+
clear,
|
|
1351
|
+
bind
|
|
737
1352
|
};
|
|
738
1353
|
}
|
|
739
1354
|
|
|
740
1355
|
// src/widgets/Tooltip.ts
|
|
1356
|
+
var tooltipIdCounter = 0;
|
|
1357
|
+
var boundTriggers = /* @__PURE__ */ new WeakMap();
|
|
741
1358
|
function tooltip(options) {
|
|
742
1359
|
const delay = options?.delay ?? 0;
|
|
1360
|
+
const hideDelay = options?.hideDelay ?? 100;
|
|
743
1361
|
const [isVisible, setIsVisible] = signal(false);
|
|
744
1362
|
const [content, setContent] = signal("");
|
|
745
1363
|
let delayTimer = null;
|
|
1364
|
+
let hideTimer = null;
|
|
746
1365
|
function show() {
|
|
1366
|
+
if (hideTimer !== null) {
|
|
1367
|
+
clearTimeout(hideTimer);
|
|
1368
|
+
hideTimer = null;
|
|
1369
|
+
}
|
|
747
1370
|
if (delay > 0) {
|
|
748
|
-
if (delayTimer !== null)
|
|
749
|
-
clearTimeout(delayTimer);
|
|
750
|
-
}
|
|
1371
|
+
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
751
1372
|
delayTimer = setTimeout(() => {
|
|
752
1373
|
setIsVisible(true);
|
|
753
1374
|
delayTimer = null;
|
|
@@ -763,10 +1384,82 @@ function tooltip(options) {
|
|
|
763
1384
|
}
|
|
764
1385
|
setIsVisible(false);
|
|
765
1386
|
}
|
|
766
|
-
|
|
1387
|
+
function scheduleHide() {
|
|
1388
|
+
if (delayTimer !== null) {
|
|
1389
|
+
clearTimeout(delayTimer);
|
|
1390
|
+
delayTimer = null;
|
|
1391
|
+
}
|
|
1392
|
+
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
1393
|
+
hideTimer = setTimeout(() => {
|
|
1394
|
+
hideTimer = null;
|
|
1395
|
+
setIsVisible(false);
|
|
1396
|
+
}, hideDelay);
|
|
1397
|
+
}
|
|
1398
|
+
function bind(els) {
|
|
1399
|
+
const existing = boundTriggers.get(els.trigger);
|
|
1400
|
+
if (existing) return existing;
|
|
1401
|
+
const id = `sibu-tooltip-${++tooltipIdCounter}`;
|
|
1402
|
+
els.tooltip.setAttribute("role", "tooltip");
|
|
1403
|
+
els.tooltip.id = id;
|
|
1404
|
+
const prevDescribedBy = els.trigger.getAttribute("aria-describedby");
|
|
1405
|
+
els.trigger.setAttribute("aria-describedby", prevDescribedBy ? `${prevDescribedBy} ${id}` : id);
|
|
1406
|
+
const fxTeardown = effect(() => {
|
|
1407
|
+
els.tooltip.hidden = !isVisible();
|
|
1408
|
+
});
|
|
1409
|
+
const onTriggerEnter = () => show();
|
|
1410
|
+
const onTriggerLeave = () => scheduleHide();
|
|
1411
|
+
const onTooltipEnter = () => {
|
|
1412
|
+
if (hideTimer !== null) {
|
|
1413
|
+
clearTimeout(hideTimer);
|
|
1414
|
+
hideTimer = null;
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
const onTooltipLeave = () => scheduleHide();
|
|
1418
|
+
const onFocus = () => show();
|
|
1419
|
+
const onBlur = () => hide();
|
|
1420
|
+
const onKey = (e) => {
|
|
1421
|
+
if (e.key === "Escape" && isVisible()) {
|
|
1422
|
+
e.stopPropagation();
|
|
1423
|
+
hide();
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1426
|
+
els.trigger.addEventListener("pointerenter", onTriggerEnter);
|
|
1427
|
+
els.trigger.addEventListener("pointerleave", onTriggerLeave);
|
|
1428
|
+
els.trigger.addEventListener("focus", onFocus);
|
|
1429
|
+
els.trigger.addEventListener("blur", onBlur);
|
|
1430
|
+
els.trigger.addEventListener("keydown", onKey);
|
|
1431
|
+
els.tooltip.addEventListener("pointerenter", onTooltipEnter);
|
|
1432
|
+
els.tooltip.addEventListener("pointerleave", onTooltipLeave);
|
|
1433
|
+
const teardown = () => {
|
|
1434
|
+
boundTriggers.delete(els.trigger);
|
|
1435
|
+
fxTeardown();
|
|
1436
|
+
els.trigger.removeEventListener("pointerenter", onTriggerEnter);
|
|
1437
|
+
els.trigger.removeEventListener("pointerleave", onTriggerLeave);
|
|
1438
|
+
els.trigger.removeEventListener("focus", onFocus);
|
|
1439
|
+
els.trigger.removeEventListener("blur", onBlur);
|
|
1440
|
+
els.trigger.removeEventListener("keydown", onKey);
|
|
1441
|
+
els.tooltip.removeEventListener("pointerenter", onTooltipEnter);
|
|
1442
|
+
els.tooltip.removeEventListener("pointerleave", onTooltipLeave);
|
|
1443
|
+
const cur = els.trigger.getAttribute("aria-describedby");
|
|
1444
|
+
if (cur) {
|
|
1445
|
+
const remaining = cur.split(/\s+/).filter((part) => part && part !== id);
|
|
1446
|
+
if (remaining.length > 0) els.trigger.setAttribute("aria-describedby", remaining.join(" "));
|
|
1447
|
+
else els.trigger.removeAttribute("aria-describedby");
|
|
1448
|
+
} else if (prevDescribedBy) {
|
|
1449
|
+
els.trigger.setAttribute("aria-describedby", prevDescribedBy);
|
|
1450
|
+
}
|
|
1451
|
+
if (delayTimer !== null) clearTimeout(delayTimer);
|
|
1452
|
+
if (hideTimer !== null) clearTimeout(hideTimer);
|
|
1453
|
+
};
|
|
1454
|
+
boundTriggers.set(els.trigger, teardown);
|
|
1455
|
+
return teardown;
|
|
1456
|
+
}
|
|
1457
|
+
return { isVisible, show, hide, content, setContent, bind };
|
|
767
1458
|
}
|
|
768
1459
|
|
|
769
1460
|
// src/widgets/FileUpload.ts
|
|
1461
|
+
var fileUploadIdCounter = 0;
|
|
1462
|
+
var boundFileUploads = /* @__PURE__ */ new WeakMap();
|
|
770
1463
|
function fileUpload(options) {
|
|
771
1464
|
const accept = options?.accept;
|
|
772
1465
|
const multiple = options?.multiple ?? false;
|
|
@@ -834,6 +1527,107 @@ function fileUpload(options) {
|
|
|
834
1527
|
setErrors([]);
|
|
835
1528
|
});
|
|
836
1529
|
}
|
|
1530
|
+
function bind(els) {
|
|
1531
|
+
const existing = boundFileUploads.get(els.input);
|
|
1532
|
+
if (existing) return existing;
|
|
1533
|
+
const id = `sibu-fileupload-${++fileUploadIdCounter}`;
|
|
1534
|
+
const restore = [];
|
|
1535
|
+
if (accept) els.input.accept = accept;
|
|
1536
|
+
els.input.multiple = multiple;
|
|
1537
|
+
let hintId = null;
|
|
1538
|
+
if (els.hint) {
|
|
1539
|
+
const assignedHintId = !els.hint.id;
|
|
1540
|
+
if (assignedHintId) els.hint.id = `${id}-hint`;
|
|
1541
|
+
hintId = els.hint.id;
|
|
1542
|
+
const prev = els.input.getAttribute("aria-describedby");
|
|
1543
|
+
els.input.setAttribute("aria-describedby", prev ? `${prev} ${hintId}` : hintId);
|
|
1544
|
+
restore.push(() => {
|
|
1545
|
+
const cur = els.input.getAttribute("aria-describedby");
|
|
1546
|
+
if (cur) {
|
|
1547
|
+
const parts = cur.split(/\s+/).filter((p) => p && p !== hintId);
|
|
1548
|
+
if (parts.length > 0) els.input.setAttribute("aria-describedby", parts.join(" "));
|
|
1549
|
+
else els.input.removeAttribute("aria-describedby");
|
|
1550
|
+
}
|
|
1551
|
+
if (assignedHintId && els.hint && els.hint.id === hintId) els.hint.removeAttribute("id");
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
if (els.errorRegion) {
|
|
1555
|
+
const prevRole = els.errorRegion.getAttribute("role");
|
|
1556
|
+
const prevLive = els.errorRegion.getAttribute("aria-live");
|
|
1557
|
+
els.errorRegion.setAttribute("role", "status");
|
|
1558
|
+
els.errorRegion.setAttribute("aria-live", "polite");
|
|
1559
|
+
restore.push(() => {
|
|
1560
|
+
if (prevRole === null) els.errorRegion.removeAttribute("role");
|
|
1561
|
+
else els.errorRegion.setAttribute("role", prevRole);
|
|
1562
|
+
if (prevLive === null) els.errorRegion.removeAttribute("aria-live");
|
|
1563
|
+
else els.errorRegion.setAttribute("aria-live", prevLive);
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
if (els.dropZone) {
|
|
1567
|
+
const prevDzRole = els.dropZone.getAttribute("role");
|
|
1568
|
+
const prevDzLabel = els.dropZone.getAttribute("aria-label");
|
|
1569
|
+
const prevDzTabindex = els.dropZone.hasAttribute("tabindex") ? els.dropZone.getAttribute("tabindex") : null;
|
|
1570
|
+
els.dropZone.setAttribute("role", "button");
|
|
1571
|
+
els.dropZone.setAttribute("aria-label", "File drop zone \u2014 click or press Enter to browse");
|
|
1572
|
+
if (els.dropZone.tabIndex < 0) els.dropZone.tabIndex = 0;
|
|
1573
|
+
restore.push(() => {
|
|
1574
|
+
if (prevDzRole === null) els.dropZone.removeAttribute("role");
|
|
1575
|
+
else els.dropZone.setAttribute("role", prevDzRole);
|
|
1576
|
+
if (prevDzLabel === null) els.dropZone.removeAttribute("aria-label");
|
|
1577
|
+
else els.dropZone.setAttribute("aria-label", prevDzLabel);
|
|
1578
|
+
if (prevDzTabindex === null) els.dropZone.removeAttribute("tabindex");
|
|
1579
|
+
else els.dropZone.setAttribute("tabindex", prevDzTabindex);
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
const fxTeardown = effect(() => {
|
|
1583
|
+
const errs = errors();
|
|
1584
|
+
if (els.errorRegion) els.errorRegion.textContent = errs.join(". ");
|
|
1585
|
+
if (els.dropZone) els.dropZone.setAttribute("data-drag-over", isDragOver() ? "true" : "false");
|
|
1586
|
+
});
|
|
1587
|
+
const onChange = () => {
|
|
1588
|
+
if (els.input.files) addFiles(els.input.files);
|
|
1589
|
+
};
|
|
1590
|
+
const onDropClick = () => els.input.click();
|
|
1591
|
+
const onDropKey = (e) => {
|
|
1592
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1593
|
+
e.preventDefault();
|
|
1594
|
+
els.input.click();
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
const onDragOver = (e) => {
|
|
1598
|
+
e.preventDefault();
|
|
1599
|
+
setDragOver(true);
|
|
1600
|
+
};
|
|
1601
|
+
const onDragLeave = () => setDragOver(false);
|
|
1602
|
+
const onDrop = (e) => {
|
|
1603
|
+
e.preventDefault();
|
|
1604
|
+
setDragOver(false);
|
|
1605
|
+
if (e.dataTransfer?.files) addFiles(e.dataTransfer.files);
|
|
1606
|
+
};
|
|
1607
|
+
els.input.addEventListener("change", onChange);
|
|
1608
|
+
if (els.dropZone) {
|
|
1609
|
+
els.dropZone.addEventListener("click", onDropClick);
|
|
1610
|
+
els.dropZone.addEventListener("keydown", onDropKey);
|
|
1611
|
+
els.dropZone.addEventListener("dragover", onDragOver);
|
|
1612
|
+
els.dropZone.addEventListener("dragleave", onDragLeave);
|
|
1613
|
+
els.dropZone.addEventListener("drop", onDrop);
|
|
1614
|
+
}
|
|
1615
|
+
const teardown = () => {
|
|
1616
|
+
boundFileUploads.delete(els.input);
|
|
1617
|
+
fxTeardown();
|
|
1618
|
+
els.input.removeEventListener("change", onChange);
|
|
1619
|
+
if (els.dropZone) {
|
|
1620
|
+
els.dropZone.removeEventListener("click", onDropClick);
|
|
1621
|
+
els.dropZone.removeEventListener("keydown", onDropKey);
|
|
1622
|
+
els.dropZone.removeEventListener("dragover", onDragOver);
|
|
1623
|
+
els.dropZone.removeEventListener("dragleave", onDragLeave);
|
|
1624
|
+
els.dropZone.removeEventListener("drop", onDrop);
|
|
1625
|
+
}
|
|
1626
|
+
for (const r of restore) r();
|
|
1627
|
+
};
|
|
1628
|
+
boundFileUploads.set(els.input, teardown);
|
|
1629
|
+
return teardown;
|
|
1630
|
+
}
|
|
837
1631
|
return {
|
|
838
1632
|
files,
|
|
839
1633
|
addFiles,
|
|
@@ -841,14 +1635,36 @@ function fileUpload(options) {
|
|
|
841
1635
|
clear,
|
|
842
1636
|
errors,
|
|
843
1637
|
isDragOver,
|
|
844
|
-
setDragOver
|
|
1638
|
+
setDragOver,
|
|
1639
|
+
bind
|
|
845
1640
|
};
|
|
846
1641
|
}
|
|
847
1642
|
|
|
1643
|
+
// src/utils/sanitize.ts
|
|
1644
|
+
function stripHtml(html) {
|
|
1645
|
+
return String(html).replace(/<[^>]*>/g, "");
|
|
1646
|
+
}
|
|
1647
|
+
|
|
848
1648
|
// src/widgets/contentEditable.ts
|
|
849
1649
|
function contentEditable() {
|
|
850
|
-
const [content,
|
|
1650
|
+
const [content, setContentInternal] = signal("");
|
|
851
1651
|
const [isFocused, setFocused] = signal(false);
|
|
1652
|
+
function setContent(input) {
|
|
1653
|
+
if (typeof input === "string") {
|
|
1654
|
+
setContentInternal(input);
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
if (typeof input.text === "string") {
|
|
1658
|
+
setContentInternal(input.text);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
if (typeof input.html === "string") {
|
|
1662
|
+
const shouldSanitize = input.sanitize !== false;
|
|
1663
|
+
setContentInternal(shouldSanitize ? stripHtml(input.html) : input.html);
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
setContentInternal("");
|
|
1667
|
+
}
|
|
852
1668
|
function wrapSelection(tagName) {
|
|
853
1669
|
if (typeof window === "undefined") return;
|
|
854
1670
|
const selection = window.getSelection();
|
|
@@ -925,6 +1741,7 @@ function contentEditable() {
|
|
|
925
1741
|
}
|
|
926
1742
|
|
|
927
1743
|
// src/widgets/datePicker.ts
|
|
1744
|
+
var boundDatePickers = /* @__PURE__ */ new WeakMap();
|
|
928
1745
|
function datePicker(options) {
|
|
929
1746
|
const minDate = options?.minDate;
|
|
930
1747
|
const maxDate = options?.maxDate;
|
|
@@ -948,33 +1765,20 @@ function datePicker(options) {
|
|
|
948
1765
|
setSelectedDate(date);
|
|
949
1766
|
}
|
|
950
1767
|
}
|
|
1768
|
+
function shiftMonth(prev, delta) {
|
|
1769
|
+
return new Date(prev.getFullYear(), prev.getMonth() + delta, 1);
|
|
1770
|
+
}
|
|
951
1771
|
function nextMonth() {
|
|
952
|
-
setViewDate((prev) =>
|
|
953
|
-
const next = new Date(prev);
|
|
954
|
-
next.setMonth(next.getMonth() + 1);
|
|
955
|
-
return next;
|
|
956
|
-
});
|
|
1772
|
+
setViewDate((prev) => shiftMonth(prev, 1));
|
|
957
1773
|
}
|
|
958
1774
|
function prevMonth() {
|
|
959
|
-
setViewDate((prev) =>
|
|
960
|
-
const next = new Date(prev);
|
|
961
|
-
next.setMonth(next.getMonth() - 1);
|
|
962
|
-
return next;
|
|
963
|
-
});
|
|
1775
|
+
setViewDate((prev) => shiftMonth(prev, -1));
|
|
964
1776
|
}
|
|
965
1777
|
function nextYear() {
|
|
966
|
-
setViewDate((prev) =>
|
|
967
|
-
const next = new Date(prev);
|
|
968
|
-
next.setFullYear(next.getFullYear() + 1);
|
|
969
|
-
return next;
|
|
970
|
-
});
|
|
1778
|
+
setViewDate((prev) => new Date(prev.getFullYear() + 1, prev.getMonth(), 1));
|
|
971
1779
|
}
|
|
972
1780
|
function prevYear() {
|
|
973
|
-
setViewDate((prev) =>
|
|
974
|
-
const next = new Date(prev);
|
|
975
|
-
next.setFullYear(next.getFullYear() - 1);
|
|
976
|
-
return next;
|
|
977
|
-
});
|
|
1781
|
+
setViewDate((prev) => new Date(prev.getFullYear() - 1, prev.getMonth(), 1));
|
|
978
1782
|
}
|
|
979
1783
|
const daysInMonth = derived(() => {
|
|
980
1784
|
const vd = viewDate();
|
|
@@ -1039,8 +1843,87 @@ function datePicker(options) {
|
|
|
1039
1843
|
daysInMonth,
|
|
1040
1844
|
isDateDisabled,
|
|
1041
1845
|
/** Reactive check — use inside class bindings for per-day reactivity */
|
|
1042
|
-
isSelected
|
|
1846
|
+
isSelected,
|
|
1847
|
+
bind
|
|
1043
1848
|
};
|
|
1849
|
+
function bind(els) {
|
|
1850
|
+
const existing = boundDatePickers.get(els.grid);
|
|
1851
|
+
if (existing) return existing;
|
|
1852
|
+
els.grid.setAttribute("role", "grid");
|
|
1853
|
+
if (els.grid.tabIndex < 0) els.grid.tabIndex = 0;
|
|
1854
|
+
const fxTeardown = effect(() => {
|
|
1855
|
+
const sel = selectedDate();
|
|
1856
|
+
const view = viewDate();
|
|
1857
|
+
const days = daysInMonth();
|
|
1858
|
+
for (const d of days) {
|
|
1859
|
+
const cell = els.cell(d.date);
|
|
1860
|
+
if (!cell) continue;
|
|
1861
|
+
cell.setAttribute("role", "gridcell");
|
|
1862
|
+
cell.setAttribute("aria-selected", sel && isSameCalendarDay(sel, d.date) ? "true" : "false");
|
|
1863
|
+
if (d.isDisabled) cell.setAttribute("aria-disabled", "true");
|
|
1864
|
+
else cell.removeAttribute("aria-disabled");
|
|
1865
|
+
cell.tabIndex = isSameCalendarDay(view, d.date) ? 0 : -1;
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
function isSameCalendarDay(a, b) {
|
|
1869
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1870
|
+
}
|
|
1871
|
+
function shiftDays(delta) {
|
|
1872
|
+
setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth(), prev.getDate() + delta));
|
|
1873
|
+
}
|
|
1874
|
+
const onKey = (e) => {
|
|
1875
|
+
switch (e.key) {
|
|
1876
|
+
case "ArrowLeft":
|
|
1877
|
+
e.preventDefault();
|
|
1878
|
+
shiftDays(-1);
|
|
1879
|
+
break;
|
|
1880
|
+
case "ArrowRight":
|
|
1881
|
+
e.preventDefault();
|
|
1882
|
+
shiftDays(1);
|
|
1883
|
+
break;
|
|
1884
|
+
case "ArrowUp":
|
|
1885
|
+
e.preventDefault();
|
|
1886
|
+
shiftDays(-7);
|
|
1887
|
+
break;
|
|
1888
|
+
case "ArrowDown":
|
|
1889
|
+
e.preventDefault();
|
|
1890
|
+
shiftDays(7);
|
|
1891
|
+
break;
|
|
1892
|
+
case "Home":
|
|
1893
|
+
e.preventDefault();
|
|
1894
|
+
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() - p.getDay()));
|
|
1895
|
+
break;
|
|
1896
|
+
case "End": {
|
|
1897
|
+
e.preventDefault();
|
|
1898
|
+
setViewDate((p) => new Date(p.getFullYear(), p.getMonth(), p.getDate() + (6 - p.getDay())));
|
|
1899
|
+
break;
|
|
1900
|
+
}
|
|
1901
|
+
case "PageUp":
|
|
1902
|
+
e.preventDefault();
|
|
1903
|
+
if (e.shiftKey) prevYear();
|
|
1904
|
+
else prevMonth();
|
|
1905
|
+
break;
|
|
1906
|
+
case "PageDown":
|
|
1907
|
+
e.preventDefault();
|
|
1908
|
+
if (e.shiftKey) nextYear();
|
|
1909
|
+
else nextMonth();
|
|
1910
|
+
break;
|
|
1911
|
+
case "Enter":
|
|
1912
|
+
case " ":
|
|
1913
|
+
e.preventDefault();
|
|
1914
|
+
select2(viewDate());
|
|
1915
|
+
break;
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
els.grid.addEventListener("keydown", onKey);
|
|
1919
|
+
const teardown = () => {
|
|
1920
|
+
boundDatePickers.delete(els.grid);
|
|
1921
|
+
fxTeardown();
|
|
1922
|
+
els.grid.removeEventListener("keydown", onKey);
|
|
1923
|
+
};
|
|
1924
|
+
boundDatePickers.set(els.grid, teardown);
|
|
1925
|
+
return teardown;
|
|
1926
|
+
}
|
|
1044
1927
|
}
|
|
1045
1928
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1046
1929
|
0 && (module.exports = {
|