react-native-gtkx 0.2.0-alpha.1 → 0.2.0-alpha.2
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 +11 -2
- package/dist/adw/widgets.generated.d.ts +4 -4
- package/dist/adw/widgets.generated.js +51 -51
- package/dist/adw/widgets.generated.js.map +1 -1
- package/dist/animated/create-animated.d.ts +2 -0
- package/dist/animated/create-animated.js +2 -0
- package/dist/animated/create-animated.js.map +1 -1
- package/dist/animated/index.d.ts +2 -0
- package/dist/animated/index.js +1 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/value-xy.d.ts +41 -0
- package/dist/animated/value-xy.js +90 -0
- package/dist/animated/value-xy.js.map +1 -0
- package/dist/animated/value.d.ts +9 -0
- package/dist/animated/value.js +30 -2
- package/dist/animated/value.js.map +1 -1
- package/dist/common/icon.d.ts +23 -0
- package/dist/common/icon.js +14 -0
- package/dist/common/icon.js.map +1 -0
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.js +2 -0
- package/dist/common/index.js.map +1 -1
- package/dist/common/list.d.ts +82 -0
- package/dist/common/list.js +166 -0
- package/dist/common/list.js.map +1 -0
- package/dist/common/widget.d.ts +1 -22
- package/dist/common/widget.js +75 -8
- package/dist/common/widget.js.map +1 -1
- package/dist/components/animated.d.ts +4 -2
- package/dist/components/animated.js +3 -1
- package/dist/components/animated.js.map +1 -1
- package/dist/components/app-registry.d.ts +26 -0
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/host-node.d.ts +7 -0
- package/dist/components/host-node.js +26 -1
- package/dist/components/host-node.js.map +1 -1
- package/dist/components/index.d.ts +6 -2
- package/dist/components/index.js +2 -1
- package/dist/components/index.js.map +1 -1
- package/dist/components/measure.d.ts +13 -0
- package/dist/components/measure.js +51 -0
- package/dist/components/measure.js.map +1 -0
- package/dist/components/modal.d.ts +1 -1
- package/dist/components/press-event.d.ts +28 -0
- package/dist/components/press-event.js +46 -0
- package/dist/components/press-event.js.map +1 -0
- package/dist/components/pressable.d.ts +2 -6
- package/dist/components/pressable.js +14 -8
- package/dist/components/pressable.js.map +1 -1
- package/dist/components/scroll-view.d.ts +4 -0
- package/dist/components/scroll-view.js +8 -2
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/text-input.js +1 -1
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/text.js +25 -1
- package/dist/components/text.js.map +1 -1
- package/dist/components/use-layout-child.js +17 -14
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/view.d.ts +9 -4
- package/dist/components/view.js +8 -2
- package/dist/components/view.js.map +1 -1
- package/dist/contracts.d.ts +19 -3
- package/dist/contracts.js.map +1 -1
- package/dist/gtk/index.d.ts +2 -1
- package/dist/gtk/index.js +8 -1
- package/dist/gtk/index.js.map +1 -1
- package/dist/gtk/widgets.generated.d.ts +14 -14
- package/dist/gtk/widgets.generated.js +101 -102
- package/dist/gtk/widgets.generated.js.map +1 -1
- package/dist/gtk/window-actions.d.ts +77 -0
- package/dist/gtk/window-actions.js +193 -0
- package/dist/gtk/window-actions.js.map +1 -0
- package/dist/gtkx/bridge/geometry.d.ts +15 -0
- package/dist/gtkx/bridge/geometry.js +38 -0
- package/dist/gtkx/bridge/geometry.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +2 -0
- package/dist/gtkx/bridge/index.js +7 -2
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/slot-portal.d.ts +12 -0
- package/dist/gtkx/bridge/slot-portal.js +17 -0
- package/dist/gtkx/bridge/slot-portal.js.map +1 -0
- package/dist/gtkx/bridge/svg-node.js +10 -54
- package/dist/gtkx/bridge/svg-node.js.map +1 -1
- package/dist/gtkx/bridge/use-signal.js +2 -2
- package/dist/gtkx/bridge/use-signal.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +99 -77
- package/dist/mcp/data/generated.js +107 -76
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/navigation/sidebar.d.ts +31 -1
- package/dist/navigation/sidebar.js +12 -2
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/responder/system.d.ts +27 -0
- package/dist/responder/system.js +184 -0
- package/dist/responder/system.js.map +1 -0
- package/dist/responder/touch-history.d.ts +10 -0
- package/dist/responder/touch-history.js +78 -0
- package/dist/responder/touch-history.js.map +1 -0
- package/dist/responder/types.d.ts +63 -0
- package/dist/responder/types.js +29 -0
- package/dist/responder/types.js.map +1 -0
- package/dist/responder/use-responder.d.ts +12 -0
- package/dist/responder/use-responder.js +98 -0
- package/dist/responder/use-responder.js.map +1 -0
- package/dist/runner/host-dev.js +3 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +5 -1
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.js +1 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/sea/gtkx-config-module.js +1 -1
- package/dist/sea/gtkx-config-module.js.map +1 -1
- package/dist/style/box-shadow.d.ts +7 -0
- package/dist/style/box-shadow.js +197 -0
- package/dist/style/box-shadow.js.map +1 -0
- package/dist/style/index.d.ts +2 -0
- package/dist/style/index.js +2 -0
- package/dist/style/index.js.map +1 -1
- package/dist/style/split-style.d.ts +5 -2
- package/dist/style/split-style.js +31 -3
- package/dist/style/split-style.js.map +1 -1
- package/dist/style/text-decoration.d.ts +15 -0
- package/dist/style/text-decoration.js +26 -0
- package/dist/style/text-decoration.js.map +1 -0
- package/dist/style/visual-css.js +37 -1
- package/dist/style/visual-css.js.map +1 -1
- package/dist/svg/gradient-geometry.js +2 -5
- package/dist/svg/gradient-geometry.js.map +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/vendor/react-native/pan-responder.d.ts +102 -0
- package/dist/vendor/react-native/pan-responder.js +196 -0
- package/dist/vendor/react-native/pan-responder.js.map +1 -0
- package/dist/vendor/react-native/touch-history-math.d.ts +18 -0
- package/dist/vendor/react-native/touch-history-math.js +102 -0
- package/dist/vendor/react-native/touch-history-math.js.map +1 -0
- package/dist/vite/index.js +1 -1
- package/dist/vite/index.js.map +1 -1
- package/dist/vitest/index.d.ts +1 -1
- package/dist/vitest/index.js.map +1 -1
- package/package.json +9 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/responder/system.ts"],"names":[],"mappings":"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","sourcesContent":["// RN's Gesture Responder System: the negotiation, in pure JS.\n//\n// Zero @gtkx imports on purpose. Everything platform-specific enters through\n// two seams — `parentOf`, which turns a host handle into its parent, and the\n// grant/release notifications the platform uses to make its one-way GTK\n// claim. That keeps the algorithm unit-testable off Linux, which matters\n// because this is the part that is subtle and the part every platform\n// historically gets wrong.\n//\n// Why reimplemented rather than reused: every other RN platform feeds\n// `topTouchStart/Move/End/Cancel` to the stock renderer's\n// ResponderEventPlugin, which lives in `facebook/react` inside\n// `react-native-renderer`. We render through `@gtkx/react` on\n// `react-reconciler`, so there is no plugin seam to feed —\n// react-native-web is in the same position and reimplemented for the same\n// reason (docs/research/gestures.md).\nimport type { NativeTouch } from \"../components/press-event\"\nimport {\n createTouchHistory,\n recordTouchEnd,\n recordTouchMove,\n recordTouchStart,\n refreshActiveTouches,\n} from \"./touch-history\"\nimport type { GestureResponderEvent, ResponderProps } from \"./types\"\n\n/** An opaque platform handle. A Gtk.Widget in practice; never treated as one. */\nexport type ResponderHost = object\n\nexport type ResponderSystemOptions = {\n /** The platform's parent link. Returning null ends the path. */\n parentOf: (host: ResponderHost) => ResponderHost | null\n /**\n * Fired after a node is granted the responder — where the platform makes\n * its GTK `CLAIMED` declaration. One-way by construction: GTK has no way\n * to hand a claimed sequence back, so this is only ever called once JS has\n * already decided (docs/research/gestures.md, \"no voluntary release\").\n */\n onGrant?: (host: ResponderHost) => void\n /** Fired when the responder is released or terminated. */\n onRelease?: (host: ResponderHost) => void\n}\n\ntype Registration = { getProps: () => ResponderProps }\n\n// One interaction, from press to release. v1 is single-pointer: a mouse is\n// one fabricated touch, so at most one session exists at a time. It also\n// does the deduplicating — GTK delivers a press to every ancestor's gesture\n// in the bubble chain, so the second and later reports for the same press\n// find a session already open and return.\ntype Session = { host: ResponderHost; identifier: number }\n\nexport type ResponderSystem = {\n register(host: ResponderHost, getProps: () => ResponderProps): () => void\n touchStart(host: ResponderHost, touch: NativeTouch): void\n touchMove(host: ResponderHost, touch: NativeTouch): void\n touchEnd(host: ResponderHost, touch: NativeTouch): void\n touchCancel(host: ResponderHost, touch: NativeTouch): void\n /** The node currently holding the responder, or null. */\n getResponder(): ResponderHost | null\n}\n\ntype ShouldSetName =\n | \"onStartShouldSetResponder\"\n | \"onStartShouldSetResponderCapture\"\n | \"onMoveShouldSetResponder\"\n | \"onMoveShouldSetResponderCapture\"\n\ntype NotifyName =\n | \"onResponderGrant\"\n | \"onResponderStart\"\n | \"onResponderMove\"\n | \"onResponderEnd\"\n | \"onResponderRelease\"\n | \"onResponderTerminate\"\n | \"onResponderReject\"\n\ntype TouchName =\n | \"onTouchStart\"\n | \"onTouchStartCapture\"\n | \"onTouchMove\"\n | \"onTouchMoveCapture\"\n | \"onTouchEnd\"\n | \"onTouchEndCapture\"\n | \"onTouchCancel\"\n | \"onTouchCancelCapture\"\n\nexport const createResponderSystem = (\n options: ResponderSystemOptions,\n): ResponderSystem => {\n const registry = new Map<ResponderHost, Registration>()\n const history = createTouchHistory()\n let responder: ResponderHost | null = null\n let session: Session | null = null\n\n /**\n * The registered nodes from the toplevel down to `host`, root first — RN's\n * capture order, reversed for bubble.\n *\n * The walk stops wherever `parentOf` stops, which on this platform is the\n * layout Root: an RN tree here is an island inside a native GTK widget\n * tree (NestedRoot/IntrinsicRoot mount engines into arbitrary GTK slots),\n * so there is no single app-wide view hierarchy to traverse. Native\n * widgets on the way up are simply not registered and take no part.\n */\n const pathOf = (host: ResponderHost): ResponderHost[] => {\n const path: ResponderHost[] = []\n let current: ResponderHost | null = host\n while (current) {\n if (registry.has(current)) {\n path.unshift(current)\n }\n current = options.parentOf(current)\n }\n return path\n }\n\n const propsOf = (host: ResponderHost): ResponderProps | null =>\n registry.get(host)?.getProps() ?? null\n\n const createEvent = (\n touch: NativeTouch,\n stillDown: boolean,\n ): GestureResponderEvent => ({\n nativeEvent: {\n ...touch,\n // Single-pointer: `touches` is the still-active set (empty once the\n // pointer is up), `changedTouches` is always this one.\n touches: stillDown ? [touch] : [],\n changedTouches: [touch],\n },\n touchHistory: history,\n })\n\n /**\n * Runs a should-set handler over `path` in order, stopping at the first\n * that returns true — RN's executeDispatchesInOrderStopAtTrue. Handlers\n * before the winner all run, which PanResponder depends on: its capture\n * handlers are where gestureState is initialised and where dx/dy are\n * accumulated on move.\n */\n const firstToClaim = (\n path: readonly ResponderHost[],\n name: ShouldSetName,\n event: GestureResponderEvent,\n ): ResponderHost | null => {\n for (const host of path) {\n const handler = propsOf(host)?.[name]\n if (handler?.(event) === true) {\n return host\n }\n }\n return null\n }\n\n const notify = (\n host: ResponderHost,\n name: NotifyName,\n event: GestureResponderEvent,\n ): void => {\n propsOf(host)?.[name]?.(event)\n }\n\n const dispatchTouch = (\n path: readonly ResponderHost[],\n captureName: TouchName,\n bubbleName: TouchName,\n event: GestureResponderEvent,\n ): void => {\n for (const host of path) {\n propsOf(host)?.[captureName]?.(event)\n }\n for (let i = path.length - 1; i >= 0; i -= 1) {\n propsOf(path[i]!)?.[bubbleName]?.(event)\n }\n }\n\n const grant = (\n host: ResponderHost,\n event: GestureResponderEvent,\n fromStart: boolean,\n ): void => {\n responder = host\n notify(host, \"onResponderGrant\", event)\n if (fromStart) {\n notify(host, \"onResponderStart\", event)\n }\n options.onGrant?.(host)\n }\n\n /**\n * Capture root-to-target, then bubble target-to-root — RN's two-phase\n * negotiation, and the one place GTK's model and RN's agree, since GTK's\n * CAPTURE/TARGET/BUBBLE phases run in exactly this order. We still do the\n * walk ourselves so a single GTK event source can drive the whole path.\n */\n const negotiate = (\n path: readonly ResponderHost[],\n event: GestureResponderEvent,\n phase: \"start\" | \"move\",\n ): ResponderHost | null => {\n const capture =\n phase === \"start\"\n ? \"onStartShouldSetResponderCapture\"\n : \"onMoveShouldSetResponderCapture\"\n const bubble =\n phase === \"start\"\n ? \"onStartShouldSetResponder\"\n : \"onMoveShouldSetResponder\"\n const captured = firstToClaim(path, capture, event)\n if (captured) {\n return captured\n }\n return firstToClaim([...path].reverse(), bubble, event)\n }\n\n const finish = (\n touch: NativeTouch,\n terminated: boolean,\n touchProps: [TouchName, TouchName],\n ): void => {\n const current = session\n if (!current) {\n return\n }\n recordTouchEnd(history, touch)\n refreshActiveTouches(history)\n const event = createEvent(touch, false)\n dispatchTouch(pathOf(current.host), touchProps[0], touchProps[1], event)\n\n const holder = responder\n session = null\n responder = null\n if (holder) {\n notify(holder, \"onResponderEnd\", event)\n notify(\n holder,\n terminated ? \"onResponderTerminate\" : \"onResponderRelease\",\n event,\n )\n options.onRelease?.(holder)\n }\n }\n\n return {\n register(host, getProps) {\n registry.set(host, { getProps })\n return () => {\n registry.delete(host)\n // A responder that unmounts mid-gesture cannot be asked anything\n // ever again; drop the lock rather than stranding it.\n if (responder === host) {\n responder = null\n }\n if (session?.host === host) {\n session = null\n }\n }\n },\n\n touchStart(host, touch) {\n // Already tracking this press: this is an ancestor's gesture seeing the\n // same event through GTK's bubble chain.\n if (session !== null) {\n return\n }\n session = { host, identifier: touch.identifier }\n recordTouchStart(history, touch)\n refreshActiveTouches(history)\n\n const path = pathOf(host)\n const event = createEvent(touch, true)\n dispatchTouch(path, \"onTouchStartCapture\", \"onTouchStart\", event)\n\n if (responder !== null) {\n return\n }\n const winner = negotiate(path, event, \"start\")\n if (winner) {\n grant(winner, event, true)\n }\n },\n\n touchMove(host, touch) {\n if (session === null || session.host !== host) {\n return\n }\n recordTouchMove(history, touch)\n refreshActiveTouches(history)\n\n const path = pathOf(host)\n const event = createEvent(touch, true)\n dispatchTouch(path, \"onTouchMoveCapture\", \"onTouchMove\", event)\n\n if (responder === null) {\n // The common PanResponder shape: nothing claims on press, and the\n // pan starts once onMoveShouldSetPanResponder sees enough movement.\n const winner = negotiate(path, event, \"move\")\n if (winner) {\n grant(winner, event, false)\n }\n return\n }\n // v1 deliberately does not renegotiate while a responder holds: GTK\n // cannot revoke a claim, so a transfer we cannot enforce natively would\n // be a lie at the boundary with native widgets. Tracked as task 002b.\n notify(responder, \"onResponderMove\", event)\n },\n\n touchEnd(host, touch) {\n if (session === null || session.host !== host) {\n return\n }\n finish(touch, false, [\"onTouchEndCapture\", \"onTouchEnd\"])\n },\n\n touchCancel(host, touch) {\n if (session === null || session.host !== host) {\n return\n }\n finish(touch, true, [\"onTouchCancelCapture\", \"onTouchCancel\"])\n },\n\n getResponder: () => responder,\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NativeTouch, TouchHistory } from "./types";
|
|
2
|
+
export declare const createTouchHistory: () => TouchHistory;
|
|
3
|
+
export declare const recordTouchStart: (history: TouchHistory, touch: NativeTouch) => void;
|
|
4
|
+
export declare const recordTouchMove: (history: TouchHistory, touch: NativeTouch) => void;
|
|
5
|
+
export declare const recordTouchEnd: (history: TouchHistory, touch: NativeTouch) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Recomputes `numberActiveTouches` and `indexOfSingleActiveTouch` — the two
|
|
8
|
+
* derived fields TouchHistoryMath's single-touch fast path reads.
|
|
9
|
+
*/
|
|
10
|
+
export declare const refreshActiveTouches: (history: TouchHistory) => void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const createTouchHistory = () => ({
|
|
2
|
+
touchBank: [],
|
|
3
|
+
numberActiveTouches: 0,
|
|
4
|
+
indexOfSingleActiveTouch: -1,
|
|
5
|
+
mostRecentTimeStamp: 0,
|
|
6
|
+
});
|
|
7
|
+
export const recordTouchStart = (history, touch) => {
|
|
8
|
+
const identifier = touch.identifier;
|
|
9
|
+
const existing = history.touchBank[identifier];
|
|
10
|
+
if (existing) {
|
|
11
|
+
existing.touchActive = true;
|
|
12
|
+
existing.startPageX = touch.pageX;
|
|
13
|
+
existing.startPageY = touch.pageY;
|
|
14
|
+
existing.startTimeStamp = touch.timestamp;
|
|
15
|
+
existing.currentPageX = touch.pageX;
|
|
16
|
+
existing.currentPageY = touch.pageY;
|
|
17
|
+
existing.currentTimeStamp = touch.timestamp;
|
|
18
|
+
existing.previousPageX = touch.pageX;
|
|
19
|
+
existing.previousPageY = touch.pageY;
|
|
20
|
+
existing.previousTimeStamp = touch.timestamp;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const record = {
|
|
24
|
+
touchActive: true,
|
|
25
|
+
startPageX: touch.pageX,
|
|
26
|
+
startPageY: touch.pageY,
|
|
27
|
+
startTimeStamp: touch.timestamp,
|
|
28
|
+
currentPageX: touch.pageX,
|
|
29
|
+
currentPageY: touch.pageY,
|
|
30
|
+
currentTimeStamp: touch.timestamp,
|
|
31
|
+
previousPageX: touch.pageX,
|
|
32
|
+
previousPageY: touch.pageY,
|
|
33
|
+
previousTimeStamp: touch.timestamp,
|
|
34
|
+
};
|
|
35
|
+
history.touchBank[identifier] = record;
|
|
36
|
+
}
|
|
37
|
+
history.mostRecentTimeStamp = touch.timestamp;
|
|
38
|
+
};
|
|
39
|
+
const recordTouchMoveOrEnd = (history, touch, stillActive) => {
|
|
40
|
+
const record = history.touchBank[touch.identifier];
|
|
41
|
+
if (!record) {
|
|
42
|
+
// Upstream warns here. A move without a start means the event source and
|
|
43
|
+
// the store disagree, which is a bug in the caller, not a user error.
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
record.touchActive = stillActive;
|
|
47
|
+
record.previousPageX = record.currentPageX;
|
|
48
|
+
record.previousPageY = record.currentPageY;
|
|
49
|
+
record.previousTimeStamp = record.currentTimeStamp;
|
|
50
|
+
record.currentPageX = touch.pageX;
|
|
51
|
+
record.currentPageY = touch.pageY;
|
|
52
|
+
record.currentTimeStamp = touch.timestamp;
|
|
53
|
+
history.mostRecentTimeStamp = touch.timestamp;
|
|
54
|
+
};
|
|
55
|
+
export const recordTouchMove = (history, touch) => {
|
|
56
|
+
recordTouchMoveOrEnd(history, touch, true);
|
|
57
|
+
};
|
|
58
|
+
export const recordTouchEnd = (history, touch) => {
|
|
59
|
+
recordTouchMoveOrEnd(history, touch, false);
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Recomputes `numberActiveTouches` and `indexOfSingleActiveTouch` — the two
|
|
63
|
+
* derived fields TouchHistoryMath's single-touch fast path reads.
|
|
64
|
+
*/
|
|
65
|
+
export const refreshActiveTouches = (history) => {
|
|
66
|
+
let active = 0;
|
|
67
|
+
let singleIndex = -1;
|
|
68
|
+
for (let i = 0; i < history.touchBank.length; i += 1) {
|
|
69
|
+
const record = history.touchBank[i];
|
|
70
|
+
if (record?.touchActive) {
|
|
71
|
+
active += 1;
|
|
72
|
+
singleIndex = i;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
history.numberActiveTouches = active;
|
|
76
|
+
history.indexOfSingleActiveTouch = active === 1 ? singleIndex : -1;
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=touch-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"touch-history.js","sourceRoot":"","sources":["../../src/responder/touch-history.ts"],"names":[],"mappings":"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","sourcesContent":["// The touch-history store, transcribed from RN's ResponderTouchHistoryStore\n// so the vendored PanResponder runs against it unmodified.\n//\n// Everything here is deliberately mechanical. The three-way split — start /\n// previous / current — is what makes velocity and clustered multi-touch\n// accumulation computable at all, and \"previous\" specifically means the\n// value before THIS event, not one frame ago. Collapsing any of it would\n// break TouchHistoryMath in ways that only show up as a subtly wrong vx.\nimport type { NativeTouch, TouchHistory, TouchRecord } from \"./types\"\n\nexport const createTouchHistory = (): TouchHistory => ({\n touchBank: [],\n numberActiveTouches: 0,\n indexOfSingleActiveTouch: -1,\n mostRecentTimeStamp: 0,\n})\n\nexport const recordTouchStart = (\n history: TouchHistory,\n touch: NativeTouch,\n): void => {\n const identifier = touch.identifier\n const existing = history.touchBank[identifier]\n if (existing) {\n existing.touchActive = true\n existing.startPageX = touch.pageX\n existing.startPageY = touch.pageY\n existing.startTimeStamp = touch.timestamp\n existing.currentPageX = touch.pageX\n existing.currentPageY = touch.pageY\n existing.currentTimeStamp = touch.timestamp\n existing.previousPageX = touch.pageX\n existing.previousPageY = touch.pageY\n existing.previousTimeStamp = touch.timestamp\n } else {\n const record: TouchRecord = {\n touchActive: true,\n startPageX: touch.pageX,\n startPageY: touch.pageY,\n startTimeStamp: touch.timestamp,\n currentPageX: touch.pageX,\n currentPageY: touch.pageY,\n currentTimeStamp: touch.timestamp,\n previousPageX: touch.pageX,\n previousPageY: touch.pageY,\n previousTimeStamp: touch.timestamp,\n }\n history.touchBank[identifier] = record\n }\n history.mostRecentTimeStamp = touch.timestamp\n}\n\nconst recordTouchMoveOrEnd = (\n history: TouchHistory,\n touch: NativeTouch,\n stillActive: boolean,\n): void => {\n const record = history.touchBank[touch.identifier]\n if (!record) {\n // Upstream warns here. A move without a start means the event source and\n // the store disagree, which is a bug in the caller, not a user error.\n return\n }\n record.touchActive = stillActive\n record.previousPageX = record.currentPageX\n record.previousPageY = record.currentPageY\n record.previousTimeStamp = record.currentTimeStamp\n record.currentPageX = touch.pageX\n record.currentPageY = touch.pageY\n record.currentTimeStamp = touch.timestamp\n history.mostRecentTimeStamp = touch.timestamp\n}\n\nexport const recordTouchMove = (\n history: TouchHistory,\n touch: NativeTouch,\n): void => {\n recordTouchMoveOrEnd(history, touch, true)\n}\n\nexport const recordTouchEnd = (\n history: TouchHistory,\n touch: NativeTouch,\n): void => {\n recordTouchMoveOrEnd(history, touch, false)\n}\n\n/**\n * Recomputes `numberActiveTouches` and `indexOfSingleActiveTouch` — the two\n * derived fields TouchHistoryMath's single-touch fast path reads.\n */\nexport const refreshActiveTouches = (history: TouchHistory): void => {\n let active = 0\n let singleIndex = -1\n for (let i = 0; i < history.touchBank.length; i += 1) {\n const record = history.touchBank[i]\n if (record?.touchActive) {\n active += 1\n singleIndex = i\n }\n }\n history.numberActiveTouches = active\n history.indexOfSingleActiveTouch = active === 1 ? singleIndex : -1\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { NativeTouch, PressEvent } from "../components/press-event";
|
|
2
|
+
/** One tracked touch. Field names are RN's; do not "tidy" them. */
|
|
3
|
+
export type TouchRecord = {
|
|
4
|
+
touchActive: boolean;
|
|
5
|
+
startPageX: number;
|
|
6
|
+
startPageY: number;
|
|
7
|
+
startTimeStamp: number;
|
|
8
|
+
currentPageX: number;
|
|
9
|
+
currentPageY: number;
|
|
10
|
+
currentTimeStamp: number;
|
|
11
|
+
previousPageX: number;
|
|
12
|
+
previousPageY: number;
|
|
13
|
+
previousTimeStamp: number;
|
|
14
|
+
};
|
|
15
|
+
export type TouchHistory = {
|
|
16
|
+
touchBank: TouchRecord[];
|
|
17
|
+
numberActiveTouches: number;
|
|
18
|
+
indexOfSingleActiveTouch: number;
|
|
19
|
+
mostRecentTimeStamp: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* What every responder callback receives. PanResponder reads `touchHistory`
|
|
23
|
+
* off the EVENT, not off `nativeEvent` — an easy detail to get wrong, and it
|
|
24
|
+
* silently zeroes every gesture if you do.
|
|
25
|
+
*/
|
|
26
|
+
export type GestureResponderEvent = PressEvent & {
|
|
27
|
+
touchHistory: TouchHistory;
|
|
28
|
+
};
|
|
29
|
+
export type ShouldSetResponder = (event: GestureResponderEvent) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* RN's responder and touch props. The touch props fire regardless of who
|
|
32
|
+
* holds the responder; the rest are the negotiation.
|
|
33
|
+
*/
|
|
34
|
+
export type ResponderProps = {
|
|
35
|
+
onStartShouldSetResponder?: ShouldSetResponder;
|
|
36
|
+
onStartShouldSetResponderCapture?: ShouldSetResponder;
|
|
37
|
+
onMoveShouldSetResponder?: ShouldSetResponder;
|
|
38
|
+
onMoveShouldSetResponderCapture?: ShouldSetResponder;
|
|
39
|
+
onResponderGrant?: (event: GestureResponderEvent) => void | boolean;
|
|
40
|
+
onResponderStart?: (event: GestureResponderEvent) => void;
|
|
41
|
+
onResponderMove?: (event: GestureResponderEvent) => void;
|
|
42
|
+
onResponderEnd?: (event: GestureResponderEvent) => void;
|
|
43
|
+
onResponderRelease?: (event: GestureResponderEvent) => void;
|
|
44
|
+
onResponderTerminate?: (event: GestureResponderEvent) => void;
|
|
45
|
+
onResponderTerminationRequest?: ShouldSetResponder;
|
|
46
|
+
onResponderReject?: (event: GestureResponderEvent) => void;
|
|
47
|
+
onTouchStart?: (event: GestureResponderEvent) => void;
|
|
48
|
+
onTouchStartCapture?: (event: GestureResponderEvent) => void;
|
|
49
|
+
onTouchMove?: (event: GestureResponderEvent) => void;
|
|
50
|
+
onTouchMoveCapture?: (event: GestureResponderEvent) => void;
|
|
51
|
+
onTouchEnd?: (event: GestureResponderEvent) => void;
|
|
52
|
+
onTouchEndCapture?: (event: GestureResponderEvent) => void;
|
|
53
|
+
onTouchCancel?: (event: GestureResponderEvent) => void;
|
|
54
|
+
onTouchCancelCapture?: (event: GestureResponderEvent) => void;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Whether a component needs an event source at all. A View with no responder
|
|
58
|
+
* props gets no GTK controller: RN only ever asks views that declare
|
|
59
|
+
* handlers, so attaching one everywhere would be pure cost.
|
|
60
|
+
*/
|
|
61
|
+
export declare const hasResponderProps: (props: ResponderProps) => boolean;
|
|
62
|
+
/** A single touch as PanResponder's `touches`/`changedTouches` see it. */
|
|
63
|
+
export type { NativeTouch };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const RESPONDER_PROP_NAMES = [
|
|
2
|
+
"onStartShouldSetResponder",
|
|
3
|
+
"onStartShouldSetResponderCapture",
|
|
4
|
+
"onMoveShouldSetResponder",
|
|
5
|
+
"onMoveShouldSetResponderCapture",
|
|
6
|
+
"onResponderGrant",
|
|
7
|
+
"onResponderStart",
|
|
8
|
+
"onResponderMove",
|
|
9
|
+
"onResponderEnd",
|
|
10
|
+
"onResponderRelease",
|
|
11
|
+
"onResponderTerminate",
|
|
12
|
+
"onResponderTerminationRequest",
|
|
13
|
+
"onResponderReject",
|
|
14
|
+
"onTouchStart",
|
|
15
|
+
"onTouchStartCapture",
|
|
16
|
+
"onTouchMove",
|
|
17
|
+
"onTouchMoveCapture",
|
|
18
|
+
"onTouchEnd",
|
|
19
|
+
"onTouchEndCapture",
|
|
20
|
+
"onTouchCancel",
|
|
21
|
+
"onTouchCancelCapture",
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Whether a component needs an event source at all. A View with no responder
|
|
25
|
+
* props gets no GTK controller: RN only ever asks views that declare
|
|
26
|
+
* handlers, so attaching one everywhere would be pure cost.
|
|
27
|
+
*/
|
|
28
|
+
export const hasResponderProps = (props) => RESPONDER_PROP_NAMES.some((name) => props[name] !== undefined);
|
|
29
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/responder/types.ts"],"names":[],"mappings":"AA2EA,MAAM,oBAAoB,GAAG;IAC3B,2BAA2B;IAC3B,kCAAkC;IAClC,0BAA0B;IAC1B,iCAAiC;IACjC,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,oBAAoB;IACpB,sBAAsB;IACtB,+BAA+B;IAC/B,mBAAmB;IACnB,cAAc;IACd,qBAAqB;IACrB,aAAa;IACb,oBAAoB;IACpB,YAAY;IACZ,mBAAmB;IACnB,eAAe;IACf,sBAAsB;CAC8B,CAAA;AAEtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAqB,EAAW,EAAE,CAClE,oBAAoB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAA","sourcesContent":["// The responder system's public vocabulary: the touch-history shape RN's\n// PanResponder expects, and the props a View accepts.\n//\n// The touch-history shape is not ours to design. react-native-web proved\n// that RN's own PanResponder runs unmodified on a foreign platform provided\n// this structure is reproduced exactly — field for field, including the\n// three-way current/previous/start split and the millisecond timestamps —\n// so it is transcribed from ResponderTouchHistoryStore rather than invented.\nimport type { NativeTouch, PressEvent } from \"../components/press-event\"\n\n/** One tracked touch. Field names are RN's; do not \"tidy\" them. */\nexport type TouchRecord = {\n touchActive: boolean\n startPageX: number\n startPageY: number\n startTimeStamp: number\n currentPageX: number\n currentPageY: number\n currentTimeStamp: number\n previousPageX: number\n previousPageY: number\n previousTimeStamp: number\n}\n\nexport type TouchHistory = {\n // Sparse: indexed by touch identifier, exactly as RN does it.\n touchBank: TouchRecord[]\n numberActiveTouches: number\n // Only meaningful when numberActiveTouches === 1; TouchHistoryMath's fast\n // path reads it directly.\n indexOfSingleActiveTouch: number\n mostRecentTimeStamp: number\n}\n\n/**\n * What every responder callback receives. PanResponder reads `touchHistory`\n * off the EVENT, not off `nativeEvent` — an easy detail to get wrong, and it\n * silently zeroes every gesture if you do.\n */\nexport type GestureResponderEvent = PressEvent & {\n touchHistory: TouchHistory\n}\n\nexport type ShouldSetResponder = (event: GestureResponderEvent) => boolean\n\n/**\n * RN's responder and touch props. The touch props fire regardless of who\n * holds the responder; the rest are the negotiation.\n */\nexport type ResponderProps = {\n onStartShouldSetResponder?: ShouldSetResponder\n onStartShouldSetResponderCapture?: ShouldSetResponder\n onMoveShouldSetResponder?: ShouldSetResponder\n onMoveShouldSetResponderCapture?: ShouldSetResponder\n // RN lets onResponderGrant return a boolean (onShouldBlockNativeResponder);\n // PanResponder's does. Nothing consumes it here yet — see docs/api.md.\n onResponderGrant?: (event: GestureResponderEvent) => void | boolean\n onResponderStart?: (event: GestureResponderEvent) => void\n onResponderMove?: (event: GestureResponderEvent) => void\n onResponderEnd?: (event: GestureResponderEvent) => void\n onResponderRelease?: (event: GestureResponderEvent) => void\n onResponderTerminate?: (event: GestureResponderEvent) => void\n onResponderTerminationRequest?: ShouldSetResponder\n onResponderReject?: (event: GestureResponderEvent) => void\n\n onTouchStart?: (event: GestureResponderEvent) => void\n onTouchStartCapture?: (event: GestureResponderEvent) => void\n onTouchMove?: (event: GestureResponderEvent) => void\n onTouchMoveCapture?: (event: GestureResponderEvent) => void\n onTouchEnd?: (event: GestureResponderEvent) => void\n onTouchEndCapture?: (event: GestureResponderEvent) => void\n onTouchCancel?: (event: GestureResponderEvent) => void\n onTouchCancelCapture?: (event: GestureResponderEvent) => void\n}\n\nconst RESPONDER_PROP_NAMES = [\n \"onStartShouldSetResponder\",\n \"onStartShouldSetResponderCapture\",\n \"onMoveShouldSetResponder\",\n \"onMoveShouldSetResponderCapture\",\n \"onResponderGrant\",\n \"onResponderStart\",\n \"onResponderMove\",\n \"onResponderEnd\",\n \"onResponderRelease\",\n \"onResponderTerminate\",\n \"onResponderTerminationRequest\",\n \"onResponderReject\",\n \"onTouchStart\",\n \"onTouchStartCapture\",\n \"onTouchMove\",\n \"onTouchMoveCapture\",\n \"onTouchEnd\",\n \"onTouchEndCapture\",\n \"onTouchCancel\",\n \"onTouchCancelCapture\",\n] as const satisfies readonly (keyof ResponderProps)[]\n\n/**\n * Whether a component needs an event source at all. A View with no responder\n * props gets no GTK controller: RN only ever asks views that declare\n * handlers, so attaching one everywhere would be pure cost.\n */\nexport const hasResponderProps = (props: ResponderProps): boolean =>\n RESPONDER_PROP_NAMES.some((name) => props[name] !== undefined)\n\n/** A single touch as PanResponder's `touches`/`changedTouches` see it. */\nexport type { NativeTouch }\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
import { Gtk } from "../gtkx/bridge/index";
|
|
3
|
+
import { type ResponderHost } from "./system";
|
|
4
|
+
import { type ResponderProps } from "./types";
|
|
5
|
+
/** Exposed for tests and for future ScrollView arbitration. */
|
|
6
|
+
export declare const getCurrentResponder: () => ResponderHost | null;
|
|
7
|
+
/**
|
|
8
|
+
* Attaches the responder event source to a component's widget, but only when
|
|
9
|
+
* it actually declares responder props — RN never asks a view without
|
|
10
|
+
* handlers, so a controller on every View would be pure cost.
|
|
11
|
+
*/
|
|
12
|
+
export declare const useResponder: (widgetRef: RefObject<Gtk.Widget | null>, props: ResponderProps) => void;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// The platform half of the responder system: GTK carries the events, the
|
|
2
|
+
// pure module in ./system owns the algorithm.
|
|
3
|
+
//
|
|
4
|
+
// Shape and why (docs/research/gestures.md, "Verifiability decides the
|
|
5
|
+
// implementation shape"): the architecturally cleanest source would be one
|
|
6
|
+
// GtkEventControllerLegacy on the toplevel doing its own hit-testing, which
|
|
7
|
+
// is react-native-web's design. It is also untestable here —
|
|
8
|
+
// @gtkx/testing's userEvent emits GtkGesture SIGNALS on the widget you name
|
|
9
|
+
// and never produces a GdkEvent, so a raw tap could not be driven in CI at
|
|
10
|
+
// all. A gesture per responder-declaring View is drivable today
|
|
11
|
+
// (`userEvent.drag`), and GTK's own bubble chain still delivers a press to
|
|
12
|
+
// every ancestor's gesture, so the path is not lost.
|
|
13
|
+
//
|
|
14
|
+
// One GtkGestureDrag per View covers press, move and release: it emits
|
|
15
|
+
// drag-begin on press with no threshold of its own, which is exactly what
|
|
16
|
+
// RN wants — the responder system has no threshold either, and PanResponder
|
|
17
|
+
// users apply their own inside onMoveShouldSetPanResponder.
|
|
18
|
+
import { useLayoutEffect, useRef } from "react";
|
|
19
|
+
import { createTouch } from "../components/press-event";
|
|
20
|
+
import { Gtk } from "../gtkx/bridge/index";
|
|
21
|
+
import { createResponderSystem } from "./system";
|
|
22
|
+
import { hasResponderProps } from "./types";
|
|
23
|
+
// The gesture that reported each registered widget, so a grant can make the
|
|
24
|
+
// GTK claim on the right one.
|
|
25
|
+
const gestures = new WeakMap();
|
|
26
|
+
/**
|
|
27
|
+
* One lock for the process, as in RN. What is island-scoped is the
|
|
28
|
+
* negotiation PATH, not the lock: `parentOf` walks the GTK widget tree and
|
|
29
|
+
* simply finds nothing registered above a layout Root, so an RN island
|
|
30
|
+
* inside a native widget tree negotiates among its own views and no others.
|
|
31
|
+
*/
|
|
32
|
+
const responderSystem = createResponderSystem({
|
|
33
|
+
parentOf: (host) => host.getParent(),
|
|
34
|
+
onGrant: (host) => {
|
|
35
|
+
// GTK's only arbitration primitive, used the only way it can honestly be
|
|
36
|
+
// used: a final one-way declaration AFTER JS has decided. There is no
|
|
37
|
+
// un-claim, so nothing may depend on taking it back.
|
|
38
|
+
gestures.get(host)?.setState(Gtk.EventSequenceState.CLAIMED);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
/** Exposed for tests and for future ScrollView arbitration. */
|
|
42
|
+
export const getCurrentResponder = () => responderSystem.getResponder();
|
|
43
|
+
/**
|
|
44
|
+
* Attaches the responder event source to a component's widget, but only when
|
|
45
|
+
* it actually declares responder props — RN never asks a view without
|
|
46
|
+
* handlers, so a controller on every View would be pure cost.
|
|
47
|
+
*/
|
|
48
|
+
export const useResponder = (widgetRef, props) => {
|
|
49
|
+
// Handlers are read through a ref so a re-render never detaches and
|
|
50
|
+
// re-adds the gesture mid-drag (the same reasoning as Pressable's). The
|
|
51
|
+
// ref is refreshed in an effect rather than during render: a render-phase
|
|
52
|
+
// write is not safe under concurrent rendering, and this effect is
|
|
53
|
+
// declared BEFORE the registration effect so the handlers are already
|
|
54
|
+
// current the first time the gesture can fire.
|
|
55
|
+
const propsRef = useRef(props);
|
|
56
|
+
useLayoutEffect(() => {
|
|
57
|
+
propsRef.current = props;
|
|
58
|
+
});
|
|
59
|
+
const active = hasResponderProps(props);
|
|
60
|
+
useLayoutEffect(() => {
|
|
61
|
+
const widget = widgetRef.current;
|
|
62
|
+
if (!widget || !active) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const unregister = responderSystem.register(widget, () => propsRef.current);
|
|
66
|
+
const drag = new Gtk.GestureDrag();
|
|
67
|
+
gestures.set(widget, drag);
|
|
68
|
+
// drag-update/end report offsets FROM the start point, not absolute
|
|
69
|
+
// coordinates — the start has to be carried.
|
|
70
|
+
let startX = 0;
|
|
71
|
+
let startY = 0;
|
|
72
|
+
drag.on("drag-begin", (x, y) => {
|
|
73
|
+
startX = x;
|
|
74
|
+
startY = y;
|
|
75
|
+
responderSystem.touchStart(widget, createTouch(widget, x, y));
|
|
76
|
+
});
|
|
77
|
+
drag.on("drag-update", (offsetX, offsetY) => {
|
|
78
|
+
responderSystem.touchMove(widget, createTouch(widget, startX + offsetX, startY + offsetY));
|
|
79
|
+
});
|
|
80
|
+
drag.on("drag-end", (offsetX, offsetY) => {
|
|
81
|
+
responderSystem.touchEnd(widget, createTouch(widget, startX + offsetX, startY + offsetY));
|
|
82
|
+
});
|
|
83
|
+
// GTK cancels a sequence when something upstream claims it — a native
|
|
84
|
+
// ancestor scrolling, say. RN calls that a termination, and it is the
|
|
85
|
+
// one termination trigger we get for free.
|
|
86
|
+
drag.on("cancel", () => {
|
|
87
|
+
responderSystem.touchCancel(widget, createTouch(widget, startX, startY));
|
|
88
|
+
});
|
|
89
|
+
widget.addController(drag);
|
|
90
|
+
return () => {
|
|
91
|
+
widget.removeController(drag);
|
|
92
|
+
gestures.delete(widget);
|
|
93
|
+
unregister();
|
|
94
|
+
};
|
|
95
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
96
|
+
}, [active]);
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=use-responder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-responder.js","sourceRoot":"","sources":["../../src/responder/use-responder.ts"],"names":[],"mappings":"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","sourcesContent":["// The platform half of the responder system: GTK carries the events, the\n// pure module in ./system owns the algorithm.\n//\n// Shape and why (docs/research/gestures.md, \"Verifiability decides the\n// implementation shape\"): the architecturally cleanest source would be one\n// GtkEventControllerLegacy on the toplevel doing its own hit-testing, which\n// is react-native-web's design. It is also untestable here —\n// @gtkx/testing's userEvent emits GtkGesture SIGNALS on the widget you name\n// and never produces a GdkEvent, so a raw tap could not be driven in CI at\n// all. A gesture per responder-declaring View is drivable today\n// (`userEvent.drag`), and GTK's own bubble chain still delivers a press to\n// every ancestor's gesture, so the path is not lost.\n//\n// One GtkGestureDrag per View covers press, move and release: it emits\n// drag-begin on press with no threshold of its own, which is exactly what\n// RN wants — the responder system has no threshold either, and PanResponder\n// users apply their own inside onMoveShouldSetPanResponder.\nimport { useLayoutEffect, useRef, type RefObject } from \"react\"\nimport { createTouch } from \"../components/press-event\"\nimport { Gtk } from \"../gtkx/bridge/index\"\nimport { createResponderSystem, type ResponderHost } from \"./system\"\nimport { hasResponderProps, type ResponderProps } from \"./types\"\n\n// The gesture that reported each registered widget, so a grant can make the\n// GTK claim on the right one.\nconst gestures = new WeakMap<ResponderHost, Gtk.Gesture>()\n\n/**\n * One lock for the process, as in RN. What is island-scoped is the\n * negotiation PATH, not the lock: `parentOf` walks the GTK widget tree and\n * simply finds nothing registered above a layout Root, so an RN island\n * inside a native widget tree negotiates among its own views and no others.\n */\nconst responderSystem = createResponderSystem({\n parentOf: (host) => (host as Gtk.Widget).getParent(),\n onGrant: (host) => {\n // GTK's only arbitration primitive, used the only way it can honestly be\n // used: a final one-way declaration AFTER JS has decided. There is no\n // un-claim, so nothing may depend on taking it back.\n gestures.get(host)?.setState(Gtk.EventSequenceState.CLAIMED)\n },\n})\n\n/** Exposed for tests and for future ScrollView arbitration. */\nexport const getCurrentResponder = (): ResponderHost | null =>\n responderSystem.getResponder()\n\n/**\n * Attaches the responder event source to a component's widget, but only when\n * it actually declares responder props — RN never asks a view without\n * handlers, so a controller on every View would be pure cost.\n */\nexport const useResponder = (\n widgetRef: RefObject<Gtk.Widget | null>,\n props: ResponderProps,\n): void => {\n // Handlers are read through a ref so a re-render never detaches and\n // re-adds the gesture mid-drag (the same reasoning as Pressable's). The\n // ref is refreshed in an effect rather than during render: a render-phase\n // write is not safe under concurrent rendering, and this effect is\n // declared BEFORE the registration effect so the handlers are already\n // current the first time the gesture can fire.\n const propsRef = useRef(props)\n useLayoutEffect(() => {\n propsRef.current = props\n })\n const active = hasResponderProps(props)\n\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget || !active) {\n return\n }\n\n const unregister = responderSystem.register(widget, () => propsRef.current)\n\n const drag = new Gtk.GestureDrag()\n gestures.set(widget, drag)\n\n // drag-update/end report offsets FROM the start point, not absolute\n // coordinates — the start has to be carried.\n let startX = 0\n let startY = 0\n\n drag.on(\"drag-begin\", (x: number, y: number) => {\n startX = x\n startY = y\n responderSystem.touchStart(widget, createTouch(widget, x, y))\n })\n drag.on(\"drag-update\", (offsetX: number, offsetY: number) => {\n responderSystem.touchMove(\n widget,\n createTouch(widget, startX + offsetX, startY + offsetY),\n )\n })\n drag.on(\"drag-end\", (offsetX: number, offsetY: number) => {\n responderSystem.touchEnd(\n widget,\n createTouch(widget, startX + offsetX, startY + offsetY),\n )\n })\n // GTK cancels a sequence when something upstream claims it — a native\n // ancestor scrolling, say. RN calls that a termination, and it is the\n // one termination trigger we get for free.\n drag.on(\"cancel\", () => {\n responderSystem.touchCancel(widget, createTouch(widget, startX, startY))\n })\n\n widget.addController(drag)\n\n return () => {\n widget.removeController(drag)\n gestures.delete(widget)\n unregister()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active])\n}\n"]}
|
package/dist/runner/host-dev.js
CHANGED
|
@@ -54,7 +54,9 @@ globalThis.__ReactRefresh = {
|
|
|
54
54
|
const CONFIG_REQUIRED = "gtkx.config.ts with an applicationId is required in the app root " +
|
|
55
55
|
'(export default defineConfig({ applicationId: "...", libraries: [...] })).';
|
|
56
56
|
const { createConfigLoader } = await import(pathToFileURL(fromPackage.resolve("@gtkx/config/internal")).href);
|
|
57
|
-
const gtkxConfig = await createConfigLoader()
|
|
57
|
+
const gtkxConfig = await createConfigLoader()
|
|
58
|
+
.resolve(process.cwd())
|
|
59
|
+
.catch((error) => fail(`${CONFIG_REQUIRED}\n${String(error)}`));
|
|
58
60
|
if (!gtkxConfig.applicationId) {
|
|
59
61
|
fail(CONFIG_REQUIRED);
|
|
60
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-dev.js","sourceRoot":"","sources":["../../src/runner/host-dev.ts"],"names":[],"mappings":"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","sourcesContent":["// The DEV host: fetch the dev bundle from a Metro dev server, execute it,\n// subscribe to HMR updates and let react-refresh re-render through the\n// @gtkx/react reconciler with component state preserved. Spawned by\n// `run-linux --dev` as `node dist/runner/host-dev.js <bundle-url>`; exits\n// with code 65 when a full refresh is required — the supervisor restarts.\n//\n// Division of labor (validated by spike/rn-platform, FINDINGS-dev.md):\n// metro-runtime's dev require scopes the react-refresh registration per\n// module and applies hot updates once global.__ReactRefresh exists; its\n// HMRClient speaks the /hot websocket protocol verbatim over Node's\n// global WebSocket. This file only adds the dev pieces on top of the\n// release host (./host.ts — deliberately self-contained twins: both must\n// stay runnable under bare Node, so they cannot share a relative\n// extensionless import).\nimport { createRequire, registerHooks } from \"node:module\"\nimport { join } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport vm from \"node:vm\"\nimport { HOST_MODULE_EXTERNALS } from \"react-native-gtkx/metro\"\n\ntype HostModule = Record<string, unknown>\n\nconst fail = (message: string): never => {\n console.error(`[react-native-gtkx] ${message}`)\n process.exit(1)\n}\n\nif (typeof registerHooks !== \"function\") {\n fail(\n `Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 24.`,\n )\n}\n\n// react and the reconciler must run their DEV builds for react-refresh.\nprocess.env.NODE_ENV = process.env.NODE_ENV ?? \"development\"\n\nconst bundleUrl = process.argv[2]\nif (!bundleUrl) {\n fail(\"usage: node host-dev.js <metro-dev-bundle-url>\")\n}\n\n// Resolution anchors: react-refresh and metro-runtime ship with the APP's\n// react-native; @gtkx/* resolve as this package's dependencies; react must\n// be the exact instance the reconciler sees (see host.ts).\nconst fromApp = createRequire(join(process.cwd(), \"package.json\"))\nconst fromPackage = createRequire(import.meta.url)\nconst fromGtkxReact = createRequire(fromPackage.resolve(\"@gtkx/react\"))\n\n// --- react-refresh: inject BEFORE @gtkx/react loads (the reconciler\n// registers into the patched devtools hook).\nconst RefreshRuntime = fromApp(\"react-refresh/runtime\") as Record<\n string,\n unknown\n> & { injectIntoGlobalHook(target: unknown): void }\nRefreshRuntime.injectIntoGlobalHook(globalThis)\nglobalThis.$RefreshReg$ = () => {}\nglobalThis.$RefreshSig$ = () => (type: unknown) => type\nglobalThis.__ReactRefresh = {\n ...RefreshRuntime,\n performFullRefresh(reason: string) {\n console.warn(\n `[react-native-gtkx] full refresh required (${reason}) — restarting`,\n )\n process.exit(65)\n },\n}\n\n// --- virtual:gtkx-config (same mechanism and same module shape as the\n// release host — see host.ts for why each export is needed).\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\n pathToFileURL(fromPackage.resolve(\"@gtkx/config/internal\")).href\n)\nconst gtkxConfig = await createConfigLoader()(process.cwd()).catch(\n (error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`),\n)\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type: string) => [type, { lazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\n].join(\"\\n\")\nregisterHooks({\n resolve(specifier, context, nextResolve) {\n if (specifier === \"virtual:gtkx-config\") {\n return { url: configModuleUrl, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n },\n load(url, context, nextLoad) {\n if (url === configModuleUrl) {\n return {\n format: \"module\",\n source: configModuleSource,\n shortCircuit: true,\n }\n }\n return nextLoad(url, context)\n },\n})\n\n// --- host modules (same interop merging as the release host).\nconst resolveExternal = (name: string): string =>\n name === \"react\" || name.startsWith(\"react/\")\n ? fromGtkxReact.resolve(name)\n : fromPackage.resolve(name)\n\nconst load = async (name: string): Promise<HostModule> => {\n const namespace: HostModule = await import(\n pathToFileURL(resolveExternal(name)).href\n )\n const merged: HostModule = { __esModule: true, ...namespace }\n if (!(\"default\" in namespace)) {\n merged.default = namespace\n }\n return merged\n}\n\nglobalThis.__hostModules = {}\nfor (const name of HOST_MODULE_EXTERNALS) {\n try {\n globalThis.__hostModules[name] = await load(name)\n } catch (error) {\n fail(\n `failed to load host module \"${name}\" — is the codegen store in ` +\n `place (npx gtkx codegen) and GTK4/libadwaita installed?\\n${String(error)}`,\n )\n }\n}\nglobalThis.__hostRequire = createRequire(import.meta.url)\n\n// --- Dev Menu (Ctrl+Shift+D, the react-native-windows precedent).\n// Installed before the bundle runs so DevSettings.reload works from app\n// code; the key controller attaches once the app window exists.\nconst requestReload = (reason?: string): never => {\n console.warn(\n `[react-native-gtkx] reload requested${reason ? ` (${reason})` : \"\"} — restarting`,\n )\n return process.exit(65)\n}\nglobalThis.__rnGtkxDevHost = { reload: requestReload }\n\n// Structural slices of the GTK wrappers the menu touches — the host talks\n// to codegen namespaces through __hostModules, untyped by design.\ntype DevMenuWindow = { addController(controller: unknown): void }\ntype DevMenuDialog = {\n setHeading(heading: string): void\n setBody(body: string): void\n addResponse(id: string, label: string): void\n setResponseAppearance(id: string, appearance: unknown): void\n setDefaultResponse(id: string): void\n setCloseResponse(id: string): void\n choose(parent: DevMenuWindow): Promise<string>\n}\n\nconst installDevMenu = (): void => {\n const gtk = globalThis.__hostModules[\"@gtkx/gi/gtk\"] as {\n EventControllerKey: new () => {\n on(signal: string, handler: (...args: unknown[]) => unknown): void\n }\n }\n const gdk = globalThis.__hostModules[\"@gtkx/gi/gdk\"] as {\n ModifierType: { CONTROL_MASK: number; SHIFT_MASK: number }\n }\n const adw = globalThis.__hostModules[\"@gtkx/gi/adw\"] as {\n AlertDialog: new () => DevMenuDialog\n ResponseAppearance: { SUGGESTED: unknown }\n }\n const gio = globalThis.__hostModules[\"@gtkx/gi/gio\"] as {\n Application: {\n getDefault():\n { getActiveWindow?: () => DevMenuWindow | null } | null | undefined\n }\n }\n // GDK keysyms for latin letters equal their ASCII codes.\n const KEY_UPPER_D = 0x44\n const KEY_LOWER_D = 0x64\n\n let menuOpen = false\n const openDevMenu = async (window: DevMenuWindow): Promise<void> => {\n if (menuOpen) {\n return\n }\n menuOpen = true\n try {\n const items = globalThis.__rnGtkxDevMenuItems ?? []\n const dialog = new adw.AlertDialog()\n dialog.setHeading(\"React Native Dev Menu\")\n dialog.setBody(bundleUrl!)\n dialog.addResponse(\"cancel\", \"Cancel\")\n items.forEach((item, index) => {\n dialog.addResponse(`custom-${index}`, item.title)\n })\n dialog.addResponse(\"reload\", \"Reload\")\n dialog.setResponseAppearance(\"reload\", adw.ResponseAppearance.SUGGESTED)\n dialog.setDefaultResponse(\"reload\")\n dialog.setCloseResponse(\"cancel\")\n const response = await dialog.choose(window)\n if (response === \"reload\") {\n requestReload()\n }\n const custom = /^custom-(\\d+)$/.exec(response)\n if (custom) {\n items[Number(custom[1])]?.handler()\n }\n } catch (error) {\n console.error(`[react-native-gtkx] dev menu failed: ${String(error)}`)\n } finally {\n menuOpen = false\n }\n }\n\n const attach = (): void => {\n const window = gio.Application.getDefault()?.getActiveWindow?.()\n if (!window) {\n // The bundle opens the window asynchronously (application activate).\n setTimeout(attach, 200)\n return\n }\n const controller = new gtk.EventControllerKey()\n controller.on(\"key-pressed\", (keyval, _keycode, state) => {\n const modifiers = state as number\n const wanted =\n (modifiers & gdk.ModifierType.CONTROL_MASK) !== 0 &&\n (modifiers & gdk.ModifierType.SHIFT_MASK) !== 0 &&\n (keyval === KEY_UPPER_D || keyval === KEY_LOWER_D)\n if (wanted) {\n void openDevMenu(window)\n return true\n }\n return false\n })\n window.addController(controller)\n console.warn(\"[react-native-gtkx] dev menu ready (Ctrl+Shift+D)\")\n }\n attach()\n}\n\n// --- fetch and run the dev bundle.\nlet response: Response\ntry {\n response = await fetch(bundleUrl!)\n} catch {\n fail(`Metro dev server is not reachable (${bundleUrl}).`)\n throw new Error(\"unreachable\")\n}\nif (!response.ok) {\n fail(\n `Metro returned ${response.status} for the dev bundle:\\n${await response.text()}`,\n )\n}\nvm.runInThisContext(await response.text(), { filename: bundleUrl })\ninstallDevMenu()\n\n// --- HMR: metro-runtime's own client (ships with react-native).\ntype HmrErrorBody = { type?: string; message?: string }\ntype HmrClient = {\n send(message: string): void\n enable(): void\n on(event: string, listener: (body?: HmrErrorBody) => void): void\n}\nconst HMRClient = fromApp(\"metro-runtime/src/modules/HMRClient\") as new (\n url: string,\n) => HmrClient\nconst client = new HMRClient(\n bundleUrl!.replace(/^http/, \"ws\").replace(/\\/[^/]*$/, \"/hot\"),\n)\nclient.send(\n JSON.stringify({ type: \"register-entrypoints\", entryPoints: [bundleUrl] }),\n)\nclient.enable()\nclient.on(\"update-done\", () => {\n console.warn(\"[react-native-gtkx] hot update applied\")\n})\nclient.on(\"error\", (body) => {\n console.error(\n `[react-native-gtkx] Metro error (${body?.type ?? \"unknown\"}):\\n${body?.message ?? \"\"}`,\n )\n})\nclient.on(\"close\", () => {\n console.warn(\n \"[react-native-gtkx] HMR connection closed (the window keeps running without hot updates)\",\n )\n})\n"]}
|
|
1
|
+
{"version":3,"file":"host-dev.js","sourceRoot":"","sources":["../../src/runner/host-dev.ts"],"names":[],"mappings":"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","sourcesContent":["// The DEV host: fetch the dev bundle from a Metro dev server, execute it,\n// subscribe to HMR updates and let react-refresh re-render through the\n// @gtkx/react reconciler with component state preserved. Spawned by\n// `run-linux --dev` as `node dist/runner/host-dev.js <bundle-url>`; exits\n// with code 65 when a full refresh is required — the supervisor restarts.\n//\n// Division of labor (validated by spike/rn-platform, FINDINGS-dev.md):\n// metro-runtime's dev require scopes the react-refresh registration per\n// module and applies hot updates once global.__ReactRefresh exists; its\n// HMRClient speaks the /hot websocket protocol verbatim over Node's\n// global WebSocket. This file only adds the dev pieces on top of the\n// release host (./host.ts — deliberately self-contained twins: both must\n// stay runnable under bare Node, so they cannot share a relative\n// extensionless import).\nimport { createRequire, registerHooks } from \"node:module\"\nimport { join } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport vm from \"node:vm\"\nimport { HOST_MODULE_EXTERNALS } from \"react-native-gtkx/metro\"\n\ntype HostModule = Record<string, unknown>\n\nconst fail = (message: string): never => {\n console.error(`[react-native-gtkx] ${message}`)\n process.exit(1)\n}\n\nif (typeof registerHooks !== \"function\") {\n fail(\n `Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 24.`,\n )\n}\n\n// react and the reconciler must run their DEV builds for react-refresh.\nprocess.env.NODE_ENV = process.env.NODE_ENV ?? \"development\"\n\nconst bundleUrl = process.argv[2]\nif (!bundleUrl) {\n fail(\"usage: node host-dev.js <metro-dev-bundle-url>\")\n}\n\n// Resolution anchors: react-refresh and metro-runtime ship with the APP's\n// react-native; @gtkx/* resolve as this package's dependencies; react must\n// be the exact instance the reconciler sees (see host.ts).\nconst fromApp = createRequire(join(process.cwd(), \"package.json\"))\nconst fromPackage = createRequire(import.meta.url)\nconst fromGtkxReact = createRequire(fromPackage.resolve(\"@gtkx/react\"))\n\n// --- react-refresh: inject BEFORE @gtkx/react loads (the reconciler\n// registers into the patched devtools hook).\nconst RefreshRuntime = fromApp(\"react-refresh/runtime\") as Record<\n string,\n unknown\n> & { injectIntoGlobalHook(target: unknown): void }\nRefreshRuntime.injectIntoGlobalHook(globalThis)\nglobalThis.$RefreshReg$ = () => {}\nglobalThis.$RefreshSig$ = () => (type: unknown) => type\nglobalThis.__ReactRefresh = {\n ...RefreshRuntime,\n performFullRefresh(reason: string) {\n console.warn(\n `[react-native-gtkx] full refresh required (${reason}) — restarting`,\n )\n process.exit(65)\n },\n}\n\n// --- virtual:gtkx-config (same mechanism and same module shape as the\n// release host — see host.ts for why each export is needed).\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\n pathToFileURL(fromPackage.resolve(\"@gtkx/config/internal\")).href\n)\nconst gtkxConfig = await createConfigLoader()\n .resolve(process.cwd())\n .catch((error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`))\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type: string) => [type, { lazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\n].join(\"\\n\")\nregisterHooks({\n resolve(specifier, context, nextResolve) {\n if (specifier === \"virtual:gtkx-config\") {\n return { url: configModuleUrl, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n },\n load(url, context, nextLoad) {\n if (url === configModuleUrl) {\n return {\n format: \"module\",\n source: configModuleSource,\n shortCircuit: true,\n }\n }\n return nextLoad(url, context)\n },\n})\n\n// --- host modules (same interop merging as the release host).\nconst resolveExternal = (name: string): string =>\n name === \"react\" || name.startsWith(\"react/\")\n ? fromGtkxReact.resolve(name)\n : fromPackage.resolve(name)\n\nconst load = async (name: string): Promise<HostModule> => {\n const namespace: HostModule = await import(\n pathToFileURL(resolveExternal(name)).href\n )\n const merged: HostModule = { __esModule: true, ...namespace }\n if (!(\"default\" in namespace)) {\n merged.default = namespace\n }\n return merged\n}\n\nglobalThis.__hostModules = {}\nfor (const name of HOST_MODULE_EXTERNALS) {\n try {\n globalThis.__hostModules[name] = await load(name)\n } catch (error) {\n fail(\n `failed to load host module \"${name}\" — is the codegen store in ` +\n `place (npx gtkx codegen) and GTK4/libadwaita installed?\\n${String(error)}`,\n )\n }\n}\nglobalThis.__hostRequire = createRequire(import.meta.url)\n\n// --- Dev Menu (Ctrl+Shift+D, the react-native-windows precedent).\n// Installed before the bundle runs so DevSettings.reload works from app\n// code; the key controller attaches once the app window exists.\nconst requestReload = (reason?: string): never => {\n console.warn(\n `[react-native-gtkx] reload requested${reason ? ` (${reason})` : \"\"} — restarting`,\n )\n return process.exit(65)\n}\nglobalThis.__rnGtkxDevHost = { reload: requestReload }\n\n// Structural slices of the GTK wrappers the menu touches — the host talks\n// to codegen namespaces through __hostModules, untyped by design.\ntype DevMenuWindow = { addController(controller: unknown): void }\ntype DevMenuDialog = {\n setHeading(heading: string): void\n setBody(body: string): void\n addResponse(id: string, label: string): void\n setResponseAppearance(id: string, appearance: unknown): void\n setDefaultResponse(id: string): void\n setCloseResponse(id: string): void\n choose(parent: DevMenuWindow): Promise<string>\n}\n\nconst installDevMenu = (): void => {\n const gtk = globalThis.__hostModules[\"@gtkx/gi/gtk\"] as {\n EventControllerKey: new () => {\n on(signal: string, handler: (...args: unknown[]) => unknown): void\n }\n }\n const gdk = globalThis.__hostModules[\"@gtkx/gi/gdk\"] as {\n ModifierType: { CONTROL_MASK: number; SHIFT_MASK: number }\n }\n const adw = globalThis.__hostModules[\"@gtkx/gi/adw\"] as {\n AlertDialog: new () => DevMenuDialog\n ResponseAppearance: { SUGGESTED: unknown }\n }\n const gio = globalThis.__hostModules[\"@gtkx/gi/gio\"] as {\n Application: {\n getDefault():\n { getActiveWindow?: () => DevMenuWindow | null } | null | undefined\n }\n }\n // GDK keysyms for latin letters equal their ASCII codes.\n const KEY_UPPER_D = 0x44\n const KEY_LOWER_D = 0x64\n\n let menuOpen = false\n const openDevMenu = async (window: DevMenuWindow): Promise<void> => {\n if (menuOpen) {\n return\n }\n menuOpen = true\n try {\n const items = globalThis.__rnGtkxDevMenuItems ?? []\n const dialog = new adw.AlertDialog()\n dialog.setHeading(\"React Native Dev Menu\")\n dialog.setBody(bundleUrl!)\n dialog.addResponse(\"cancel\", \"Cancel\")\n items.forEach((item, index) => {\n dialog.addResponse(`custom-${index}`, item.title)\n })\n dialog.addResponse(\"reload\", \"Reload\")\n dialog.setResponseAppearance(\"reload\", adw.ResponseAppearance.SUGGESTED)\n dialog.setDefaultResponse(\"reload\")\n dialog.setCloseResponse(\"cancel\")\n const response = await dialog.choose(window)\n if (response === \"reload\") {\n requestReload()\n }\n const custom = /^custom-(\\d+)$/.exec(response)\n if (custom) {\n items[Number(custom[1])]?.handler()\n }\n } catch (error) {\n console.error(`[react-native-gtkx] dev menu failed: ${String(error)}`)\n } finally {\n menuOpen = false\n }\n }\n\n const attach = (): void => {\n const window = gio.Application.getDefault()?.getActiveWindow?.()\n if (!window) {\n // The bundle opens the window asynchronously (application activate).\n setTimeout(attach, 200)\n return\n }\n const controller = new gtk.EventControllerKey()\n controller.on(\"key-pressed\", (keyval, _keycode, state) => {\n const modifiers = state as number\n const wanted =\n (modifiers & gdk.ModifierType.CONTROL_MASK) !== 0 &&\n (modifiers & gdk.ModifierType.SHIFT_MASK) !== 0 &&\n (keyval === KEY_UPPER_D || keyval === KEY_LOWER_D)\n if (wanted) {\n void openDevMenu(window)\n return true\n }\n return false\n })\n window.addController(controller)\n console.warn(\"[react-native-gtkx] dev menu ready (Ctrl+Shift+D)\")\n }\n attach()\n}\n\n// --- fetch and run the dev bundle.\nlet response: Response\ntry {\n response = await fetch(bundleUrl!)\n} catch {\n fail(`Metro dev server is not reachable (${bundleUrl}).`)\n throw new Error(\"unreachable\")\n}\nif (!response.ok) {\n fail(\n `Metro returned ${response.status} for the dev bundle:\\n${await response.text()}`,\n )\n}\nvm.runInThisContext(await response.text(), { filename: bundleUrl })\ninstallDevMenu()\n\n// --- HMR: metro-runtime's own client (ships with react-native).\ntype HmrErrorBody = { type?: string; message?: string }\ntype HmrClient = {\n send(message: string): void\n enable(): void\n on(event: string, listener: (body?: HmrErrorBody) => void): void\n}\nconst HMRClient = fromApp(\"metro-runtime/src/modules/HMRClient\") as new (\n url: string,\n) => HmrClient\nconst client = new HMRClient(\n bundleUrl!.replace(/^http/, \"ws\").replace(/\\/[^/]*$/, \"/hot\"),\n)\nclient.send(\n JSON.stringify({ type: \"register-entrypoints\", entryPoints: [bundleUrl] }),\n)\nclient.enable()\nclient.on(\"update-done\", () => {\n console.warn(\"[react-native-gtkx] hot update applied\")\n})\nclient.on(\"error\", (body) => {\n console.error(\n `[react-native-gtkx] Metro error (${body?.type ?? \"unknown\"}):\\n${body?.message ?? \"\"}`,\n )\n})\nclient.on(\"close\", () => {\n console.warn(\n \"[react-native-gtkx] HMR connection closed (the window keeps running without hot updates)\",\n )\n})\n"]}
|
package/dist/runner/host.js
CHANGED
|
@@ -48,7 +48,11 @@ const CONFIG_REQUIRED = "gtkx.config.ts with an applicationId is required in the
|
|
|
48
48
|
'(export default defineConfig({ applicationId: "...", libraries: [...] })).';
|
|
49
49
|
const { createConfigLoader } = await import("@gtkx/config/internal");
|
|
50
50
|
// The loader validates the config, so a missing or malformed one throws.
|
|
51
|
-
|
|
51
|
+
// rc.3 turned the loader from a bare function into `{ load, resolve }`;
|
|
52
|
+
// `resolve` is the runtime projection this module needs.
|
|
53
|
+
const gtkxConfig = await createConfigLoader()
|
|
54
|
+
.resolve(process.cwd())
|
|
55
|
+
.catch((error) => fail(`${CONFIG_REQUIRED}\n${String(error)}`));
|
|
52
56
|
if (!gtkxConfig.applicationId) {
|
|
53
57
|
fail(CONFIG_REQUIRED);
|
|
54
58
|
}
|
package/dist/runner/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/runner/host.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,gDAAgD;AAChD,yEAAyE;AACzE,iDAAiD;AACjD,EAAE;AACF,0EAA0E;AAC1E,sEAAsE;AACtE,qDAAqD;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAI/D,MAAM,IAAI,GAAG,CAAC,OAAe,EAAS,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAA;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAA;AAED,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE,CAAC;IACxC,IAAI,CACF,QAAQ,OAAO,CAAC,OAAO,gEAAgE,CACxF,CAAA;AACH,CAAC;AAED,yEAAyE;AACzE,sEAAsE;AACtE,yEAAyE;AACzE,0EAA0E;AAC1E,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAClD,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAA;AAEvE,MAAM,eAAe,GAAG,CAAC,IAAY,EAAU,EAAE,CAC/C,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;IAC3C,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;IAC7B,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAE/B,mEAAmE;AACnE,8DAA8D;AAC9D,MAAM,IAAI,GAAG,KAAK,EAAE,IAAY,EAAuB,EAAE;IACvD,MAAM,SAAS,GAAe,MAAM,MAAM,CACxC,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAC1C,CAAA;IACD,MAAM,MAAM,GAAe,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,SAAS,EAAE,CAAA;IAC7D,IAAI,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,OAAO,GAAG,SAAS,CAAA;IAC5B,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,2EAA2E;AAC3E,wEAAwE;AACxE,yEAAyE;AACzE,4EAA4E;AAC5E,2EAA2E;AAC3E,6EAA6E;AAC7E,gEAAgE;AAChE,MAAM,eAAe,GACnB,mEAAmE;IACnE,4EAA4E,CAAA;AAC9E,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;AACpE,yEAAyE;AACzE,MAAM,UAAU,GAAG,MAAM,kBAAkB,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/runner/host.ts"],"names":[],"mappings":"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","sourcesContent":["// The Node+GTK host: executes a Metro jsbundle built for the linux\n// platform. Spawned by the run-linux command as\n// `node dist/runner/host.js <bundle>`; the bundle's externalized proxies\n// (see ../metro) read the modules injected here.\n//\n// This file must stay runnable under BARE Node: no extensionless relative\n// imports — only builtins, bare dependency specifiers and the package\n// self-reference (resolved through the exports map).\nimport { readFileSync } from \"node:fs\"\nimport { createRequire, registerHooks } from \"node:module\"\nimport { pathToFileURL } from \"node:url\"\nimport vm from \"node:vm\"\nimport { HOST_MODULE_EXTERNALS } from \"react-native-gtkx/metro\"\n\ntype HostModule = Record<string, unknown>\n\nconst fail = (message: string): never => {\n console.error(`[react-native-gtkx] ${message}`)\n process.exit(1)\n}\n\nif (typeof registerHooks !== \"function\") {\n fail(\n `Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 24.`,\n )\n}\n\n// Resolution anchors. @gtkx/* and @gtkx/config resolve as THIS package's\n// dependencies; react resolves FROM @gtkx/react's real location — the\n// reconciler and the app must share one React instance, and anchoring at\n// the app could pick up a second copy installed by npm peer auto-install.\nconst fromPackage = createRequire(import.meta.url)\nconst fromGtkxReact = createRequire(fromPackage.resolve(\"@gtkx/react\"))\n\nconst resolveExternal = (name: string): string =>\n name === \"react\" || name.startsWith(\"react/\")\n ? fromGtkxReact.resolve(name)\n : fromPackage.resolve(name)\n\n// import() handles both ESM and CJS; merge a `default` for Babel's\n// default-import interop when the module has none of its own.\nconst load = async (name: string): Promise<HostModule> => {\n const namespace: HostModule = await import(\n pathToFileURL(resolveExternal(name)).href\n )\n const merged: HostModule = { __esModule: true, ...namespace }\n if (!(\"default\" in namespace)) {\n merged.default = namespace\n }\n return merged\n}\n\n// @gtkx/react imports `virtual:gtkx-config` — JSX metadata plus the values\n// resolved from gtkx.config.ts (applicationId for the GApplication, the\n// userEventSignals suppressed during commits and the elements config the\n// reconciler registry is primed with). In the vite path the gtkx CLI plugin\n// serves it; replicate it with a loader hook, mirroring @gtkx/config's own\n// renderConfigModule. The fake module URL is anchored inside this package so\n// the re-exported bare specifier resolves through node_modules.\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\"@gtkx/config/internal\")\n// The loader validates the config, so a missing or malformed one throws.\n// rc.3 turned the loader from a bare function into `{ load, resolve }`;\n// `resolve` is the runtime projection this module needs.\nconst gtkxConfig = await createConfigLoader()\n .resolve(process.cwd())\n .catch((error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`))\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\n// A behaviors module would have to be bundled and merged through\n// @gtkx/react/config; the react-native surface owns element behaviors, so no\n// app declares one — refuse rather than silently drop it.\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type) => [type, { lazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\n].join(\"\\n\")\nregisterHooks({\n resolve(specifier, context, nextResolve) {\n if (specifier === \"virtual:gtkx-config\") {\n return { url: configModuleUrl, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n },\n load(url, context, nextLoad) {\n if (url === configModuleUrl) {\n return {\n format: \"module\",\n source: configModuleSource,\n shortCircuit: true,\n }\n }\n return nextLoad(url, context)\n },\n})\n\nglobalThis.__hostModules = {}\nfor (const name of HOST_MODULE_EXTERNALS) {\n try {\n globalThis.__hostModules[name] = await load(name)\n } catch (error) {\n fail(\n `failed to load host module \"${name}\" — is the codegen store in ` +\n `place (npx gtkx codegen) and GTK4/libadwaita installed?\\n${String(error)}`,\n )\n }\n}\n// Node builtin proxies resolve lazily through the host's own require.\nglobalThis.__hostRequire = createRequire(import.meta.url)\n\nconst bundlePath = process.argv[2]\nif (!bundlePath) {\n fail(\"usage: node host.js <path/to/main.jsbundle>\")\n}\nlet source: string\ntry {\n source = readFileSync(bundlePath!, \"utf8\")\n} catch {\n fail(`bundle not found at ${bundlePath} — run react-native run-linux.`)\n throw new Error(\"unreachable\")\n}\n// The entry calls AppRegistry.runApplication itself (the react-native-web\n// pattern); the GLib main loop keeps the process alive afterwards.\nvm.runInThisContext(source, { filename: bundlePath })\n"]}
|
package/dist/runner/index.js
CHANGED
|
@@ -34,7 +34,7 @@ const reactSubexportsOf = (manifest) => Object.keys(manifest.exports ?? {})
|
|
|
34
34
|
.filter((key) => key.startsWith("./") && key !== "./package.json")
|
|
35
35
|
.map((key) => key.slice(2));
|
|
36
36
|
// @gtkx/cli is meant for apps: its `codegen` command resolves gtkx.config.ts
|
|
37
|
-
// from a cwd and trusts a freshness stamp, which is what the
|
|
37
|
+
// from a cwd and trusts a freshness stamp, which is what the RC3-WORKAROUND
|
|
38
38
|
// this replaced was dodging (running from a reconstructed "project that owns
|
|
39
39
|
// the hosting node_modules" purely to keep that cwd resolution honest — see
|
|
40
40
|
// gtkx-org/gtkx#468, #470). A library generating bindings on a consumer's
|