@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/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, fn) {
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
- if (typeof fn !== "function") {
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 event = eventName === "mount" ? "attach" : eventName;
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
- schedulerInstance.enqueue("lifecycle", () => {
3927
- if (!destroyed) {
3928
- fn(target);
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: target,
3932
- key: "visible:fallback"
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 (entries.some((entry) => entry.isIntersecting)) {
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 () => observer.disconnect();
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.14",
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
- "./browser.js": {
69
- "types": "./browser.d.ts",
70
- "default": "./browser.js"
63
+ "./runtime": {
64
+ "types": "./runtime.d.ts",
65
+ "import": "./runtime.js",
66
+ "default": "./runtime.js"
71
67
  },
72
- "./browser.min.js": {
73
- "types": "./browser.d.ts",
74
- "default": "./browser.min.js"
68
+ "./runtime/signals": {
69
+ "types": "./runtime/signals.d.ts",
70
+ "import": "./runtime/signals.js",
71
+ "default": "./runtime/signals.js"
75
72
  },
76
- "./browser.umd.js": {
77
- "types": "./browser.d.ts",
78
- "default": "./browser.umd.js"
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
- "LICENSE",
113
- "package.json"
114
- ],
115
- "scripts": {
116
- "async-pipeline": "async-pipeline",
117
- "bundle": "node scripts/build-framework-bundle.js",
118
- "bundle:check": "node scripts/build-framework-bundle.js --check",
119
- "bundle:size": "node scripts/bundle-size.js",
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;