octane 0.1.33 → 0.1.34
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/dist/cjs/behavior-root.cjs +711 -0
- package/dist/cjs/component-flags.cjs +41 -0
- package/dist/cjs/constants.cjs +144 -0
- package/dist/cjs/css.cjs +60 -0
- package/dist/cjs/devtools-hook.cjs +194 -0
- package/dist/cjs/dom-tables.cjs +500 -0
- package/dist/cjs/error-codes.client.generated.cjs +176 -0
- package/dist/cjs/error-codes.server.generated.cjs +147 -0
- package/dist/cjs/error-message.cjs +53 -0
- package/dist/cjs/head-ownership.cjs +56 -0
- package/dist/cjs/html-tree-validation.cjs +175 -0
- package/dist/cjs/hydration/event-capture.cjs +188 -0
- package/dist/cjs/hydration/interaction-config.cjs +36 -0
- package/dist/cjs/index.cjs +413 -0
- package/dist/cjs/method-dep.cjs +35 -0
- package/dist/cjs/profiling.cjs +462 -0
- package/dist/cjs/renderer-bridge.cjs +64 -0
- package/dist/cjs/runtime.cjs +16054 -0
- package/dist/cjs/runtime.server.cjs +4818 -0
- package/dist/cjs/sanitize-url.cjs +59 -0
- package/dist/cjs/server/index.cjs +256 -0
- package/dist/cjs/server/rpc.cjs +58 -0
- package/dist/cjs/server-rpc-client.cjs +70 -0
- package/dist/cjs/stream-protocol.cjs +97 -0
- package/dist/cjs/version.cjs +28 -0
- package/dist/compiler/bundler.js +49 -33
- package/dist/compiler/compile.js +963 -83
- package/dist/error-codes.client.generated.d.ts +2 -0
- package/dist/error-codes.client.generated.js +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -0
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/runtime.d.ts +85 -69
- package/dist/runtime.js +719 -188
- package/dist/runtime.server.d.ts +9 -3
- package/dist/runtime.server.js +97 -27
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +2 -0
- package/dist/version.js +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var behavior_root_exports = {};
|
|
20
|
+
__export(behavior_root_exports, {
|
|
21
|
+
attachBehaviorRoot: () => attachBehaviorRoot
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(behavior_root_exports);
|
|
24
|
+
const documentRegistries = /* @__PURE__ */ new WeakMap();
|
|
25
|
+
const CANCELED = /* @__PURE__ */ Symbol("octane.behavior.canceled");
|
|
26
|
+
function createReadiness() {
|
|
27
|
+
let resolvePromise;
|
|
28
|
+
let rejectPromise;
|
|
29
|
+
const promise = new Promise((resolve, reject) => {
|
|
30
|
+
resolvePromise = resolve;
|
|
31
|
+
rejectPromise = reject;
|
|
32
|
+
});
|
|
33
|
+
void promise.catch(() => void 0);
|
|
34
|
+
const readiness = {
|
|
35
|
+
promise,
|
|
36
|
+
settled: false,
|
|
37
|
+
resolve() {
|
|
38
|
+
if (readiness.settled) return;
|
|
39
|
+
readiness.settled = true;
|
|
40
|
+
resolvePromise();
|
|
41
|
+
},
|
|
42
|
+
reject(reason) {
|
|
43
|
+
if (readiness.settled) return;
|
|
44
|
+
readiness.settled = true;
|
|
45
|
+
rejectPromise(reason);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return readiness;
|
|
49
|
+
}
|
|
50
|
+
function createController(document) {
|
|
51
|
+
const Controller = document.defaultView?.AbortController ?? globalThis.AbortController;
|
|
52
|
+
return new Controller();
|
|
53
|
+
}
|
|
54
|
+
function linkSignal(signal, controller) {
|
|
55
|
+
if (signal.aborted) {
|
|
56
|
+
controller.abort(signal.reason);
|
|
57
|
+
return () => void 0;
|
|
58
|
+
}
|
|
59
|
+
const abort = () => controller.abort(signal.reason);
|
|
60
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
61
|
+
return () => signal.removeEventListener("abort", abort);
|
|
62
|
+
}
|
|
63
|
+
function waitUntilReady(source, signal) {
|
|
64
|
+
if (signal.aborted) {
|
|
65
|
+
void Promise.resolve(source).then(void 0, () => void 0);
|
|
66
|
+
return Promise.resolve(CANCELED);
|
|
67
|
+
}
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
let settled = false;
|
|
70
|
+
const cancel = () => {
|
|
71
|
+
if (settled) return;
|
|
72
|
+
settled = true;
|
|
73
|
+
resolve(CANCELED);
|
|
74
|
+
};
|
|
75
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
76
|
+
Promise.resolve(source).then(
|
|
77
|
+
(value) => {
|
|
78
|
+
if (settled) return;
|
|
79
|
+
settled = true;
|
|
80
|
+
signal.removeEventListener("abort", cancel);
|
|
81
|
+
resolve(value);
|
|
82
|
+
},
|
|
83
|
+
(error) => {
|
|
84
|
+
if (settled) return;
|
|
85
|
+
settled = true;
|
|
86
|
+
signal.removeEventListener("abort", cancel);
|
|
87
|
+
reject(error);
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function trackPending(root, promise) {
|
|
93
|
+
root.pending.add(promise);
|
|
94
|
+
void promise.then(
|
|
95
|
+
() => root.pending.delete(promise),
|
|
96
|
+
() => root.pending.delete(promise)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
function isElement(value) {
|
|
100
|
+
return typeof value === "object" && value !== null && value.nodeType === 1;
|
|
101
|
+
}
|
|
102
|
+
function contains(root, element) {
|
|
103
|
+
return element.ownerDocument === root.document && (element === root.container || root.container.contains(element));
|
|
104
|
+
}
|
|
105
|
+
function assertActiveRoot(root) {
|
|
106
|
+
if (root.disposed || root.controller.signal.aborted) {
|
|
107
|
+
throw new Error("Cannot register behavior on a disposed behavior root.");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function assertContainedElement(root, element, label) {
|
|
111
|
+
if (!isElement(element) || !contains(root, element)) {
|
|
112
|
+
throw new Error(`${label} must belong to the behavior root container and document.`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function nearestRange(root, element) {
|
|
116
|
+
let current = element;
|
|
117
|
+
while (current !== null) {
|
|
118
|
+
const range = root.registry.ranges.get(current);
|
|
119
|
+
if (range !== void 0 && range.status !== "disposed" && range.status !== "failed") {
|
|
120
|
+
return range;
|
|
121
|
+
}
|
|
122
|
+
if (current === root.container) return void 0;
|
|
123
|
+
current = current.parentElement;
|
|
124
|
+
}
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
function matchesTarget(record, element) {
|
|
128
|
+
return typeof record.entry.target === "string" ? element.matches(record.entry.target) : record.entry.target === element;
|
|
129
|
+
}
|
|
130
|
+
function rangeMatches(record, range) {
|
|
131
|
+
return record.entry.owner === void 0 || range !== void 0 && Object.is(record.entry.owner, range.owner);
|
|
132
|
+
}
|
|
133
|
+
function dependsOnRange(record, range) {
|
|
134
|
+
if (record.waitingRanges.has(range)) return true;
|
|
135
|
+
if (record.entry.owner === void 0 || !Object.is(record.entry.owner, range.owner) || !contains(record.root, range.element)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (typeof record.entry.target !== "string") {
|
|
139
|
+
return range.element.contains(record.entry.target) && nearestRange(record.root, record.entry.target) === range;
|
|
140
|
+
}
|
|
141
|
+
if (range.element.matches(record.entry.target) && nearestRange(record.root, range.element) === range) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
for (const element of range.element.querySelectorAll(record.entry.target)) {
|
|
145
|
+
if (nearestRange(record.root, element) === range) return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
function adoptionContext(adoption, event) {
|
|
150
|
+
const context = {
|
|
151
|
+
signal: adoption.controller.signal,
|
|
152
|
+
...adoption.range === void 0 ? {} : { range: adoption.range.publicRange },
|
|
153
|
+
...event === void 0 ? {} : { event }
|
|
154
|
+
};
|
|
155
|
+
return context;
|
|
156
|
+
}
|
|
157
|
+
function disposeAdoption(adoption) {
|
|
158
|
+
if (adoption.disposed) return;
|
|
159
|
+
adoption.disposed = true;
|
|
160
|
+
adoption.entry.adoptions.delete(adoption.element);
|
|
161
|
+
adoption.controller.abort();
|
|
162
|
+
for (const unlink of adoption.unlinks) unlink();
|
|
163
|
+
adoption.unlinks.length = 0;
|
|
164
|
+
const cleanup = adoption.cleanup;
|
|
165
|
+
adoption.cleanup = void 0;
|
|
166
|
+
cleanup?.();
|
|
167
|
+
}
|
|
168
|
+
function flushQueuedEvents(record) {
|
|
169
|
+
if (record.status !== "active") return;
|
|
170
|
+
while (record.queuedEvents.length !== 0) {
|
|
171
|
+
const queued = record.queuedEvents[0];
|
|
172
|
+
if (!contains(record.root, queued.element)) {
|
|
173
|
+
record.queuedEvents.shift();
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const range = nearestRange(record.root, queued.element);
|
|
177
|
+
if (range !== queued.range || !rangeMatches(record, range)) {
|
|
178
|
+
record.queuedEvents.shift();
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (range?.status === "pending") return;
|
|
182
|
+
let adoption = record.adoptions.get(queued.element);
|
|
183
|
+
if (adoption === void 0) {
|
|
184
|
+
adoption = adoptElement(record, queued.element, range, queued.event);
|
|
185
|
+
}
|
|
186
|
+
if (adoption === void 0 || adoption.pending) return;
|
|
187
|
+
record.queuedEvents.shift();
|
|
188
|
+
record.entry.handleEvent?.(
|
|
189
|
+
queued.event,
|
|
190
|
+
queued.element,
|
|
191
|
+
adoptionContext(adoption, queued.event)
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function completeBehavior(record) {
|
|
196
|
+
if (record.status !== "active" || !record.initialScanComplete) return;
|
|
197
|
+
for (const range of [...record.waitingRanges]) {
|
|
198
|
+
if (range.status === "pending") return;
|
|
199
|
+
record.waitingRanges.delete(range);
|
|
200
|
+
}
|
|
201
|
+
for (const adoption of record.adoptions.values()) {
|
|
202
|
+
if (adoption.pending) return;
|
|
203
|
+
}
|
|
204
|
+
flushQueuedEvents(record);
|
|
205
|
+
if (record.queuedEvents.length !== 0) return;
|
|
206
|
+
record.readiness.resolve();
|
|
207
|
+
}
|
|
208
|
+
function failBehavior(record, error) {
|
|
209
|
+
if (record.status === "disposed" || record.status === "failed") return;
|
|
210
|
+
record.status = "failed";
|
|
211
|
+
record.readiness.reject(error);
|
|
212
|
+
disposeBehavior(record);
|
|
213
|
+
}
|
|
214
|
+
function adoptElement(record, element, range, event) {
|
|
215
|
+
if (record.status !== "active" || !contains(record.root, element) || !rangeMatches(record, range)) {
|
|
216
|
+
return void 0;
|
|
217
|
+
}
|
|
218
|
+
if (range?.status === "pending") {
|
|
219
|
+
record.waitingRanges.add(range);
|
|
220
|
+
return void 0;
|
|
221
|
+
}
|
|
222
|
+
const existing = record.adoptions.get(element);
|
|
223
|
+
if (existing !== void 0) return existing;
|
|
224
|
+
const controller = createController(record.root.document);
|
|
225
|
+
const adoption = {
|
|
226
|
+
entry: record,
|
|
227
|
+
element,
|
|
228
|
+
range,
|
|
229
|
+
controller,
|
|
230
|
+
unlinks: [linkSignal(record.controller.signal, controller)],
|
|
231
|
+
cleanup: void 0,
|
|
232
|
+
pending: false,
|
|
233
|
+
disposed: false
|
|
234
|
+
};
|
|
235
|
+
if (range !== void 0) adoption.unlinks.push(linkSignal(range.controller.signal, controller));
|
|
236
|
+
if (controller.signal.aborted) return void 0;
|
|
237
|
+
record.adoptions.set(element, adoption);
|
|
238
|
+
let result;
|
|
239
|
+
try {
|
|
240
|
+
result = record.entry.adopt(element, adoptionContext(adoption, event));
|
|
241
|
+
} catch (error) {
|
|
242
|
+
disposeAdoption(adoption);
|
|
243
|
+
failBehavior(record, error);
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
if (typeof result === "function") {
|
|
247
|
+
if (adoption.disposed || controller.signal.aborted) result();
|
|
248
|
+
else adoption.cleanup = result;
|
|
249
|
+
return adoption;
|
|
250
|
+
}
|
|
251
|
+
if (typeof result === "object" && result !== null && typeof result.then === "function") {
|
|
252
|
+
adoption.pending = true;
|
|
253
|
+
const settled = Promise.resolve(result).then(
|
|
254
|
+
(cleanup) => {
|
|
255
|
+
adoption.pending = false;
|
|
256
|
+
if (typeof cleanup === "function") {
|
|
257
|
+
if (adoption.disposed || adoption.controller.signal.aborted) cleanup();
|
|
258
|
+
else adoption.cleanup = cleanup;
|
|
259
|
+
}
|
|
260
|
+
if (!adoption.disposed) {
|
|
261
|
+
flushQueuedEvents(record);
|
|
262
|
+
completeBehavior(record);
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
(error) => {
|
|
266
|
+
adoption.pending = false;
|
|
267
|
+
if (adoption.disposed || record.controller.signal.aborted) return;
|
|
268
|
+
disposeAdoption(adoption);
|
|
269
|
+
failBehavior(record, error);
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
const cancelable = waitUntilReady(settled, adoption.controller.signal).then(() => void 0);
|
|
273
|
+
trackPending(record.root, cancelable);
|
|
274
|
+
}
|
|
275
|
+
return adoption;
|
|
276
|
+
}
|
|
277
|
+
function reconcileBehavior(record) {
|
|
278
|
+
if (record.status !== "active") return;
|
|
279
|
+
record.waitingRanges.clear();
|
|
280
|
+
for (const [element, adoption] of [...record.adoptions]) {
|
|
281
|
+
const range = contains(record.root, element) ? nearestRange(record.root, element) : void 0;
|
|
282
|
+
if (!contains(record.root, element) || !matchesTarget(record, element) || !rangeMatches(record, range) || range !== adoption.range || range?.status === "pending") {
|
|
283
|
+
disposeAdoption(adoption);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
let elements;
|
|
287
|
+
if (typeof record.entry.target === "string") {
|
|
288
|
+
elements = Array.from(record.root.container.querySelectorAll(record.entry.target));
|
|
289
|
+
if (record.root.container.matches(record.entry.target)) elements.unshift(record.root.container);
|
|
290
|
+
} else {
|
|
291
|
+
elements = contains(record.root, record.entry.target) ? [record.entry.target] : [];
|
|
292
|
+
}
|
|
293
|
+
for (const element of elements) {
|
|
294
|
+
const range = nearestRange(record.root, element);
|
|
295
|
+
if (!rangeMatches(record, range)) continue;
|
|
296
|
+
if (range?.status === "pending") {
|
|
297
|
+
record.waitingRanges.add(range);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
adoptElement(record, element, range);
|
|
301
|
+
}
|
|
302
|
+
record.initialScanComplete = true;
|
|
303
|
+
completeBehavior(record);
|
|
304
|
+
}
|
|
305
|
+
function refreshDocument(registry) {
|
|
306
|
+
for (const root of [...registry.roots.values()]) {
|
|
307
|
+
if (root.disposed) continue;
|
|
308
|
+
for (const record of [...root.behaviors]) reconcileBehavior(record);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function ensureObserver(root) {
|
|
312
|
+
if (root.observer !== null || root.disposed) return;
|
|
313
|
+
const Observer = root.document.defaultView?.MutationObserver ?? globalThis.MutationObserver;
|
|
314
|
+
if (Observer === void 0) return;
|
|
315
|
+
root.observer = new Observer(() => {
|
|
316
|
+
if (root.disposed) return;
|
|
317
|
+
for (const record of [...root.behaviors]) reconcileBehavior(record);
|
|
318
|
+
});
|
|
319
|
+
root.observer.observe(root.container, { attributes: true, childList: true, subtree: true });
|
|
320
|
+
}
|
|
321
|
+
function targetElement(event) {
|
|
322
|
+
const target = event.target;
|
|
323
|
+
if (!target || typeof target.nodeType !== "number") return null;
|
|
324
|
+
return target.nodeType === 1 ? target : target.parentElement ?? null;
|
|
325
|
+
}
|
|
326
|
+
function handleDelegatedEvent(root, event) {
|
|
327
|
+
if (root.disposed) return;
|
|
328
|
+
const target = targetElement(event);
|
|
329
|
+
if (target === null || !contains(root, target)) return;
|
|
330
|
+
for (const record of [...root.behaviors]) {
|
|
331
|
+
if (record.status === "disposed" || record.status === "failed" || !record.entry.events?.includes(event.type)) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
let matched = target;
|
|
335
|
+
while (matched !== null && contains(root, matched) && !matchesTarget(record, matched)) {
|
|
336
|
+
if (matched === root.container) {
|
|
337
|
+
matched = null;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
matched = matched.parentElement;
|
|
341
|
+
}
|
|
342
|
+
if (matched === null || !contains(root, matched)) continue;
|
|
343
|
+
const range = nearestRange(root, matched);
|
|
344
|
+
if (!rangeMatches(record, range)) continue;
|
|
345
|
+
if (record.status !== "active" || range?.status === "pending") {
|
|
346
|
+
record.queuedEvents.push({ event, element: matched, range });
|
|
347
|
+
if (range?.status === "pending") record.waitingRanges.add(range);
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const adoption = record.adoptions.get(matched) ?? adoptElement(record, matched, range, event);
|
|
351
|
+
if (adoption === void 0 || adoption.pending || record.queuedEvents.length !== 0) {
|
|
352
|
+
record.queuedEvents.push({ event, element: matched, range });
|
|
353
|
+
flushQueuedEvents(record);
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
record.entry.handleEvent?.(event, matched, adoptionContext(adoption, event));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function installListeners(root, events) {
|
|
360
|
+
if (events === void 0) return;
|
|
361
|
+
for (const event of new Set(events)) {
|
|
362
|
+
if (typeof event !== "string" || event.length === 0) {
|
|
363
|
+
throw new Error("Behavior event names must be non-empty strings.");
|
|
364
|
+
}
|
|
365
|
+
if (root.listeners.has(event)) continue;
|
|
366
|
+
const listener = (nativeEvent) => handleDelegatedEvent(root, nativeEvent);
|
|
367
|
+
root.listeners.set(event, listener);
|
|
368
|
+
root.container.addEventListener(event, listener, true);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function removeUnusedListeners(root) {
|
|
372
|
+
for (const [event, listener] of root.listeners) {
|
|
373
|
+
let used = false;
|
|
374
|
+
for (const record of root.behaviors) {
|
|
375
|
+
if (record.entry.events?.includes(event)) {
|
|
376
|
+
used = true;
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (used) continue;
|
|
381
|
+
root.container.removeEventListener(event, listener, true);
|
|
382
|
+
root.listeners.delete(event);
|
|
383
|
+
}
|
|
384
|
+
if (root.behaviors.size === 0) {
|
|
385
|
+
root.observer?.disconnect();
|
|
386
|
+
root.observer = null;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function disposeBehavior(record) {
|
|
390
|
+
if (record.status === "disposed") return;
|
|
391
|
+
const failed = record.status === "failed";
|
|
392
|
+
record.status = "disposed";
|
|
393
|
+
record.controller.abort();
|
|
394
|
+
for (const unlink of record.unlinks) unlink();
|
|
395
|
+
record.unlinks.length = 0;
|
|
396
|
+
record.root.behaviors.delete(record);
|
|
397
|
+
if (record.entry.id !== void 0 && record.root.behaviorsById.get(record.entry.id) === record) {
|
|
398
|
+
record.root.behaviorsById.delete(record.entry.id);
|
|
399
|
+
}
|
|
400
|
+
record.queuedEvents.length = 0;
|
|
401
|
+
record.waitingRanges.clear();
|
|
402
|
+
let firstError;
|
|
403
|
+
for (const adoption of [...record.adoptions.values()]) {
|
|
404
|
+
try {
|
|
405
|
+
disposeAdoption(adoption);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
firstError ??= error;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (!failed) record.readiness.resolve();
|
|
411
|
+
removeUnusedListeners(record.root);
|
|
412
|
+
if (firstError !== void 0) throw firstError;
|
|
413
|
+
}
|
|
414
|
+
function activateBehavior(record) {
|
|
415
|
+
if (record.status !== "pending" || record.controller.signal.aborted) return;
|
|
416
|
+
record.status = "active";
|
|
417
|
+
reconcileBehavior(record);
|
|
418
|
+
}
|
|
419
|
+
function registerBehavior(root, entry) {
|
|
420
|
+
assertActiveRoot(root);
|
|
421
|
+
if (entry === null || typeof entry !== "object" || typeof entry.adopt !== "function") {
|
|
422
|
+
throw new Error("A behavior entry requires an adopt(element, context) function.");
|
|
423
|
+
}
|
|
424
|
+
if (typeof entry.target !== "string") {
|
|
425
|
+
assertContainedElement(root, entry.target, "A behavior target");
|
|
426
|
+
} else {
|
|
427
|
+
root.container.matches(entry.target);
|
|
428
|
+
}
|
|
429
|
+
if (entry.id !== void 0 && root.behaviorsById.has(entry.id)) {
|
|
430
|
+
throw new Error(`A behavior with identity ${JSON.stringify(entry.id)} is already registered.`);
|
|
431
|
+
}
|
|
432
|
+
const dependencies = [];
|
|
433
|
+
for (const id of entry.dependencies ?? []) {
|
|
434
|
+
const dependency = root.behaviorsById.get(id);
|
|
435
|
+
if (dependency === void 0) {
|
|
436
|
+
throw new Error(`Behavior dependency ${JSON.stringify(id)} is not registered.`);
|
|
437
|
+
}
|
|
438
|
+
dependencies.push(dependency);
|
|
439
|
+
}
|
|
440
|
+
for (const existing of root.behaviors) {
|
|
441
|
+
if (entry.id !== void 0 && existing.entry.conflicts?.includes(entry.id) || existing.entry.id !== void 0 && entry.conflicts?.includes(existing.entry.id)) {
|
|
442
|
+
throw new Error("The requested behavior conflicts with an existing behavior registration.");
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
const controller = createController(root.document);
|
|
446
|
+
const readiness = createReadiness();
|
|
447
|
+
const record = {
|
|
448
|
+
root,
|
|
449
|
+
entry,
|
|
450
|
+
controller,
|
|
451
|
+
readiness,
|
|
452
|
+
status: "pending",
|
|
453
|
+
adoptions: /* @__PURE__ */ new Map(),
|
|
454
|
+
waitingRanges: /* @__PURE__ */ new Set(),
|
|
455
|
+
queuedEvents: [],
|
|
456
|
+
unlinks: [linkSignal(root.controller.signal, controller)],
|
|
457
|
+
initialScanComplete: false
|
|
458
|
+
};
|
|
459
|
+
const registration = {
|
|
460
|
+
...entry.id === void 0 ? {} : { id: entry.id },
|
|
461
|
+
signal: controller.signal,
|
|
462
|
+
ready: readiness.promise,
|
|
463
|
+
dispose: () => disposeBehavior(record)
|
|
464
|
+
};
|
|
465
|
+
if (entry.signal !== void 0) record.unlinks.push(linkSignal(entry.signal, controller));
|
|
466
|
+
if (controller.signal.aborted) {
|
|
467
|
+
disposeBehavior(record);
|
|
468
|
+
return registration;
|
|
469
|
+
}
|
|
470
|
+
root.behaviors.add(record);
|
|
471
|
+
if (entry.id !== void 0) root.behaviorsById.set(entry.id, record);
|
|
472
|
+
controller.signal.addEventListener("abort", () => disposeBehavior(record), { once: true });
|
|
473
|
+
try {
|
|
474
|
+
installListeners(root, entry.events);
|
|
475
|
+
ensureObserver(root);
|
|
476
|
+
} catch (error) {
|
|
477
|
+
disposeBehavior(record);
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
const blockers = [];
|
|
481
|
+
if (entry.ready !== void 0) blockers.push(entry.ready);
|
|
482
|
+
for (const dependency of dependencies) {
|
|
483
|
+
if (!dependency.readiness.settled) blockers.push(dependency.readiness.promise);
|
|
484
|
+
}
|
|
485
|
+
if (blockers.length === 0) {
|
|
486
|
+
activateBehavior(record);
|
|
487
|
+
} else {
|
|
488
|
+
const gate = Promise.all(
|
|
489
|
+
blockers.map((blocker) => waitUntilReady(blocker, controller.signal))
|
|
490
|
+
).then(
|
|
491
|
+
(results) => {
|
|
492
|
+
if (results.includes(CANCELED) || controller.signal.aborted) return;
|
|
493
|
+
activateBehavior(record);
|
|
494
|
+
},
|
|
495
|
+
(error) => {
|
|
496
|
+
if (!controller.signal.aborted) failBehavior(record, error);
|
|
497
|
+
}
|
|
498
|
+
);
|
|
499
|
+
trackPending(root, gate);
|
|
500
|
+
}
|
|
501
|
+
return registration;
|
|
502
|
+
}
|
|
503
|
+
function disposeRange(record) {
|
|
504
|
+
if (record.status === "disposed") return;
|
|
505
|
+
const failed = record.status === "failed";
|
|
506
|
+
record.status = "disposed";
|
|
507
|
+
record.controller.abort();
|
|
508
|
+
for (const unlink of record.unlinks) unlink();
|
|
509
|
+
record.unlinks.length = 0;
|
|
510
|
+
record.root.ranges.delete(record);
|
|
511
|
+
if (record.root.registry.ranges.get(record.element) === record) {
|
|
512
|
+
record.root.registry.ranges.delete(record.element);
|
|
513
|
+
}
|
|
514
|
+
if (!failed) record.readiness.resolve();
|
|
515
|
+
if (!record.root.disposed) refreshDocument(record.root.registry);
|
|
516
|
+
}
|
|
517
|
+
function registerExternalRange(root, element, options) {
|
|
518
|
+
assertActiveRoot(root);
|
|
519
|
+
assertContainedElement(root, element, "An externally owned range");
|
|
520
|
+
if (options === null || typeof options !== "object" || !("owner" in options)) {
|
|
521
|
+
throw new Error("An external range requires an explicit owner identity.");
|
|
522
|
+
}
|
|
523
|
+
const existing = root.registry.ranges.get(element);
|
|
524
|
+
if (existing !== void 0) {
|
|
525
|
+
if (existing.root === root && Object.is(existing.owner, options.owner) && !options.replace) {
|
|
526
|
+
return existing.publicRange;
|
|
527
|
+
}
|
|
528
|
+
if (!options.replace) {
|
|
529
|
+
throw new Error("External ownership conflict: pass replace: true to hand this range off.");
|
|
530
|
+
}
|
|
531
|
+
if (!options.signal?.aborted) disposeRange(existing);
|
|
532
|
+
}
|
|
533
|
+
const controller = createController(root.document);
|
|
534
|
+
const readiness = createReadiness();
|
|
535
|
+
const record = {
|
|
536
|
+
root,
|
|
537
|
+
element,
|
|
538
|
+
owner: options.owner,
|
|
539
|
+
controller,
|
|
540
|
+
readiness,
|
|
541
|
+
status: options.ready === void 0 ? "ready" : "pending",
|
|
542
|
+
unlinks: [linkSignal(root.controller.signal, controller)],
|
|
543
|
+
publicRange: void 0
|
|
544
|
+
};
|
|
545
|
+
const range = {
|
|
546
|
+
element,
|
|
547
|
+
owner: options.owner,
|
|
548
|
+
signal: controller.signal,
|
|
549
|
+
ready: readiness.promise,
|
|
550
|
+
dispose: () => disposeRange(record)
|
|
551
|
+
};
|
|
552
|
+
record.publicRange = range;
|
|
553
|
+
if (options.signal !== void 0) record.unlinks.push(linkSignal(options.signal, controller));
|
|
554
|
+
if (controller.signal.aborted) {
|
|
555
|
+
disposeRange(record);
|
|
556
|
+
return range;
|
|
557
|
+
}
|
|
558
|
+
root.ranges.add(record);
|
|
559
|
+
root.registry.ranges.set(element, record);
|
|
560
|
+
controller.signal.addEventListener("abort", () => disposeRange(record), { once: true });
|
|
561
|
+
refreshDocument(root.registry);
|
|
562
|
+
if (options.ready === void 0) {
|
|
563
|
+
readiness.resolve();
|
|
564
|
+
} else {
|
|
565
|
+
const gate = waitUntilReady(options.ready, controller.signal).then(
|
|
566
|
+
(result) => {
|
|
567
|
+
if (result === CANCELED || record.status !== "pending") return;
|
|
568
|
+
record.status = "ready";
|
|
569
|
+
refreshDocument(root.registry);
|
|
570
|
+
readiness.resolve();
|
|
571
|
+
},
|
|
572
|
+
(error) => {
|
|
573
|
+
if (controller.signal.aborted || record.status !== "pending") return;
|
|
574
|
+
try {
|
|
575
|
+
for (const candidateRoot of [...root.registry.roots.values()]) {
|
|
576
|
+
for (const behavior of [...candidateRoot.behaviors]) {
|
|
577
|
+
if (!dependsOnRange(behavior, record)) continue;
|
|
578
|
+
try {
|
|
579
|
+
failBehavior(behavior, error);
|
|
580
|
+
} catch {
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
} finally {
|
|
585
|
+
record.status = "failed";
|
|
586
|
+
readiness.reject(error);
|
|
587
|
+
try {
|
|
588
|
+
disposeRange(record);
|
|
589
|
+
} catch {
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
trackPending(root, gate);
|
|
595
|
+
}
|
|
596
|
+
return range;
|
|
597
|
+
}
|
|
598
|
+
function disposeRoot(root, options = {}) {
|
|
599
|
+
if (root.disposed) return;
|
|
600
|
+
const releasedExternalOwnership = root.ranges.size !== 0;
|
|
601
|
+
root.disposed = true;
|
|
602
|
+
root.controller.abort();
|
|
603
|
+
root.unlinkSignal?.();
|
|
604
|
+
root.unlinkSignal = null;
|
|
605
|
+
root.observer?.disconnect();
|
|
606
|
+
root.observer = null;
|
|
607
|
+
let firstError;
|
|
608
|
+
for (const behavior of [...root.behaviors]) {
|
|
609
|
+
try {
|
|
610
|
+
disposeBehavior(behavior);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
firstError ??= error;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
for (const range of [...root.ranges]) {
|
|
616
|
+
try {
|
|
617
|
+
disposeRange(range);
|
|
618
|
+
} catch (error) {
|
|
619
|
+
firstError ??= error;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
for (const [event, listener] of root.listeners) {
|
|
623
|
+
root.container.removeEventListener(event, listener, true);
|
|
624
|
+
}
|
|
625
|
+
root.listeners.clear();
|
|
626
|
+
if (root.registry.roots.get(root.container) === root) {
|
|
627
|
+
root.registry.roots.delete(root.container);
|
|
628
|
+
}
|
|
629
|
+
if (root.registry.roots.size === 0 && root.registry.ranges.size === 0) {
|
|
630
|
+
documentRegistries.delete(root.document);
|
|
631
|
+
}
|
|
632
|
+
if (options.preserveDOM === false) root.container.replaceChildren();
|
|
633
|
+
if (releasedExternalOwnership && root.registry.roots.size !== 0) {
|
|
634
|
+
try {
|
|
635
|
+
refreshDocument(root.registry);
|
|
636
|
+
} catch (error) {
|
|
637
|
+
firstError ??= error;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (firstError !== void 0) throw firstError;
|
|
641
|
+
}
|
|
642
|
+
function attachBehaviorRoot(container, options = {}) {
|
|
643
|
+
if (!isElement(container) || container.ownerDocument === null) {
|
|
644
|
+
throw new Error("A behavior root requires an element with an owner document.");
|
|
645
|
+
}
|
|
646
|
+
const document = container.ownerDocument;
|
|
647
|
+
let registry = documentRegistries.get(document);
|
|
648
|
+
if (registry === void 0) {
|
|
649
|
+
registry = { roots: /* @__PURE__ */ new Map(), ranges: /* @__PURE__ */ new Map() };
|
|
650
|
+
documentRegistries.set(document, registry);
|
|
651
|
+
}
|
|
652
|
+
const existing = registry.roots.get(container);
|
|
653
|
+
const canceledReplacement = existing !== void 0 && options.replace && options.signal?.aborted;
|
|
654
|
+
if (existing !== void 0) {
|
|
655
|
+
if (!options.replace) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
"This container already has a behavior root; pass replace: true to replace it."
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
if (!canceledReplacement) {
|
|
661
|
+
disposeRoot(existing);
|
|
662
|
+
registry = documentRegistries.get(document);
|
|
663
|
+
if (registry === void 0) {
|
|
664
|
+
registry = { roots: /* @__PURE__ */ new Map(), ranges: /* @__PURE__ */ new Map() };
|
|
665
|
+
documentRegistries.set(document, registry);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
const controller = createController(document);
|
|
670
|
+
const record = {
|
|
671
|
+
container,
|
|
672
|
+
document,
|
|
673
|
+
registry,
|
|
674
|
+
controller,
|
|
675
|
+
behaviors: /* @__PURE__ */ new Set(),
|
|
676
|
+
behaviorsById: /* @__PURE__ */ new Map(),
|
|
677
|
+
ranges: /* @__PURE__ */ new Set(),
|
|
678
|
+
pending: /* @__PURE__ */ new Set(),
|
|
679
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
680
|
+
observer: null,
|
|
681
|
+
disposed: false,
|
|
682
|
+
unlinkSignal: null
|
|
683
|
+
};
|
|
684
|
+
const root = {
|
|
685
|
+
container,
|
|
686
|
+
signal: controller.signal,
|
|
687
|
+
get ready() {
|
|
688
|
+
const waiting = [...record.pending];
|
|
689
|
+
for (const range of record.ranges) waiting.push(range.readiness.promise);
|
|
690
|
+
for (const behavior of record.behaviors) waiting.push(behavior.readiness.promise);
|
|
691
|
+
const ready = Promise.all(waiting).then(() => void 0);
|
|
692
|
+
void ready.catch(() => void 0);
|
|
693
|
+
return ready;
|
|
694
|
+
},
|
|
695
|
+
registerExternalRange: (element, rangeOptions) => registerExternalRange(record, element, rangeOptions),
|
|
696
|
+
registerBehavior: (entry) => registerBehavior(record, entry),
|
|
697
|
+
dispose: (disposeOptions) => disposeRoot(record, disposeOptions)
|
|
698
|
+
};
|
|
699
|
+
if (!canceledReplacement) registry.roots.set(container, record);
|
|
700
|
+
if (options.signal !== void 0) record.unlinkSignal = linkSignal(options.signal, controller);
|
|
701
|
+
if (controller.signal.aborted) {
|
|
702
|
+
disposeRoot(record);
|
|
703
|
+
} else {
|
|
704
|
+
controller.signal.addEventListener("abort", () => disposeRoot(record), { once: true });
|
|
705
|
+
}
|
|
706
|
+
return root;
|
|
707
|
+
}
|
|
708
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
709
|
+
0 && (module.exports = {
|
|
710
|
+
attachBehaviorRoot
|
|
711
|
+
});
|