sibujs 3.4.0 → 4.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.
Files changed (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +118 -15
  3. package/dist/browser.cjs +410 -101
  4. package/dist/browser.d.cts +50 -5
  5. package/dist/browser.d.ts +50 -5
  6. package/dist/browser.js +8 -6
  7. package/dist/build.cjs +777 -385
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
  11. package/dist/chunk-4MFZMLUU.js +147 -0
  12. package/dist/chunk-52XFPGSN.js +123 -0
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
  15. package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
  16. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  17. package/dist/chunk-DHDZ7IVN.js +109 -0
  18. package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
  19. package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
  20. package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
  21. package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
  22. package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
  23. package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
  24. package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
  25. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  26. package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
  27. package/dist/chunk-O3QQ3XOL.js +61 -0
  28. package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
  29. package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
  30. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  31. package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
  34. package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
  35. package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
  36. package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
  37. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
  41. package/dist/data.cjs +483 -205
  42. package/dist/data.d.cts +139 -7
  43. package/dist/data.d.ts +139 -7
  44. package/dist/data.js +9 -9
  45. package/dist/devtools.cjs +222 -87
  46. package/dist/devtools.js +8 -8
  47. package/dist/dispose-4FZ6OFXR.js +19 -0
  48. package/dist/ecosystem.cjs +419 -175
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1981 -765
  51. package/dist/extras.d.cts +7 -7
  52. package/dist/extras.d.ts +7 -7
  53. package/dist/extras.js +29 -26
  54. package/dist/index.cjs +784 -385
  55. package/dist/index.d.cts +299 -28
  56. package/dist/index.d.ts +299 -28
  57. package/dist/index.js +33 -18
  58. package/dist/motion.cjs +180 -50
  59. package/dist/motion.d.cts +26 -0
  60. package/dist/motion.d.ts +26 -0
  61. package/dist/motion.js +5 -5
  62. package/dist/patterns.cjs +437 -170
  63. package/dist/patterns.d.cts +60 -13
  64. package/dist/patterns.d.ts +60 -13
  65. package/dist/patterns.js +7 -7
  66. package/dist/performance.cjs +333 -148
  67. package/dist/performance.d.cts +55 -7
  68. package/dist/performance.d.ts +55 -7
  69. package/dist/performance.js +9 -9
  70. package/dist/plugins.cjs +1374 -576
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +613 -321
  74. package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
  75. package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
  76. package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
  77. package/dist/ssr.cjs +1104 -443
  78. package/dist/ssr.d.cts +230 -20
  79. package/dist/ssr.d.ts +230 -20
  80. package/dist/ssr.js +15 -12
  81. package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
  82. package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
  83. package/dist/testing.cjs +205 -63
  84. package/dist/testing.d.cts +1 -1
  85. package/dist/testing.d.ts +1 -1
  86. package/dist/testing.js +8 -10
  87. package/dist/ui.cjs +640 -199
  88. package/dist/ui.d.cts +2 -2
  89. package/dist/ui.d.ts +2 -2
  90. package/dist/ui.js +10 -10
  91. package/dist/widgets.cjs +207 -82
  92. package/dist/widgets.js +9 -9
  93. package/package.json +12 -7
  94. package/dist/chunk-5VGSK6D2.js +0 -80
  95. package/dist/chunk-COY6PUD2.js +0 -34
  96. package/dist/chunk-K35BAR4P.js +0 -96
  97. package/dist/chunk-L3GAGWCC.js +0 -111
  98. package/dist/chunk-RT3IYFN2.js +0 -38
@@ -0,0 +1,142 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+
13
+ // src/core/dev.ts
14
+ function isDev() {
15
+ return typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
16
+ // The bare `__SIBU_DEV__` is a bundler define that only exists in
17
+ // production builds; under the test runner it is always undefined, so
18
+ // this branch is unreachable here.
19
+ /* v8 ignore next 2 */
20
+ typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
21
+ );
22
+ }
23
+ var _isDev = isDev();
24
+ function devAssert(condition, message) {
25
+ if (_isDev && !condition) {
26
+ throw new Error(`[SibuJS] ${message}`);
27
+ }
28
+ }
29
+ function devWarn(message) {
30
+ if (_isDev) {
31
+ console.warn(`[SibuJS] ${message}`);
32
+ }
33
+ }
34
+
35
+ // src/core/errors.ts
36
+ var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
37
+ function state() {
38
+ const g = globalThis;
39
+ const existing = g[ERROR_STATE_KEY];
40
+ if (existing) return existing;
41
+ const created = { handler: null, handlerDepth: 0 };
42
+ g[ERROR_STATE_KEY] = created;
43
+ return created;
44
+ }
45
+ function setRuntimeErrorHandler(handler) {
46
+ const s = state();
47
+ const prev = s.handler;
48
+ s.handler = handler;
49
+ return prev;
50
+ }
51
+ function getRuntimeErrorHandler() {
52
+ return state().handler;
53
+ }
54
+ function normalizeError(value) {
55
+ if (value instanceof Error) return value;
56
+ const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
57
+ return new Error(message, { cause: value });
58
+ }
59
+ function safeStringify(value) {
60
+ if (typeof value === "symbol") return value.toString();
61
+ try {
62
+ return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
63
+ } catch {
64
+ return Object.prototype.toString.call(value);
65
+ }
66
+ }
67
+ function describe(context) {
68
+ return context.name ? `${context.phase} "${context.name}"` : context.phase;
69
+ }
70
+ var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
71
+ function untrackedRun(fn) {
72
+ const api = globalThis[REACTIVE_REGISTRY_KEY];
73
+ return api?.untracked ? api.untracked(fn) : fn();
74
+ }
75
+ var PROPAGATE_EVENT = "sibu:error-propagate";
76
+ function claimedByBoundary(error, context) {
77
+ const raw = context.node;
78
+ if (!raw || typeof CustomEvent === "undefined") return false;
79
+ const target = resolveEventTarget(raw);
80
+ if (!target) return false;
81
+ try {
82
+ const event = new CustomEvent(PROPAGATE_EVENT, {
83
+ bubbles: true,
84
+ cancelable: true,
85
+ detail: { error, context }
86
+ });
87
+ return target.dispatchEvent(event) === false;
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+ function resolveEventTarget(node) {
93
+ const ELEMENT_NODE = 1;
94
+ let current = node;
95
+ while (current) {
96
+ if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
97
+ return current;
98
+ }
99
+ current = current.parentNode;
100
+ }
101
+ const self = node;
102
+ return typeof self.dispatchEvent === "function" ? self : null;
103
+ }
104
+ function defaultReport(error, context) {
105
+ if (typeof console === "undefined") return;
106
+ console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
107
+ }
108
+ function reportError(error, context) {
109
+ const err = normalizeError(error);
110
+ untrackedRun(() => {
111
+ if (claimedByBoundary(err, context)) return;
112
+ const s = state();
113
+ const handler = s.handler;
114
+ if (handler && s.handlerDepth === 0) {
115
+ s.handlerDepth++;
116
+ try {
117
+ handler(error instanceof Error ? error : err, context);
118
+ return;
119
+ } catch (handlerError) {
120
+ if (typeof console !== "undefined") {
121
+ const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
122
+ console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
123
+ }
124
+ } finally {
125
+ s.handlerDepth--;
126
+ }
127
+ }
128
+ defaultReport(err, context);
129
+ });
130
+ }
131
+
132
+ export {
133
+ __require,
134
+ __export,
135
+ isDev,
136
+ devAssert,
137
+ devWarn,
138
+ setRuntimeErrorHandler,
139
+ getRuntimeErrorHandler,
140
+ normalizeError,
141
+ reportError
142
+ };
@@ -3,10 +3,10 @@ import {
3
3
  notifySubscribers,
4
4
  queueSignalNotification,
5
5
  recordDependency
6
- } from "./chunk-OOUQUCNN.js";
6
+ } from "./chunk-ACBT6UZS.js";
7
7
  import {
8
8
  isDev
9
- } from "./chunk-COY6PUD2.js";
9
+ } from "./chunk-VPP2FONR.js";
10
10
 
11
11
  // src/reactivity/batch.ts
12
12
  var batchDepth = 0;
@@ -69,7 +69,9 @@ function signal(initial, options) {
69
69
  subsHead: null,
70
70
  subsTail: null,
71
71
  __activeNode: null,
72
- __name: void 0
72
+ __name: void 0,
73
+ _d: false,
74
+ _validate: void 0
73
75
  };
74
76
  const debugName = _isDev ? options?.name : void 0;
75
77
  const equalsFn = options?.equals;
@@ -3,17 +3,17 @@ import {
3
3
  } from "./chunk-WWV3SJ3L.js";
4
4
  import {
5
5
  tagFactory
6
- } from "./chunk-JNGGM2XE.js";
6
+ } from "./chunk-DQVUBVNX.js";
7
7
  import {
8
8
  derived
9
- } from "./chunk-ITWCTZYH.js";
9
+ } from "./chunk-Z2CE42DB.js";
10
10
  import {
11
11
  effect
12
- } from "./chunk-BUKYCWHX.js";
12
+ } from "./chunk-PBQEW5VW.js";
13
13
  import {
14
14
  batch,
15
15
  signal
16
- } from "./chunk-KZBEVFXZ.js";
16
+ } from "./chunk-W55YHPEP.js";
17
17
 
18
18
  // src/ecosystem/adapters/mobx.ts
19
19
  function mobXAdapter(options) {
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-H3SRKIYX.js";
5
5
  import {
6
6
  derived
7
- } from "./chunk-ITWCTZYH.js";
7
+ } from "./chunk-Z2CE42DB.js";
8
8
  import {
9
9
  effect
10
- } from "./chunk-BUKYCWHX.js";
10
+ } from "./chunk-PBQEW5VW.js";
11
11
  import {
12
12
  batch,
13
13
  signal
14
- } from "./chunk-KZBEVFXZ.js";
14
+ } from "./chunk-W55YHPEP.js";
15
15
 
16
16
  // src/patterns/machine.ts
17
17
  function machine(config) {
@@ -177,116 +177,258 @@ function optimistic(initialValue) {
177
177
  }
178
178
  } finally {
179
179
  inflightCount--;
180
- if (inflightCount === 0) setPending(false);
180
+ if (inflightCount <= 0) {
181
+ inflightCount = 0;
182
+ setPending(false);
183
+ }
181
184
  }
182
185
  }
183
186
  return { value, pending, update };
184
187
  }
185
188
  function optimisticList(initialValue) {
186
- const [items, setItems] = signal([...initialValue]);
187
- const [pending, setPending] = signal(false);
188
- let inflightCount = 0;
189
- let version = 0;
190
- let tempIdCounter = 0;
191
- const itemIds = /* @__PURE__ */ new WeakMap();
192
- const idToItem = /* @__PURE__ */ new Map();
193
- function tagItem(item) {
194
- const id = ++tempIdCounter;
195
- if (item !== null && typeof item === "object") {
196
- itemIds.set(item, id);
189
+ let nextRowId = 0;
190
+ let nextKey = 0;
191
+ let nextOpId = 0;
192
+ const records = /* @__PURE__ */ new Map();
193
+ let order = [];
194
+ for (const value of initialValue) {
195
+ const row = { id: nextRowId++, key: nextKey++, base: value, claims: [], visible: true, refs: 0 };
196
+ records.set(row.id, row);
197
+ order.push(row.id);
198
+ }
199
+ function effectiveValue(row) {
200
+ const claims = row.claims;
201
+ return claims.length > 0 ? claims[claims.length - 1].value : row.base;
202
+ }
203
+ function valueBelow(row, opId) {
204
+ const claims = row.claims;
205
+ for (let i = claims.length - 1; i >= 0; i--) {
206
+ if (claims[i].opId < opId) return claims[i].value;
207
+ }
208
+ return row.base;
209
+ }
210
+ function stake(row, opId, value) {
211
+ const claim = { opId, value, settled: false };
212
+ const claims = row.claims;
213
+ let at = claims.length;
214
+ while (at > 0 && claims[at - 1].opId > opId) at--;
215
+ claims.splice(at, 0, claim);
216
+ return claim;
217
+ }
218
+ function dropClaim(row, claim) {
219
+ const at = row.claims.indexOf(claim);
220
+ if (at !== -1) row.claims.splice(at, 1);
221
+ }
222
+ function collapse(row) {
223
+ const claims = row.claims;
224
+ let i = 0;
225
+ while (i < claims.length && claims[i].settled) {
226
+ row.base = claims[i].value;
227
+ i++;
197
228
  }
198
- idToItem.set(id, item);
199
- return id;
200
- }
201
- function findIndexById(list, id) {
202
- for (let i = 0; i < list.length; i++) {
203
- const it = list[i];
204
- if (it !== null && typeof it === "object" && itemIds.get(it) === id) {
205
- return i;
229
+ if (i > 0) claims.splice(0, i);
230
+ }
231
+ const [items, setItems] = signal(order.map((id) => effectiveValue(records.get(id))));
232
+ const [pending, setPending] = signal(false);
233
+ let inflight = 0;
234
+ const retiredRowIds = /* @__PURE__ */ new Set();
235
+ function project() {
236
+ const out = new Array(order.length);
237
+ for (let i = 0; i < order.length; i++) out[i] = effectiveValue(records.get(order[i]));
238
+ return out;
239
+ }
240
+ function commit(mutate) {
241
+ batch(() => {
242
+ let visibleChanged = false;
243
+ try {
244
+ visibleChanged = mutate();
245
+ } finally {
246
+ setPending(inflight > 0);
247
+ if (visibleChanged) setItems(project());
206
248
  }
207
- if (Object.is(it, idToItem.get(id))) return i;
249
+ });
250
+ }
251
+ function hide(id) {
252
+ const row = records.get(id);
253
+ if (!row || !row.visible) return false;
254
+ row.visible = false;
255
+ order = order.filter((x) => x !== id);
256
+ return true;
257
+ }
258
+ function restore(ids) {
259
+ const restorable = [];
260
+ for (const id of ids) {
261
+ const row = records.get(id);
262
+ if (!row || row.visible || retiredRowIds.has(id)) continue;
263
+ restorable.push(id);
264
+ }
265
+ if (restorable.length === 0) return false;
266
+ const merged = new Array(order.length + restorable.length);
267
+ let i = 0;
268
+ let j = 0;
269
+ let w = 0;
270
+ while (i < order.length && j < restorable.length) {
271
+ const a = records.get(order[i]).key;
272
+ const b = records.get(restorable[j]).key;
273
+ merged[w++] = a <= b ? order[i++] : restorable[j++];
208
274
  }
209
- return -1;
275
+ while (i < order.length) merged[w++] = order[i++];
276
+ while (j < restorable.length) merged[w++] = restorable[j++];
277
+ for (const id of restorable) records.get(id).visible = true;
278
+ order = merged;
279
+ return true;
210
280
  }
211
- function begin() {
212
- const v = ++version;
213
- inflightCount++;
214
- setPending(true);
215
- return v;
281
+ function retain(ids) {
282
+ for (const id of ids) {
283
+ const row = records.get(id);
284
+ if (row) row.refs++;
285
+ }
216
286
  }
217
- function end(myVersion, revertFn) {
218
- if (revertFn && version === myVersion) {
219
- revertFn();
287
+ function release(ids) {
288
+ for (const id of ids) {
289
+ const row = records.get(id);
290
+ if (!row) continue;
291
+ row.refs--;
292
+ if (row.refs <= 0 && !row.visible) {
293
+ records.delete(id);
294
+ retiredRowIds.delete(id);
295
+ }
296
+ }
297
+ }
298
+ function settle(heldIds) {
299
+ release(heldIds);
300
+ inflight--;
301
+ if (inflight <= 0) {
302
+ inflight = 0;
303
+ retiredRowIds.clear();
304
+ if (records.size !== order.length) {
305
+ for (const [id, row] of records) {
306
+ if (!row.visible) records.delete(id);
307
+ }
308
+ }
220
309
  }
221
- inflightCount--;
222
- if (inflightCount === 0) setPending(false);
223
310
  }
224
311
  async function add(item, asyncAction) {
225
- const prev = items();
226
- const id = tagItem(item);
227
- setItems([...prev, item]);
228
- const myVersion = begin();
312
+ const opId = ++nextOpId;
313
+ const row = { id: nextRowId++, key: nextKey++, base: item, claims: [], visible: false, refs: 1 };
314
+ const claim = stake(row, opId, item);
315
+ commit(() => {
316
+ records.set(row.id, row);
317
+ row.visible = true;
318
+ order = [...order, row.id];
319
+ inflight++;
320
+ return true;
321
+ });
322
+ let result;
323
+ let failed = false;
229
324
  try {
230
- const result = await asyncAction();
231
- setItems((current) => {
232
- const idx = findIndexById(current, id);
233
- if (idx >= 0) {
234
- const next = [...current];
235
- next[idx] = result;
236
- return next;
237
- }
238
- return [...current, result];
239
- });
240
- idToItem.delete(id);
241
- end(myVersion);
325
+ result = await asyncAction();
242
326
  } catch {
243
- idToItem.delete(id);
244
- end(myVersion, () => setItems(prev));
327
+ failed = true;
245
328
  }
329
+ commit(() => {
330
+ try {
331
+ if (failed) {
332
+ retiredRowIds.add(row.id);
333
+ dropClaim(row, claim);
334
+ return hide(row.id);
335
+ }
336
+ const before = effectiveValue(row);
337
+ claim.value = result;
338
+ claim.settled = true;
339
+ collapse(row);
340
+ return row.visible && !Object.is(before, effectiveValue(row));
341
+ } finally {
342
+ settle([row.id]);
343
+ }
344
+ });
246
345
  }
247
346
  async function remove(predicate, asyncAction) {
248
- const prev = items();
249
- setItems(prev.filter((item) => !predicate(item)));
250
- const myVersion = begin();
347
+ const opId = ++nextOpId;
348
+ const matchedIds = [];
349
+ for (const id of order) {
350
+ if (predicate(valueBelow(records.get(id), opId))) matchedIds.push(id);
351
+ }
352
+ commit(() => {
353
+ retain(matchedIds);
354
+ inflight++;
355
+ if (matchedIds.length === 0) return false;
356
+ const removing = new Set(matchedIds);
357
+ for (const id of matchedIds) {
358
+ const row = records.get(id);
359
+ if (row) row.visible = false;
360
+ }
361
+ order = order.filter((id) => !removing.has(id));
362
+ return true;
363
+ });
364
+ let failed = false;
251
365
  try {
252
366
  await asyncAction();
253
- end(myVersion);
254
367
  } catch {
255
- end(myVersion, () => setItems(prev));
368
+ failed = true;
256
369
  }
370
+ commit(() => {
371
+ try {
372
+ if (!failed) {
373
+ for (const id of matchedIds) retiredRowIds.add(id);
374
+ return false;
375
+ }
376
+ return restore(matchedIds);
377
+ } finally {
378
+ settle(matchedIds);
379
+ }
380
+ });
257
381
  }
258
382
  async function updateItem(predicate, patch, asyncAction) {
259
- const prev = items();
260
- const patchedIds = [];
261
- setItems(
262
- prev.map((item) => {
263
- if (predicate(item)) {
264
- const patched = { ...item, ...patch };
265
- const id = tagItem(patched);
266
- patchedIds.push(id);
267
- return patched;
268
- }
269
- return item;
270
- })
271
- );
272
- const myVersion = begin();
383
+ const opId = ++nextOpId;
384
+ const prepared = [];
385
+ for (const id of order) {
386
+ const row = records.get(id);
387
+ const seen = valueBelow(row, opId);
388
+ if (!predicate(seen)) continue;
389
+ prepared.push({ row, nextValue: { ...seen, ...patch } });
390
+ }
391
+ const preparedIds = prepared.map((p) => p.row.id);
392
+ const claims = [];
393
+ commit(() => {
394
+ retain(preparedIds);
395
+ inflight++;
396
+ let visibleChanged = false;
397
+ for (const p of prepared) {
398
+ const before = effectiveValue(p.row);
399
+ claims.push(stake(p.row, opId, p.nextValue));
400
+ if (p.row.visible && !Object.is(before, effectiveValue(p.row))) visibleChanged = true;
401
+ }
402
+ return visibleChanged;
403
+ });
404
+ let result;
405
+ let failed = false;
273
406
  try {
274
- const result = await asyncAction();
275
- setItems(
276
- (current) => current.map((item) => {
277
- if (item !== null && typeof item === "object") {
278
- const existingId = itemIds.get(item);
279
- if (existingId !== void 0 && patchedIds.includes(existingId)) return result;
280
- }
281
- return item;
282
- })
283
- );
284
- for (const id of patchedIds) idToItem.delete(id);
285
- end(myVersion);
407
+ result = await asyncAction();
286
408
  } catch {
287
- for (const id of patchedIds) idToItem.delete(id);
288
- end(myVersion, () => setItems(prev));
409
+ failed = true;
289
410
  }
411
+ commit(() => {
412
+ try {
413
+ let visibleChanged = false;
414
+ for (let i = 0; i < claims.length; i++) {
415
+ const row = prepared[i].row;
416
+ const claim = claims[i];
417
+ const before = effectiveValue(row);
418
+ if (failed) {
419
+ dropClaim(row, claim);
420
+ } else {
421
+ claim.value = result;
422
+ claim.settled = true;
423
+ }
424
+ collapse(row);
425
+ if (row.visible && !Object.is(before, effectiveValue(row))) visibleChanged = true;
426
+ }
427
+ return visibleChanged;
428
+ } finally {
429
+ settle(preparedIds);
430
+ }
431
+ });
290
432
  }
291
433
  return {
292
434
  items,
@@ -3,10 +3,10 @@ import {
3
3
  recordDependency,
4
4
  retrack,
5
5
  track
6
- } from "./chunk-OOUQUCNN.js";
6
+ } from "./chunk-ACBT6UZS.js";
7
7
  import {
8
8
  devAssert
9
- } from "./chunk-COY6PUD2.js";
9
+ } from "./chunk-VPP2FONR.js";
10
10
 
11
11
  // src/core/signals/derived.ts
12
12
  function derived(getter, options) {
@@ -43,6 +43,21 @@ function derived(getter, options) {
43
43
  }, markDirty);
44
44
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
45
45
  let evaluating = false;
46
+ const validate = () => {
47
+ if (!cs._d) return;
48
+ const oldValue = cs._v;
49
+ evaluating = true;
50
+ try {
51
+ retrack(recompute, markDirty);
52
+ if (!Object.is(oldValue, cs._v)) cs.__v++;
53
+ } finally {
54
+ evaluating = false;
55
+ }
56
+ if (hook && !Object.is(oldValue, cs._v)) {
57
+ hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
58
+ }
59
+ };
60
+ cs._validate = validate;
46
61
  function computedGetter() {
47
62
  if (evaluating) {
48
63
  throw new Error(
@@ -50,32 +65,11 @@ function derived(getter, options) {
50
65
  );
51
66
  }
52
67
  if (isTrackingSuspended()) {
53
- if (cs._d) {
54
- const prev = cs._v;
55
- evaluating = true;
56
- try {
57
- retrack(recompute, markDirty);
58
- if (!Object.is(prev, cs._v)) cs.__v++;
59
- } finally {
60
- evaluating = false;
61
- }
62
- }
68
+ if (cs._d) validate();
63
69
  return cs._v;
64
70
  }
71
+ if (cs._d) validate();
65
72
  recordDependency(cs);
66
- if (cs._d) {
67
- const oldValue = cs._v;
68
- evaluating = true;
69
- try {
70
- retrack(recompute, markDirty);
71
- if (!Object.is(oldValue, cs._v)) cs.__v++;
72
- } finally {
73
- evaluating = false;
74
- }
75
- if (hook && oldValue !== cs._v) {
76
- hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
77
- }
78
- }
79
73
  return cs._v;
80
74
  }
81
75
  if (debugName) {
@@ -32,7 +32,7 @@ declare function withWrapper<P>(WrappedComponent: Component<P>, wrapper: (compon
32
32
  * Button("Click"); // type="button", disabled=false automatically
33
33
  * ```
34
34
  */
35
- declare function withDefaults<P extends Record<string, unknown>>(component: Component<P>, defaults: Partial<P>): Component<Partial<P>>;
35
+ declare function withDefaults<P extends object>(component: Component<P>, defaults: Partial<P>): Component<Partial<P>>;
36
36
  /**
37
37
  * Composes multiple HOC wrappers into a single wrapper.
38
38
  * Applied from right to left (like function composition).
@@ -117,7 +117,7 @@ type WithNodes<Props> = Props & {
117
117
  * // Usage: Button({ label: 'Click me' }) — TypeScript infers props
118
118
  * ```
119
119
  */
120
- declare function defineComponent<Props extends Record<string, unknown>>(config: {
120
+ declare function defineComponent<Props extends object>(config: {
121
121
  defaults?: Partial<Props>;
122
122
  setup: (props: Props) => HTMLElement;
123
123
  }): (props: Props) => HTMLElement;
@@ -148,7 +148,7 @@ declare function defineComponent<Props extends Record<string, unknown>>(config:
148
148
  * // Usage: Card({ title: 'Hello', nodes: p('World') })
149
149
  * ```
150
150
  */
151
- declare function defineSlottedComponent<Props extends Record<string, unknown>>(config: {
151
+ declare function defineSlottedComponent<Props extends object>(config: {
152
152
  defaults?: Partial<Props>;
153
153
  setup: (props: WithNodes<Props>) => HTMLElement;
154
154
  }): (props: WithNodes<Props>) => HTMLElement;
@@ -177,7 +177,7 @@ declare function defineSlottedComponent<Props extends Record<string, unknown>>(c
177
177
  * // Usage: SmallIconButton({ icon: 'star', label: 'Favorite' })
178
178
  * ```
179
179
  */
180
- declare function withProps<OuterProps extends Record<string, unknown>, InnerProps extends Record<string, unknown>>(component: (props: InnerProps) => HTMLElement, mapProps: (outer: OuterProps) => InnerProps): (props: OuterProps) => HTMLElement;
180
+ declare function withProps<OuterProps extends object, InnerProps extends object>(component: (props: InnerProps) => HTMLElement, mapProps: (outer: OuterProps) => InnerProps): (props: OuterProps) => HTMLElement;
181
181
 
182
182
  /**
183
183
  * Runtime prop validation and strict typing contracts for SibuJS.
@@ -216,12 +216,12 @@ type PropSchema<Props> = {
216
216
  * In production mode (process.env.NODE_ENV === 'production'), validation is skipped
217
217
  * and only defaults are applied for performance.
218
218
  */
219
- declare function validateProps<Props extends Record<string, unknown>>(props: Partial<Props>, schema: PropSchema<Props>): Props;
219
+ declare function validateProps<Props extends object>(props: Partial<Props>, schema: PropSchema<Props>): Props;
220
220
  /**
221
221
  * Define a component with runtime prop validation.
222
222
  * Validates props in development mode, applies defaults, then calls setup.
223
223
  */
224
- declare function defineStrictComponent<Props extends Record<string, unknown>>(config: {
224
+ declare function defineStrictComponent<Props extends object>(config: {
225
225
  name: string;
226
226
  props: PropSchema<Props>;
227
227
  setup: (props: Props) => HTMLElement;