react-native-gtkx 0.1.0-alpha.2 → 0.1.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +41 -8
  2. package/dist/animated/create-animated.js +1 -1
  3. package/dist/animated/create-animated.js.map +1 -1
  4. package/dist/animated/index.js +3 -3
  5. package/dist/animated/index.js.map +1 -1
  6. package/dist/apis/back-handler.d.ts +9 -0
  7. package/dist/apis/back-handler.js +30 -0
  8. package/dist/apis/back-handler.js.map +1 -0
  9. package/dist/apis/host.d.ts +7 -1
  10. package/dist/apis/host.gtkx.js +12 -1
  11. package/dist/apis/host.gtkx.js.map +1 -1
  12. package/dist/apis/host.js.map +1 -1
  13. package/dist/apis/i18n-manager.d.ts +14 -0
  14. package/dist/apis/i18n-manager.js +20 -0
  15. package/dist/apis/i18n-manager.js.map +1 -0
  16. package/dist/apis/index.d.ts +17 -0
  17. package/dist/apis/index.js +5 -0
  18. package/dist/apis/index.js.map +1 -1
  19. package/dist/apis/interaction-manager.d.ts +16 -0
  20. package/dist/apis/interaction-manager.js +96 -0
  21. package/dist/apis/interaction-manager.js.map +1 -0
  22. package/dist/apis/linking.d.ts +4 -0
  23. package/dist/apis/linking.js +9 -0
  24. package/dist/apis/linking.js.map +1 -1
  25. package/dist/components/app-registry.d.ts +2 -0
  26. package/dist/components/app-registry.js +19 -2
  27. package/dist/components/app-registry.js.map +1 -1
  28. package/dist/components/flat-list.d.ts +2 -0
  29. package/dist/components/flat-list.js.map +1 -1
  30. package/dist/components/index.d.ts +1 -1
  31. package/dist/components/index.js +1 -1
  32. package/dist/components/index.js.map +1 -1
  33. package/dist/components/modal.d.ts +1 -1
  34. package/dist/components/pressable.js +4 -4
  35. package/dist/components/pressable.js.map +1 -1
  36. package/dist/components/root.d.ts +10 -1
  37. package/dist/components/root.js +39 -1
  38. package/dist/components/root.js.map +1 -1
  39. package/dist/components/scroll-view.js +58 -5
  40. package/dist/components/scroll-view.js.map +1 -1
  41. package/dist/components/text-input.d.ts +1 -0
  42. package/dist/components/text-input.js +34 -5
  43. package/dist/components/text-input.js.map +1 -1
  44. package/dist/components/use-layout-child.d.ts +1 -1
  45. package/dist/components/use-layout-child.js +22 -2
  46. package/dist/components/use-layout-child.js.map +1 -1
  47. package/dist/components/virtualized-list.d.ts +2 -0
  48. package/dist/components/virtualized-list.js +132 -10
  49. package/dist/components/virtualized-list.js.map +1 -1
  50. package/dist/contracts.js +2 -3
  51. package/dist/contracts.js.map +1 -1
  52. package/dist/gtkx/bridge/index.d.ts +4 -2
  53. package/dist/gtkx/bridge/index.js +7 -3
  54. package/dist/gtkx/bridge/index.js.map +1 -1
  55. package/dist/gtkx/bridge/measure.js +5 -0
  56. package/dist/gtkx/bridge/measure.js.map +1 -1
  57. package/dist/gtkx/bridge/theme.js +1 -1
  58. package/dist/gtkx/bridge/theme.js.map +1 -1
  59. package/dist/gtkx/bridge/use-signal.d.ts +2 -0
  60. package/dist/gtkx/bridge/use-signal.js +31 -0
  61. package/dist/gtkx/bridge/use-signal.js.map +1 -0
  62. package/dist/index.d.ts +2 -2
  63. package/dist/index.js +3 -3
  64. package/dist/index.js.map +1 -1
  65. package/dist/layout/engine.d.ts +4 -0
  66. package/dist/layout/engine.js +97 -5
  67. package/dist/layout/engine.js.map +1 -1
  68. package/dist/layout/node.d.ts +1 -1
  69. package/dist/layout/node.js +8 -5
  70. package/dist/layout/node.js.map +1 -1
  71. package/dist/metro/index.js +1 -0
  72. package/dist/metro/index.js.map +1 -1
  73. package/dist/navigation/index.d.ts +44 -0
  74. package/dist/navigation/index.js +216 -0
  75. package/dist/navigation/index.js.map +1 -0
  76. package/dist/navigation/option-warnings.d.ts +2 -0
  77. package/dist/navigation/option-warnings.js +61 -0
  78. package/dist/navigation/option-warnings.js.map +1 -0
  79. package/dist/navigation/sidebar.d.ts +37 -0
  80. package/dist/navigation/sidebar.js +71 -0
  81. package/dist/navigation/sidebar.js.map +1 -0
  82. package/dist/perf.d.ts +9 -0
  83. package/dist/perf.js +156 -0
  84. package/dist/perf.js.map +1 -0
  85. package/dist/runner/host-dev.js +15 -6
  86. package/dist/runner/host-dev.js.map +1 -1
  87. package/dist/runner/host.js +24 -9
  88. package/dist/runner/host.js.map +1 -1
  89. package/dist/runner/index.js +7 -3
  90. package/dist/runner/index.js.map +1 -1
  91. package/dist/style/colors.js +3 -1
  92. package/dist/style/colors.js.map +1 -1
  93. package/dist/style/index.js +2 -2
  94. package/dist/style/index.js.map +1 -1
  95. package/dist/style/registry.gtkx.js +1 -1
  96. package/dist/style/registry.gtkx.js.map +1 -1
  97. package/dist/style/split-style.js +1 -1
  98. package/dist/style/split-style.js.map +1 -1
  99. package/dist/style/text-align.js +1 -1
  100. package/dist/style/text-align.js.map +1 -1
  101. package/dist/vite/index.d.ts +5 -4
  102. package/dist/vite/index.js +42 -7
  103. package/dist/vite/index.js.map +1 -1
  104. package/package.json +18 -10
  105. package/types.d.ts +13 -0
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../../src/components/scroll-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Children,\n createContext,\n forwardRef,\n useContext,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkBox,\n GtkScrolledWindow,\n queueAllocate,\n queueResize,\n useSignal,\n} from \"../gtkx/bridge/index\"\nimport { HostNodeContext } from \"./host-node\"\nimport { deferDuringAllocate, setStoredOffset } from \"./rect-store\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\nexport type ScrollViewHandle = {\n scrollTo(options: { x?: number; y?: number; animated?: boolean }): void\n scrollToEnd(options?: { animated?: boolean }): void\n}\n\nexport type ScrollEvent = {\n nativeEvent: {\n contentOffset: { x: number; y: number }\n contentSize: { width: number; height: number }\n }\n}\n\nexport type ScrollViewProps = {\n style?: StyleProp\n contentContainerStyle?: StyleProp\n horizontal?: boolean\n // RN sticky headers (vertical lists): the children at these indices pin to\n // the top while scrolled past, each pushed out by the next one.\n stickyHeaderIndices?: readonly number[]\n onScroll?: (event: ScrollEvent) => void\n // RN onContentSizeChange(contentWidth, contentHeight): fires when the\n // scrollable content changes size. GTK's adjustments emit \"changed\" right\n // after the allocation that resized their range — exactly the moment the\n // new scroll extent is real, which windowed lists rely on to reposition.\n onContentSizeChange?: (width: number, height: number) => void\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n testID?: string\n}\n\ntype StickyRecord = { y: number; height: number; widget: Gtk.Widget }\n\n// The sticky registry lives on the nearest ScrollView: any descendant may\n// register a slot with its content-relative geometry (measured children of\n// the ScrollView itself, or windowed list cells with engine-known offsets).\nexport type StickyRegistry = {\n register(key: string, record: StickyRecord): void\n unregister(key: string): void\n}\n\nexport const StickyRegistryContext = createContext<StickyRegistry | null>(null)\n\n// A wrapper around a sticky child: a plain container that reports its layout\n// and widget into the registry, so the scroll handler can translate/reorder\n// the REAL instance (RN semantics — no duplicate is ever rendered, external\n// margins travel with the header exactly as designed). An explicit `top`\n// (windowed cells) overrides the measured position.\nexport const StickySlot = ({\n stickyKey,\n style,\n top,\n onLayout,\n children,\n}: {\n stickyKey: string\n style?: StyleProp\n top?: number\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n}) => {\n const registry = useContext(StickyRegistryContext)\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { host, node } = useLayoutChild(widgetRef, {\n style,\n onLayout: (event) => {\n onLayout?.(event)\n const widget = widgetRef.current\n if (registry && widget) {\n registry.register(stickyKey, {\n y: top ?? event.nativeEvent.layout.y,\n height: event.nativeEvent.layout.height,\n widget,\n })\n }\n },\n })\n useRnContainer(widgetRef, node)\n useLayoutEffect(() => {\n return () => {\n registry?.unregister(stickyKey)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stickyKey])\n return (\n <GtkBox ref={widgetRef}>\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\n// GtkScrolledWindow whose child is a content GtkBox backed by its own Yoga\n// node inside the same engine: the content's RnGtkxLayout measures the engine\n// content size (which grows past the viewport — that IS the scroll range;\n// overflow: scroll on the outer node) and the scrolled window pans it.\nexport const ScrollView = forwardRef<ScrollViewHandle, ScrollViewProps>(\n (\n {\n style,\n contentContainerStyle,\n horizontal = false,\n stickyHeaderIndices,\n onScroll,\n onContentSizeChange,\n onLayout,\n children,\n testID,\n },\n handleRef,\n ) => {\n const outerRef = useRef<Gtk.ScrolledWindow | null>(null)\n const contentRef = useRef<Gtk.Box | null>(null)\n const [scrolled, setScrolled] = useState<Gtk.ScrolledWindow | null>(null)\n\n const { host, node: outerNode } = useLayoutChild(outerRef, {\n // Yoga unconstrains a scroll node's MAIN axis — align it with the\n // scroll direction or a horizontal list's content clamps to the\n // viewport width (hadjustment upper == page).\n style: [\n style,\n { overflow: \"scroll\", flexDirection: horizontal ? \"row\" : \"column\" },\n ],\n onLayout,\n })\n\n const [contentNode] = useState(() => host.engine.createNode())\n // Sticky positions are computed INSIDE the same allocation pass that\n // places the children (beforeAllocate): the viewport has already settled\n // on this frame's scroll offset, so the pinned header lands exactly —\n // reacting to the adjustment signal instead lags a frame and jitters.\n useRnContainer(contentRef, contentNode, {\n beforeAllocate: () => {\n if (stickyRecords.current.size > 0) {\n updateSticky(outerRef.current?.getVadjustment()?.getValue() ?? 0)\n }\n },\n })\n\n // RN semantics: a ScrollView CLIPS its content. Branch B made containers\n // paint-overflow by default, so without this the scrolled-away content\n // (e.g. the original of a pinned sticky header) keeps drawing past the\n // scroll area's edges.\n useLayoutEffect(() => {\n outerRef.current?.setOverflow(Gtk.Overflow.HIDDEN)\n }, [])\n\n useLayoutEffect(() => {\n outerNode.insertChild(contentNode, 0)\n contentNode.setCommit(() => {\n // The content size IS this widget's measure (scroll range) — the\n // ScrolledWindow itself allocates the content widget.\n const widget = contentRef.current\n if (!widget) {\n return\n }\n const queue = (): void => {\n queueResize(widget)\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n contentNode.setCommit(null)\n outerNode.removeChild(contentNode)\n contentNode.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const contentLayout = splitStyle(\n StyleSheet.flatten(contentContainerStyle),\n ).layout\n const contentKey = JSON.stringify({ horizontal, contentLayout })\n useLayoutEffect(() => {\n contentNode.setStyle({\n flexDirection: horizontal ? \"row\" : \"column\",\n alignItems: \"flex-start\",\n ...contentLayout,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [contentNode, contentKey])\n\n useImperativeHandle(handleRef, () => ({\n scrollTo({ x, y }) {\n const widget = outerRef.current\n if (!widget) {\n return\n }\n if (y !== undefined) {\n widget.getVadjustment()?.setValue(y)\n }\n if (x !== undefined) {\n widget.getHadjustment()?.setValue(x)\n }\n },\n scrollToEnd() {\n const widget = outerRef.current\n const adjustment = horizontal\n ? widget?.getHadjustment()\n : widget?.getVadjustment()\n if (adjustment) {\n adjustment.setValue(adjustment.getUpper() - adjustment.getPageSize())\n }\n },\n }))\n\n // --- sticky headers -------------------------------------------------\n // The RN model, faithfully: the REAL child is translated (no duplicate,\n // state preserved). RN gives the pinned cell a zIndex; GTK's z-order is\n // sibling paint order, so the active slot is reordered to be the LAST\n // content child while pinned and restored afterwards. Per-frame movement\n // goes through the rect-store offset fast path — zero React work while\n // scrolling.\n const stickySet = stickyHeaderIndices ?? []\n const stickyRecords = useRef(new Map<string, StickyRecord>())\n const restoreSibling = useRef(new Map<string, Gtk.Widget | null>())\n const activeStickyRef = useRef<string | null>(null)\n const [hasSticky, setHasSticky] = useState(false)\n\n const stickyRegistry = useRef<StickyRegistry>({\n register: (key, record) => {\n stickyRecords.current.set(key, record)\n setHasSticky(true)\n const parent = record.widget.getParent()\n if (parent) {\n queueAllocate(parent)\n }\n },\n unregister: (key) => {\n stickyRecords.current.delete(key)\n restoreSibling.current.delete(key)\n if (activeStickyRef.current === key) {\n activeStickyRef.current = null\n }\n if (stickyRecords.current.size === 0) {\n setHasSticky(false)\n }\n },\n })\n\n const updateSticky = (rawScrollTop: number): void => {\n if (stickyRecords.current.size === 0) {\n return\n }\n // The viewport translates the content by the FRACTIONAL adjustment\n // value while widget allocations are integer — an unquantized pin\n // disagrees with the translation by ±1px and shimmers every frame.\n // Frame telemetry (docs/research/sticky-probe.md) proved the viewport quantizes\n // like floor: with Math.floor the header's window-relative position is\n // a flat 0.00 across every frame; round oscillates 0/1, ceil sits at 1.\n const scrollTop = Math.floor(rawScrollTop)\n let active: string | null = null\n let next: StickyRecord | null = null\n for (const [key, record] of stickyRecords.current) {\n if (record.y <= scrollTop) {\n if (\n active === null ||\n record.y >= stickyRecords.current.get(active)!.y\n ) {\n active = key\n }\n } else if (next === null || record.y < next.y) {\n next = record\n }\n }\n\n const previous = activeStickyRef.current\n if (previous !== active) {\n activeStickyRef.current = active\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n if (record) {\n setStoredOffset(record.widget, 0, 0)\n }\n }\n // Reordering widgets queues GTK work — not allowed mid-allocation.\n // The z-switch lands a frame later; the POSITION is already exact.\n setTimeout(() => {\n applyStickyReorder(previous, active)\n }, 0)\n }\n\n if (active !== null) {\n const record = stickyRecords.current.get(active)!\n // Pin at the viewport top; the next sticky header pushes it out.\n const pinned = next\n ? Math.min(scrollTop, next.y - record.height)\n : scrollTop\n setStoredOffset(record.widget, 0, Math.max(0, pinned - record.y))\n }\n }\n\n const applyStickyReorder = (\n previous: string | null,\n active: string | null,\n ): void => {\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n // Slot parents are always our GtkBox containers.\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n // Put the slot back where the reconciler expects it.\n parent.reorderChildAfter(\n record.widget,\n restoreSibling.current.get(previous) ?? null,\n )\n queueAllocate(parent)\n }\n }\n if (active !== null) {\n const record = stickyRecords.current.get(active)\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n restoreSibling.current.set(active, record.widget.getPrevSibling())\n parent.reorderChildAfter(record.widget, parent.getLastChild())\n queueAllocate(parent)\n }\n }\n }\n\n const emitScroll = (): void => {\n if (!onScroll) {\n return\n }\n const widget = outerRef.current\n const contentRect = contentNode.getRect()\n if (!widget || !contentRect) {\n return\n }\n onScroll({\n nativeEvent: {\n contentOffset: {\n x: widget.getHadjustment()?.getValue() ?? 0,\n y: widget.getVadjustment()?.getValue() ?? 0,\n },\n contentSize: { width: contentRect.width, height: contentRect.height },\n },\n })\n }\n\n const adjustment = horizontal\n ? (scrolled?.getHadjustment() ?? null)\n : (scrolled?.getVadjustment() ?? null)\n const onAdjustment = (): void => {\n emitScroll()\n }\n\n // Content-size reports dedupe on the engine rect: \"changed\" also fires\n // for pure viewport (page-size) changes, which RN does not report.\n const lastContentSize = useRef({ width: -1, height: -1 })\n const onRangeChanged = (): void => {\n if (!onContentSizeChange) {\n return\n }\n const rect = contentNode.getRect()\n if (!rect) {\n return\n }\n const last = lastContentSize.current\n if (rect.width === last.width && rect.height === last.height) {\n return\n }\n lastContentSize.current = { width: rect.width, height: rect.height }\n onContentSizeChange(rect.width, rect.height)\n }\n\n // Frame-synced sticky driver: a pure scroll TRANSLATES the content\n // without re-allocating it (same size → GTK skips the vfunc), so signal\n // handlers land a frame late and the pinned header jitters. A tick\n // callback runs in the frame's UPDATE phase, before layout: when the\n // scroll offset moved, queue an allocation for THIS frame — the\n // translation and the pin correction then paint atomically.\n useLayoutEffect(() => {\n if (!hasSticky || horizontal) {\n return\n }\n const widget = scrolled\n if (!widget) {\n return\n }\n const id = widget.addTickCallback(() => {\n // Unconditionally, every frame: the scrolled window's own kinetic\n // tick may run AFTER ours, so comparing values here can miss the\n // frame's final offset. The allocation itself reads the adjustment\n // in the LAYOUT phase — always after every update-phase mutation —\n // so queuing each frame guarantees a same-frame correction.\n const content = contentRef.current\n if (content) {\n queueAllocate(content)\n }\n return true\n })\n return () => {\n widget.removeTickCallback(id)\n }\n }, [scrolled, hasSticky, horizontal])\n useSignal(adjustment, \"value-changed\", onAdjustment)\n // Both axes report into the same handler — RN's callback carries both\n // dimensions no matter which one moved.\n useSignal(scrolled?.getVadjustment() ?? null, \"changed\", onRangeChanged)\n useSignal(scrolled?.getHadjustment() ?? null, \"changed\", onRangeChanged)\n\n return (\n <GtkScrolledWindow\n ref={(widget: Gtk.ScrolledWindow | null) => {\n outerRef.current = widget\n setScrolled(widget)\n }}\n name={testID}\n >\n <GtkBox ref={contentRef}>\n <HostNodeContext.Provider\n value={{\n engine: host.engine,\n node: contentNode,\n widgetRef: contentRef,\n }}\n >\n <StickyRegistryContext.Provider value={stickyRegistry.current}>\n {stickySet.length === 0\n ? children\n : Children.toArray(children).map((child, index) =>\n stickySet.includes(index) ? (\n <StickySlot\n key={`sticky-slot-${index}`}\n stickyKey={`index-${index}`}\n >\n {child}\n </StickySlot>\n ) : (\n child\n ),\n )}\n </StickyRegistryContext.Provider>\n </HostNodeContext.Provider>\n </GtkBox>\n </GtkScrolledWindow>\n )\n },\n)\nScrollView.displayName = \"ScrollView\"\n"]}
1
+ {"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../../src/components/scroll-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Children,\n createContext,\n forwardRef,\n useContext,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkBox,\n GtkScrolledWindow,\n queueAllocate,\n queueResize,\n useSignal,\n} from \"../gtkx/bridge/index\"\nimport {\n ensurePerfReporter,\n perfAddTime,\n perfCount,\n perfEnabled,\n perfFrameTick,\n perfNow,\n} from \"../perf\"\nimport { HostNodeContext } from \"./host-node\"\nimport { deferDuringAllocate, setStoredOffset } from \"./rect-store\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\nexport type ScrollViewHandle = {\n scrollTo(options: { x?: number; y?: number; animated?: boolean }): void\n scrollToEnd(options?: { animated?: boolean }): void\n}\n\nexport type ScrollEvent = {\n nativeEvent: {\n contentOffset: { x: number; y: number }\n contentSize: { width: number; height: number }\n }\n}\n\nexport type ScrollViewProps = {\n style?: StyleProp\n contentContainerStyle?: StyleProp\n horizontal?: boolean\n // RN sticky headers (vertical lists): the children at these indices pin to\n // the top while scrolled past, each pushed out by the next one.\n stickyHeaderIndices?: readonly number[]\n onScroll?: (event: ScrollEvent) => void\n // RN onContentSizeChange(contentWidth, contentHeight): fires when the\n // scrollable content changes size. GTK's adjustments emit \"changed\" right\n // after the allocation that resized their range — exactly the moment the\n // new scroll extent is real, which windowed lists rely on to reposition.\n onContentSizeChange?: (width: number, height: number) => void\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n testID?: string\n}\n\ntype StickyRecord = { y: number; height: number; widget: Gtk.Widget }\n\n// The sticky registry lives on the nearest ScrollView: any descendant may\n// register a slot with its content-relative geometry (measured children of\n// the ScrollView itself, or windowed list cells with engine-known offsets).\nexport type StickyRegistry = {\n register(key: string, record: StickyRecord): void\n unregister(key: string): void\n}\n\nexport const StickyRegistryContext = createContext<StickyRegistry | null>(null)\n\n// A wrapper around a sticky child: a plain container that reports its layout\n// and widget into the registry, so the scroll handler can translate/reorder\n// the REAL instance (RN semantics — no duplicate is ever rendered, external\n// margins travel with the header exactly as designed). An explicit `top`\n// (windowed cells) overrides the measured position.\nexport const StickySlot = ({\n stickyKey,\n style,\n top,\n onLayout,\n children,\n}: {\n stickyKey: string\n style?: StyleProp\n top?: number\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n}) => {\n const registry = useContext(StickyRegistryContext)\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { host, node } = useLayoutChild(widgetRef, {\n style,\n onLayout: (event) => {\n onLayout?.(event)\n const widget = widgetRef.current\n if (registry && widget) {\n registry.register(stickyKey, {\n y: top ?? event.nativeEvent.layout.y,\n height: event.nativeEvent.layout.height,\n widget,\n })\n }\n },\n })\n useRnContainer(widgetRef, node)\n useLayoutEffect(() => {\n return () => {\n registry?.unregister(stickyKey)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stickyKey])\n return (\n <GtkBox ref={widgetRef}>\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\n// GtkScrolledWindow whose child is a content GtkBox backed by its own Yoga\n// node inside the same engine: the content's RnGtkxLayout measures the engine\n// content size (which grows past the viewport — that IS the scroll range;\n// overflow: scroll on the outer node) and the scrolled window pans it.\nexport const ScrollView = forwardRef<ScrollViewHandle, ScrollViewProps>(\n (\n {\n style,\n contentContainerStyle,\n horizontal = false,\n stickyHeaderIndices,\n onScroll,\n onContentSizeChange,\n onLayout,\n children,\n testID,\n },\n handleRef,\n ) => {\n const outerRef = useRef<Gtk.ScrolledWindow | null>(null)\n const contentRef = useRef<Gtk.Box | null>(null)\n const [scrolled, setScrolled] = useState<Gtk.ScrolledWindow | null>(null)\n\n const { host, node: outerNode } = useLayoutChild(outerRef, {\n // Yoga unconstrains a scroll node's MAIN axis — align it with the\n // scroll direction or a horizontal list's content clamps to the\n // viewport width (hadjustment upper == page).\n style: [\n style,\n { overflow: \"scroll\", flexDirection: horizontal ? \"row\" : \"column\" },\n ],\n onLayout,\n })\n\n const [contentNode] = useState(() => host.engine.createNode())\n // Sticky positions are computed INSIDE the same allocation pass that\n // places the children (beforeAllocate): the viewport has already settled\n // on this frame's scroll offset, so the pinned header lands exactly —\n // reacting to the adjustment signal instead lags a frame and jitters.\n useRnContainer(contentRef, contentNode, {\n beforeAllocate: () => {\n if (stickyRecords.current.size > 0) {\n updateSticky(outerRef.current?.getVadjustment()?.getValue() ?? 0)\n }\n },\n })\n\n // RN semantics: a ScrollView CLIPS its content. Branch B made containers\n // paint-overflow by default, so without this the scrolled-away content\n // (e.g. the original of a pinned sticky header) keeps drawing past the\n // scroll area's edges.\n useLayoutEffect(() => {\n outerRef.current?.setOverflow(Gtk.Overflow.HIDDEN)\n }, [])\n\n useLayoutEffect(() => {\n outerNode.insertChild(contentNode, 0)\n contentNode.setCommit(() => {\n // The content size IS this widget's measure (scroll range) — the\n // ScrolledWindow itself allocates the content widget.\n const widget = contentRef.current\n if (!widget) {\n return\n }\n const queue = (): void => {\n queueResize(widget)\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n contentNode.setCommit(null)\n outerNode.removeChild(contentNode)\n contentNode.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const contentLayout = splitStyle(\n StyleSheet.flatten(contentContainerStyle),\n ).layout\n const contentKey = JSON.stringify({ horizontal, contentLayout })\n useLayoutEffect(() => {\n contentNode.setStyle({\n flexDirection: horizontal ? \"row\" : \"column\",\n alignItems: \"flex-start\",\n ...contentLayout,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [contentNode, contentKey])\n\n useImperativeHandle(handleRef, () => ({\n scrollTo({ x, y }) {\n const widget = outerRef.current\n if (!widget) {\n return\n }\n if (y !== undefined) {\n widget.getVadjustment()?.setValue(y)\n }\n if (x !== undefined) {\n widget.getHadjustment()?.setValue(x)\n }\n },\n scrollToEnd() {\n const widget = outerRef.current\n const adjustment = horizontal\n ? widget?.getHadjustment()\n : widget?.getVadjustment()\n if (adjustment) {\n adjustment.setValue(adjustment.getUpper() - adjustment.getPageSize())\n }\n },\n }))\n\n // --- sticky headers -------------------------------------------------\n // The RN model, faithfully: the REAL child is translated (no duplicate,\n // state preserved). RN gives the pinned cell a zIndex; GTK's z-order is\n // sibling paint order, so the active slot is reordered to be the LAST\n // content child while pinned and restored afterwards. Per-frame movement\n // goes through the rect-store offset fast path — zero React work while\n // scrolling.\n const stickySet = stickyHeaderIndices ?? []\n const stickyRecords = useRef(new Map<string, StickyRecord>())\n const restoreSibling = useRef(new Map<string, Gtk.Widget | null>())\n const activeStickyRef = useRef<string | null>(null)\n const [hasSticky, setHasSticky] = useState(false)\n\n const stickyRegistry = useRef<StickyRegistry>({\n register: (key, record) => {\n stickyRecords.current.set(key, record)\n setHasSticky(true)\n const parent = record.widget.getParent()\n if (parent) {\n queueAllocate(parent)\n }\n },\n unregister: (key) => {\n stickyRecords.current.delete(key)\n restoreSibling.current.delete(key)\n if (activeStickyRef.current === key) {\n activeStickyRef.current = null\n }\n if (stickyRecords.current.size === 0) {\n setHasSticky(false)\n }\n },\n })\n\n const updateSticky = (rawScrollTop: number): void => {\n if (stickyRecords.current.size === 0) {\n return\n }\n // The viewport translates the content by the FRACTIONAL adjustment\n // value while widget allocations are integer — an unquantized pin\n // disagrees with the translation by ±1px and shimmers every frame.\n // Frame telemetry (docs/research/sticky-probe.md) proved the viewport quantizes\n // like floor: with Math.floor the header's window-relative position is\n // a flat 0.00 across every frame; round oscillates 0/1, ceil sits at 1.\n const scrollTop = Math.floor(rawScrollTop)\n let active: string | null = null\n let next: StickyRecord | null = null\n for (const [key, record] of stickyRecords.current) {\n if (record.y <= scrollTop) {\n if (\n active === null ||\n record.y >= stickyRecords.current.get(active)!.y\n ) {\n active = key\n }\n } else if (next === null || record.y < next.y) {\n next = record\n }\n }\n\n const previous = activeStickyRef.current\n if (previous !== active) {\n activeStickyRef.current = active\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n if (record) {\n setStoredOffset(record.widget, 0, 0)\n }\n }\n // Reordering widgets queues GTK work — not allowed mid-allocation.\n // The z-switch lands a frame later; the POSITION is already exact.\n setTimeout(() => {\n applyStickyReorder(previous, active)\n }, 0)\n }\n\n if (active !== null) {\n const record = stickyRecords.current.get(active)!\n // Pin at the viewport top; the next sticky header pushes it out.\n const pinned = next\n ? Math.min(scrollTop, next.y - record.height)\n : scrollTop\n setStoredOffset(record.widget, 0, Math.max(0, pinned - record.y))\n }\n }\n\n const applyStickyReorder = (\n previous: string | null,\n active: string | null,\n ): void => {\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n // Slot parents are always our GtkBox containers.\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n // Put the slot back where the reconciler expects it.\n parent.reorderChildAfter(\n record.widget,\n restoreSibling.current.get(previous) ?? null,\n )\n queueAllocate(parent)\n }\n }\n if (active !== null) {\n const record = stickyRecords.current.get(active)\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n restoreSibling.current.set(active, record.widget.getPrevSibling())\n parent.reorderChildAfter(record.widget, parent.getLastChild())\n queueAllocate(parent)\n }\n }\n }\n\n const emitScroll = (): void => {\n if (!onScroll) {\n return\n }\n const widget = outerRef.current\n const contentRect = contentNode.getRect()\n if (!widget || !contentRect) {\n return\n }\n onScroll({\n nativeEvent: {\n contentOffset: {\n x: widget.getHadjustment()?.getValue() ?? 0,\n y: widget.getVadjustment()?.getValue() ?? 0,\n },\n contentSize: { width: contentRect.width, height: contentRect.height },\n },\n })\n }\n\n const adjustment = horizontal\n ? (scrolled?.getHadjustment() ?? null)\n : (scrolled?.getVadjustment() ?? null)\n const onAdjustment = (): void => {\n if (!perfEnabled) {\n emitScroll()\n return\n }\n // Perf: full wall time of one scroll tick's JS work — the FFI reads in\n // emitScroll plus the app/VirtualizedList onScroll handler (windowing,\n // viewability, endReached) — everything that blocks the GTK frame.\n perfCount(\"scroll.events\")\n const start = perfNow()\n emitScroll()\n perfAddTime(\"scroll.js\", perfNow() - start)\n }\n\n // Content-size reports dedupe on the engine rect: \"changed\" also fires\n // for pure viewport (page-size) changes, which RN does not report.\n const lastContentSize = useRef({ width: -1, height: -1 })\n const onRangeChanged = (): void => {\n if (!onContentSizeChange) {\n return\n }\n const rect = contentNode.getRect()\n if (!rect) {\n return\n }\n const last = lastContentSize.current\n if (rect.width === last.width && rect.height === last.height) {\n return\n }\n lastContentSize.current = { width: rect.width, height: rect.height }\n onContentSizeChange(rect.width, rect.height)\n }\n\n // Frame-synced sticky driver: a pure scroll TRANSLATES the content\n // without re-allocating it (same size → GTK skips the vfunc), so signal\n // handlers land a frame late and the pinned header jitters. A tick\n // callback runs in the frame's UPDATE phase, before layout: when the\n // scroll offset moved, queue an allocation for THIS frame — the\n // translation and the pin correction then paint atomically.\n useLayoutEffect(() => {\n if (!hasSticky || horizontal) {\n return\n }\n const widget = scrolled\n if (!widget) {\n return\n }\n const vadjustment = widget.getVadjustment()\n let lastValue = vadjustment?.getValue() ?? 0\n // Frames to keep requeueing after the last observed move. The scrolled\n // window's own kinetic tick may run AFTER ours, so this tick's read can\n // be one frame stale: without the grace window the first frame of a\n // deceleration (its value change lands after our read) would miss its\n // correction. Kinetic deceleration changes the value every frame, so\n // three frames of slack cover the handoff at both ends of the motion.\n const graceFrames = 3\n let remaining = graceFrames\n const id = widget.addTickCallback(() => {\n perfCount(\"sticky.ticks\")\n const value = vadjustment?.getValue() ?? 0\n if (value !== lastValue) {\n lastValue = value\n remaining = graceFrames\n } else if (remaining > 0) {\n remaining -= 1\n } else {\n // At rest: the pin is already correct and nothing translated it,\n // so an allocation pass per frame would be pure idle cost.\n return true\n }\n perfCount(\"sticky.queues\")\n const content = contentRef.current\n if (content) {\n queueAllocate(content)\n }\n return true\n })\n return () => {\n widget.removeTickCallback(id)\n }\n }, [scrolled, hasSticky, horizontal])\n\n // Perf: observe the GTK frame clock through a tick callback — the delta\n // between consecutive ticks is the real frame interval (late frames show\n // up directly). Note: registering a tick callback keeps the frame clock\n // running, so idle seconds show ~60 ticks too; the reporter separates\n // load by the accompanying counters.\n useLayoutEffect(() => {\n if (!perfEnabled) {\n return\n }\n ensurePerfReporter()\n const widget = scrolled\n if (!widget) {\n return\n }\n const id = widget.addTickCallback(() => {\n perfFrameTick(perfNow())\n return true\n })\n return () => {\n widget.removeTickCallback(id)\n }\n }, [scrolled])\n useSignal(adjustment, \"value-changed\", onAdjustment)\n // Both axes report into the same handler — RN's callback carries both\n // dimensions no matter which one moved.\n useSignal(scrolled?.getVadjustment() ?? null, \"changed\", onRangeChanged)\n useSignal(scrolled?.getHadjustment() ?? null, \"changed\", onRangeChanged)\n\n return (\n <GtkScrolledWindow\n ref={(widget: Gtk.ScrolledWindow | null) => {\n outerRef.current = widget\n setScrolled(widget)\n }}\n name={testID}\n >\n <GtkBox ref={contentRef}>\n <HostNodeContext.Provider\n value={{\n engine: host.engine,\n node: contentNode,\n widgetRef: contentRef,\n }}\n >\n <StickyRegistryContext.Provider value={stickyRegistry.current}>\n {stickySet.length === 0\n ? children\n : Children.toArray(children).map((child, index) =>\n stickySet.includes(index) ? (\n <StickySlot\n key={`sticky-slot-${index}`}\n stickyKey={`index-${index}`}\n >\n {child}\n </StickySlot>\n ) : (\n child\n ),\n )}\n </StickyRegistryContext.Provider>\n </HostNodeContext.Provider>\n </GtkBox>\n </GtkScrolledWindow>\n )\n },\n)\nScrollView.displayName = \"ScrollView\"\n"]}
@@ -16,6 +16,7 @@ export type TextInputProps = {
16
16
  editable?: boolean;
17
17
  keyboardType?: "default" | "numeric" | "email-address" | "phone-pad" | "url";
18
18
  multiline?: boolean;
19
+ clearButtonMode?: "never" | "while-editing" | "unless-editing" | "always";
19
20
  style?: StyleProp;
20
21
  onLayout?: (event: LayoutEvent) => void;
21
22
  testID?: string;
@@ -10,8 +10,9 @@ const INPUT_PURPOSE = {
10
10
  "phone-pad": Gtk.InputPurpose.PHONE,
11
11
  url: Gtk.InputPurpose.URL,
12
12
  };
13
- // RC1-WORKAROUND(controllers-as-children): see docs/gtkx-rc1-vs-main.md
14
- // rc.1: controllers attach imperatively (JSX children work on main only).
13
+ // The focus controller is attached imperatively (rc.2 also offers a
14
+ // declarative `controllers` slot): one wiring per widget, handlers read from a
15
+ // ref, so changing onFocus/onBlur never re-creates the controller.
15
16
  const useFocusController = (widgetRef, onFocus, onBlur) => {
16
17
  const handlers = useRef({ onFocus, onBlur });
17
18
  handlers.current = { onFocus, onBlur };
@@ -35,8 +36,9 @@ const useFocusController = (widgetRef, onFocus, onBlur) => {
35
36
  // Single-line input over GtkEntry. gtkx's controlled-text behavior keeps the
36
37
  // widget in sync with the `text` prop (RN controlled semantics); uncontrolled
37
38
  // usage passes defaultValue once.
38
- const SingleLineTextInput = ({ value, defaultValue, onChangeText, onSubmitEditing, onFocus, onBlur, placeholder, secureTextEntry = false, editable = true, keyboardType = "default", style, onLayout, testID, }) => {
39
+ const SingleLineTextInput = ({ value, defaultValue, onChangeText, onSubmitEditing, onFocus, onBlur, placeholder, secureTextEntry = false, editable = true, keyboardType = "default", clearButtonMode = "never", style, onLayout, testID, }) => {
39
40
  const widgetRef = useRef(null);
41
+ const [focused, setFocused] = useState(false);
40
42
  useLayoutChild(widgetRef, {
41
43
  style,
42
44
  onLayout,
@@ -46,8 +48,35 @@ const SingleLineTextInput = ({ value, defaultValue, onChangeText, onSubmitEditin
46
48
  extraLayout: { minWidth: 60 },
47
49
  });
48
50
  const controlled = value !== undefined;
49
- useFocusController(widgetRef, onFocus, onBlur);
50
- return (_jsx(GtkEntry, { ref: widgetRef, name: testID, text: controlled ? value : (defaultValue ?? ""), placeholderText: placeholder ?? "", visibility: !secureTextEntry, editable: editable, sensitive: editable, inputPurpose: INPUT_PURPOSE[keyboardType], onChanged: () => {
51
+ useFocusController(widgetRef, () => {
52
+ setFocused(true);
53
+ onFocus?.();
54
+ }, () => {
55
+ setFocused(false);
56
+ onBlur?.();
57
+ });
58
+ // RN semantics: the affordance only shows when there is something to
59
+ // clear, and while-editing / unless-editing follow focus.
60
+ const text = controlled ? value : undefined;
61
+ const hasText = text !== undefined
62
+ ? text.length > 0
63
+ : (widgetRef.current?.getText().length ?? 0) > 0;
64
+ const showClear = hasText &&
65
+ (clearButtonMode === "always" ||
66
+ (clearButtonMode === "while-editing" && focused) ||
67
+ (clearButtonMode === "unless-editing" && !focused));
68
+ return (_jsx(GtkEntry, { ref: widgetRef, name: testID, secondaryIconName: showClear ? "edit-clear-symbolic" : null, secondaryIconActivatable: showClear, secondaryIconTooltipText: showClear ? "Clear" : null, onIconRelease: () => {
69
+ const widget = widgetRef.current;
70
+ if (!widget) {
71
+ return;
72
+ }
73
+ // Uncontrolled inputs clear themselves; controlled ones report an
74
+ // empty string and let the owner drive the value (RN contract).
75
+ if (!controlled) {
76
+ widget.setText("");
77
+ }
78
+ onChangeText?.("");
79
+ }, text: controlled ? value : (defaultValue ?? ""), placeholderText: placeholder ?? "", visibility: !secureTextEntry, editable: editable, sensitive: editable, inputPurpose: INPUT_PURPOSE[keyboardType], onChanged: () => {
51
80
  const widget = widgetRef.current;
52
81
  if (widget) {
53
82
  onChangeText?.(widget.getText());
@@ -1 +1 @@
1
- {"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/components/text-input.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState } from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkEntry,\n GtkLabel,\n GtkScrolledWindow,\n GtkTextView,\n type Gtk as GtkNs,\n} from \"../gtkx/bridge/index\"\nimport { useLayoutChild, type LayoutEvent } from \"./use-layout-child\"\nimport { View } from \"./view\"\n\nexport type TextInputProps = {\n value?: string\n defaultValue?: string\n onChangeText?: (text: string) => void\n onSubmitEditing?: (event: { nativeEvent: { text: string } }) => void\n onFocus?: () => void\n onBlur?: () => void\n placeholder?: string\n secureTextEntry?: boolean\n editable?: boolean\n keyboardType?: \"default\" | \"numeric\" | \"email-address\" | \"phone-pad\" | \"url\"\n // RN: a multiline input needs a height in the style; Enter inserts a\n // newline and never fires onSubmitEditing.\n multiline?: boolean\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n}\n\nconst INPUT_PURPOSE: Record<\n NonNullable<TextInputProps[\"keyboardType\"]>,\n Gtk.InputPurpose\n> = {\n default: Gtk.InputPurpose.FREE_FORM,\n numeric: Gtk.InputPurpose.NUMBER,\n \"email-address\": Gtk.InputPurpose.EMAIL,\n \"phone-pad\": Gtk.InputPurpose.PHONE,\n url: Gtk.InputPurpose.URL,\n}\n\n// RC1-WORKAROUND(controllers-as-children): see docs/gtkx-rc1-vs-main.md\n// rc.1: controllers attach imperatively (JSX children work on main only).\nconst useFocusController = (\n widgetRef: React.RefObject<GtkNs.Widget | null>,\n onFocus?: () => void,\n onBlur?: () => void,\n): void => {\n const handlers = useRef({ onFocus, onBlur })\n handlers.current = { onFocus, onBlur }\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const focus = new Gtk.EventControllerFocus()\n const enter = (): void => handlers.current.onFocus?.()\n const leave = (): void => handlers.current.onBlur?.()\n focus.on(\"enter\", enter)\n focus.on(\"leave\", leave)\n widget.addController(focus)\n return () => {\n widget.removeController(focus)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n\n// Single-line input over GtkEntry. gtkx's controlled-text behavior keeps the\n// widget in sync with the `text` prop (RN controlled semantics); uncontrolled\n// usage passes defaultValue once.\nconst SingleLineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onSubmitEditing,\n onFocus,\n onBlur,\n placeholder,\n secureTextEntry = false,\n editable = true,\n keyboardType = \"default\",\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const widgetRef = useRef<GtkNs.Entry | null>(null)\n\n useLayoutChild(widgetRef, {\n style,\n onLayout,\n // The entry measures itself (theme-accurate height); width is driven by\n // the style (flex/width), with a small floor for usability.\n measureFromWidget: true,\n extraLayout: { minWidth: 60 },\n })\n\n const controlled = value !== undefined\n\n useFocusController(widgetRef, onFocus, onBlur)\n\n return (\n <GtkEntry\n ref={widgetRef}\n name={testID}\n text={controlled ? value : (defaultValue ?? \"\")}\n placeholderText={placeholder ?? \"\"}\n visibility={!secureTextEntry}\n editable={editable}\n sensitive={editable}\n inputPurpose={INPUT_PURPOSE[keyboardType]}\n onChanged={() => {\n const widget = widgetRef.current\n if (widget) {\n onChangeText?.(widget.getText())\n }\n }}\n onActivate={() => {\n const widget = widgetRef.current\n if (widget) {\n onSubmitEditing?.({ nativeEvent: { text: widget.getText() } })\n }\n }}\n />\n )\n}\n\nconst readBuffer = (buffer: GtkNs.TextBuffer): string =>\n buffer.getText(buffer.getStartIter(), buffer.getEndIter(), true)\n\n// GtkTextView has no native placeholder — a dim, click-transparent label\n// sits over the empty view (RN shows the placeholder while empty, focused\n// or not).\nconst MultilinePlaceholder = ({ text }: { text: string }) => {\n const labelRef = useRef<GtkNs.Label | null>(null)\n useLayoutChild(labelRef, {\n style: { position: \"absolute\", left: 12, top: 8 },\n onLayout: undefined,\n })\n useLayoutEffect(() => {\n labelRef.current?.setCanTarget(false)\n labelRef.current?.addCssClass(\"dim-label\")\n }, [])\n return (\n <GtkLabel\n ref={labelRef}\n label={text}\n />\n )\n}\n\n// Multiline input over GtkTextView in a GtkScrolledWindow: word wrap, the\n// style sets the box (RN requires a height for multiline), overflowing\n// content scrolls inside. The buffer syncs with `value` under RN controlled\n// semantics; Enter inserts a newline (onSubmitEditing never fires — RN\n// multiline behavior).\nconst MultilineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onFocus,\n onBlur,\n placeholder,\n editable = true,\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const scrolledRef = useRef<GtkNs.ScrolledWindow | null>(null)\n const viewRef = useRef<GtkNs.TextView | null>(null)\n const controlled = value !== undefined\n const [empty, setEmpty] = useState(\n (controlled ? (value ?? \"\") : (defaultValue ?? \"\")) === \"\",\n )\n\n const suppressEcho = useRef(false)\n const latest = useRef({ onChangeText })\n latest.current = { onChangeText }\n\n useLayoutEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n // Breathing room akin to GtkEntry's built-in padding.\n view.setLeftMargin(10)\n view.setRightMargin(10)\n view.setTopMargin(8)\n view.setBottomMargin(8)\n const buffer = view.getBuffer()\n const initial = controlled ? (value ?? \"\") : (defaultValue ?? \"\")\n if (initial !== \"\") {\n suppressEcho.current = true\n buffer.setText(initial, -1)\n suppressEcho.current = false\n }\n const changed = (): void => {\n const text = readBuffer(buffer)\n setEmpty(text === \"\")\n if (!suppressEcho.current) {\n latest.current.onChangeText?.(text)\n }\n }\n buffer.on(\"changed\", changed)\n return () => {\n buffer.off(\"changed\", changed)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // RN controlled semantics: the prop wins over whatever was typed.\n useLayoutEffect(() => {\n if (!controlled) {\n return\n }\n const view = viewRef.current\n if (!view) {\n return\n }\n const buffer = view.getBuffer()\n const next = value ?? \"\"\n if (readBuffer(buffer) !== next) {\n suppressEcho.current = true\n buffer.setText(next, -1)\n suppressEcho.current = false\n setEmpty(next === \"\")\n }\n }, [controlled, value])\n\n useFocusController(viewRef, onFocus, onBlur)\n\n return (\n <View\n style={[style, { minHeight: 36, minWidth: 60 }]}\n onLayout={onLayout}\n >\n <ScrolledFill scrolledRef={scrolledRef}>\n <GtkTextView\n ref={viewRef}\n name={testID}\n editable={editable}\n sensitive={editable}\n wrapMode={Gtk.WrapMode.WORD_CHAR}\n />\n </ScrolledFill>\n {empty && placeholder ? (\n <MultilinePlaceholder text={placeholder} />\n ) : null}\n </View>\n )\n}\n\n// The scrolled window fills the styled box exactly (its own layout child).\nconst ScrolledFill = ({\n scrolledRef,\n children,\n}: {\n scrolledRef: React.RefObject<GtkNs.ScrolledWindow | null>\n children: React.ReactNode\n}) => {\n useLayoutChild(scrolledRef, {\n style: { position: \"absolute\", left: 0, right: 0, top: 0, bottom: 0 },\n onLayout: undefined,\n })\n return <GtkScrolledWindow ref={scrolledRef}>{children}</GtkScrolledWindow>\n}\n\nexport const TextInput = (props: TextInputProps) =>\n props.multiline ? (\n <MultilineTextInput {...props} />\n ) : (\n <SingleLineTextInput {...props} />\n )\n"]}
1
+ {"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/components/text-input.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState } from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkEntry,\n GtkLabel,\n GtkScrolledWindow,\n GtkTextView,\n type Gtk as GtkNs,\n} from \"../gtkx/bridge/index\"\nimport { useLayoutChild, type LayoutEvent } from \"./use-layout-child\"\nimport { View } from \"./view\"\n\nexport type TextInputProps = {\n value?: string\n defaultValue?: string\n onChangeText?: (text: string) => void\n onSubmitEditing?: (event: { nativeEvent: { text: string } }) => void\n onFocus?: () => void\n onBlur?: () => void\n placeholder?: string\n secureTextEntry?: boolean\n editable?: boolean\n keyboardType?: \"default\" | \"numeric\" | \"email-address\" | \"phone-pad\" | \"url\"\n // RN: a multiline input needs a height in the style; Enter inserts a\n // newline and never fires onSubmitEditing.\n multiline?: boolean\n // RN's iOS-only clear affordance, native here: GtkEntry's built-in\n // secondary icon (inside the field, so nothing shifts around it).\n // Single-line only, like RN.\n clearButtonMode?: \"never\" | \"while-editing\" | \"unless-editing\" | \"always\"\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n}\n\nconst INPUT_PURPOSE: Record<\n NonNullable<TextInputProps[\"keyboardType\"]>,\n Gtk.InputPurpose\n> = {\n default: Gtk.InputPurpose.FREE_FORM,\n numeric: Gtk.InputPurpose.NUMBER,\n \"email-address\": Gtk.InputPurpose.EMAIL,\n \"phone-pad\": Gtk.InputPurpose.PHONE,\n url: Gtk.InputPurpose.URL,\n}\n\n// The focus controller is attached imperatively (rc.2 also offers a\n// declarative `controllers` slot): one wiring per widget, handlers read from a\n// ref, so changing onFocus/onBlur never re-creates the controller.\nconst useFocusController = (\n widgetRef: React.RefObject<GtkNs.Widget | null>,\n onFocus?: () => void,\n onBlur?: () => void,\n): void => {\n const handlers = useRef({ onFocus, onBlur })\n handlers.current = { onFocus, onBlur }\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const focus = new Gtk.EventControllerFocus()\n const enter = (): void => handlers.current.onFocus?.()\n const leave = (): void => handlers.current.onBlur?.()\n focus.on(\"enter\", enter)\n focus.on(\"leave\", leave)\n widget.addController(focus)\n return () => {\n widget.removeController(focus)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n\n// Single-line input over GtkEntry. gtkx's controlled-text behavior keeps the\n// widget in sync with the `text` prop (RN controlled semantics); uncontrolled\n// usage passes defaultValue once.\nconst SingleLineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onSubmitEditing,\n onFocus,\n onBlur,\n placeholder,\n secureTextEntry = false,\n editable = true,\n keyboardType = \"default\",\n clearButtonMode = \"never\",\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const widgetRef = useRef<GtkNs.Entry | null>(null)\n const [focused, setFocused] = useState(false)\n\n useLayoutChild(widgetRef, {\n style,\n onLayout,\n // The entry measures itself (theme-accurate height); width is driven by\n // the style (flex/width), with a small floor for usability.\n measureFromWidget: true,\n extraLayout: { minWidth: 60 },\n })\n\n const controlled = value !== undefined\n\n useFocusController(\n widgetRef,\n () => {\n setFocused(true)\n onFocus?.()\n },\n () => {\n setFocused(false)\n onBlur?.()\n },\n )\n\n // RN semantics: the affordance only shows when there is something to\n // clear, and while-editing / unless-editing follow focus.\n const text = controlled ? value : undefined\n const hasText =\n text !== undefined\n ? text.length > 0\n : (widgetRef.current?.getText().length ?? 0) > 0\n const showClear =\n hasText &&\n (clearButtonMode === \"always\" ||\n (clearButtonMode === \"while-editing\" && focused) ||\n (clearButtonMode === \"unless-editing\" && !focused))\n\n return (\n <GtkEntry\n ref={widgetRef}\n name={testID}\n secondaryIconName={showClear ? \"edit-clear-symbolic\" : null}\n secondaryIconActivatable={showClear}\n secondaryIconTooltipText={showClear ? \"Clear\" : null}\n onIconRelease={() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n // Uncontrolled inputs clear themselves; controlled ones report an\n // empty string and let the owner drive the value (RN contract).\n if (!controlled) {\n widget.setText(\"\")\n }\n onChangeText?.(\"\")\n }}\n text={controlled ? value : (defaultValue ?? \"\")}\n placeholderText={placeholder ?? \"\"}\n visibility={!secureTextEntry}\n editable={editable}\n sensitive={editable}\n inputPurpose={INPUT_PURPOSE[keyboardType]}\n onChanged={() => {\n const widget = widgetRef.current\n if (widget) {\n onChangeText?.(widget.getText())\n }\n }}\n onActivate={() => {\n const widget = widgetRef.current\n if (widget) {\n onSubmitEditing?.({ nativeEvent: { text: widget.getText() } })\n }\n }}\n />\n )\n}\n\nconst readBuffer = (buffer: GtkNs.TextBuffer): string =>\n buffer.getText(buffer.getStartIter(), buffer.getEndIter(), true)\n\n// GtkTextView has no native placeholder — a dim, click-transparent label\n// sits over the empty view (RN shows the placeholder while empty, focused\n// or not).\nconst MultilinePlaceholder = ({ text }: { text: string }) => {\n const labelRef = useRef<GtkNs.Label | null>(null)\n useLayoutChild(labelRef, {\n style: { position: \"absolute\", left: 12, top: 8 },\n onLayout: undefined,\n })\n useLayoutEffect(() => {\n labelRef.current?.setCanTarget(false)\n labelRef.current?.addCssClass(\"dim-label\")\n }, [])\n return (\n <GtkLabel\n ref={labelRef}\n label={text}\n />\n )\n}\n\n// Multiline input over GtkTextView in a GtkScrolledWindow: word wrap, the\n// style sets the box (RN requires a height for multiline), overflowing\n// content scrolls inside. The buffer syncs with `value` under RN controlled\n// semantics; Enter inserts a newline (onSubmitEditing never fires — RN\n// multiline behavior).\nconst MultilineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onFocus,\n onBlur,\n placeholder,\n editable = true,\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const scrolledRef = useRef<GtkNs.ScrolledWindow | null>(null)\n const viewRef = useRef<GtkNs.TextView | null>(null)\n const controlled = value !== undefined\n const [empty, setEmpty] = useState(\n (controlled ? (value ?? \"\") : (defaultValue ?? \"\")) === \"\",\n )\n\n const suppressEcho = useRef(false)\n const latest = useRef({ onChangeText })\n latest.current = { onChangeText }\n\n useLayoutEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n // Breathing room akin to GtkEntry's built-in padding.\n view.setLeftMargin(10)\n view.setRightMargin(10)\n view.setTopMargin(8)\n view.setBottomMargin(8)\n const buffer = view.getBuffer()\n const initial = controlled ? (value ?? \"\") : (defaultValue ?? \"\")\n if (initial !== \"\") {\n suppressEcho.current = true\n buffer.setText(initial, -1)\n suppressEcho.current = false\n }\n const changed = (): void => {\n const text = readBuffer(buffer)\n setEmpty(text === \"\")\n if (!suppressEcho.current) {\n latest.current.onChangeText?.(text)\n }\n }\n buffer.on(\"changed\", changed)\n return () => {\n buffer.off(\"changed\", changed)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // RN controlled semantics: the prop wins over whatever was typed.\n useLayoutEffect(() => {\n if (!controlled) {\n return\n }\n const view = viewRef.current\n if (!view) {\n return\n }\n const buffer = view.getBuffer()\n const next = value ?? \"\"\n if (readBuffer(buffer) !== next) {\n suppressEcho.current = true\n buffer.setText(next, -1)\n suppressEcho.current = false\n setEmpty(next === \"\")\n }\n }, [controlled, value])\n\n useFocusController(viewRef, onFocus, onBlur)\n\n return (\n <View\n style={[style, { minHeight: 36, minWidth: 60 }]}\n onLayout={onLayout}\n >\n <ScrolledFill scrolledRef={scrolledRef}>\n <GtkTextView\n ref={viewRef}\n name={testID}\n editable={editable}\n sensitive={editable}\n wrapMode={Gtk.WrapMode.WORD_CHAR}\n />\n </ScrolledFill>\n {empty && placeholder ? (\n <MultilinePlaceholder text={placeholder} />\n ) : null}\n </View>\n )\n}\n\n// The scrolled window fills the styled box exactly (its own layout child).\nconst ScrolledFill = ({\n scrolledRef,\n children,\n}: {\n scrolledRef: React.RefObject<GtkNs.ScrolledWindow | null>\n children: React.ReactNode\n}) => {\n useLayoutChild(scrolledRef, {\n style: { position: \"absolute\", left: 0, right: 0, top: 0, bottom: 0 },\n onLayout: undefined,\n })\n return <GtkScrolledWindow ref={scrolledRef}>{children}</GtkScrolledWindow>\n}\n\nexport const TextInput = (props: TextInputProps) =>\n props.multiline ? (\n <MultilineTextInput {...props} />\n ) : (\n <SingleLineTextInput {...props} />\n )\n"]}
@@ -30,7 +30,7 @@ export type LayoutChild = {
30
30
  };
31
31
  export declare const useLayoutChild: (widgetRef: RefObject<Gtk.Widget | null>, options: LayoutChildOptions) => LayoutChild;
32
32
  export type RnContainerOptions = {
33
- measure?: (orientation: "horizontal" | "vertical") => number;
33
+ measure?: (orientation: "horizontal" | "vertical", forSize: number) => number;
34
34
  beforeAllocate?: (width: number, height: number) => void;
35
35
  };
36
36
  export declare const useRnContainer: (widgetRef: RefObject<Gtk.Widget | null>, node: LayoutNode, options?: RnContainerOptions) => void;
@@ -2,8 +2,14 @@ import { useLayoutEffect, useRef, useState } from "react";
2
2
  import { splitStyle, StyleSheet } from "../style/index";
3
3
  import { defaultCssRegistry } from "../style/registry.gtkx";
4
4
  import { allocateChild, attachRnLayout, detachRnLayout, measureWidget, queueAllocate, queueResize, } from "../gtkx/bridge/index";
5
+ import { perfAddTime, perfBurst, perfCount, perfEnabled, perfNow, } from "../perf";
5
6
  import { useHostNode } from "./host-node";
6
7
  import { deferDuringAllocate, getStoredOffset, getStoredRect, setStoredRect, } from "./rect-store";
8
+ // Perf: sizeAllocate recurses synchronously into child containers, so a
9
+ // naive per-pass timer double-counts nested passes. Track depth and time
10
+ // only the outermost (top-level) allocate — that is the real wall time GTK
11
+ // spends in OUR layout code for the frame.
12
+ let perfAllocDepth = 0;
7
13
  // Shared plumbing for every leaf/container component: owns one LayoutNode,
8
14
  // keeps it in the parent's shadow tree for the component lifetime, applies
9
15
  // the layout half of the style and commits Yoga rects into the rect store,
@@ -147,25 +153,39 @@ export const useRnContainer = (widgetRef, node, options) => {
147
153
  return;
148
154
  }
149
155
  attachRnLayout(widget, {
150
- measure: (orientation) => {
156
+ measure: (orientation, forSize) => {
151
157
  const custom = optionsRef.current?.measure;
152
158
  if (custom) {
153
- return custom(orientation);
159
+ return custom(orientation, forSize);
154
160
  }
155
161
  const rect = node.getRect();
156
162
  return Math.round((orientation === "horizontal" ? rect?.width : rect?.height) ?? 0);
157
163
  },
158
164
  allocate: (width, height) => {
165
+ const start = perfEnabled ? perfNow() : 0;
166
+ perfAllocDepth += 1;
159
167
  optionsRef.current?.beforeAllocate?.(width, height);
160
168
  let child = widget.getFirstChild();
169
+ let children = 0;
161
170
  while (child) {
162
171
  const rect = getStoredRect(child);
163
172
  if (rect) {
164
173
  const offset = getStoredOffset(child);
165
174
  allocateChild(child, rect.x + offset.dx, rect.y + offset.dy, rect.width, rect.height);
175
+ children += 1;
166
176
  }
167
177
  child = child.getNextSibling();
168
178
  }
179
+ perfAllocDepth -= 1;
180
+ if (perfEnabled) {
181
+ perfCount("gtk.allocPass");
182
+ perfCount("gtk.allocChild", children);
183
+ if (perfAllocDepth === 0) {
184
+ const elapsed = perfNow() - start;
185
+ perfAddTime("gtk.allocTop", elapsed);
186
+ perfBurst("gtk.allocMsPerFrame", elapsed);
187
+ }
188
+ }
169
189
  },
170
190
  });
171
191
  return () => {
@@ -1 +1 @@
1
- {"version":3,"file":"use-layout-child.js","sourceRoot":"","sources":["../../src/components/use-layout-child.ts"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\nimport type { LayoutNode } from \"../layout/index\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport { defaultCssRegistry } from \"../style/registry.gtkx\"\nimport type {\n LayoutStyle,\n MeasureFn,\n Rect,\n StyleProp,\n VisualStyle,\n} from \"../contracts\"\nimport {\n allocateChild,\n attachRnLayout,\n detachRnLayout,\n measureWidget,\n queueAllocate,\n queueResize,\n type Gtk,\n} from \"../gtkx/bridge/index\"\nimport { useHostNode, type HostNode } from \"./host-node\"\nimport {\n deferDuringAllocate,\n getStoredOffset,\n getStoredRect,\n setStoredRect,\n} from \"./rect-store\"\n\nexport type LayoutEvent = {\n nativeEvent: {\n layout: { x: number; y: number; width: number; height: number }\n }\n}\n\nexport type LayoutChildOptions = {\n style: StyleProp | undefined\n onLayout: ((event: LayoutEvent) => void) | undefined\n measure?: MeasureFn\n // Leaves with intrinsic GTK sizes (Entry, Switch, Spinner) measure their\n // own widget so Yoga reserves exactly what the theme will draw.\n measureFromWidget?: boolean\n extraLayout?: LayoutStyle\n}\n\nexport type LayoutChild = {\n host: HostNode\n node: LayoutNode\n flat: ReturnType<typeof StyleSheet.flatten>\n visual: VisualStyle\n cssClass: string | null\n}\n\n// Shared plumbing for every leaf/container component: owns one LayoutNode,\n// keeps it in the parent's shadow tree for the component lifetime, applies\n// the layout half of the style and commits Yoga rects into the rect store,\n// where the parent container's RnGtkxLayout allocate() picks them up.\nexport const useLayoutChild = (\n widgetRef: RefObject<Gtk.Widget | null>,\n options: LayoutChildOptions,\n): LayoutChild => {\n const host = useHostNode()\n\n // useState's lazy initializer is guaranteed once-per-instance even under\n // the React Compiler — a lazy ref here got its creation memoized ACROSS\n // component instances, sharing one Yoga node and double-freeing it.\n const [node] = useState<LayoutNode>(() => host.engine.createNode())\n\n const flat = StyleSheet.flatten(options.style)\n const { layout, visual } = splitStyle(flat)\n const effectiveLayout = options.extraLayout\n ? { ...layout, ...options.extraLayout }\n : layout\n\n // Re-apply layout style only when it actually changed (keyed effect) —\n // setStyle dirties the whole tree.\n const layoutKey = JSON.stringify(effectiveLayout)\n useLayoutEffect(() => {\n node.setStyle(JSON.parse(layoutKey) as LayoutStyle)\n }, [node, layoutKey])\n\n const cssClass = defaultCssRegistry.getClassName(visual)\n\n useLayoutEffect(() => {\n const parent = host.node\n // The reconciler has already attached our widget in JSX order, so its\n // sibling position is the correct Yoga index — this keeps the shadow tree\n // ordered even for mid-list mounts (conditional children, list inserts).\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n let index = parent.children.length\n if (widget && parentWidget) {\n let position = 0\n let sibling = parentWidget.getFirstChild()\n while (sibling !== null && sibling !== widget) {\n position += 1\n sibling = sibling.getNextSibling()\n }\n if (sibling === widget) {\n index = Math.min(position, parent.children.length)\n }\n }\n parent.insertChild(node, index)\n node.setCommit((rect: Rect) => {\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n if (!widget || !parentWidget) {\n return\n }\n const previous = getStoredRect(widget)\n setStoredRect(widget, rect)\n const sizeChanged =\n !previous ||\n previous.width !== rect.width ||\n previous.height !== rect.height\n const queue = (): void => {\n if (sizeChanged) {\n // A size change invalidates this widget's cached measure (nested\n // managers, ScrolledWindow ranges) and re-allocates the ancestors.\n queueResize(widget)\n } else {\n // Pure move: the parent just needs another allocation pass. GTK\n // dedupes queued allocates, so per-child calls batch into one.\n queueAllocate(parentWidget)\n }\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n node.setCommit(null)\n parent.removeChild(node)\n node.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const onLayout = options.onLayout\n useLayoutEffect(() => {\n node.setOnLayout(\n onLayout\n ? (rect: Rect) => {\n onLayout({ nativeEvent: { layout: rect } })\n }\n : null,\n )\n }, [node, onLayout])\n\n // The explicit return type keeps the inner params contextually typed: with a\n // bare lazy initializer TS may match the outer arrow against MeasureFn\n // itself (useState accepts S | () => S) and drop the context.\n const [widgetMeasure] = useState<MeasureFn>(\n (): MeasureFn => (width, widthMode) => {\n const widget = widgetRef.current\n if (!widget) {\n return { width: 0, height: 0 }\n }\n const natural = measureWidget(widget, \"horizontal\").natural\n const used =\n widthMode === \"undefined\"\n ? natural\n : Math.min(natural, Math.max(1, Math.floor(width)))\n return {\n width: used,\n height: measureWidget(widget, \"vertical\", used).natural,\n }\n },\n )\n const measure =\n options.measure ?? (options.measureFromWidget ? widgetMeasure : undefined)\n useLayoutEffect(() => {\n if (!measure) {\n return\n }\n node.setMeasureFn(measure)\n // Widgets measured before their window is mapped report zero (no realized\n // theme context yet, unlike offscreen probes) and Yoga caches it —\n // invalidate once the widget actually maps.\n const widget = widgetRef.current\n const remeasure = (): void => {\n node.markDirty()\n }\n if (options.measureFromWidget && widget) {\n widget.on(\"map\", remeasure)\n }\n return () => {\n if (options.measureFromWidget && widget) {\n widget.off(\"map\", remeasure)\n }\n // Cleared by free() on unmount; explicit unset only when measure is\n // removed while mounted.\n node.setMeasureFn(null)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [node, measure])\n\n return { host, node, flat, visual, cssClass }\n}\n\nexport type RnContainerOptions = {\n // Overrides the default engine-rect measure (the window root reports 0 so\n // the window can shrink freely below the current content size).\n measure?: (orientation: \"horizontal\" | \"vertical\") => number\n // Runs before children are placed — the window root syncs the engine\n // viewport to the actual allocation here.\n beforeAllocate?: (width: number, height: number) => void\n}\n\n// Containers (Root, View, Animated.View, ScrollView content) drive their GTK\n// side with an RnGtkxLayout: measure() reports the engine rect of `node`\n// (minimum == natural — GTK minimums of children never leak upward), and\n// allocate() places every child widget at exactly its stored engine rect\n// plus the Animated offset.\nexport const useRnContainer = (\n widgetRef: RefObject<Gtk.Widget | null>,\n node: LayoutNode,\n options?: RnContainerOptions,\n): void => {\n const optionsRef = useRef<RnContainerOptions | undefined>(options)\n optionsRef.current = options\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n attachRnLayout(widget, {\n measure: (orientation) => {\n const custom = optionsRef.current?.measure\n if (custom) {\n return custom(orientation)\n }\n const rect = node.getRect()\n return Math.round(\n (orientation === \"horizontal\" ? rect?.width : rect?.height) ?? 0,\n )\n },\n allocate: (width, height) => {\n optionsRef.current?.beforeAllocate?.(width, height)\n let child = widget.getFirstChild()\n while (child) {\n const rect = getStoredRect(child)\n if (rect) {\n const offset = getStoredOffset(child)\n allocateChild(\n child,\n rect.x + offset.dx,\n rect.y + offset.dy,\n rect.width,\n rect.height,\n )\n }\n child = child.getNextSibling()\n }\n },\n })\n return () => {\n detachRnLayout(widget)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n"]}
1
+ {"version":3,"file":"use-layout-child.js","sourceRoot":"","sources":["../../src/components/use-layout-child.ts"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\nimport type { LayoutNode } from \"../layout/index\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport { defaultCssRegistry } from \"../style/registry.gtkx\"\nimport type {\n LayoutStyle,\n MeasureFn,\n Rect,\n StyleProp,\n VisualStyle,\n} from \"../contracts\"\nimport {\n allocateChild,\n attachRnLayout,\n detachRnLayout,\n measureWidget,\n queueAllocate,\n queueResize,\n type Gtk,\n} from \"../gtkx/bridge/index\"\nimport {\n perfAddTime,\n perfBurst,\n perfCount,\n perfEnabled,\n perfNow,\n} from \"../perf\"\nimport { useHostNode, type HostNode } from \"./host-node\"\nimport {\n deferDuringAllocate,\n getStoredOffset,\n getStoredRect,\n setStoredRect,\n} from \"./rect-store\"\n\nexport type LayoutEvent = {\n nativeEvent: {\n layout: { x: number; y: number; width: number; height: number }\n }\n}\n\n// Perf: sizeAllocate recurses synchronously into child containers, so a\n// naive per-pass timer double-counts nested passes. Track depth and time\n// only the outermost (top-level) allocate — that is the real wall time GTK\n// spends in OUR layout code for the frame.\nlet perfAllocDepth = 0\n\nexport type LayoutChildOptions = {\n style: StyleProp | undefined\n onLayout: ((event: LayoutEvent) => void) | undefined\n measure?: MeasureFn\n // Leaves with intrinsic GTK sizes (Entry, Switch, Spinner) measure their\n // own widget so Yoga reserves exactly what the theme will draw.\n measureFromWidget?: boolean\n extraLayout?: LayoutStyle\n}\n\nexport type LayoutChild = {\n host: HostNode\n node: LayoutNode\n flat: ReturnType<typeof StyleSheet.flatten>\n visual: VisualStyle\n cssClass: string | null\n}\n\n// Shared plumbing for every leaf/container component: owns one LayoutNode,\n// keeps it in the parent's shadow tree for the component lifetime, applies\n// the layout half of the style and commits Yoga rects into the rect store,\n// where the parent container's RnGtkxLayout allocate() picks them up.\nexport const useLayoutChild = (\n widgetRef: RefObject<Gtk.Widget | null>,\n options: LayoutChildOptions,\n): LayoutChild => {\n const host = useHostNode()\n\n // useState's lazy initializer is guaranteed once-per-instance even under\n // the React Compiler — a lazy ref here got its creation memoized ACROSS\n // component instances, sharing one Yoga node and double-freeing it.\n const [node] = useState<LayoutNode>(() => host.engine.createNode())\n\n const flat = StyleSheet.flatten(options.style)\n const { layout, visual } = splitStyle(flat)\n const effectiveLayout = options.extraLayout\n ? { ...layout, ...options.extraLayout }\n : layout\n\n // Re-apply layout style only when it actually changed (keyed effect) —\n // setStyle dirties the whole tree.\n const layoutKey = JSON.stringify(effectiveLayout)\n useLayoutEffect(() => {\n node.setStyle(JSON.parse(layoutKey) as LayoutStyle)\n }, [node, layoutKey])\n\n const cssClass = defaultCssRegistry.getClassName(visual)\n\n useLayoutEffect(() => {\n const parent = host.node\n // The reconciler has already attached our widget in JSX order, so its\n // sibling position is the correct Yoga index — this keeps the shadow tree\n // ordered even for mid-list mounts (conditional children, list inserts).\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n let index = parent.children.length\n if (widget && parentWidget) {\n let position = 0\n let sibling = parentWidget.getFirstChild()\n while (sibling !== null && sibling !== widget) {\n position += 1\n sibling = sibling.getNextSibling()\n }\n if (sibling === widget) {\n index = Math.min(position, parent.children.length)\n }\n }\n parent.insertChild(node, index)\n node.setCommit((rect: Rect) => {\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n if (!widget || !parentWidget) {\n return\n }\n const previous = getStoredRect(widget)\n setStoredRect(widget, rect)\n const sizeChanged =\n !previous ||\n previous.width !== rect.width ||\n previous.height !== rect.height\n const queue = (): void => {\n if (sizeChanged) {\n // A size change invalidates this widget's cached measure (nested\n // managers, ScrolledWindow ranges) and re-allocates the ancestors.\n queueResize(widget)\n } else {\n // Pure move: the parent just needs another allocation pass. GTK\n // dedupes queued allocates, so per-child calls batch into one.\n queueAllocate(parentWidget)\n }\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n node.setCommit(null)\n parent.removeChild(node)\n node.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const onLayout = options.onLayout\n useLayoutEffect(() => {\n node.setOnLayout(\n onLayout\n ? (rect: Rect) => {\n onLayout({ nativeEvent: { layout: rect } })\n }\n : null,\n )\n }, [node, onLayout])\n\n // The explicit return type keeps the inner params contextually typed: with a\n // bare lazy initializer TS may match the outer arrow against MeasureFn\n // itself (useState accepts S | () => S) and drop the context.\n const [widgetMeasure] = useState<MeasureFn>(\n (): MeasureFn => (width, widthMode) => {\n const widget = widgetRef.current\n if (!widget) {\n return { width: 0, height: 0 }\n }\n const natural = measureWidget(widget, \"horizontal\").natural\n const used =\n widthMode === \"undefined\"\n ? natural\n : Math.min(natural, Math.max(1, Math.floor(width)))\n return {\n width: used,\n height: measureWidget(widget, \"vertical\", used).natural,\n }\n },\n )\n const measure =\n options.measure ?? (options.measureFromWidget ? widgetMeasure : undefined)\n useLayoutEffect(() => {\n if (!measure) {\n return\n }\n node.setMeasureFn(measure)\n // Widgets measured before their window is mapped report zero (no realized\n // theme context yet, unlike offscreen probes) and Yoga caches it —\n // invalidate once the widget actually maps.\n const widget = widgetRef.current\n const remeasure = (): void => {\n node.markDirty()\n }\n if (options.measureFromWidget && widget) {\n widget.on(\"map\", remeasure)\n }\n return () => {\n if (options.measureFromWidget && widget) {\n widget.off(\"map\", remeasure)\n }\n // Cleared by free() on unmount; explicit unset only when measure is\n // removed while mounted.\n node.setMeasureFn(null)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [node, measure])\n\n return { host, node, flat, visual, cssClass }\n}\n\nexport type RnContainerOptions = {\n // Overrides the default engine-rect measure (the window root reports 0 so\n // the window can shrink freely below the current content size; the\n // intrinsic root measures its content through Yoga, honoring forSize for\n // height-for-width).\n measure?: (orientation: \"horizontal\" | \"vertical\", forSize: number) => number\n // Runs before children are placed — the window root syncs the engine\n // viewport to the actual allocation here.\n beforeAllocate?: (width: number, height: number) => void\n}\n\n// Containers (Root, View, Animated.View, ScrollView content) drive their GTK\n// side with an RnGtkxLayout: measure() reports the engine rect of `node`\n// (minimum == natural — GTK minimums of children never leak upward), and\n// allocate() places every child widget at exactly its stored engine rect\n// plus the Animated offset.\nexport const useRnContainer = (\n widgetRef: RefObject<Gtk.Widget | null>,\n node: LayoutNode,\n options?: RnContainerOptions,\n): void => {\n const optionsRef = useRef<RnContainerOptions | undefined>(options)\n optionsRef.current = options\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n attachRnLayout(widget, {\n measure: (orientation, forSize) => {\n const custom = optionsRef.current?.measure\n if (custom) {\n return custom(orientation, forSize)\n }\n const rect = node.getRect()\n return Math.round(\n (orientation === \"horizontal\" ? rect?.width : rect?.height) ?? 0,\n )\n },\n allocate: (width, height) => {\n const start = perfEnabled ? perfNow() : 0\n perfAllocDepth += 1\n optionsRef.current?.beforeAllocate?.(width, height)\n let child = widget.getFirstChild()\n let children = 0\n while (child) {\n const rect = getStoredRect(child)\n if (rect) {\n const offset = getStoredOffset(child)\n allocateChild(\n child,\n rect.x + offset.dx,\n rect.y + offset.dy,\n rect.width,\n rect.height,\n )\n children += 1\n }\n child = child.getNextSibling()\n }\n perfAllocDepth -= 1\n if (perfEnabled) {\n perfCount(\"gtk.allocPass\")\n perfCount(\"gtk.allocChild\", children)\n if (perfAllocDepth === 0) {\n const elapsed = perfNow() - start\n perfAddTime(\"gtk.allocTop\", elapsed)\n perfBurst(\"gtk.allocMsPerFrame\", elapsed)\n }\n }\n },\n })\n return () => {\n detachRnLayout(widget)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n"]}
@@ -45,6 +45,8 @@ export type VirtualizedListProps<T> = Omit<ScrollViewProps, "children"> & {
45
45
  getItemLayout?: (data: readonly T[], index: number) => ItemLayout;
46
46
  windowSize?: number;
47
47
  initialNumToRender?: number;
48
+ maxToRenderPerBatch?: number;
49
+ updateCellsBatchingPeriod?: number;
48
50
  extraData?: unknown;
49
51
  inverted?: boolean;
50
52
  refreshing?: boolean;