mithril-lynx 0.0.9 → 2.0.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.
Files changed (61) hide show
  1. package/.omo/plans/m-request-fetch-lynx.md +306 -0
  2. package/.omo/plans/m-route-en-memoria.md +397 -0
  3. package/.omo/plans/mithril-lynx-v2-desde-cero.md +548 -0
  4. package/FETCH_INVESTIGATION.md +307 -0
  5. package/README.md +32 -302
  6. package/REQUEST.md +71 -0
  7. package/ROUTE.md +71 -0
  8. package/package.json +24 -80
  9. package/plugin.d.ts +4 -33
  10. package/plugin.js +108 -438
  11. package/rstest.config.ts +27 -0
  12. package/src/apply-patch.js +179 -0
  13. package/src/backends/virtual-backend.js +80 -0
  14. package/src/background.d.ts +11 -0
  15. package/src/background.js +79 -0
  16. package/src/channel.js +41 -0
  17. package/src/commit.js +67 -0
  18. package/src/dev-reload-client.js +171 -187
  19. package/src/dev-transport-noop.js +10 -0
  20. package/src/fake-dom.js +374 -0
  21. package/src/main-thread.d.ts +1 -0
  22. package/src/main-thread.js +68 -0
  23. package/src/mount-redraw.js +67 -0
  24. package/src/patch-protocol.js +40 -0
  25. package/src/reload/version.js +28 -0
  26. package/src/request.d.ts +37 -0
  27. package/src/request.js +181 -0
  28. package/src/route.d.ts +33 -0
  29. package/src/route.js +207 -0
  30. package/test/end-to-end.test.ts +86 -0
  31. package/test/reload-version.test.ts +17 -0
  32. package/test/request.test.ts +182 -0
  33. package/test/route-hot-reload.test.ts +40 -0
  34. package/test/route.test.ts +152 -0
  35. package/test/setup.ts +25 -0
  36. package/test/structural-reload.test.ts +95 -0
  37. package/CONTRACT.md +0 -151
  38. package/LICENSE +0 -21
  39. package/background.d.ts +0 -54
  40. package/background.js +0 -169
  41. package/element.d.ts +0 -34
  42. package/element.js +0 -83
  43. package/gesture.d.ts +0 -40
  44. package/gesture.js +0 -117
  45. package/internal/constants.js +0 -26
  46. package/internal/virtual-node.js +0 -388
  47. package/list.d.ts +0 -31
  48. package/list.js +0 -185
  49. package/main-thread.d.ts +0 -43
  50. package/main-thread.js +0 -165
  51. package/navigation.d.ts +0 -35
  52. package/navigation.js +0 -76
  53. package/renderer/background.d.ts +0 -21
  54. package/renderer/background.js +0 -84
  55. package/renderer/main-thread.d.ts +0 -12
  56. package/renderer/main-thread.js +0 -175
  57. package/src/lynx-mithril-shim.d.ts +0 -16
  58. package/src/lynx-mithril-shim.js +0 -1505
  59. package/src/worklet-runtime.js +0 -82
  60. package/testing.d.ts +0 -10
  61. package/testing.js +0 -91
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 carlos-sweb
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/background.d.ts DELETED
@@ -1,54 +0,0 @@
1
- // Ambient declaration for the ESM background.js (the file itself is not
2
- // type-checked; this describes its runtime export shape for TS consumers).
3
-
4
- export type StoreData = Record<string, unknown>;
5
-
6
- export interface SetDataOptions {
7
- /** Set false to update the store without pushing a sync to the main thread. Defaults to true. */
8
- shouldSyncToMainThread?: boolean;
9
- }
10
-
11
- /** Returns the background thread's mutable data store. */
12
- export function getData<T = StoreData>(): T;
13
-
14
- /** Merges `patch` into the store, then (by default) pushes the changed keys to the main thread. */
15
- export function setData(patch: StoreData, options?: SetDataOptions): void;
16
-
17
- /**
18
- * Registers the single handler invoked for every dispatchToBackground() call
19
- * made from the main thread, as (handlerName, data).
20
- */
21
- export function setBackgroundEventHandler(
22
- handleEvent: (handlerName: string, data: unknown) => unknown,
23
- ): void;
24
-
25
- /**
26
- * Wires the background thread's core-context listeners for the
27
- * main-thread <-> background-thread data channel. Call once, at
28
- * background.ts's top level. See the project plan, Phase 3.
29
- */
30
- export function setupBackground(): void;
31
-
32
- export interface BackgroundRef {
33
- /** Resolves with the native method's success data, rejects with its failure data. */
34
- invoke(method: string, params?: Record<string, unknown>): Promise<unknown>;
35
- }
36
-
37
- /**
38
- * A background-thread ref: imperative calls to a native element identified
39
- * by a CSS selector, via lynx.createSelectorQuery(). See the project plan,
40
- * Phase 5.
41
- */
42
- export function createRef(selector: string): BackgroundRef;
43
-
44
- /**
45
- * Registers a handler main-thread.js's runOnBackground(key, ...args) can
46
- * call by name. See the project plan, Phase 6.
47
- */
48
- export function registerHandler(key: string, fn: (...args: unknown[]) => unknown): void;
49
-
50
- /**
51
- * Calls a handler main-thread.js registered via registerHandler(key, fn).
52
- * Args and the resolved value must be JSON-serializable.
53
- */
54
- export function runOnMainThread<T = unknown>(key: string, ...args: unknown[]): Promise<T>;
package/background.js DELETED
@@ -1,169 +0,0 @@
1
- // background.js
2
- //
3
- // Cross-thread "data-channel mode" adapter for the background thread (see
4
- // the project plan, Phase 3). Ports
5
- // lynx-examples/examples/vanilla/src/common/background/{setup,data,event}.ts
6
- // into a single module — this side is framework-agnostic (Mithril never
7
- // renders on the background thread in data-channel mode), so nothing here
8
- // depends on the shim.
9
- //
10
- // A single mutable data store is diffed against its last-synced snapshot on
11
- // every setData() call and only the changed keys are pushed to the main
12
- // thread. Data received FROM the main thread is never echoed back (the
13
- // reference implementation does, on every update after the first — a
14
- // pure round-trip echo that's wasteful, and directly visible as a redundant
15
- // extra Mithril redraw in this port, so it isn't reproduced here).
16
-
17
- import {
18
- callBackgroundEventName,
19
- callBackgroundResultEventName,
20
- callMainThreadEventName,
21
- callMainThreadResultEventName,
22
- destroyLifetimeEventName,
23
- dispatchEventToBackgroundEventName,
24
- updateDataFromBackgroundEventName,
25
- updateDataFromMainThreadEventName,
26
- } from "./internal/constants.js";
27
-
28
- const data = {};
29
- let lastSyncedData = { ...data };
30
- let handleBackgroundEvent;
31
-
32
- export function getData() {
33
- return data;
34
- }
35
-
36
- export function setData(patch, options = {}) {
37
- const { shouldSyncToMainThread = true } = options;
38
- Object.assign(data, patch);
39
- if (!shouldSyncToMainThread) {
40
- lastSyncedData = { ...data };
41
- return;
42
- }
43
- sendToMainThread();
44
- }
45
-
46
- function sendToMainThread() {
47
- const patch = {};
48
- for (const [key, value] of Object.entries(data)) {
49
- if (value !== lastSyncedData[key]) patch[key] = value;
50
- }
51
- if (Object.keys(patch).length === 0) return;
52
- lastSyncedData = { ...data };
53
- lynx.getCoreContext().dispatchEvent({
54
- type: updateDataFromBackgroundEventName,
55
- data: patch,
56
- });
57
- }
58
-
59
- // handleEvent(handlerName, data) — called for every dispatchToBackground()
60
- // call made from the main thread. Only one handler at a time; Phase 6 of the
61
- // project plan generalizes this into a full string-keyed registry with
62
- // call/return correlation.
63
- export function setBackgroundEventHandler(handleEvent) {
64
- handleBackgroundEvent = handleEvent;
65
- }
66
-
67
- export function setupBackground() {
68
- const coreContext = lynx.getCoreContext();
69
-
70
- const onUpdateDataFromMainThread = (event) => {
71
- const incoming = event.data;
72
- if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return;
73
- // Never echo data back to the thread it just came from — only
74
- // background-initiated setData() calls (elsewhere in app code)
75
- // should sync to the main thread.
76
- setData(incoming, { shouldSyncToMainThread: false });
77
- };
78
-
79
- const onDispatchToBackground = (event) => {
80
- const payload = event.data;
81
- if (!payload || typeof payload.handlerName !== "string") return;
82
- handleBackgroundEvent?.(payload.handlerName, payload.data);
83
- };
84
-
85
- const cleanup = () => {
86
- coreContext.removeEventListener(updateDataFromMainThreadEventName, onUpdateDataFromMainThread);
87
- coreContext.removeEventListener(dispatchEventToBackgroundEventName, onDispatchToBackground);
88
- coreContext.removeEventListener(destroyLifetimeEventName, cleanup);
89
- };
90
-
91
- coreContext.addEventListener(updateDataFromMainThreadEventName, onUpdateDataFromMainThread);
92
- coreContext.addEventListener(dispatchEventToBackgroundEventName, onDispatchToBackground);
93
- coreContext.addEventListener(destroyLifetimeEventName, cleanup);
94
- }
95
-
96
- // Refs (project plan, Phase 5): the background thread has no direct native
97
- // handle, so imperative calls go through Lynx's existing selector-query
98
- // bridge (the same primitive ReactLynx's own background-thread refs
99
- // ultimately bottom out on) rather than a new protocol.
100
- export function createRef(selector) {
101
- return {
102
- invoke(method, params) {
103
- return new Promise((resolve, reject) => {
104
- lynx.createSelectorQuery()
105
- .select(selector)
106
- .invoke({
107
- method,
108
- params: params || {},
109
- success: (data) => resolve(data),
110
- fail: (data) => reject(data),
111
- })
112
- .exec();
113
- });
114
- },
115
- };
116
- }
117
-
118
- // Cross-thread function registry (project plan, Phase 6 — worklet
119
- // substitute). See main-thread.js's registerHandler()/runOnBackground() for
120
- // the full rationale; this is the mirror image for the reverse direction.
121
- // Lazy setup on first use, same reasoning as main-thread.js.
122
- const backgroundHandlers = new Map();
123
- const pendingMainThreadCalls = new Map();
124
- let nextCallId = 1;
125
- let crossThreadCallsReady = false;
126
-
127
- function ensureCrossThreadCalls() {
128
- if (crossThreadCallsReady) return;
129
- crossThreadCallsReady = true;
130
- const coreContext = lynx.getCoreContext();
131
-
132
- coreContext.addEventListener(callBackgroundEventName, (event) => {
133
- const { callId, key, args } = event.data;
134
- const fn = backgroundHandlers.get(key);
135
- let result;
136
- let error;
137
- try {
138
- result = fn ? fn(...args) : undefined;
139
- } catch (e) {
140
- error = e instanceof Error ? e.message : String(e);
141
- }
142
- coreContext.dispatchEvent({ type: callBackgroundResultEventName, data: { callId, result, error } });
143
- });
144
-
145
- coreContext.addEventListener(callMainThreadResultEventName, (event) => {
146
- const { callId, result, error } = event.data;
147
- const pending = pendingMainThreadCalls.get(callId);
148
- if (pending == null) return;
149
- pendingMainThreadCalls.delete(callId);
150
- if (error != null) pending.reject(new Error(error));
151
- else pending.resolve(result);
152
- });
153
- }
154
-
155
- /** Registers a handler main-thread.js's runOnBackground(key, ...) can call by name. */
156
- export function registerHandler(key, fn) {
157
- ensureCrossThreadCalls();
158
- backgroundHandlers.set(key, fn);
159
- }
160
-
161
- /** Calls a handler main-thread.js registered via registerHandler(key, fn), by name. Args must be JSON-serializable. */
162
- export function runOnMainThread(key, ...args) {
163
- ensureCrossThreadCalls();
164
- return new Promise((resolve, reject) => {
165
- const callId = nextCallId++;
166
- pendingMainThreadCalls.set(callId, { resolve, reject });
167
- lynx.getCoreContext().dispatchEvent({ type: callMainThreadEventName, data: { callId, key, args } });
168
- });
169
- }
package/element.d.ts DELETED
@@ -1,34 +0,0 @@
1
- // Ambient declaration for the ESM element.js (the file itself is not
2
- // type-checked; this describes its runtime export shape for TS consumers).
3
-
4
- export interface SelectorParams {
5
- onlyCurrentComponent?: boolean;
6
- }
7
-
8
- export interface AnimationTimingOptions {
9
- name?: string;
10
- duration?: number | string;
11
- delay?: number | string;
12
- iterationCount?: number | string;
13
- fillMode?: string;
14
- timingFunction?: string;
15
- direction?: string;
16
- }
17
-
18
- export type Keyframe = Record<string, string | number>;
19
-
20
- export interface MainThreadElement {
21
- setStyleProperty(name: string, value: string | number): void;
22
- setStyleProperties(styles: Record<string, string | number>): void;
23
- setAttribute(name: string, value: unknown): void;
24
- querySelector(selector: string, params?: SelectorParams): MainThreadElement | null;
25
- querySelectorAll(selector: string, params?: SelectorParams): MainThreadElement[];
26
- animate(keyframes: Keyframe[], options?: AnimationTimingOptions): void;
27
- playAnimation(name: string): void;
28
- pauseAnimation(name: string): void;
29
- cancelAnimation(name: string): void;
30
- invoke(method: string, params?: Record<string, unknown>): Promise<{ code: number; data: unknown }>;
31
- }
32
-
33
- /** Wraps a node (anything with a `_handle`, i.e. a real LynxNodeWrapper) with imperative PAPI methods. */
34
- export function wrapElement(node: { _handle: unknown }): MainThreadElement;
package/element.js DELETED
@@ -1,83 +0,0 @@
1
- // element.js
2
- //
3
- // Ergonomic imperative escape hatch for a main-thread node — whatever
4
- // Mithril's oncreate(vnode)/onupdate(vnode) hooks hand you as `vnode.dom`
5
- // (works for any real LynxNodeWrapper: main-thread-owned mode, or
6
- // data-channel mode's main-thread half). Not part of render.js's own DOM
7
- // contract (see ../CONTRACT.md) — these are Element PAPI capabilities apps
8
- // reach for directly (focusing a native input, animating, calling a native
9
- // custom element's method), so they live in their own small module instead
10
- // of the shim.
11
- //
12
- // Project plan, Phase 5. Background-thread refs are the selector-query
13
- // equivalent — see background.js's createRef().
14
-
15
- const ANIMATION_OPERATION = { START: 0, PLAY: 1, PAUSE: 2, CANCEL: 3 };
16
-
17
- function wrapRef(handle) {
18
- return handle == null ? null : wrapElement({ _handle: handle });
19
- }
20
-
21
- /**
22
- * Wraps a node (anything with a `_handle`, i.e. a real LynxNodeWrapper OR a
23
- * raw ElementRef from querySelector) with imperative PAPI methods render.js
24
- * itself never needs. setAttribute mirrors the real LynxNodeWrapper's own
25
- * class/id/data-prefixed/generic-attribute special-casing (see
26
- * ../CONTRACT.md) rather than delegating to node.setAttribute() directly —
27
- * a raw querySelector result has no such method, only a `_handle`.
28
- */
29
- export function wrapElement(node) {
30
- const handle = node._handle;
31
-
32
- return {
33
- setStyleProperty(name, value) {
34
- __SetInlineStyles(handle, { [name]: value });
35
- },
36
-
37
- setStyleProperties(styles) {
38
- __SetInlineStyles(handle, styles);
39
- },
40
-
41
- setAttribute(name, value) {
42
- // "" not undefined when clearing: real hardware's FiberSetClasses
43
- // rejects a non-string argument ("FiberSetClasses param 1 should be
44
- // String") — see lynx-mithril-shim.js's own matching fix for the
45
- // same call.
46
- if (name === "class") __SetClasses(handle, value == null ? "" : String(value));
47
- else if (name === "id") __SetID(handle, value == null ? null : String(value));
48
- else if (name.slice(0, 5) === "data-") __AddDataset(handle, name.slice(5), value);
49
- else __SetAttribute(handle, name, value == null ? null : value);
50
- },
51
-
52
- querySelector(selector, params) {
53
- return wrapRef(__QuerySelector(handle, selector, params || {}));
54
- },
55
-
56
- querySelectorAll(selector, params) {
57
- return __QuerySelectorAll(handle, selector, params || {}).map((ref) => wrapRef(ref));
58
- },
59
-
60
- animate(keyframes, options) {
61
- __ElementAnimate(handle, [ANIMATION_OPERATION.START, (options && options.name) || "", keyframes, options]);
62
- },
63
-
64
- playAnimation(name) {
65
- __ElementAnimate(handle, [ANIMATION_OPERATION.PLAY, name]);
66
- },
67
-
68
- pauseAnimation(name) {
69
- __ElementAnimate(handle, [ANIMATION_OPERATION.PAUSE, name]);
70
- },
71
-
72
- cancelAnimation(name) {
73
- __ElementAnimate(handle, [ANIMATION_OPERATION.CANCEL, name]);
74
- },
75
-
76
- /** Always resolves with { code, data } — check `code` yourself; PAPI's success/failure convention isn't assumed here. */
77
- invoke(method, params) {
78
- return new Promise((resolve) => {
79
- __InvokeUIMethod(handle, method, params || {}, (res) => resolve(res));
80
- });
81
- },
82
- };
83
- }
package/gesture.d.ts DELETED
@@ -1,40 +0,0 @@
1
- // Ambient declaration for the ESM gesture.js (the file itself is not
2
- // type-checked; this describes its runtime export shape for TS consumers).
3
-
4
- export const GestureType: {
5
- readonly COMPOSED: -1;
6
- readonly PAN: 0;
7
- readonly FLING: 1;
8
- readonly DEFAULT: 2;
9
- readonly TAP: 3;
10
- readonly LONGPRESS: 4;
11
- readonly ROTATION: 5;
12
- readonly PINCH: 6;
13
- readonly NATIVE: 7;
14
- };
15
-
16
- export type GestureTypeName = keyof typeof GestureType;
17
-
18
- export interface Gesture {
19
- id: number;
20
- remove(): void;
21
- setState(state: number): void;
22
- }
23
-
24
- export interface GestureController {
25
- __SetGestureState(state: number): void;
26
- __ConsumeGesture(options: Record<string, boolean>): void;
27
- }
28
-
29
- export interface CreateGestureOptions {
30
- type: number | GestureTypeName;
31
- /** Each callback is invoked as `(event, controller) => {}`; `controller` can usually be ignored. */
32
- callbacks?: Record<string, (event: unknown, controller: GestureController) => unknown>;
33
- waitFor?: Gesture[];
34
- simultaneousWith?: Gesture[];
35
- continueWith?: Gesture[];
36
- config?: Record<string, unknown>;
37
- }
38
-
39
- /** Registers a gesture detector on a node (anything with a `_handle`). See the project plan, Phase 7. */
40
- export function createGesture(node: { _handle: unknown }, options: CreateGestureOptions): Gesture;
package/gesture.js DELETED
@@ -1,117 +0,0 @@
1
- // gesture.js
2
- //
3
- // Gesture composition API (project plan, Phase 7), main-thread only. Built
4
- // on __SetGestureDetector — a plain, same-thread PAPI call (no cross-thread
5
- // serialization boundary), so this needs nothing beyond a real node handle
6
- // PLUS the small worklet-registration step below. A callback that needs to
7
- // notify background-owned state can call main-thread.js's
8
- // runOnBackground() itself, inside the callback body — an explicit, opt-in
9
- // cross-thread hop only where the app actually needs one.
10
- //
11
- // RESOLVED (2026-09-09), via the SAME technique used to fix list.js's Tier
12
- // 2 (read the real, shipped @lynx-js/react source more deeply — see
13
- // DEVICE_VERIFICATION.md), plus one config-level bug found the hard way.
14
- // THREE issues stacked here, found and fixed in this order:
15
- //
16
- // 1. The config/relationMap shape below matches @lynx-js/react's own
17
- // runtime/lib/snapshot/gesture/processGesture.js verbatim (real, shipped
18
- // code — __SetGestureDetector for both create and update, has-react-
19
- // gesture/flatten set first). But that file's own callback slot type is
20
- // loose (`callback: unknown`) — reading one file deeper,
21
- // runtime/lib/worklet-runtime/workletRuntime.js, revealed native invokes
22
- // gesture callbacks through a global `runWorklet(ctx, params)`, whose
23
- // `validateWorklet(ctx)` requires `typeof ctx === 'object'`. A plain JS
24
- // function fails that and is dropped with NO error — exactly this
25
- // project's first real-device symptom (zero console output on a swipe).
26
- // Fixed by `./src/worklet-runtime.js`'s `wrapWorkletCallback()`.
27
- // 2. Even with (1) fixed, still zero output — because `enableNewGesture`
28
- // (a Lynx SDK compiler/runtime option, @lynx-js/type-config's
29
- // config.d.ts, `@defaultValue false`) was never turned on for this app.
30
- // Without it, __SetGestureDetector registrations are accepted but the
31
- // runtime keeps using "the legacy touch-only gesture path" and never
32
- // acts on them at all — see the consuming app's lynx.config.ts.
33
- // 3. With both fixed, native finally called into JS — and immediately threw
34
- // `TypeError: not a object`. Bisected step-by-step on-device: native
35
- // calls a gesture callback with TWO arguments, `(event, controller)`,
36
- // where `controller` is a native host object (`{__SetGestureState,
37
- // __ConsumeGesture}`). That object throws when it crosses
38
- // `Function.prototype.apply()`'s argument-list marshalling, but is fine
39
- // passed positionally — matching @lynx-js/react's own runWorkletImpl,
40
- // which never uses apply()/call() either (`worklet(...params_)`, a
41
- // plain spread call). Fixed in `./src/worklet-runtime.js`.
42
- //
43
- // Confirmed end-to-end on the real device: a full pan (start → update →
44
- // end) updates UI state with zero errors. See `./src/worklet-runtime.js`
45
- // for exactly what's reimplemented vs. scoped out of the real worklet
46
- // runtime, and `callbacks`' new second-argument note below.
47
-
48
- import { wrapWorkletCallback } from "./src/worklet-runtime.js";
49
-
50
- export const GestureType = {
51
- COMPOSED: -1,
52
- PAN: 0,
53
- FLING: 1,
54
- DEFAULT: 2,
55
- TAP: 3,
56
- LONGPRESS: 4,
57
- ROTATION: 5,
58
- PINCH: 6,
59
- NATIVE: 7,
60
- };
61
-
62
- let nextGestureId = 1;
63
-
64
- /**
65
- * Registers a gesture detector on `node` (anything with a `_handle`, i.e. a
66
- * real LynxNodeWrapper). `type` is a GestureType value or its string key
67
- * ("pan", "tap", ...). `callbacks` keys are event names (e.g. "onStart",
68
- * "onUpdate", "onEnd") mapped to plain functions, called directly, same
69
- * thread. Each is invoked as `(event, controller) => {}` — `controller`
70
- * (`{__SetGestureState, __ConsumeGesture}`) is a native gesture-arena
71
- * handle; most callbacks can ignore it entirely.
72
- * `waitFor`/`simultaneousWith`/`continueWith` are arrays of OTHER
73
- * createGesture() return values, for gesture-arena composition.
74
- */
75
- export function createGesture(node, options) {
76
- const {
77
- type,
78
- callbacks = {},
79
- waitFor = [],
80
- simultaneousWith = [],
81
- continueWith = [],
82
- config,
83
- } = options;
84
- const handle = node._handle;
85
- const gestureType = typeof type === "string" ? GestureType[type.toUpperCase()] : type;
86
- const id = nextGestureId++;
87
-
88
- // Marker attributes native needs to recognize a gesture-enabled element —
89
- // kept verbatim from processGesture.js's own names/values, since it's
90
- // unclear whether native checks these exact strings independent of
91
- // framework, or whether they're purely a ReactLynx-side bookkeeping detail.
92
- __SetAttribute(handle, "has-react-gesture", true);
93
- __SetAttribute(handle, "flatten", false);
94
-
95
- const detectorConfig = {
96
- callbacks: Object.keys(callbacks).map((name) => ({ name, callback: wrapWorkletCallback(callbacks[name]) })),
97
- };
98
- if (config != null) detectorConfig.config = config;
99
-
100
- const relationMap = {
101
- waitFor: waitFor.map((g) => g.id),
102
- simultaneous: simultaneousWith.map((g) => g.id),
103
- continueWith: continueWith.map((g) => g.id),
104
- };
105
-
106
- __SetGestureDetector(handle, id, gestureType, detectorConfig, relationMap);
107
-
108
- return {
109
- id,
110
- remove() {
111
- if (typeof __RemoveGestureDetector === "function") __RemoveGestureDetector(handle, id);
112
- },
113
- setState(state) {
114
- __SetGestureState(handle, id, state);
115
- },
116
- };
117
- }
@@ -1,26 +0,0 @@
1
- // Shared event-name constants for the main-thread <-> background-thread
2
- // channel, ported from lynx-examples/examples/vanilla/src/common/constant.ts.
3
- // Native engine lifecycle events keep their exact native names; custom
4
- // app-level events are namespaced to avoid colliding with other libraries
5
- // dispatching on the same shared event bus.
6
-
7
- export const renderPageEventName = "__RenderPage";
8
- export const updatePageEventName = "__UpdatePage";
9
- export const destroyLifetimeEventName = "__DestroyLifetime";
10
-
11
- export const updateDataFromMainThreadEventName = "MithrilLynx:UpdateDataFromMainThread";
12
- export const updateDataFromBackgroundEventName = "MithrilLynx:UpdateDataFromBackground";
13
- export const dispatchEventToBackgroundEventName = "MithrilLynx:DispatchEventToBackground";
14
-
15
- // Renderer mode (Phase 4): background thread ships op-log patches to main
16
- // thread; main thread forwards real PAPI events back to background by vid.
17
- export const rendererPatchEventName = "MithrilLynx:RendererPatch";
18
- export const rendererEventEventName = "MithrilLynx:RendererEvent";
19
-
20
- // Cross-thread function registry (Phase 6, worklet substitute): call/return
21
- // correlation for genuinely cross-thread calls. "ToMainThread"/"ToBackground"
22
- // name which side the CALL travels to — each has its own result event.
23
- export const callMainThreadEventName = "MithrilLynx:CallMainThread";
24
- export const callMainThreadResultEventName = "MithrilLynx:CallMainThreadResult";
25
- export const callBackgroundEventName = "MithrilLynx:CallBackground";
26
- export const callBackgroundResultEventName = "MithrilLynx:CallBackgroundResult";