@askrjs/askr 0.3.0 → 0.4.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/CHANGELOG.md +874 -0
- package/README.md +61 -29
- package/capabilities.json +19 -9
- package/dist/actions/index.js +56 -12
- package/dist/benchmark.js +10 -15
- package/dist/boot/index.d.ts +3 -2
- package/dist/boot/index.js +1 -1
- package/dist/boot-DaoTYoCw.js +3989 -0
- package/dist/browser-activity-CB8e-V4f.js +220 -0
- package/dist/components/index.d.ts +8 -1
- package/dist/components/index.js +1 -43
- package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
- package/dist/control/index.d.ts +2 -0
- package/dist/control/index.js +1 -1
- package/dist/control-nfpT2fbK.js +209 -0
- package/dist/core.d.ts +5 -9
- package/dist/csp-nonce-DwGw1A6Q.js +35 -0
- package/dist/data/index.js +3 -3
- package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
- package/dist/data-runtime-C1bFAlba.js +242 -0
- package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
- package/dist/domains/actions.d.ts +8 -3
- package/dist/domains/component.d.ts +1 -107
- package/dist/domains/context.d.ts +0 -15
- package/dist/domains/control.d.ts +36 -249
- package/dist/domains/data.d.ts +31 -13
- package/dist/domains/diagnostics.d.ts +1 -2
- package/dist/domains/lifecycle.d.ts +2 -5
- package/dist/domains/refs.d.ts +0 -2
- package/dist/domains/routing.d.ts +43 -8
- package/dist/domains/scheduler.d.ts +1 -76
- package/dist/domains/server.d.ts +5 -2
- package/dist/domains/state.d.ts +2 -5
- package/dist/domains/telemetry.d.ts +0 -2
- package/dist/elements.d.ts +214 -51
- package/dist/error-boundary-Bpwofwps.js +293 -0
- package/dist/foundations/icon/index.d.ts +0 -58
- package/dist/foundations/icon/index.js +2 -2
- package/dist/foundations/index.js +2 -1
- package/dist/foundations/interactions/index.js +1 -1
- package/dist/foundations/state/index.d.ts +3 -3
- package/dist/foundations/state/index.js +5 -3
- package/dist/foundations/structures/index.js +2 -1
- package/dist/foundations/utilities/index.d.ts +2 -0
- package/dist/foundations/utilities/index.js +1 -2
- package/dist/fx/index.d.ts +31 -58
- package/dist/fx/index.js +313 -195
- package/dist/hooks-BimKStr4.js +202 -0
- package/dist/index.d.ts +11 -74
- package/dist/index.js +8 -447
- package/dist/instance-BAnfmXOR.js +988 -0
- package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
- package/dist/jsx-dev-runtime.d.ts +41 -18
- package/dist/jsx-dev-runtime.js +1 -6
- package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
- package/dist/jsx-runtime.js +1 -1
- package/dist/jsx.d.ts +61 -37
- package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
- package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
- package/dist/navigation.d.ts +12 -3
- package/dist/peer-types.d.ts +8 -0
- package/dist/portal-DuOKfnLa.js +349 -0
- package/dist/promise-Dz8iIHAm.js +16 -0
- package/dist/query-registry-WMCN0BJL.js +320 -0
- package/dist/readable-DFWOsTac.js +21 -0
- package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
- package/dist/render-sync-IC5lMFpq.js +1240 -0
- package/dist/resolution-Cx82-xjW.js +1244 -0
- package/dist/resource-CLjB7RBQ.js +377 -0
- package/dist/resources/index.d.ts +21 -11
- package/dist/resources/index.js +45 -244
- package/dist/router/index.d.ts +14 -5
- package/dist/router/index.js +22 -53
- package/dist/scope-CwpVSHVf.js +55 -0
- package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
- package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
- package/dist/ssg/index.d.ts +1 -2
- package/dist/ssg/index.js +5 -13
- package/dist/ssr/index.d.ts +26 -28
- package/dist/ssr/index.js +4 -4
- package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
- package/dist/ssr-DoV-vJ-5.js +229 -0
- package/dist/state-DWO1KzkX.js +232 -0
- package/dist/structures-D4dDMqHX.js +231 -0
- package/dist/testing/index.d.ts +8 -4
- package/dist/testing/index.js +29 -34
- package/dist/url-CnbfpX0K.js +185 -0
- package/dist/utilities.d.ts +48 -2
- package/dist/verify-hydration-DpVaDnqz.js +152 -0
- package/package.json +19 -9
- package/dist/access-CEA2pOry.js +0 -1046
- package/dist/activity-oy2YFTFF.js +0 -201
- package/dist/boot-BMBMWUGI.js +0 -1084
- package/dist/capabilities-Bbf0mlp9.js +0 -42
- package/dist/compose-ref-v0qGlHoN.js +0 -26
- package/dist/control-BR_mrX__.js +0 -173
- package/dist/control-C-ApnFs1.js +0 -20
- package/dist/csp-nonce-BfFWcd0w.js +0 -173
- package/dist/data-runtime-CxoY98lX.js +0 -149
- package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
- package/dist/dom-renderer.d.ts +0 -77
- package/dist/domains/renderer.d.ts +0 -127
- package/dist/eager-control.d.ts +0 -8
- package/dist/effect-C3Zsc1k6.js +0 -292
- package/dist/for-state-BDykeOJL.js +0 -1753
- package/dist/instance-VAFYVJOa.js +0 -1027
- package/dist/notify-DxxuDPeY.js +0 -266
- package/dist/portal-w3oQ6oQU.js +0 -29
- package/dist/query-registry-LrYpQsDJ.js +0 -83
- package/dist/render-resolved-BC0W7_5b.js +0 -1123
- package/dist/renderer-CT0HeY58.js +0 -8623
- package/dist/resolution-3DskUkjG.js +0 -577
- package/dist/resource-18-sFRl9.js +0 -344
- package/dist/route-matching-CUzZ31gT.js +0 -551
- package/dist/router-internal-7nuNEHfG.js +0 -36
- package/dist/scope-Cq_iYbTR.js +0 -403
- package/dist/selector-BSPVkjKP.js +0 -311
- package/dist/ssr-EPjwJH5R.js +0 -29
- package/dist/state-BXJfudq1.js +0 -91
- package/dist/structures-CjEzfj4h.js +0 -654
- package/dist/timer-C7uqnJVt.js +0 -85
- package/dist/verify-hydration-ikaxotf7.js +0 -27
- package/dist/vnode-D24p6IW2.js +0 -7
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { S as queueTask, d as recordUndo, v as effectScheduler, w as Computation } from "./instance-BAnfmXOR.js";
|
|
2
|
+
import { c as onCommit, d as reportLifecycleError, f as withOwner, i as currentComponent, o as hookSlot } from "./hooks-BimKStr4.js";
|
|
3
|
+
import { t as isRouteActivityActive } from "./route-activity-CNJfpwx-.js";
|
|
4
|
+
//#region src/core/api/lifecycle.ts
|
|
5
|
+
/**
|
|
6
|
+
* Component lifecycle hooks: work that starts after a render commits and
|
|
7
|
+
* ends with the component. Each is a no-op outside a component render and
|
|
8
|
+
* never starts on the server.
|
|
9
|
+
*/
|
|
10
|
+
/** Run `fn` once after the component's first commit; a returned function is its cleanup. */
|
|
11
|
+
function task(fn) {
|
|
12
|
+
const instance = currentComponent();
|
|
13
|
+
if (!instance) return;
|
|
14
|
+
const slot = hookSlot(instance, "task", () => ({
|
|
15
|
+
started: false,
|
|
16
|
+
fn
|
|
17
|
+
}));
|
|
18
|
+
if (slot.started || instance.server) return;
|
|
19
|
+
const previous = slot.fn;
|
|
20
|
+
slot.fn = fn;
|
|
21
|
+
recordUndo(() => {
|
|
22
|
+
slot.fn = previous;
|
|
23
|
+
});
|
|
24
|
+
onCommit(instance, () => {
|
|
25
|
+
if (slot.started) return;
|
|
26
|
+
slot.started = true;
|
|
27
|
+
try {
|
|
28
|
+
return withOwner(instance, slot.fn);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return Promise.reject(error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** Snapshot `fn()` now and return a thunk that yields that value later. */
|
|
35
|
+
function capture(fn) {
|
|
36
|
+
const value = fn();
|
|
37
|
+
return () => value;
|
|
38
|
+
}
|
|
39
|
+
function sameValues(previous, next) {
|
|
40
|
+
if (Array.isArray(previous) && Array.isArray(next)) {
|
|
41
|
+
if (previous.length !== next.length) return false;
|
|
42
|
+
return previous.every((value, index) => Object.is(value, next[index]));
|
|
43
|
+
}
|
|
44
|
+
return Object.is(previous, next);
|
|
45
|
+
}
|
|
46
|
+
function stopGeneration(slot) {
|
|
47
|
+
const controller = slot.controller;
|
|
48
|
+
slot.controller = null;
|
|
49
|
+
if (controller && !controller.signal.aborted) controller.abort();
|
|
50
|
+
const cleanup = slot.cleanup;
|
|
51
|
+
slot.cleanup = null;
|
|
52
|
+
cleanup?.();
|
|
53
|
+
}
|
|
54
|
+
function observe(instance, slot, value, previous) {
|
|
55
|
+
stopGeneration(slot);
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
slot.controller = controller;
|
|
58
|
+
const initial = !slot.observed;
|
|
59
|
+
slot.observed = true;
|
|
60
|
+
let result;
|
|
61
|
+
try {
|
|
62
|
+
result = withOwner(instance, () => slot.callback(value, {
|
|
63
|
+
initial,
|
|
64
|
+
previous,
|
|
65
|
+
signal: controller.signal
|
|
66
|
+
}));
|
|
67
|
+
} catch (error) {
|
|
68
|
+
reportLifecycleError(instance, error);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (typeof result === "function") slot.cleanup = result;
|
|
72
|
+
else if (result && typeof result.then === "function") Promise.resolve(result).catch((error) => {
|
|
73
|
+
if (!controller.signal.aborted) reportLifecycleError(instance, error);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function startWatch(instance, slot) {
|
|
77
|
+
if (slot.effect) {
|
|
78
|
+
slot.effect.invalidate();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const effect = new Computation(instance, () => {
|
|
82
|
+
let value;
|
|
83
|
+
try {
|
|
84
|
+
const values = slot.sources.map((source) => source());
|
|
85
|
+
value = values.length === 1 ? values[0] : values;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
reportLifecycleError(instance, error);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (slot.version > 0 && sameValues(slot.value, value)) return;
|
|
91
|
+
slot.value = value;
|
|
92
|
+
const version = ++slot.version;
|
|
93
|
+
queueTask(() => {
|
|
94
|
+
if (instance.disposed || version !== slot.version) return;
|
|
95
|
+
const previous = slot.deliveredValue;
|
|
96
|
+
slot.deliveredValue = value;
|
|
97
|
+
observe(instance, slot, value, previous);
|
|
98
|
+
});
|
|
99
|
+
}, effectScheduler("post", instance.depth, () => {
|
|
100
|
+
reportLifecycleError(instance, /* @__PURE__ */ new Error("[Askr] reactive cycle in watch(): the source changed in its own callback."));
|
|
101
|
+
}, 48), null);
|
|
102
|
+
slot.effect = effect;
|
|
103
|
+
instance.onCleanup(() => {
|
|
104
|
+
stopGeneration(slot);
|
|
105
|
+
slot.effect = null;
|
|
106
|
+
});
|
|
107
|
+
effect.run();
|
|
108
|
+
}
|
|
109
|
+
function watch(sourceOrSources, callback) {
|
|
110
|
+
const instance = currentComponent();
|
|
111
|
+
if (!instance) return;
|
|
112
|
+
const sources = Array.isArray(sourceOrSources) ? sourceOrSources : [sourceOrSources];
|
|
113
|
+
const slot = hookSlot(instance, "watch", () => ({
|
|
114
|
+
sources,
|
|
115
|
+
callback,
|
|
116
|
+
effect: null,
|
|
117
|
+
controller: null,
|
|
118
|
+
cleanup: null,
|
|
119
|
+
observed: false,
|
|
120
|
+
value: void 0,
|
|
121
|
+
deliveredValue: void 0,
|
|
122
|
+
version: 0
|
|
123
|
+
}));
|
|
124
|
+
if (instance.server) return;
|
|
125
|
+
onCommit(instance, () => {
|
|
126
|
+
slot.sources = sources;
|
|
127
|
+
slot.callback = callback;
|
|
128
|
+
startWatch(instance, slot);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function predicatesOf(when) {
|
|
132
|
+
if (!when) return [];
|
|
133
|
+
return typeof when === "function" ? [when] : when;
|
|
134
|
+
}
|
|
135
|
+
/** Run `fn` every `intervalMs` while the component lives and `options.when` passes. */
|
|
136
|
+
function timer(intervalMs, fn, options) {
|
|
137
|
+
const instance = currentComponent();
|
|
138
|
+
if (!instance) return;
|
|
139
|
+
const slot = hookSlot(instance, "timer", () => ({
|
|
140
|
+
id: null,
|
|
141
|
+
intervalMs: null,
|
|
142
|
+
callback: fn,
|
|
143
|
+
predicates: predicatesOf(options?.when)
|
|
144
|
+
}));
|
|
145
|
+
if (instance.server) return;
|
|
146
|
+
const predicates = predicatesOf(options?.when);
|
|
147
|
+
onCommit(instance, () => {
|
|
148
|
+
slot.callback = fn;
|
|
149
|
+
slot.predicates = predicates;
|
|
150
|
+
if (slot.id !== null && slot.intervalMs === intervalMs) return;
|
|
151
|
+
const first = slot.id === null && slot.intervalMs === null;
|
|
152
|
+
if (slot.id !== null) clearInterval(slot.id);
|
|
153
|
+
slot.intervalMs = intervalMs;
|
|
154
|
+
slot.id = setInterval(() => {
|
|
155
|
+
if (slot.predicates.every((predicate) => predicate())) slot.callback();
|
|
156
|
+
}, intervalMs);
|
|
157
|
+
if (first) instance.onCleanup(() => {
|
|
158
|
+
if (slot.id !== null) clearInterval(slot.id);
|
|
159
|
+
slot.id = null;
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/** An {@link ActivityPredicate} that is true while the current route matches. */
|
|
164
|
+
function routeActive(pathOrPaths) {
|
|
165
|
+
return () => isRouteActivityActive(pathOrPaths);
|
|
166
|
+
}
|
|
167
|
+
function sameOptions(a, b) {
|
|
168
|
+
if (a === b) return true;
|
|
169
|
+
if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
|
|
170
|
+
return a.capture === b.capture && a.once === b.once && a.passive === b.passive && a.signal === b.signal;
|
|
171
|
+
}
|
|
172
|
+
/** Attach an event listener to `target` for the component's lifetime. */
|
|
173
|
+
function on(target, event, handler, options) {
|
|
174
|
+
const instance = currentComponent();
|
|
175
|
+
if (!instance) return;
|
|
176
|
+
const slot = hookSlot(instance, "on", () => {
|
|
177
|
+
const created = {
|
|
178
|
+
target: null,
|
|
179
|
+
event,
|
|
180
|
+
options: void 0,
|
|
181
|
+
handler,
|
|
182
|
+
attached: false,
|
|
183
|
+
listener: ((evt) => {
|
|
184
|
+
created.handler.call(created.target, evt);
|
|
185
|
+
})
|
|
186
|
+
};
|
|
187
|
+
return created;
|
|
188
|
+
});
|
|
189
|
+
if (instance.server) return;
|
|
190
|
+
onCommit(instance, () => {
|
|
191
|
+
slot.handler = handler;
|
|
192
|
+
const resolved = typeof target === "function" ? target() ?? null : target;
|
|
193
|
+
if (slot.attached && slot.target === resolved && slot.event === event && sameOptions(slot.options, options)) return;
|
|
194
|
+
const first = !slot.attached && slot.target === null;
|
|
195
|
+
if (slot.attached && slot.target) slot.target.removeEventListener(slot.event, slot.listener, slot.options);
|
|
196
|
+
slot.attached = false;
|
|
197
|
+
slot.target = resolved;
|
|
198
|
+
slot.event = event;
|
|
199
|
+
slot.options = options;
|
|
200
|
+
if (resolved) {
|
|
201
|
+
resolved.addEventListener(event, slot.listener, options);
|
|
202
|
+
slot.attached = true;
|
|
203
|
+
}
|
|
204
|
+
if (first) instance.onCleanup(() => {
|
|
205
|
+
if (slot.attached && slot.target) slot.target.removeEventListener(slot.event, slot.listener, slot.options);
|
|
206
|
+
slot.attached = false;
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/resources/browser-activity.ts
|
|
212
|
+
/** Activity gates retain their permissive server defaults. */
|
|
213
|
+
function documentVisible() {
|
|
214
|
+
return () => typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
215
|
+
}
|
|
216
|
+
function windowFocused() {
|
|
217
|
+
return () => typeof document === "undefined" || typeof document.hasFocus !== "function" || document.hasFocus();
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
export { routeActive as a, watch as c, on as i, windowFocused as n, task as o, capture as r, timer as s, documentVisible as t };
|
|
@@ -2,6 +2,12 @@ import { VNode } from '../core.js';
|
|
|
2
2
|
import { JSXElement, Props } from '../elements.js';
|
|
3
3
|
type ErrorBoundaryContent = VNode | readonly VNode[];
|
|
4
4
|
type ErrorBoundaryFallbackValue = ErrorBoundaryContent | Node;
|
|
5
|
+
/** A child of an {@link ErrorBoundary}; a raw DOM `Node` is not a child. */
|
|
6
|
+
type ErrorBoundaryChild =
|
|
7
|
+
| VNode
|
|
8
|
+
| JSXElement
|
|
9
|
+
| (() => unknown)
|
|
10
|
+
| readonly ErrorBoundaryChild[];
|
|
5
11
|
/** Renders a fallback for the caught error; call `reset` to retry the children. */
|
|
6
12
|
type ErrorBoundaryFallbackRender = (
|
|
7
13
|
error: unknown,
|
|
@@ -9,7 +15,8 @@ type ErrorBoundaryFallbackRender = (
|
|
|
9
15
|
) => ErrorBoundaryFallbackValue;
|
|
10
16
|
/** Props for {@link ErrorBoundary}. */
|
|
11
17
|
interface ErrorBoundaryProps extends Props {
|
|
12
|
-
children
|
|
18
|
+
/** Boundary content: nodes, elements, function children, or a list of them. */
|
|
19
|
+
children?: ErrorBoundaryChild;
|
|
13
20
|
/** Static fallback content, or a render function receiving the error and a reset callback. */
|
|
14
21
|
fallback?: ErrorBoundaryFallbackValue | ErrorBoundaryFallbackRender;
|
|
15
22
|
/** Called with the caught error when the boundary trips. */
|
package/dist/components/index.js
CHANGED
|
@@ -1,44 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as __ERROR_BOUNDARY__ } from "../vnode-D24p6IW2.js";
|
|
3
|
-
import { t as ELEMENT_TYPE } from "../jsx-DRS-qjiN.js";
|
|
4
|
-
//#region src/components/error-boundary.tsx
|
|
5
|
-
function ensureBoundaryState(instance, resetKey) {
|
|
6
|
-
const boundaryState = instance.errorBoundaryState ?? (instance.errorBoundaryState = {
|
|
7
|
-
error: null,
|
|
8
|
-
resetKey,
|
|
9
|
-
notified: false
|
|
10
|
-
});
|
|
11
|
-
if (!Object.is(boundaryState.resetKey, resetKey)) {
|
|
12
|
-
boundaryState.error = null;
|
|
13
|
-
boundaryState.resetKey = resetKey;
|
|
14
|
-
boundaryState.notified = false;
|
|
15
|
-
}
|
|
16
|
-
return boundaryState;
|
|
17
|
-
}
|
|
18
|
-
function createBoundaryVNode(instance, props) {
|
|
19
|
-
const key = typeof props.key === "symbol" ? null : props.key ?? null;
|
|
20
|
-
return {
|
|
21
|
-
$$typeof: ELEMENT_TYPE,
|
|
22
|
-
type: __ERROR_BOUNDARY__,
|
|
23
|
-
props: {
|
|
24
|
-
children: props.children,
|
|
25
|
-
fallback: props.fallback,
|
|
26
|
-
onError: props.onError,
|
|
27
|
-
resetKey: props.resetKey
|
|
28
|
-
},
|
|
29
|
-
key,
|
|
30
|
-
__instance: instance
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Creates a boundary for descendant mount and post-mount render/commit errors,
|
|
35
|
-
* including content materialized through a portal host.
|
|
36
|
-
*/
|
|
37
|
-
function ErrorBoundary(props) {
|
|
38
|
-
const instance = getCurrentComponentInstance();
|
|
39
|
-
if (!instance) throw new Error("[Askr] ErrorBoundary() can only be used during component render execution.");
|
|
40
|
-
ensureBoundaryState(instance, props.resetKey);
|
|
41
|
-
return createBoundaryVNode(instance, props);
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
1
|
+
import { t as ErrorBoundary } from "../error-boundary-Bpwofwps.js";
|
|
44
2
|
export { ErrorBoundary };
|
|
@@ -25,6 +25,8 @@ function noop() {}
|
|
|
25
25
|
*
|
|
26
26
|
* Deterministic props merging.
|
|
27
27
|
* - For non-handlers: `base` overwrites `injected`.
|
|
28
|
+
* - A `base` value of `undefined` means "not provided" and never overwrites an
|
|
29
|
+
* `injected` value; pass `null` to clear an injected prop explicitly.
|
|
28
30
|
* - For handlers present in both: handlers are composed with `injected` running
|
|
29
31
|
* first; it may call `preventDefault()` to suppress the `base` handler.
|
|
30
32
|
*
|
|
@@ -42,15 +44,24 @@ function noop() {}
|
|
|
42
44
|
* Injected handler runs first, base handler second.
|
|
43
45
|
* This allows injected handlers to prevent default.
|
|
44
46
|
*
|
|
45
|
-
* 4.
|
|
46
|
-
*
|
|
47
|
+
* 4. Undefined Means Absent
|
|
48
|
+
* A `base` key whose value is `undefined` does not override `injected`.
|
|
49
|
+
* Forwarding an optional prop that was not supplied
|
|
50
|
+
* (`onClick={props.onClick}`) must not wipe injected behaviour or ARIA.
|
|
51
|
+
* `null` is an explicit value and still overrides (base wins).
|
|
52
|
+
*
|
|
53
|
+
* 5. Return Type
|
|
54
|
+
* Returns MergedProps<TBase, TInjected>: base value types win unless they
|
|
55
|
+
* may be undefined, in which case the injected type is included.
|
|
47
56
|
*/
|
|
48
57
|
function isEventHandlerKey(key) {
|
|
49
58
|
return key.startsWith("on");
|
|
50
59
|
}
|
|
51
60
|
/**
|
|
52
61
|
* Merge `base` props over `injected` props: non-handler keys in `base` win,
|
|
53
|
-
* and matching event handlers are composed (`injected` runs first).
|
|
62
|
+
* and matching event handlers are composed (`injected` runs first). `base`
|
|
63
|
+
* values that are `undefined` are treated as absent and never overwrite an
|
|
64
|
+
* injected value; use `null` to clear one explicitly.
|
|
54
65
|
*/
|
|
55
66
|
function mergeProps(base, injected) {
|
|
56
67
|
const baseKeys = Object.keys(base);
|
|
@@ -59,6 +70,7 @@ function mergeProps(base, injected) {
|
|
|
59
70
|
for (const key of baseKeys) {
|
|
60
71
|
const baseValue = base[key];
|
|
61
72
|
const injectedValue = injected[key];
|
|
73
|
+
if (baseValue === void 0 && Object.prototype.hasOwnProperty.call(out, key)) continue;
|
|
62
74
|
if (isEventHandlerKey(key) && typeof baseValue === "function" && typeof injectedValue === "function") {
|
|
63
75
|
out[key] = composeHandlers(injectedValue, baseValue);
|
|
64
76
|
continue;
|
|
@@ -85,4 +97,29 @@ function ariaSelected(selected) {
|
|
|
85
97
|
return selected === void 0 ? {} : { "aria-selected": String(selected) };
|
|
86
98
|
}
|
|
87
99
|
//#endregion
|
|
88
|
-
|
|
100
|
+
//#region src/foundations/utilities/compose-ref.ts
|
|
101
|
+
/** Write `value` to a {@link Ref}, ignoring failures on readonly object refs. */
|
|
102
|
+
function setRef(ref, value) {
|
|
103
|
+
if (!ref) return;
|
|
104
|
+
if (typeof ref === "function") {
|
|
105
|
+
ref(value);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
ref.current = value;
|
|
110
|
+
} catch {}
|
|
111
|
+
}
|
|
112
|
+
/** Combine multiple refs into one callback ref that writes to all of them. */
|
|
113
|
+
function composeRefs(...refs) {
|
|
114
|
+
return (value) => {
|
|
115
|
+
const errors = [];
|
|
116
|
+
for (const ref of refs) try {
|
|
117
|
+
setRef(ref, value);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
errors.push(error);
|
|
120
|
+
}
|
|
121
|
+
if (errors.length > 0) throw new AggregateError(errors, "Composed ref callbacks failed");
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { ariaSelected as a, ariaExpanded as i, setRef as n, mergeProps as o, ariaDisabled as r, composeHandlers as s, composeRefs as t };
|
package/dist/control/index.d.ts
CHANGED
package/dist/control/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { i as Show, n as For, r as Match, t as Case } from "../control-nfpT2fbK.js";
|
|
2
2
|
export { Case, For, Match, Show };
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { F as logger, I as isDevelopmentEnvironment, T as Signal, d as recordUndo, h as isRendering } from "./instance-BAnfmXOR.js";
|
|
2
|
+
import { n as Fragment, t as ELEMENT_TYPE } from "./jsx-DRS-qjiN.js";
|
|
3
|
+
import { c as onCommit, i as currentComponent, o as hookSlot } from "./hooks-BimKStr4.js";
|
|
4
|
+
//#region src/core/api/control.ts
|
|
5
|
+
/**
|
|
6
|
+
* Control flow as ordinary components.
|
|
7
|
+
*
|
|
8
|
+
* `Show`, `Case`, and `For` are element types like any other component: they
|
|
9
|
+
* render lazily in their own lifetime, read their sources in their own
|
|
10
|
+
* render, and never claim hook slots in the component that uses them. A
|
|
11
|
+
* branch is wrapped in a keyed fragment so switching branches replaces the
|
|
12
|
+
* branch's lifetime instead of patching one branch's DOM into another's.
|
|
13
|
+
*/
|
|
14
|
+
function element(type, props, key = null) {
|
|
15
|
+
return {
|
|
16
|
+
$$typeof: ELEMENT_TYPE,
|
|
17
|
+
type,
|
|
18
|
+
props,
|
|
19
|
+
key
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function branch(key, children) {
|
|
23
|
+
return element(Fragment, { children }, key);
|
|
24
|
+
}
|
|
25
|
+
function resolve(value) {
|
|
26
|
+
return typeof value === "function" ? value() : value;
|
|
27
|
+
}
|
|
28
|
+
function isPresent(value) {
|
|
29
|
+
return value !== null && value !== void 0 && value !== false;
|
|
30
|
+
}
|
|
31
|
+
/** Render `children` while `when` is truthy, otherwise `fallback`. */
|
|
32
|
+
function Show(props) {
|
|
33
|
+
const value = resolve(props.when);
|
|
34
|
+
if (value) return branch("show:when", typeof props.children === "function" ? props.children(value) : props.children);
|
|
35
|
+
return isPresent(props.fallback) ? branch("show:fallback", props.fallback) : null;
|
|
36
|
+
}
|
|
37
|
+
/** Declares one branch of a {@link Case}; only valid as its direct child. */
|
|
38
|
+
function Match(_props) {
|
|
39
|
+
throw new Error("[askr] <Match> may only be used as a direct child of <Case>.");
|
|
40
|
+
}
|
|
41
|
+
function flatten(children, out = []) {
|
|
42
|
+
if (Array.isArray(children)) for (const child of children) flatten(child, out);
|
|
43
|
+
else if (isPresent(children)) out.push(children);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/** Render the first {@link Match} whose `when` is truthy, else `fallback`. */
|
|
47
|
+
function Case(props) {
|
|
48
|
+
const children = flatten(props.children);
|
|
49
|
+
for (let index = 0; index < children.length; index++) {
|
|
50
|
+
const child = children[index];
|
|
51
|
+
if (typeof child !== "object" || child === null || child.type !== Match) throw new Error("[askr] <Case> only accepts <Match> children.");
|
|
52
|
+
}
|
|
53
|
+
for (let index = 0; index < children.length; index++) {
|
|
54
|
+
const child = children[index];
|
|
55
|
+
const matchProps = child.props;
|
|
56
|
+
if (!resolve(matchProps.when)) continue;
|
|
57
|
+
return branch(child.key == null ? `match:${index}` : `match:${index}:${typeof child.key}:${String(child.key)}`, resolve(matchProps.children));
|
|
58
|
+
}
|
|
59
|
+
return isPresent(props.fallback) ? branch("case:fallback", props.fallback) : null;
|
|
60
|
+
}
|
|
61
|
+
/** One list row: re-renders only when its item or the row callback changes. */
|
|
62
|
+
function ForRow(props) {
|
|
63
|
+
return props.render(props.row.readItem(), props.row.readIndex);
|
|
64
|
+
}
|
|
65
|
+
function recordRowUndo(undo) {
|
|
66
|
+
if (isRendering() && !currentComponent()?.server) recordUndo(undo);
|
|
67
|
+
}
|
|
68
|
+
function createRow(index, item) {
|
|
69
|
+
const indexSource = new Signal(index);
|
|
70
|
+
const source = new Signal(item);
|
|
71
|
+
const overlay = /* @__PURE__ */ new Map();
|
|
72
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
73
|
+
/** One signal per property a reader has read through the proxy. */
|
|
74
|
+
const properties = /* @__PURE__ */ new Map();
|
|
75
|
+
let proxy = null;
|
|
76
|
+
const readProperty = (key) => {
|
|
77
|
+
let property = properties.get(key);
|
|
78
|
+
if (!property) {
|
|
79
|
+
property = new Signal(Reflect.get(source.peek(), key));
|
|
80
|
+
properties.set(key, property);
|
|
81
|
+
recordRowUndo(() => properties.delete(key));
|
|
82
|
+
}
|
|
83
|
+
return property.read();
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
index: indexSource,
|
|
87
|
+
readIndex: () => indexSource.read(),
|
|
88
|
+
source,
|
|
89
|
+
readItem: () => {
|
|
90
|
+
const item = source.peek();
|
|
91
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) return item;
|
|
92
|
+
if (proxy) return proxy;
|
|
93
|
+
proxy = new Proxy({}, {
|
|
94
|
+
get(_target, key) {
|
|
95
|
+
if (deleted.has(key)) return void 0;
|
|
96
|
+
const own = overlay.get(key);
|
|
97
|
+
if (own) return own.get ? own.get.call(proxy) : own.value;
|
|
98
|
+
return readProperty(key);
|
|
99
|
+
},
|
|
100
|
+
set(_target, key, value) {
|
|
101
|
+
const previous = overlay.get(key);
|
|
102
|
+
if (!previous && typeof key !== "symbol" && isDevelopmentEnvironment() && key in Object(source.peek())) logger.warn(`[Askr] Assigning to "${String(key)}" on a <For> item shadows a property from the source data - it will not update when the source item changes and does not trigger a re-render. Use a different property name for cached/derived per-row values, or a state() cell for values that should be reactive.`);
|
|
103
|
+
const wasDeleted = deleted.delete(key);
|
|
104
|
+
overlay.set(key, {
|
|
105
|
+
value,
|
|
106
|
+
writable: true,
|
|
107
|
+
enumerable: true,
|
|
108
|
+
configurable: true
|
|
109
|
+
});
|
|
110
|
+
recordRowUndo(() => {
|
|
111
|
+
if (previous) overlay.set(key, previous);
|
|
112
|
+
else overlay.delete(key);
|
|
113
|
+
if (wasDeleted) deleted.add(key);
|
|
114
|
+
});
|
|
115
|
+
return true;
|
|
116
|
+
},
|
|
117
|
+
has(_target, key) {
|
|
118
|
+
return !deleted.has(key) && (overlay.has(key) || Reflect.has(source.read(), key));
|
|
119
|
+
},
|
|
120
|
+
ownKeys() {
|
|
121
|
+
return [...overlay.keys(), ...Reflect.ownKeys(source.read()).filter((key) => !overlay.has(key) && !deleted.has(key))];
|
|
122
|
+
},
|
|
123
|
+
getOwnPropertyDescriptor(_target, key) {
|
|
124
|
+
if (deleted.has(key)) return void 0;
|
|
125
|
+
const descriptor = overlay.get(key) ?? Reflect.getOwnPropertyDescriptor(source.read(), key);
|
|
126
|
+
return descriptor ? {
|
|
127
|
+
...descriptor,
|
|
128
|
+
configurable: true
|
|
129
|
+
} : void 0;
|
|
130
|
+
},
|
|
131
|
+
getPrototypeOf() {
|
|
132
|
+
return Reflect.getPrototypeOf(source.read());
|
|
133
|
+
},
|
|
134
|
+
deleteProperty(_target, key) {
|
|
135
|
+
const previous = overlay.get(key);
|
|
136
|
+
const wasDeleted = deleted.has(key);
|
|
137
|
+
overlay.delete(key);
|
|
138
|
+
deleted.add(key);
|
|
139
|
+
recordRowUndo(() => {
|
|
140
|
+
if (previous) overlay.set(key, previous);
|
|
141
|
+
if (!wasDeleted) deleted.delete(key);
|
|
142
|
+
});
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return proxy;
|
|
147
|
+
},
|
|
148
|
+
writeItem(item) {
|
|
149
|
+
const previousItem = source.peek();
|
|
150
|
+
if (!source.write(item)) return;
|
|
151
|
+
recordRowUndo(() => {
|
|
152
|
+
source.write(previousItem);
|
|
153
|
+
});
|
|
154
|
+
if (typeof item !== "object" || item === null) return;
|
|
155
|
+
for (const [key, property] of properties) {
|
|
156
|
+
const previous = property.peek();
|
|
157
|
+
if (property.write(Reflect.get(item, key))) recordRowUndo(() => {
|
|
158
|
+
property.write(previous);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function validateKey(key, index) {
|
|
165
|
+
if (key === null || key === void 0) throw new Error(`[askr] Invalid For key detected at index ${index}: ${String(key)}. Keys should be stable, non-null, and unique within a For list.`);
|
|
166
|
+
}
|
|
167
|
+
function For(props) {
|
|
168
|
+
const by = props.by;
|
|
169
|
+
if (!by && props.byIndex !== true) throw new Error("[Askr] <For> requires a stable `by` key function or `byIndex={true}`.");
|
|
170
|
+
if (by && props.byIndex) throw new Error("[Askr] <For> accepts `by` or `byIndex`, not both.");
|
|
171
|
+
const instance = currentComponent();
|
|
172
|
+
const rows = instance ? hookSlot(instance, "for", () => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
|
|
173
|
+
const items = resolve(props.each) ?? [];
|
|
174
|
+
if (items.length === 0) {
|
|
175
|
+
if (instance) onCommit(instance, () => rows.clear());
|
|
176
|
+
return isPresent(props.fallback) ? branch("for:fallback", props.fallback) : null;
|
|
177
|
+
}
|
|
178
|
+
const output = [];
|
|
179
|
+
const live = /* @__PURE__ */ new Set();
|
|
180
|
+
for (let index = 0; index < items.length; index++) {
|
|
181
|
+
const item = items[index];
|
|
182
|
+
const key = by ? by(item, index) : index;
|
|
183
|
+
validateKey(key, index);
|
|
184
|
+
if (live.has(key)) throw new Error(`[askr] Duplicate For key detected: ${String(key)}. Keys should be stable, non-null, and unique within a For list.`);
|
|
185
|
+
let row = rows.get(key);
|
|
186
|
+
if (!row) {
|
|
187
|
+
row = createRow(index, item);
|
|
188
|
+
rows.set(key, row);
|
|
189
|
+
recordRowUndo(() => rows.delete(key));
|
|
190
|
+
} else {
|
|
191
|
+
const indexSource = row.index;
|
|
192
|
+
const previous = indexSource.peek();
|
|
193
|
+
if (indexSource.write(index)) recordRowUndo(() => indexSource.write(previous));
|
|
194
|
+
row.writeItem(item);
|
|
195
|
+
}
|
|
196
|
+
live.add(key);
|
|
197
|
+
output.push(element(ForRow, {
|
|
198
|
+
item,
|
|
199
|
+
row,
|
|
200
|
+
render: props.children
|
|
201
|
+
}, key));
|
|
202
|
+
}
|
|
203
|
+
if (instance) onCommit(instance, () => {
|
|
204
|
+
for (const key of rows.keys()) if (!live.has(key)) rows.delete(key);
|
|
205
|
+
});
|
|
206
|
+
return output;
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
export { Show as i, For as n, Match as r, Case as t };
|
package/dist/core.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Aggregates the maintained domain contracts in `domains/` so entrypoint
|
|
3
|
+
* declarations can import them from one module. Not a package subpath.
|
|
4
|
+
*/
|
|
2
5
|
import './jsx-globals.js';
|
|
3
6
|
export {
|
|
4
7
|
selector,
|
|
@@ -113,14 +116,6 @@ export {
|
|
|
113
116
|
} from './domains/routing.js';
|
|
114
117
|
export { getSignal } from './domains/component.js';
|
|
115
118
|
export { scheduleEventHandler } from './domains/scheduler.js';
|
|
116
|
-
export {
|
|
117
|
-
RuntimeKeyedReorderDecision,
|
|
118
|
-
getDefaultRuntime,
|
|
119
|
-
RuntimeRendererHost,
|
|
120
|
-
AskrRuntime,
|
|
121
|
-
AskrRuntimeOptions,
|
|
122
|
-
createRuntime,
|
|
123
|
-
} from './domains/renderer.js';
|
|
124
119
|
export {
|
|
125
120
|
Show,
|
|
126
121
|
ShowProps,
|
|
@@ -129,6 +124,7 @@ export {
|
|
|
129
124
|
Match,
|
|
130
125
|
MatchProps,
|
|
131
126
|
ForProps,
|
|
127
|
+
ForGetterProps,
|
|
132
128
|
Case,
|
|
133
129
|
} from './domains/control.js';
|
|
134
130
|
export {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { n as isScopeReadable, r as readScope, t as defineScope } from "./scope-CwpVSHVf.js";
|
|
2
|
+
//#region src/csp-nonce.ts
|
|
3
|
+
/** Lexical scope carrying the CSP nonce for the current render, if any. */
|
|
4
|
+
const CspNonceScope = defineScope(void 0);
|
|
5
|
+
/**
|
|
6
|
+
* Read the CSP nonce for the current render from {@link CspNonceScope}.
|
|
7
|
+
*
|
|
8
|
+
* @returns The active nonce, or `undefined` when called outside of a
|
|
9
|
+
* component render or when no nonce was configured.
|
|
10
|
+
*/
|
|
11
|
+
function cspNonce() {
|
|
12
|
+
return isScopeReadable() ? readScope(CspNonceScope) : void 0;
|
|
13
|
+
}
|
|
14
|
+
function validateCspNonce(value) {
|
|
15
|
+
if (value === void 0) return void 0;
|
|
16
|
+
const invalid = () => {
|
|
17
|
+
throw new TypeError("CSP nonce must be valid base64 or base64url encoding at least 16 bytes.");
|
|
18
|
+
};
|
|
19
|
+
if (value.length === 0 || !/^[A-Za-z0-9+/_-]+={0,2}$/.test(value) || value.length % 4 === 1 || /=/.test(value.slice(0, -2))) invalid();
|
|
20
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
21
|
+
let end = normalized.length;
|
|
22
|
+
while (end > 0 && normalized[end - 1] === "=") end--;
|
|
23
|
+
const unpadded = normalized.slice(0, end);
|
|
24
|
+
const padded = unpadded.padEnd(Math.ceil(unpadded.length / 4) * 4, "=");
|
|
25
|
+
let decoded = "";
|
|
26
|
+
try {
|
|
27
|
+
decoded = atob(padded);
|
|
28
|
+
} catch {
|
|
29
|
+
invalid();
|
|
30
|
+
}
|
|
31
|
+
if (decoded.length < 16) invalid();
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { cspNonce as n, validateCspNonce as r, CspNonceScope as t };
|
package/dist/data/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { a as hydrateDataRuntime, i as dehydrateDataRuntime, n as defineQuery, o as prefetchQuery, r as defineServerQueries, s as serveQuery, t as createQueryPrefetchContext } from "../query-registry-WMCN0BJL.js";
|
|
2
|
+
import { a as getDefaultDataRuntime, t as createDataRuntime } from "../data-runtime-C1bFAlba.js";
|
|
3
|
+
import { c as createMutation, d as queryScope, l as invalidate, n as createQuery, t as createQueryCollection, u as invalidateOnInterval } from "../data-BCwClJiF.js";
|
|
4
4
|
export { createDataRuntime, createMutation, createQuery, createQueryCollection, createQueryPrefetchContext, defineQuery, defineServerQueries, dehydrateDataRuntime, getDefaultDataRuntime, hydrateDataRuntime, invalidate, invalidateOnInterval, prefetchQuery, queryScope, serveQuery };
|