@sigx/lynx-runtime-main 0.4.0 → 0.4.1
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/animated-bridge-mt.js +228 -0
- package/dist/animated-style-mappers.js +154 -0
- package/dist/element-registry.js +16 -0
- package/dist/entry-main.js +229 -1
- package/dist/event-slots.d.ts +1 -1
- package/dist/event-slots.js +111 -0
- package/dist/hybrid-worklet.d.ts +1 -1
- package/dist/hybrid-worklet.js +73 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +22 -63
- package/dist/install-hybrid-worklet.js +19 -6
- package/dist/mt-element.js +203 -0
- package/dist/ops-apply.js +449 -0
- package/dist/run-on-background-mt.js +91 -0
- package/dist/upstream/observers.js +39 -0
- package/dist/upstream/processGesture.js +147 -0
- package/dist/worklet-events.js +47 -0
- package/dist/worklet-refs.js +43 -0
- package/package.json +8 -8
- package/dist/entry-main-CBM2DHsU.js +0 -615
- package/dist/entry-main-CBM2DHsU.js.map +0 -1
- package/dist/hybrid-worklet-nTcCh-mA.js +0 -58
- package/dist/hybrid-worklet-nTcCh-mA.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/install-hybrid-worklet.js.map +0 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
2
|
+
// TypeScript types added 2026 by SignalX contributors.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0. The full license text and
|
|
5
|
+
// upstream attribution are reproduced in `THIRD_PARTY_NOTICES.md` at the
|
|
6
|
+
// root of this package (`@sigx/lynx-runtime-main`). The MIT LICENSE at the
|
|
7
|
+
// repository root governs the rest of this repository; it does NOT apply
|
|
8
|
+
// to this file.
|
|
9
|
+
//
|
|
10
|
+
// TS port of `@lynx-js/react@0.119.0`'s
|
|
11
|
+
// `runtime/lib/gesture/processGesture.js`. Source preserved verbatim; only
|
|
12
|
+
// types added. Why vendor: upstream's `gesture/processGesture.js` is the
|
|
13
|
+
// canonical platform-call sequence used by `@lynx-js/react`'s snapshot
|
|
14
|
+
// pipeline. Calling our hand-rolled equivalent on a real device shows the
|
|
15
|
+
// gesture arena doesn't engage; vendoring eliminates any subtle divergence.
|
|
16
|
+
//
|
|
17
|
+
// Sigx-specific deltas:
|
|
18
|
+
// - `dom` is sigx's raw `MainThreadElement`, not a SnapshotInstance member.
|
|
19
|
+
// - Caller passes `isFirstScreen=false` (no SSR/hydration in sigx).
|
|
20
|
+
// - `gestureOptions` always undefined.
|
|
21
|
+
import { onWorkletCtxUpdate } from './observers.js';
|
|
22
|
+
const COMPOSED = -1;
|
|
23
|
+
function isSerializedGesture(gesture) {
|
|
24
|
+
return gesture?.__isSerialized === true;
|
|
25
|
+
}
|
|
26
|
+
function getSerializedBaseGesture(gesture) {
|
|
27
|
+
if (!gesture || !isSerializedGesture(gesture))
|
|
28
|
+
return undefined;
|
|
29
|
+
if (gesture.type !== COMPOSED)
|
|
30
|
+
return gesture;
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function appendUniqueSerializedBaseGestures(gesture, out, seenIds) {
|
|
34
|
+
if (!gesture || !isSerializedGesture(gesture))
|
|
35
|
+
return;
|
|
36
|
+
if (gesture.type === COMPOSED) {
|
|
37
|
+
for (const sub of gesture.gestures) {
|
|
38
|
+
appendUniqueSerializedBaseGestures(sub, out, seenIds);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const base = gesture;
|
|
43
|
+
if (seenIds.has(base.id))
|
|
44
|
+
return;
|
|
45
|
+
seenIds.add(base.id);
|
|
46
|
+
out.push(base);
|
|
47
|
+
}
|
|
48
|
+
function appendOldGestureInfo(gesture, out, byId) {
|
|
49
|
+
if (!gesture || !isSerializedGesture(gesture))
|
|
50
|
+
return;
|
|
51
|
+
if (gesture.type === COMPOSED) {
|
|
52
|
+
for (const sub of gesture.gestures) {
|
|
53
|
+
appendOldGestureInfo(sub, out, byId);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const base = gesture;
|
|
58
|
+
if (!byId.has(base.id)) {
|
|
59
|
+
byId.set(base.id, base);
|
|
60
|
+
out.push(base);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function collectOldGestureInfo(oldGesture) {
|
|
64
|
+
const uniqOldBaseGestures = [];
|
|
65
|
+
const oldBaseGesturesById = new Map();
|
|
66
|
+
appendOldGestureInfo(oldGesture, uniqOldBaseGestures, oldBaseGesturesById);
|
|
67
|
+
return { uniqOldBaseGestures, oldBaseGesturesById };
|
|
68
|
+
}
|
|
69
|
+
function consumeOldBaseGesture(baseGesture, uniqOldBaseGestures, oldBaseGesturesById) {
|
|
70
|
+
const idMatched = oldBaseGesturesById.get(baseGesture.id);
|
|
71
|
+
if (idMatched) {
|
|
72
|
+
oldBaseGesturesById.delete(baseGesture.id);
|
|
73
|
+
return idMatched;
|
|
74
|
+
}
|
|
75
|
+
const fallback = uniqOldBaseGestures.find((og) => oldBaseGesturesById.has(og.id));
|
|
76
|
+
if (!fallback)
|
|
77
|
+
return undefined;
|
|
78
|
+
oldBaseGesturesById.delete(fallback.id);
|
|
79
|
+
return fallback;
|
|
80
|
+
}
|
|
81
|
+
function removeGestureDetector(dom, id) {
|
|
82
|
+
if (typeof __RemoveGestureDetector === 'function') {
|
|
83
|
+
__RemoveGestureDetector(dom, id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function getGestureInfo(gesture, oldGesture, isFirstScreen, dom) {
|
|
87
|
+
const config = { callbacks: [] };
|
|
88
|
+
if (gesture.config) {
|
|
89
|
+
config.config = gesture.config;
|
|
90
|
+
}
|
|
91
|
+
for (const key of Object.keys(gesture.callbacks)) {
|
|
92
|
+
const callback = gesture.callbacks[key];
|
|
93
|
+
const oldCallback = oldGesture?.callbacks[key];
|
|
94
|
+
// Upstream types `Worklet._c` as `Record<string, ClosureValueType>`; ours
|
|
95
|
+
// is `Record<string, unknown>` from the wire. The runtime contract is
|
|
96
|
+
// identical — cast through `unknown` to satisfy the upstream signature.
|
|
97
|
+
onWorkletCtxUpdate(callback, oldCallback, isFirstScreen, dom);
|
|
98
|
+
config.callbacks.push({ name: key, callback });
|
|
99
|
+
}
|
|
100
|
+
const relationMap = {
|
|
101
|
+
waitFor: gesture.waitFor?.map((g) => g.id) ?? [],
|
|
102
|
+
simultaneous: gesture.simultaneousWith?.map((g) => g.id) ?? [],
|
|
103
|
+
continueWith: gesture.continueWith?.map((g) => g.id) ?? [],
|
|
104
|
+
};
|
|
105
|
+
return { config, relationMap };
|
|
106
|
+
}
|
|
107
|
+
export function processGesture(dom, gesture, oldGesture, isFirstScreen, gestureOptions) {
|
|
108
|
+
const domSet = gestureOptions?.domSet === true;
|
|
109
|
+
const { uniqOldBaseGestures, oldBaseGesturesById } = collectOldGestureInfo(oldGesture);
|
|
110
|
+
const singleBaseGesture = getSerializedBaseGesture(gesture);
|
|
111
|
+
const singleOldBaseGesture = getSerializedBaseGesture(oldGesture);
|
|
112
|
+
if (singleBaseGesture && (!oldGesture || singleOldBaseGesture)) {
|
|
113
|
+
if (!domSet) {
|
|
114
|
+
__SetAttribute(dom, 'has-react-gesture', true);
|
|
115
|
+
__SetAttribute(dom, 'flatten', false);
|
|
116
|
+
}
|
|
117
|
+
if (singleOldBaseGesture) {
|
|
118
|
+
removeGestureDetector(dom, singleOldBaseGesture.id);
|
|
119
|
+
}
|
|
120
|
+
const { config, relationMap } = getGestureInfo(singleBaseGesture, singleOldBaseGesture, isFirstScreen, dom);
|
|
121
|
+
__SetGestureDetector(dom, singleBaseGesture.id, singleBaseGesture.type, config, relationMap);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const uniqBaseGestures = [];
|
|
125
|
+
appendUniqueSerializedBaseGestures(gesture, uniqBaseGestures, new Set());
|
|
126
|
+
if (uniqBaseGestures.length === 0) {
|
|
127
|
+
for (const og of oldBaseGesturesById.values()) {
|
|
128
|
+
removeGestureDetector(dom, og.id);
|
|
129
|
+
}
|
|
130
|
+
if (!domSet) {
|
|
131
|
+
__SetAttribute(dom, 'has-react-gesture', null);
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!domSet) {
|
|
136
|
+
__SetAttribute(dom, 'has-react-gesture', true);
|
|
137
|
+
__SetAttribute(dom, 'flatten', false);
|
|
138
|
+
}
|
|
139
|
+
for (const og of oldBaseGesturesById.values()) {
|
|
140
|
+
removeGestureDetector(dom, og.id);
|
|
141
|
+
}
|
|
142
|
+
for (const base of uniqBaseGestures) {
|
|
143
|
+
const oldBase = consumeOldBaseGesture(base, uniqOldBaseGestures, oldBaseGesturesById);
|
|
144
|
+
const { config, relationMap } = getGestureInfo(base, oldBase, isFirstScreen, dom);
|
|
145
|
+
__SetGestureDetector(dom, base.id, base.type, config, relationMap);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for invoking worklets from the BG → MT bridge.
|
|
3
|
+
*
|
|
4
|
+
* Most of the worklet machinery (registry, ref map, event dispatch) is owned
|
|
5
|
+
* by `@lynx-js/react/worklet-runtime`, which is side-effect-imported from
|
|
6
|
+
* `entry-main.ts`. That runtime installs `globalThis.lynxWorkletImpl`,
|
|
7
|
+
* `globalThis.registerWorkletInternal`, and `globalThis.runWorklet`. Lynx
|
|
8
|
+
* native dispatches MT-routed events directly into `runWorklet`.
|
|
9
|
+
*
|
|
10
|
+
* What sigx-lynx still needs to provide is the `runOnMainThread` BG → MT call
|
|
11
|
+
* path: BG ships `{ wkltId, args }` over `callLepusMethod('sigxRunOnMT')`, the
|
|
12
|
+
* MT bridge handler in `entry-main.ts` calls `invokeWorklet()` here, and we
|
|
13
|
+
* look up the function in upstream's `_workletMap`.
|
|
14
|
+
*/
|
|
15
|
+
function getWorkletImpl() {
|
|
16
|
+
return globalThis['lynxWorkletImpl'];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Invoke a worklet by id with the given args. Used by the runOnMainThread
|
|
20
|
+
* bridge — event-driven worklets go through Lynx's native runWorklet path
|
|
21
|
+
* and never touch this function.
|
|
22
|
+
*/
|
|
23
|
+
export function invokeWorklet(wkltId, captured, args) {
|
|
24
|
+
const impl = getWorkletImpl();
|
|
25
|
+
if (!impl) {
|
|
26
|
+
console.log('[sigx-mt] lynxWorkletImpl not initialized');
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const fn = impl._workletMap[wkltId];
|
|
30
|
+
if (!fn) {
|
|
31
|
+
console.log('[sigx-mt] worklet not registered:', wkltId);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
// Match upstream's calling convention: `function(arg) { let { x } = this["_c"]; ... }`
|
|
35
|
+
try {
|
|
36
|
+
return fn.apply({ _c: captured ?? {} }, args);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
console.log('[sigx-mt] worklet threw:', String(e));
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Reset hook — for testing. The upstream worklet-runtime has its own state. */
|
|
44
|
+
export function resetWorkletEvents() {
|
|
45
|
+
// No sigx-side state to clear; upstream's _workletMap survives module reset
|
|
46
|
+
// (registrations re-run when the user module re-evaluates on hot reload).
|
|
47
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worklet ref registry — manages MainThreadRef state on the Main Thread.
|
|
3
|
+
*
|
|
4
|
+
* Each ref is identified by a worklet variable ID (wvid) assigned on the
|
|
5
|
+
* BG thread. When INIT_MT_REF arrives, we create a holder. When SET_MT_REF
|
|
6
|
+
* arrives, we set the holder's .current to the real element wrapper.
|
|
7
|
+
*/
|
|
8
|
+
import { MTElementWrapper } from './mt-element.js';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Registry
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const workletRefs = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* Initialize a worklet ref on the Main Thread.
|
|
15
|
+
* Called when the BG thread sends INIT_MT_REF(wvid, initValue).
|
|
16
|
+
*/
|
|
17
|
+
export function initWorkletRef(wvid, initValue) {
|
|
18
|
+
workletRefs.set(wvid, { current: initValue });
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Bind a worklet ref to a Main Thread element.
|
|
22
|
+
* Called when the BG thread sends SET_MT_REF(elementId, wvid).
|
|
23
|
+
* The ref's .current is set to an MTElementWrapper around the real element.
|
|
24
|
+
*/
|
|
25
|
+
export function bindWorkletRef(wvid, el) {
|
|
26
|
+
const holder = workletRefs.get(wvid);
|
|
27
|
+
if (holder) {
|
|
28
|
+
holder.current = new MTElementWrapper(el);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get a worklet ref holder by wvid — used by worklet event handlers
|
|
33
|
+
* to access refs.
|
|
34
|
+
*/
|
|
35
|
+
export function getWorkletRef(wvid) {
|
|
36
|
+
return workletRefs.get(wvid);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reset all worklet refs — for testing and hot reload.
|
|
40
|
+
*/
|
|
41
|
+
export function resetWorkletRefs() {
|
|
42
|
+
workletRefs.clear();
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigx/lynx-runtime-main",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Main Thread (Lepus) entry and ops applier for SignalX Lynx renderer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"url": "https://github.com/signalxjs/lynx/issues"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@sigx/lynx-runtime-internal": "0.4.
|
|
45
|
+
"@sigx/lynx-runtime-internal": "0.4.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@lynx-js/types": ">=3.0.0"
|
|
@@ -53,16 +53,16 @@
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@lynx-js/types": "^3.
|
|
57
|
-
"@
|
|
58
|
-
"typescript": "^6.0.3"
|
|
59
|
-
"vite": "^8.0.12"
|
|
56
|
+
"@lynx-js/types": "^3.9.0",
|
|
57
|
+
"@typescript/native-preview": "7.0.0-dev.20260511.1",
|
|
58
|
+
"typescript": "^6.0.3"
|
|
60
59
|
},
|
|
61
60
|
"publishConfig": {
|
|
62
61
|
"access": "public"
|
|
63
62
|
},
|
|
64
63
|
"scripts": {
|
|
65
|
-
"build": "
|
|
66
|
-
"dev": "
|
|
64
|
+
"build": "node ../../scripts/clean.mjs dist && tsgo",
|
|
65
|
+
"dev": "tsgo --watch",
|
|
66
|
+
"clean": "node ../../scripts/clean.mjs dist .turbo"
|
|
67
67
|
}
|
|
68
68
|
}
|