react-native-gtkx 0.2.0-alpha.2 → 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 +5 -2
- 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/index.d.ts +2 -0
- package/dist/animated/index.js +5 -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/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/index.d.ts +0 -1
- package/dist/common/index.js +24 -1
- package/dist/common/index.js.map +1 -1
- package/dist/components/animated.d.ts +70 -6
- package/dist/components/animated.js +559 -46
- package/dist/components/animated.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/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 +7 -5
- package/dist/components/index.js +5 -3
- package/dist/components/index.js.map +1 -1
- package/dist/components/measure.d.ts +51 -1
- package/dist/components/measure.js +101 -2
- package/dist/components/measure.js.map +1 -1
- package/dist/components/pressable.d.ts +61 -1
- package/dist/components/pressable.js +151 -4
- 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 +39 -3
- package/dist/components/scroll-view.js +378 -43
- 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 +43 -8
- 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 +188 -5
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/view.d.ts +5 -2
- package/dist/components/view.js +18 -13
- 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 +4 -0
- 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 +2 -1
- package/dist/gtk/index.js +7 -1
- package/dist/gtk/index.js.map +1 -1
- package/dist/gtkx/bridge/geometry.js +6 -4
- package/dist/gtkx/bridge/geometry.js.map +1 -1
- package/dist/gtkx/bridge/index.d.ts +5 -3
- package/dist/gtkx/bridge/index.js +6 -3
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/slot-portal.js.map +1 -1
- package/dist/gtkx/bridge/use-signal.js +1 -1
- 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 +257 -60
- package/dist/mcp/data/generated.js +306 -62
- package/dist/mcp/data/generated.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 +16 -0
- package/dist/navigation/sidebar.js +65 -1
- 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 +80 -7
- package/dist/responder/system.js +143 -23
- package/dist/responder/system.js.map +1 -1
- package/dist/responder/use-responder.d.ts +11 -0
- package/dist/responder/use-responder.js +225 -6
- package/dist/responder/use-responder.js.map +1 -1
- package/dist/runner/host-dev.js +1 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +1 -1
- 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 +1 -1
- 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/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 +2 -1
- package/dist/style/index.js +2 -1
- package/dist/style/index.js.map +1 -1
- package/dist/style/split-style.js +5 -0
- package/dist/style/split-style.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/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
- package/dist/common/list.d.ts +0 -82
- package/dist/common/list.js +0 -166
- package/dist/common/list.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtualized-list.js","sourceRoot":"","sources":["../../src/components/virtualized-list.tsx"],"names":[],"mappings":"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","sourcesContent":["// The windowed list core (RN VirtualizedList model, leaner): only the rows\n// around the viewport are mounted; the content View carries the prefix-sum\n// height so the ScrollView gets the full range; every mounted cell is\n// absolutely positioned at its offset. Heights come from getItemLayout (exact)\n// or estimatedItemSize refined by per-cell onLayout; corrections above the\n// first visible row are anchored by compensating the scroll offset in the\n// same commit (docs/research/list-window.md).\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type ReactElement,\n type ReactNode,\n} from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n perfAddTime,\n perfBurst,\n perfCount,\n perfEnabled,\n perfNow,\n} from \"../perf\"\nimport { ActivityIndicator } from \"./activity-indicator\"\nimport {\n ScrollView,\n StickySlot,\n type ScrollEvent,\n type ScrollViewHandle,\n type ScrollViewProps,\n} from \"./scroll-view\"\nimport type { LayoutEvent } from \"./use-layout-child\"\nimport { View } from \"./view\"\n\nexport type ListRenderItemInfo<T> = { item: T; index: number }\n\nexport type ItemLayout = { length: number; offset: number; index: number }\n\n// RN ViewToken: one entry per item in the viewability report.\nexport type ViewToken<T = unknown> = {\n item: T\n key: string\n index: number\n isViewable: boolean\n}\n\nexport type ViewabilityConfig = {\n // Percent (0..100) of the ITEM that must be visible. A fully visible item\n // always counts, even when it covers less than the threshold.\n itemVisiblePercentThreshold?: number\n // Percent (0..100) of the VIEWPORT the item must cover. Takes precedence\n // over itemVisiblePercentThreshold when both are set (RN ViewabilityHelper).\n viewAreaCoveragePercentThreshold?: number\n // The item must stay continuously visible this many ms before it is\n // reported viewable; scrolling out before that cancels the report.\n minimumViewTime?: number\n}\n\n// RN FlatList scroll surface on top of ScrollViewHandle. The handle is not\n// generic: scrollToItem takes the item as unknown and resolves the index with\n// indexOf on the latest data.\nexport type VirtualizedListHandle = ScrollViewHandle & {\n scrollToIndex(params: {\n index: number\n viewPosition?: number\n animated?: boolean\n }): void\n scrollToItem(params: {\n item: unknown\n viewPosition?: number\n animated?: boolean\n }): void\n scrollToOffset(params: { offset: number; animated?: boolean }): void\n}\n\nexport type VirtualizedListProps<T> = Omit<ScrollViewProps, \"children\"> & {\n data: readonly T[]\n renderItem: (info: ListRenderItemInfo<T>) => ReactElement | null\n keyExtractor?: (item: T, index: number) => string\n estimatedItemSize?: number\n getItemLayout?: (data: readonly T[], index: number) => ItemLayout\n // Overscan in viewport multiples (RN semantics: `windowSize` viewports are\n // mounted, one of them visible). RN's mobile default is 5; the desktop\n // default is 11 — see the note on DEFAULT_WINDOW_SIZE.\n windowSize?: number\n initialNumToRender?: number\n // RN batching pair. Rows OUTSIDE the visible area are mounted at most\n // `maxToRenderPerBatch` per pass, one pass every `updateCellsBatchingPeriod`\n // ms, so a flick or a long jump spreads its mounts over frames instead of\n // stalling one. The visible rows never wait for a batch.\n maxToRenderPerBatch?: number\n updateCellsBatchingPeriod?: number\n extraData?: unknown\n // RN inverted semantics: the list opens at the START of the data (visually\n // at the far end — a chat's latest message sits at the bottom), and\n // contentOffset counts from that end. See the projection math below.\n inverted?: boolean\n // RefreshControl parity. Desktop has no pull gesture: `refreshing` renders\n // a spinner row above the content; `onRefresh` is accepted for RN API\n // compatibility but is never triggered by a gesture — app code must call\n // it itself (e.g. from a toolbar button or a keyboard shortcut).\n refreshing?: boolean\n onRefresh?: () => void\n ItemSeparatorComponent?: ComponentType | null\n ListHeaderComponent?: ComponentType | ReactElement | null\n ListFooterComponent?: ComponentType | ReactElement | null\n ListEmptyComponent?: ComponentType | ReactElement | null\n onEndReached?: () => void\n onEndReachedThreshold?: number\n onViewableItemsChanged?: (info: {\n viewableItems: ViewToken<T>[]\n changed: ViewToken<T>[]\n }) => void\n viewabilityConfig?: ViewabilityConfig\n style?: StyleProp\n}\n\nconst renderAux = (\n component: ComponentType | ReactElement | null | undefined,\n): ReactNode => {\n if (component === null || component === undefined) {\n return null\n }\n if (typeof component === \"function\") {\n const Aux = component\n return <Aux />\n }\n return component\n}\n\n// First index whose offset-end is past `target` (binary search over prefix\n// sums; offsets has count+1 entries).\nconst indexAt = (offsets: number[], target: number): number => {\n let low = 0\n let high = offsets.length - 2\n while (low < high) {\n const mid = (low + high) >> 1\n if (offsets[mid + 1]! <= target) {\n low = mid + 1\n } else {\n high = mid\n }\n }\n return low\n}\n\n// Overscan default. RN ships 5 because a phone pays for mounted rows in\n// memory; a desktop app does not, and here the mounted set is what costs\n// frames: every window boundary crossing is a mount + Yoga reflow + GTK\n// allocate burst, so a WIDER window means fewer crossings per scrolled pixel.\n// Measured (docs/research/scroll-performance.md): 11 instead of 5 cuts\n// mount/unmount churn by ~21% and late frames from ~10/s to ~7.7/s.\nconst DEFAULT_WINDOW_SIZE = 11\n\n// Perf: counts real React mounts/unmounts of windowed cells (rendered as a\n// null child inside each cell only when GTKX_PERF=1).\nconst CellMountProbe = (): null => {\n useLayoutEffect(() => {\n perfCount(\"vl.cellMount\")\n perfBurst(\"vl.mountsPerFrame\")\n return () => {\n perfCount(\"vl.cellUnmount\")\n }\n }, [])\n return null\n}\n\nconst VirtualizedListInner = forwardRef(\n <T,>(\n {\n data,\n renderItem,\n keyExtractor,\n estimatedItemSize = 44,\n getItemLayout,\n windowSize = DEFAULT_WINDOW_SIZE,\n initialNumToRender = 10,\n maxToRenderPerBatch = 10,\n updateCellsBatchingPeriod = 50,\n extraData,\n inverted = false,\n refreshing = false,\n onRefresh,\n ItemSeparatorComponent,\n ListHeaderComponent,\n ListFooterComponent,\n ListEmptyComponent,\n onEndReached,\n onEndReachedThreshold = 0.1,\n onViewableItemsChanged,\n viewabilityConfig,\n onScroll,\n onContentSizeChange,\n onLayout,\n horizontal = false,\n stickyHeaderIndices,\n ...scrollProps\n }: VirtualizedListProps<T>,\n ref: React.Ref<VirtualizedListHandle>,\n ) => {\n const count = data.length\n const scrollRef = useRef<ScrollViewHandle>(null)\n\n const measured = useRef<(number | undefined)[]>([])\n const [version, setVersion] = useState(0)\n // Scroll position along the main axis (contentOffset.x when horizontal).\n // Always in RAW adjustment space — all windowing math below is raw.\n const scrollY = useRef(0)\n // Viewport extent along the main axis (width when horizontal).\n const viewportH = useRef(0)\n // RN-space offset for inverted lists. RN's scaleY(-1) flip puts\n // contentOffset 0 at the far (raw) end of the content, so the exposed\n // offset counts from there: exposed = maxRaw - raw. It is the pinned\n // source of truth across content growth — restoring raw from it is what\n // keeps an inverted chat glued to its latest message on prepend.\n const exposedOffset = useRef(0)\n // Main-axis content size as GTK last reported it (the adjustment range).\n // The raw scroll maximum is contentMain - viewport; before the first\n // report it falls back to the list extent (header/footer not yet known).\n const contentMain = useRef(0)\n const pendingAnchor = useRef(0)\n // scrollToIndex issued while sizes were still estimates: re-run the\n // positioning once after the remount measures real sizes (≤2 scrollTo\n // corrections in total).\n const pendingScrollIndex = useRef<{\n index: number\n viewPosition: number\n animated?: boolean\n } | null>(null)\n const endReachedForSize = useRef(-1)\n // Currently reported viewable tokens keyed by item key (isViewable true).\n const viewableTokens = useRef(new Map<string, ViewToken<T>>())\n // Items meeting the viewability criteria but still waiting out\n // minimumViewTime; cancelled if they leave the viewport first.\n const viewabilityTimers = useRef(\n new Map<string, ReturnType<typeof setTimeout>>(),\n )\n // Keys whose minimumViewTime elapsed while continuously visible.\n const maturedKeys = useRef(new Set<string>())\n // Timers must call the LATEST closure (data may change while pending).\n const recomputeViewabilityRef = useRef<() => void>(() => {})\n\n // Prefix sums; rebuilt on any size correction (O(N) — cheap even at\n // 10k, see the spike). getItemLayout skips measuring entirely.\n const offsets = useMemo(() => {\n const out = new Array<number>(count + 1)\n out[0] = 0\n for (let index = 0; index < count; index += 1) {\n const size = getItemLayout\n ? getItemLayout(data, index).length\n : (measured.current[index] ?? estimatedItemSize)\n out[index + 1] = out[index]! + size\n }\n return out\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [count, version, estimatedItemSize, getItemLayout, data])\n\n // INVERTED PROJECTION. RN implements inverted as a scaleY(-1) flip of\n // the scroller and every cell; the net layout is the data mirrored\n // around the content extent C = offsets[count]: data index i occupies\n // [C - offsets[i+1], C - offsets[i]) in raw scroll space, so data index\n // 0 sits at the far end. The flip also reverses the scroll axis: RN's\n // contentOffset counts from that far end, so the raw GTK offset and the\n // exposed RN offset are complements (exposed = maxRaw - raw).\n const cellStart = (index: number): number =>\n inverted ? offsets[count]! - offsets[index + 1]! : offsets[index]!\n\n const keyOf = (item: T, index: number): string =>\n keyExtractor ? keyExtractor(item, index) : String(index)\n\n const [range, setRange] = useState(() => ({\n first: 0,\n last: Math.min(count, initialNumToRender) - 1,\n }))\n // Mirror of `range` for event-time math: several scroll events (and a\n // batch timer) can run before React re-renders, and each needs the range\n // the previous one asked for, not the one currently rendered.\n const rangeRef = useRef(range)\n const batchTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n // Mount allowance as a token bucket: maxToRenderPerBatch rows per\n // updateCellsBatchingPeriod, NOT per pass. One frame can run several passes\n // (scroll event, content-size report, measurement version bump) and a\n // per-pass cap would let them stack back into the burst we are avoiding.\n // A steady scroll needs about one row per frame, far under the refill, so\n // its window still follows the offset exactly.\n const batchTokens = useRef(0)\n const batchFilledAt = useRef(0)\n // The batch timer must call the LATEST closure (offsets/data may change).\n const updateRangeRef = useRef<() => void>(() => {})\n\n // Index range covering the visual window grown by `overscan` px on both\n // sides (0 → exactly the visible rows).\n const rangeFor = (overscan: number): { first: number; last: number } => {\n let start = scrollY.current - overscan\n let end = scrollY.current + viewportH.current + overscan\n if (inverted) {\n // Map the visual window back to data-offset space: visual position v\n // covers data offsets C - v (mirror around the extent), so the\n // visual window [start, end] covers data offsets [C - end, C - start].\n const extent = offsets[count]!\n ;[start, end] = [extent - end, extent - start]\n }\n return {\n first: indexAt(offsets, Math.max(0, start)),\n last: Math.min(count - 1, indexAt(offsets, end)),\n }\n }\n\n const updateRange = (): void => {\n perfCount(\"vl.updateRange\")\n const target = rangeFor(\n Math.max(1, (windowSize - 1) / 2) * viewportH.current,\n )\n const current = rangeRef.current\n // MOUNT BUDGET (RN maxToRenderPerBatch). A flick or a scrollToOffset\n // moves the offset by whole viewports in a single frame, so the target\n // window can be an almost entirely new set of rows — mounting it in one\n // go is a burst of cell mounts + Yoga reflow + GTK allocate that shows\n // up as a visible mid-flick stall (docs/research/scroll-performance.md).\n // The VISIBLE rows are always mounted at once (a blank row is worse than\n // a late one); the overscan beyond them fills in over the following\n // batches.\n const visible = rangeFor(0)\n // Reuse the mounted set only when it still covers what is on screen.\n // The mounted set is ONE contiguous range, so keeping a window that no\n // longer reaches the visible rows would mean mounting the whole gap\n // between them in this pass — the burst, by another route. Overlapping\n // the target window is not enough: with a wide windowSize a jump of\n // several viewports still overlaps it.\n const reusable =\n current.last >= visible.first && current.first <= visible.last\n // Keep what is both mounted and still wanted, always covering the\n // visible rows; after a teleport nothing is reusable and the visible\n // rows are the whole starting window.\n let first = reusable\n ? Math.min(Math.max(current.first, target.first), visible.first)\n : visible.first\n let last = reusable\n ? Math.max(Math.min(current.last, target.last), visible.last)\n : visible.last\n // Rows the visible set already costs this pass count against the batch:\n // after a teleport they ARE the batch.\n const kept = reusable\n ? Math.max(\n 0,\n Math.min(last, current.last) - Math.max(first, current.first) + 1,\n )\n : 0\n const now = Date.now()\n if (now - batchFilledAt.current >= updateCellsBatchingPeriod) {\n batchTokens.current = maxToRenderPerBatch\n batchFilledAt.current = now\n }\n let budget = Math.max(0, batchTokens.current - (last - first + 1 - kept))\n while (budget > 0 && (first > target.first || last < target.last)) {\n if (last < target.last) {\n last += 1\n budget -= 1\n }\n if (budget > 0 && first > target.first) {\n first -= 1\n budget -= 1\n }\n }\n batchTokens.current = budget\n if (first !== current.first || last !== current.last) {\n perfCount(\"vl.rangeChange\")\n rangeRef.current = { first, last }\n setRange({ first, last })\n }\n // Still short of the full window: continue on the next batch tick.\n if (first > target.first || last < target.last) {\n perfCount(\"vl.rangePending\")\n if (batchTimer.current === null) {\n batchTimer.current = setTimeout(() => {\n batchTimer.current = null\n updateRangeRef.current()\n }, updateCellsBatchingPeriod)\n }\n }\n }\n useLayoutEffect(() => {\n updateRangeRef.current = updateRange\n })\n\n useEffect(() => {\n return () => {\n if (batchTimer.current !== null) {\n clearTimeout(batchTimer.current)\n batchTimer.current = null\n }\n }\n }, [])\n\n // Clamp a scroll target to the valid range of the axis.\n const clampOffset = (target: number): number => {\n const max = Math.max(0, offsets[count]! - viewportH.current)\n return Math.min(max, Math.max(0, target))\n }\n\n // Raw scroll maximum along the main axis (adjustment upper - page).\n const maxRawScroll = (): number =>\n Math.max(0, (contentMain.current || offsets[count]!) - viewportH.current)\n\n // Translate an RN-space main-axis offset into raw adjustment space (and\n // back — the mapping is its own inverse).\n const toRaw = (offset: number): number =>\n Math.max(0, maxRawScroll() - offset)\n\n // Raw scroll offset that places `index` in the viewport: viewPosition 0\n // aligns the cell start with the viewport start, 0.5 centers it, 1\n // aligns the cell end with the viewport end. Inverted flips which edge\n // viewPosition 0 means: RN computes the target in data space and the\n // scaleY(-1) flip shows it from the other end, so 0 aligns the cell\n // with the visual BOTTOM — in mirrored raw coordinates that is the\n // complementary alignment.\n const offsetForIndex = (index: number, viewPosition: number): number => {\n const size = offsets[index + 1]! - offsets[index]!\n const align = inverted ? 1 - viewPosition : viewPosition\n return clampOffset(cellStart(index) - align * (viewportH.current - size))\n }\n\n const scrollToAxis = (offset: number, animated?: boolean): void => {\n scrollRef.current?.scrollTo(\n horizontal ? { x: offset, animated } : { y: offset, animated },\n )\n }\n\n const scrollToIndex = (params: {\n index: number\n viewPosition?: number\n animated?: boolean\n }): void => {\n if (count === 0) {\n return\n }\n const index = Math.min(count - 1, Math.max(0, Math.trunc(params.index)))\n const viewPosition = params.viewPosition ?? 0\n // Without getItemLayout the target may rest on estimates: remember the\n // request so the version effect can re-run the positioning once the\n // remounted cells have measured (the ≤2-corrections convergence).\n pendingScrollIndex.current = getItemLayout\n ? null\n : { index, viewPosition, animated: params.animated }\n scrollToAxis(offsetForIndex(index, viewPosition), params.animated)\n }\n\n useImperativeHandle(ref, () => ({\n // Any direct scroll cancels a pending scrollToIndex correction. The\n // caller always speaks RN-space offsets; inverted translates the main\n // axis into raw adjustment space.\n scrollTo: (options) => {\n pendingScrollIndex.current = null\n const main = horizontal ? options.x : options.y\n if (!inverted || main === undefined) {\n scrollRef.current?.scrollTo(options)\n return\n }\n scrollRef.current?.scrollTo({\n ...options,\n ...(horizontal ? { x: toRaw(main) } : { y: toRaw(main) }),\n })\n },\n scrollToEnd: (options) => {\n pendingScrollIndex.current = null\n // Inverted: the END of the data sits at raw offset 0 (visual top).\n if (inverted) {\n scrollToAxis(0, options?.animated)\n return\n }\n scrollRef.current?.scrollToEnd(options)\n },\n scrollToOffset: ({ offset, animated }) => {\n pendingScrollIndex.current = null\n scrollToAxis(inverted ? toRaw(offset) : offset, animated)\n },\n scrollToIndex,\n scrollToItem: ({ item, viewPosition, animated }) => {\n const index = data.indexOf(item as T)\n if (index >= 0) {\n scrollToIndex({ index, viewPosition, animated })\n }\n },\n }))\n\n // Data changes move the window in BOTH directions: growth from an empty\n // list must extend the initial range, shrinking must clamp it.\n useLayoutEffect(() => {\n updateRange()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [count])\n\n // Runs right after offsets rebuilt from new measurements. A pending\n // scrollToIndex supersedes anchoring: re-issue the (now refined) target\n // once and stop — this is the second and final correction.\n useLayoutEffect(() => {\n const pending = pendingScrollIndex.current\n if (pending) {\n pendingScrollIndex.current = null\n pendingAnchor.current = 0\n scrollToAxis(\n offsetForIndex(pending.index, pending.viewPosition),\n pending.animated,\n )\n return\n }\n // Anchor: apply the accumulated correction delta right after offsets\n // rebuilt, in the same frame — the viewport does not visually move.\n if (pendingAnchor.current !== 0) {\n const delta = pendingAnchor.current\n pendingAnchor.current = 0\n scrollToAxis(scrollY.current + delta)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [version])\n\n const onItemLayout = (index: number, size: number): void => {\n if (getItemLayout) {\n return\n }\n const known = measured.current[index] ?? estimatedItemSize\n if (Math.abs(known - size) < 0.5) {\n return\n }\n measured.current[index] = size\n perfCount(\"vl.versionBump\")\n perfBurst(\"vl.bumpsPerFrame\")\n // A size change shifts every cell BEFORE the changed one in visual\n // order — for a normal list that is cells above the window (index <\n // first), compensated by the anchor. Inverted lists skip the anchor\n // entirely: their correction is the exposed-offset restore on the\n // content-size report, which re-pins the view to the far end exactly\n // like RN's flip keeps contentOffset counting from there.\n if (!inverted && index < range.first) {\n pendingAnchor.current += size - known\n }\n setVersion((value) => value + 1)\n }\n\n // VIEWABILITY. Pure math over the prefix sums — no widget queries. All\n // positions are visual (scroll-space): cellStart already folds in the\n // inverted mirror and scrollY/viewportH track the main axis, so the same\n // code serves normal, inverted, and horizontal lists.\n const recomputeViewability = (): void => {\n if (!onViewableItemsChanged) {\n return\n }\n const viewport = viewportH.current\n const extent = offsets[count] ?? 0\n // Items currently meeting the visibility criteria, in index order.\n const eligible = new Map<string, { item: T; index: number }>()\n if (count > 0 && viewport > 0 && extent > 0) {\n const windowStart = scrollY.current\n const windowEnd = windowStart + viewport\n // Visible data-index range: mirror the visual window into data-offset\n // space when inverted (same mapping as updateRange, zero overscan).\n let start = windowStart\n let end = windowEnd\n if (inverted) {\n ;[start, end] = [extent - end, extent - start]\n }\n const first = indexAt(offsets, Math.max(0, start))\n const last = Math.min(count - 1, indexAt(offsets, end))\n const areaThreshold =\n viewabilityConfig?.viewAreaCoveragePercentThreshold\n const itemThreshold = viewabilityConfig?.itemVisiblePercentThreshold\n for (let index = first; index <= last; index += 1) {\n const length = offsets[index + 1]! - offsets[index]!\n const startPos = cellStart(index)\n const visible =\n Math.min(startPos + length, windowEnd) -\n Math.max(startPos, windowStart)\n if (visible <= 0) {\n continue\n }\n let viewable: boolean\n if (visible >= length) {\n // A fully visible item always counts, even when it covers less\n // than the configured share (RN ViewabilityHelper).\n viewable = true\n } else if (areaThreshold !== undefined) {\n viewable = (100 * visible) / viewport >= areaThreshold\n } else if (itemThreshold !== undefined) {\n viewable = (100 * visible) / length >= itemThreshold\n } else {\n // RN default: any visible pixel counts.\n viewable = true\n }\n if (viewable) {\n const item = data[index]!\n eligible.set(keyOf(item, index), { item, index })\n }\n }\n }\n const minimumViewTime = viewabilityConfig?.minimumViewTime ?? 0\n // Leaving the viewport cancels a pending timer and resets maturity —\n // re-entering restarts the continuous-visibility clock.\n for (const [key, timer] of viewabilityTimers.current) {\n if (!eligible.has(key)) {\n clearTimeout(timer)\n viewabilityTimers.current.delete(key)\n }\n }\n for (const key of maturedKeys.current) {\n if (!eligible.has(key)) {\n maturedKeys.current.delete(key)\n }\n }\n const next = new Map<string, ViewToken<T>>()\n for (const [key, entry] of eligible) {\n if (\n minimumViewTime <= 0 ||\n viewableTokens.current.has(key) ||\n maturedKeys.current.has(key)\n ) {\n next.set(key, {\n item: entry.item,\n key,\n index: entry.index,\n isViewable: true,\n })\n } else if (!viewabilityTimers.current.has(key)) {\n const timer = setTimeout(() => {\n viewabilityTimers.current.delete(key)\n maturedKeys.current.add(key)\n recomputeViewabilityRef.current()\n }, minimumViewTime)\n viewabilityTimers.current.set(key, timer)\n }\n }\n // Emit only when the viewable KEY SET changed: newly-viewable tokens\n // first, then the ones that left (isViewable false), each index-ordered.\n const changed: ViewToken<T>[] = []\n for (const token of next.values()) {\n if (!viewableTokens.current.has(token.key)) {\n changed.push(token)\n }\n }\n for (const token of viewableTokens.current.values()) {\n if (!next.has(token.key)) {\n changed.push({ ...token, isViewable: false })\n }\n }\n // Keep tokens fresh (indices may shift under stable keys) but stay\n // silent while the key set is unchanged.\n viewableTokens.current = next\n if (changed.length === 0) {\n return\n }\n onViewableItemsChanged({ viewableItems: [...next.values()], changed })\n }\n useLayoutEffect(() => {\n recomputeViewabilityRef.current = recomputeViewability\n })\n\n const maybeFireEndReached = (): void => {\n // Before the first layout the viewport extent is unknown — every\n // trigger path below re-runs once it is.\n if (!onEndReached || viewportH.current <= 0) {\n return\n }\n const extent = offsets[count]!\n const threshold =\n viewportH.current * Math.max(0, onEndReachedThreshold ?? 0.1)\n // Distance from the viewport to the DATA end (RN semantics: the end\n // of `data`, not the visual bottom). Normal lists keep the data end\n // at raw position `extent`; the inverted projection places it at raw\n // position 0 (the visual top), so the distance is simply the raw\n // scroll offset — an inverted chat fires this while scrolling up\n // into its history, which is where \"load older\" belongs.\n // Content shorter than the viewport has a negative distance, so short\n // lists fire right after the first layout without any scrolling.\n const distance = inverted\n ? scrollY.current\n : extent - (scrollY.current + viewportH.current)\n if (extent > 0 && distance <= threshold) {\n if (endReachedForSize.current !== extent) {\n endReachedForSize.current = extent\n onEndReached()\n }\n }\n }\n\n const handleScroll = (event: ScrollEvent): void => {\n const raw = horizontal\n ? event.nativeEvent.contentOffset.x\n : event.nativeEvent.contentOffset.y\n scrollY.current = raw\n if (inverted) {\n exposedOffset.current = Math.max(0, maxRawScroll() - raw)\n // The caller sees RN-space offsets: contentOffset 0 is the far end\n // where the data starts (a chat's latest message).\n onScroll?.({\n nativeEvent: {\n ...event.nativeEvent,\n contentOffset: {\n x: horizontal\n ? exposedOffset.current\n : event.nativeEvent.contentOffset.x,\n y: horizontal\n ? event.nativeEvent.contentOffset.y\n : exposedOffset.current,\n },\n },\n })\n } else {\n onScroll?.(event)\n }\n updateRange()\n recomputeViewability()\n maybeFireEndReached()\n }\n\n const handleLayout = (event: LayoutEvent): void => {\n onLayout?.(event)\n viewportH.current = horizontal\n ? event.nativeEvent.layout.width\n : event.nativeEvent.layout.height\n if (inverted) {\n // The viewport changed under a pinned exposed offset: re-derive the\n // raw position and window against the value we are about to take.\n // Best effort — the adjustment may still clamp against the previous\n // page size; the next content-size report settles it.\n scrollY.current = toRaw(exposedOffset.current)\n scrollToAxis(scrollY.current)\n }\n updateRange()\n // First layout doubles as the initial viewability/end-reached pass.\n recomputeViewability()\n maybeFireEndReached()\n }\n\n const handleContentSizeChange = (width: number, height: number): void => {\n onContentSizeChange?.(width, height)\n contentMain.current = horizontal ? width : height\n if (!inverted) {\n return\n }\n // The raw scroll range changed under a pinned exposed offset: restore\n // the raw value from it (the adjustment is fresh — GTK emits \"changed\"\n // only after the allocation that resized it). Content prepended to an\n // inverted chat therefore appears WITHOUT the view moving, exactly\n // like RN's contentOffset staying put under the flip. This also\n // performs the initial positioning: exposed 0 = the data start.\n const raw = toRaw(exposedOffset.current)\n scrollY.current = raw\n scrollToAxis(raw)\n updateRange()\n }\n\n // Data or measurement changes move content under a static viewport (no\n // scroll event fires): refresh viewability and the end-reached trigger.\n useEffect(() => {\n recomputeViewability()\n maybeFireEndReached()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [offsets])\n\n // Unmount: cancel every pending minimumViewTime timer.\n useEffect(() => {\n const timers = viewabilityTimers.current\n return () => {\n for (const timer of timers.values()) {\n clearTimeout(timer)\n }\n timers.clear()\n }\n }, [])\n\n // Sticky cells (vertical, non-inverted): the ACTIVE header must stay\n // mounted even when its own offset left the window — extend the mount\n // set with it; geometry comes from the registry offsets, pinning is the\n // ScrollView registry's job (same mechanism as plain sticky children).\n const stickySorted =\n stickyHeaderIndices && !horizontal && !inverted\n ? [...stickyHeaderIndices].sort((a, b) => a - b)\n : []\n let activeStickyIndex = -1\n for (const stickyIndex of stickySorted) {\n if (stickyIndex < count && cellStart(stickyIndex) <= scrollY.current) {\n activeStickyIndex = stickyIndex\n }\n }\n\n const renderCell = (index: number): ReactNode => {\n const item = data[index]!\n const key = keyOf(item, index)\n // Vertical cells stretch across the width and sit at their offset;\n // horizontal cells stretch across the height and take their own\n // width from content (so onLayout can measure it).\n const cellStyle: StyleProp = horizontal\n ? { position: \"absolute\", left: cellStart(index), top: 0, bottom: 0 }\n : { position: \"absolute\", left: 0, right: 0, top: cellStart(index) }\n const measure = (event: {\n nativeEvent: { layout: { width: number; height: number } }\n }): void =>\n onItemLayout(\n index,\n horizontal\n ? event.nativeEvent.layout.width\n : event.nativeEvent.layout.height,\n )\n const body = (\n <>\n {perfEnabled ? <CellMountProbe /> : null}\n {renderItem({ item, index })}\n {index < count - 1 && ItemSeparatorComponent ? (\n <ItemSeparatorComponent />\n ) : null}\n </>\n )\n if (stickySorted.includes(index)) {\n return (\n <StickySlot\n key={key}\n stickyKey={`cell-${key}`}\n top={cellStart(index)}\n style={cellStyle}\n onLayout={measure}\n >\n {body}\n </StickySlot>\n )\n }\n return (\n <View\n key={key}\n style={cellStyle}\n onLayout={measure}\n >\n {body}\n </View>\n )\n }\n\n const cells: ReactNode[] = []\n const renderStart = perfEnabled ? perfNow() : 0\n if (count > 0) {\n if (activeStickyIndex >= 0 && activeStickyIndex < range.first) {\n cells.push(renderCell(activeStickyIndex))\n }\n const last = Math.min(range.last, count - 1)\n for (let index = range.first; index <= last; index += 1) {\n cells.push(renderCell(index))\n }\n }\n if (perfEnabled) {\n // Element construction only — reconciliation and host mutations happen\n // inside React afterwards; those are visible in engine.flush and the\n // mount counters instead.\n perfAddTime(\"vl.renderCells\", perfNow() - renderStart)\n perfCount(\"vl.render\")\n }\n\n // extraData participates in identity so memoized parents re-render rows.\n void extraData\n // Accepted for RN parity only; no desktop gesture ever calls it.\n void onRefresh\n\n return (\n <ScrollView\n {...scrollProps}\n horizontal={horizontal}\n ref={scrollRef}\n onScroll={handleScroll}\n onContentSizeChange={handleContentSizeChange}\n onLayout={handleLayout}\n >\n {refreshing ? (\n // Desktop RefreshControl: no pull gesture exists, so `refreshing`\n // simply shows an in-flow spinner row above the list content.\n <View style={{ alignItems: \"center\", padding: 8 }}>\n <ActivityIndicator />\n </View>\n ) : null}\n {/* RN's flip mirrors the chrome too: on an inverted list the footer\n sits at the visual top and the header at the visual bottom. */}\n {renderAux(inverted ? ListFooterComponent : ListHeaderComponent)}\n {count === 0 && renderAux(ListEmptyComponent)}\n {count > 0 && (\n <View\n style={\n horizontal\n ? { width: offsets[count]! }\n : { height: offsets[count]! }\n }\n >\n {cells}\n </View>\n )}\n {renderAux(inverted ? ListHeaderComponent : ListFooterComponent)}\n </ScrollView>\n )\n },\n)\nVirtualizedListInner.displayName = \"VirtualizedList\"\n\nexport const VirtualizedList = VirtualizedListInner as <T>(\n props: VirtualizedListProps<T> & { ref?: React.Ref<VirtualizedListHandle> },\n) => ReactElement\n"]}
|
|
1
|
+
{"version":3,"file":"virtualized-list.js","sourceRoot":"","sources":["../../src/components/virtualized-list.tsx"],"names":[],"mappings":"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","sourcesContent":["// The windowed list core (RN VirtualizedList model, leaner): only the rows\n// around the viewport are mounted; the content View carries the prefix-sum\n// height so the ScrollView gets the full range; every mounted cell is\n// absolutely positioned at its offset. Heights come from getItemLayout (exact)\n// or estimatedItemSize refined by per-cell onLayout; corrections above the\n// first visible row are anchored by compensating the scroll offset in the\n// same commit (docs/research/list-window.md).\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type ReactElement,\n type ReactNode,\n} from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n perfAddTime,\n perfBurst,\n perfCount,\n perfEnabled,\n perfNow,\n} from \"../perf\"\nimport { ActivityIndicator } from \"./activity-indicator\"\nimport { registerHandleAlias } from \"./measure\"\nimport { scrollPhaseSink, setScrollPhaseSink } from \"./scroll-phase\"\nimport {\n ScrollView,\n StickySlot,\n type ScrollEvent,\n type ScrollHandle,\n type ScrollViewHandle,\n type ScrollViewProps,\n} from \"./scroll-view\"\nimport type { LayoutEvent } from \"./use-layout-child\"\nimport { View } from \"./view\"\n\nexport type ListRenderItemInfo<T> = { item: T; index: number }\n\nexport type ItemLayout = { length: number; offset: number; index: number }\n\n// RN ViewToken: one entry per item in the viewability report.\nexport type ViewToken<T = unknown> = {\n item: T\n key: string\n index: number\n isViewable: boolean\n}\n\nexport type ViewabilityConfig = {\n // Percent (0..100) of the ITEM that must be visible. A fully visible item\n // always counts, even when it covers less than the threshold.\n itemVisiblePercentThreshold?: number\n // Percent (0..100) of the VIEWPORT the item must cover. Takes precedence\n // over itemVisiblePercentThreshold when both are set (RN ViewabilityHelper).\n viewAreaCoveragePercentThreshold?: number\n // The item must stay continuously visible this many ms before it is\n // reported viewable; scrolling out before that cancels the report.\n minimumViewTime?: number\n}\n\n// RN FlatList scroll surface on top of the ScrollView's SCROLL half. The\n// handle is not generic: scrollToItem takes the item as unknown and resolves\n// the index with indexOf on the latest data.\n//\n// It stops at the scroll methods deliberately. A ScrollView ref also carries\n// RN's geometry methods, because a ScrollView is a host component with a\n// widget behind it; a windowed list is a composite over one, so a `measure()`\n// here would have to pick some inner widget to speak for it and pretend that\n// was the list. Measure the ScrollView, or a cell.\nexport type VirtualizedListHandle = ScrollHandle & {\n scrollToIndex(params: {\n index: number\n viewPosition?: number\n animated?: boolean\n }): void\n scrollToItem(params: {\n item: unknown\n viewPosition?: number\n animated?: boolean\n }): void\n scrollToOffset(params: { offset: number; animated?: boolean }): void\n}\n\nexport type VirtualizedListProps<T> = Omit<ScrollViewProps, \"children\"> & {\n // The data source. `FlatList`'s shape — a plain array — is the default and\n // needs nothing else. RN's `VirtualizedList` shape passes an OPAQUE value\n // plus the two accessors below, and then this prop is never indexed at all;\n // that is why it is typed `unknown` rather than `readonly T[]`.\n data: readonly T[] | unknown\n /**\n * RN's `VirtualizedList` accessor pair. Supplying them makes `data` opaque:\n * the list asks `getItemCount(data)` for the length and `getItem(data, i)`\n * for a row, and reads nothing else out of it. Left out (FlatList,\n * SectionList) `data` is indexed directly.\n *\n * They are honoured LAZILY — `getItem` is called for the rows the window\n * actually mounts, never for the whole range — because the point of the\n * pair upstream is that the source need not be materialised.\n *\n * `never` for the `data` parameter is what makes an accessor written\n * against a CONCRETE source (`(rows: Row[], i) => rows[i]`) assignable\n * here: parameters are contravariant, and RN's own types say `any`.\n */\n getItem?: (data: never, index: number) => T\n getItemCount?: (data: never) => number\n renderItem: (info: ListRenderItemInfo<T>) => ReactElement | null\n keyExtractor?: (item: T, index: number) => string\n estimatedItemSize?: number\n getItemLayout?: (data: never, index: number) => ItemLayout\n // Overscan in viewport multiples (RN semantics: `windowSize` viewports are\n // mounted, one of them visible). RN's mobile default is 5; the desktop\n // default is 11 — see the note on DEFAULT_WINDOW_SIZE.\n windowSize?: number\n initialNumToRender?: number\n // RN batching pair. Rows OUTSIDE the visible area are mounted at most\n // `maxToRenderPerBatch` per pass, one pass every `updateCellsBatchingPeriod`\n // ms, so a flick or a long jump spreads its mounts over frames instead of\n // stalling one. The visible rows never wait for a batch.\n maxToRenderPerBatch?: number\n updateCellsBatchingPeriod?: number\n extraData?: unknown\n // RN inverted semantics: the list opens at the START of the data (visually\n // at the far end — a chat's latest message sits at the bottom), and\n // contentOffset counts from that end. See the projection math below.\n inverted?: boolean\n // RefreshControl parity. Desktop has no pull gesture: `refreshing` renders\n // a spinner row above the content; `onRefresh` is accepted for RN API\n // compatibility but is never triggered by a gesture — app code must call\n // it itself (e.g. from a toolbar button or a keyboard shortcut).\n refreshing?: boolean\n onRefresh?: () => void\n /**\n * RN's per-cell wrapper. The list still decides where a cell goes — the\n * absolute `style` and the `onLayout` that measures it are handed in and\n * must be applied — and this component owns everything else about the\n * container, which is how a library adds a transform or a context to every\n * row without touching `renderItem`.\n *\n * `react-native-draggable-flatlist` is the reason it exists here: its whole\n * design is a cell renderer that translates the row being dragged and puts\n * the \"am I the active cell\" context around it.\n *\n * NOT applied to a STICKY cell (`stickyHeaderIndices`): pinning works by\n * reordering the cell's real GTK widget, so the sticky container has to be\n * the cell. See docs/api.md.\n */\n CellRendererComponent?: ComponentType<{\n cellKey: string\n index: number\n item: T\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n }>\n ItemSeparatorComponent?: ComponentType | null\n ListHeaderComponent?: ComponentType | ReactElement | null\n ListFooterComponent?: ComponentType | ReactElement | null\n ListEmptyComponent?: ComponentType | ReactElement | null\n onEndReached?: () => void\n onEndReachedThreshold?: number\n onViewableItemsChanged?: (info: {\n viewableItems: ViewToken<T>[]\n changed: ViewToken<T>[]\n }) => void\n viewabilityConfig?: ViewabilityConfig\n style?: StyleProp\n}\n\nconst renderAux = (\n component: ComponentType | ReactElement | null | undefined,\n): ReactNode => {\n if (component === null || component === undefined) {\n return null\n }\n if (typeof component === \"function\") {\n const Aux = component\n return <Aux />\n }\n return component\n}\n\n// First index whose offset-end is past `target` (binary search over prefix\n// sums; offsets has count+1 entries).\n//\n// The `target <= offsets[0]` guard is RN's, not an optimisation:\n// `elementsThatOverlapOffsets` treats the FIRST cell's start as INCLUSIVE and\n// every later cell's as exclusive (`mid === 0 && currentOffset <\n// scaledOffsetStart`), and that asymmetry is the whole reason a list of\n// ZERO-LENGTH cells resolves offset 0 to index 0 there. Without it the search\n// walks past every cell whose end is `<= target` — and a zero-length cell at\n// `target` always is — so it lands on the END of the run and the list mounts\n// only its last row.\n//\n// That is not a hypothetical shape. A `FlatList` whose cells each contain one\n// `position: absolute` child has zero flow height in EVERY cell, which is\n// exactly how `react-native-reanimated-dnd`'s `Sortable` renders (rows are\n// absolutely positioned and driven by a per-frame animated `top`), and how\n// any list that positions its own rows does. RN renders all of them; we\n// rendered one. See docs/research/dnd-differential.md.\nconst indexAt = (offsets: number[], target: number): number => {\n if (target <= offsets[0]!) {\n return 0\n }\n let low = 0\n let high = offsets.length - 2\n while (low < high) {\n const mid = (low + high) >> 1\n if (offsets[mid + 1]! <= target) {\n low = mid + 1\n } else {\n high = mid\n }\n }\n return low\n}\n\n// Overscan default. RN ships 5 because a phone pays for mounted rows in\n// memory; a desktop app does not, and here the mounted set is what costs\n// frames: every window boundary crossing is a mount + Yoga reflow + GTK\n// allocate burst, so a WIDER window means fewer crossings per scrolled pixel.\n// Measured (docs/research/scroll-performance.md): 11 instead of 5 cuts\n// mount/unmount churn by ~21% and late frames from ~10/s to ~7.7/s.\nconst DEFAULT_WINDOW_SIZE = 11\n\n// Perf: counts real React mounts/unmounts of windowed cells (rendered as a\n// null child inside each cell only when GTKX_PERF=1).\nconst CellMountProbe = (): null => {\n useLayoutEffect(() => {\n perfCount(\"vl.cellMount\")\n perfBurst(\"vl.mountsPerFrame\")\n return () => {\n perfCount(\"vl.cellUnmount\")\n }\n }, [])\n return null\n}\n\nconst VirtualizedListInner = forwardRef(\n <T,>(\n {\n data,\n getItem,\n getItemCount,\n renderItem,\n keyExtractor,\n estimatedItemSize = 44,\n getItemLayout,\n windowSize = DEFAULT_WINDOW_SIZE,\n initialNumToRender = 10,\n maxToRenderPerBatch = 10,\n updateCellsBatchingPeriod = 50,\n extraData,\n inverted = false,\n refreshing = false,\n onRefresh,\n CellRendererComponent,\n ItemSeparatorComponent,\n ListHeaderComponent,\n ListFooterComponent,\n ListEmptyComponent,\n onEndReached,\n onEndReachedThreshold = 0.1,\n onViewableItemsChanged,\n viewabilityConfig,\n onScroll,\n onContentSizeChange,\n onLayout,\n horizontal = false,\n stickyHeaderIndices,\n ...scrollProps\n }: VirtualizedListProps<T>,\n ref: React.Ref<VirtualizedListHandle>,\n ) => {\n // The three reads the list makes of its data source, in the one place\n // that knows which shape it was given. Everything below goes through\n // them, so the windowing, the prefix sums, the viewability pass and the\n // scroll handle are identical whether the source is an array or RN's\n // opaque value plus accessors.\n const source = data as readonly T[]\n const count = getItemCount ? getItemCount(data as never) : source.length\n const itemAt = (index: number): T =>\n getItem ? getItem(data as never, index) : source[index]!\n const indexOfItem = (item: unknown): number => {\n if (!getItem) {\n return source.indexOf(item as T)\n }\n // RN's own VirtualizedList scans for `scrollToItem` too — an opaque\n // source has no index to ask.\n for (let index = 0; index < count; index += 1) {\n if (itemAt(index) === item) {\n return index\n }\n }\n return -1\n }\n const scrollRef = useRef<ScrollViewHandle>(null)\n\n const measured = useRef<(number | undefined)[]>([])\n const [version, setVersion] = useState(0)\n // Scroll position along the main axis (contentOffset.x when horizontal).\n // Always in RAW adjustment space — all windowing math below is raw.\n const scrollY = useRef(0)\n // Viewport extent along the main axis (width when horizontal).\n const viewportH = useRef(0)\n // RN-space offset for inverted lists. RN's scaleY(-1) flip puts\n // contentOffset 0 at the far (raw) end of the content, so the exposed\n // offset counts from there: exposed = maxRaw - raw. It is the pinned\n // source of truth across content growth — restoring raw from it is what\n // keeps an inverted chat glued to its latest message on prepend.\n const exposedOffset = useRef(0)\n // Main-axis content size as GTK last reported it (the adjustment range).\n // The raw scroll maximum is contentMain - viewport; before the first\n // report it falls back to the list extent (header/footer not yet known).\n const contentMain = useRef(0)\n const pendingAnchor = useRef(0)\n // scrollToIndex issued while sizes were still estimates: re-run the\n // positioning once after the remount measures real sizes (≤2 scrollTo\n // corrections in total).\n const pendingScrollIndex = useRef<{\n index: number\n viewPosition: number\n animated?: boolean\n } | null>(null)\n const endReachedForSize = useRef(-1)\n // Currently reported viewable tokens keyed by item key (isViewable true).\n const viewableTokens = useRef(new Map<string, ViewToken<T>>())\n // Items meeting the viewability criteria but still waiting out\n // minimumViewTime; cancelled if they leave the viewport first.\n const viewabilityTimers = useRef(\n new Map<string, ReturnType<typeof setTimeout>>(),\n )\n // Keys whose minimumViewTime elapsed while continuously visible.\n const maturedKeys = useRef(new Set<string>())\n // Timers must call the LATEST closure (data may change while pending).\n const recomputeViewabilityRef = useRef<() => void>(() => {})\n\n // Prefix sums; rebuilt on any size correction (O(N) — cheap even at\n // 10k, see the spike). getItemLayout skips measuring entirely.\n const offsets = useMemo(() => {\n const out = new Array<number>(count + 1)\n out[0] = 0\n for (let index = 0; index < count; index += 1) {\n const size = getItemLayout\n ? getItemLayout(data as never, index).length\n : (measured.current[index] ?? estimatedItemSize)\n out[index + 1] = out[index]! + size\n }\n return out\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [count, version, estimatedItemSize, getItemLayout, data])\n\n // INVERTED PROJECTION. RN implements inverted as a scaleY(-1) flip of\n // the scroller and every cell; the net layout is the data mirrored\n // around the content extent C = offsets[count]: data index i occupies\n // [C - offsets[i+1], C - offsets[i]) in raw scroll space, so data index\n // 0 sits at the far end. The flip also reverses the scroll axis: RN's\n // contentOffset counts from that far end, so the raw GTK offset and the\n // exposed RN offset are complements (exposed = maxRaw - raw).\n const cellStart = (index: number): number =>\n inverted ? offsets[count]! - offsets[index + 1]! : offsets[index]!\n\n const keyOf = (item: T, index: number): string =>\n keyExtractor ? keyExtractor(item, index) : String(index)\n\n const [range, setRange] = useState(() => ({\n first: 0,\n last: Math.min(count, initialNumToRender) - 1,\n }))\n // Mirror of `range` for event-time math: several scroll events (and a\n // batch timer) can run before React re-renders, and each needs the range\n // the previous one asked for, not the one currently rendered.\n const rangeRef = useRef(range)\n const batchTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n // Mount allowance as a token bucket: maxToRenderPerBatch rows per\n // updateCellsBatchingPeriod, NOT per pass. One frame can run several passes\n // (scroll event, content-size report, measurement version bump) and a\n // per-pass cap would let them stack back into the burst we are avoiding.\n // A steady scroll needs about one row per frame, far under the refill, so\n // its window still follows the offset exactly.\n const batchTokens = useRef(0)\n const batchFilledAt = useRef(0)\n // The batch timer must call the LATEST closure (offsets/data may change).\n const updateRangeRef = useRef<() => void>(() => {})\n\n // Index range covering the visual window grown by `overscan` px on both\n // sides (0 → exactly the visible rows).\n const rangeFor = (overscan: number): { first: number; last: number } => {\n let start = scrollY.current - overscan\n let end = scrollY.current + viewportH.current + overscan\n if (inverted) {\n // Map the visual window back to data-offset space: visual position v\n // covers data offsets C - v (mirror around the extent), so the\n // visual window [start, end] covers data offsets [C - end, C - start].\n const extent = offsets[count]!\n ;[start, end] = [extent - end, extent - start]\n }\n return {\n first: indexAt(offsets, Math.max(0, start)),\n last: Math.min(count - 1, indexAt(offsets, end)),\n }\n }\n\n const updateRange = (): void => {\n perfCount(\"vl.updateRange\")\n const target = rangeFor(\n Math.max(1, (windowSize - 1) / 2) * viewportH.current,\n )\n const current = rangeRef.current\n // MOUNT BUDGET (RN maxToRenderPerBatch). A flick or a scrollToOffset\n // moves the offset by whole viewports in a single frame, so the target\n // window can be an almost entirely new set of rows — mounting it in one\n // go is a burst of cell mounts + Yoga reflow + GTK allocate that shows\n // up as a visible mid-flick stall (docs/research/scroll-performance.md).\n // The VISIBLE rows are always mounted at once (a blank row is worse than\n // a late one); the overscan beyond them fills in over the following\n // batches.\n const visible = rangeFor(0)\n // Reuse the mounted set only when it still covers what is on screen.\n // The mounted set is ONE contiguous range, so keeping a window that no\n // longer reaches the visible rows would mean mounting the whole gap\n // between them in this pass — the burst, by another route. Overlapping\n // the target window is not enough: with a wide windowSize a jump of\n // several viewports still overlaps it.\n const reusable =\n current.last >= visible.first && current.first <= visible.last\n // Keep what is both mounted and still wanted, always covering the\n // visible rows; after a teleport nothing is reusable and the visible\n // rows are the whole starting window.\n let first = reusable\n ? Math.min(Math.max(current.first, target.first), visible.first)\n : visible.first\n let last = reusable\n ? Math.max(Math.min(current.last, target.last), visible.last)\n : visible.last\n // Rows the visible set already costs this pass count against the batch:\n // after a teleport they ARE the batch.\n const kept = reusable\n ? Math.max(\n 0,\n Math.min(last, current.last) - Math.max(first, current.first) + 1,\n )\n : 0\n const now = Date.now()\n if (now - batchFilledAt.current >= updateCellsBatchingPeriod) {\n batchTokens.current = maxToRenderPerBatch\n batchFilledAt.current = now\n }\n let budget = Math.max(0, batchTokens.current - (last - first + 1 - kept))\n while (budget > 0 && (first > target.first || last < target.last)) {\n if (last < target.last) {\n last += 1\n budget -= 1\n }\n if (budget > 0 && first > target.first) {\n first -= 1\n budget -= 1\n }\n }\n batchTokens.current = budget\n if (first !== current.first || last !== current.last) {\n perfCount(\"vl.rangeChange\")\n rangeRef.current = { first, last }\n setRange({ first, last })\n }\n // Still short of the full window: continue on the next batch tick.\n if (first > target.first || last < target.last) {\n perfCount(\"vl.rangePending\")\n if (batchTimer.current === null) {\n batchTimer.current = setTimeout(() => {\n batchTimer.current = null\n updateRangeRef.current()\n }, updateCellsBatchingPeriod)\n }\n }\n }\n useLayoutEffect(() => {\n updateRangeRef.current = updateRange\n })\n\n useEffect(() => {\n return () => {\n if (batchTimer.current !== null) {\n clearTimeout(batchTimer.current)\n batchTimer.current = null\n }\n }\n }, [])\n\n // Clamp a scroll target to the valid range of the axis.\n const clampOffset = (target: number): number => {\n const max = Math.max(0, offsets[count]! - viewportH.current)\n return Math.min(max, Math.max(0, target))\n }\n\n // Raw scroll maximum along the main axis (adjustment upper - page).\n const maxRawScroll = (): number =>\n Math.max(0, (contentMain.current || offsets[count]!) - viewportH.current)\n\n // Translate an RN-space main-axis offset into raw adjustment space (and\n // back — the mapping is its own inverse).\n const toRaw = (offset: number): number =>\n Math.max(0, maxRawScroll() - offset)\n\n // Raw scroll offset that places `index` in the viewport: viewPosition 0\n // aligns the cell start with the viewport start, 0.5 centers it, 1\n // aligns the cell end with the viewport end. Inverted flips which edge\n // viewPosition 0 means: RN computes the target in data space and the\n // scaleY(-1) flip shows it from the other end, so 0 aligns the cell\n // with the visual BOTTOM — in mirrored raw coordinates that is the\n // complementary alignment.\n const offsetForIndex = (index: number, viewPosition: number): number => {\n const size = offsets[index + 1]! - offsets[index]!\n const align = inverted ? 1 - viewPosition : viewPosition\n return clampOffset(cellStart(index) - align * (viewportH.current - size))\n }\n\n const scrollToAxis = (offset: number, animated?: boolean): void => {\n scrollRef.current?.scrollTo(\n horizontal ? { x: offset, animated } : { y: offset, animated },\n )\n }\n\n const scrollToIndex = (params: {\n index: number\n viewPosition?: number\n animated?: boolean\n }): void => {\n if (count === 0) {\n return\n }\n const index = Math.min(count - 1, Math.max(0, Math.trunc(params.index)))\n const viewPosition = params.viewPosition ?? 0\n // Without getItemLayout the target may rest on estimates: remember the\n // request so the version effect can re-run the positioning once the\n // remounted cells have measured (the ≤2-corrections convergence).\n pendingScrollIndex.current = getItemLayout\n ? null\n : { index, viewPosition, animated: params.animated }\n scrollToAxis(offsetForIndex(index, viewPosition), params.animated)\n }\n\n // The handle stands for the ScrollView this list renders: `findNodeHandle`\n // on a list resolves to it (RN resolves a FlatList's the same way), and so\n // does `measureLayout(listRef, …)` from another view. It gains no\n // `measure()` of its own — see the note on VirtualizedListHandle.\n const registerAlias = (handle: VirtualizedListHandle) => {\n registerHandleAlias(handle, () => scrollRef.current)\n return handle\n }\n useImperativeHandle(ref, () =>\n registerAlias({\n // Any direct scroll cancels a pending scrollToIndex correction. The\n // caller always speaks RN-space offsets; inverted translates the main\n // axis into raw adjustment space.\n scrollTo: (options) => {\n pendingScrollIndex.current = null\n const main = horizontal ? options.x : options.y\n if (!inverted || main === undefined) {\n scrollRef.current?.scrollTo(options)\n return\n }\n scrollRef.current?.scrollTo({\n ...options,\n ...(horizontal ? { x: toRaw(main) } : { y: toRaw(main) }),\n })\n },\n scrollToEnd: (options) => {\n pendingScrollIndex.current = null\n // Inverted: the END of the data sits at raw offset 0 (visual top).\n if (inverted) {\n scrollToAxis(0, options?.animated)\n return\n }\n scrollRef.current?.scrollToEnd(options)\n },\n scrollToOffset: ({ offset, animated }) => {\n pendingScrollIndex.current = null\n scrollToAxis(inverted ? toRaw(offset) : offset, animated)\n },\n scrollToIndex,\n scrollToItem: ({ item, viewPosition, animated }) => {\n const index = indexOfItem(item)\n if (index >= 0) {\n scrollToIndex({ index, viewPosition, animated })\n }\n },\n }),\n )\n\n // Data changes move the window in BOTH directions: growth from an empty\n // list must extend the initial range, shrinking must clamp it.\n useLayoutEffect(() => {\n updateRange()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [count])\n\n // Runs right after offsets rebuilt from new measurements. A pending\n // scrollToIndex supersedes anchoring: re-issue the (now refined) target\n // once and stop — this is the second and final correction.\n useLayoutEffect(() => {\n const pending = pendingScrollIndex.current\n if (pending) {\n pendingScrollIndex.current = null\n pendingAnchor.current = 0\n scrollToAxis(\n offsetForIndex(pending.index, pending.viewPosition),\n pending.animated,\n )\n return\n }\n // Anchor: apply the accumulated correction delta right after offsets\n // rebuilt, in the same frame — the viewport does not visually move.\n if (pendingAnchor.current !== 0) {\n const delta = pendingAnchor.current\n pendingAnchor.current = 0\n scrollToAxis(scrollY.current + delta)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [version])\n\n const onItemLayout = (index: number, size: number): void => {\n if (getItemLayout) {\n return\n }\n const known = measured.current[index] ?? estimatedItemSize\n if (Math.abs(known - size) < 0.5) {\n return\n }\n measured.current[index] = size\n perfCount(\"vl.versionBump\")\n perfBurst(\"vl.bumpsPerFrame\")\n // A size change shifts every cell BEFORE the changed one in visual\n // order — for a normal list that is cells above the window (index <\n // first), compensated by the anchor. Inverted lists skip the anchor\n // entirely: their correction is the exposed-offset restore on the\n // content-size report, which re-pins the view to the far end exactly\n // like RN's flip keeps contentOffset counting from there.\n if (!inverted && index < range.first) {\n pendingAnchor.current += size - known\n }\n setVersion((value) => value + 1)\n }\n\n // VIEWABILITY. Pure math over the prefix sums — no widget queries. All\n // positions are visual (scroll-space): cellStart already folds in the\n // inverted mirror and scrollY/viewportH track the main axis, so the same\n // code serves normal, inverted, and horizontal lists.\n const recomputeViewability = (): void => {\n if (!onViewableItemsChanged) {\n return\n }\n const viewport = viewportH.current\n const extent = offsets[count] ?? 0\n // Items currently meeting the visibility criteria, in index order.\n const eligible = new Map<string, { item: T; index: number }>()\n if (count > 0 && viewport > 0 && extent > 0) {\n const windowStart = scrollY.current\n const windowEnd = windowStart + viewport\n // Visible data-index range: mirror the visual window into data-offset\n // space when inverted (same mapping as updateRange, zero overscan).\n let start = windowStart\n let end = windowEnd\n if (inverted) {\n ;[start, end] = [extent - end, extent - start]\n }\n const first = indexAt(offsets, Math.max(0, start))\n const last = Math.min(count - 1, indexAt(offsets, end))\n const areaThreshold =\n viewabilityConfig?.viewAreaCoveragePercentThreshold\n const itemThreshold = viewabilityConfig?.itemVisiblePercentThreshold\n for (let index = first; index <= last; index += 1) {\n const length = offsets[index + 1]! - offsets[index]!\n const startPos = cellStart(index)\n const visible =\n Math.min(startPos + length, windowEnd) -\n Math.max(startPos, windowStart)\n if (visible <= 0) {\n continue\n }\n let viewable: boolean\n if (visible >= length) {\n // A fully visible item always counts, even when it covers less\n // than the configured share (RN ViewabilityHelper).\n viewable = true\n } else if (areaThreshold !== undefined) {\n viewable = (100 * visible) / viewport >= areaThreshold\n } else if (itemThreshold !== undefined) {\n viewable = (100 * visible) / length >= itemThreshold\n } else {\n // RN default: any visible pixel counts.\n viewable = true\n }\n if (viewable) {\n const item = itemAt(index)\n eligible.set(keyOf(item, index), { item, index })\n }\n }\n }\n const minimumViewTime = viewabilityConfig?.minimumViewTime ?? 0\n // Leaving the viewport cancels a pending timer and resets maturity —\n // re-entering restarts the continuous-visibility clock.\n for (const [key, timer] of viewabilityTimers.current) {\n if (!eligible.has(key)) {\n clearTimeout(timer)\n viewabilityTimers.current.delete(key)\n }\n }\n for (const key of maturedKeys.current) {\n if (!eligible.has(key)) {\n maturedKeys.current.delete(key)\n }\n }\n const next = new Map<string, ViewToken<T>>()\n for (const [key, entry] of eligible) {\n if (\n minimumViewTime <= 0 ||\n viewableTokens.current.has(key) ||\n maturedKeys.current.has(key)\n ) {\n next.set(key, {\n item: entry.item,\n key,\n index: entry.index,\n isViewable: true,\n })\n } else if (!viewabilityTimers.current.has(key)) {\n const timer = setTimeout(() => {\n viewabilityTimers.current.delete(key)\n maturedKeys.current.add(key)\n recomputeViewabilityRef.current()\n }, minimumViewTime)\n viewabilityTimers.current.set(key, timer)\n }\n }\n // Emit only when the viewable KEY SET changed: newly-viewable tokens\n // first, then the ones that left (isViewable false), each index-ordered.\n const changed: ViewToken<T>[] = []\n for (const token of next.values()) {\n if (!viewableTokens.current.has(token.key)) {\n changed.push(token)\n }\n }\n for (const token of viewableTokens.current.values()) {\n if (!next.has(token.key)) {\n changed.push({ ...token, isViewable: false })\n }\n }\n // Keep tokens fresh (indices may shift under stable keys) but stay\n // silent while the key set is unchanged.\n viewableTokens.current = next\n if (changed.length === 0) {\n return\n }\n onViewableItemsChanged({ viewableItems: [...next.values()], changed })\n }\n useLayoutEffect(() => {\n recomputeViewabilityRef.current = recomputeViewability\n })\n\n const maybeFireEndReached = (): void => {\n // Before the first layout the viewport extent is unknown — every\n // trigger path below re-runs once it is.\n if (!onEndReached || viewportH.current <= 0) {\n return\n }\n const extent = offsets[count]!\n const threshold =\n viewportH.current * Math.max(0, onEndReachedThreshold ?? 0.1)\n // Distance from the viewport to the DATA end (RN semantics: the end\n // of `data`, not the visual bottom). Normal lists keep the data end\n // at raw position `extent`; the inverted projection places it at raw\n // position 0 (the visual top), so the distance is simply the raw\n // scroll offset — an inverted chat fires this while scrolling up\n // into its history, which is where \"load older\" belongs.\n // Content shorter than the viewport has a negative distance, so short\n // lists fire right after the first layout without any scrolling.\n const distance = inverted\n ? scrollY.current\n : extent - (scrollY.current + viewportH.current)\n if (extent > 0 && distance <= threshold) {\n if (endReachedForSize.current !== extent) {\n endReachedForSize.current = extent\n onEndReached()\n }\n }\n }\n\n const toExposedEvent = (event: ScrollEvent): ScrollEvent => {\n if (!inverted) {\n return event\n }\n const raw = horizontal\n ? event.nativeEvent.contentOffset.x\n : event.nativeEvent.contentOffset.y\n const exposed = Math.max(0, maxRawScroll() - raw)\n return {\n nativeEvent: {\n ...event.nativeEvent,\n contentOffset: {\n x: horizontal ? exposed : event.nativeEvent.contentOffset.x,\n y: horizontal ? event.nativeEvent.contentOffset.y : exposed,\n },\n },\n }\n }\n\n const handleScroll = (event: ScrollEvent): void => {\n const raw = horizontal\n ? event.nativeEvent.contentOffset.x\n : event.nativeEvent.contentOffset.y\n scrollY.current = raw\n if (inverted) {\n exposedOffset.current = Math.max(0, maxRawScroll() - raw)\n }\n onScroll?.(toExposedEvent(event))\n updateRange()\n recomputeViewability()\n maybeFireEndReached()\n }\n\n // Reanimated attaches one phase sink to the handler it hands us. This\n // wrapper used to forward only the function call and silently dropped the\n // sink, so every FlatList/VirtualizedList received onScroll but NONE of\n // onBeginDrag/onEndDrag/momentum — direct ScrollView tests could not catch\n // it. Carry the seam through the composite, translating inverted offsets\n // exactly as the ordinary event path does.\n const upstreamPhaseSink = scrollPhaseSink(onScroll)\n if (upstreamPhaseSink) {\n setScrollPhaseSink(handleScroll, {\n wants: (phase) => upstreamPhaseSink.wants(phase),\n deliver: (phase, event) =>\n upstreamPhaseSink.deliver(phase, toExposedEvent(event)),\n })\n }\n\n const handleLayout = (event: LayoutEvent): void => {\n onLayout?.(event)\n viewportH.current = horizontal\n ? event.nativeEvent.layout.width\n : event.nativeEvent.layout.height\n if (inverted) {\n // The viewport changed under a pinned exposed offset: re-derive the\n // raw position and window against the value we are about to take.\n // Best effort — the adjustment may still clamp against the previous\n // page size; the next content-size report settles it.\n scrollY.current = toRaw(exposedOffset.current)\n scrollToAxis(scrollY.current)\n }\n updateRange()\n // First layout doubles as the initial viewability/end-reached pass.\n recomputeViewability()\n maybeFireEndReached()\n }\n\n const handleContentSizeChange = (width: number, height: number): void => {\n onContentSizeChange?.(width, height)\n contentMain.current = horizontal ? width : height\n if (!inverted) {\n return\n }\n // The raw scroll range changed under a pinned exposed offset: restore\n // the raw value from it (the adjustment is fresh — GTK emits \"changed\"\n // only after the allocation that resized it). Content prepended to an\n // inverted chat therefore appears WITHOUT the view moving, exactly\n // like RN's contentOffset staying put under the flip. This also\n // performs the initial positioning: exposed 0 = the data start.\n const raw = toRaw(exposedOffset.current)\n scrollY.current = raw\n scrollToAxis(raw)\n updateRange()\n }\n\n // Data or measurement changes move content under a static viewport (no\n // scroll event fires): refresh viewability and the end-reached trigger.\n useEffect(() => {\n recomputeViewability()\n maybeFireEndReached()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [offsets])\n\n // Unmount: cancel every pending minimumViewTime timer.\n useEffect(() => {\n const timers = viewabilityTimers.current\n return () => {\n for (const timer of timers.values()) {\n clearTimeout(timer)\n }\n timers.clear()\n }\n }, [])\n\n // Sticky cells (vertical, non-inverted): the ACTIVE header must stay\n // mounted even when its own offset left the window — extend the mount\n // set with it; geometry comes from the registry offsets, pinning is the\n // ScrollView registry's job (same mechanism as plain sticky children).\n const stickySorted =\n stickyHeaderIndices && !horizontal && !inverted\n ? [...stickyHeaderIndices].sort((a, b) => a - b)\n : []\n let activeStickyIndex = -1\n for (const stickyIndex of stickySorted) {\n if (stickyIndex < count && cellStart(stickyIndex) <= scrollY.current) {\n activeStickyIndex = stickyIndex\n }\n }\n\n const renderCell = (index: number): ReactNode => {\n const item = itemAt(index)\n const key = keyOf(item, index)\n // Vertical cells stretch across the width and sit at their offset;\n // horizontal cells stretch across the height and take their own\n // width from content (so onLayout can measure it).\n const cellStyle: StyleProp = horizontal\n ? { position: \"absolute\", left: cellStart(index), top: 0, bottom: 0 }\n : { position: \"absolute\", left: 0, right: 0, top: cellStart(index) }\n const measure = (event: {\n nativeEvent: { layout: { width: number; height: number } }\n }): void =>\n onItemLayout(\n index,\n horizontal\n ? event.nativeEvent.layout.width\n : event.nativeEvent.layout.height,\n )\n const body = (\n <>\n {perfEnabled ? <CellMountProbe /> : null}\n {renderItem({ item, index })}\n {index < count - 1 && ItemSeparatorComponent ? (\n <ItemSeparatorComponent />\n ) : null}\n </>\n )\n if (stickySorted.includes(index)) {\n return (\n <StickySlot\n key={key}\n stickyKey={`cell-${key}`}\n top={cellStart(index)}\n style={cellStyle}\n onLayout={measure}\n >\n {body}\n </StickySlot>\n )\n }\n if (CellRendererComponent) {\n return (\n <CellRendererComponent\n key={key}\n cellKey={key}\n index={index}\n item={item}\n style={cellStyle}\n onLayout={measure}\n >\n {body}\n </CellRendererComponent>\n )\n }\n return (\n <View\n key={key}\n style={cellStyle}\n onLayout={measure}\n >\n {body}\n </View>\n )\n }\n\n const cells: ReactNode[] = []\n const renderStart = perfEnabled ? perfNow() : 0\n if (count > 0) {\n if (activeStickyIndex >= 0 && activeStickyIndex < range.first) {\n cells.push(renderCell(activeStickyIndex))\n }\n const last = Math.min(range.last, count - 1)\n for (let index = range.first; index <= last; index += 1) {\n cells.push(renderCell(index))\n }\n }\n if (perfEnabled) {\n // Element construction only — reconciliation and host mutations happen\n // inside React afterwards; those are visible in engine.flush and the\n // mount counters instead.\n perfAddTime(\"vl.renderCells\", perfNow() - renderStart)\n perfCount(\"vl.render\")\n }\n\n // extraData participates in identity so memoized parents re-render rows.\n void extraData\n // Accepted for RN parity only; no desktop gesture ever calls it.\n void onRefresh\n\n return (\n <ScrollView\n {...scrollProps}\n horizontal={horizontal}\n ref={scrollRef}\n onScroll={handleScroll}\n onContentSizeChange={handleContentSizeChange}\n onLayout={handleLayout}\n >\n {refreshing ? (\n // Desktop RefreshControl: no pull gesture exists, so `refreshing`\n // simply shows an in-flow spinner row above the list content.\n <View style={{ alignItems: \"center\", padding: 8 }}>\n <ActivityIndicator />\n </View>\n ) : null}\n {/* RN's flip mirrors the chrome too: on an inverted list the footer\n sits at the visual top and the header at the visual bottom. */}\n {renderAux(inverted ? ListFooterComponent : ListHeaderComponent)}\n {count === 0 && renderAux(ListEmptyComponent)}\n {count > 0 && (\n <View\n style={\n horizontal\n ? { width: offsets[count]! }\n : { height: offsets[count]! }\n }\n >\n {cells}\n </View>\n )}\n {renderAux(inverted ? ListHeaderComponent : ListFooterComponent)}\n </ScrollView>\n )\n },\n)\nVirtualizedListInner.displayName = \"VirtualizedList\"\n\nexport const VirtualizedList = VirtualizedListInner as <T>(\n props: VirtualizedListProps<T> & { ref?: React.Ref<VirtualizedListHandle> },\n) => ReactElement\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type WheelScrollSession = {
|
|
2
|
+
detent(): void;
|
|
3
|
+
/** End now before another input device starts its own native session. */
|
|
4
|
+
finish(): void;
|
|
5
|
+
dispose(): void;
|
|
6
|
+
};
|
|
7
|
+
export declare const createWheelScrollSession: (begin: () => void, end: () => void, delay?: (callback: () => void, ms: number) => ReturnType<typeof setTimeout>, cancel?: (timer: ReturnType<typeof setTimeout>) => void, idleMs?: number) => WheelScrollSession;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// A physical wheel reports isolated detents: no begin/end signals and no
|
|
2
|
+
// momentum. Consumers still need a user-driven SESSION around a burst — the
|
|
3
|
+
// same distinction browsers expose as wheel-start/wheel-end internally — so
|
|
4
|
+
// they can capture state before the first detent mutates it. Kept pure so the
|
|
5
|
+
// ordering, deduplication and teardown rules are unit-testable without GTK.
|
|
6
|
+
export const createWheelScrollSession = (begin, end, delay = setTimeout, cancel = clearTimeout, idleMs = 120) => {
|
|
7
|
+
let active = false;
|
|
8
|
+
let endTimer = null;
|
|
9
|
+
let generation = 0;
|
|
10
|
+
const cancelEnd = () => {
|
|
11
|
+
if (endTimer !== null) {
|
|
12
|
+
cancel(endTimer);
|
|
13
|
+
endTimer = null;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const finish = () => {
|
|
17
|
+
generation += 1;
|
|
18
|
+
cancelEnd();
|
|
19
|
+
if (!active) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
active = false;
|
|
23
|
+
end();
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
detent: () => {
|
|
27
|
+
if (!active) {
|
|
28
|
+
active = true;
|
|
29
|
+
begin();
|
|
30
|
+
}
|
|
31
|
+
cancelEnd();
|
|
32
|
+
const ownGeneration = ++generation;
|
|
33
|
+
endTimer = delay(() => {
|
|
34
|
+
// clearTimeout normally makes this impossible. The generation also
|
|
35
|
+
// covers a callback already queued when a later detent re-arms the
|
|
36
|
+
// session — ending that newer burst early would lose its context.
|
|
37
|
+
if (!active || ownGeneration !== generation) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
endTimer = null;
|
|
41
|
+
active = false;
|
|
42
|
+
end();
|
|
43
|
+
}, idleMs);
|
|
44
|
+
},
|
|
45
|
+
finish,
|
|
46
|
+
dispose: () => {
|
|
47
|
+
generation += 1;
|
|
48
|
+
cancelEnd();
|
|
49
|
+
active = false;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=wheel-scroll-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wheel-scroll-session.js","sourceRoot":"","sources":["../../src/components/wheel-scroll-session.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAS5E,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,KAAiB,EACjB,GAAe,EACf,QAGqC,UAAU,EAC/C,SAAyD,YAAY,EACrE,MAAM,GAAG,GAAG,EACQ,EAAE;IACtB,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,IAAI,QAAQ,GAAyC,IAAI,CAAA;IACzD,IAAI,UAAU,GAAG,CAAC,CAAA;IAElB,MAAM,SAAS,GAAG,GAAS,EAAE;QAC3B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,CAAC,QAAQ,CAAC,CAAA;YAChB,QAAQ,GAAG,IAAI,CAAA;QACjB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,UAAU,IAAI,CAAC,CAAA;QACf,SAAS,EAAE,CAAA;QACX,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QACD,MAAM,GAAG,KAAK,CAAA;QACd,GAAG,EAAE,CAAA;IACP,CAAC,CAAA;IAED,OAAO;QACL,MAAM,EAAE,GAAG,EAAE;YACX,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,IAAI,CAAA;gBACb,KAAK,EAAE,CAAA;YACT,CAAC;YACD,SAAS,EAAE,CAAA;YACX,MAAM,aAAa,GAAG,EAAE,UAAU,CAAA;YAClC,QAAQ,GAAG,KAAK,CAAC,GAAG,EAAE;gBACpB,mEAAmE;gBACnE,mEAAmE;gBACnE,kEAAkE;gBAClE,IAAI,CAAC,MAAM,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;oBAC5C,OAAM;gBACR,CAAC;gBACD,QAAQ,GAAG,IAAI,CAAA;gBACf,MAAM,GAAG,KAAK,CAAA;gBACd,GAAG,EAAE,CAAA;YACP,CAAC,EAAE,MAAM,CAAC,CAAA;QACZ,CAAC;QACD,MAAM;QACN,OAAO,EAAE,GAAG,EAAE;YACZ,UAAU,IAAI,CAAC,CAAA;YACf,SAAS,EAAE,CAAA;YACX,MAAM,GAAG,KAAK,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["// A physical wheel reports isolated detents: no begin/end signals and no\n// momentum. Consumers still need a user-driven SESSION around a burst — the\n// same distinction browsers expose as wheel-start/wheel-end internally — so\n// they can capture state before the first detent mutates it. Kept pure so the\n// ordering, deduplication and teardown rules are unit-testable without GTK.\n\nexport type WheelScrollSession = {\n detent(): void\n /** End now before another input device starts its own native session. */\n finish(): void\n dispose(): void\n}\n\nexport const createWheelScrollSession = (\n begin: () => void,\n end: () => void,\n delay: (\n callback: () => void,\n ms: number,\n ) => ReturnType<typeof setTimeout> = setTimeout,\n cancel: (timer: ReturnType<typeof setTimeout>) => void = clearTimeout,\n idleMs = 120,\n): WheelScrollSession => {\n let active = false\n let endTimer: ReturnType<typeof setTimeout> | null = null\n let generation = 0\n\n const cancelEnd = (): void => {\n if (endTimer !== null) {\n cancel(endTimer)\n endTimer = null\n }\n }\n\n const finish = (): void => {\n generation += 1\n cancelEnd()\n if (!active) {\n return\n }\n active = false\n end()\n }\n\n return {\n detent: () => {\n if (!active) {\n active = true\n begin()\n }\n cancelEnd()\n const ownGeneration = ++generation\n endTimer = delay(() => {\n // clearTimeout normally makes this impossible. The generation also\n // covers a callback already queued when a later detent re-arms the\n // session — ending that newer burst early would lose its context.\n if (!active || ownGeneration !== generation) {\n return\n }\n endTimer = null\n active = false\n end()\n }, idleMs)\n },\n finish,\n dispose: () => {\n generation += 1\n cancelEnd()\n active = false\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Gtk } from "../gtkx/bridge/index";
|
|
2
|
+
/** A live retention. Releasing is idempotent — the timer may get there first. */
|
|
3
|
+
export type WidgetRetention = {
|
|
4
|
+
/** Drops the widget and runs everything deferred while it was held. */
|
|
5
|
+
release(): void;
|
|
6
|
+
};
|
|
7
|
+
/** @internal Test seam: how many widgets are being held right now. */
|
|
8
|
+
export declare const retainedWidgetCount: () => number;
|
|
9
|
+
/**
|
|
10
|
+
* Postpones `job` if `widget` is inside a subtree being retained; otherwise
|
|
11
|
+
* says so and leaves the caller to run it now.
|
|
12
|
+
*
|
|
13
|
+
* This is the single seam the unmount path uses (see use-layout-child.ts).
|
|
14
|
+
* Jobs run in reverse registration order when the retention is released, so
|
|
15
|
+
* a subtree is taken apart from the leaves back up the way it was built.
|
|
16
|
+
*/
|
|
17
|
+
export declare const deferUntilReleased: (widget: Gtk.Widget | null | undefined, job: () => void) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Holds `widget` in `parent` until the returned handle is released or
|
|
20
|
+
* `fallbackMs` elapses.
|
|
21
|
+
*
|
|
22
|
+
* Call it from the unmounting component's own layout-effect cleanup — which
|
|
23
|
+
* React runs BEFORE the cleanups of the components below it and before the
|
|
24
|
+
* widget is unparented, so the retention is registered by the time the rest
|
|
25
|
+
* of the subtree asks whether it is inside one.
|
|
26
|
+
*
|
|
27
|
+
* Returns null when there is nothing to retain: no widget, or a parent that
|
|
28
|
+
* is being unmounted in the same commit (its ref has already been detached,
|
|
29
|
+
* which is exactly the case where an exit animation would be animating
|
|
30
|
+
* something on its way out anyway).
|
|
31
|
+
*/
|
|
32
|
+
export declare const retainWidget: (widget: Gtk.Widget | null | undefined, parent: Gtk.Widget | null | undefined, options?: {
|
|
33
|
+
fallbackMs?: number;
|
|
34
|
+
onRelease?: () => void;
|
|
35
|
+
}) => WidgetRetention | null;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// Keeping a widget on screen after React has reconciled it away.
|
|
2
|
+
//
|
|
3
|
+
// THE PROBLEM. Every exit animation — a Reanimated `exiting`, a route
|
|
4
|
+
// leaving a stack, anything that has to be *seen* going — needs the view
|
|
5
|
+
// layer to keep drawing something React already considers gone. React's
|
|
6
|
+
// deletion is not asynchronous and does not ask: the reconciler runs the
|
|
7
|
+
// unmounting subtree's layout-effect cleanups and then unparents its topmost
|
|
8
|
+
// widget, in one synchronous commit. By the time our own cleanup in
|
|
9
|
+
// use-layout-child.ts runs, the Yoga node is about to be freed and the widget
|
|
10
|
+
// is one call away from having no parent, so there is nothing left to
|
|
11
|
+
// animate.
|
|
12
|
+
//
|
|
13
|
+
// THE SHAPE OF THE ANSWER is the one src/common/navigation-stack.tsx already
|
|
14
|
+
// uses for pages: hold on to what is leaving, drop it on the real end-of-
|
|
15
|
+
// animation signal, and arm a timer in case that signal never comes. This
|
|
16
|
+
// module is that pattern with the React-element half replaced by the widget
|
|
17
|
+
// half, and generalised: it knows nothing about Reanimated, about layout
|
|
18
|
+
// animations, or about what is being animated. It knows how to keep a widget
|
|
19
|
+
// alive, parented and laid out until somebody says stop.
|
|
20
|
+
//
|
|
21
|
+
// WHAT RETENTION HAS TO COVER, measured against what actually breaks:
|
|
22
|
+
//
|
|
23
|
+
// 1. The widget is unparented by the reconciler. It SURVIVES that (its
|
|
24
|
+
// JS wrapper holds the reference; verified on the rig — a widget removed
|
|
25
|
+
// by React re-parents and re-allocates at its stored rect), so the fix
|
|
26
|
+
// is to put it back, in the same container, at the end of the child list
|
|
27
|
+
// so it draws over the siblings that are reflowing into its place.
|
|
28
|
+
// 2. Every container in the subtree has its RnGtkxLayout DETACHED, which
|
|
29
|
+
// hands its children back to a GtkBox with no layout manager at all —
|
|
30
|
+
// after which nothing size-allocates them, GTK warns once per frame that
|
|
31
|
+
// it is snapshotting a child "without a current allocation", and the
|
|
32
|
+
// subtree measures 0×0 instead of the size the engine gave it. That
|
|
33
|
+
// detach is what gets deferred.
|
|
34
|
+
//
|
|
35
|
+
// AND WHAT IT DELIBERATELY DOES NOT COVER: the Yoga nodes. They are removed
|
|
36
|
+
// from the shadow tree and freed on the spot, like any other unmount, because
|
|
37
|
+
// the only thing the retained subtree still reads from a node is
|
|
38
|
+
// `getRect()` — and that returns `lastRect`, an ordinary JS object that
|
|
39
|
+
// outlives the WASM node. Deferring the free as well was measured against the
|
|
40
|
+
// same test and changed nothing, so it is not here.
|
|
41
|
+
//
|
|
42
|
+
// (2) applies to the whole retained SUBTREE, not just its root, so the
|
|
43
|
+
// deferral is looked up by walking the widget's parent chain — which is
|
|
44
|
+
// intact at cleanup time, because the reconciler unparents only the topmost
|
|
45
|
+
// widget of a deleted subtree and does it last.
|
|
46
|
+
//
|
|
47
|
+
// THE TIMER IS NOT OPTIONAL. A retained widget is a widget nothing owns: if
|
|
48
|
+
// the animation that was supposed to release it never ends — it was never
|
|
49
|
+
// started, it threw, the frame source died — the widget stays parented,
|
|
50
|
+
// drawn, and hit-testable forever. Every retention therefore arms a fallback
|
|
51
|
+
// that releases it regardless, and `release()` is idempotent so whichever
|
|
52
|
+
// arrives first wins.
|
|
53
|
+
import { queueAllocate } from "../gtkx/bridge/index";
|
|
54
|
+
// A deliberately generous upper bound for how long a widget may be retained
|
|
55
|
+
// when the caller does not name its own, mirroring navigation-stack.tsx's
|
|
56
|
+
// `DEFAULT_TRANSITION_MS`: NOT a measurement of any real animation, just the
|
|
57
|
+
// point past which "still animating" stops being a credible explanation for a
|
|
58
|
+
// widget nothing owns.
|
|
59
|
+
const DEFAULT_RETENTION_MS = 1000;
|
|
60
|
+
// Keyed by the retained widget, and a real Map rather than a WeakMap on
|
|
61
|
+
// purpose: while a widget is retained, this IS its owner — nothing else
|
|
62
|
+
// references it — and `size` is the fast path that keeps `deferUntilReleased`
|
|
63
|
+
// free for every unmount that is not part of a retention.
|
|
64
|
+
const retentions = new Map();
|
|
65
|
+
/** @internal Test seam: how many widgets are being held right now. */
|
|
66
|
+
export const retainedWidgetCount = () => retentions.size;
|
|
67
|
+
const findRetention = (widget) => {
|
|
68
|
+
let current = widget;
|
|
69
|
+
while (current !== null) {
|
|
70
|
+
const found = retentions.get(current);
|
|
71
|
+
if (found !== undefined) {
|
|
72
|
+
return found;
|
|
73
|
+
}
|
|
74
|
+
current = current.getParent();
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Postpones `job` if `widget` is inside a subtree being retained; otherwise
|
|
80
|
+
* says so and leaves the caller to run it now.
|
|
81
|
+
*
|
|
82
|
+
* This is the single seam the unmount path uses (see use-layout-child.ts).
|
|
83
|
+
* Jobs run in reverse registration order when the retention is released, so
|
|
84
|
+
* a subtree is taken apart from the leaves back up the way it was built.
|
|
85
|
+
*/
|
|
86
|
+
export const deferUntilReleased = (widget, job) => {
|
|
87
|
+
if (!widget || retentions.size === 0) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const retention = findRetention(widget);
|
|
91
|
+
if (retention === null) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
retention.deferred.push(job);
|
|
95
|
+
return true;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Holds `widget` in `parent` until the returned handle is released or
|
|
99
|
+
* `fallbackMs` elapses.
|
|
100
|
+
*
|
|
101
|
+
* Call it from the unmounting component's own layout-effect cleanup — which
|
|
102
|
+
* React runs BEFORE the cleanups of the components below it and before the
|
|
103
|
+
* widget is unparented, so the retention is registered by the time the rest
|
|
104
|
+
* of the subtree asks whether it is inside one.
|
|
105
|
+
*
|
|
106
|
+
* Returns null when there is nothing to retain: no widget, or a parent that
|
|
107
|
+
* is being unmounted in the same commit (its ref has already been detached,
|
|
108
|
+
* which is exactly the case where an exit animation would be animating
|
|
109
|
+
* something on its way out anyway).
|
|
110
|
+
*/
|
|
111
|
+
export const retainWidget = (widget, parent, options) => {
|
|
112
|
+
if (!widget || !parent) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const existing = retentions.get(widget);
|
|
116
|
+
if (existing !== undefined) {
|
|
117
|
+
// Retaining the same widget twice would fight over one parent slot.
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
const retention = {
|
|
121
|
+
deferred: [],
|
|
122
|
+
timer: null,
|
|
123
|
+
released: false,
|
|
124
|
+
onRelease: options?.onRelease,
|
|
125
|
+
};
|
|
126
|
+
retentions.set(widget, retention);
|
|
127
|
+
const release = () => {
|
|
128
|
+
if (retention.released) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
retention.released = true;
|
|
132
|
+
if (retention.timer !== null) {
|
|
133
|
+
clearTimeout(retention.timer);
|
|
134
|
+
retention.timer = null;
|
|
135
|
+
}
|
|
136
|
+
retentions.delete(widget);
|
|
137
|
+
// Unparent first: everything below undoes the layout bookkeeping that
|
|
138
|
+
// only matters while the widget is still on screen.
|
|
139
|
+
if (widget.getParent() !== null) {
|
|
140
|
+
widget.unparent();
|
|
141
|
+
}
|
|
142
|
+
for (let index = retention.deferred.length - 1; index >= 0; index -= 1) {
|
|
143
|
+
retention.deferred[index]();
|
|
144
|
+
}
|
|
145
|
+
retention.deferred.length = 0;
|
|
146
|
+
retention.onRelease?.();
|
|
147
|
+
};
|
|
148
|
+
// The reconciler unparents the widget AFTER this cleanup returns, so the
|
|
149
|
+
// re-attach cannot happen here. A microtask is the earliest moment that is
|
|
150
|
+
// still inside the same turn of the main loop — GTK has not had a chance to
|
|
151
|
+
// lay out or paint, so nothing flickers.
|
|
152
|
+
queueMicrotask(() => {
|
|
153
|
+
if (retention.released) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (widget.getParent() === null) {
|
|
157
|
+
// Appended rather than restored to its old index, and that is
|
|
158
|
+
// load-bearing twice over: last in the child list means drawn over the
|
|
159
|
+
// siblings closing the gap, and it means the sibling positions
|
|
160
|
+
// use-layout-child.ts derives a new child's Yoga index from are not
|
|
161
|
+
// shifted by a widget that has no Yoga node any more.
|
|
162
|
+
widget.setParent(parent);
|
|
163
|
+
}
|
|
164
|
+
queueAllocate(parent);
|
|
165
|
+
});
|
|
166
|
+
retention.timer = setTimeout(release, options?.fallbackMs ?? DEFAULT_RETENTION_MS);
|
|
167
|
+
return { release };
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=widget-retention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-retention.js","sourceRoot":"","sources":["../../src/components/widget-retention.ts"],"names":[],"mappings":"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","sourcesContent":["// Keeping a widget on screen after React has reconciled it away.\n//\n// THE PROBLEM. Every exit animation — a Reanimated `exiting`, a route\n// leaving a stack, anything that has to be *seen* going — needs the view\n// layer to keep drawing something React already considers gone. React's\n// deletion is not asynchronous and does not ask: the reconciler runs the\n// unmounting subtree's layout-effect cleanups and then unparents its topmost\n// widget, in one synchronous commit. By the time our own cleanup in\n// use-layout-child.ts runs, the Yoga node is about to be freed and the widget\n// is one call away from having no parent, so there is nothing left to\n// animate.\n//\n// THE SHAPE OF THE ANSWER is the one src/common/navigation-stack.tsx already\n// uses for pages: hold on to what is leaving, drop it on the real end-of-\n// animation signal, and arm a timer in case that signal never comes. This\n// module is that pattern with the React-element half replaced by the widget\n// half, and generalised: it knows nothing about Reanimated, about layout\n// animations, or about what is being animated. It knows how to keep a widget\n// alive, parented and laid out until somebody says stop.\n//\n// WHAT RETENTION HAS TO COVER, measured against what actually breaks:\n//\n// 1. The widget is unparented by the reconciler. It SURVIVES that (its\n// JS wrapper holds the reference; verified on the rig — a widget removed\n// by React re-parents and re-allocates at its stored rect), so the fix\n// is to put it back, in the same container, at the end of the child list\n// so it draws over the siblings that are reflowing into its place.\n// 2. Every container in the subtree has its RnGtkxLayout DETACHED, which\n// hands its children back to a GtkBox with no layout manager at all —\n// after which nothing size-allocates them, GTK warns once per frame that\n// it is snapshotting a child \"without a current allocation\", and the\n// subtree measures 0×0 instead of the size the engine gave it. That\n// detach is what gets deferred.\n//\n// AND WHAT IT DELIBERATELY DOES NOT COVER: the Yoga nodes. They are removed\n// from the shadow tree and freed on the spot, like any other unmount, because\n// the only thing the retained subtree still reads from a node is\n// `getRect()` — and that returns `lastRect`, an ordinary JS object that\n// outlives the WASM node. Deferring the free as well was measured against the\n// same test and changed nothing, so it is not here.\n//\n// (2) applies to the whole retained SUBTREE, not just its root, so the\n// deferral is looked up by walking the widget's parent chain — which is\n// intact at cleanup time, because the reconciler unparents only the topmost\n// widget of a deleted subtree and does it last.\n//\n// THE TIMER IS NOT OPTIONAL. A retained widget is a widget nothing owns: if\n// the animation that was supposed to release it never ends — it was never\n// started, it threw, the frame source died — the widget stays parented,\n// drawn, and hit-testable forever. Every retention therefore arms a fallback\n// that releases it regardless, and `release()` is idempotent so whichever\n// arrives first wins.\nimport { queueAllocate, type Gtk } from \"../gtkx/bridge/index\"\n\n// A deliberately generous upper bound for how long a widget may be retained\n// when the caller does not name its own, mirroring navigation-stack.tsx's\n// `DEFAULT_TRANSITION_MS`: NOT a measurement of any real animation, just the\n// point past which \"still animating\" stops being a credible explanation for a\n// widget nothing owns.\nconst DEFAULT_RETENTION_MS = 1000\n\n/** A live retention. Releasing is idempotent — the timer may get there first. */\nexport type WidgetRetention = {\n /** Drops the widget and runs everything deferred while it was held. */\n release(): void\n}\n\ntype Retention = {\n deferred: (() => void)[]\n timer: ReturnType<typeof setTimeout> | null\n released: boolean\n onRelease: (() => void) | undefined\n}\n\n// Keyed by the retained widget, and a real Map rather than a WeakMap on\n// purpose: while a widget is retained, this IS its owner — nothing else\n// references it — and `size` is the fast path that keeps `deferUntilReleased`\n// free for every unmount that is not part of a retention.\nconst retentions = new Map<Gtk.Widget, Retention>()\n\n/** @internal Test seam: how many widgets are being held right now. */\nexport const retainedWidgetCount = (): number => retentions.size\n\nconst findRetention = (widget: Gtk.Widget): Retention | null => {\n let current: Gtk.Widget | null = widget\n while (current !== null) {\n const found = retentions.get(current)\n if (found !== undefined) {\n return found\n }\n current = current.getParent() as Gtk.Widget | null\n }\n return null\n}\n\n/**\n * Postpones `job` if `widget` is inside a subtree being retained; otherwise\n * says so and leaves the caller to run it now.\n *\n * This is the single seam the unmount path uses (see use-layout-child.ts).\n * Jobs run in reverse registration order when the retention is released, so\n * a subtree is taken apart from the leaves back up the way it was built.\n */\nexport const deferUntilReleased = (\n widget: Gtk.Widget | null | undefined,\n job: () => void,\n): boolean => {\n if (!widget || retentions.size === 0) {\n return false\n }\n const retention = findRetention(widget)\n if (retention === null) {\n return false\n }\n retention.deferred.push(job)\n return true\n}\n\n/**\n * Holds `widget` in `parent` until the returned handle is released or\n * `fallbackMs` elapses.\n *\n * Call it from the unmounting component's own layout-effect cleanup — which\n * React runs BEFORE the cleanups of the components below it and before the\n * widget is unparented, so the retention is registered by the time the rest\n * of the subtree asks whether it is inside one.\n *\n * Returns null when there is nothing to retain: no widget, or a parent that\n * is being unmounted in the same commit (its ref has already been detached,\n * which is exactly the case where an exit animation would be animating\n * something on its way out anyway).\n */\nexport const retainWidget = (\n widget: Gtk.Widget | null | undefined,\n parent: Gtk.Widget | null | undefined,\n options?: { fallbackMs?: number; onRelease?: () => void },\n): WidgetRetention | null => {\n if (!widget || !parent) {\n return null\n }\n const existing = retentions.get(widget)\n if (existing !== undefined) {\n // Retaining the same widget twice would fight over one parent slot.\n return null\n }\n\n const retention: Retention = {\n deferred: [],\n timer: null,\n released: false,\n onRelease: options?.onRelease,\n }\n retentions.set(widget, retention)\n\n const release = (): void => {\n if (retention.released) {\n return\n }\n retention.released = true\n if (retention.timer !== null) {\n clearTimeout(retention.timer)\n retention.timer = null\n }\n retentions.delete(widget)\n // Unparent first: everything below undoes the layout bookkeeping that\n // only matters while the widget is still on screen.\n if (widget.getParent() !== null) {\n widget.unparent()\n }\n for (let index = retention.deferred.length - 1; index >= 0; index -= 1) {\n retention.deferred[index]!()\n }\n retention.deferred.length = 0\n retention.onRelease?.()\n }\n\n // The reconciler unparents the widget AFTER this cleanup returns, so the\n // re-attach cannot happen here. A microtask is the earliest moment that is\n // still inside the same turn of the main loop — GTK has not had a chance to\n // lay out or paint, so nothing flickers.\n queueMicrotask(() => {\n if (retention.released) {\n return\n }\n if (widget.getParent() === null) {\n // Appended rather than restored to its old index, and that is\n // load-bearing twice over: last in the child list means drawn over the\n // siblings closing the gap, and it means the sibling positions\n // use-layout-child.ts derives a new child's Yoga index from are not\n // shifted by a widget that has no Yoga node any more.\n widget.setParent(parent)\n }\n queueAllocate(parent)\n })\n\n retention.timer = setTimeout(\n release,\n options?.fallbackMs ?? DEFAULT_RETENTION_MS,\n )\n\n return { release }\n}\n"]}
|