@async/framework 0.11.14 → 0.11.16
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 +42 -3
- package/README.md +101 -14
- package/browser.d.ts +42 -2
- package/browser.js +288 -16
- package/browser.min.js +1 -1
- package/browser.ts +288 -16
- package/browser.umd.js +288 -16
- package/browser.umd.min.js +1 -1
- package/framework.d.ts +42 -2
- package/framework.ts +288 -16
- package/package.json +23 -68
- package/runtime/events.d.ts +48 -0
- package/runtime/events.js +208 -0
- package/runtime/shared.js +85 -0
- package/runtime/signals.d.ts +31 -0
- package/runtime/signals.js +209 -0
- package/runtime.d.ts +72 -0
- package/runtime.js +63 -0
- package/server.js +288 -16
package/framework.ts
CHANGED
|
@@ -1164,6 +1164,7 @@ const __attributesModule = (() => {
|
|
|
1164
1164
|
async: ["async:"],
|
|
1165
1165
|
class: ["class:"],
|
|
1166
1166
|
signal: ["signal:"],
|
|
1167
|
+
intersect: ["intersect:"],
|
|
1167
1168
|
on: ["on:"]
|
|
1168
1169
|
});
|
|
1169
1170
|
|
|
@@ -1176,6 +1177,7 @@ const __attributesModule = (() => {
|
|
|
1176
1177
|
async: normalizePrefixes(config.async, defaultPrefixes.async),
|
|
1177
1178
|
class: normalizePrefixes(config.class, defaultPrefixes.class),
|
|
1178
1179
|
signal: normalizePrefixes(config.signal, defaultPrefixes.signal),
|
|
1180
|
+
intersect: normalizePrefixes(config.intersect, defaultPrefixes.intersect),
|
|
1179
1181
|
on: normalizePrefixes(config.on, defaultPrefixes.on)
|
|
1180
1182
|
};
|
|
1181
1183
|
}
|
|
@@ -2141,6 +2143,7 @@ const __componentModule = (() => {
|
|
|
2141
2143
|
const cleanups = [];
|
|
2142
2144
|
const attachHooks = [];
|
|
2143
2145
|
const visibleHooks = [];
|
|
2146
|
+
const intersectionHooks = [];
|
|
2144
2147
|
const destroyHooks = [];
|
|
2145
2148
|
const bindingIds = [];
|
|
2146
2149
|
const templateOptions = {
|
|
@@ -2162,6 +2165,7 @@ const __componentModule = (() => {
|
|
|
2162
2165
|
cleanups,
|
|
2163
2166
|
attachHooks,
|
|
2164
2167
|
visibleHooks,
|
|
2168
|
+
intersectionHooks,
|
|
2165
2169
|
destroyHooks,
|
|
2166
2170
|
renderScopedTemplate
|
|
2167
2171
|
});
|
|
@@ -2213,6 +2217,15 @@ const __componentModule = (() => {
|
|
|
2213
2217
|
cleanups.push(cleanup);
|
|
2214
2218
|
}
|
|
2215
2219
|
},
|
|
2220
|
+
intersection(target, observeIntersection) {
|
|
2221
|
+
if (intersectionHooks.length === 0) {
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
for (let index = 0; index < intersectionHooks.length; index += 1) {
|
|
2225
|
+
const hook = intersectionHooks[index];
|
|
2226
|
+
hook(target, observeIntersection);
|
|
2227
|
+
}
|
|
2228
|
+
},
|
|
2216
2229
|
cleanup() {
|
|
2217
2230
|
while (destroyHooks.length > 0) {
|
|
2218
2231
|
destroyHooks.pop()?.();
|
|
@@ -2242,7 +2255,7 @@ const __componentModule = (() => {
|
|
|
2242
2255
|
}
|
|
2243
2256
|
}
|
|
2244
2257
|
|
|
2245
|
-
function createComponentContext({ runtime, scope, cleanups, attachHooks, visibleHooks, destroyHooks, renderScopedTemplate }) {
|
|
2258
|
+
function createComponentContext({ runtime, scope, cleanups, attachHooks, visibleHooks, intersectionHooks, destroyHooks, renderScopedTemplate }) {
|
|
2246
2259
|
const { signals, handlers, loader, server, router, cache, scheduler } = runtime;
|
|
2247
2260
|
const generatedHandlers = new WeakMap();
|
|
2248
2261
|
let generatedHandlerCounter = 0;
|
|
@@ -2330,6 +2343,7 @@ const __componentModule = (() => {
|
|
|
2330
2343
|
cleanups.push(child.cleanup);
|
|
2331
2344
|
attachHooks.push((target) => child.attach(target));
|
|
2332
2345
|
visibleHooks.push((target) => child.visible(target, loader._observeVisible));
|
|
2346
|
+
intersectionHooks.push((target) => child.intersection(target, loader._observeIntersection));
|
|
2333
2347
|
return rawHtml(child.html);
|
|
2334
2348
|
},
|
|
2335
2349
|
|
|
@@ -2353,14 +2367,22 @@ const __componentModule = (() => {
|
|
|
2353
2367
|
return rawHtml(chunks.join(""));
|
|
2354
2368
|
},
|
|
2355
2369
|
|
|
2356
|
-
on(eventName,
|
|
2370
|
+
on(eventName, optionsOrFn, maybeFn) {
|
|
2357
2371
|
if (typeof eventName !== "string" || eventName.length === 0) {
|
|
2358
2372
|
throw new TypeError("Component lifecycle event must be a non-empty string.");
|
|
2359
2373
|
}
|
|
2360
|
-
|
|
2374
|
+
const event = eventName === "mount" ? "attach" : eventName;
|
|
2375
|
+
if (event === "intersect") {
|
|
2376
|
+
const { options, fn } = normalizeOptionsCallback(`Component lifecycle "${eventName}"`, optionsOrFn, maybeFn);
|
|
2377
|
+
intersectionHooks.push((target) => {
|
|
2378
|
+
context.intersect(target, options, fn);
|
|
2379
|
+
});
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
if (maybeFn !== undefined || typeof optionsOrFn !== "function") {
|
|
2361
2383
|
throw new TypeError(`Component lifecycle "${eventName}" requires a function.`);
|
|
2362
2384
|
}
|
|
2363
|
-
const
|
|
2385
|
+
const fn = optionsOrFn;
|
|
2364
2386
|
if (event === "attach") {
|
|
2365
2387
|
attachHooks.push((target) => fn.call(context, target));
|
|
2366
2388
|
return;
|
|
@@ -2382,6 +2404,18 @@ const __componentModule = (() => {
|
|
|
2382
2404
|
|
|
2383
2405
|
onVisible(fn) {
|
|
2384
2406
|
context.on("visible", fn);
|
|
2407
|
+
},
|
|
2408
|
+
|
|
2409
|
+
intersect(target, optionsOrFn, maybeFn) {
|
|
2410
|
+
const { options, fn } = normalizeOptionsCallback("this.intersect(target, ...)", optionsOrFn, maybeFn);
|
|
2411
|
+
const cleanup = loader._observeIntersection(target, (event) => fn.call(context, event), {
|
|
2412
|
+
...options,
|
|
2413
|
+
scope
|
|
2414
|
+
});
|
|
2415
|
+
if (typeof cleanup === "function") {
|
|
2416
|
+
cleanups.push(cleanup);
|
|
2417
|
+
}
|
|
2418
|
+
return cleanup;
|
|
2385
2419
|
}
|
|
2386
2420
|
};
|
|
2387
2421
|
|
|
@@ -2397,6 +2431,16 @@ const __componentModule = (() => {
|
|
|
2397
2431
|
}
|
|
2398
2432
|
}
|
|
2399
2433
|
|
|
2434
|
+
function normalizeOptionsCallback(label, optionsOrFn, maybeFn) {
|
|
2435
|
+
if (typeof optionsOrFn === "function" && maybeFn === undefined) {
|
|
2436
|
+
return { options: {}, fn: optionsOrFn };
|
|
2437
|
+
}
|
|
2438
|
+
if ((optionsOrFn == null || (typeof optionsOrFn === "object" && !Array.isArray(optionsOrFn))) && typeof maybeFn === "function") {
|
|
2439
|
+
return { options: optionsOrFn ?? {}, fn: maybeFn };
|
|
2440
|
+
}
|
|
2441
|
+
throw new TypeError(`${label} requires (fn) or (options, fn).`);
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2400
2444
|
function scoped(scope, name) {
|
|
2401
2445
|
if (typeof name !== "string" || name.length === 0) {
|
|
2402
2446
|
throw new TypeError("Scoped signal or handler name must be a non-empty string.");
|
|
@@ -3492,6 +3536,7 @@ const __loaderModule = (() => {
|
|
|
3492
3536
|
const signalBindings = new WeakMap();
|
|
3493
3537
|
const mountedElements = new WeakSet();
|
|
3494
3538
|
const visibleElements = new WeakSet();
|
|
3539
|
+
const intersectionBindings = new WeakMap();
|
|
3495
3540
|
const boundaryState = new WeakMap();
|
|
3496
3541
|
const renderingBoundaries = new WeakSet();
|
|
3497
3542
|
const inlineBindings = new Map();
|
|
@@ -3555,6 +3600,7 @@ const __loaderModule = (() => {
|
|
|
3555
3600
|
api.scan(target);
|
|
3556
3601
|
rendered.mount(target);
|
|
3557
3602
|
rendered.visible(target, api._observeVisible);
|
|
3603
|
+
rendered.intersection(target, api._observeIntersection);
|
|
3558
3604
|
addCleanup(rendered.cleanup, target, "children");
|
|
3559
3605
|
return rendered;
|
|
3560
3606
|
},
|
|
@@ -3578,6 +3624,10 @@ const __loaderModule = (() => {
|
|
|
3578
3624
|
return observeVisible(target, fn);
|
|
3579
3625
|
},
|
|
3580
3626
|
|
|
3627
|
+
_observeIntersection(target, fn, options = {}) {
|
|
3628
|
+
return observeIntersection(target, fn, options);
|
|
3629
|
+
},
|
|
3630
|
+
|
|
3581
3631
|
_registerBinding(value) {
|
|
3582
3632
|
const id = `${inlineBindingPrefix}${++inlineBindingCounter}`;
|
|
3583
3633
|
inlineBindings.set(id, value);
|
|
@@ -3609,7 +3659,7 @@ const __loaderModule = (() => {
|
|
|
3609
3659
|
if (!eventName) {
|
|
3610
3660
|
continue;
|
|
3611
3661
|
}
|
|
3612
|
-
if (eventName === "attach" || eventName === "mount" || eventName === "visible") {
|
|
3662
|
+
if (eventName === "attach" || eventName === "mount" || eventName === "visible" || eventName === "intersect") {
|
|
3613
3663
|
continue;
|
|
3614
3664
|
}
|
|
3615
3665
|
bindEvent(element, eventName, element.getAttribute(name));
|
|
@@ -3882,6 +3932,25 @@ const __loaderModule = (() => {
|
|
|
3882
3932
|
visibleElements.add(element);
|
|
3883
3933
|
addCleanup(observeVisible(element, () => scheduleLifecycle(element, () => runPseudo(element, ref), `visible:${ref}`)), element);
|
|
3884
3934
|
}
|
|
3935
|
+
|
|
3936
|
+
for (const element of elementsIn(scope)) {
|
|
3937
|
+
const ref = readAttribute(element, attributeConfig, "on", "intersect");
|
|
3938
|
+
if (ref == null) {
|
|
3939
|
+
continue;
|
|
3940
|
+
}
|
|
3941
|
+
const options = readIntersectionOptions(element);
|
|
3942
|
+
const key = `intersect:${ref}:${serializeIntersectionOptions(options)}`;
|
|
3943
|
+
const bound = intersectionBindings.get(element) ?? new Set();
|
|
3944
|
+
if (bound.has(key)) {
|
|
3945
|
+
continue;
|
|
3946
|
+
}
|
|
3947
|
+
bound.add(key);
|
|
3948
|
+
intersectionBindings.set(element, bound);
|
|
3949
|
+
addCleanup(observeIntersection(element, (event) => runPseudo(element, ref, event), {
|
|
3950
|
+
...options,
|
|
3951
|
+
key
|
|
3952
|
+
}), element);
|
|
3953
|
+
}
|
|
3885
3954
|
}
|
|
3886
3955
|
|
|
3887
3956
|
function readPseudoRefs(element, names) {
|
|
@@ -3895,7 +3964,7 @@ const __loaderModule = (() => {
|
|
|
3895
3964
|
return refs;
|
|
3896
3965
|
}
|
|
3897
3966
|
|
|
3898
|
-
async function runPseudo(element, ref) {
|
|
3967
|
+
async function runPseudo(element, ref, context = {}) {
|
|
3899
3968
|
try {
|
|
3900
3969
|
const results = await handlerRegistry.run(ref, {
|
|
3901
3970
|
signals: signalRegistry,
|
|
@@ -3907,7 +3976,8 @@ const __loaderModule = (() => {
|
|
|
3907
3976
|
scheduler: schedulerInstance,
|
|
3908
3977
|
element,
|
|
3909
3978
|
el: element,
|
|
3910
|
-
root: rootNode
|
|
3979
|
+
root: rootNode,
|
|
3980
|
+
...context
|
|
3911
3981
|
});
|
|
3912
3982
|
for (const result of results) {
|
|
3913
3983
|
if (typeof result === "function") {
|
|
@@ -3920,28 +3990,230 @@ const __loaderModule = (() => {
|
|
|
3920
3990
|
}
|
|
3921
3991
|
|
|
3922
3992
|
function observeVisible(target, fn) {
|
|
3993
|
+
return observeIntersection(target, (event) => {
|
|
3994
|
+
if (event.isIntersecting) {
|
|
3995
|
+
fn(target);
|
|
3996
|
+
}
|
|
3997
|
+
}, {
|
|
3998
|
+
once: true,
|
|
3999
|
+
threshold: 0
|
|
4000
|
+
});
|
|
4001
|
+
}
|
|
4002
|
+
|
|
4003
|
+
function observeIntersection(target, fn, options = {}) {
|
|
4004
|
+
if (typeof fn !== "function") {
|
|
4005
|
+
throw new TypeError("observeIntersection(target, fn) requires a callback.");
|
|
4006
|
+
}
|
|
4007
|
+
const normalized = normalizeIntersectionOptions(target, options);
|
|
3923
4008
|
const ownerWindow = target.ownerDocument?.defaultView ?? globalThis;
|
|
3924
4009
|
const Observer = ownerWindow.IntersectionObserver ?? globalThis.IntersectionObserver;
|
|
3925
4010
|
if (!Observer) {
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
4011
|
+
let cleaned = false;
|
|
4012
|
+
const event = createIntersectionEvent({
|
|
4013
|
+
target,
|
|
4014
|
+
root: normalized.root,
|
|
4015
|
+
entry: createFallbackIntersectionEntry(target),
|
|
4016
|
+
observer: null,
|
|
4017
|
+
unsupported: true
|
|
4018
|
+
});
|
|
4019
|
+
const cancel = schedulerInstance.enqueue("lifecycle", () => {
|
|
4020
|
+
if (!cleaned && !destroyed) {
|
|
4021
|
+
fn(event);
|
|
3929
4022
|
}
|
|
3930
4023
|
}, {
|
|
3931
|
-
scope:
|
|
3932
|
-
key: "
|
|
4024
|
+
scope: normalized.scope,
|
|
4025
|
+
key: normalized.key ?? "intersect:fallback"
|
|
3933
4026
|
});
|
|
3934
|
-
return () => {
|
|
4027
|
+
return () => {
|
|
4028
|
+
cleaned = true;
|
|
4029
|
+
cancel?.();
|
|
4030
|
+
};
|
|
3935
4031
|
}
|
|
3936
4032
|
|
|
4033
|
+
let cleaned = false;
|
|
4034
|
+
let stopped = false;
|
|
3937
4035
|
const observer = new Observer((entries) => {
|
|
3938
|
-
if (
|
|
4036
|
+
if (cleaned || stopped || destroyed) {
|
|
4037
|
+
return;
|
|
4038
|
+
}
|
|
4039
|
+
const observedEntries = entries.filter((entry) => entry.target === target);
|
|
4040
|
+
const targetEntries = observedEntries.length > 0 ? observedEntries : entries;
|
|
4041
|
+
const entry = targetEntries[0];
|
|
4042
|
+
if (!entry) {
|
|
4043
|
+
return;
|
|
4044
|
+
}
|
|
4045
|
+
const event = createIntersectionEvent({
|
|
4046
|
+
target,
|
|
4047
|
+
root: normalized.root,
|
|
4048
|
+
entry,
|
|
4049
|
+
entries: targetEntries,
|
|
4050
|
+
observer,
|
|
4051
|
+
unsupported: false
|
|
4052
|
+
});
|
|
4053
|
+
if (normalized.once && event.isIntersecting) {
|
|
4054
|
+
stopped = true;
|
|
3939
4055
|
observer.disconnect();
|
|
3940
|
-
fn(target);
|
|
3941
4056
|
}
|
|
4057
|
+
runIntersectionCallback(fn, event, normalized, () => !cleaned);
|
|
4058
|
+
}, {
|
|
4059
|
+
root: normalized.root,
|
|
4060
|
+
rootMargin: normalized.rootMargin,
|
|
4061
|
+
threshold: normalized.threshold
|
|
3942
4062
|
});
|
|
3943
4063
|
observer.observe(target);
|
|
3944
|
-
return () =>
|
|
4064
|
+
return () => {
|
|
4065
|
+
if (cleaned) {
|
|
4066
|
+
return;
|
|
4067
|
+
}
|
|
4068
|
+
cleaned = true;
|
|
4069
|
+
stopped = true;
|
|
4070
|
+
observer.disconnect();
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
4073
|
+
|
|
4074
|
+
function readIntersectionOptions(element) {
|
|
4075
|
+
const options = {};
|
|
4076
|
+
const threshold = readAttribute(element, attributeConfig, "intersect", "threshold");
|
|
4077
|
+
if (threshold != null) {
|
|
4078
|
+
options.threshold = parseIntersectionThreshold(threshold);
|
|
4079
|
+
}
|
|
4080
|
+
const rootMargin = readAttribute(element, attributeConfig, "intersect", "root-margin")
|
|
4081
|
+
?? readAttribute(element, attributeConfig, "intersect", "rootMargin");
|
|
4082
|
+
if (rootMargin != null) {
|
|
4083
|
+
options.rootMargin = rootMargin;
|
|
4084
|
+
}
|
|
4085
|
+
const once = readAttribute(element, attributeConfig, "intersect", "once");
|
|
4086
|
+
if (once != null) {
|
|
4087
|
+
options.once = parseBooleanAttribute(once);
|
|
4088
|
+
}
|
|
4089
|
+
return options;
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
function parseIntersectionThreshold(value) {
|
|
4093
|
+
const parts = String(value).split(",").map((part) => part.trim()).filter(Boolean);
|
|
4094
|
+
if (parts.length === 0) {
|
|
4095
|
+
throw new TypeError("intersect:threshold must include a number from 0 to 1.");
|
|
4096
|
+
}
|
|
4097
|
+
const thresholds = parts.map((part) => {
|
|
4098
|
+
const number = Number(part);
|
|
4099
|
+
return validateIntersectionThreshold(number);
|
|
4100
|
+
});
|
|
4101
|
+
return thresholds.length === 1 ? thresholds[0] : thresholds;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
function parseBooleanAttribute(value) {
|
|
4105
|
+
const normalized = String(value).trim().toLowerCase();
|
|
4106
|
+
return normalized === "" || normalized === "true" || normalized === "1";
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
function serializeIntersectionOptions(options) {
|
|
4110
|
+
return JSON.stringify({
|
|
4111
|
+
rootMargin: options.rootMargin ?? "0px",
|
|
4112
|
+
threshold: options.threshold ?? 0,
|
|
4113
|
+
once: Boolean(options.once)
|
|
4114
|
+
});
|
|
4115
|
+
}
|
|
4116
|
+
|
|
4117
|
+
function normalizeIntersectionOptions(target, options) {
|
|
4118
|
+
const ownerWindow = target?.ownerDocument?.defaultView ?? globalThis;
|
|
4119
|
+
if (!isElement(target, ownerWindow)) {
|
|
4120
|
+
throw new TypeError("Intersection target must be an Element.");
|
|
4121
|
+
}
|
|
4122
|
+
const root = options.root ?? null;
|
|
4123
|
+
if (root !== null && !isElement(root, ownerWindow) && !isDocument(root, ownerWindow)) {
|
|
4124
|
+
throw new TypeError("Intersection root must be an Element, Document, or null.");
|
|
4125
|
+
}
|
|
4126
|
+
const rootMargin = options.rootMargin ?? "0px";
|
|
4127
|
+
if (typeof rootMargin !== "string") {
|
|
4128
|
+
throw new TypeError("Intersection rootMargin must be a string.");
|
|
4129
|
+
}
|
|
4130
|
+
const threshold = normalizeIntersectionThreshold(options.threshold ?? 0);
|
|
4131
|
+
const schedule = options.schedule ?? "lifecycle";
|
|
4132
|
+
if (schedule !== "lifecycle" && schedule !== "sync") {
|
|
4133
|
+
throw new TypeError('Intersection schedule must be "lifecycle" or "sync".');
|
|
4134
|
+
}
|
|
4135
|
+
return {
|
|
4136
|
+
root,
|
|
4137
|
+
rootMargin,
|
|
4138
|
+
threshold,
|
|
4139
|
+
once: Boolean(options.once),
|
|
4140
|
+
schedule,
|
|
4141
|
+
scope: options.scope ?? target,
|
|
4142
|
+
key: options.key
|
|
4143
|
+
};
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
function normalizeIntersectionThreshold(threshold) {
|
|
4147
|
+
if (Array.isArray(threshold)) {
|
|
4148
|
+
return threshold.map(validateIntersectionThreshold);
|
|
4149
|
+
}
|
|
4150
|
+
return validateIntersectionThreshold(threshold);
|
|
4151
|
+
}
|
|
4152
|
+
|
|
4153
|
+
function validateIntersectionThreshold(value) {
|
|
4154
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
4155
|
+
throw new TypeError("Intersection threshold must be a number from 0 to 1.");
|
|
4156
|
+
}
|
|
4157
|
+
return value;
|
|
4158
|
+
}
|
|
4159
|
+
|
|
4160
|
+
function runIntersectionCallback(fn, event, options, isActive = () => true) {
|
|
4161
|
+
if (options.schedule === "sync") {
|
|
4162
|
+
if (isActive()) {
|
|
4163
|
+
fn(event);
|
|
4164
|
+
}
|
|
4165
|
+
return;
|
|
4166
|
+
}
|
|
4167
|
+
schedulerInstance.enqueue("lifecycle", () => {
|
|
4168
|
+
if (!destroyed && isActive()) {
|
|
4169
|
+
fn(event);
|
|
4170
|
+
}
|
|
4171
|
+
}, {
|
|
4172
|
+
scope: options.scope,
|
|
4173
|
+
key: options.key
|
|
4174
|
+
});
|
|
4175
|
+
}
|
|
4176
|
+
|
|
4177
|
+
function createIntersectionEvent({ target, root, entry, entries = [entry], observer, unsupported }) {
|
|
4178
|
+
const isIntersecting = Boolean(entry?.isIntersecting);
|
|
4179
|
+
const intersectionRatio = typeof entry?.intersectionRatio === "number"
|
|
4180
|
+
? entry.intersectionRatio
|
|
4181
|
+
: (isIntersecting ? 1 : 0);
|
|
4182
|
+
return {
|
|
4183
|
+
target,
|
|
4184
|
+
element: target,
|
|
4185
|
+
el: target,
|
|
4186
|
+
root: root ?? rootNode,
|
|
4187
|
+
entry,
|
|
4188
|
+
entries,
|
|
4189
|
+
observer,
|
|
4190
|
+
isIntersecting,
|
|
4191
|
+
intersectionRatio,
|
|
4192
|
+
unsupported: Boolean(unsupported)
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
function createFallbackIntersectionEntry(target) {
|
|
4197
|
+
const rect = target.getBoundingClientRect?.() ?? null;
|
|
4198
|
+
return {
|
|
4199
|
+
target,
|
|
4200
|
+
isIntersecting: true,
|
|
4201
|
+
intersectionRatio: 1,
|
|
4202
|
+
time: 0,
|
|
4203
|
+
rootBounds: null,
|
|
4204
|
+
boundingClientRect: rect,
|
|
4205
|
+
intersectionRect: rect
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4209
|
+
function isElement(value, ownerWindow = globalThis) {
|
|
4210
|
+
const ElementRef = ownerWindow.Element ?? globalThis.Element;
|
|
4211
|
+
return Boolean(ElementRef && value instanceof ElementRef);
|
|
4212
|
+
}
|
|
4213
|
+
|
|
4214
|
+
function isDocument(value, ownerWindow = globalThis) {
|
|
4215
|
+
const DocumentRef = ownerWindow.Document ?? globalThis.Document;
|
|
4216
|
+
return Boolean(DocumentRef && value instanceof DocumentRef);
|
|
3945
4217
|
}
|
|
3946
4218
|
|
|
3947
4219
|
function assertActive() {
|
package/package.json
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@async/framework",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.16",
|
|
4
4
|
"description": "No-build Loader app runtime with browser and server entrypoints, signals, command events, route partials, cache split, SSR activation, and streaming boundaries.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./server.js",
|
|
7
|
-
"module": "./browser.min.js",
|
|
8
|
-
"browser": "./browser.min.js",
|
|
9
6
|
"sideEffects": false,
|
|
10
|
-
"packageManager": "pnpm@11.1.0",
|
|
11
7
|
"engines": {
|
|
12
8
|
"node": ">=24"
|
|
13
9
|
},
|
|
@@ -32,7 +28,6 @@
|
|
|
32
28
|
"web-framework"
|
|
33
29
|
],
|
|
34
30
|
"license": "MIT",
|
|
35
|
-
"types": "./framework.d.ts",
|
|
36
31
|
"unpkg": "./browser.umd.min.js",
|
|
37
32
|
"jsdelivr": "./browser.umd.min.js",
|
|
38
33
|
"exports": {
|
|
@@ -65,41 +60,27 @@
|
|
|
65
60
|
"import": "./server.js",
|
|
66
61
|
"default": "./server.js"
|
|
67
62
|
},
|
|
68
|
-
"./
|
|
69
|
-
"types": "./
|
|
70
|
-
"
|
|
63
|
+
"./runtime": {
|
|
64
|
+
"types": "./runtime.d.ts",
|
|
65
|
+
"import": "./runtime.js",
|
|
66
|
+
"default": "./runtime.js"
|
|
71
67
|
},
|
|
72
|
-
"./
|
|
73
|
-
"types": "./
|
|
74
|
-
"
|
|
68
|
+
"./runtime/signals": {
|
|
69
|
+
"types": "./runtime/signals.d.ts",
|
|
70
|
+
"import": "./runtime/signals.js",
|
|
71
|
+
"default": "./runtime/signals.js"
|
|
75
72
|
},
|
|
76
|
-
"./
|
|
77
|
-
"types": "./
|
|
78
|
-
"
|
|
73
|
+
"./runtime/events": {
|
|
74
|
+
"types": "./runtime/events.d.ts",
|
|
75
|
+
"import": "./runtime/events.js",
|
|
76
|
+
"default": "./runtime/events.js"
|
|
79
77
|
},
|
|
80
|
-
"./browser.umd.min.js": {
|
|
81
|
-
"types": "./browser.d.ts",
|
|
82
|
-
"default": "./browser.umd.min.js"
|
|
83
|
-
},
|
|
84
|
-
"./browser.ts": {
|
|
85
|
-
"types": "./browser.d.ts",
|
|
86
|
-
"default": "./browser.ts"
|
|
87
|
-
},
|
|
88
|
-
"./browser.d.ts": "./browser.d.ts",
|
|
89
|
-
"./server.js": {
|
|
90
|
-
"types": "./framework.d.ts",
|
|
91
|
-
"default": "./server.js"
|
|
92
|
-
},
|
|
93
|
-
"./framework.ts": {
|
|
94
|
-
"types": "./framework.d.ts",
|
|
95
|
-
"default": "./framework.ts"
|
|
96
|
-
},
|
|
97
|
-
"./framework.d.ts": "./framework.d.ts",
|
|
98
78
|
"./package.json": "./package.json"
|
|
99
79
|
},
|
|
100
80
|
"files": [
|
|
101
81
|
"CHANGELOG.md",
|
|
102
82
|
"README.md",
|
|
83
|
+
"LICENSE",
|
|
103
84
|
"browser.d.ts",
|
|
104
85
|
"browser.js",
|
|
105
86
|
"browser.min.js",
|
|
@@ -108,40 +89,14 @@
|
|
|
108
89
|
"browser.ts",
|
|
109
90
|
"framework.d.ts",
|
|
110
91
|
"framework.ts",
|
|
92
|
+
"package.json",
|
|
111
93
|
"server.js",
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
|
|
120
|
-
"bundle:size:check": "node scripts/bundle-size.js --check",
|
|
121
|
-
"docs:build": "node scripts/build-pages.js",
|
|
122
|
-
"examples": "node --test tests/examples.test.js",
|
|
123
|
-
"examples:check": "node --test tests/examples.test.js",
|
|
124
|
-
"pack:check": "pnpm run bundle:check && npm pack --dry-run --ignore-scripts",
|
|
125
|
-
"pipeline:github:check": "async-pipeline github check",
|
|
126
|
-
"pipeline:github:generate": "async-pipeline github generate",
|
|
127
|
-
"pipeline:pages": "async-pipeline run-task docs.site",
|
|
128
|
-
"pipeline:publish": "async-pipeline run publish",
|
|
129
|
-
"pipeline:publish:github:release": "async-pipeline publish github release --package . --registry https://npm.pkg.github.com",
|
|
130
|
-
"pipeline:publish:npm": "async-pipeline publish npm --package .",
|
|
131
|
-
"pipeline:release-doctor": "async-pipeline run release-doctor",
|
|
132
|
-
"pipeline:release:doctor": "async-pipeline release doctor --package .",
|
|
133
|
-
"pipeline:release:ensure": "async-pipeline release ensure --package .",
|
|
134
|
-
"pipeline:sync:check": "async-pipeline sync check",
|
|
135
|
-
"pipeline:sync:generate": "async-pipeline sync generate",
|
|
136
|
-
"pipeline:task:docs.site": "async-pipeline run-task docs.site",
|
|
137
|
-
"pipeline:verify": "async-pipeline run verify",
|
|
138
|
-
"registry:lint": "node scripts/registry-lint.js",
|
|
139
|
-
"release:check": "pnpm run pipeline:verify -- --force && pnpm run bundle:size:check && pnpm run pipeline:pages -- --force && pnpm run pipeline:sync:check && pnpm run pipeline:github:check",
|
|
140
|
-
"test": "node --test tests/*.test.js"
|
|
141
|
-
},
|
|
142
|
-
"devDependencies": {
|
|
143
|
-
"@async/pipeline": "0.9.1",
|
|
144
|
-
"happy-dom": "20.10.5",
|
|
145
|
-
"terser": "5.48.0"
|
|
146
|
-
}
|
|
94
|
+
"runtime.d.ts",
|
|
95
|
+
"runtime/signals.d.ts",
|
|
96
|
+
"runtime/events.d.ts",
|
|
97
|
+
"runtime.js",
|
|
98
|
+
"runtime/signals.js",
|
|
99
|
+
"runtime/events.js",
|
|
100
|
+
"runtime/shared.js"
|
|
101
|
+
]
|
|
147
102
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Generated by scripts/build-framework-bundle.js. Do not edit by hand.
|
|
2
|
+
// Type declarations for @async/framework/runtime/events.
|
|
3
|
+
|
|
4
|
+
export type ElementLocator = string | { readonly selector: string; readonly optional?: boolean };
|
|
5
|
+
export type EventRuntimeContext = {
|
|
6
|
+
event: Event;
|
|
7
|
+
element: Element;
|
|
8
|
+
el: Element;
|
|
9
|
+
root: ParentNode;
|
|
10
|
+
signals?: { set(path: string, value: unknown): void };
|
|
11
|
+
};
|
|
12
|
+
export type EventValueSource =
|
|
13
|
+
| readonly ["event.target.value"]
|
|
14
|
+
| readonly ["event.target.checked"]
|
|
15
|
+
| readonly ["constant", value: unknown];
|
|
16
|
+
export type EventCommand =
|
|
17
|
+
| readonly ["handler", id: string]
|
|
18
|
+
| readonly ["preventDefault"]
|
|
19
|
+
| readonly ["stopPropagation"]
|
|
20
|
+
| readonly ["stopImmediatePropagation"]
|
|
21
|
+
| readonly ["setSignal", path: string, valueSource: EventValueSource];
|
|
22
|
+
export type EventBindingRecord = readonly [element: number, event: string, commands: readonly EventCommand[]];
|
|
23
|
+
export type StrictHandlerDescriptor = {
|
|
24
|
+
readonly mode?: "strict";
|
|
25
|
+
readonly module?: string;
|
|
26
|
+
readonly browserImport: string;
|
|
27
|
+
readonly exportName: string;
|
|
28
|
+
readonly version?: string;
|
|
29
|
+
readonly integrity?: string;
|
|
30
|
+
};
|
|
31
|
+
export type HandlerDescriptor = ((context: EventRuntimeContext) => unknown | Promise<unknown>) | StrictHandlerDescriptor;
|
|
32
|
+
export type EventRuntimePlan = {
|
|
33
|
+
readonly version?: 1;
|
|
34
|
+
readonly events: readonly EventBindingRecord[];
|
|
35
|
+
readonly handlers?: Record<string, HandlerDescriptor>;
|
|
36
|
+
};
|
|
37
|
+
export type EventRuntimeOptions = {
|
|
38
|
+
readonly elements?: readonly ElementLocator[];
|
|
39
|
+
readonly signal?: AbortSignal;
|
|
40
|
+
readonly signals?: { set(path: string, value: unknown): void };
|
|
41
|
+
readonly importModule?: (specifier: string) => Promise<Record<string, unknown>>;
|
|
42
|
+
readonly onDiagnostic?: (diagnostic: Record<string, unknown>) => void;
|
|
43
|
+
};
|
|
44
|
+
export type EventRuntimeController = {
|
|
45
|
+
readonly stopped: boolean;
|
|
46
|
+
stop(): void;
|
|
47
|
+
};
|
|
48
|
+
export declare function startEvents(rootOrOptions: ParentNode | ({ root: ParentNode; plan: EventRuntimePlan } & EventRuntimeOptions), plan?: EventRuntimePlan, options?: EventRuntimeOptions): EventRuntimeController;
|