@zenithbuild/runtime 0.7.4 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/RUNTIME_CONTRACT.md +8 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/presence.d.ts +67 -0
- package/dist/presence.js +297 -0
- package/dist/template.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ It does not define a public virtual-DOM framework API.
|
|
|
23
23
|
- **Fine-Grained Reactivity**: signal/state/effect primitives used by emitted code.
|
|
24
24
|
- **Hydration**: deterministic client-side hydration for server-rendered HTML.
|
|
25
25
|
- **Lifecycle Cleanup**: explicit mount/effect cleanup semantics.
|
|
26
|
+
- **Narrow Presence Helper**: canonical `zenPresence(...)` plus optional `presence(...)` alias for ref-owned always-mounted nodes when app code explicitly imports the runtime package.
|
|
26
27
|
|
|
27
28
|
## Usage
|
|
28
29
|
This package is installed as an internal framework dependency. App code should normally use the public Zenith surface instead of importing `@zenithbuild/runtime` directly.
|
package/RUNTIME_CONTRACT.md
CHANGED
|
@@ -171,6 +171,7 @@ export { signal } // Create reactive signal
|
|
|
171
171
|
export { state } // Create deep reactive state proxy
|
|
172
172
|
export { zeneffect } // Canonical reactive effect subscription
|
|
173
173
|
export { zenMount } // Canonical component bootstrap lifecycle hook
|
|
174
|
+
export { zenPresence } // Explicit import for ref-owned always-mounted node presence
|
|
174
175
|
export { zenWindow } // Canonical SSR-safe global window access
|
|
175
176
|
export { zenDocument } // Canonical SSR-safe global document access
|
|
176
177
|
export { hydrate } // Mount page module into container
|
|
@@ -182,10 +183,17 @@ For developer convenience, the runtime also exports optional, standard-named ali
|
|
|
182
183
|
```js
|
|
183
184
|
export { effect } // Alias for zeneffect
|
|
184
185
|
export { mount } // Alias for zenMount
|
|
186
|
+
export { presence } // Alias for zenPresence
|
|
185
187
|
export { window } // Alias for zenWindow
|
|
186
188
|
export { document } // Alias for zenDocument
|
|
187
189
|
```
|
|
188
190
|
|
|
191
|
+
`zenPresence` is the canonical presence helper name. `presence` is an optional convenience alias only.
|
|
192
|
+
|
|
193
|
+
`zenPresence` is intentionally not a compiler-owned implicit global. It is a narrow runtime import used with `zenMount(...)` + `zeneffect(...)` for always-mounted nodes only.
|
|
194
|
+
|
|
195
|
+
Its options may include narrow node-local coordination such as `onPhaseChange`, but it does not widen into fragment retention, focus trapping, or a generalized accessibility framework.
|
|
196
|
+
|
|
189
197
|
---
|
|
190
198
|
|
|
191
199
|
## 9. Alignment Verification
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { signal } from "./signal.js";
|
|
|
2
2
|
export { state } from "./state.js";
|
|
3
3
|
export { hydrate } from "./hydrate.js";
|
|
4
4
|
export { effect, mount, zeneffect, zenEffect, zenMount } from "./zeneffect.js";
|
|
5
|
+
export { zenPresence, presence } from "./presence.js";
|
|
5
6
|
export { window, document, zenWindow, zenDocument } from "./env.js";
|
|
6
7
|
export { zenOn, zenResize, collectRefs } from "./platform.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { signal } from './signal.js';
|
|
2
2
|
export { state } from './state.js';
|
|
3
3
|
export { effect, mount, zeneffect, zenEffect, zenMount } from './zeneffect.js';
|
|
4
|
+
export { zenPresence, presence } from './presence.js';
|
|
4
5
|
export { hydrate } from './hydrate.js';
|
|
5
6
|
export { window, document, zenWindow, zenDocument } from './env.js';
|
|
6
7
|
export { zenOn, zenResize, collectRefs } from './platform.js';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ref-owned presence controller for always-mounted nodes.
|
|
3
|
+
*
|
|
4
|
+
* Canonical pattern:
|
|
5
|
+
* - create once per ref
|
|
6
|
+
* - call `presence.mount()` inside `zenMount`
|
|
7
|
+
* - drive `presence.setPresent(next)` from reactive state
|
|
8
|
+
*
|
|
9
|
+
* @template {Element} T
|
|
10
|
+
* @param {{ current?: T | null }} ref
|
|
11
|
+
* @param {{ timeoutMs?: number, onPhaseChange?: ((phase: ZenPresencePhase, context: { node: T | null, previousPhase: ZenPresencePhase | null, present: boolean }) => void) } | null | undefined} [options]
|
|
12
|
+
* @returns {{
|
|
13
|
+
* mount: () => () => void,
|
|
14
|
+
* destroy: () => void,
|
|
15
|
+
* getPhase: () => ZenPresencePhase,
|
|
16
|
+
* setPresent: (nextPresent: boolean) => void
|
|
17
|
+
* }}
|
|
18
|
+
*/
|
|
19
|
+
export function zenPresence<T extends Element>(ref: {
|
|
20
|
+
current?: T | null;
|
|
21
|
+
}, options?: {
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
onPhaseChange?: ((phase: ZenPresencePhase, context: {
|
|
24
|
+
node: T | null;
|
|
25
|
+
previousPhase: ZenPresencePhase | null;
|
|
26
|
+
present: boolean;
|
|
27
|
+
}) => void);
|
|
28
|
+
} | null | undefined): {
|
|
29
|
+
mount: () => () => void;
|
|
30
|
+
destroy: () => void;
|
|
31
|
+
getPhase: () => ZenPresencePhase;
|
|
32
|
+
setPresent: (nextPresent: boolean) => void;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Ref-owned presence controller for always-mounted nodes.
|
|
36
|
+
*
|
|
37
|
+
* Canonical pattern:
|
|
38
|
+
* - create once per ref
|
|
39
|
+
* - call `presence.mount()` inside `zenMount`
|
|
40
|
+
* - drive `presence.setPresent(next)` from reactive state
|
|
41
|
+
*
|
|
42
|
+
* @template {Element} T
|
|
43
|
+
* @param {{ current?: T | null }} ref
|
|
44
|
+
* @param {{ timeoutMs?: number, onPhaseChange?: ((phase: ZenPresencePhase, context: { node: T | null, previousPhase: ZenPresencePhase | null, present: boolean }) => void) } | null | undefined} [options]
|
|
45
|
+
* @returns {{
|
|
46
|
+
* mount: () => () => void,
|
|
47
|
+
* destroy: () => void,
|
|
48
|
+
* getPhase: () => ZenPresencePhase,
|
|
49
|
+
* setPresent: (nextPresent: boolean) => void
|
|
50
|
+
* }}
|
|
51
|
+
*/
|
|
52
|
+
export function presence<T extends Element>(ref: {
|
|
53
|
+
current?: T | null;
|
|
54
|
+
}, options?: {
|
|
55
|
+
timeoutMs?: number;
|
|
56
|
+
onPhaseChange?: ((phase: ZenPresencePhase, context: {
|
|
57
|
+
node: T | null;
|
|
58
|
+
previousPhase: ZenPresencePhase | null;
|
|
59
|
+
present: boolean;
|
|
60
|
+
}) => void);
|
|
61
|
+
} | null | undefined): {
|
|
62
|
+
mount: () => () => void;
|
|
63
|
+
destroy: () => void;
|
|
64
|
+
getPhase: () => ZenPresencePhase;
|
|
65
|
+
setPresent: (nextPresent: boolean) => void;
|
|
66
|
+
};
|
|
67
|
+
export type ZenPresencePhase = "hidden" | "entering" | "present" | "exiting";
|
package/dist/presence.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { zenOn } from './platform.js';
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {'hidden' | 'entering' | 'present' | 'exiting'} ZenPresencePhase
|
|
5
|
+
*/
|
|
6
|
+
function isRefLike(value) {
|
|
7
|
+
return !!value && typeof value === 'object' && 'current' in value;
|
|
8
|
+
}
|
|
9
|
+
function normalizeOptions(options) {
|
|
10
|
+
if (options === undefined || options === null) {
|
|
11
|
+
return {
|
|
12
|
+
timeoutMs: undefined,
|
|
13
|
+
onPhaseChange: null
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
17
|
+
throw new Error('[Zenith Runtime] zenPresence(ref, options) requires an options object when provided');
|
|
18
|
+
}
|
|
19
|
+
if (options.timeoutMs !== undefined) {
|
|
20
|
+
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0) {
|
|
21
|
+
throw new Error('[Zenith Runtime] zenPresence options.timeoutMs must be a non-negative number');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (options.onPhaseChange !== undefined && typeof options.onPhaseChange !== 'function') {
|
|
25
|
+
throw new Error('[Zenith Runtime] zenPresence options.onPhaseChange must be a function when provided');
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
timeoutMs: options.timeoutMs === undefined ? undefined : Math.floor(options.timeoutMs),
|
|
29
|
+
onPhaseChange: typeof options.onPhaseChange === 'function' ? options.onPhaseChange : null
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function parseCssTimeToken(token) {
|
|
33
|
+
const value = String(token || '').trim();
|
|
34
|
+
if (value.length === 0) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
if (value.endsWith('ms')) {
|
|
38
|
+
const ms = Number.parseFloat(value.slice(0, -2));
|
|
39
|
+
return Number.isFinite(ms) ? Math.max(0, ms) : 0;
|
|
40
|
+
}
|
|
41
|
+
if (value.endsWith('s')) {
|
|
42
|
+
const seconds = Number.parseFloat(value.slice(0, -1));
|
|
43
|
+
return Number.isFinite(seconds) ? Math.max(0, seconds * 1000) : 0;
|
|
44
|
+
}
|
|
45
|
+
const numeric = Number.parseFloat(value);
|
|
46
|
+
return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
|
|
47
|
+
}
|
|
48
|
+
function parseCssTimeList(value) {
|
|
49
|
+
return String(value || '')
|
|
50
|
+
.split(',')
|
|
51
|
+
.map((token) => parseCssTimeToken(token))
|
|
52
|
+
.filter((candidate) => Number.isFinite(candidate));
|
|
53
|
+
}
|
|
54
|
+
function computeMaxCssTotal(durations, delays) {
|
|
55
|
+
if (!Array.isArray(durations) || durations.length === 0) {
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
let maxTotal = 0;
|
|
59
|
+
for (let index = 0; index < durations.length; index += 1) {
|
|
60
|
+
const duration = durations[index] || 0;
|
|
61
|
+
const delay = Array.isArray(delays) && delays.length > 0
|
|
62
|
+
? delays[index % delays.length] || 0
|
|
63
|
+
: 0;
|
|
64
|
+
const total = duration + delay;
|
|
65
|
+
if (total > maxTotal) {
|
|
66
|
+
maxTotal = total;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return maxTotal;
|
|
70
|
+
}
|
|
71
|
+
function resolveFallbackTimeoutMs(node, explicitTimeoutMs) {
|
|
72
|
+
if (Number.isFinite(explicitTimeoutMs)) {
|
|
73
|
+
return explicitTimeoutMs;
|
|
74
|
+
}
|
|
75
|
+
const activeWindow = node?.ownerDocument?.defaultView;
|
|
76
|
+
if (!activeWindow || typeof activeWindow.getComputedStyle !== 'function') {
|
|
77
|
+
return 34;
|
|
78
|
+
}
|
|
79
|
+
const styles = activeWindow.getComputedStyle(node);
|
|
80
|
+
const transitionTotal = computeMaxCssTotal(parseCssTimeList(styles.transitionDuration), parseCssTimeList(styles.transitionDelay));
|
|
81
|
+
const animationTotal = computeMaxCssTotal(parseCssTimeList(styles.animationDuration), parseCssTimeList(styles.animationDelay));
|
|
82
|
+
const total = Math.max(transitionTotal, animationTotal);
|
|
83
|
+
return total > 0 ? Math.ceil(total + 34) : 34;
|
|
84
|
+
}
|
|
85
|
+
function getTimerApi(node) {
|
|
86
|
+
const activeWindow = node?.ownerDocument?.defaultView;
|
|
87
|
+
if (activeWindow && typeof activeWindow.setTimeout === 'function' && typeof activeWindow.clearTimeout === 'function') {
|
|
88
|
+
return {
|
|
89
|
+
setTimeout: activeWindow.setTimeout.bind(activeWindow),
|
|
90
|
+
clearTimeout: activeWindow.clearTimeout.bind(activeWindow)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
setTimeout: globalThis.setTimeout.bind(globalThis),
|
|
95
|
+
clearTimeout: globalThis.clearTimeout.bind(globalThis)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function isOwnedEvent(event, node) {
|
|
99
|
+
return !!event && event.target === node;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Ref-owned presence controller for always-mounted nodes.
|
|
103
|
+
*
|
|
104
|
+
* Canonical pattern:
|
|
105
|
+
* - create once per ref
|
|
106
|
+
* - call `presence.mount()` inside `zenMount`
|
|
107
|
+
* - drive `presence.setPresent(next)` from reactive state
|
|
108
|
+
*
|
|
109
|
+
* @template {Element} T
|
|
110
|
+
* @param {{ current?: T | null }} ref
|
|
111
|
+
* @param {{ timeoutMs?: number, onPhaseChange?: ((phase: ZenPresencePhase, context: { node: T | null, previousPhase: ZenPresencePhase | null, present: boolean }) => void) } | null | undefined} [options]
|
|
112
|
+
* @returns {{
|
|
113
|
+
* mount: () => () => void,
|
|
114
|
+
* destroy: () => void,
|
|
115
|
+
* getPhase: () => ZenPresencePhase,
|
|
116
|
+
* setPresent: (nextPresent: boolean) => void
|
|
117
|
+
* }}
|
|
118
|
+
*/
|
|
119
|
+
export function zenPresence(ref, options = null) {
|
|
120
|
+
if (!isRefLike(ref)) {
|
|
121
|
+
throw new Error('[Zenith Runtime] zenPresence(ref, options) requires a ref-like object with current');
|
|
122
|
+
}
|
|
123
|
+
const normalizedOptions = normalizeOptions(options);
|
|
124
|
+
let desiredPresent = false;
|
|
125
|
+
/** @type {ZenPresencePhase} */
|
|
126
|
+
let currentPhase = 'hidden';
|
|
127
|
+
let mounted = false;
|
|
128
|
+
let mountEpoch = 0;
|
|
129
|
+
let pendingCompletion = null;
|
|
130
|
+
function getNode() {
|
|
131
|
+
const candidate = ref.current;
|
|
132
|
+
if (!candidate || typeof candidate !== 'object' || typeof candidate.nodeType !== 'number') {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
return candidate;
|
|
136
|
+
}
|
|
137
|
+
function notifyPhaseChange(previousPhase) {
|
|
138
|
+
if (typeof normalizedOptions.onPhaseChange !== 'function') {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
normalizedOptions.onPhaseChange(currentPhase, {
|
|
142
|
+
node: getNode(),
|
|
143
|
+
previousPhase,
|
|
144
|
+
present: desiredPresent
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function applyPhaseToNode() {
|
|
148
|
+
const node = getNode();
|
|
149
|
+
if (!node) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
node.setAttribute('data-zen-presence', currentPhase);
|
|
153
|
+
}
|
|
154
|
+
function setPhase(nextPhase, forceApply = false) {
|
|
155
|
+
const previousPhase = currentPhase;
|
|
156
|
+
const changed = previousPhase !== nextPhase;
|
|
157
|
+
if (!changed && !forceApply) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
currentPhase = nextPhase;
|
|
161
|
+
applyPhaseToNode();
|
|
162
|
+
if (changed) {
|
|
163
|
+
notifyPhaseChange(previousPhase);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function cancelPendingCompletion() {
|
|
167
|
+
if (!pendingCompletion) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
pendingCompletion.cancel();
|
|
171
|
+
pendingCompletion = null;
|
|
172
|
+
}
|
|
173
|
+
function scheduleCompletion(targetPhase, node) {
|
|
174
|
+
cancelPendingCompletion();
|
|
175
|
+
if (!mounted || !node) {
|
|
176
|
+
setPhase(targetPhase);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const timerApi = getTimerApi(node);
|
|
180
|
+
const timeoutMs = resolveFallbackTimeoutMs(node, normalizedOptions.timeoutMs);
|
|
181
|
+
const disposers = [];
|
|
182
|
+
let settled = false;
|
|
183
|
+
let timeoutId = null;
|
|
184
|
+
const settle = () => {
|
|
185
|
+
if (settled) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
settled = true;
|
|
189
|
+
while (disposers.length > 0) {
|
|
190
|
+
const dispose = disposers.pop();
|
|
191
|
+
try {
|
|
192
|
+
dispose();
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (timeoutId !== null) {
|
|
198
|
+
timerApi.clearTimeout(timeoutId);
|
|
199
|
+
timeoutId = null;
|
|
200
|
+
}
|
|
201
|
+
pendingCompletion = null;
|
|
202
|
+
setPhase(targetPhase);
|
|
203
|
+
};
|
|
204
|
+
const handleEnd = (event) => {
|
|
205
|
+
if (!isOwnedEvent(event, node)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
settle();
|
|
209
|
+
};
|
|
210
|
+
disposers.push(zenOn(node, 'transitionend', handleEnd));
|
|
211
|
+
disposers.push(zenOn(node, 'animationend', handleEnd));
|
|
212
|
+
timeoutId = timerApi.setTimeout(settle, timeoutMs);
|
|
213
|
+
pendingCompletion = {
|
|
214
|
+
cancel() {
|
|
215
|
+
if (settled) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
settled = true;
|
|
219
|
+
while (disposers.length > 0) {
|
|
220
|
+
const dispose = disposers.pop();
|
|
221
|
+
try {
|
|
222
|
+
dispose();
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (timeoutId !== null) {
|
|
228
|
+
timerApi.clearTimeout(timeoutId);
|
|
229
|
+
timeoutId = null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function reconcile() {
|
|
235
|
+
if (!mounted) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const node = getNode();
|
|
239
|
+
if (!node) {
|
|
240
|
+
cancelPendingCompletion();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (desiredPresent) {
|
|
244
|
+
if (currentPhase === 'entering' || currentPhase === 'present') {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
setPhase('entering');
|
|
248
|
+
scheduleCompletion('present', node);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (currentPhase === 'hidden' || currentPhase === 'exiting') {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
setPhase('exiting');
|
|
255
|
+
scheduleCompletion('hidden', node);
|
|
256
|
+
}
|
|
257
|
+
function destroyCurrentMount() {
|
|
258
|
+
mounted = false;
|
|
259
|
+
cancelPendingCompletion();
|
|
260
|
+
currentPhase = 'hidden';
|
|
261
|
+
const node = getNode();
|
|
262
|
+
if (node) {
|
|
263
|
+
node.removeAttribute('data-zen-presence');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
mount() {
|
|
268
|
+
mountEpoch += 1;
|
|
269
|
+
const activeMount = mountEpoch;
|
|
270
|
+
mounted = true;
|
|
271
|
+
setPhase(currentPhase, true);
|
|
272
|
+
reconcile();
|
|
273
|
+
return () => {
|
|
274
|
+
if (activeMount !== mountEpoch) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
destroyCurrentMount();
|
|
278
|
+
};
|
|
279
|
+
},
|
|
280
|
+
destroy() {
|
|
281
|
+
mountEpoch += 1;
|
|
282
|
+
destroyCurrentMount();
|
|
283
|
+
},
|
|
284
|
+
getPhase() {
|
|
285
|
+
return currentPhase;
|
|
286
|
+
},
|
|
287
|
+
setPresent(nextPresent) {
|
|
288
|
+
desiredPresent = nextPresent === true;
|
|
289
|
+
reconcile();
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* @alias zenPresence
|
|
295
|
+
* @description Optional secondary alias for the canonical zenPresence helper.
|
|
296
|
+
*/
|
|
297
|
+
export const presence = zenPresence;
|
package/dist/template.js
CHANGED
|
@@ -20,7 +20,7 @@ function buildRuntimeModuleSource() {
|
|
|
20
20
|
const segments = [
|
|
21
21
|
'reactivity-core.js', 'side-effect-scope.js', 'effect-utils.js', 'effect-scheduler.js',
|
|
22
22
|
'effect-runtime.js', 'mount-runtime.js', 'zeneffect.js', 'ref.js', 'env.js',
|
|
23
|
-
'platform.js', 'signal.js', 'state.js',
|
|
23
|
+
'platform.js', 'presence.js', 'signal.js', 'state.js',
|
|
24
24
|
'diagnostics.js', 'cleanup.js', 'template-parser.js', 'markup.js', 'payload.js',
|
|
25
25
|
'expressions.js', 'render.js', 'fragment-patch.js', 'scanner.js', 'events.js', 'hydrate.js'
|
|
26
26
|
].map((fileName) => stripImports(readRuntimeSourceFile(fileName))).filter(Boolean);
|