@atolljs/islands 0.1.9 → 0.1.10
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/package.json +2 -2
- package/src/island.ts +17 -0
- package/src/ops.ts +29 -0
- package/src/worker/dom/document.ts +7 -0
- package/src/worker/subIsland.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atolljs/islands",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Atoll islands — MonoWorker/PolyWorker hosts rendering framework islands (React/Vue/Svelte/Solid/Angular) over a proxy-DOM op protocol",
|
|
5
5
|
"homepage": "https://jwhenry3.github.io/atolljs/consumer/quickstart/",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"htmlparser2": "^12.0.0"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@atolljs/core": "0.1.
|
|
22
|
+
"@atolljs/core": "0.1.10"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
package/src/island.ts
CHANGED
|
@@ -227,6 +227,7 @@ function buildEventPayload(
|
|
|
227
227
|
e: Event,
|
|
228
228
|
target: EventTarget | null,
|
|
229
229
|
targetId: number | undefined,
|
|
230
|
+
relatedTargetId?: number,
|
|
230
231
|
): EventPayload {
|
|
231
232
|
const input = target as HTMLInputElement | null;
|
|
232
233
|
const mouse = e as MouseEvent;
|
|
@@ -243,6 +244,18 @@ function buildEventPayload(
|
|
|
243
244
|
const coord = (v: unknown): number | undefined =>
|
|
244
245
|
num(v) ?? (pointerFam ? 0 : undefined);
|
|
245
246
|
const button = num(mouse.button) ?? (pointerFam ? 0 : undefined);
|
|
247
|
+
// currentTarget is the element this listener was attached to — the exact
|
|
248
|
+
// element hit-testing libraries normalize pointer coords against
|
|
249
|
+
// (zrender's `normalizeEvent(this.dom, e)`). Checked structurally, not
|
|
250
|
+
// via `instanceof Element`: in in-process embeddings the worker-side
|
|
251
|
+
// dispatcher may point the global at ProxyElement.
|
|
252
|
+
const ct = e.currentTarget as Element | null;
|
|
253
|
+
const localRect =
|
|
254
|
+
ct && typeof ct.getBoundingClientRect === 'function'
|
|
255
|
+
? ct.getBoundingClientRect()
|
|
256
|
+
: null;
|
|
257
|
+
const local = (v: number | undefined, origin: number): number | undefined =>
|
|
258
|
+
localRect && typeof v === 'number' ? v - origin : undefined;
|
|
246
259
|
return {
|
|
247
260
|
type: e.type,
|
|
248
261
|
value: input && 'value' in input ? input.value : undefined,
|
|
@@ -252,6 +265,8 @@ function buildEventPayload(
|
|
|
252
265
|
clientY: coord(mouse.clientY),
|
|
253
266
|
screenX: coord(mouse.screenX),
|
|
254
267
|
screenY: coord(mouse.screenY),
|
|
268
|
+
zrX: local(mouse.clientX, localRect?.left ?? 0),
|
|
269
|
+
zrY: local(mouse.clientY, localRect?.top ?? 0),
|
|
255
270
|
button,
|
|
256
271
|
which:
|
|
257
272
|
typeof mouse.which === 'number' && mouse.which !== 0
|
|
@@ -273,6 +288,7 @@ function buildEventPayload(
|
|
|
273
288
|
pointerType: typeof pointer.pointerType === 'string' ? pointer.pointerType : undefined,
|
|
274
289
|
scrollTop: input instanceof HTMLElement ? input.scrollTop : undefined,
|
|
275
290
|
targetId,
|
|
291
|
+
relatedTargetId,
|
|
276
292
|
};
|
|
277
293
|
}
|
|
278
294
|
|
|
@@ -547,6 +563,7 @@ export async function mountIsland(opts: MountIslandOptions): Promise<IslandHandl
|
|
|
547
563
|
e,
|
|
548
564
|
target,
|
|
549
565
|
target !== null ? nodeIds.get(target as Node) : undefined,
|
|
566
|
+
nodeIds.get((e as MouseEvent).relatedTarget as Node),
|
|
550
567
|
);
|
|
551
568
|
// The whole point: an event = one postMessage round-trip. The worker
|
|
552
569
|
// re-renders, we apply whatever ops come back.
|
package/src/ops.ts
CHANGED
|
@@ -124,6 +124,19 @@ export interface EventPayload {
|
|
|
124
124
|
clientY?: number;
|
|
125
125
|
screenX?: number;
|
|
126
126
|
screenY?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Pointer coords in the LISTENER element's local space:
|
|
129
|
+
* `clientX/Y − event.currentTarget.getBoundingClientRect()` computed
|
|
130
|
+
* main-thread where real rects exist. The proxy DOM has no measurement
|
|
131
|
+
* channel, so worker-side hit-testing libraries cannot derive local
|
|
132
|
+
* coords themselves: zrender's four-marker getBoundingClientRect
|
|
133
|
+
* transform degenerates, and e.offsetX is absent anyway. zrender's
|
|
134
|
+
* normalizeEvent early-returns on `e.zrX != null`, which is why the
|
|
135
|
+
* fields carry its names — charts (echarts SVG renderer) get working
|
|
136
|
+
* axis pointers/tooltips, any library can read them the same way.
|
|
137
|
+
*/
|
|
138
|
+
zrX?: number;
|
|
139
|
+
zrY?: number;
|
|
127
140
|
button?: number;
|
|
128
141
|
/**
|
|
129
142
|
* UIEvent.which — non-standard but set by every browser (1 = left button,
|
|
@@ -153,6 +166,15 @@ export interface EventPayload {
|
|
|
153
166
|
scrollTop?: number;
|
|
154
167
|
/** The worker instance id of `event.target`, when it maps to one. */
|
|
155
168
|
targetId?: number;
|
|
169
|
+
/**
|
|
170
|
+
* The worker instance id of `event.relatedTarget` (MouseEvent/FocusEvent),
|
|
171
|
+
* when it maps to an op-created node. Lets over/out/leave/enter handlers
|
|
172
|
+
* distinguish "moved to a child" from "actually left the element" —
|
|
173
|
+
* zrender's mouseout gate (`toElement || relatedTarget` → isLocalEl walk)
|
|
174
|
+
* is the canonical consumer; without it every child transition looks like
|
|
175
|
+
* a real leave and charts flicker as tooltips hide/show.
|
|
176
|
+
*/
|
|
177
|
+
relatedTargetId?: number;
|
|
156
178
|
/**
|
|
157
179
|
* The proxy-DOM node for `targetId` — SYNTHESIZED worker-side by the proxy
|
|
158
180
|
* DOM when it wraps a listener (it never crosses the wire). Lets delegated
|
|
@@ -162,6 +184,13 @@ export interface EventPayload {
|
|
|
162
184
|
* same proxy document.
|
|
163
185
|
*/
|
|
164
186
|
target?: unknown;
|
|
187
|
+
/**
|
|
188
|
+
* The proxy-DOM node for `relatedTargetId` — SYNTHESIZED worker-side like
|
|
189
|
+
* `target` (never crosses the wire). Handler code can walk
|
|
190
|
+
* `relatedTarget.parentNode` — e.g. zrender's isLocalEl — to test
|
|
191
|
+
* whether the pointer moved within the listener's subtree.
|
|
192
|
+
*/
|
|
193
|
+
relatedTarget?: unknown;
|
|
165
194
|
/**
|
|
166
195
|
* Synthesized NO-OPS — added worker-side by the proxy DOM when it wraps a
|
|
167
196
|
* listener's payload (they never cross the wire). They exist so library
|
|
@@ -307,6 +307,13 @@ export class InternalDocument implements ProxyDocument {
|
|
|
307
307
|
out.target = node;
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
+
// Materialize relatedTarget the same way — over/out handlers walk it
|
|
311
|
+
// (zrender's isLocalEl climbs parentNode to the listener root) to tell
|
|
312
|
+
// "moved to a child" apart from "actually left".
|
|
313
|
+
if (typeof payload.relatedTargetId === 'number') {
|
|
314
|
+
const related = instances.get(payload.relatedTargetId);
|
|
315
|
+
if (related !== undefined) out.relatedTarget = this._wrap(related);
|
|
316
|
+
}
|
|
310
317
|
if (out.composedPath === undefined) {
|
|
311
318
|
const path: unknown[] = [];
|
|
312
319
|
let n = out.target as ProxyNode | undefined;
|