@atolljs/islands 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +346 -0
- package/package.json +29 -0
- package/src/app.ts +81 -0
- package/src/callbackProps.ts +75 -0
- package/src/index.ts +40 -0
- package/src/island.ts +905 -0
- package/src/memory.ts +30 -0
- package/src/ops.ts +215 -0
- package/src/react-reconciler.d.ts +18 -0
- package/src/worker/defineWorkers.ts +666 -0
- package/src/worker/dom/css.ts +152 -0
- package/src/worker/dom/document.ts +589 -0
- package/src/worker/dom/element.ts +656 -0
- package/src/worker/dom/html.ts +107 -0
- package/src/worker/dom/node.ts +481 -0
- package/src/worker/dom/selectors.ts +108 -0
- package/src/worker/dom/window.ts +528 -0
- package/src/worker/hostConfig.ts +446 -0
- package/src/worker/index.ts +78 -0
- package/src/worker/instance.ts +317 -0
- package/src/worker/proxyDom.ts +28 -0
- package/src/worker/reactInstance.ts +74 -0
- package/src/worker/slot.tsx +18 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React-reconciler host adapter for the worker DOM backend.
|
|
3
|
+
*
|
|
4
|
+
* The generic instance state (op queues, instance ids, handler registry,
|
|
5
|
+
* doorbell, geometry) lives in `instance.ts`. This file only wires the
|
|
6
|
+
* reconciler's create/append/update/remove/commit hooks to that backend.
|
|
7
|
+
*
|
|
8
|
+
* react-reconciler@0.34 reads ~150 fields off the config object. Most are
|
|
9
|
+
* stubs for features this renderer doesn't implement (hydration,
|
|
10
|
+
* persistence, resources, singletons, view transitions, test selectors,
|
|
11
|
+
* scope/hydratable APIs) — they exist so nothing throws when the reconciler
|
|
12
|
+
* destructures them; they are never invoked behind the `supports*` flags.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createContext } from 'react';
|
|
16
|
+
import {
|
|
17
|
+
bumpOpsVersion,
|
|
18
|
+
getActiveInstance,
|
|
19
|
+
getLastActiveInstance,
|
|
20
|
+
instances,
|
|
21
|
+
pushOp,
|
|
22
|
+
serializeProps,
|
|
23
|
+
unregisterHandler,
|
|
24
|
+
type ElementInstance,
|
|
25
|
+
type HostInstance,
|
|
26
|
+
type RootContainer,
|
|
27
|
+
type TextInstance,
|
|
28
|
+
} from './instance';
|
|
29
|
+
import { newElement, newText } from './instance';
|
|
30
|
+
import { docForInstance, type ProxyNode } from './proxyDom';
|
|
31
|
+
|
|
32
|
+
/* ── Event-priority plumbing ────────────────────────────────────────────── */
|
|
33
|
+
/*
|
|
34
|
+
* React 19 expresses event priorities as lane numbers: 2 = discrete
|
|
35
|
+
* (click/keydown → SyncLane), 8 = continuous, 32 = default, 0 = none. The
|
|
36
|
+
* reconciler calls setCurrentUpdatePriority around its own flushes
|
|
37
|
+
* (flushSyncFromReconciler sets 2), so honoring the set/get pair and echoing
|
|
38
|
+
* the value back from resolveUpdatePriority is all that's needed.
|
|
39
|
+
*/
|
|
40
|
+
let currentUpdatePriority = 0;
|
|
41
|
+
const DEFAULT_EVENT_PRIORITY = 32;
|
|
42
|
+
|
|
43
|
+
/* ── React-19 transition context (must be real React objects) ───────────── */
|
|
44
|
+
|
|
45
|
+
const NotPendingTransition = Object.freeze({ pending: false, data: null, method: null, action: null });
|
|
46
|
+
const HostTransitionContext = createContext(NotPendingTransition);
|
|
47
|
+
|
|
48
|
+
const noop = (): void => {};
|
|
49
|
+
const NULL = (): null => null;
|
|
50
|
+
const FALSE = (): boolean => false;
|
|
51
|
+
const TRUE = (): boolean => true;
|
|
52
|
+
|
|
53
|
+
/* ── Refs & portals ───────────────────────────────────────────────────────
|
|
54
|
+
*
|
|
55
|
+
* React refs must receive an object the COMPONENT treats as "the element" —
|
|
56
|
+
* for React DOM that's the real DOM node, for us the closest truthful thing
|
|
57
|
+
* is the proxy DOM's facade (it navigates the shadow tree, mutates via ops,
|
|
58
|
+
* and reports `nodeType === 1`). getPublicInstance therefore adopts the
|
|
59
|
+
* host instance into a per-instance proxy document, created lazily so React
|
|
60
|
+
* mounts only pay for it when something actually holds a ref.
|
|
61
|
+
*
|
|
62
|
+
* This is what makes react-dom's `createPortal(children, ref.current)` work
|
|
63
|
+
* here: isValidContainer() only checks nodeType, the portal fiber then feeds
|
|
64
|
+
* the facade back as `containerInfo`, and the container-level methods below
|
|
65
|
+
* unwrap `.instance` so portal children land inside the real target node —
|
|
66
|
+
* that is the entire recharts <Tooltip>/<Legend> path.
|
|
67
|
+
*/
|
|
68
|
+
const publicInstanceFor = (instance: HostInstance): ProxyNode | HostInstance =>
|
|
69
|
+
docForInstance(instance.instance).adopt(instance);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Portal `containerInfo` is the public instance (a ProxyElement) the caller
|
|
73
|
+
* passed to createPortal; the ROOT_CONTAINER sentinel and raw instances keep
|
|
74
|
+
* their own `id`. Anything unrecognizable falls back to the island root.
|
|
75
|
+
*/
|
|
76
|
+
const containerParentId = (container: unknown): number => {
|
|
77
|
+
const inst = (container as { instance?: { id?: unknown } } | null)?.instance;
|
|
78
|
+
if (inst && typeof inst.id === 'number') return inst.id;
|
|
79
|
+
const id = (container as { id?: unknown } | null)?.id;
|
|
80
|
+
return typeof id === 'number' ? id : 0;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The instance a create should bind to — read off the root container for
|
|
85
|
+
* ordinary renders, off the portal container's wrapped instance for portal
|
|
86
|
+
* subtrees (a ProxyElement, whose `.instance` field doesn't exist but whose
|
|
87
|
+
* `.instance.instance` does), finally falling back to ambient instance state.
|
|
88
|
+
*/
|
|
89
|
+
const containerInstance = (container: unknown): string => {
|
|
90
|
+
// `.instance` is the instance KEY on a RootContainer/raw host record and
|
|
91
|
+
// the host RECORD on a ProxyElement (portal containers) — disambiguate
|
|
92
|
+
// by shape: a string IS the key; a record holds `.instance.instance`.
|
|
93
|
+
const inner = (container as { instance?: unknown } | null)?.instance;
|
|
94
|
+
if (typeof inner === 'string') return inner;
|
|
95
|
+
return (inner as { instance?: string } | undefined)?.instance ??
|
|
96
|
+
(getActiveInstance() !== '' ? getActiveInstance() : getLastActiveInstance());
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/* Host context = DOM namespace tracking, same role it plays in React DOM:
|
|
100
|
+
* `getChildHostContext` flips the namespace when the element type requires
|
|
101
|
+
* it, and `createInstance` stamps the result on the instance so the `create`
|
|
102
|
+
* op can tell the driver to createElementNS. Recharts-style SVG trees need
|
|
103
|
+
* this — without it every <svg>/<path> would arrive as an HTMLUnknownElement. */
|
|
104
|
+
interface HostContext {
|
|
105
|
+
ns?: string;
|
|
106
|
+
}
|
|
107
|
+
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
108
|
+
const MATH_NS = 'http://www.w3.org/1998/Math/MathML';
|
|
109
|
+
const HTML_CTX: HostContext = Object.freeze({});
|
|
110
|
+
const SVG_CTX: HostContext = Object.freeze({ ns: SVG_NS });
|
|
111
|
+
const MATH_CTX: HostContext = Object.freeze({ ns: MATH_NS });
|
|
112
|
+
|
|
113
|
+
/** The namespace context a host element gives its children — and the
|
|
114
|
+
* namespace the element itself belongs to (getChildNamespace semantics:
|
|
115
|
+
* <svg> in HTML is SVG, foreignObject/desc/title flip back to HTML). */
|
|
116
|
+
const childHostContextFor = (parent: HostContext, type: string): HostContext => {
|
|
117
|
+
if (type === 'svg') return SVG_CTX;
|
|
118
|
+
if (type === 'math') return MATH_CTX;
|
|
119
|
+
if (type === 'foreignObject' || type === 'desc' || type === 'title') return HTML_CTX;
|
|
120
|
+
return parent;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/* ── The host config ────────────────────────────────────────────────────── */
|
|
124
|
+
|
|
125
|
+
export const hostConfig = {
|
|
126
|
+
// Identity / capabilities
|
|
127
|
+
rendererVersion: '0.34.0',
|
|
128
|
+
rendererPackageName: '@atolljs/islands',
|
|
129
|
+
extraDevToolsConfig: null,
|
|
130
|
+
isPrimaryRenderer: true,
|
|
131
|
+
warnsIfNotActing: false,
|
|
132
|
+
supportsMutation: true,
|
|
133
|
+
supportsPersistence: false,
|
|
134
|
+
supportsHydration: false,
|
|
135
|
+
supportsResources: false,
|
|
136
|
+
supportsSingletons: false,
|
|
137
|
+
supportsMicrotasks: false,
|
|
138
|
+
supportsTestSelectors: false,
|
|
139
|
+
|
|
140
|
+
getPublicInstance: (instance: HostInstance): unknown => publicInstanceFor(instance),
|
|
141
|
+
// Host contexts must be non-null objects (the reconciler pushes them on a
|
|
142
|
+
// context stack and warns "Expected host context to exist" on null). This
|
|
143
|
+
// renderer carries no per-subtree context — echo a single frozen sentinel.
|
|
144
|
+
// Host contexts must be non-null objects (the reconciler warns on null).
|
|
145
|
+
// Ours carries only the element namespace: <svg>/<math> enter their
|
|
146
|
+
// namespaces; foreignObject/desc/title are HTML-integration points that
|
|
147
|
+
// flip children back to HTML; everything else inherits the parent's.
|
|
148
|
+
// For portals, this becomes the context the portal subtree renders under —
|
|
149
|
+
// derived from the container's own namespace so children of an SVG portal
|
|
150
|
+
// target (recharts zIndex <g> layers) stay in the SVG namespace.
|
|
151
|
+
getRootHostContext: (container: unknown): HostContext => {
|
|
152
|
+
const ns = (container as { instance?: { ns?: string } } | null)?.instance?.ns;
|
|
153
|
+
if (ns === SVG_NS) return SVG_CTX;
|
|
154
|
+
if (ns === MATH_NS) return MATH_CTX;
|
|
155
|
+
return HTML_CTX;
|
|
156
|
+
},
|
|
157
|
+
getChildHostContext: (parent: HostContext, type: string): HostContext =>
|
|
158
|
+
childHostContextFor(parent, type),
|
|
159
|
+
prepareForCommit: NULL,
|
|
160
|
+
// The doorbell: every commit bumps opsVersion once — the main thread's
|
|
161
|
+
// observe() wakes (Atomics.waitAsync) and flushes the op queue, so commits
|
|
162
|
+
// made outside task calls (effects, timers, async setState) arrive as a
|
|
163
|
+
// push instead of waiting on a poll. Task-returned ops bump too; the
|
|
164
|
+
// follow-up flush just finds an empty queue.
|
|
165
|
+
resetAfterCommit: bumpOpsVersion,
|
|
166
|
+
|
|
167
|
+
// Creation — emit ops
|
|
168
|
+
createInstance: (
|
|
169
|
+
type: string,
|
|
170
|
+
props: Record<string, unknown>,
|
|
171
|
+
rootContainer: unknown,
|
|
172
|
+
hostContext: unknown,
|
|
173
|
+
_internalHandle: unknown,
|
|
174
|
+
): ElementInstance => {
|
|
175
|
+
// The element's own namespace = the child context its TYPE produces
|
|
176
|
+
// under the parent's context — the same computation React DOM runs
|
|
177
|
+
// (getChildNamespace): <svg> in HTML is itself SVG, <foreignObject> in
|
|
178
|
+
// SVG is itself HTML. Instance comes from the container (see RootContainer).
|
|
179
|
+
const ctx = childHostContextFor(hostContext as HostContext, type);
|
|
180
|
+
const instance = newElement(type, props, ctx.ns, containerInstance(rootContainer));
|
|
181
|
+
pushOp(instance.instance, {
|
|
182
|
+
t: 'create',
|
|
183
|
+
id: instance.id,
|
|
184
|
+
type,
|
|
185
|
+
props: instance.props,
|
|
186
|
+
ns: instance.ns,
|
|
187
|
+
});
|
|
188
|
+
return instance;
|
|
189
|
+
},
|
|
190
|
+
createTextInstance: (
|
|
191
|
+
text: string,
|
|
192
|
+
rootContainer: unknown,
|
|
193
|
+
_hostContext: unknown,
|
|
194
|
+
_internalHandle: unknown,
|
|
195
|
+
): TextInstance => {
|
|
196
|
+
const instance = newText(text, containerInstance(rootContainer));
|
|
197
|
+
pushOp(instance.instance, { t: 'text', id: instance.id, text });
|
|
198
|
+
return instance;
|
|
199
|
+
},
|
|
200
|
+
finalizeInitialChildren: FALSE,
|
|
201
|
+
// Always false: string/number children become real text instances, so the
|
|
202
|
+
// tree arrives as linear ops and `utext` handles every text update. (The
|
|
203
|
+
// `true` path would expect commitUpdate to set textContent from
|
|
204
|
+
// props.children — which we deliberately never serialize.)
|
|
205
|
+
shouldSetTextContent: FALSE,
|
|
206
|
+
|
|
207
|
+
// Tree wiring — emit ops
|
|
208
|
+
appendInitialChild: (parent: HostInstance, child: HostInstance): void => {
|
|
209
|
+
pushOp(parent.instance, { t: 'append', parent: parent.id, child: child.id });
|
|
210
|
+
},
|
|
211
|
+
appendChild: (parent: HostInstance, child: HostInstance): void => {
|
|
212
|
+
pushOp(parent.instance, { t: 'append', parent: parent.id, child: child.id });
|
|
213
|
+
},
|
|
214
|
+
appendChildToContainer: (container: unknown, child: HostInstance): void => {
|
|
215
|
+
pushOp(child.instance, { t: 'append', parent: containerParentId(container), child: child.id });
|
|
216
|
+
},
|
|
217
|
+
insertBefore: (parent: HostInstance, child: HostInstance, before: HostInstance): void => {
|
|
218
|
+
pushOp(parent.instance, { t: 'append', parent: parent.id, child: child.id, before: before.id });
|
|
219
|
+
},
|
|
220
|
+
insertInContainerBefore: (container: unknown, child: HostInstance, before: HostInstance): void => {
|
|
221
|
+
pushOp(child.instance, {
|
|
222
|
+
t: 'append',
|
|
223
|
+
parent: containerParentId(container),
|
|
224
|
+
child: child.id,
|
|
225
|
+
before: before.id,
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
removeChild: (_parent: HostInstance, child: HostInstance): void => {
|
|
229
|
+
pushOp(child.instance, { t: 'remove', child: child.id });
|
|
230
|
+
},
|
|
231
|
+
removeChildFromContainer: (_container: unknown, child: HostInstance): void => {
|
|
232
|
+
pushOp(child.instance, { t: 'remove', child: child.id });
|
|
233
|
+
},
|
|
234
|
+
// No instance argument — routed by the task's active instance (only reached
|
|
235
|
+
// inside mount/remount's syncCommit).
|
|
236
|
+
clearContainer: (): void => {
|
|
237
|
+
pushOp(getActiveInstance(), { t: 'clear' });
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
// Updates — emit ops
|
|
241
|
+
commitUpdate: (
|
|
242
|
+
instance: ElementInstance,
|
|
243
|
+
_type: string,
|
|
244
|
+
_oldProps: Record<string, unknown>,
|
|
245
|
+
newProps: Record<string, unknown>,
|
|
246
|
+
_internalHandle: unknown,
|
|
247
|
+
): void => {
|
|
248
|
+
// Serialize first so the op carries the latest props; re-serialization
|
|
249
|
+
// also re-registers event handlers against the current closure.
|
|
250
|
+
instance.props = serializeProps(instance, newProps);
|
|
251
|
+
pushOp(instance.instance, { t: 'update', id: instance.id, props: instance.props });
|
|
252
|
+
},
|
|
253
|
+
commitTextUpdate: (instance: TextInstance, _oldText: string, newText: string): void => {
|
|
254
|
+
instance.text = newText;
|
|
255
|
+
pushOp(instance.instance, { t: 'utext', id: instance.id, text: newText });
|
|
256
|
+
},
|
|
257
|
+
commitMount: noop,
|
|
258
|
+
// Unreachable while shouldSetTextContent is always false; still emit the
|
|
259
|
+
// spec'd op for completeness.
|
|
260
|
+
resetTextContent: (instance: ElementInstance): void => {
|
|
261
|
+
instance.props = {};
|
|
262
|
+
pushOp(instance.instance, { t: 'update', id: instance.id, props: {} });
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
// Suspense visibility — `hidden` is a global HTML attribute the main
|
|
266
|
+
// thread applies like any other prop.
|
|
267
|
+
hideInstance: (instance: ElementInstance): void => {
|
|
268
|
+
pushOp(instance.instance, { t: 'update', id: instance.id, props: { ...instance.props, hidden: true } });
|
|
269
|
+
},
|
|
270
|
+
unhideInstance: (instance: ElementInstance): void => {
|
|
271
|
+
pushOp(instance.instance, { t: 'update', id: instance.id, props: { ...instance.props } });
|
|
272
|
+
},
|
|
273
|
+
hideTextInstance: (instance: TextInstance): void => {
|
|
274
|
+
pushOp(instance.instance, { t: 'utext', id: instance.id, text: '' });
|
|
275
|
+
},
|
|
276
|
+
unhideTextInstance: (instance: TextInstance, text: string): void => {
|
|
277
|
+
pushOp(instance.instance, { t: 'utext', id: instance.id, text });
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
// GC hook — drop the record and its handler slots.
|
|
281
|
+
detachDeletedInstance: (instance: HostInstance): void => {
|
|
282
|
+
instances.delete(instance.id);
|
|
283
|
+
if (instance.kind === 'element') {
|
|
284
|
+
for (const hid of Object.values(instance.listenerSlots)) unregisterHandler(hid);
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
// Scheduler
|
|
289
|
+
scheduleTimeout: setTimeout,
|
|
290
|
+
cancelTimeout: clearTimeout,
|
|
291
|
+
noTimeout: -1,
|
|
292
|
+
// supportsMicrotasks is false, so the reconciler schedules root work via
|
|
293
|
+
// the `scheduler` package (MessageChannel in a worker). This export is
|
|
294
|
+
// still destructured — provide a real one for completeness.
|
|
295
|
+
scheduleMicrotask: (fn: () => void): void => queueMicrotask(fn),
|
|
296
|
+
|
|
297
|
+
// Event priorities (see note above — values are lane numbers).
|
|
298
|
+
setCurrentUpdatePriority: (p: number): void => {
|
|
299
|
+
currentUpdatePriority = p;
|
|
300
|
+
},
|
|
301
|
+
getCurrentUpdatePriority: (): number => currentUpdatePriority,
|
|
302
|
+
resolveUpdatePriority: (): number =>
|
|
303
|
+
currentUpdatePriority !== 0 ? currentUpdatePriority : DEFAULT_EVENT_PRIORITY,
|
|
304
|
+
resolveEventType: NULL,
|
|
305
|
+
resolveEventTimeStamp: (): number => -1.1,
|
|
306
|
+
trackSchedulerEvent: noop,
|
|
307
|
+
shouldAttemptEagerTransition: FALSE,
|
|
308
|
+
|
|
309
|
+
// Events/portals/scopes — no DOM event system exists worker-side.
|
|
310
|
+
getInstanceFromNode: NULL,
|
|
311
|
+
beforeActiveInstanceBlur: noop,
|
|
312
|
+
afterActiveInstanceBlur: noop,
|
|
313
|
+
preparePortalMount: noop,
|
|
314
|
+
prepareScopeUpdate: noop,
|
|
315
|
+
getInstanceFromScope: NULL,
|
|
316
|
+
|
|
317
|
+
// React 19 "suspend on commit" — never suspend.
|
|
318
|
+
requestPostPaintCallback: noop,
|
|
319
|
+
maySuspendCommit: FALSE,
|
|
320
|
+
maySuspendCommitOnUpdate: FALSE,
|
|
321
|
+
maySuspendCommitInSyncRender: FALSE,
|
|
322
|
+
preloadInstance: TRUE,
|
|
323
|
+
startSuspendingCommit: noop,
|
|
324
|
+
suspendInstance: noop,
|
|
325
|
+
suspendOnActiveViewTransition: noop,
|
|
326
|
+
waitForCommitToBeReady: NULL,
|
|
327
|
+
getSuspendedCommitReason: () => 0,
|
|
328
|
+
|
|
329
|
+
// Transitions / forms / console
|
|
330
|
+
NotPendingTransition,
|
|
331
|
+
HostTransitionContext,
|
|
332
|
+
resetFormInstance: noop,
|
|
333
|
+
bindToConsole: (methodName: string, args: unknown[]) =>
|
|
334
|
+
(console as unknown as Record<string, (...a: unknown[]) => void>)[methodName]?.bind(console, ...args) ??
|
|
335
|
+
noop,
|
|
336
|
+
|
|
337
|
+
// Persistence (supportsPersistence: false — destructured, never called)
|
|
338
|
+
createContainerChildSet: () => [],
|
|
339
|
+
appendChildToContainerChildSet: noop,
|
|
340
|
+
finalizeContainerChildren: noop,
|
|
341
|
+
replaceContainerChildren: noop,
|
|
342
|
+
cloneInstance: NULL,
|
|
343
|
+
cloneMutableInstance: (instance: HostInstance) => instance,
|
|
344
|
+
cloneMutableTextInstance: (instance: HostInstance) => instance,
|
|
345
|
+
cloneHiddenInstance: (instance: HostInstance) => instance,
|
|
346
|
+
cloneHiddenTextInstance: (instance: HostInstance) => instance,
|
|
347
|
+
|
|
348
|
+
// Fragment instances (only used for `<Fragment ref={…}>` — unimplemented)
|
|
349
|
+
createFragmentInstance: () => ({}),
|
|
350
|
+
updateFragmentInstanceFiber: noop,
|
|
351
|
+
commitNewChildToFragmentInstance: noop,
|
|
352
|
+
deleteChildFromFragmentInstance: noop,
|
|
353
|
+
|
|
354
|
+
// View transitions (React 19) — all stubs
|
|
355
|
+
createViewTransitionInstance: (name: string) => ({ name, autoName: null }),
|
|
356
|
+
applyViewTransitionName: noop,
|
|
357
|
+
restoreViewTransitionName: noop,
|
|
358
|
+
cancelViewTransitionName: noop,
|
|
359
|
+
cancelRootViewTransitionName: noop,
|
|
360
|
+
restoreRootViewTransitionName: noop,
|
|
361
|
+
cloneRootViewTransitionContainer: noop,
|
|
362
|
+
removeRootViewTransitionClone: noop,
|
|
363
|
+
measureInstance: NULL,
|
|
364
|
+
measureClonedInstance: NULL,
|
|
365
|
+
wasInstanceInViewport: FALSE,
|
|
366
|
+
hasInstanceChanged: FALSE,
|
|
367
|
+
hasInstanceAffectedParent: FALSE,
|
|
368
|
+
startViewTransition: NULL,
|
|
369
|
+
startGestureTransition: NULL,
|
|
370
|
+
stopViewTransition: noop,
|
|
371
|
+
addViewTransitionFinishedListener: noop,
|
|
372
|
+
getCurrentGestureOffset: () => 0,
|
|
373
|
+
|
|
374
|
+
// Hydration (supportsHydration: false — destructured, never called)
|
|
375
|
+
isSuspenseInstancePending: FALSE,
|
|
376
|
+
isSuspenseInstanceFallback: FALSE,
|
|
377
|
+
getSuspenseInstanceFallbackErrorDetails: () => ({}),
|
|
378
|
+
registerSuspenseInstanceRetry: noop,
|
|
379
|
+
getNextHydratableSibling: NULL,
|
|
380
|
+
getNextHydratableSiblingAfterSingleton: NULL,
|
|
381
|
+
getFirstHydratableChild: NULL,
|
|
382
|
+
getFirstHydratableChildWithinContainer: NULL,
|
|
383
|
+
getFirstHydratableChildWithinActivityInstance: NULL,
|
|
384
|
+
getFirstHydratableChildWithinSingleton: NULL,
|
|
385
|
+
getFirstHydratableChildWithinSuspenseInstance: NULL,
|
|
386
|
+
canHydrateInstance: NULL,
|
|
387
|
+
canHydrateTextInstance: NULL,
|
|
388
|
+
canHydrateActivityInstance: NULL,
|
|
389
|
+
canHydrateSuspenseInstance: NULL,
|
|
390
|
+
canHydrateFormStateMarker: NULL,
|
|
391
|
+
isFormStateMarkerMatching: FALSE,
|
|
392
|
+
hydrateInstance: noop,
|
|
393
|
+
hydrateTextInstance: noop,
|
|
394
|
+
hydrateActivityInstance: noop,
|
|
395
|
+
hydrateSuspenseInstance: noop,
|
|
396
|
+
getNextHydratableInstanceAfterActivityInstance: NULL,
|
|
397
|
+
getNextHydratableInstanceAfterSuspenseInstance: NULL,
|
|
398
|
+
commitHydratedInstance: noop,
|
|
399
|
+
commitHydratedContainer: noop,
|
|
400
|
+
commitHydratedSuspenseInstance: noop,
|
|
401
|
+
finalizeHydratedChildren: FALSE,
|
|
402
|
+
flushHydrationEvents: noop,
|
|
403
|
+
clearActivityBoundary: FALSE,
|
|
404
|
+
clearSuspenseBoundary: FALSE,
|
|
405
|
+
clearActivityBoundaryFromContainer: FALSE,
|
|
406
|
+
clearSuspenseBoundaryFromContainer: FALSE,
|
|
407
|
+
hideDehydratedBoundary: noop,
|
|
408
|
+
unhideDehydratedBoundary: noop,
|
|
409
|
+
shouldDeleteUnhydratedTailInstances: FALSE,
|
|
410
|
+
diffHydratedPropsForDevWarnings: NULL,
|
|
411
|
+
diffHydratedTextForDevWarnings: NULL,
|
|
412
|
+
describeHydratableInstanceForDevWarnings: NULL,
|
|
413
|
+
validateHydratableInstance: TRUE,
|
|
414
|
+
validateHydratableTextInstance: TRUE,
|
|
415
|
+
|
|
416
|
+
// Host resources (stylesheets/scripts — supportsResources: false)
|
|
417
|
+
isHostHoistableType: FALSE,
|
|
418
|
+
getHoistableRoot: NULL,
|
|
419
|
+
getResource: NULL,
|
|
420
|
+
acquireResource: noop,
|
|
421
|
+
releaseResource: noop,
|
|
422
|
+
hydrateHoistable: noop,
|
|
423
|
+
mountHoistable: noop,
|
|
424
|
+
unmountHoistable: noop,
|
|
425
|
+
createHoistableInstance: NULL,
|
|
426
|
+
prepareToCommitHoistables: noop,
|
|
427
|
+
mayResourceSuspendCommit: FALSE,
|
|
428
|
+
preloadResource: TRUE,
|
|
429
|
+
suspendResource: noop,
|
|
430
|
+
|
|
431
|
+
// Singletons (supportsSingletons: false)
|
|
432
|
+
resolveSingletonInstance: NULL,
|
|
433
|
+
acquireSingletonInstance: noop,
|
|
434
|
+
releaseSingletonInstance: noop,
|
|
435
|
+
isHostSingletonType: FALSE,
|
|
436
|
+
isSingletonScope: FALSE,
|
|
437
|
+
|
|
438
|
+
// Test selectors (supportsTestSelectors: false)
|
|
439
|
+
findFiberRoot: NULL,
|
|
440
|
+
getBoundingRect: NULL,
|
|
441
|
+
getTextContent: NULL,
|
|
442
|
+
isHiddenSubtree: FALSE,
|
|
443
|
+
matchAccessibilityRole: FALSE,
|
|
444
|
+
setFocusIfFocusable: FALSE,
|
|
445
|
+
setupIntersectionObserver: noop,
|
|
446
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The worker-side surface of @atolljs/islands — import from
|
|
3
|
+
* '@atolljs/islands/worker' inside the worker entry:
|
|
4
|
+
*
|
|
5
|
+
* import { definePolyWorker } from '@atolljs/islands/worker';
|
|
6
|
+
* export const renderWorker = definePolyWorker({ apps: { ... } });
|
|
7
|
+
*
|
|
8
|
+
* Apps (React or `{ imperative }`) also use from here: `emit` (island→shell
|
|
9
|
+
* channel), `runInInstance` (instance scoping for worker-initiated work), `Slot`
|
|
10
|
+
* (transclusion), `createProxyDocument`/`installDomShim` (imperative DOM).
|
|
11
|
+
*/
|
|
12
|
+
export { definePolyWorker, defineMonoWorker } from './defineWorkers';
|
|
13
|
+
export type {
|
|
14
|
+
ImperativeIslandApp,
|
|
15
|
+
Instance,
|
|
16
|
+
IslandApp,
|
|
17
|
+
PolyWorkerRegistry,
|
|
18
|
+
ReactIslandApp,
|
|
19
|
+
RenderContext,
|
|
20
|
+
RenderedHandle,
|
|
21
|
+
RenderedIslandApp,
|
|
22
|
+
} from './defineWorkers';
|
|
23
|
+
|
|
24
|
+
export { islandApp, islandAppNameOf } from '../app';
|
|
25
|
+
|
|
26
|
+
// hostConfig is deliberately NOT exported — a static re-export would pull
|
|
27
|
+
// react + react-reconciler into every /worker bundle. The reconciler is
|
|
28
|
+
// reachable only through definePolyWorker's lazy import of reactInstance.
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
allocId,
|
|
32
|
+
bumpOpsVersion,
|
|
33
|
+
emit,
|
|
34
|
+
getActiveInstance,
|
|
35
|
+
getHandler,
|
|
36
|
+
getLastActiveInstance,
|
|
37
|
+
getLastTouchedInstance,
|
|
38
|
+
getInstanceSize,
|
|
39
|
+
instances,
|
|
40
|
+
pushOp,
|
|
41
|
+
registerHandler,
|
|
42
|
+
ROOT_CONTAINER,
|
|
43
|
+
runInInstance,
|
|
44
|
+
setActiveInstance,
|
|
45
|
+
setDoorbellContract,
|
|
46
|
+
setInstanceSize,
|
|
47
|
+
takeOps,
|
|
48
|
+
unregisterHandler,
|
|
49
|
+
} from './instance';
|
|
50
|
+
export type { ElementInstance, HostInstance, TextInstance } from './instance';
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
createProxyDocument,
|
|
54
|
+
installDomShim,
|
|
55
|
+
installInstanceDispatcher,
|
|
56
|
+
ProxyComment,
|
|
57
|
+
ProxyElement,
|
|
58
|
+
ProxyFragment,
|
|
59
|
+
ProxyNode,
|
|
60
|
+
ProxyText,
|
|
61
|
+
docForInstance,
|
|
62
|
+
} from './proxyDom';
|
|
63
|
+
export type {
|
|
64
|
+
AdjacentPosition,
|
|
65
|
+
InternalDocument,
|
|
66
|
+
ProxyClassList,
|
|
67
|
+
ProxyDocument,
|
|
68
|
+
ProxyEventHandler,
|
|
69
|
+
WindowShim,
|
|
70
|
+
WireListenerOpts,
|
|
71
|
+
} from './proxyDom';
|
|
72
|
+
|
|
73
|
+
export { Slot } from './slot';
|
|
74
|
+
|
|
75
|
+
export type { EventPayload, IslandWorkerMethods, Op, WireProps } from '../ops';
|
|
76
|
+
export { isEventRef } from '../ops';
|
|
77
|
+
export { renderMemory } from '../memory';
|
|
78
|
+
export type { DoorbellSpec } from '../memory';
|