sibujs 4.6.0 → 4.7.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 +1 -1
- package/dist/browser.cjs +18 -5
- package/dist/browser.js +4 -4
- package/dist/build.cjs +1956 -1007
- package/dist/build.d.cts +133 -44
- package/dist/build.d.ts +133 -44
- package/dist/build.js +1368 -569
- package/dist/cdn.dev.global.js +12 -12
- package/dist/cdn.full.dev.global.js +11 -11
- package/dist/cdn.full.global.js +10 -10
- package/dist/cdn.global.js +12 -12
- package/dist/{chunk-SXXVZMKZ.js → chunk-2BPG2XDA.js} +5 -5
- package/dist/{chunk-BAAG6ZTI.js → chunk-3QWBSL5R.js} +4 -4
- package/dist/{chunk-5MT6SJ3P.js → chunk-4AWA2PVD.js} +2 -2
- package/dist/{chunk-JSXPZCET.js → chunk-7LUJQAOJ.js} +1 -1
- package/dist/{chunk-3ISI6ACU.js → chunk-BC2SECJD.js} +1 -1
- package/dist/{chunk-DKGBBKOF.js → chunk-BSY63EM6.js} +2 -2
- package/dist/{chunk-7NCARGJW.js → chunk-DKXRACVN.js} +3 -3
- package/dist/{chunk-47M47FOM.js → chunk-FNJXNGYZ.js} +1 -1
- package/dist/{chunk-D33YTSX5.js → chunk-FQRUXCEE.js} +5 -4
- package/dist/{chunk-5Q4R7HCL.js → chunk-JWKYU5GV.js} +11 -2
- package/dist/{chunk-QE4TTDU3.js → chunk-RUSSKG6G.js} +12 -11
- package/dist/{chunk-UZQ6ALFS.js → chunk-SLM3IA34.js} +1 -1
- package/dist/{chunk-XRRZKZYX.js → chunk-UNWRJRKC.js} +1 -1
- package/dist/{chunk-VVWPJ543.js → chunk-UOL2ECCS.js} +40 -11
- package/dist/{chunk-ORMZXBKQ.js → chunk-VZSG24LS.js} +3 -3
- package/dist/{chunk-XC4MEKGA.js → chunk-WEQ3DMVL.js} +8 -2
- package/dist/{chunk-PK6FK2G2.js → chunk-WOLJZUFQ.js} +176 -27
- package/dist/{chunk-7GQCWFOE.js → chunk-XYV3EDB7.js} +143 -74
- package/dist/{chunk-AIF3Z2T7.js → chunk-XZR4PXRE.js} +3 -3
- package/dist/{chunk-HYXDKS4N.js → chunk-Z3OHK6QT.js} +4 -4
- package/dist/{chunk-OXUY2A6L.js → chunk-ZVL7TY4K.js} +2 -2
- package/dist/{contracts-DRIuclVT.d.ts → contracts-CLqzJnOV.d.ts} +28 -17
- package/dist/{contracts-DRIuclVT.d.cts → contracts-CTOJXu-x.d.cts} +28 -17
- package/dist/data.cjs +198 -39
- package/dist/data.d.cts +119 -3
- package/dist/data.d.ts +119 -3
- package/dist/data.js +5 -5
- package/dist/devtools.cjs +18 -5
- package/dist/devtools.js +4 -4
- package/dist/ecosystem.cjs +64 -23
- package/dist/ecosystem.d.cts +2 -1
- package/dist/ecosystem.d.ts +2 -1
- package/dist/ecosystem.js +7 -7
- package/dist/extras.cjs +236 -49
- package/dist/extras.d.cts +3 -2
- package/dist/extras.d.ts +3 -2
- package/dist/extras.js +20 -20
- package/dist/index.cjs +259 -108
- package/dist/index.d.cts +193 -168
- package/dist/index.d.ts +193 -168
- package/dist/index.js +10 -10
- package/dist/motion.cjs +12 -4
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +28 -15
- package/dist/patterns.d.cts +2 -1
- package/dist/patterns.d.ts +2 -1
- package/dist/patterns.js +5 -5
- package/dist/performance.cjs +18 -5
- package/dist/performance.js +4 -4
- package/dist/plugins.cjs +118 -34
- package/dist/plugins.d.cts +124 -11
- package/dist/plugins.d.ts +124 -11
- package/dist/plugins.js +68 -26
- package/dist/ssr.cjs +54 -13
- package/dist/ssr.js +7 -7
- package/dist/{tagFactory-DFstCLQV.d.cts → tagFactory-8qL9LCIx.d.cts} +58 -19
- package/dist/{tagFactory-DkaNVUNV.d.ts → tagFactory-BL2fymez.d.ts} +58 -19
- package/dist/testing.cjs +15 -2
- package/dist/testing.js +2 -2
- package/dist/types-CJFViL6Q.d.cts +26 -0
- package/dist/types-CJFViL6Q.d.ts +26 -0
- package/dist/ui.cjs +28 -15
- package/dist/ui.d.cts +2 -1
- package/dist/ui.d.ts +2 -1
- package/dist/ui.js +7 -7
- package/dist/widgets.cjs +22 -14
- package/dist/widgets.js +6 -6
- package/package.json +4 -2
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { C as Component } from './types-CJFViL6Q.cjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Higher-order component utilities for SibuJS.
|
|
3
5
|
* These functions wrap or compose components to add behavior.
|
|
6
|
+
*
|
|
7
|
+
* Each helper is generic over the wrapped component's root type `R`, so a
|
|
8
|
+
* component returning `div()` keeps its `HTMLDivElement` root and an SVG
|
|
9
|
+
* component works as well. `R` defaults to `HTMLElement`, the type these
|
|
10
|
+
* helpers used before, for callers that pass the type arguments explicitly.
|
|
4
11
|
*/
|
|
5
|
-
|
|
12
|
+
|
|
6
13
|
/**
|
|
7
14
|
* Wraps a component with additional behavior that runs before/after rendering.
|
|
8
15
|
*
|
|
@@ -18,7 +25,7 @@ type Component<P = unknown> = (props: P) => HTMLElement;
|
|
|
18
25
|
* });
|
|
19
26
|
* ```
|
|
20
27
|
*/
|
|
21
|
-
declare function withWrapper<P>(WrappedComponent: Component<P>, wrapper: (component: Component<P>, props: P) =>
|
|
28
|
+
declare function withWrapper<P, R extends Node = HTMLElement, W extends Node = R>(WrappedComponent: Component<P, R>, wrapper: (component: Component<P, R>, props: P) => W): Component<P, W>;
|
|
22
29
|
/**
|
|
23
30
|
* Adds default props to a component. Missing props are filled from defaults.
|
|
24
31
|
*
|
|
@@ -38,9 +45,9 @@ declare function withWrapper<P>(WrappedComponent: Component<P>, wrapper: (compon
|
|
|
38
45
|
* optional status.
|
|
39
46
|
*/
|
|
40
47
|
type WithDefaultsProps<P, D> = Omit<P, keyof D> & Partial<Pick<P, Extract<keyof P, keyof D>>>;
|
|
41
|
-
declare function withDefaults<P extends object, const D extends Partial<P> = Partial<P
|
|
48
|
+
declare function withDefaults<P extends object, const D extends Partial<P> = Partial<P>, R extends Node = HTMLElement>(component: Component<P, R>, defaults: D & {
|
|
42
49
|
[K in Exclude<keyof D, keyof P>]: never;
|
|
43
|
-
}): Component<WithDefaultsProps<P, D
|
|
50
|
+
}): Component<WithDefaultsProps<P, D>, R>;
|
|
44
51
|
/**
|
|
45
52
|
* Composes multiple HOC wrappers into a single wrapper.
|
|
46
53
|
* Applied from right to left (like function composition).
|
|
@@ -54,7 +61,7 @@ declare function withDefaults<P extends object, const D extends Partial<P> = Par
|
|
|
54
61
|
* const EnhancedPage = enhance(Page);
|
|
55
62
|
* ```
|
|
56
63
|
*/
|
|
57
|
-
declare function compose(...wrappers: Array<(component:
|
|
64
|
+
declare function compose<C extends Component<never, Node> = Component<unknown, HTMLElement>>(...wrappers: Array<(component: C) => C>): (component: C) => C;
|
|
58
65
|
|
|
59
66
|
/**
|
|
60
67
|
* RenderProp implements the render-prop pattern.
|
|
@@ -83,6 +90,7 @@ declare function createSlots(slots: Record<string, () => HTMLElement | HTMLEleme
|
|
|
83
90
|
* Provides utilities to define typed components with prop defaults,
|
|
84
91
|
* nodes slots, and prop mapping — all with full TypeScript inference.
|
|
85
92
|
*/
|
|
93
|
+
|
|
86
94
|
/**
|
|
87
95
|
* Extract the props type from a component defined with defineComponent.
|
|
88
96
|
*
|
|
@@ -94,7 +102,7 @@ declare function createSlots(slots: Record<string, () => HTMLElement | HTMLEleme
|
|
|
94
102
|
* type ButtonProps = ComponentProps<typeof Button>; // { label: string }
|
|
95
103
|
* ```
|
|
96
104
|
*/
|
|
97
|
-
type ComponentProps<T> = T extends (props: infer P) =>
|
|
105
|
+
type ComponentProps<T> = T extends (props: infer P) => Node ? P : never;
|
|
98
106
|
/**
|
|
99
107
|
* Props that include an optional nodes slot.
|
|
100
108
|
*/
|
|
@@ -104,11 +112,14 @@ type WithNodes<Props> = Props & {
|
|
|
104
112
|
/**
|
|
105
113
|
* Define a typed component with props inference, defaults, and a setup function.
|
|
106
114
|
*
|
|
107
|
-
* The `setup` function receives merged props (defaults + provided) and
|
|
108
|
-
*
|
|
115
|
+
* The `setup` function receives merged props (defaults + provided) and
|
|
116
|
+
* returns the component's root. TypeScript infers the full props type from the
|
|
117
|
+
* generic. `R` is the root type; it defaults to `HTMLElement` (every HTML tag
|
|
118
|
+
* factory's result fits) — pass it explicitly for an SVG root
|
|
119
|
+
* (`defineComponent<Props, SVGSVGElement>`).
|
|
109
120
|
*
|
|
110
121
|
* @param config Component configuration with optional defaults and a setup function
|
|
111
|
-
* @returns A component function that accepts props and returns
|
|
122
|
+
* @returns A component function that accepts props and returns the root
|
|
112
123
|
*
|
|
113
124
|
* @example
|
|
114
125
|
* ```ts
|
|
@@ -125,10 +136,10 @@ type WithNodes<Props> = Props & {
|
|
|
125
136
|
* // Usage: Button({ label: 'Click me' }) — TypeScript infers props
|
|
126
137
|
* ```
|
|
127
138
|
*/
|
|
128
|
-
declare function defineComponent<Props extends object>(config: {
|
|
139
|
+
declare function defineComponent<Props extends object, R extends Node = HTMLElement>(config: {
|
|
129
140
|
defaults?: Partial<Props>;
|
|
130
|
-
setup: (props: Props) =>
|
|
131
|
-
}):
|
|
141
|
+
setup: (props: Props) => R;
|
|
142
|
+
}): Component<Props, R>;
|
|
132
143
|
/**
|
|
133
144
|
* Create a component with nodes slot support.
|
|
134
145
|
*
|
|
@@ -137,7 +148,7 @@ declare function defineComponent<Props extends object>(config: {
|
|
|
137
148
|
* wraps arbitrary child content.
|
|
138
149
|
*
|
|
139
150
|
* @param config Component configuration with optional defaults and a setup function
|
|
140
|
-
* @returns A component function that accepts props (including nodes) and returns
|
|
151
|
+
* @returns A component function that accepts props (including nodes) and returns the root
|
|
141
152
|
*
|
|
142
153
|
* @example
|
|
143
154
|
* ```ts
|
|
@@ -156,10 +167,10 @@ declare function defineComponent<Props extends object>(config: {
|
|
|
156
167
|
* // Usage: Card({ title: 'Hello', nodes: p('World') })
|
|
157
168
|
* ```
|
|
158
169
|
*/
|
|
159
|
-
declare function defineSlottedComponent<Props extends object>(config: {
|
|
170
|
+
declare function defineSlottedComponent<Props extends object, R extends Node = HTMLElement>(config: {
|
|
160
171
|
defaults?: Partial<Props>;
|
|
161
|
-
setup: (props: WithNodes<Props>) =>
|
|
162
|
-
}):
|
|
172
|
+
setup: (props: WithNodes<Props>) => R;
|
|
173
|
+
}): Component<WithNodes<Props>, R>;
|
|
163
174
|
/**
|
|
164
175
|
* Higher-order helper to create a component that maps outer props to inner props.
|
|
165
176
|
*
|
|
@@ -185,7 +196,7 @@ declare function defineSlottedComponent<Props extends object>(config: {
|
|
|
185
196
|
* // Usage: SmallIconButton({ icon: 'star', label: 'Favorite' })
|
|
186
197
|
* ```
|
|
187
198
|
*/
|
|
188
|
-
declare function withProps<OuterProps extends object, InnerProps extends object>(component:
|
|
199
|
+
declare function withProps<OuterProps extends object, InnerProps extends object, R extends Node = HTMLElement>(component: Component<InnerProps, R>, mapProps: (outer: OuterProps) => InnerProps): Component<OuterProps, R>;
|
|
189
200
|
|
|
190
201
|
/**
|
|
191
202
|
* Runtime prop validation and strict typing contracts for SibuJS.
|
package/dist/data.cjs
CHANGED
|
@@ -660,7 +660,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
// src/reactivity/track.ts
|
|
663
|
-
var _runtimeVersion = true ? "4.
|
|
663
|
+
var _runtimeVersion = true ? "4.7.0" : "dev";
|
|
664
664
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
665
665
|
function resolveReactiveApi() {
|
|
666
666
|
const g = globalThis;
|
|
@@ -716,6 +716,14 @@ var getSubscriberCount2 = API.getSubscriberCount;
|
|
|
716
716
|
var getSubscriberDeps2 = API.getSubscriberDeps;
|
|
717
717
|
var forEachSubscriber2 = API.forEachSubscriber;
|
|
718
718
|
|
|
719
|
+
// src/core/devtoolsHook.ts
|
|
720
|
+
function emitDevtools(hook, event, payload) {
|
|
721
|
+
try {
|
|
722
|
+
hook.emit(event, payload);
|
|
723
|
+
} catch {
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
719
727
|
// src/core/signals/derived.ts
|
|
720
728
|
function derived(getter, options) {
|
|
721
729
|
devAssert(typeof getter === "function", "derived: argument must be a getter function.");
|
|
@@ -742,17 +750,17 @@ function derived(getter, options) {
|
|
|
742
750
|
cs._d = false;
|
|
743
751
|
cs._init = true;
|
|
744
752
|
};
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
try {
|
|
753
|
+
try {
|
|
754
|
+
track2(() => {
|
|
748
755
|
cs._v = getter();
|
|
749
756
|
cs._d = false;
|
|
750
757
|
cs._init = true;
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
758
|
+
}, markDirty);
|
|
759
|
+
} catch (err) {
|
|
760
|
+
disposed = true;
|
|
761
|
+
cleanup2(markDirty);
|
|
762
|
+
throw err;
|
|
763
|
+
}
|
|
756
764
|
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
757
765
|
const validate = () => {
|
|
758
766
|
if (!cs._d || disposed || pendingError !== void 0) return;
|
|
@@ -771,7 +779,7 @@ function derived(getter, options) {
|
|
|
771
779
|
if (disposed) cleanup2(markDirty);
|
|
772
780
|
}
|
|
773
781
|
if (hook && !disposed && !Object.is(oldValue, cs._v)) {
|
|
774
|
-
hook
|
|
782
|
+
emitDevtools(hook, "computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
775
783
|
}
|
|
776
784
|
};
|
|
777
785
|
cs._validate = validate;
|
|
@@ -822,7 +830,7 @@ function derived(getter, options) {
|
|
|
822
830
|
}
|
|
823
831
|
}
|
|
824
832
|
};
|
|
825
|
-
if (hook) hook
|
|
833
|
+
if (hook) emitDevtools(hook, "computed:create", { signal: cs, name: debugName, getter: computedGetter });
|
|
826
834
|
return computedGetter;
|
|
827
835
|
}
|
|
828
836
|
|
|
@@ -991,12 +999,17 @@ function effect(effectFn, options) {
|
|
|
991
999
|
try {
|
|
992
1000
|
retrack2(ctx.bodyFn, ctx.subscriber);
|
|
993
1001
|
if (ctx.rerunPending) drainReruns(ctx);
|
|
1002
|
+
} catch (err) {
|
|
1003
|
+
ctx.disposed = true;
|
|
1004
|
+
if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
|
|
1005
|
+
cleanup2(ctx.subscriber);
|
|
1006
|
+
throw err;
|
|
994
1007
|
} finally {
|
|
995
1008
|
ctx.running = false;
|
|
996
1009
|
ctx.rerunPending = false;
|
|
997
1010
|
}
|
|
998
1011
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
999
|
-
if (hook) hook
|
|
1012
|
+
if (hook) emitDevtools(hook, "effect:create", { effectFn });
|
|
1000
1013
|
return () => disposeEffect(ctx);
|
|
1001
1014
|
}
|
|
1002
1015
|
|
|
@@ -1083,7 +1096,7 @@ function signal(initial, options) {
|
|
|
1083
1096
|
state2.__v++;
|
|
1084
1097
|
if (DEV) {
|
|
1085
1098
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
1086
|
-
if (hook) hook
|
|
1099
|
+
if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
1087
1100
|
}
|
|
1088
1101
|
if (!enqueueBatchedSignal(state2)) {
|
|
1089
1102
|
notifySubscribers2(state2);
|
|
@@ -1097,7 +1110,7 @@ function signal(initial, options) {
|
|
|
1097
1110
|
state2.value = newValue;
|
|
1098
1111
|
state2.__v++;
|
|
1099
1112
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
1100
|
-
if (hook) hook
|
|
1113
|
+
if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
1101
1114
|
if (!enqueueBatchedSignal(state2)) {
|
|
1102
1115
|
notifySubscribers2(state2);
|
|
1103
1116
|
}
|
|
@@ -1116,7 +1129,7 @@ function signal(initial, options) {
|
|
|
1116
1129
|
}
|
|
1117
1130
|
if (DEV) {
|
|
1118
1131
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
1119
|
-
if (hook) hook
|
|
1132
|
+
if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
1120
1133
|
}
|
|
1121
1134
|
return [get, set];
|
|
1122
1135
|
}
|
|
@@ -1238,7 +1251,83 @@ function waitForRetryDelay(delay, signal2) {
|
|
|
1238
1251
|
});
|
|
1239
1252
|
}
|
|
1240
1253
|
|
|
1254
|
+
// src/data/structuralSharing.ts
|
|
1255
|
+
function isPlainObject(value) {
|
|
1256
|
+
if (value === null || typeof value !== "object") return false;
|
|
1257
|
+
const proto = Object.getPrototypeOf(value);
|
|
1258
|
+
return proto === Object.prototype || proto === null;
|
|
1259
|
+
}
|
|
1260
|
+
function isPlainArray(value) {
|
|
1261
|
+
return Array.isArray(value) && Object.getPrototypeOf(value) === Array.prototype;
|
|
1262
|
+
}
|
|
1263
|
+
function reconcile(prev, next, depth, walk, newRoot) {
|
|
1264
|
+
if (Object.is(prev, next)) return prev;
|
|
1265
|
+
const arrays = isPlainArray(prev) && isPlainArray(next);
|
|
1266
|
+
if (!arrays && !(isPlainObject(prev) && isPlainObject(next))) return next;
|
|
1267
|
+
if (Object.getPrototypeOf(prev) !== Object.getPrototypeOf(next)) return next;
|
|
1268
|
+
const nextObject = next;
|
|
1269
|
+
const seenAt = walk.path.get(nextObject);
|
|
1270
|
+
if (seenAt !== void 0) {
|
|
1271
|
+
walk.cycleTo = Math.min(walk.cycleTo, seenAt);
|
|
1272
|
+
return next;
|
|
1273
|
+
}
|
|
1274
|
+
const prevRecord = prev;
|
|
1275
|
+
const nextRecord = next;
|
|
1276
|
+
const nextKeys = arrays ? Array.from({ length: next.length }, (_, i) => i) : Object.keys(nextRecord);
|
|
1277
|
+
const prevSize = arrays ? prev.length : Object.keys(prevRecord).length;
|
|
1278
|
+
const copy = arrays ? new Array(nextKeys.length) : Object.create(Object.getPrototypeOf(next));
|
|
1279
|
+
let allFromPrev = prevSize === nextKeys.length;
|
|
1280
|
+
let allFromNext = true;
|
|
1281
|
+
const outerCycleTo = walk.cycleTo;
|
|
1282
|
+
walk.cycleTo = Number.POSITIVE_INFINITY;
|
|
1283
|
+
walk.path.set(nextObject, depth);
|
|
1284
|
+
for (const key of nextKeys) {
|
|
1285
|
+
if (arrays && !Object.hasOwn(nextRecord, key)) {
|
|
1286
|
+
if (Object.hasOwn(prevRecord, key)) allFromPrev = false;
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
const nextChild = nextRecord[key];
|
|
1290
|
+
const hasPrev = Object.hasOwn(prevRecord, key);
|
|
1291
|
+
const shared = hasPrev ? reconcile(prevRecord[key], nextChild, depth + 1, walk, false) : nextChild;
|
|
1292
|
+
copy[key] = shared;
|
|
1293
|
+
if (!hasPrev || !Object.is(shared, prevRecord[key])) allFromPrev = false;
|
|
1294
|
+
if (!Object.is(shared, nextChild)) allFromNext = false;
|
|
1295
|
+
}
|
|
1296
|
+
walk.path.delete(nextObject);
|
|
1297
|
+
const reached = walk.cycleTo;
|
|
1298
|
+
walk.cycleTo = Math.min(outerCycleTo, reached < depth ? reached : Number.POSITIVE_INFINITY);
|
|
1299
|
+
if (reached <= depth) return next;
|
|
1300
|
+
if (allFromPrev && !newRoot) return prev;
|
|
1301
|
+
if (allFromNext) return next;
|
|
1302
|
+
return copy;
|
|
1303
|
+
}
|
|
1304
|
+
function applyStructuralSharing(option, prev, next, explicit = false) {
|
|
1305
|
+
if (option === false || prev === void 0) return next;
|
|
1306
|
+
const forceNew = explicit && !Object.is(prev, next);
|
|
1307
|
+
if (typeof option === "function") {
|
|
1308
|
+
const shared = option(prev, next);
|
|
1309
|
+
return forceNew && Object.is(shared, prev) ? next : shared;
|
|
1310
|
+
}
|
|
1311
|
+
return reconcile(prev, next, 0, { path: /* @__PURE__ */ new Map(), cycleTo: Number.POSITIVE_INFINITY }, forceNew);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1241
1314
|
// src/data/query.ts
|
|
1315
|
+
function shareSafely(option, prev, next, explicit) {
|
|
1316
|
+
const shared = untracked2(
|
|
1317
|
+
() => runSelect("query structuralSharing", () => applyStructuralSharing(option, prev, next, explicit))
|
|
1318
|
+
);
|
|
1319
|
+
return shared.ok ? shared.value : next;
|
|
1320
|
+
}
|
|
1321
|
+
function sharedView(entry) {
|
|
1322
|
+
const raw = entry.data;
|
|
1323
|
+
if (raw === void 0) return void 0;
|
|
1324
|
+
if (entry.hasShared && Object.is(entry.sharedFrom, raw)) return entry.shared;
|
|
1325
|
+
const value = shareSafely(true, entry.hasShared ? entry.shared : void 0, raw, entry.explicit);
|
|
1326
|
+
entry.shared = value;
|
|
1327
|
+
entry.sharedFrom = raw;
|
|
1328
|
+
entry.hasShared = true;
|
|
1329
|
+
return value;
|
|
1330
|
+
}
|
|
1242
1331
|
var globalQueryCache = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.query.cache.v1"), () => /* @__PURE__ */ new Map());
|
|
1243
1332
|
function getActiveQueryCache() {
|
|
1244
1333
|
return getRequestScopedCache("query") ?? globalQueryCache;
|
|
@@ -1264,7 +1353,11 @@ function getOrCreateEntry(cache, key, initialData) {
|
|
|
1264
1353
|
listeners: /* @__PURE__ */ new Set(),
|
|
1265
1354
|
refetchers: /* @__PURE__ */ new Set(),
|
|
1266
1355
|
controller: null,
|
|
1267
|
-
generation: 0
|
|
1356
|
+
generation: 0,
|
|
1357
|
+
explicit: false,
|
|
1358
|
+
shared: void 0,
|
|
1359
|
+
sharedFrom: void 0,
|
|
1360
|
+
hasShared: false
|
|
1268
1361
|
};
|
|
1269
1362
|
cache.set(key, entry);
|
|
1270
1363
|
}
|
|
@@ -1283,13 +1376,24 @@ function query(key, fetcher, options = {}) {
|
|
|
1283
1376
|
onSuccess,
|
|
1284
1377
|
onError,
|
|
1285
1378
|
onSettled,
|
|
1286
|
-
select
|
|
1379
|
+
select,
|
|
1380
|
+
structuralSharing = true
|
|
1287
1381
|
} = options;
|
|
1288
1382
|
const resolveKey = typeof key === "function" ? key : () => key;
|
|
1289
1383
|
const cache = getActiveQueryCache();
|
|
1290
1384
|
const [data, setData] = signal(initialData);
|
|
1291
1385
|
const [isFetching, setIsFetching] = signal(false);
|
|
1292
1386
|
const [error, setError] = signal(void 0);
|
|
1387
|
+
const [updatedAt, setUpdatedAt] = signal(0);
|
|
1388
|
+
const [base, setBase] = signal(void 0);
|
|
1389
|
+
let baseEntry = null;
|
|
1390
|
+
let baseValue;
|
|
1391
|
+
let baseExplicit = false;
|
|
1392
|
+
let customEntry = null;
|
|
1393
|
+
let customFrom;
|
|
1394
|
+
let customValue;
|
|
1395
|
+
let selectedEntry = null;
|
|
1396
|
+
let selectedValue;
|
|
1293
1397
|
let disposed = false;
|
|
1294
1398
|
let currentKey = null;
|
|
1295
1399
|
let attachedEntry = null;
|
|
@@ -1298,11 +1402,57 @@ function query(key, fetcher, options = {}) {
|
|
|
1298
1402
|
const loading = derived(() => isFetching() && data() === void 0);
|
|
1299
1403
|
const isStale = derived(() => {
|
|
1300
1404
|
data();
|
|
1405
|
+
updatedAt();
|
|
1301
1406
|
if (!currentKey) return true;
|
|
1302
1407
|
const entry = cache.get(currentKey);
|
|
1303
1408
|
if (!entry || entry.dataUpdatedAt === 0) return true;
|
|
1304
1409
|
return Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
1305
1410
|
});
|
|
1411
|
+
function viewOf(entry) {
|
|
1412
|
+
const raw = entry.data;
|
|
1413
|
+
if (raw === void 0) return void 0;
|
|
1414
|
+
if (structuralSharing === false) return raw;
|
|
1415
|
+
if (typeof structuralSharing !== "function") return sharedView(entry);
|
|
1416
|
+
const sameEntry = customEntry === entry;
|
|
1417
|
+
if (sameEntry && Object.is(customFrom, raw)) return customValue;
|
|
1418
|
+
const value = shareSafely(structuralSharing, sameEntry ? customValue : void 0, raw, entry.explicit);
|
|
1419
|
+
customEntry = entry;
|
|
1420
|
+
customFrom = raw;
|
|
1421
|
+
customValue = value;
|
|
1422
|
+
return value;
|
|
1423
|
+
}
|
|
1424
|
+
function commitBase(entry, value) {
|
|
1425
|
+
const changed = !Object.is(value, baseValue);
|
|
1426
|
+
baseEntry = entry;
|
|
1427
|
+
baseValue = value;
|
|
1428
|
+
if (!select) {
|
|
1429
|
+
setData(value);
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
if (!changed) return;
|
|
1433
|
+
baseExplicit = entry?.explicit === true;
|
|
1434
|
+
setBase(value);
|
|
1435
|
+
}
|
|
1436
|
+
const stopSelect = select ? effect(() => {
|
|
1437
|
+
const raw = base();
|
|
1438
|
+
const entry = baseEntry;
|
|
1439
|
+
const explicit = baseExplicit;
|
|
1440
|
+
baseExplicit = false;
|
|
1441
|
+
if (entry === null && selectedEntry === null) return;
|
|
1442
|
+
if (raw === void 0) {
|
|
1443
|
+
selectedEntry = entry;
|
|
1444
|
+
selectedValue = void 0;
|
|
1445
|
+
setData(void 0);
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
const selected = runSelect("query select", () => select(raw));
|
|
1449
|
+
if (!selected.ok) return;
|
|
1450
|
+
const prev = selectedEntry === entry ? selectedValue : void 0;
|
|
1451
|
+
const value = shareSafely(structuralSharing, prev, selected.value, explicit);
|
|
1452
|
+
selectedEntry = entry;
|
|
1453
|
+
selectedValue = value;
|
|
1454
|
+
setData(value);
|
|
1455
|
+
}) : null;
|
|
1306
1456
|
function detachFromEntry() {
|
|
1307
1457
|
const entry = attachedEntry;
|
|
1308
1458
|
const key2 = attachedKey;
|
|
@@ -1361,7 +1511,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1361
1511
|
const settledError = entry.error;
|
|
1362
1512
|
runCallback("query onError", () => onError?.(settledError));
|
|
1363
1513
|
} else if (entry.data !== void 0) {
|
|
1364
|
-
const settledData = entry
|
|
1514
|
+
const settledData = viewOf(entry);
|
|
1365
1515
|
runCallback("query onSuccess", () => onSuccess?.(settledData));
|
|
1366
1516
|
}
|
|
1367
1517
|
runCallback("query onSettled", () => onSettled?.());
|
|
@@ -1392,17 +1542,14 @@ function query(key, fetcher, options = {}) {
|
|
|
1392
1542
|
entry.promise = null;
|
|
1393
1543
|
entry.controller = null;
|
|
1394
1544
|
entry.data = result;
|
|
1545
|
+
entry.explicit = false;
|
|
1395
1546
|
entry.dataUpdatedAt = Date.now();
|
|
1396
1547
|
entry.error = void 0;
|
|
1397
1548
|
notifyListeners(entry.listeners, "query cache listener");
|
|
1398
1549
|
if (disposed || currentKey !== key2) return;
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
setIsFetching(false);
|
|
1403
|
-
setError(void 0);
|
|
1404
|
-
});
|
|
1405
|
-
runCallback("query onSuccess", () => onSuccess?.(result));
|
|
1550
|
+
if (!entry.listeners.has(onCacheUpdate)) onCacheUpdate();
|
|
1551
|
+
const committedResult = viewOf(entry);
|
|
1552
|
+
runCallback("query onSuccess", () => onSuccess?.(committedResult));
|
|
1406
1553
|
} catch (err) {
|
|
1407
1554
|
if (entry.generation !== generation) return;
|
|
1408
1555
|
entry.promise = null;
|
|
@@ -1432,18 +1579,19 @@ function query(key, fetcher, options = {}) {
|
|
|
1432
1579
|
const entry = cache.get(currentKey);
|
|
1433
1580
|
if (!entry) {
|
|
1434
1581
|
batch(() => {
|
|
1435
|
-
|
|
1582
|
+
commitBase(null, void 0);
|
|
1436
1583
|
setError(void 0);
|
|
1437
1584
|
setIsFetching(false);
|
|
1585
|
+
setUpdatedAt(0);
|
|
1438
1586
|
});
|
|
1439
1587
|
return;
|
|
1440
1588
|
}
|
|
1441
|
-
const
|
|
1442
|
-
const selected = raw !== void 0 && select ? runSelect("query select", () => select(raw)) : { ok: true, value: raw };
|
|
1589
|
+
const view = viewOf(entry);
|
|
1443
1590
|
batch(() => {
|
|
1444
|
-
|
|
1591
|
+
commitBase(entry, view);
|
|
1445
1592
|
setError(entry.error);
|
|
1446
1593
|
if (!entry.promise) setIsFetching(false);
|
|
1594
|
+
setUpdatedAt(entry.dataUpdatedAt);
|
|
1447
1595
|
});
|
|
1448
1596
|
}
|
|
1449
1597
|
const effectCleanup = effect(() => {
|
|
@@ -1453,11 +1601,11 @@ function query(key, fetcher, options = {}) {
|
|
|
1453
1601
|
const entry = getOrCreateEntry(cache, key2, initialData);
|
|
1454
1602
|
attachToEntry(entry, key2);
|
|
1455
1603
|
if (entry.data !== void 0) {
|
|
1456
|
-
const
|
|
1457
|
-
const selected = runSelect("query select", () => select ? select(raw) : raw);
|
|
1604
|
+
const view = viewOf(entry);
|
|
1458
1605
|
batch(() => {
|
|
1459
|
-
|
|
1606
|
+
commitBase(entry, view);
|
|
1460
1607
|
setError(entry.error);
|
|
1608
|
+
setUpdatedAt(entry.dataUpdatedAt);
|
|
1461
1609
|
});
|
|
1462
1610
|
}
|
|
1463
1611
|
if (!keyChanged && currentKey === key2 && entry.data !== void 0) {
|
|
@@ -1495,6 +1643,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1495
1643
|
if (disposed) return;
|
|
1496
1644
|
disposed = true;
|
|
1497
1645
|
effectCleanup();
|
|
1646
|
+
stopSelect?.();
|
|
1498
1647
|
loading.dispose();
|
|
1499
1648
|
isStale.dispose();
|
|
1500
1649
|
if (intervalTimer) clearInterval(intervalTimer);
|
|
@@ -1526,13 +1675,15 @@ function invalidateQueries(keyOrPredicate) {
|
|
|
1526
1675
|
}
|
|
1527
1676
|
}
|
|
1528
1677
|
function getQueryData(key) {
|
|
1529
|
-
|
|
1678
|
+
const entry = getActiveQueryCache().get(key);
|
|
1679
|
+
return entry ? sharedView(entry) : void 0;
|
|
1530
1680
|
}
|
|
1531
1681
|
function setQueryData(key, data) {
|
|
1532
1682
|
const entry = getActiveQueryCache().get(key);
|
|
1533
1683
|
if (!entry) return;
|
|
1534
|
-
const newData = typeof data === "function" ? data(entry
|
|
1684
|
+
const newData = typeof data === "function" ? data(sharedView(entry)) : data;
|
|
1535
1685
|
entry.data = newData;
|
|
1686
|
+
entry.explicit = true;
|
|
1536
1687
|
entry.dataUpdatedAt = Date.now();
|
|
1537
1688
|
notifyListeners(entry.listeners, "query cache listener");
|
|
1538
1689
|
}
|
|
@@ -1916,6 +2067,15 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
|
|
|
1916
2067
|
const [loading, setLoading] = signal(false);
|
|
1917
2068
|
const [error, setError] = signal(void 0);
|
|
1918
2069
|
let currentData = options.initialValue;
|
|
2070
|
+
function commitData(next, explicit) {
|
|
2071
|
+
const sharing = options.structuralSharing ?? true;
|
|
2072
|
+
const shared = untracked2(
|
|
2073
|
+
() => runSelect("resource structuralSharing", () => applyStructuralSharing(sharing, currentData, next, explicit))
|
|
2074
|
+
);
|
|
2075
|
+
currentData = shared.ok ? shared.value : next;
|
|
2076
|
+
setData(currentData);
|
|
2077
|
+
return currentData;
|
|
2078
|
+
}
|
|
1919
2079
|
let abortController = null;
|
|
1920
2080
|
let disposed = false;
|
|
1921
2081
|
let effectCleanup = null;
|
|
@@ -1935,12 +2095,12 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
|
|
|
1935
2095
|
try {
|
|
1936
2096
|
const result = await withRetry(() => fetcher(sourceValue, { signal: signal2, prev }), options.retry, void 0, signal2);
|
|
1937
2097
|
if (version !== fetchVersion || disposed) return;
|
|
1938
|
-
|
|
2098
|
+
let committed = result;
|
|
1939
2099
|
batch(() => {
|
|
1940
|
-
|
|
2100
|
+
committed = commitData(result, false);
|
|
1941
2101
|
setLoading(false);
|
|
1942
2102
|
});
|
|
1943
|
-
runCallback("resource onSuccess", () => options.onSuccess?.(
|
|
2103
|
+
runCallback("resource onSuccess", () => options.onSuccess?.(committed));
|
|
1944
2104
|
} catch (err) {
|
|
1945
2105
|
if (version !== fetchVersion || disposed) return;
|
|
1946
2106
|
if (isAbortError(err)) {
|
|
@@ -1974,8 +2134,7 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
|
|
|
1974
2134
|
refetch: () => doFetch(source ? source() : void 0),
|
|
1975
2135
|
mutate: (value) => {
|
|
1976
2136
|
const newValue = typeof value === "function" ? value(currentData) : value;
|
|
1977
|
-
|
|
1978
|
-
setData(newValue);
|
|
2137
|
+
commitData(newValue, true);
|
|
1979
2138
|
},
|
|
1980
2139
|
abort: () => abortController?.abort(),
|
|
1981
2140
|
dispose: () => {
|