react-native-gtkx 0.2.0-alpha.1 → 0.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -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/aliases/index.d.ts +84 -0
- package/dist/aliases/index.js +208 -0
- package/dist/aliases/index.js.map +1 -0
- 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 +4 -0
- package/dist/animated/index.js +6 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/types.d.ts +1 -0
- package/dist/animated/types.js.map +1 -1
- package/dist/animated/value-animation.js +17 -4
- package/dist/animated/value-animation.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/apis/host.gtkx.js +9 -12
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/apis/index.d.ts +4 -2
- package/dist/apis/index.js +2 -0
- package/dist/apis/index.js.map +1 -1
- package/dist/apis/keyboard.d.ts +60 -0
- package/dist/apis/keyboard.js +63 -0
- package/dist/apis/keyboard.js.map +1 -0
- package/dist/apis/log-box.d.ts +15 -0
- package/dist/apis/log-box.js +46 -0
- package/dist/apis/log-box.js.map +1 -0
- package/dist/apis/platform.d.ts +18 -1
- package/dist/apis/platform.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 +1 -0
- package/dist/common/index.js +25 -0
- package/dist/common/index.js.map +1 -1
- 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 +73 -7
- package/dist/components/animated.js +560 -45
- 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/driven-size.d.ts +27 -0
- package/dist/components/driven-size.js +85 -0
- package/dist/components/driven-size.js.map +1 -0
- package/dist/components/find-node-handle.d.ts +11 -0
- package/dist/components/find-node-handle.js +53 -0
- package/dist/components/find-node-handle.js.map +1 -0
- package/dist/components/flat-list.d.ts +3 -2
- package/dist/components/flat-list.js.map +1 -1
- package/dist/components/frame-scheduler.d.ts +16 -0
- package/dist/components/frame-scheduler.js +37 -0
- package/dist/components/frame-scheduler.js.map +1 -0
- 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/image.d.ts +6 -1
- package/dist/components/image.js +15 -4
- package/dist/components/image.js.map +1 -1
- package/dist/components/index.d.ts +11 -5
- package/dist/components/index.js +7 -4
- package/dist/components/index.js.map +1 -1
- package/dist/components/measure.d.ts +63 -0
- package/dist/components/measure.js +150 -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 +63 -7
- package/dist/components/pressable.js +165 -12
- package/dist/components/pressable.js.map +1 -1
- package/dist/components/rect-store.d.ts +58 -0
- package/dist/components/rect-store.js +124 -3
- package/dist/components/rect-store.js.map +1 -1
- package/dist/components/root.js +6 -1
- package/dist/components/root.js.map +1 -1
- package/dist/components/scroll-phase.d.ts +35 -0
- package/dist/components/scroll-phase.js +26 -0
- package/dist/components/scroll-phase.js.map +1 -0
- package/dist/components/scroll-view.d.ts +43 -3
- package/dist/components/scroll-view.js +386 -45
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/text-input.js +9 -25
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/text.d.ts +6 -2
- package/dist/components/text.js +68 -9
- package/dist/components/text.js.map +1 -1
- package/dist/components/use-focus.d.ts +27 -0
- package/dist/components/use-focus.js +116 -0
- package/dist/components/use-focus.js.map +1 -0
- package/dist/components/use-layout-child.d.ts +13 -1
- package/dist/components/use-layout-child.js +205 -19
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/view.d.ts +12 -4
- package/dist/components/view.js +25 -14
- package/dist/components/view.js.map +1 -1
- package/dist/components/virtualized-list.d.ts +45 -5
- package/dist/components/virtualized-list.js +90 -24
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/components/wheel-scroll-session.d.ts +7 -0
- package/dist/components/wheel-scroll-session.js +53 -0
- package/dist/components/wheel-scroll-session.js.map +1 -0
- package/dist/components/widget-retention.d.ts +35 -0
- package/dist/components/widget-retention.js +169 -0
- package/dist/components/widget-retention.js.map +1 -0
- package/dist/contracts.d.ts +23 -3
- package/dist/contracts.js.map +1 -1
- package/dist/dnd/context.d.ts +69 -0
- package/dist/dnd/context.js +149 -0
- package/dist/dnd/context.js.map +1 -0
- package/dist/dnd/draggable.d.ts +59 -0
- package/dist/dnd/draggable.js +149 -0
- package/dist/dnd/draggable.js.map +1 -0
- package/dist/dnd/droppable.d.ts +24 -0
- package/dist/dnd/droppable.js +74 -0
- package/dist/dnd/droppable.js.map +1 -0
- package/dist/dnd/gtk-controllers.d.ts +39 -0
- package/dist/dnd/gtk-controllers.js +110 -0
- package/dist/dnd/gtk-controllers.js.map +1 -0
- package/dist/dnd/index.d.ts +6 -0
- package/dist/dnd/index.js +31 -0
- package/dist/dnd/index.js.map +1 -0
- package/dist/dnd/order.d.ts +7 -0
- package/dist/dnd/order.js +20 -0
- package/dist/dnd/order.js.map +1 -0
- package/dist/dnd/payload.d.ts +14 -0
- package/dist/dnd/payload.js +41 -0
- package/dist/dnd/payload.js.map +1 -0
- package/dist/dnd/sortable.d.ts +49 -0
- package/dist/dnd/sortable.js +307 -0
- package/dist/dnd/sortable.js.map +1 -0
- package/dist/dnd/types.d.ts +290 -0
- package/dist/dnd/types.js +25 -0
- package/dist/dnd/types.js.map +1 -0
- package/dist/gesture-handler-compat/builder.d.ts +251 -0
- package/dist/gesture-handler-compat/builder.js +513 -0
- package/dist/gesture-handler-compat/builder.js.map +1 -0
- package/dist/gesture-handler-compat/composition.d.ts +23 -0
- package/dist/gesture-handler-compat/composition.js +111 -0
- package/dist/gesture-handler-compat/composition.js.map +1 -0
- package/dist/gesture-handler-compat/deciders.d.ts +3 -0
- package/dist/gesture-handler-compat/deciders.js +47 -0
- package/dist/gesture-handler-compat/deciders.js.map +1 -0
- package/dist/gesture-handler-compat/detector-runtime.d.ts +44 -0
- package/dist/gesture-handler-compat/detector-runtime.js +374 -0
- package/dist/gesture-handler-compat/detector-runtime.js.map +1 -0
- package/dist/gesture-handler-compat/detector.d.ts +22 -0
- package/dist/gesture-handler-compat/detector.js +104 -0
- package/dist/gesture-handler-compat/detector.js.map +1 -0
- package/dist/gesture-handler-compat/fling.d.ts +24 -0
- package/dist/gesture-handler-compat/fling.js +123 -0
- package/dist/gesture-handler-compat/fling.js.map +1 -0
- package/dist/gesture-handler-compat/force-touch.d.ts +13 -0
- package/dist/gesture-handler-compat/force-touch.js +40 -0
- package/dist/gesture-handler-compat/force-touch.js.map +1 -0
- package/dist/gesture-handler-compat/hooks.d.ts +157 -0
- package/dist/gesture-handler-compat/hooks.js +268 -0
- package/dist/gesture-handler-compat/hooks.js.map +1 -0
- package/dist/gesture-handler-compat/hover.d.ts +2 -0
- package/dist/gesture-handler-compat/hover.js +22 -0
- package/dist/gesture-handler-compat/hover.js.map +1 -0
- package/dist/gesture-handler-compat/index.d.ts +98 -0
- package/dist/gesture-handler-compat/index.js +255 -0
- package/dist/gesture-handler-compat/index.js.map +1 -0
- package/dist/gesture-handler-compat/long-press.d.ts +6 -0
- package/dist/gesture-handler-compat/long-press.js +21 -0
- package/dist/gesture-handler-compat/long-press.js.map +1 -0
- package/dist/gesture-handler-compat/manual.d.ts +2 -0
- package/dist/gesture-handler-compat/manual.js +18 -0
- package/dist/gesture-handler-compat/manual.js.map +1 -0
- package/dist/gesture-handler-compat/native.d.ts +7 -0
- package/dist/gesture-handler-compat/native.js +34 -0
- package/dist/gesture-handler-compat/native.js.map +1 -0
- package/dist/gesture-handler-compat/orchestrator.d.ts +77 -0
- package/dist/gesture-handler-compat/orchestrator.js +284 -0
- package/dist/gesture-handler-compat/orchestrator.js.map +1 -0
- package/dist/gesture-handler-compat/pan.d.ts +23 -0
- package/dist/gesture-handler-compat/pan.js +116 -0
- package/dist/gesture-handler-compat/pan.js.map +1 -0
- package/dist/gesture-handler-compat/recognizer.d.ts +268 -0
- package/dist/gesture-handler-compat/recognizer.js +1056 -0
- package/dist/gesture-handler-compat/recognizer.js.map +1 -0
- package/dist/gesture-handler-compat/relations.d.ts +43 -0
- package/dist/gesture-handler-compat/relations.js +128 -0
- package/dist/gesture-handler-compat/relations.js.map +1 -0
- package/dist/gesture-handler-compat/tap.d.ts +6 -0
- package/dist/gesture-handler-compat/tap.js +29 -0
- package/dist/gesture-handler-compat/tap.js.map +1 -0
- package/dist/gesture-handler-compat/touchpad.d.ts +41 -0
- package/dist/gesture-handler-compat/touchpad.js +64 -0
- package/dist/gesture-handler-compat/touchpad.js.map +1 -0
- package/dist/gesture-handler-compat/types.d.ts +441 -0
- package/dist/gesture-handler-compat/types.js +167 -0
- package/dist/gesture-handler-compat/types.js.map +1 -0
- package/dist/gtk/controllers.d.ts +39 -0
- package/dist/gtk/controllers.js +92 -0
- package/dist/gtk/controllers.js.map +1 -0
- package/dist/gtk/index.d.ts +3 -1
- package/dist/gtk/index.js +14 -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 +40 -0
- package/dist/gtkx/bridge/geometry.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +7 -3
- package/dist/gtkx/bridge/index.js +12 -4
- 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/gtkx/bridge/view-box.d.ts +56 -0
- package/dist/gtkx/bridge/view-box.js +394 -9
- package/dist/gtkx/bridge/view-box.js.map +1 -1
- package/dist/gtkx/bridge/widget-css.d.ts +17 -0
- package/dist/gtkx/bridge/widget-css.js +72 -0
- package/dist/gtkx/bridge/widget-css.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/layout/driven-size.d.ts +12 -0
- package/dist/layout/driven-size.js +70 -0
- package/dist/layout/driven-size.js.map +1 -0
- package/dist/layout/engine.d.ts +17 -1
- package/dist/layout/engine.js +3 -20
- package/dist/layout/engine.js.map +1 -1
- package/dist/layout/node.d.ts +13 -0
- package/dist/layout/node.js +14 -0
- package/dist/layout/node.js.map +1 -1
- package/dist/layout/yoga.d.ts +3 -2
- package/dist/layout/yoga.js +5 -2
- package/dist/layout/yoga.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +310 -91
- package/dist/mcp/data/generated.js +365 -90
- 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/metro/index.d.ts +10 -0
- package/dist/metro/index.js +21 -12
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/sidebar.d.ts +47 -1
- package/dist/navigation/sidebar.js +77 -3
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/reanimated-compat/animated-ref.d.ts +32 -0
- package/dist/reanimated-compat/animated-ref.js +57 -0
- package/dist/reanimated-compat/animated-ref.js.map +1 -0
- package/dist/reanimated-compat/animation.d.ts +177 -0
- package/dist/reanimated-compat/animation.js +540 -0
- package/dist/reanimated-compat/animation.js.map +1 -0
- package/dist/reanimated-compat/color.d.ts +28 -0
- package/dist/reanimated-compat/color.js +249 -0
- package/dist/reanimated-compat/color.js.map +1 -0
- package/dist/reanimated-compat/decay.d.ts +39 -0
- package/dist/reanimated-compat/decay.js +96 -0
- package/dist/reanimated-compat/decay.js.map +1 -0
- package/dist/reanimated-compat/easing.d.ts +30 -0
- package/dist/reanimated-compat/easing.js +76 -0
- package/dist/reanimated-compat/easing.js.map +1 -0
- package/dist/reanimated-compat/hooks.d.ts +14 -0
- package/dist/reanimated-compat/hooks.js +217 -0
- package/dist/reanimated-compat/hooks.js.map +1 -0
- package/dist/reanimated-compat/index.d.ts +258 -0
- package/dist/reanimated-compat/index.js +464 -0
- package/dist/reanimated-compat/index.js.map +1 -0
- package/dist/reanimated-compat/interpolation.d.ts +18 -0
- package/dist/reanimated-compat/interpolation.js +122 -0
- package/dist/reanimated-compat/interpolation.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-config.d.ts +43 -0
- package/dist/reanimated-compat/layout-animation-config.js +78 -0
- package/dist/reanimated-compat/layout-animation-config.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-presets.d.ts +117 -0
- package/dist/reanimated-compat/layout-animation-presets.js +498 -0
- package/dist/reanimated-compat/layout-animation-presets.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-runtime.d.ts +21 -0
- package/dist/reanimated-compat/layout-animation-runtime.js +311 -0
- package/dist/reanimated-compat/layout-animation-runtime.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-view.d.ts +27 -0
- package/dist/reanimated-compat/layout-animation-view.js +266 -0
- package/dist/reanimated-compat/layout-animation-view.js.map +1 -0
- package/dist/reanimated-compat/layout-animation.d.ts +171 -0
- package/dist/reanimated-compat/layout-animation.js +469 -0
- package/dist/reanimated-compat/layout-animation.js.map +1 -0
- package/dist/reanimated-compat/layout-transitions.d.ts +83 -0
- package/dist/reanimated-compat/layout-transitions.js +350 -0
- package/dist/reanimated-compat/layout-transitions.js.map +1 -0
- package/dist/reanimated-compat/mutable.d.ts +29 -0
- package/dist/reanimated-compat/mutable.js +139 -0
- package/dist/reanimated-compat/mutable.js.map +1 -0
- package/dist/reanimated-compat/props.d.ts +18 -0
- package/dist/reanimated-compat/props.js +111 -0
- package/dist/reanimated-compat/props.js.map +1 -0
- package/dist/reanimated-compat/scroll-handler.d.ts +119 -0
- package/dist/reanimated-compat/scroll-handler.js +274 -0
- package/dist/reanimated-compat/scroll-handler.js.map +1 -0
- package/dist/reanimated-compat/scroll-offset.d.ts +12 -0
- package/dist/reanimated-compat/scroll-offset.js +104 -0
- package/dist/reanimated-compat/scroll-offset.js.map +1 -0
- package/dist/reanimated-compat/style.d.ts +90 -0
- package/dist/reanimated-compat/style.js +452 -0
- package/dist/reanimated-compat/style.js.map +1 -0
- package/dist/reanimated-compat/test-timers.d.ts +28 -0
- package/dist/reanimated-compat/test-timers.js +136 -0
- package/dist/reanimated-compat/test-timers.js.map +1 -0
- package/dist/reanimated-compat/threads.d.ts +13 -0
- package/dist/reanimated-compat/threads.js +41 -0
- package/dist/reanimated-compat/threads.js.map +1 -0
- package/dist/reanimated-compat/tracking.d.ts +41 -0
- package/dist/reanimated-compat/tracking.js +106 -0
- package/dist/reanimated-compat/tracking.js.map +1 -0
- package/dist/reanimated-compat/updater-animations.d.ts +36 -0
- package/dist/reanimated-compat/updater-animations.js +273 -0
- package/dist/reanimated-compat/updater-animations.js.map +1 -0
- package/dist/responder/system.d.ts +100 -0
- package/dist/responder/system.js +304 -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 +23 -0
- package/dist/responder/use-responder.js +317 -0
- package/dist/responder/use-responder.js.map +1 -0
- package/dist/runner/host-dev.js +4 -2
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +6 -2
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.js +3 -3
- package/dist/runner/index.js.map +1 -1
- package/dist/sea/gtkx-config-module.js +2 -2
- package/dist/sea/gtkx-config-module.js.map +1 -1
- package/dist/style/absolute-insets.d.ts +26 -0
- package/dist/style/absolute-insets.js +113 -0
- package/dist/style/absolute-insets.js.map +1 -0
- package/dist/style/animated-size.d.ts +25 -0
- package/dist/style/animated-size.js +225 -0
- package/dist/style/animated-size.js.map +1 -0
- 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/colors.d.ts +17 -0
- package/dist/style/colors.js +25 -6
- package/dist/style/colors.js.map +1 -1
- package/dist/style/imperative-css.d.ts +21 -0
- package/dist/style/imperative-css.js +63 -0
- package/dist/style/imperative-css.js.map +1 -0
- package/dist/style/index.d.ts +4 -1
- package/dist/style/index.js +4 -1
- package/dist/style/index.js.map +1 -1
- package/dist/style/split-style.d.ts +5 -2
- package/dist/style/split-style.js +36 -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/unsupported-export.d.ts +8 -0
- package/dist/unsupported-export.js +66 -0
- package/dist/unsupported-export.js.map +1 -0
- 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.d.ts +21 -8
- package/dist/vite/index.js +127 -82
- package/dist/vite/index.js.map +1 -1
- package/dist/vitest/index.d.ts +2 -2
- package/dist/vitest/index.js.map +1 -1
- package/dist/worklets-compat/index.d.ts +4 -0
- package/dist/worklets-compat/index.js +28 -0
- package/dist/worklets-compat/index.js.map +1 -0
- package/dist/worklets-compat/surface.d.ts +110 -0
- package/dist/worklets-compat/surface.js +153 -0
- package/dist/worklets-compat/surface.js.map +1 -0
- package/package.json +25 -9
- package/types.d.ts +9 -0
|
@@ -0,0 +1,317 @@
|
|
|
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
|
+
//
|
|
19
|
+
// The terminations that are not pointer events (watchTerminations, below)
|
|
20
|
+
// were expected to need that raw tap after all. Measurement said otherwise.
|
|
21
|
+
import { useLayoutEffect, useRef } from "react";
|
|
22
|
+
import { createTouch } from "../components/press-event";
|
|
23
|
+
import { Gtk } from "../gtkx/bridge/index";
|
|
24
|
+
import { createResponderSystem } from "./system";
|
|
25
|
+
import { hasResponderProps } from "./types";
|
|
26
|
+
// The gesture that reported each registered widget, so a grant can make the
|
|
27
|
+
// GTK claim on the right one.
|
|
28
|
+
const gestures = new WeakMap();
|
|
29
|
+
/** Whether `widget` is `ancestor` or sits underneath it. */
|
|
30
|
+
const contains = (ancestor, widget) => {
|
|
31
|
+
for (let current = widget; current !== null; current = current.getParent()) {
|
|
32
|
+
if (current === ancestor) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Every `GtkScrolledWindow` above `source`, innermost first. Nested
|
|
40
|
+
* scrollers are rare but real, and stopping only the innermost would let an
|
|
41
|
+
* outer one take the drag instead.
|
|
42
|
+
*/
|
|
43
|
+
const enclosingScrollers = (source) => {
|
|
44
|
+
const found = [];
|
|
45
|
+
for (let widget = source.getParent(); widget !== null; widget = widget.getParent()) {
|
|
46
|
+
if (widget instanceof Gtk.ScrolledWindow) {
|
|
47
|
+
found.push(widget);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return found;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* `setIsJSResponder`, which is what every RN platform calls the message
|
|
54
|
+
* "JavaScript has taken this interaction, native scroller stop stealing the
|
|
55
|
+
* drag". iOS cancels the `UIScrollView` pan when the responder is a
|
|
56
|
+
* descendant; Android has a `JSResponderHandler`; react-native-windows
|
|
57
|
+
* punted on it in 2017, shipped a `manipulationModes` prop instead, and its
|
|
58
|
+
* tracking issues are still open.
|
|
59
|
+
*
|
|
60
|
+
* On GTK the message is `kinetic-scrolling`. Measured on GTK 4 rather than
|
|
61
|
+
* inferred (tests/gtk/components/scroll-arbitration.gtk.test.tsx):
|
|
62
|
+
* `GtkScrolledWindow` installs exactly four gestures of its own —
|
|
63
|
+
* `GestureLongPress`, `GestureSwipe`, `GesturePan`, `GestureDrag`, all
|
|
64
|
+
* touch-only, all in the CAPTURE phase — and turning kinetic scrolling off
|
|
65
|
+
* puts those four, and only those four, into `GTK_PHASE_NONE`. Setting a
|
|
66
|
+
* controller's phase to NONE resets it, so a scroll that had already begun
|
|
67
|
+
* stops there; the wheel and the motion controllers are untouched, so
|
|
68
|
+
* scrolling with a mouse keeps working while a child pans.
|
|
69
|
+
*
|
|
70
|
+
* Why this is needed at all when the `CLAIMED` declaration above already
|
|
71
|
+
* denies ancestor gestures: it is a race, and only sometimes ours.
|
|
72
|
+
* `GtkScrolledWindow` does not claim on press — it claims in `drag-update`,
|
|
73
|
+
* once movement passes `gtk-dnd-drag-threshold` (8 px). A view that claims
|
|
74
|
+
* on press beats it. A view that claims on a MOVE — which is what
|
|
75
|
+
* `onMoveShouldSetPanResponder` does, and it is the commonest shape there
|
|
76
|
+
* is — usually does not, and `CLAIMED` cannot be taken back once the
|
|
77
|
+
* scroller has it. So the claim is not enough on its own, and this is the
|
|
78
|
+
* part that makes a child pan reachable inside a scrolling list.
|
|
79
|
+
*
|
|
80
|
+
* Restores the previous value rather than assuming `true`: an app that
|
|
81
|
+
* turned kinetic scrolling off itself must not have it turned back on.
|
|
82
|
+
*/
|
|
83
|
+
const suspendEnclosingScrollers = (source) => {
|
|
84
|
+
const suspended = enclosingScrollers(source).filter((scroller) => scroller.getKineticScrolling());
|
|
85
|
+
for (const scroller of suspended) {
|
|
86
|
+
scroller.setKineticScrolling(false);
|
|
87
|
+
}
|
|
88
|
+
return () => {
|
|
89
|
+
for (const scroller of suspended) {
|
|
90
|
+
scroller.setKineticScrolling(true);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* The scroller suspension for the interaction currently under way. Module
|
|
96
|
+
* scope because it is set when the responder is granted and undone when the
|
|
97
|
+
* interaction ends, which are two different events on two different
|
|
98
|
+
* objects; there is only ever one interaction, which is the same assumption
|
|
99
|
+
* the responder system itself is built on (one pointer, one session).
|
|
100
|
+
*/
|
|
101
|
+
let restoreScrollers = null;
|
|
102
|
+
/**
|
|
103
|
+
* One lock for the process, as in RN. What is island-scoped is the
|
|
104
|
+
* negotiation PATH, not the lock: `parentOf` walks the GTK widget tree and
|
|
105
|
+
* simply finds nothing registered above a layout Root, so an RN island
|
|
106
|
+
* inside a native widget tree negotiates among its own views and no others.
|
|
107
|
+
*/
|
|
108
|
+
const responderSystem = createResponderSystem({
|
|
109
|
+
parentOf: (host) => host.getParent(),
|
|
110
|
+
onClaim: (source) => {
|
|
111
|
+
// GTK's only arbitration primitive, used the only way it can honestly be
|
|
112
|
+
// used: a final one-way declaration AFTER JS has decided. There is no
|
|
113
|
+
// un-claim, so nothing may depend on taking it back.
|
|
114
|
+
//
|
|
115
|
+
// On the SOURCE's gesture — the one the interaction is arriving through
|
|
116
|
+
// — never on the granted view's. Claiming denies the sequence on every
|
|
117
|
+
// gesture above the claimer and cancels it on everything below, so
|
|
118
|
+
// claiming on an ancestor kills the source and the drag goes silent
|
|
119
|
+
// after the grant. Slice 2 did exactly that, and the common
|
|
120
|
+
// onMoveShouldSetPanResponder shape never received a single move.
|
|
121
|
+
gestures.get(source)?.setState(Gtk.EventSequenceState.CLAIMED);
|
|
122
|
+
// A ResponderHost is deliberately opaque to the pure module; on this
|
|
123
|
+
// platform it is always the Gtk.Widget that registered it.
|
|
124
|
+
restoreScrollers = suspendEnclosingScrollers(source);
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
/**
|
|
128
|
+
* Everything that ends a gesture without being a pointer event, connected
|
|
129
|
+
* for the length of one interaction and torn down with it.
|
|
130
|
+
*
|
|
131
|
+
* The plan for this task called for a single `GtkEventControllerLegacy` on
|
|
132
|
+
* the toplevel in the capture phase — react-native-web's shape, on the
|
|
133
|
+
* reasoning that a raw event tap is the only way to see terminations that
|
|
134
|
+
* are not pointer events. Measured against GTK, it buys nothing here. Each
|
|
135
|
+
* of the two triggers that survive has a first-class signal that says
|
|
136
|
+
* exactly what we need to know and nothing else, and the rest of RNW's list
|
|
137
|
+
* turned out to arrive as an ordinary gesture `::cancel` (see
|
|
138
|
+
* `TerminationReason`). A legacy controller would have re-derived all of it
|
|
139
|
+
* from a stream of raw events, and its one advantage — hearing events on a
|
|
140
|
+
* sequence GTK has already denied us — matters only for triggers that no
|
|
141
|
+
* longer exist.
|
|
142
|
+
*/
|
|
143
|
+
const watchTerminations = (source) => {
|
|
144
|
+
const disposers = [];
|
|
145
|
+
// Window blur. GTK's `is-active` on the toplevel is the same thing the DOM
|
|
146
|
+
// reports as a window `blur` — the window stopped being the active one,
|
|
147
|
+
// which on a desktop usually means the user alt-tabbed mid-drag.
|
|
148
|
+
const root = source.getRoot();
|
|
149
|
+
if (root instanceof Gtk.Window) {
|
|
150
|
+
const onActive = () => {
|
|
151
|
+
if (!root.isActive()) {
|
|
152
|
+
responderSystem.terminate("blur");
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
root.on("notify::is-active", onActive);
|
|
156
|
+
disposers.push(() => {
|
|
157
|
+
root.off("notify::is-active", onActive);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// An ancestor scrolling. RNW's rule exactly: the scroller has to CONTAIN
|
|
161
|
+
// the responder and not BE it — a ScrollView that holds the responder
|
|
162
|
+
// itself keeps it, and a sibling list scrolling is none of our business.
|
|
163
|
+
// Watching the adjustments rather than a scroll controller is what makes
|
|
164
|
+
// that precise: it fires for a wheel, for a keyboard scroll and for
|
|
165
|
+
// kinetic deceleration alike, and only for this scroller.
|
|
166
|
+
for (const scroller of enclosingScrollers(source)) {
|
|
167
|
+
const onScrolled = () => {
|
|
168
|
+
const holder = responderSystem.getResponder();
|
|
169
|
+
if (holder !== null &&
|
|
170
|
+
holder !== scroller &&
|
|
171
|
+
contains(scroller, holder)) {
|
|
172
|
+
responderSystem.terminate("scroll");
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
for (const adjustment of [
|
|
176
|
+
scroller.getHadjustment(),
|
|
177
|
+
scroller.getVadjustment(),
|
|
178
|
+
]) {
|
|
179
|
+
adjustment.on("value-changed", onScrolled);
|
|
180
|
+
disposers.push(() => {
|
|
181
|
+
adjustment.off("value-changed", onScrolled);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return () => {
|
|
186
|
+
for (const dispose of disposers) {
|
|
187
|
+
dispose();
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
/** Exposed for tests and for future ScrollView arbitration. */
|
|
192
|
+
export const getCurrentResponder = () => responderSystem.getResponder();
|
|
193
|
+
/**
|
|
194
|
+
* The out-of-event grant channel, for a recognizer whose mind was changed by
|
|
195
|
+
* a timer rather than by a pointer (`activateAfterLongPress`). See
|
|
196
|
+
* `ResponderSystem.requestResponder` for what it does and
|
|
197
|
+
* docs/research/gestures.md for why the model is extended at all.
|
|
198
|
+
*
|
|
199
|
+
* @internal Not part of the RN surface: an app writes responder props, and
|
|
200
|
+
* nothing in RN asks for the responder from outside an event. This exists for
|
|
201
|
+
* `GestureDetector`, whose recognizers do.
|
|
202
|
+
*/
|
|
203
|
+
export const requestResponder = (widget) => responderSystem.requestResponder(widget);
|
|
204
|
+
/**
|
|
205
|
+
* Attaches the responder event source to a component's widget, but only when
|
|
206
|
+
* it actually declares responder props — RN never asks a view without
|
|
207
|
+
* handlers, so a controller on every View would be pure cost.
|
|
208
|
+
*/
|
|
209
|
+
export const useResponder = (widgetRef, props) => {
|
|
210
|
+
// Handlers are read through a ref so a re-render never detaches and
|
|
211
|
+
// re-adds the gesture mid-drag (the same reasoning as Pressable's). The
|
|
212
|
+
// ref is refreshed in an effect rather than during render: a render-phase
|
|
213
|
+
// write is not safe under concurrent rendering, and this effect is
|
|
214
|
+
// declared BEFORE the registration effect so the handlers are already
|
|
215
|
+
// current the first time the gesture can fire.
|
|
216
|
+
const propsRef = useRef(props);
|
|
217
|
+
useLayoutEffect(() => {
|
|
218
|
+
propsRef.current = props;
|
|
219
|
+
});
|
|
220
|
+
const active = hasResponderProps(props);
|
|
221
|
+
useLayoutEffect(() => {
|
|
222
|
+
const widget = widgetRef.current;
|
|
223
|
+
if (!widget || !active) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const unregister = responderSystem.register(widget, () => propsRef.current);
|
|
227
|
+
const drag = new Gtk.GestureDrag();
|
|
228
|
+
gestures.set(widget, drag);
|
|
229
|
+
// drag-update/end report offsets FROM the start point, not absolute
|
|
230
|
+
// coordinates — the start has to be carried.
|
|
231
|
+
let startX = 0;
|
|
232
|
+
let startY = 0;
|
|
233
|
+
let stopWatching = null;
|
|
234
|
+
// Whether this sequence was taken from us by something above. See the
|
|
235
|
+
// `sequence-state-changed` handler below.
|
|
236
|
+
let denied = false;
|
|
237
|
+
const endInteraction = () => {
|
|
238
|
+
stopWatching?.();
|
|
239
|
+
stopWatching = null;
|
|
240
|
+
restoreScrollers?.();
|
|
241
|
+
restoreScrollers = null;
|
|
242
|
+
};
|
|
243
|
+
// THE ONE SIGNAL THAT TELLS A THEFT FROM AN ENDING.
|
|
244
|
+
//
|
|
245
|
+
// GTK's claim propagation is asymmetric, and measuring it on 4.22.4
|
|
246
|
+
// corrected `docs/research/gestures.md`, which had it backwards. A claim
|
|
247
|
+
// by a DESCENDANT cancels the ancestor's gesture — `::cancel` then
|
|
248
|
+
// `::end`, and no state transition at all, which the `cancel` handler
|
|
249
|
+
// below already turns into a termination. A claim by an ANCESTOR is the
|
|
250
|
+
// dangerous direction: it DENIES the descendant's sequence and then ends
|
|
251
|
+
// it with an ordinary `drag-end`, exactly the signal a finger lifting
|
|
252
|
+
// produces. Without this handler a native ancestor stealing the drag
|
|
253
|
+
// mid-gesture reaches JS as `onResponderRelease` — a CLEAN RELEASE,
|
|
254
|
+
// indistinguishable from the user letting go, so a drag would commit
|
|
255
|
+
// itself at whatever position the theft happened at.
|
|
256
|
+
//
|
|
257
|
+
// `->DENIED` is the only thing that separates the two, which is why the
|
|
258
|
+
// sequence state has to be watched rather than just the drag signals.
|
|
259
|
+
// Nothing else here can produce it: this module never sets DENIED, and
|
|
260
|
+
// our own CLAIMED is always made on the source, which cancels ancestors
|
|
261
|
+
// rather than denying them.
|
|
262
|
+
drag.on("sequence-state-changed", (_sequence, state) => {
|
|
263
|
+
if (state === Gtk.EventSequenceState.DENIED) {
|
|
264
|
+
denied = true;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
drag.on("drag-begin", (x, y) => {
|
|
268
|
+
startX = x;
|
|
269
|
+
startY = y;
|
|
270
|
+
// A `GtkGestureSingle` denies its own sequence when a press arrives on
|
|
271
|
+
// the wrong button and nothing is down yet, so the flag can survive from
|
|
272
|
+
// before this press. Every interaction starts clean.
|
|
273
|
+
denied = false;
|
|
274
|
+
responderSystem.touchStart(widget, createTouch(widget, x, y));
|
|
275
|
+
// Every ancestor's gesture reports the same press; only the one that
|
|
276
|
+
// opened the interaction owns it, and asking the system afterwards is
|
|
277
|
+
// the cheapest way to find out which that was.
|
|
278
|
+
if (responderSystem.getSource() === widget) {
|
|
279
|
+
stopWatching = watchTerminations(widget);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
drag.on("drag-update", (offsetX, offsetY) => {
|
|
283
|
+
responderSystem.touchMove(widget, createTouch(widget, startX + offsetX, startY + offsetY));
|
|
284
|
+
});
|
|
285
|
+
drag.on("drag-end", (offsetX, offsetY) => {
|
|
286
|
+
const touch = createTouch(widget, startX + offsetX, startY + offsetY);
|
|
287
|
+
// A denied sequence ends with this same signal, and it is not an
|
|
288
|
+
// ending: the interaction was taken away. RN's word for that is a
|
|
289
|
+
// termination, so it goes down the cancel path.
|
|
290
|
+
if (denied) {
|
|
291
|
+
responderSystem.touchCancel(widget, touch);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
responderSystem.touchEnd(widget, touch);
|
|
295
|
+
}
|
|
296
|
+
endInteraction();
|
|
297
|
+
});
|
|
298
|
+
// GTK cancels a sequence when something takes it away from us: a native
|
|
299
|
+
// ancestor claiming it, a `GtkDragSource` attached through `Controllers`
|
|
300
|
+
// reaching its threshold, a second mouse button going down for a context
|
|
301
|
+
// menu. RN calls all of that a termination, and unlike RNW we never get
|
|
302
|
+
// to ask first — by the time GTK tells us, the sequence is gone.
|
|
303
|
+
drag.on("cancel", () => {
|
|
304
|
+
responderSystem.touchCancel(widget, createTouch(widget, startX, startY));
|
|
305
|
+
endInteraction();
|
|
306
|
+
});
|
|
307
|
+
widget.addController(drag);
|
|
308
|
+
return () => {
|
|
309
|
+
endInteraction();
|
|
310
|
+
widget.removeController(drag);
|
|
311
|
+
gestures.delete(widget);
|
|
312
|
+
unregister();
|
|
313
|
+
};
|
|
314
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
315
|
+
}, [active]);
|
|
316
|
+
};
|
|
317
|
+
//# 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.\n//\n// The terminations that are not pointer events (watchTerminations, below)\n// were expected to need that raw tap after all. Measurement said otherwise.\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/** Whether `widget` is `ancestor` or sits underneath it. */\nconst contains = (ancestor: Gtk.Widget, widget: object): boolean => {\n for (\n let current = widget as Gtk.Widget | null;\n current !== null;\n current = current.getParent()\n ) {\n if (current === ancestor) {\n return true\n }\n }\n return false\n}\n\n/**\n * Every `GtkScrolledWindow` above `source`, innermost first. Nested\n * scrollers are rare but real, and stopping only the innermost would let an\n * outer one take the drag instead.\n */\nconst enclosingScrollers = (source: Gtk.Widget): Gtk.ScrolledWindow[] => {\n const found: Gtk.ScrolledWindow[] = []\n for (\n let widget = source.getParent();\n widget !== null;\n widget = widget.getParent()\n ) {\n if (widget instanceof Gtk.ScrolledWindow) {\n found.push(widget)\n }\n }\n return found\n}\n\n/**\n * `setIsJSResponder`, which is what every RN platform calls the message\n * \"JavaScript has taken this interaction, native scroller stop stealing the\n * drag\". iOS cancels the `UIScrollView` pan when the responder is a\n * descendant; Android has a `JSResponderHandler`; react-native-windows\n * punted on it in 2017, shipped a `manipulationModes` prop instead, and its\n * tracking issues are still open.\n *\n * On GTK the message is `kinetic-scrolling`. Measured on GTK 4 rather than\n * inferred (tests/gtk/components/scroll-arbitration.gtk.test.tsx):\n * `GtkScrolledWindow` installs exactly four gestures of its own —\n * `GestureLongPress`, `GestureSwipe`, `GesturePan`, `GestureDrag`, all\n * touch-only, all in the CAPTURE phase — and turning kinetic scrolling off\n * puts those four, and only those four, into `GTK_PHASE_NONE`. Setting a\n * controller's phase to NONE resets it, so a scroll that had already begun\n * stops there; the wheel and the motion controllers are untouched, so\n * scrolling with a mouse keeps working while a child pans.\n *\n * Why this is needed at all when the `CLAIMED` declaration above already\n * denies ancestor gestures: it is a race, and only sometimes ours.\n * `GtkScrolledWindow` does not claim on press — it claims in `drag-update`,\n * once movement passes `gtk-dnd-drag-threshold` (8 px). A view that claims\n * on press beats it. A view that claims on a MOVE — which is what\n * `onMoveShouldSetPanResponder` does, and it is the commonest shape there\n * is — usually does not, and `CLAIMED` cannot be taken back once the\n * scroller has it. So the claim is not enough on its own, and this is the\n * part that makes a child pan reachable inside a scrolling list.\n *\n * Restores the previous value rather than assuming `true`: an app that\n * turned kinetic scrolling off itself must not have it turned back on.\n */\nconst suspendEnclosingScrollers = (source: Gtk.Widget): (() => void) => {\n const suspended = enclosingScrollers(source).filter((scroller) =>\n scroller.getKineticScrolling(),\n )\n for (const scroller of suspended) {\n scroller.setKineticScrolling(false)\n }\n return () => {\n for (const scroller of suspended) {\n scroller.setKineticScrolling(true)\n }\n }\n}\n\n/**\n * The scroller suspension for the interaction currently under way. Module\n * scope because it is set when the responder is granted and undone when the\n * interaction ends, which are two different events on two different\n * objects; there is only ever one interaction, which is the same assumption\n * the responder system itself is built on (one pointer, one session).\n */\nlet restoreScrollers: (() => void) | null = null\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 onClaim: (source) => {\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 //\n // On the SOURCE's gesture — the one the interaction is arriving through\n // — never on the granted view's. Claiming denies the sequence on every\n // gesture above the claimer and cancels it on everything below, so\n // claiming on an ancestor kills the source and the drag goes silent\n // after the grant. Slice 2 did exactly that, and the common\n // onMoveShouldSetPanResponder shape never received a single move.\n gestures.get(source)?.setState(Gtk.EventSequenceState.CLAIMED)\n // A ResponderHost is deliberately opaque to the pure module; on this\n // platform it is always the Gtk.Widget that registered it.\n restoreScrollers = suspendEnclosingScrollers(source as Gtk.Widget)\n },\n})\n\n/**\n * Everything that ends a gesture without being a pointer event, connected\n * for the length of one interaction and torn down with it.\n *\n * The plan for this task called for a single `GtkEventControllerLegacy` on\n * the toplevel in the capture phase — react-native-web's shape, on the\n * reasoning that a raw event tap is the only way to see terminations that\n * are not pointer events. Measured against GTK, it buys nothing here. Each\n * of the two triggers that survive has a first-class signal that says\n * exactly what we need to know and nothing else, and the rest of RNW's list\n * turned out to arrive as an ordinary gesture `::cancel` (see\n * `TerminationReason`). A legacy controller would have re-derived all of it\n * from a stream of raw events, and its one advantage — hearing events on a\n * sequence GTK has already denied us — matters only for triggers that no\n * longer exist.\n */\nconst watchTerminations = (source: Gtk.Widget): (() => void) => {\n const disposers: (() => void)[] = []\n\n // Window blur. GTK's `is-active` on the toplevel is the same thing the DOM\n // reports as a window `blur` — the window stopped being the active one,\n // which on a desktop usually means the user alt-tabbed mid-drag.\n const root = source.getRoot()\n if (root instanceof Gtk.Window) {\n const onActive = (): void => {\n if (!root.isActive()) {\n responderSystem.terminate(\"blur\")\n }\n }\n root.on(\"notify::is-active\", onActive)\n disposers.push(() => {\n root.off(\"notify::is-active\", onActive)\n })\n }\n\n // An ancestor scrolling. RNW's rule exactly: the scroller has to CONTAIN\n // the responder and not BE it — a ScrollView that holds the responder\n // itself keeps it, and a sibling list scrolling is none of our business.\n // Watching the adjustments rather than a scroll controller is what makes\n // that precise: it fires for a wheel, for a keyboard scroll and for\n // kinetic deceleration alike, and only for this scroller.\n for (const scroller of enclosingScrollers(source)) {\n const onScrolled = (): void => {\n const holder = responderSystem.getResponder()\n if (\n holder !== null &&\n holder !== scroller &&\n contains(scroller, holder)\n ) {\n responderSystem.terminate(\"scroll\")\n }\n }\n for (const adjustment of [\n scroller.getHadjustment(),\n scroller.getVadjustment(),\n ]) {\n adjustment.on(\"value-changed\", onScrolled)\n disposers.push(() => {\n adjustment.off(\"value-changed\", onScrolled)\n })\n }\n }\n\n return () => {\n for (const dispose of disposers) {\n dispose()\n }\n }\n}\n\n/** Exposed for tests and for future ScrollView arbitration. */\nexport const getCurrentResponder = (): ResponderHost | null =>\n responderSystem.getResponder()\n\n/**\n * The out-of-event grant channel, for a recognizer whose mind was changed by\n * a timer rather than by a pointer (`activateAfterLongPress`). See\n * `ResponderSystem.requestResponder` for what it does and\n * docs/research/gestures.md for why the model is extended at all.\n *\n * @internal Not part of the RN surface: an app writes responder props, and\n * nothing in RN asks for the responder from outside an event. This exists for\n * `GestureDetector`, whose recognizers do.\n */\nexport const requestResponder = (widget: Gtk.Widget): boolean =>\n responderSystem.requestResponder(widget)\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 let stopWatching: (() => void) | null = null\n // Whether this sequence was taken from us by something above. See the\n // `sequence-state-changed` handler below.\n let denied = false\n\n const endInteraction = (): void => {\n stopWatching?.()\n stopWatching = null\n restoreScrollers?.()\n restoreScrollers = null\n }\n\n // THE ONE SIGNAL THAT TELLS A THEFT FROM AN ENDING.\n //\n // GTK's claim propagation is asymmetric, and measuring it on 4.22.4\n // corrected `docs/research/gestures.md`, which had it backwards. A claim\n // by a DESCENDANT cancels the ancestor's gesture — `::cancel` then\n // `::end`, and no state transition at all, which the `cancel` handler\n // below already turns into a termination. A claim by an ANCESTOR is the\n // dangerous direction: it DENIES the descendant's sequence and then ends\n // it with an ordinary `drag-end`, exactly the signal a finger lifting\n // produces. Without this handler a native ancestor stealing the drag\n // mid-gesture reaches JS as `onResponderRelease` — a CLEAN RELEASE,\n // indistinguishable from the user letting go, so a drag would commit\n // itself at whatever position the theft happened at.\n //\n // `->DENIED` is the only thing that separates the two, which is why the\n // sequence state has to be watched rather than just the drag signals.\n // Nothing else here can produce it: this module never sets DENIED, and\n // our own CLAIMED is always made on the source, which cancels ancestors\n // rather than denying them.\n drag.on(\n \"sequence-state-changed\",\n (_sequence: unknown, state: Gtk.EventSequenceState) => {\n if (state === Gtk.EventSequenceState.DENIED) {\n denied = true\n }\n },\n )\n\n drag.on(\"drag-begin\", (x: number, y: number) => {\n startX = x\n startY = y\n // A `GtkGestureSingle` denies its own sequence when a press arrives on\n // the wrong button and nothing is down yet, so the flag can survive from\n // before this press. Every interaction starts clean.\n denied = false\n responderSystem.touchStart(widget, createTouch(widget, x, y))\n // Every ancestor's gesture reports the same press; only the one that\n // opened the interaction owns it, and asking the system afterwards is\n // the cheapest way to find out which that was.\n if (responderSystem.getSource() === widget) {\n stopWatching = watchTerminations(widget)\n }\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 const touch = createTouch(widget, startX + offsetX, startY + offsetY)\n // A denied sequence ends with this same signal, and it is not an\n // ending: the interaction was taken away. RN's word for that is a\n // termination, so it goes down the cancel path.\n if (denied) {\n responderSystem.touchCancel(widget, touch)\n } else {\n responderSystem.touchEnd(widget, touch)\n }\n endInteraction()\n })\n // GTK cancels a sequence when something takes it away from us: a native\n // ancestor claiming it, a `GtkDragSource` attached through `Controllers`\n // reaching its threshold, a second mouse button going down for a context\n // menu. RN calls all of that a termination, and unlike RNW we never get\n // to ask first — by the time GTK tells us, the sequence is gone.\n drag.on(\"cancel\", () => {\n responderSystem.touchCancel(widget, createTouch(widget, startX, startY))\n endInteraction()\n })\n\n widget.addController(drag)\n\n return () => {\n endInteraction()\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
|
}
|
|
@@ -64,7 +66,7 @@ if (gtkxConfig.elements !== null) {
|
|
|
64
66
|
}
|
|
65
67
|
const configModuleUrl = new URL("./__virtual-gtkx-config.mjs", import.meta.url)
|
|
66
68
|
.href;
|
|
67
|
-
const lazyElements = Object.fromEntries(gtkxConfig.lazyElements.map((type) => [type, {
|
|
69
|
+
const lazyElements = Object.fromEntries(gtkxConfig.lazyElements.map((type) => [type, { isLazy: true }]));
|
|
68
70
|
const configModuleSource = [
|
|
69
71
|
`export * from "@gtkx/jsx/metadata";`,
|
|
70
72
|
`export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,
|
|
@@ -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, { isLazy: 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
|
}
|
|
@@ -61,7 +65,7 @@ if (gtkxConfig.elements !== null) {
|
|
|
61
65
|
}
|
|
62
66
|
const configModuleUrl = new URL("./__virtual-gtkx-config.mjs", import.meta.url)
|
|
63
67
|
.href;
|
|
64
|
-
const lazyElements = Object.fromEntries(gtkxConfig.lazyElements.map((type) => [type, {
|
|
68
|
+
const lazyElements = Object.fromEntries(gtkxConfig.lazyElements.map((type) => [type, { isLazy: true }]));
|
|
65
69
|
const configModuleSource = [
|
|
66
70
|
`export * from "@gtkx/jsx/metadata";`,
|
|
67
71
|
`export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,
|
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, { isLazy: 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,8 +34,8 @@ 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
|
|
38
|
-
// this replaced was dodging (running from a reconstructed "project that owns
|
|
37
|
+
// from a cwd and trusts a freshness stamp, which is what the retired rc.2-era
|
|
38
|
+
// workaround 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
|
|
41
41
|
// behalf should use the programmatic @gtkx/codegen API instead: it takes the
|
|
@@ -84,7 +84,7 @@ const ensureCodegenStore = async (root) => {
|
|
|
84
84
|
},
|
|
85
85
|
reactSubexports: reactSubexportsOf(react),
|
|
86
86
|
});
|
|
87
|
-
console.warn(result.
|
|
87
|
+
console.warn(result.isRegenerated
|
|
88
88
|
? "[react-native-gtkx] codegen: regenerated stale bindings"
|
|
89
89
|
: "[react-native-gtkx] codegen: bindings up to date");
|
|
90
90
|
}
|