sibujs 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -119
- package/dist/browser.cjs +53 -14
- package/dist/browser.d.cts +14 -9
- package/dist/browser.d.ts +14 -9
- package/dist/browser.js +4 -4
- package/dist/build.cjs +124 -42
- package/dist/build.d.cts +1 -1
- package/dist/build.d.ts +1 -1
- package/dist/build.js +10 -10
- package/dist/cdn.global.js +7 -7
- package/dist/chunk-5ZYQ6KDD.js +154 -0
- package/dist/chunk-6BMPXPUW.js +26 -0
- package/dist/chunk-7GRNSCFT.js +1097 -0
- package/dist/chunk-BGTHZHJ5.js +1016 -0
- package/dist/chunk-BMPL52BF.js +654 -0
- package/dist/chunk-GJPXRJ45.js +37 -0
- package/dist/chunk-JCDUJN2F.js +2779 -0
- package/dist/chunk-K4G4ZQNR.js +286 -0
- package/dist/chunk-MB6QFH3I.js +2776 -0
- package/dist/chunk-MYRV7VDM.js +742 -0
- package/dist/chunk-NZIIMDWI.js +84 -0
- package/dist/chunk-P3XWXJZU.js +282 -0
- package/dist/chunk-PDZQY43A.js +616 -0
- package/dist/chunk-RJ46C3CS.js +1293 -0
- package/dist/chunk-SFKNRVCU.js +292 -0
- package/dist/chunk-TDGZL5CU.js +365 -0
- package/dist/chunk-VAPYJN4X.js +368 -0
- package/dist/chunk-VQDZK23A.js +1023 -0
- package/dist/chunk-VQNQZCWJ.js +61 -0
- package/dist/chunk-XHK6BDAJ.js +76 -0
- package/dist/chunk-XUEEGU5O.js +409 -0
- package/dist/contracts-ey_Qh8ef.d.cts +239 -0
- package/dist/contracts-ey_Qh8ef.d.ts +239 -0
- package/dist/customElement-BL3Uo8dL.d.cts +318 -0
- package/dist/customElement-BL3Uo8dL.d.ts +318 -0
- package/dist/data.cjs +52 -11
- package/dist/data.js +6 -6
- package/dist/devtools.cjs +22 -24
- package/dist/devtools.js +26 -28
- package/dist/ecosystem.cjs +31 -6
- package/dist/ecosystem.d.cts +4 -4
- package/dist/ecosystem.d.ts +4 -4
- package/dist/ecosystem.js +7 -7
- package/dist/extras.cjs +304 -108
- package/dist/extras.d.cts +3 -3
- package/dist/extras.d.ts +3 -3
- package/dist/extras.js +19 -19
- package/dist/index.cjs +124 -42
- package/dist/index.d.cts +58 -48
- package/dist/index.d.ts +58 -48
- package/dist/index.js +10 -10
- package/dist/motion.cjs +13 -2
- package/dist/motion.d.cts +1 -1
- package/dist/motion.d.ts +1 -1
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +91 -24
- package/dist/patterns.d.cts +46 -12
- package/dist/patterns.d.ts +46 -12
- package/dist/patterns.js +5 -5
- package/dist/performance.cjs +97 -12
- package/dist/performance.d.cts +6 -1
- package/dist/performance.d.ts +6 -1
- package/dist/performance.js +5 -3
- package/dist/plugins.cjs +19 -13
- package/dist/plugins.d.cts +3 -3
- package/dist/plugins.d.ts +3 -3
- package/dist/plugins.js +16 -18
- package/dist/ssr.cjs +9 -0
- package/dist/ssr.d.cts +1 -1
- package/dist/ssr.d.ts +1 -1
- package/dist/ssr.js +7 -7
- package/dist/testing.js +2 -2
- package/dist/ui.cjs +130 -48
- package/dist/ui.d.cts +13 -16
- package/dist/ui.d.ts +13 -16
- package/dist/ui.js +6 -6
- package/dist/widgets.cjs +31 -6
- package/dist/widgets.js +5 -5
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -319,14 +319,12 @@ declare function each<T>(getArray: () => T[], render: (item: () => T, index: ()
|
|
|
319
319
|
*
|
|
320
320
|
* @example
|
|
321
321
|
* ```ts
|
|
322
|
-
* div(
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* ]
|
|
329
|
-
* });
|
|
322
|
+
* div([
|
|
323
|
+
* Fragment([
|
|
324
|
+
* p("First"),
|
|
325
|
+
* p("Second"),
|
|
326
|
+
* ])
|
|
327
|
+
* ]);
|
|
330
328
|
* ```
|
|
331
329
|
*
|
|
332
330
|
* @param nodes Array of child nodes to include in the fragment
|
|
@@ -338,6 +336,10 @@ declare function Fragment(nodes: NodeChildren[]): DocumentFragment;
|
|
|
338
336
|
* Portal renders nodes into a DOM node outside the parent component hierarchy.
|
|
339
337
|
* Useful for modals, tooltips, dropdowns, and overlays.
|
|
340
338
|
*
|
|
339
|
+
* Cleanup integrates with `dispose()` / `registerDisposer()` so portals
|
|
340
|
+
* are properly torn down when the anchor is disposed by `when()`, `match()`,
|
|
341
|
+
* `each()`, or manual `dispose(anchor)`.
|
|
342
|
+
*
|
|
341
343
|
* @param nodes Function that returns the content to render
|
|
342
344
|
* @param target Target DOM element (defaults to document.body)
|
|
343
345
|
* @returns A Comment anchor node in the original position
|
|
@@ -345,11 +347,11 @@ declare function Fragment(nodes: NodeChildren[]): DocumentFragment;
|
|
|
345
347
|
* @example
|
|
346
348
|
* ```ts
|
|
347
349
|
* // Render modal at document.body
|
|
348
|
-
* Portal(() => div(
|
|
350
|
+
* Portal(() => div("modal", "Modal content"));
|
|
349
351
|
*
|
|
350
352
|
* // Render into specific container
|
|
351
353
|
* const overlay = document.getElementById("overlay-root")!;
|
|
352
|
-
* Portal(() => div(
|
|
354
|
+
* Portal(() => div("Tooltip"), overlay);
|
|
353
355
|
* ```
|
|
354
356
|
*/
|
|
355
357
|
declare function Portal(nodes: () => HTMLElement, target?: HTMLElement): Comment;
|
|
@@ -382,7 +384,7 @@ declare function unregisterComponent(name: string): void;
|
|
|
382
384
|
* @example
|
|
383
385
|
* ```ts
|
|
384
386
|
* registerComponent("Widget", MyWidget);
|
|
385
|
-
* div(
|
|
387
|
+
* div([resolveComponent("Widget")]);
|
|
386
388
|
* ```
|
|
387
389
|
*/
|
|
388
390
|
declare function resolveComponent(name: string): HTMLElement;
|
|
@@ -418,7 +420,7 @@ declare function getSlot(slots: Slots | undefined, name?: string): SlotFn | unde
|
|
|
418
420
|
* @example
|
|
419
421
|
* ```ts
|
|
420
422
|
* const [visible, setVisible] = signal(true);
|
|
421
|
-
* div(
|
|
423
|
+
* div([show(() => visible(), span("I toggle!"))]);
|
|
422
424
|
* ```
|
|
423
425
|
*/
|
|
424
426
|
declare function show<T extends Element>(condition: () => boolean, element: T): T;
|
|
@@ -435,8 +437,8 @@ declare function show<T extends Element>(condition: () => boolean, element: T):
|
|
|
435
437
|
* ```ts
|
|
436
438
|
* when(
|
|
437
439
|
* () => isLoggedIn(),
|
|
438
|
-
* () => div(
|
|
439
|
-
* () => div(
|
|
440
|
+
* () => div("Welcome!"),
|
|
441
|
+
* () => div("Please log in")
|
|
440
442
|
* );
|
|
441
443
|
* ```
|
|
442
444
|
*/
|
|
@@ -459,7 +461,7 @@ declare function when<T>(condition: () => T, thenBranch: () => NodeChild, elseBr
|
|
|
459
461
|
* error: () => ErrorMessage(),
|
|
460
462
|
* success: () => Content(),
|
|
461
463
|
* },
|
|
462
|
-
* () => div(
|
|
464
|
+
* () => div("Unknown status")
|
|
463
465
|
* );
|
|
464
466
|
* ```
|
|
465
467
|
*/
|
|
@@ -527,8 +529,7 @@ type ActionFn<T = void> = (element: HTMLElement, param: T) => (() => void) | und
|
|
|
527
529
|
* action(el, clickOutside, () => setOpen(false));
|
|
528
530
|
* action(el, longPress, { duration: 500, callback: onLongPress });
|
|
529
531
|
* },
|
|
530
|
-
*
|
|
531
|
-
* });
|
|
532
|
+
* }, "Content");
|
|
532
533
|
* ```
|
|
533
534
|
*/
|
|
534
535
|
declare function action<T>(element: HTMLElement, actionFn: ActionFn<T>, param: T): void;
|
|
@@ -636,10 +637,10 @@ declare function setGlobalErrorHandler(handler: ErrorHandler): void;
|
|
|
636
637
|
* ```ts
|
|
637
638
|
* function Field(labelText: string) {
|
|
638
639
|
* const id = createId("field");
|
|
639
|
-
* return div(
|
|
640
|
-
* label({ for: id,
|
|
640
|
+
* return div([
|
|
641
|
+
* label({ for: id }, labelText),
|
|
641
642
|
* input({ id }),
|
|
642
|
-
* ]
|
|
643
|
+
* ]);
|
|
643
644
|
* }
|
|
644
645
|
* ```
|
|
645
646
|
*/
|
|
@@ -681,9 +682,9 @@ declare const __accessor: unique symbol;
|
|
|
681
682
|
* ```ts
|
|
682
683
|
* const [count, setCount] = signal(0);
|
|
683
684
|
*
|
|
684
|
-
* div(
|
|
685
|
-
* div(
|
|
686
|
-
* div(
|
|
685
|
+
* div(count) // ✓ reactive — Accessor passed directly
|
|
686
|
+
* div(() => count()) // ✓ reactive — explicit arrow wrapper
|
|
687
|
+
* div(count()) // ✗ static — evaluated once, not reactive
|
|
687
688
|
* ```
|
|
688
689
|
*/
|
|
689
690
|
type Accessor<T> = (() => T) & {
|
|
@@ -903,16 +904,23 @@ declare function reactiveArray<T>(initial?: T[]): [Accessor<readonly T[]>, Array
|
|
|
903
904
|
/**
|
|
904
905
|
* Deep equality comparison for objects and arrays.
|
|
905
906
|
* Falls back to Object.is for primitives.
|
|
906
|
-
* Handles circular references
|
|
907
|
+
* Handles circular references, shared sub-references, and common
|
|
908
|
+
* built-in types (Date, RegExp, Map, Set, ArrayBuffer, TypedArrays).
|
|
909
|
+
*
|
|
910
|
+
* The `seen` parameter tracks `(a, b)` pairs — not just `a` — so that
|
|
911
|
+
* a shared sub-object compared against two different partners is always
|
|
912
|
+
* fully checked, while genuine cycles (same a-with-same-b revisited)
|
|
913
|
+
* still terminate.
|
|
907
914
|
*/
|
|
908
|
-
declare function deepEqual(a: unknown, b: unknown, seen?: Set<
|
|
915
|
+
declare function deepEqual(a: unknown, b: unknown, seen?: Map<object, Set<object>>): boolean;
|
|
909
916
|
/**
|
|
910
917
|
* Like signal but uses deep equality comparison instead of Object.is.
|
|
911
918
|
* This prevents unnecessary re-renders when setting an object/array
|
|
912
919
|
* to a structurally identical value.
|
|
913
920
|
*
|
|
914
921
|
* @param initial Initial value
|
|
915
|
-
* @returns Tuple [getter, setter]
|
|
922
|
+
* @returns Tuple [getter, setter] — same shape as `signal()`, preserving
|
|
923
|
+
* the `Accessor<T>` brand on the getter.
|
|
916
924
|
*
|
|
917
925
|
* @example
|
|
918
926
|
* ```ts
|
|
@@ -921,7 +929,7 @@ declare function deepEqual(a: unknown, b: unknown, seen?: Set<unknown>): boolean
|
|
|
921
929
|
* setUser({ name: "Bob", age: 25 }); // Notifies — different value
|
|
922
930
|
* ```
|
|
923
931
|
*/
|
|
924
|
-
declare function deepSignal<T>(initial: T): [
|
|
932
|
+
declare function deepSignal<T>(initial: T): [Accessor<T>, (next: T | ((prev: T) => T)) => void];
|
|
925
933
|
|
|
926
934
|
/**
|
|
927
935
|
* Creates a writable computed value — a derived getter paired with
|
|
@@ -1017,7 +1025,7 @@ declare function asyncDerived<T>(factory: () => Promise<T>, initial: T): AsyncDe
|
|
|
1017
1025
|
* console.log("Component was removed");
|
|
1018
1026
|
* });
|
|
1019
1027
|
*
|
|
1020
|
-
* return div(
|
|
1028
|
+
* return div("Hello");
|
|
1021
1029
|
* }
|
|
1022
1030
|
* ```
|
|
1023
1031
|
*/
|
|
@@ -1054,7 +1062,7 @@ declare function onUnmount(callback: CleanupFn, element: HTMLElement): void;
|
|
|
1054
1062
|
* ```ts
|
|
1055
1063
|
* function RealtimeBar(siteId: string) {
|
|
1056
1064
|
* const ws = new WebSocket(`/ws/sites/${siteId}/realtime`);
|
|
1057
|
-
* const root = div(
|
|
1065
|
+
* const root = div("Realtime data...");
|
|
1058
1066
|
* onCleanup(() => ws.close(), root);
|
|
1059
1067
|
* return root;
|
|
1060
1068
|
* }
|
|
@@ -1063,29 +1071,31 @@ declare function onUnmount(callback: CleanupFn, element: HTMLElement): void;
|
|
|
1063
1071
|
declare function onCleanup(callback: CleanupFn, element: Node): void;
|
|
1064
1072
|
|
|
1065
1073
|
/**
|
|
1066
|
-
* Context API for SibuJS —
|
|
1067
|
-
*
|
|
1074
|
+
* Context API for SibuJS — a reactive global value that any component
|
|
1075
|
+
* can read without prop drilling.
|
|
1076
|
+
*
|
|
1077
|
+
* Note: this is a **global reactive store**, not a subtree-scoped DI
|
|
1078
|
+
* system. Calling `provide()` sets the value for ALL consumers, not
|
|
1079
|
+
* just descendants of the provider. For most apps this is sufficient
|
|
1080
|
+
* — use separate `context()` instances for independent scopes.
|
|
1068
1081
|
*
|
|
1069
1082
|
* @example
|
|
1070
1083
|
* ```ts
|
|
1071
1084
|
* // Create a context with a default value
|
|
1072
1085
|
* const ThemeContext = context("light");
|
|
1073
1086
|
*
|
|
1074
|
-
* //
|
|
1075
|
-
*
|
|
1076
|
-
* ThemeContext.provide("dark");
|
|
1077
|
-
* return div({ nodes: [Child()] });
|
|
1078
|
-
* }
|
|
1087
|
+
* // Set the value (global — affects all consumers)
|
|
1088
|
+
* ThemeContext.provide("dark");
|
|
1079
1089
|
*
|
|
1080
|
-
* //
|
|
1090
|
+
* // Read reactively from any component
|
|
1081
1091
|
* function Child() {
|
|
1082
1092
|
* const theme = ThemeContext.use(); // reactive getter
|
|
1083
|
-
* return div(
|
|
1093
|
+
* return div(() => `Theme: ${theme()}`);
|
|
1084
1094
|
* }
|
|
1085
1095
|
* ```
|
|
1086
1096
|
*/
|
|
1087
1097
|
interface Context<T> {
|
|
1088
|
-
/**
|
|
1098
|
+
/** Set the context value globally. Affects all consumers. */
|
|
1089
1099
|
provide(value: T): void;
|
|
1090
1100
|
/** Get a reactive getter for the current context value. */
|
|
1091
1101
|
use(): () => T;
|
|
@@ -1243,7 +1253,7 @@ declare function nextTick(): Promise<void>;
|
|
|
1243
1253
|
* input({ on: { input: e => setQuery(e.target.value) } });
|
|
1244
1254
|
*
|
|
1245
1255
|
* // heavy list reads deferredQuery() and updates one frame later
|
|
1246
|
-
* each(() => heavyFilter(items, deferredQuery()), row => li(
|
|
1256
|
+
* each(() => heavyFilter(items, deferredQuery()), row => li(row.name));
|
|
1247
1257
|
* ```
|
|
1248
1258
|
*/
|
|
1249
1259
|
declare function defer<T>(getter: () => T): () => T;
|
|
@@ -1312,7 +1322,7 @@ type LazyImport = () => Promise<{
|
|
|
1312
1322
|
* // Use inside Suspense for custom loading UI
|
|
1313
1323
|
* Suspense({
|
|
1314
1324
|
* nodes: () => LazyDashboard(),
|
|
1315
|
-
* fallback: () => div(
|
|
1325
|
+
* fallback: () => div("Loading dashboard..."),
|
|
1316
1326
|
* });
|
|
1317
1327
|
*
|
|
1318
1328
|
* // Or use standalone — shows default "Loading..." text
|
|
@@ -1330,7 +1340,7 @@ declare function lazy(importFn: LazyImport): Component;
|
|
|
1330
1340
|
* ```ts
|
|
1331
1341
|
* Suspense({
|
|
1332
1342
|
* nodes: () => LazyChart(),
|
|
1333
|
-
* fallback: () => div(
|
|
1343
|
+
* fallback: () => div("Loading chart..."),
|
|
1334
1344
|
* });
|
|
1335
1345
|
* ```
|
|
1336
1346
|
*
|
|
@@ -1370,7 +1380,7 @@ interface ErrorBoundaryProps {
|
|
|
1370
1380
|
* const [route, setRoute] = signal("/");
|
|
1371
1381
|
* ErrorBoundary({
|
|
1372
1382
|
* resetKeys: [route],
|
|
1373
|
-
* nodes: () => div(
|
|
1383
|
+
* nodes: () => div(riskyPageFor(route())),
|
|
1374
1384
|
* });
|
|
1375
1385
|
* ```
|
|
1376
1386
|
*/
|
|
@@ -1429,13 +1439,13 @@ interface ErrorDisplayProps {
|
|
|
1429
1439
|
*
|
|
1430
1440
|
* @example
|
|
1431
1441
|
* ```ts
|
|
1432
|
-
* button(
|
|
1433
|
-
* on: { click: async () => {
|
|
1442
|
+
* button(
|
|
1443
|
+
* { on: { click: async () => {
|
|
1434
1444
|
* try { await save(); }
|
|
1435
1445
|
* catch (err) { mount(ErrorDisplay({ error: err, onRetry: save }), errorHost); }
|
|
1436
|
-
* }},
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1446
|
+
* }}},
|
|
1447
|
+
* "Save",
|
|
1448
|
+
* );
|
|
1439
1449
|
* ```
|
|
1440
1450
|
*/
|
|
1441
1451
|
declare function ErrorDisplay(props: ErrorDisplayProps): Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -319,14 +319,12 @@ declare function each<T>(getArray: () => T[], render: (item: () => T, index: ()
|
|
|
319
319
|
*
|
|
320
320
|
* @example
|
|
321
321
|
* ```ts
|
|
322
|
-
* div(
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* ]
|
|
329
|
-
* });
|
|
322
|
+
* div([
|
|
323
|
+
* Fragment([
|
|
324
|
+
* p("First"),
|
|
325
|
+
* p("Second"),
|
|
326
|
+
* ])
|
|
327
|
+
* ]);
|
|
330
328
|
* ```
|
|
331
329
|
*
|
|
332
330
|
* @param nodes Array of child nodes to include in the fragment
|
|
@@ -338,6 +336,10 @@ declare function Fragment(nodes: NodeChildren[]): DocumentFragment;
|
|
|
338
336
|
* Portal renders nodes into a DOM node outside the parent component hierarchy.
|
|
339
337
|
* Useful for modals, tooltips, dropdowns, and overlays.
|
|
340
338
|
*
|
|
339
|
+
* Cleanup integrates with `dispose()` / `registerDisposer()` so portals
|
|
340
|
+
* are properly torn down when the anchor is disposed by `when()`, `match()`,
|
|
341
|
+
* `each()`, or manual `dispose(anchor)`.
|
|
342
|
+
*
|
|
341
343
|
* @param nodes Function that returns the content to render
|
|
342
344
|
* @param target Target DOM element (defaults to document.body)
|
|
343
345
|
* @returns A Comment anchor node in the original position
|
|
@@ -345,11 +347,11 @@ declare function Fragment(nodes: NodeChildren[]): DocumentFragment;
|
|
|
345
347
|
* @example
|
|
346
348
|
* ```ts
|
|
347
349
|
* // Render modal at document.body
|
|
348
|
-
* Portal(() => div(
|
|
350
|
+
* Portal(() => div("modal", "Modal content"));
|
|
349
351
|
*
|
|
350
352
|
* // Render into specific container
|
|
351
353
|
* const overlay = document.getElementById("overlay-root")!;
|
|
352
|
-
* Portal(() => div(
|
|
354
|
+
* Portal(() => div("Tooltip"), overlay);
|
|
353
355
|
* ```
|
|
354
356
|
*/
|
|
355
357
|
declare function Portal(nodes: () => HTMLElement, target?: HTMLElement): Comment;
|
|
@@ -382,7 +384,7 @@ declare function unregisterComponent(name: string): void;
|
|
|
382
384
|
* @example
|
|
383
385
|
* ```ts
|
|
384
386
|
* registerComponent("Widget", MyWidget);
|
|
385
|
-
* div(
|
|
387
|
+
* div([resolveComponent("Widget")]);
|
|
386
388
|
* ```
|
|
387
389
|
*/
|
|
388
390
|
declare function resolveComponent(name: string): HTMLElement;
|
|
@@ -418,7 +420,7 @@ declare function getSlot(slots: Slots | undefined, name?: string): SlotFn | unde
|
|
|
418
420
|
* @example
|
|
419
421
|
* ```ts
|
|
420
422
|
* const [visible, setVisible] = signal(true);
|
|
421
|
-
* div(
|
|
423
|
+
* div([show(() => visible(), span("I toggle!"))]);
|
|
422
424
|
* ```
|
|
423
425
|
*/
|
|
424
426
|
declare function show<T extends Element>(condition: () => boolean, element: T): T;
|
|
@@ -435,8 +437,8 @@ declare function show<T extends Element>(condition: () => boolean, element: T):
|
|
|
435
437
|
* ```ts
|
|
436
438
|
* when(
|
|
437
439
|
* () => isLoggedIn(),
|
|
438
|
-
* () => div(
|
|
439
|
-
* () => div(
|
|
440
|
+
* () => div("Welcome!"),
|
|
441
|
+
* () => div("Please log in")
|
|
440
442
|
* );
|
|
441
443
|
* ```
|
|
442
444
|
*/
|
|
@@ -459,7 +461,7 @@ declare function when<T>(condition: () => T, thenBranch: () => NodeChild, elseBr
|
|
|
459
461
|
* error: () => ErrorMessage(),
|
|
460
462
|
* success: () => Content(),
|
|
461
463
|
* },
|
|
462
|
-
* () => div(
|
|
464
|
+
* () => div("Unknown status")
|
|
463
465
|
* );
|
|
464
466
|
* ```
|
|
465
467
|
*/
|
|
@@ -527,8 +529,7 @@ type ActionFn<T = void> = (element: HTMLElement, param: T) => (() => void) | und
|
|
|
527
529
|
* action(el, clickOutside, () => setOpen(false));
|
|
528
530
|
* action(el, longPress, { duration: 500, callback: onLongPress });
|
|
529
531
|
* },
|
|
530
|
-
*
|
|
531
|
-
* });
|
|
532
|
+
* }, "Content");
|
|
532
533
|
* ```
|
|
533
534
|
*/
|
|
534
535
|
declare function action<T>(element: HTMLElement, actionFn: ActionFn<T>, param: T): void;
|
|
@@ -636,10 +637,10 @@ declare function setGlobalErrorHandler(handler: ErrorHandler): void;
|
|
|
636
637
|
* ```ts
|
|
637
638
|
* function Field(labelText: string) {
|
|
638
639
|
* const id = createId("field");
|
|
639
|
-
* return div(
|
|
640
|
-
* label({ for: id,
|
|
640
|
+
* return div([
|
|
641
|
+
* label({ for: id }, labelText),
|
|
641
642
|
* input({ id }),
|
|
642
|
-
* ]
|
|
643
|
+
* ]);
|
|
643
644
|
* }
|
|
644
645
|
* ```
|
|
645
646
|
*/
|
|
@@ -681,9 +682,9 @@ declare const __accessor: unique symbol;
|
|
|
681
682
|
* ```ts
|
|
682
683
|
* const [count, setCount] = signal(0);
|
|
683
684
|
*
|
|
684
|
-
* div(
|
|
685
|
-
* div(
|
|
686
|
-
* div(
|
|
685
|
+
* div(count) // ✓ reactive — Accessor passed directly
|
|
686
|
+
* div(() => count()) // ✓ reactive — explicit arrow wrapper
|
|
687
|
+
* div(count()) // ✗ static — evaluated once, not reactive
|
|
687
688
|
* ```
|
|
688
689
|
*/
|
|
689
690
|
type Accessor<T> = (() => T) & {
|
|
@@ -903,16 +904,23 @@ declare function reactiveArray<T>(initial?: T[]): [Accessor<readonly T[]>, Array
|
|
|
903
904
|
/**
|
|
904
905
|
* Deep equality comparison for objects and arrays.
|
|
905
906
|
* Falls back to Object.is for primitives.
|
|
906
|
-
* Handles circular references
|
|
907
|
+
* Handles circular references, shared sub-references, and common
|
|
908
|
+
* built-in types (Date, RegExp, Map, Set, ArrayBuffer, TypedArrays).
|
|
909
|
+
*
|
|
910
|
+
* The `seen` parameter tracks `(a, b)` pairs — not just `a` — so that
|
|
911
|
+
* a shared sub-object compared against two different partners is always
|
|
912
|
+
* fully checked, while genuine cycles (same a-with-same-b revisited)
|
|
913
|
+
* still terminate.
|
|
907
914
|
*/
|
|
908
|
-
declare function deepEqual(a: unknown, b: unknown, seen?: Set<
|
|
915
|
+
declare function deepEqual(a: unknown, b: unknown, seen?: Map<object, Set<object>>): boolean;
|
|
909
916
|
/**
|
|
910
917
|
* Like signal but uses deep equality comparison instead of Object.is.
|
|
911
918
|
* This prevents unnecessary re-renders when setting an object/array
|
|
912
919
|
* to a structurally identical value.
|
|
913
920
|
*
|
|
914
921
|
* @param initial Initial value
|
|
915
|
-
* @returns Tuple [getter, setter]
|
|
922
|
+
* @returns Tuple [getter, setter] — same shape as `signal()`, preserving
|
|
923
|
+
* the `Accessor<T>` brand on the getter.
|
|
916
924
|
*
|
|
917
925
|
* @example
|
|
918
926
|
* ```ts
|
|
@@ -921,7 +929,7 @@ declare function deepEqual(a: unknown, b: unknown, seen?: Set<unknown>): boolean
|
|
|
921
929
|
* setUser({ name: "Bob", age: 25 }); // Notifies — different value
|
|
922
930
|
* ```
|
|
923
931
|
*/
|
|
924
|
-
declare function deepSignal<T>(initial: T): [
|
|
932
|
+
declare function deepSignal<T>(initial: T): [Accessor<T>, (next: T | ((prev: T) => T)) => void];
|
|
925
933
|
|
|
926
934
|
/**
|
|
927
935
|
* Creates a writable computed value — a derived getter paired with
|
|
@@ -1017,7 +1025,7 @@ declare function asyncDerived<T>(factory: () => Promise<T>, initial: T): AsyncDe
|
|
|
1017
1025
|
* console.log("Component was removed");
|
|
1018
1026
|
* });
|
|
1019
1027
|
*
|
|
1020
|
-
* return div(
|
|
1028
|
+
* return div("Hello");
|
|
1021
1029
|
* }
|
|
1022
1030
|
* ```
|
|
1023
1031
|
*/
|
|
@@ -1054,7 +1062,7 @@ declare function onUnmount(callback: CleanupFn, element: HTMLElement): void;
|
|
|
1054
1062
|
* ```ts
|
|
1055
1063
|
* function RealtimeBar(siteId: string) {
|
|
1056
1064
|
* const ws = new WebSocket(`/ws/sites/${siteId}/realtime`);
|
|
1057
|
-
* const root = div(
|
|
1065
|
+
* const root = div("Realtime data...");
|
|
1058
1066
|
* onCleanup(() => ws.close(), root);
|
|
1059
1067
|
* return root;
|
|
1060
1068
|
* }
|
|
@@ -1063,29 +1071,31 @@ declare function onUnmount(callback: CleanupFn, element: HTMLElement): void;
|
|
|
1063
1071
|
declare function onCleanup(callback: CleanupFn, element: Node): void;
|
|
1064
1072
|
|
|
1065
1073
|
/**
|
|
1066
|
-
* Context API for SibuJS —
|
|
1067
|
-
*
|
|
1074
|
+
* Context API for SibuJS — a reactive global value that any component
|
|
1075
|
+
* can read without prop drilling.
|
|
1076
|
+
*
|
|
1077
|
+
* Note: this is a **global reactive store**, not a subtree-scoped DI
|
|
1078
|
+
* system. Calling `provide()` sets the value for ALL consumers, not
|
|
1079
|
+
* just descendants of the provider. For most apps this is sufficient
|
|
1080
|
+
* — use separate `context()` instances for independent scopes.
|
|
1068
1081
|
*
|
|
1069
1082
|
* @example
|
|
1070
1083
|
* ```ts
|
|
1071
1084
|
* // Create a context with a default value
|
|
1072
1085
|
* const ThemeContext = context("light");
|
|
1073
1086
|
*
|
|
1074
|
-
* //
|
|
1075
|
-
*
|
|
1076
|
-
* ThemeContext.provide("dark");
|
|
1077
|
-
* return div({ nodes: [Child()] });
|
|
1078
|
-
* }
|
|
1087
|
+
* // Set the value (global — affects all consumers)
|
|
1088
|
+
* ThemeContext.provide("dark");
|
|
1079
1089
|
*
|
|
1080
|
-
* //
|
|
1090
|
+
* // Read reactively from any component
|
|
1081
1091
|
* function Child() {
|
|
1082
1092
|
* const theme = ThemeContext.use(); // reactive getter
|
|
1083
|
-
* return div(
|
|
1093
|
+
* return div(() => `Theme: ${theme()}`);
|
|
1084
1094
|
* }
|
|
1085
1095
|
* ```
|
|
1086
1096
|
*/
|
|
1087
1097
|
interface Context<T> {
|
|
1088
|
-
/**
|
|
1098
|
+
/** Set the context value globally. Affects all consumers. */
|
|
1089
1099
|
provide(value: T): void;
|
|
1090
1100
|
/** Get a reactive getter for the current context value. */
|
|
1091
1101
|
use(): () => T;
|
|
@@ -1243,7 +1253,7 @@ declare function nextTick(): Promise<void>;
|
|
|
1243
1253
|
* input({ on: { input: e => setQuery(e.target.value) } });
|
|
1244
1254
|
*
|
|
1245
1255
|
* // heavy list reads deferredQuery() and updates one frame later
|
|
1246
|
-
* each(() => heavyFilter(items, deferredQuery()), row => li(
|
|
1256
|
+
* each(() => heavyFilter(items, deferredQuery()), row => li(row.name));
|
|
1247
1257
|
* ```
|
|
1248
1258
|
*/
|
|
1249
1259
|
declare function defer<T>(getter: () => T): () => T;
|
|
@@ -1312,7 +1322,7 @@ type LazyImport = () => Promise<{
|
|
|
1312
1322
|
* // Use inside Suspense for custom loading UI
|
|
1313
1323
|
* Suspense({
|
|
1314
1324
|
* nodes: () => LazyDashboard(),
|
|
1315
|
-
* fallback: () => div(
|
|
1325
|
+
* fallback: () => div("Loading dashboard..."),
|
|
1316
1326
|
* });
|
|
1317
1327
|
*
|
|
1318
1328
|
* // Or use standalone — shows default "Loading..." text
|
|
@@ -1330,7 +1340,7 @@ declare function lazy(importFn: LazyImport): Component;
|
|
|
1330
1340
|
* ```ts
|
|
1331
1341
|
* Suspense({
|
|
1332
1342
|
* nodes: () => LazyChart(),
|
|
1333
|
-
* fallback: () => div(
|
|
1343
|
+
* fallback: () => div("Loading chart..."),
|
|
1334
1344
|
* });
|
|
1335
1345
|
* ```
|
|
1336
1346
|
*
|
|
@@ -1370,7 +1380,7 @@ interface ErrorBoundaryProps {
|
|
|
1370
1380
|
* const [route, setRoute] = signal("/");
|
|
1371
1381
|
* ErrorBoundary({
|
|
1372
1382
|
* resetKeys: [route],
|
|
1373
|
-
* nodes: () => div(
|
|
1383
|
+
* nodes: () => div(riskyPageFor(route())),
|
|
1374
1384
|
* });
|
|
1375
1385
|
* ```
|
|
1376
1386
|
*/
|
|
@@ -1429,13 +1439,13 @@ interface ErrorDisplayProps {
|
|
|
1429
1439
|
*
|
|
1430
1440
|
* @example
|
|
1431
1441
|
* ```ts
|
|
1432
|
-
* button(
|
|
1433
|
-
* on: { click: async () => {
|
|
1442
|
+
* button(
|
|
1443
|
+
* { on: { click: async () => {
|
|
1434
1444
|
* try { await save(); }
|
|
1435
1445
|
* catch (err) { mount(ErrorDisplay({ error: err, onRetry: save }), errorHost); }
|
|
1436
|
-
* }},
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1446
|
+
* }}},
|
|
1447
|
+
* "Save",
|
|
1448
|
+
* );
|
|
1439
1449
|
* ```
|
|
1440
1450
|
*/
|
|
1441
1451
|
declare function ErrorDisplay(props: ErrorDisplayProps): Element;
|
package/dist/index.js
CHANGED
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
unregisterComponent,
|
|
44
44
|
when,
|
|
45
45
|
writable
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-JCDUJN2F.js";
|
|
47
47
|
import {
|
|
48
48
|
__resetIdCounter,
|
|
49
49
|
createId
|
|
@@ -185,31 +185,31 @@ import {
|
|
|
185
185
|
use,
|
|
186
186
|
var_,
|
|
187
187
|
video
|
|
188
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-P3XWXJZU.js";
|
|
189
189
|
import {
|
|
190
190
|
watch
|
|
191
|
-
} from "./chunk-
|
|
191
|
+
} from "./chunk-GJPXRJ45.js";
|
|
192
192
|
import {
|
|
193
193
|
context
|
|
194
|
-
} from "./chunk-
|
|
194
|
+
} from "./chunk-6BMPXPUW.js";
|
|
195
195
|
import {
|
|
196
196
|
SVG_NS,
|
|
197
197
|
tagFactory
|
|
198
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-SFKNRVCU.js";
|
|
199
199
|
import {
|
|
200
200
|
bindDynamic,
|
|
201
201
|
checkLeaks,
|
|
202
202
|
dispose,
|
|
203
203
|
registerDisposer
|
|
204
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-5ZYQ6KDD.js";
|
|
205
205
|
import {
|
|
206
206
|
derived
|
|
207
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-XHK6BDAJ.js";
|
|
208
208
|
import "./chunk-CMBFNA7L.js";
|
|
209
209
|
import {
|
|
210
210
|
effect,
|
|
211
211
|
on
|
|
212
|
-
} from "./chunk-
|
|
212
|
+
} from "./chunk-VQNQZCWJ.js";
|
|
213
213
|
import {
|
|
214
214
|
disableSSR,
|
|
215
215
|
enableSSR,
|
|
@@ -221,10 +221,10 @@ import {
|
|
|
221
221
|
enqueueBatchedSignal,
|
|
222
222
|
isBatching,
|
|
223
223
|
signal
|
|
224
|
-
} from "./chunk-
|
|
224
|
+
} from "./chunk-NZIIMDWI.js";
|
|
225
225
|
import {
|
|
226
226
|
untracked
|
|
227
|
-
} from "./chunk-
|
|
227
|
+
} from "./chunk-K4G4ZQNR.js";
|
|
228
228
|
import "./chunk-5X6PP2UK.js";
|
|
229
229
|
export {
|
|
230
230
|
DynamicComponent,
|
package/dist/motion.cjs
CHANGED
|
@@ -57,20 +57,29 @@ function transition(element, options = {}) {
|
|
|
57
57
|
onLeaveDone
|
|
58
58
|
} = options;
|
|
59
59
|
const transitionValue = `${property} ${duration}ms ${easing} ${delay}ms`;
|
|
60
|
+
let activeTimer = null;
|
|
61
|
+
function cancelPending() {
|
|
62
|
+
if (activeTimer !== null) {
|
|
63
|
+
clearTimeout(activeTimer);
|
|
64
|
+
activeTimer = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
60
67
|
function enter() {
|
|
61
68
|
return new Promise((resolve) => {
|
|
69
|
+
cancelPending();
|
|
62
70
|
element.style.transition = transitionValue;
|
|
63
71
|
if (enterClass) element.classList.add(enterClass);
|
|
64
72
|
if (leaveClass) element.classList.remove(leaveClass);
|
|
65
73
|
void element.offsetHeight;
|
|
66
74
|
if (activeClass) element.classList.add(activeClass);
|
|
67
75
|
const done = () => {
|
|
76
|
+
activeTimer = null;
|
|
68
77
|
if (enterClass) element.classList.remove(enterClass);
|
|
69
78
|
onEnterDone?.();
|
|
70
79
|
resolve();
|
|
71
80
|
};
|
|
72
81
|
if (duration > 0) {
|
|
73
|
-
setTimeout(done, duration + delay);
|
|
82
|
+
activeTimer = setTimeout(done, duration + delay);
|
|
74
83
|
} else {
|
|
75
84
|
done();
|
|
76
85
|
}
|
|
@@ -78,17 +87,19 @@ function transition(element, options = {}) {
|
|
|
78
87
|
}
|
|
79
88
|
function leave() {
|
|
80
89
|
return new Promise((resolve) => {
|
|
90
|
+
cancelPending();
|
|
81
91
|
element.style.transition = transitionValue;
|
|
82
92
|
if (activeClass) element.classList.remove(activeClass);
|
|
83
93
|
if (leaveClass) element.classList.add(leaveClass);
|
|
84
94
|
if (enterClass) element.classList.remove(enterClass);
|
|
85
95
|
const done = () => {
|
|
96
|
+
activeTimer = null;
|
|
86
97
|
if (leaveClass) element.classList.remove(leaveClass);
|
|
87
98
|
onLeaveDone?.();
|
|
88
99
|
resolve();
|
|
89
100
|
};
|
|
90
101
|
if (duration > 0) {
|
|
91
|
-
setTimeout(done, duration + delay);
|
|
102
|
+
activeTimer = setTimeout(done, duration + delay);
|
|
92
103
|
} else {
|
|
93
104
|
done();
|
|
94
105
|
}
|
package/dist/motion.d.cts
CHANGED
package/dist/motion.d.ts
CHANGED
package/dist/motion.js
CHANGED
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
stagger,
|
|
20
20
|
transition,
|
|
21
21
|
viewTransition
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
22
|
+
} from "./chunk-XUEEGU5O.js";
|
|
23
|
+
import "./chunk-NZIIMDWI.js";
|
|
24
|
+
import "./chunk-K4G4ZQNR.js";
|
|
25
25
|
import "./chunk-5X6PP2UK.js";
|
|
26
26
|
export {
|
|
27
27
|
TransitionGroup,
|