react-native-gtkx 0.1.0-alpha.2 → 0.1.0-alpha.3
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 +4 -5
- package/dist/apis/back-handler.d.ts +9 -0
- package/dist/apis/back-handler.js +30 -0
- package/dist/apis/back-handler.js.map +1 -0
- package/dist/apis/host.d.ts +7 -1
- package/dist/apis/host.gtkx.js +12 -1
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/apis/host.js.map +1 -1
- package/dist/apis/i18n-manager.d.ts +14 -0
- package/dist/apis/i18n-manager.js +20 -0
- package/dist/apis/i18n-manager.js.map +1 -0
- package/dist/apis/index.d.ts +17 -0
- package/dist/apis/index.js +5 -0
- package/dist/apis/index.js.map +1 -1
- package/dist/apis/interaction-manager.d.ts +16 -0
- package/dist/apis/interaction-manager.js +96 -0
- package/dist/apis/interaction-manager.js.map +1 -0
- package/dist/apis/linking.d.ts +4 -0
- package/dist/apis/linking.js +9 -0
- package/dist/apis/linking.js.map +1 -1
- package/dist/components/app-registry.d.ts +2 -0
- package/dist/components/app-registry.js +19 -2
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/flat-list.d.ts +2 -0
- package/dist/components/flat-list.js.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/components/modal.d.ts +1 -1
- package/dist/components/root.d.ts +10 -1
- package/dist/components/root.js +39 -1
- package/dist/components/root.js.map +1 -1
- package/dist/components/scroll-view.js +58 -5
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/text-input.d.ts +1 -0
- package/dist/components/text-input.js +31 -3
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/use-layout-child.d.ts +1 -1
- package/dist/components/use-layout-child.js +22 -2
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/virtualized-list.d.ts +2 -0
- package/dist/components/virtualized-list.js +132 -10
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/gtkx/bridge/index.d.ts +4 -2
- package/dist/gtkx/bridge/index.js +6 -2
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/measure.js +5 -0
- package/dist/gtkx/bridge/measure.js.map +1 -1
- package/dist/gtkx/bridge/use-signal.d.ts +2 -0
- package/dist/gtkx/bridge/use-signal.js +30 -0
- package/dist/gtkx/bridge/use-signal.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/layout/engine.d.ts +4 -0
- package/dist/layout/engine.js +97 -5
- package/dist/layout/engine.js.map +1 -1
- package/dist/layout/node.d.ts +1 -1
- package/dist/layout/node.js +8 -5
- package/dist/layout/node.js.map +1 -1
- package/dist/metro/index.js +1 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/index.d.ts +44 -0
- package/dist/navigation/index.js +216 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/option-warnings.d.ts +2 -0
- package/dist/navigation/option-warnings.js +61 -0
- package/dist/navigation/option-warnings.js.map +1 -0
- package/dist/navigation/sidebar.d.ts +37 -0
- package/dist/navigation/sidebar.js +71 -0
- package/dist/navigation/sidebar.js.map +1 -0
- package/dist/perf.d.ts +9 -0
- package/dist/perf.js +156 -0
- package/dist/perf.js.map +1 -0
- package/dist/runner/host-dev.js +15 -6
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +24 -9
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.js +4 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/vite/index.d.ts +5 -4
- package/dist/vite/index.js +41 -7
- package/dist/vite/index.js.map +1 -1
- package/package.json +18 -10
- package/types.d.ts +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-registry.js","sourceRoot":"","sources":["../../src/components/app-registry.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAsB,MAAM,OAAO,CAAA;AAC3D,OAAO,EACL,UAAU,EACV,GAAG,EACH,cAAc,EACd,oBAAoB,EACpB,IAAI,GACL,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAI7B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"app-registry.js","sourceRoot":"","sources":["../../src/components/app-registry.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, type ComponentType } from \"react\"\nimport {\n AdwApplicationWindow,\n createRoot,\n Gtk,\n GtkApplication,\n GtkApplicationWindow,\n quit,\n} from \"../gtkx/bridge/index\"\nimport { Root } from \"./root\"\n\ntype ComponentProvider = () => ComponentType<Record<string, unknown>>\n\nconst registry = new Map<string, ComponentProvider>()\n\n// The chrome the running app was started with — read by the navigation\n// dev-mode hint (a HeaderBar page under \"system\" chrome renders a doubled\n// titlebar). null until runApplication ran (test harnesses never set it).\nlet activeChrome: \"system\" | \"content\" | null = null\nexport const getActiveChrome = (): \"system\" | \"content\" | null => activeChrome\n\nexport type RunApplicationParams = {\n initialProps?: Record<string, unknown>\n title?: string\n width?: number\n height?: number\n // Window chrome. \"system\" (default): a GtkApplicationWindow with its own\n // titlebar. \"content\": an AdwApplicationWindow with NO window titlebar —\n // the app's content provides HeaderBars (navigation apps: the page\n // HeaderBar becomes the titlebar, with the window controls in it).\n chrome?: \"system\" | \"content\"\n}\n\n// RN parity: system \"reduce animations\" hints never auto-stop RN animations\n// (ActivityIndicator keeps spinning; honoring reduce-motion is an explicit\n// opt-in via AccessibilityInfo). Our Animated runs on GLib timers and already\n// ignores the hint, so GTK-internal animations (GtkSpinner, switch slides)\n// must behave the same — otherwise e.g. GNOME under software rendering\n// reports enable-animations=false through the settings portal and spinners\n// freeze while Animated keeps moving.\nlet animationsForced = false\nconst forceEnableAnimations = (): void => {\n if (animationsForced) {\n return\n }\n const settings = Gtk.Settings.getDefault()\n if (!settings) {\n return\n }\n animationsForced = true\n // Application-set GtkSettings values outrank the desktop backend, so a\n // later portal update cannot flip this back.\n settings.gtkEnableAnimations = true\n}\n\n// chrome \"content\": the app component IS the window content (a navigation\n// container whose pages host their own NestedRoots) — no window-level Yoga\n// root in between: the layout root would not allocate foreign GTK children.\nconst ContentChrome = ({\n App,\n initialProps,\n}: {\n App: ComponentType<Record<string, unknown>>\n initialProps: Record<string, unknown>\n}) => {\n useLayoutEffect(() => {\n forceEnableAnimations()\n }, [])\n return <App {...initialProps} />\n}\n\nconst WindowContent = ({\n App,\n initialProps,\n initialWidth,\n initialHeight,\n}: {\n App: ComponentType<Record<string, unknown>>\n initialProps: Record<string, unknown>\n initialWidth: number\n initialHeight: number\n}) => {\n // Settings need an initialized display, and writing them mid-render is\n // unsafe — apply after the window mounts.\n useLayoutEffect(() => {\n forceEnableAnimations()\n }, [])\n\n // The Root is the window's direct child: RnGtkxLayout reports a zero\n // minimum (the window shrinks freely — no ratchet) and adopts the actual\n // content-area allocation as the layout viewport. No scrollable wrapper\n // means a window can never scroll its own root — RN semantics, scrolling\n // stays opt-in via <ScrollView>.\n return (\n <Root\n width={initialWidth}\n height={initialHeight}\n followAllocation\n >\n <App {...initialProps} />\n </Root>\n )\n}\n\nexport const AppRegistry = {\n registerComponent(appKey: string, provider: ComponentProvider): string {\n registry.set(appKey, provider)\n return appKey\n },\n\n getAppKeys(): string[] {\n return [...registry.keys()]\n },\n\n runApplication(appKey: string, params: RunApplicationParams = {}): void {\n const provider = registry.get(appKey)\n if (!provider) {\n throw new Error(\n `AppRegistry: no component registered for \"${appKey}\". ` +\n `Registered: ${[...registry.keys()].join(\", \") || \"(none)\"}`,\n )\n }\n const App = provider()\n const width = params.width ?? 800\n const height = params.height ?? 600\n\n const contentChrome = params.chrome === \"content\"\n activeChrome = contentChrome ? \"content\" : \"system\"\n const Window = contentChrome ? AdwApplicationWindow : GtkApplicationWindow\n const AppWindow = () => (\n <Window\n title={params.title ?? appKey}\n defaultWidth={width}\n defaultHeight={height}\n onCloseRequest={quit}\n >\n {contentChrome ? (\n <ContentChrome\n App={App}\n initialProps={params.initialProps ?? {}}\n />\n ) : (\n <WindowContent\n App={App}\n initialProps={params.initialProps ?? {}}\n initialWidth={width}\n initialHeight={height}\n />\n )}\n </Window>\n )\n\n createRoot().render(\n <GtkApplication>\n <AppWindow />\n </GtkApplication>,\n )\n },\n}\n"]}
|
|
@@ -23,6 +23,8 @@ export type FlatListProps<T> = Omit<ScrollViewProps, "children"> & {
|
|
|
23
23
|
getItemLayout?: (data: readonly T[], index: number) => ItemLayout;
|
|
24
24
|
windowSize?: number;
|
|
25
25
|
initialNumToRender?: number;
|
|
26
|
+
maxToRenderPerBatch?: number;
|
|
27
|
+
updateCellsBatchingPeriod?: number;
|
|
26
28
|
extraData?: unknown;
|
|
27
29
|
inverted?: boolean;
|
|
28
30
|
refreshing?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flat-list.js","sourceRoot":"","sources":["../../src/components/flat-list.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAyC,MAAM,OAAO,CAAA;AAGzE,OAAO,EACL,eAAe,GAMhB,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"flat-list.js","sourceRoot":"","sources":["../../src/components/flat-list.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAyC,MAAM,OAAO,CAAA;AAGzE,OAAO,EACL,eAAe,GAMhB,MAAM,oBAAoB,CAAA;AAuC3B,6EAA6E;AAC7E,mEAAmE;AACnE,MAAM,aAAa,GAAG,UAAU,CAC9B,CAAK,KAAuB,EAAE,GAAqC,EAAE,EAAE,CAAC,CACtE,KAAC,eAAe,OACV,KAAK,EACT,GAAG,EAAE,GAAG,GACR,CACH,CACF,CAAA;AACD,aAAa,CAAC,WAAW,GAAG,UAAU,CAAA;AAEtC,MAAM,CAAC,MAAM,QAAQ,GAAG,aAEP,CAAA;AA+BjB,MAAM,CAAC,MAAM,WAAW,GAAG,CAAK,EAC9B,QAAQ,EACR,UAAU,EACV,mBAAmB,EACnB,2BAA2B,GAAG,IAAI,EAClC,GAAG,EACH,GAAG,IAAI,EACa,EAAgB,EAAE;IACtC,MAAM,IAAI,GAAoB,EAAE,CAAA;IAChC,MAAM,aAAa,GAAa,EAAE,CAAA;IAClC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QACtC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACnC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,CACL,KAAC,QAAQ,OACH,IAAI,EACR,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,IAAI,EACV,mBAAmB,EACjB,2BAA2B,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,EAEzD,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAC5C,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAC5B,GAAG,CAAC,IAAI,KAAK,QAAQ;YACnB,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,IAAI,CAAC;YAC3D,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,GAEtD,CACH,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { forwardRef, type ComponentType, type ReactElement } from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport type { ScrollViewProps } from \"./scroll-view\"\nimport {\n VirtualizedList,\n type ItemLayout,\n type ListRenderItemInfo,\n type ViewabilityConfig,\n type ViewToken,\n type VirtualizedListHandle,\n} from \"./virtualized-list\"\n\nexport type {\n ListRenderItemInfo,\n ViewabilityConfig,\n ViewToken,\n} from \"./virtualized-list\"\n// The FlatList ref exposes the full scroll surface of the windowed core\n// (scrollTo, scrollToEnd, scrollToIndex, scrollToItem, scrollToOffset).\nexport type { VirtualizedListHandle as FlatListHandle } from \"./virtualized-list\"\n\nexport type FlatListProps<T> = Omit<ScrollViewProps, \"children\"> & {\n data: readonly T[]\n renderItem: (info: ListRenderItemInfo<T>) => ReactElement | null\n keyExtractor?: (item: T, index: number) => string\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 estimatedItemSize?: number\n getItemLayout?: (data: readonly T[], index: number) => ItemLayout\n windowSize?: number\n initialNumToRender?: number\n maxToRenderPerBatch?: number\n updateCellsBatchingPeriod?: number\n extraData?: unknown\n inverted?: boolean\n refreshing?: boolean\n onRefresh?: () => void\n style?: StyleProp\n}\n\n// FlatList is a thin veneer over the windowed VirtualizedList core: only the\n// rows around the viewport are mounted (see virtualized-list.tsx).\nconst FlatListInner = forwardRef(\n <T,>(props: FlatListProps<T>, ref: React.Ref<VirtualizedListHandle>) => (\n <VirtualizedList\n {...props}\n ref={ref}\n />\n ),\n)\nFlatListInner.displayName = \"FlatList\"\n\nexport const FlatList = FlatListInner as <T>(\n props: FlatListProps<T> & { ref?: React.Ref<VirtualizedListHandle> },\n) => ReactElement\n\nexport type SectionListData<T> = { title: string; data: readonly T[] }\n\n// Viewability props are excluded: SectionList flattens sections into private\n// row records, so ViewTokens would leak that internal row type instead of T —\n// section-aware tokens are not implemented yet.\nexport type SectionListProps<T> = Omit<\n FlatListProps<T>,\n | \"data\"\n | \"renderItem\"\n | \"getItemLayout\"\n | \"onViewableItemsChanged\"\n | \"viewabilityConfig\"\n> & {\n sections: readonly SectionListData<T>[]\n renderItem: (info: ListRenderItemInfo<T>) => ReactElement | null\n renderSectionHeader?: (info: {\n section: SectionListData<T>\n }) => ReactElement | null\n // RN default on iOS; ours defaults to true too — section headers pin to\n // the top and get pushed out by the next section's header.\n stickySectionHeadersEnabled?: boolean\n // React 19 ref-as-prop: the same scroll surface FlatList exposes.\n ref?: React.Ref<VirtualizedListHandle>\n}\n\ntype SectionRow<T> =\n | { kind: \"header\"; section: SectionListData<T> }\n | { kind: \"item\"; item: T; index: number }\n\nexport const SectionList = <T,>({\n sections,\n renderItem,\n renderSectionHeader,\n stickySectionHeadersEnabled = true,\n ref,\n ...rest\n}: SectionListProps<T>): ReactElement => {\n const rows: SectionRow<T>[] = []\n const headerIndices: number[] = []\n for (const section of sections) {\n headerIndices.push(rows.length)\n rows.push({ kind: \"header\", section })\n section.data.forEach((item, index) => {\n rows.push({ kind: \"item\", item, index })\n })\n }\n return (\n <FlatList\n {...rest}\n ref={ref}\n data={rows}\n stickyHeaderIndices={\n stickySectionHeadersEnabled ? headerIndices : undefined\n }\n keyExtractor={(_row, index) => String(index)}\n renderItem={({ item: row }) =>\n row.kind === \"header\"\n ? (renderSectionHeader?.({ section: row.section }) ?? null)\n : renderItem({ item: row.item, index: row.index })\n }\n />\n )\n}\n"]}
|
|
@@ -5,7 +5,7 @@ export { FlatList, SectionList, type FlatListProps, type ListRenderItemInfo, typ
|
|
|
5
5
|
export { Image, type ImageProps, type ImageSource } from "./image";
|
|
6
6
|
export { Modal, type ModalProps } from "./modal";
|
|
7
7
|
export { Pressable, TouchableOpacity, type PressableProps, type PressableStateCallbackType, type PressEvent, type TouchableOpacityProps, } from "./pressable";
|
|
8
|
-
export { Root, type RootProps } from "./root";
|
|
8
|
+
export { IntrinsicRoot, NestedRoot, Root, type IntrinsicRootProps, type NestedRootProps, type RootProps, } from "./root";
|
|
9
9
|
export { ScrollView, type ScrollEvent, type ScrollViewHandle, type ScrollViewProps, } from "./scroll-view";
|
|
10
10
|
export { Switch, type SwitchProps } from "./switch";
|
|
11
11
|
export { Text, type TextProps } from "./text";
|
package/dist/components/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { FlatList, SectionList, } from "./flat-list";
|
|
|
5
5
|
export { Image } from "./image";
|
|
6
6
|
export { Modal } from "./modal";
|
|
7
7
|
export { Pressable, TouchableOpacity, } from "./pressable";
|
|
8
|
-
export { Root } from "./root";
|
|
8
|
+
export { IntrinsicRoot, NestedRoot, Root, } from "./root";
|
|
9
9
|
export { ScrollView, } from "./scroll-view";
|
|
10
10
|
export { Switch } from "./switch";
|
|
11
11
|
export { Text } from "./text";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,QAAQ,EACR,MAAM,GAGP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAA;AACvE,OAAO,EACL,QAAQ,EACR,WAAW,GAOZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,KAAK,EAAqC,MAAM,SAAS,CAAA;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,SAAS,CAAA;AAChD,OAAO,EACL,SAAS,EACT,gBAAgB,GAKjB,MAAM,aAAa,CAAA;AACpB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,QAAQ,EACR,MAAM,GAGP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAA;AACvE,OAAO,EACL,QAAQ,EACR,WAAW,GAOZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,KAAK,EAAqC,MAAM,SAAS,CAAA;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,SAAS,CAAA;AAChD,OAAO,EACL,SAAS,EACT,gBAAgB,GAKjB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,aAAa,EACb,UAAU,EACV,IAAI,GAIL,MAAM,QAAQ,CAAA;AACf,OAAO,EACL,UAAU,GAIX,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAuB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA","sourcesContent":["export {\n ActivityIndicator,\n type ActivityIndicatorProps,\n} from \"./activity-indicator\"\nexport {\n Animated,\n Easing,\n type AnimatedViewProps,\n type AnimatedViewStyle,\n} from \"./animated\"\nexport { AppRegistry, type RunApplicationParams } from \"./app-registry\"\nexport {\n FlatList,\n SectionList,\n type FlatListProps,\n type ListRenderItemInfo,\n type SectionListData,\n type SectionListProps,\n type ViewabilityConfig,\n type ViewToken,\n} from \"./flat-list\"\nexport { Image, type ImageProps, type ImageSource } from \"./image\"\nexport { Modal, type ModalProps } from \"./modal\"\nexport {\n Pressable,\n TouchableOpacity,\n type PressableProps,\n type PressableStateCallbackType,\n type PressEvent,\n type TouchableOpacityProps,\n} from \"./pressable\"\nexport {\n IntrinsicRoot,\n NestedRoot,\n Root,\n type IntrinsicRootProps,\n type NestedRootProps,\n type RootProps,\n} from \"./root\"\nexport {\n ScrollView,\n type ScrollEvent,\n type ScrollViewHandle,\n type ScrollViewProps,\n} from \"./scroll-view\"\nexport { Switch, type SwitchProps } from \"./switch\"\nexport { Text, type TextProps } from \"./text\"\nexport { TextInput, type TextInputProps } from \"./text-input\"\nexport { SafeAreaView, StatusBar, View, type ViewProps } from \"./view\"\nexport { type LayoutEvent } from \"./use-layout-child\"\n"]}
|
|
@@ -9,4 +9,4 @@ export type ModalProps = {
|
|
|
9
9
|
height?: number;
|
|
10
10
|
children?: ReactNode;
|
|
11
11
|
};
|
|
12
|
-
export declare const Modal: ({ visible, onRequestClose, title, width, height, children, }: ModalProps) =>
|
|
12
|
+
export declare const Modal: ({ visible, onRequestClose, title, width, height, children, }: ModalProps) => ReactNode;
|
|
@@ -3,6 +3,15 @@ export type RootProps = {
|
|
|
3
3
|
width: number;
|
|
4
4
|
height: number;
|
|
5
5
|
followAllocation?: boolean;
|
|
6
|
+
expand?: boolean;
|
|
6
7
|
children?: ReactNode;
|
|
7
8
|
};
|
|
8
|
-
export declare const Root: ({ width, height, followAllocation, children, }: RootProps) => React.JSX.Element;
|
|
9
|
+
export declare const Root: ({ width, height, followAllocation, expand, children, }: RootProps) => React.JSX.Element;
|
|
10
|
+
export type NestedRootProps = {
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
export declare const NestedRoot: ({ children }: NestedRootProps) => React.JSX.Element;
|
|
14
|
+
export type IntrinsicRootProps = {
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
};
|
|
17
|
+
export declare const IntrinsicRoot: ({ children }: IntrinsicRootProps) => React.JSX.Element;
|
package/dist/components/root.js
CHANGED
|
@@ -9,7 +9,7 @@ import { useRnContainer } from "./use-layout-child";
|
|
|
9
9
|
// reports the engine viewport as its measure (via RnGtkxLayout) and is sized
|
|
10
10
|
// by its parent (window/harness); the owner keeps the engine viewport in sync
|
|
11
11
|
// (AppRegistry does it from window-size changes).
|
|
12
|
-
export const Root = ({ width, height, followAllocation = false, children, }) => {
|
|
12
|
+
export const Root = ({ width, height, followAllocation = false, expand = false, children, }) => {
|
|
13
13
|
const widgetRef = useRef(null);
|
|
14
14
|
// useState lazy init — see the note in use-layout-child.ts (React Compiler).
|
|
15
15
|
const [engine] = useState(() => new LayoutEngine({ width, height }));
|
|
@@ -54,6 +54,44 @@ export const Root = ({ width, height, followAllocation = false, children, }) =>
|
|
|
54
54
|
},
|
|
55
55
|
}
|
|
56
56
|
: undefined);
|
|
57
|
+
return (_jsx(GtkBox, { ref: widgetRef, hexpand: expand, vexpand: expand, children: _jsx(HostNodeContext.Provider, { value: host, children: children }) }));
|
|
58
|
+
};
|
|
59
|
+
// Nested layout root: a full Yoga engine mounted inside ANY GTK container
|
|
60
|
+
// slot — an Adw.NavigationPage, a toolbar view content area, a future
|
|
61
|
+
// gtk-components container. The slot's allocation is the layout viewport
|
|
62
|
+
// (viewport-following; the initial 0×0 viewport is replaced synchronously
|
|
63
|
+
// inside the first allocation pass, so nothing paints at zero). Attach is
|
|
64
|
+
// the JSX mount; detach is the unmount — the engine is disposed with it.
|
|
65
|
+
// Allocate passes of sibling/nested roots may overlap: the rect-store
|
|
66
|
+
// tracks pass depth, so deferred GTK queue jobs run only after the
|
|
67
|
+
// outermost pass ends.
|
|
68
|
+
export const NestedRoot = ({ children }) => (_jsx(Root, { width: 0, height: 0, followAllocation: true, expand: true, children: children }));
|
|
69
|
+
// Content-sized layout root: unlike NestedRoot (which fills a slot), the
|
|
70
|
+
// intrinsic root REPORTS its Yoga-computed content size to GTK — this is
|
|
71
|
+
// what lets RN content live in size-to-content chrome slots (HeaderBar
|
|
72
|
+
// start/end, sidebar rows). Measure runs a speculative uncommitted Yoga
|
|
73
|
+
// pass (height honors the width constraint); the allocation pass then
|
|
74
|
+
// recomputes at the real size and commits.
|
|
75
|
+
export const IntrinsicRoot = ({ children }) => {
|
|
76
|
+
const widgetRef = useRef(null);
|
|
77
|
+
const [engine] = useState(() => new LayoutEngine({ width: 0, height: 0 }));
|
|
78
|
+
useEffect(() => () => {
|
|
79
|
+
engine.dispose();
|
|
80
|
+
}, [engine]);
|
|
81
|
+
const host = useMemo(() => ({ engine, node: engine.root, widgetRef }), [engine]);
|
|
82
|
+
useRnContainer(widgetRef, engine.root, {
|
|
83
|
+
measure: (orientation, forSize) => engine.measureContent(orientation, forSize),
|
|
84
|
+
beforeAllocate: (allocatedWidth, allocatedHeight) => {
|
|
85
|
+
beginAllocatePass();
|
|
86
|
+
try {
|
|
87
|
+
engine.setViewport({ width: allocatedWidth, height: allocatedHeight });
|
|
88
|
+
engine.flushSync();
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
endAllocatePass();
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
});
|
|
57
95
|
return (_jsx(GtkBox, { ref: widgetRef, children: _jsx(HostNodeContext.Provider, { value: host, children: children }) }));
|
|
58
96
|
};
|
|
59
97
|
//# sourceMappingURL=root.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/components/root.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,SAAS,EACT,eAAe,EACf,OAAO,EACP,MAAM,EACN,QAAQ,GAET,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAY,MAAM,sBAAsB,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/components/root.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { LayoutEngine } from \"../layout/index\"\nimport { GtkBox, queueResize, type Gtk } from \"../gtkx/bridge/index\"\nimport { HostNodeContext } from \"./host-node\"\nimport { beginAllocatePass, endAllocatePass } from \"./rect-store\"\nimport { useRnContainer } from \"./use-layout-child\"\n\nexport type RootProps = {\n width: number\n height: number\n // Window mode: report a zero minimum (the window may shrink freely) and\n // adopt whatever the window actually allocates as the engine viewport —\n // the allocation IS the layout viewport, headerbar excluded by GTK itself.\n followAllocation?: boolean\n // Claim the parent slot: a zero-minimum box inside a plain GTK container\n // gets no space unless it expands (window children fill implicitly, other\n // containers honor the expand flags).\n expand?: boolean\n children?: ReactNode\n}\n\n// Layout root: one engine per window (or per test harness). The root GtkBox\n// reports the engine viewport as its measure (via RnGtkxLayout) and is sized\n// by its parent (window/harness); the owner keeps the engine viewport in sync\n// (AppRegistry does it from window-size changes).\nexport const Root = ({\n width,\n height,\n followAllocation = false,\n expand = false,\n children,\n}: RootProps) => {\n const widgetRef = useRef<Gtk.Box | null>(null)\n\n // useState lazy init — see the note in use-layout-child.ts (React Compiler).\n const [engine] = useState<LayoutEngine>(\n () => new LayoutEngine({ width, height }),\n )\n\n useLayoutEffect(() => {\n if (followAllocation) {\n return\n }\n engine.setViewport({ width, height })\n // The viewport is this widget's measure — invalidate the cached one.\n const widget = widgetRef.current\n if (widget) {\n queueResize(widget)\n }\n }, [engine, followAllocation, width, height])\n\n useEffect(\n () => () => {\n engine.dispose()\n },\n [engine],\n )\n\n const host = useMemo(\n () => ({ engine, node: engine.root, widgetRef }),\n [engine],\n )\n\n useRnContainer(\n widgetRef,\n engine.root,\n followAllocation\n ? {\n measure: () => 0,\n beforeAllocate: (allocatedWidth, allocatedHeight) => {\n const current = engine.root.getRect()\n if (\n current &&\n current.width === allocatedWidth &&\n current.height === allocatedHeight\n ) {\n return\n }\n // Synchronous reflow inside the allocation pass: commits fill the\n // rect store now; their GTK queue calls are deferred past the pass.\n beginAllocatePass()\n try {\n engine.setViewport({\n width: allocatedWidth,\n height: allocatedHeight,\n })\n engine.flushSync()\n } finally {\n endAllocatePass()\n }\n },\n }\n : undefined,\n )\n\n return (\n <GtkBox\n ref={widgetRef}\n hexpand={expand}\n vexpand={expand}\n >\n <HostNodeContext.Provider value={host}>\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\nexport type NestedRootProps = {\n children?: ReactNode\n}\n\n// Nested layout root: a full Yoga engine mounted inside ANY GTK container\n// slot — an Adw.NavigationPage, a toolbar view content area, a future\n// gtk-components container. The slot's allocation is the layout viewport\n// (viewport-following; the initial 0×0 viewport is replaced synchronously\n// inside the first allocation pass, so nothing paints at zero). Attach is\n// the JSX mount; detach is the unmount — the engine is disposed with it.\n// Allocate passes of sibling/nested roots may overlap: the rect-store\n// tracks pass depth, so deferred GTK queue jobs run only after the\n// outermost pass ends.\nexport const NestedRoot = ({ children }: NestedRootProps) => (\n <Root\n width={0}\n height={0}\n followAllocation\n expand\n >\n {children}\n </Root>\n)\n\nexport type IntrinsicRootProps = {\n children?: ReactNode\n}\n\n// Content-sized layout root: unlike NestedRoot (which fills a slot), the\n// intrinsic root REPORTS its Yoga-computed content size to GTK — this is\n// what lets RN content live in size-to-content chrome slots (HeaderBar\n// start/end, sidebar rows). Measure runs a speculative uncommitted Yoga\n// pass (height honors the width constraint); the allocation pass then\n// recomputes at the real size and commits.\nexport const IntrinsicRoot = ({ children }: IntrinsicRootProps) => {\n const widgetRef = useRef<Gtk.Box | null>(null)\n const [engine] = useState<LayoutEngine>(\n () => new LayoutEngine({ width: 0, height: 0 }),\n )\n useEffect(\n () => () => {\n engine.dispose()\n },\n [engine],\n )\n const host = useMemo(\n () => ({ engine, node: engine.root, widgetRef }),\n [engine],\n )\n useRnContainer(widgetRef, engine.root, {\n measure: (orientation, forSize) =>\n engine.measureContent(orientation, forSize),\n beforeAllocate: (allocatedWidth, allocatedHeight) => {\n beginAllocatePass()\n try {\n engine.setViewport({ width: allocatedWidth, height: allocatedHeight })\n engine.flushSync()\n } finally {\n endAllocatePass()\n }\n },\n })\n return (\n <GtkBox ref={widgetRef}>\n <HostNodeContext.Provider value={host}>\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Children, createContext, forwardRef, useContext, useImperativeHandle, useLayoutEffect, useRef, useState, } from "react";
|
|
3
3
|
import { splitStyle, StyleSheet } from "../style/index";
|
|
4
4
|
import { Gtk, GtkBox, GtkScrolledWindow, queueAllocate, queueResize, useSignal, } from "../gtkx/bridge/index";
|
|
5
|
+
import { ensurePerfReporter, perfAddTime, perfCount, perfEnabled, perfFrameTick, perfNow, } from "../perf";
|
|
5
6
|
import { HostNodeContext } from "./host-node";
|
|
6
7
|
import { deferDuringAllocate, setStoredOffset } from "./rect-store";
|
|
7
8
|
import { useLayoutChild, useRnContainer, } from "./use-layout-child";
|
|
@@ -254,7 +255,17 @@ export const ScrollView = forwardRef(({ style, contentContainerStyle, horizontal
|
|
|
254
255
|
? (scrolled?.getHadjustment() ?? null)
|
|
255
256
|
: (scrolled?.getVadjustment() ?? null);
|
|
256
257
|
const onAdjustment = () => {
|
|
258
|
+
if (!perfEnabled) {
|
|
259
|
+
emitScroll();
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
// Perf: full wall time of one scroll tick's JS work — the FFI reads in
|
|
263
|
+
// emitScroll plus the app/VirtualizedList onScroll handler (windowing,
|
|
264
|
+
// viewability, endReached) — everything that blocks the GTK frame.
|
|
265
|
+
perfCount("scroll.events");
|
|
266
|
+
const start = perfNow();
|
|
257
267
|
emitScroll();
|
|
268
|
+
perfAddTime("scroll.js", perfNow() - start);
|
|
258
269
|
};
|
|
259
270
|
// Content-size reports dedupe on the engine rect: "changed" also fires
|
|
260
271
|
// for pure viewport (page-size) changes, which RN does not report.
|
|
@@ -288,12 +299,32 @@ export const ScrollView = forwardRef(({ style, contentContainerStyle, horizontal
|
|
|
288
299
|
if (!widget) {
|
|
289
300
|
return;
|
|
290
301
|
}
|
|
302
|
+
const vadjustment = widget.getVadjustment();
|
|
303
|
+
let lastValue = vadjustment?.getValue() ?? 0;
|
|
304
|
+
// Frames to keep requeueing after the last observed move. The scrolled
|
|
305
|
+
// window's own kinetic tick may run AFTER ours, so this tick's read can
|
|
306
|
+
// be one frame stale: without the grace window the first frame of a
|
|
307
|
+
// deceleration (its value change lands after our read) would miss its
|
|
308
|
+
// correction. Kinetic deceleration changes the value every frame, so
|
|
309
|
+
// three frames of slack cover the handoff at both ends of the motion.
|
|
310
|
+
const graceFrames = 3;
|
|
311
|
+
let remaining = graceFrames;
|
|
291
312
|
const id = widget.addTickCallback(() => {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
313
|
+
perfCount("sticky.ticks");
|
|
314
|
+
const value = vadjustment?.getValue() ?? 0;
|
|
315
|
+
if (value !== lastValue) {
|
|
316
|
+
lastValue = value;
|
|
317
|
+
remaining = graceFrames;
|
|
318
|
+
}
|
|
319
|
+
else if (remaining > 0) {
|
|
320
|
+
remaining -= 1;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// At rest: the pin is already correct and nothing translated it,
|
|
324
|
+
// so an allocation pass per frame would be pure idle cost.
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
perfCount("sticky.queues");
|
|
297
328
|
const content = contentRef.current;
|
|
298
329
|
if (content) {
|
|
299
330
|
queueAllocate(content);
|
|
@@ -304,6 +335,28 @@ export const ScrollView = forwardRef(({ style, contentContainerStyle, horizontal
|
|
|
304
335
|
widget.removeTickCallback(id);
|
|
305
336
|
};
|
|
306
337
|
}, [scrolled, hasSticky, horizontal]);
|
|
338
|
+
// Perf: observe the GTK frame clock through a tick callback — the delta
|
|
339
|
+
// between consecutive ticks is the real frame interval (late frames show
|
|
340
|
+
// up directly). Note: registering a tick callback keeps the frame clock
|
|
341
|
+
// running, so idle seconds show ~60 ticks too; the reporter separates
|
|
342
|
+
// load by the accompanying counters.
|
|
343
|
+
useLayoutEffect(() => {
|
|
344
|
+
if (!perfEnabled) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
ensurePerfReporter();
|
|
348
|
+
const widget = scrolled;
|
|
349
|
+
if (!widget) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const id = widget.addTickCallback(() => {
|
|
353
|
+
perfFrameTick(perfNow());
|
|
354
|
+
return true;
|
|
355
|
+
});
|
|
356
|
+
return () => {
|
|
357
|
+
widget.removeTickCallback(id);
|
|
358
|
+
};
|
|
359
|
+
}, [scrolled]);
|
|
307
360
|
useSignal(adjustment, "value-changed", onAdjustment);
|
|
308
361
|
// Both axes report into the same handler — RN's callback carries both
|
|
309
362
|
// dimensions no matter which one moved.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../../src/components/scroll-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Children,\n createContext,\n forwardRef,\n useContext,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkBox,\n GtkScrolledWindow,\n queueAllocate,\n queueResize,\n useSignal,\n} from \"../gtkx/bridge/index\"\nimport { HostNodeContext } from \"./host-node\"\nimport { deferDuringAllocate, setStoredOffset } from \"./rect-store\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\nexport type ScrollViewHandle = {\n scrollTo(options: { x?: number; y?: number; animated?: boolean }): void\n scrollToEnd(options?: { animated?: boolean }): void\n}\n\nexport type ScrollEvent = {\n nativeEvent: {\n contentOffset: { x: number; y: number }\n contentSize: { width: number; height: number }\n }\n}\n\nexport type ScrollViewProps = {\n style?: StyleProp\n contentContainerStyle?: StyleProp\n horizontal?: boolean\n // RN sticky headers (vertical lists): the children at these indices pin to\n // the top while scrolled past, each pushed out by the next one.\n stickyHeaderIndices?: readonly number[]\n onScroll?: (event: ScrollEvent) => void\n // RN onContentSizeChange(contentWidth, contentHeight): fires when the\n // scrollable content changes size. GTK's adjustments emit \"changed\" right\n // after the allocation that resized their range — exactly the moment the\n // new scroll extent is real, which windowed lists rely on to reposition.\n onContentSizeChange?: (width: number, height: number) => void\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n testID?: string\n}\n\ntype StickyRecord = { y: number; height: number; widget: Gtk.Widget }\n\n// The sticky registry lives on the nearest ScrollView: any descendant may\n// register a slot with its content-relative geometry (measured children of\n// the ScrollView itself, or windowed list cells with engine-known offsets).\nexport type StickyRegistry = {\n register(key: string, record: StickyRecord): void\n unregister(key: string): void\n}\n\nexport const StickyRegistryContext = createContext<StickyRegistry | null>(null)\n\n// A wrapper around a sticky child: a plain container that reports its layout\n// and widget into the registry, so the scroll handler can translate/reorder\n// the REAL instance (RN semantics — no duplicate is ever rendered, external\n// margins travel with the header exactly as designed). An explicit `top`\n// (windowed cells) overrides the measured position.\nexport const StickySlot = ({\n stickyKey,\n style,\n top,\n onLayout,\n children,\n}: {\n stickyKey: string\n style?: StyleProp\n top?: number\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n}) => {\n const registry = useContext(StickyRegistryContext)\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { host, node } = useLayoutChild(widgetRef, {\n style,\n onLayout: (event) => {\n onLayout?.(event)\n const widget = widgetRef.current\n if (registry && widget) {\n registry.register(stickyKey, {\n y: top ?? event.nativeEvent.layout.y,\n height: event.nativeEvent.layout.height,\n widget,\n })\n }\n },\n })\n useRnContainer(widgetRef, node)\n useLayoutEffect(() => {\n return () => {\n registry?.unregister(stickyKey)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stickyKey])\n return (\n <GtkBox ref={widgetRef}>\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\n// GtkScrolledWindow whose child is a content GtkBox backed by its own Yoga\n// node inside the same engine: the content's RnGtkxLayout measures the engine\n// content size (which grows past the viewport — that IS the scroll range;\n// overflow: scroll on the outer node) and the scrolled window pans it.\nexport const ScrollView = forwardRef<ScrollViewHandle, ScrollViewProps>(\n (\n {\n style,\n contentContainerStyle,\n horizontal = false,\n stickyHeaderIndices,\n onScroll,\n onContentSizeChange,\n onLayout,\n children,\n testID,\n },\n handleRef,\n ) => {\n const outerRef = useRef<Gtk.ScrolledWindow | null>(null)\n const contentRef = useRef<Gtk.Box | null>(null)\n const [scrolled, setScrolled] = useState<Gtk.ScrolledWindow | null>(null)\n\n const { host, node: outerNode } = useLayoutChild(outerRef, {\n // Yoga unconstrains a scroll node's MAIN axis — align it with the\n // scroll direction or a horizontal list's content clamps to the\n // viewport width (hadjustment upper == page).\n style: [\n style,\n { overflow: \"scroll\", flexDirection: horizontal ? \"row\" : \"column\" },\n ],\n onLayout,\n })\n\n const [contentNode] = useState(() => host.engine.createNode())\n // Sticky positions are computed INSIDE the same allocation pass that\n // places the children (beforeAllocate): the viewport has already settled\n // on this frame's scroll offset, so the pinned header lands exactly —\n // reacting to the adjustment signal instead lags a frame and jitters.\n useRnContainer(contentRef, contentNode, {\n beforeAllocate: () => {\n if (stickyRecords.current.size > 0) {\n updateSticky(outerRef.current?.getVadjustment()?.getValue() ?? 0)\n }\n },\n })\n\n // RN semantics: a ScrollView CLIPS its content. Branch B made containers\n // paint-overflow by default, so without this the scrolled-away content\n // (e.g. the original of a pinned sticky header) keeps drawing past the\n // scroll area's edges.\n useLayoutEffect(() => {\n outerRef.current?.setOverflow(Gtk.Overflow.HIDDEN)\n }, [])\n\n useLayoutEffect(() => {\n outerNode.insertChild(contentNode, 0)\n contentNode.setCommit(() => {\n // The content size IS this widget's measure (scroll range) — the\n // ScrolledWindow itself allocates the content widget.\n const widget = contentRef.current\n if (!widget) {\n return\n }\n const queue = (): void => {\n queueResize(widget)\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n contentNode.setCommit(null)\n outerNode.removeChild(contentNode)\n contentNode.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const contentLayout = splitStyle(\n StyleSheet.flatten(contentContainerStyle),\n ).layout\n const contentKey = JSON.stringify({ horizontal, contentLayout })\n useLayoutEffect(() => {\n contentNode.setStyle({\n flexDirection: horizontal ? \"row\" : \"column\",\n alignItems: \"flex-start\",\n ...contentLayout,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [contentNode, contentKey])\n\n useImperativeHandle(handleRef, () => ({\n scrollTo({ x, y }) {\n const widget = outerRef.current\n if (!widget) {\n return\n }\n if (y !== undefined) {\n widget.getVadjustment()?.setValue(y)\n }\n if (x !== undefined) {\n widget.getHadjustment()?.setValue(x)\n }\n },\n scrollToEnd() {\n const widget = outerRef.current\n const adjustment = horizontal\n ? widget?.getHadjustment()\n : widget?.getVadjustment()\n if (adjustment) {\n adjustment.setValue(adjustment.getUpper() - adjustment.getPageSize())\n }\n },\n }))\n\n // --- sticky headers -------------------------------------------------\n // The RN model, faithfully: the REAL child is translated (no duplicate,\n // state preserved). RN gives the pinned cell a zIndex; GTK's z-order is\n // sibling paint order, so the active slot is reordered to be the LAST\n // content child while pinned and restored afterwards. Per-frame movement\n // goes through the rect-store offset fast path — zero React work while\n // scrolling.\n const stickySet = stickyHeaderIndices ?? []\n const stickyRecords = useRef(new Map<string, StickyRecord>())\n const restoreSibling = useRef(new Map<string, Gtk.Widget | null>())\n const activeStickyRef = useRef<string | null>(null)\n const [hasSticky, setHasSticky] = useState(false)\n\n const stickyRegistry = useRef<StickyRegistry>({\n register: (key, record) => {\n stickyRecords.current.set(key, record)\n setHasSticky(true)\n const parent = record.widget.getParent()\n if (parent) {\n queueAllocate(parent)\n }\n },\n unregister: (key) => {\n stickyRecords.current.delete(key)\n restoreSibling.current.delete(key)\n if (activeStickyRef.current === key) {\n activeStickyRef.current = null\n }\n if (stickyRecords.current.size === 0) {\n setHasSticky(false)\n }\n },\n })\n\n const updateSticky = (rawScrollTop: number): void => {\n if (stickyRecords.current.size === 0) {\n return\n }\n // The viewport translates the content by the FRACTIONAL adjustment\n // value while widget allocations are integer — an unquantized pin\n // disagrees with the translation by ±1px and shimmers every frame.\n // Frame telemetry (docs/research/sticky-probe.md) proved the viewport quantizes\n // like floor: with Math.floor the header's window-relative position is\n // a flat 0.00 across every frame; round oscillates 0/1, ceil sits at 1.\n const scrollTop = Math.floor(rawScrollTop)\n let active: string | null = null\n let next: StickyRecord | null = null\n for (const [key, record] of stickyRecords.current) {\n if (record.y <= scrollTop) {\n if (\n active === null ||\n record.y >= stickyRecords.current.get(active)!.y\n ) {\n active = key\n }\n } else if (next === null || record.y < next.y) {\n next = record\n }\n }\n\n const previous = activeStickyRef.current\n if (previous !== active) {\n activeStickyRef.current = active\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n if (record) {\n setStoredOffset(record.widget, 0, 0)\n }\n }\n // Reordering widgets queues GTK work — not allowed mid-allocation.\n // The z-switch lands a frame later; the POSITION is already exact.\n setTimeout(() => {\n applyStickyReorder(previous, active)\n }, 0)\n }\n\n if (active !== null) {\n const record = stickyRecords.current.get(active)!\n // Pin at the viewport top; the next sticky header pushes it out.\n const pinned = next\n ? Math.min(scrollTop, next.y - record.height)\n : scrollTop\n setStoredOffset(record.widget, 0, Math.max(0, pinned - record.y))\n }\n }\n\n const applyStickyReorder = (\n previous: string | null,\n active: string | null,\n ): void => {\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n // Slot parents are always our GtkBox containers.\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n // Put the slot back where the reconciler expects it.\n parent.reorderChildAfter(\n record.widget,\n restoreSibling.current.get(previous) ?? null,\n )\n queueAllocate(parent)\n }\n }\n if (active !== null) {\n const record = stickyRecords.current.get(active)\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n restoreSibling.current.set(active, record.widget.getPrevSibling())\n parent.reorderChildAfter(record.widget, parent.getLastChild())\n queueAllocate(parent)\n }\n }\n }\n\n const emitScroll = (): void => {\n if (!onScroll) {\n return\n }\n const widget = outerRef.current\n const contentRect = contentNode.getRect()\n if (!widget || !contentRect) {\n return\n }\n onScroll({\n nativeEvent: {\n contentOffset: {\n x: widget.getHadjustment()?.getValue() ?? 0,\n y: widget.getVadjustment()?.getValue() ?? 0,\n },\n contentSize: { width: contentRect.width, height: contentRect.height },\n },\n })\n }\n\n const adjustment = horizontal\n ? (scrolled?.getHadjustment() ?? null)\n : (scrolled?.getVadjustment() ?? null)\n const onAdjustment = (): void => {\n emitScroll()\n }\n\n // Content-size reports dedupe on the engine rect: \"changed\" also fires\n // for pure viewport (page-size) changes, which RN does not report.\n const lastContentSize = useRef({ width: -1, height: -1 })\n const onRangeChanged = (): void => {\n if (!onContentSizeChange) {\n return\n }\n const rect = contentNode.getRect()\n if (!rect) {\n return\n }\n const last = lastContentSize.current\n if (rect.width === last.width && rect.height === last.height) {\n return\n }\n lastContentSize.current = { width: rect.width, height: rect.height }\n onContentSizeChange(rect.width, rect.height)\n }\n\n // Frame-synced sticky driver: a pure scroll TRANSLATES the content\n // without re-allocating it (same size → GTK skips the vfunc), so signal\n // handlers land a frame late and the pinned header jitters. A tick\n // callback runs in the frame's UPDATE phase, before layout: when the\n // scroll offset moved, queue an allocation for THIS frame — the\n // translation and the pin correction then paint atomically.\n useLayoutEffect(() => {\n if (!hasSticky || horizontal) {\n return\n }\n const widget = scrolled\n if (!widget) {\n return\n }\n const id = widget.addTickCallback(() => {\n // Unconditionally, every frame: the scrolled window's own kinetic\n // tick may run AFTER ours, so comparing values here can miss the\n // frame's final offset. The allocation itself reads the adjustment\n // in the LAYOUT phase — always after every update-phase mutation —\n // so queuing each frame guarantees a same-frame correction.\n const content = contentRef.current\n if (content) {\n queueAllocate(content)\n }\n return true\n })\n return () => {\n widget.removeTickCallback(id)\n }\n }, [scrolled, hasSticky, horizontal])\n useSignal(adjustment, \"value-changed\", onAdjustment)\n // Both axes report into the same handler — RN's callback carries both\n // dimensions no matter which one moved.\n useSignal(scrolled?.getVadjustment() ?? null, \"changed\", onRangeChanged)\n useSignal(scrolled?.getHadjustment() ?? null, \"changed\", onRangeChanged)\n\n return (\n <GtkScrolledWindow\n ref={(widget: Gtk.ScrolledWindow | null) => {\n outerRef.current = widget\n setScrolled(widget)\n }}\n name={testID}\n >\n <GtkBox ref={contentRef}>\n <HostNodeContext.Provider\n value={{\n engine: host.engine,\n node: contentNode,\n widgetRef: contentRef,\n }}\n >\n <StickyRegistryContext.Provider value={stickyRegistry.current}>\n {stickySet.length === 0\n ? children\n : Children.toArray(children).map((child, index) =>\n stickySet.includes(index) ? (\n <StickySlot\n key={`sticky-slot-${index}`}\n stickyKey={`index-${index}`}\n >\n {child}\n </StickySlot>\n ) : (\n child\n ),\n )}\n </StickyRegistryContext.Provider>\n </HostNodeContext.Provider>\n </GtkBox>\n </GtkScrolledWindow>\n )\n },\n)\nScrollView.displayName = \"ScrollView\"\n"]}
|
|
1
|
+
{"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../../src/components/scroll-view.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,QAAQ,EACR,aAAa,EACb,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,eAAe,EACf,MAAM,EACN,QAAQ,GAET,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEvD,OAAO,EACL,GAAG,EACH,MAAM,EACN,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,SAAS,GACV,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,WAAW,EACX,aAAa,EACb,OAAO,GACR,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnE,OAAO,EACL,cAAc,EACd,cAAc,GAEf,MAAM,oBAAoB,CAAA;AA0C3B,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAwB,IAAI,CAAC,CAAA;AAE/E,6EAA6E;AAC7E,4EAA4E;AAC5E,4EAA4E;AAC5E,yEAAyE;AACzE,oDAAoD;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,SAAS,EACT,KAAK,EACL,GAAG,EACH,QAAQ,EACR,QAAQ,GAOT,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC9C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE;QAC/C,KAAK;QACL,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAClB,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;YACjB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;YAChC,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;gBACvB,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE;oBAC3B,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBACpC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM;oBACvC,MAAM;iBACP,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CAAA;IACF,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAC/B,eAAe,CAAC,GAAG,EAAE;QACnB,OAAO,GAAG,EAAE;YACV,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;QACjC,CAAC,CAAA;QACD,uDAAuD;IACzD,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IACf,OAAO,CACL,KAAC,MAAM,IAAC,GAAG,EAAE,SAAS,YACpB,KAAC,eAAe,CAAC,QAAQ,IACvB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,YAE9C,QAAQ,GACgB,GACpB,CACV,CAAA;AACH,CAAC,CAAA;AAED,2EAA2E;AAC3E,8EAA8E;AAC9E,0EAA0E;AAC1E,uEAAuE;AACvE,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAClC,CACE,EACE,KAAK,EACL,qBAAqB,EACrB,UAAU,GAAG,KAAK,EAClB,mBAAmB,EACnB,QAAQ,EACR,mBAAmB,EACnB,QAAQ,EACR,QAAQ,EACR,MAAM,GACP,EACD,SAAS,EACT,EAAE;IACF,MAAM,QAAQ,GAAG,MAAM,CAA4B,IAAI,CAAC,CAAA;IACxD,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC/C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAA4B,IAAI,CAAC,CAAA;IAEzE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,cAAc,CAAC,QAAQ,EAAE;QACzD,kEAAkE;QAClE,gEAAgE;QAChE,8CAA8C;QAC9C,KAAK,EAAE;YACL,KAAK;YACL,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE;SACrE;QACD,QAAQ;KACT,CAAC,CAAA;IAEF,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;IAC9D,qEAAqE;IACrE,yEAAyE;IACzE,sEAAsE;IACtE,sEAAsE;IACtE,cAAc,CAAC,UAAU,EAAE,WAAW,EAAE;QACtC,cAAc,EAAE,GAAG,EAAE;YACnB,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACnC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;YACnE,CAAC;QACH,CAAC;KACF,CAAC,CAAA;IAEF,yEAAyE;IACzE,uEAAuE;IACvE,uEAAuE;IACvE,uBAAuB;IACvB,eAAe,CAAC,GAAG,EAAE;QACnB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACpD,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,eAAe,CAAC,GAAG,EAAE;QACnB,SAAS,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QACrC,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE;YACzB,iEAAiE;YACjE,sDAAsD;YACtD,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAA;YACjC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAM;YACR,CAAC;YACD,MAAM,KAAK,GAAG,GAAS,EAAE;gBACvB,WAAW,CAAC,MAAM,CAAC,CAAA;YACrB,CAAC,CAAA;YACD,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;gBACxC,KAAK,EAAE,CAAA;YACT,CAAC;QACH,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YAC3B,SAAS,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;YAClC,WAAW,CAAC,IAAI,EAAE,CAAA;QACpB,CAAC,CAAA;QACD,uDAAuD;IACzD,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,aAAa,GAAG,UAAU,CAC9B,UAAU,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAC1C,CAAC,MAAM,CAAA;IACR,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAA;IAChE,eAAe,CAAC,GAAG,EAAE;QACnB,WAAW,CAAC,QAAQ,CAAC;YACnB,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ;YAC5C,UAAU,EAAE,YAAY;YACxB,GAAG,aAAa;SACjB,CAAC,CAAA;QACF,uDAAuD;IACzD,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;IAE7B,mBAAmB,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;YACf,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAA;YAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAM;YACR,CAAC;YACD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBACpB,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;YACtC,CAAC;YACD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBACpB,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;QACD,WAAW;YACT,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAA;YAC/B,MAAM,UAAU,GAAG,UAAU;gBAC3B,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE;gBAC1B,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,CAAA;YAC5B,IAAI,UAAU,EAAE,CAAC;gBACf,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC,CAAA;YACvE,CAAC;QACH,CAAC;KACF,CAAC,CAAC,CAAA;IAEH,uEAAuE;IACvE,wEAAwE;IACxE,wEAAwE;IACxE,sEAAsE;IACtE,yEAAyE;IACzE,uEAAuE;IACvE,aAAa;IACb,MAAM,SAAS,GAAG,mBAAmB,IAAI,EAAE,CAAA;IAC3C,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,GAAG,EAAwB,CAAC,CAAA;IAC7D,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,GAAG,EAA6B,CAAC,CAAA;IACnE,MAAM,eAAe,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAA;IACnD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEjD,MAAM,cAAc,GAAG,MAAM,CAAiB;QAC5C,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YACxB,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACtC,YAAY,CAAC,IAAI,CAAC,CAAA;YAClB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,CAAA;YACxC,IAAI,MAAM,EAAE,CAAC;gBACX,aAAa,CAAC,MAAM,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;QACD,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE;YAClB,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACjC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAClC,IAAI,eAAe,CAAC,OAAO,KAAK,GAAG,EAAE,CAAC;gBACpC,eAAe,CAAC,OAAO,GAAG,IAAI,CAAA;YAChC,CAAC;YACD,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACrC,YAAY,CAAC,KAAK,CAAC,CAAA;YACrB,CAAC;QACH,CAAC;KACF,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,CAAC,YAAoB,EAAQ,EAAE;QAClD,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACrC,OAAM;QACR,CAAC;QACD,mEAAmE;QACnE,kEAAkE;QAClE,mEAAmE;QACnE,gFAAgF;QAChF,uEAAuE;QACvE,wEAAwE;QACxE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAC1C,IAAI,MAAM,GAAkB,IAAI,CAAA;QAChC,IAAI,IAAI,GAAwB,IAAI,CAAA;QACpC,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;YAClD,IAAI,MAAM,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,IACE,MAAM,KAAK,IAAI;oBACf,MAAM,CAAC,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,CAAC,EAChD,CAAC;oBACD,MAAM,GAAG,GAAG,CAAA;gBACd,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC9C,IAAI,GAAG,MAAM,CAAA;YACf,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAA;QACxC,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,eAAe,CAAC,OAAO,GAAG,MAAM,CAAA;YAChC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;gBAClD,IAAI,MAAM,EAAE,CAAC;oBACX,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;gBACtC,CAAC;YACH,CAAC;YACD,mEAAmE;YACnE,mEAAmE;YACnE,UAAU,CAAC,GAAG,EAAE;gBACd,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;YACtC,CAAC,EAAE,CAAC,CAAC,CAAA;QACP,CAAC;QAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;YACjD,iEAAiE;YACjE,MAAM,MAAM,GAAG,IAAI;gBACjB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC7C,CAAC,CAAC,SAAS,CAAA;YACb,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACnE,CAAC;IACH,CAAC,CAAA;IAED,MAAM,kBAAkB,GAAG,CACzB,QAAuB,EACvB,MAAqB,EACf,EAAE;QACR,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAClD,iDAAiD;YACjD,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,SAAS,EAAoB,CAAA;YAC3D,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;gBACrB,qDAAqD;gBACrD,MAAM,CAAC,iBAAiB,CACtB,MAAM,CAAC,MAAM,EACb,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAC7C,CAAA;gBACD,aAAa,CAAC,MAAM,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;QACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAChD,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,SAAS,EAAoB,CAAA;YAC3D,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;gBACrB,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAA;gBAClE,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;gBAC9D,aAAa,CAAC,MAAM,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAED,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAA;QAC/B,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,CAAA;QACzC,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5B,OAAM;QACR,CAAC;QACD,QAAQ,CAAC;YACP,WAAW,EAAE;gBACX,aAAa,EAAE;oBACb,CAAC,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC;oBAC3C,CAAC,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC;iBAC5C;gBACD,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE;aACtE;SACF,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,UAAU,GAAG,UAAU;QAC3B,CAAC,CAAC,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,IAAI,CAAC;QACtC,CAAC,CAAC,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,IAAI,CAAC,CAAA;IACxC,MAAM,YAAY,GAAG,GAAS,EAAE;QAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,UAAU,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QACD,uEAAuE;QACvE,uEAAuE;QACvE,mEAAmE;QACnE,SAAS,CAAC,eAAe,CAAC,CAAA;QAC1B,MAAM,KAAK,GAAG,OAAO,EAAE,CAAA;QACvB,UAAU,EAAE,CAAA;QACZ,WAAW,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,CAAA;IAC7C,CAAC,CAAA;IAED,uEAAuE;IACvE,mEAAmE;IACnE,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;IACzD,MAAM,cAAc,GAAG,GAAS,EAAE;QAChC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACzB,OAAM;QACR,CAAC;QACD,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,EAAE,CAAA;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QACD,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAA;QACpC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7D,OAAM;QACR,CAAC;QACD,eAAe,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAA;QACpE,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IAC9C,CAAC,CAAA;IAED,mEAAmE;IACnE,wEAAwE;IACxE,mEAAmE;IACnE,qEAAqE;IACrE,gEAAgE;IAChE,4DAA4D;IAC5D,eAAe,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,SAAS,IAAI,UAAU,EAAE,CAAC;YAC7B,OAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAA;QACvB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,EAAE,CAAA;QAC3C,IAAI,SAAS,GAAG,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC5C,uEAAuE;QACvE,wEAAwE;QACxE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,MAAM,WAAW,GAAG,CAAC,CAAA;QACrB,IAAI,SAAS,GAAG,WAAW,CAAA;QAC3B,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE;YACrC,SAAS,CAAC,cAAc,CAAC,CAAA;YACzB,MAAM,KAAK,GAAG,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;YAC1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,SAAS,GAAG,KAAK,CAAA;gBACjB,SAAS,GAAG,WAAW,CAAA;YACzB,CAAC;iBAAM,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;gBACzB,SAAS,IAAI,CAAC,CAAA;YAChB,CAAC;iBAAM,CAAC;gBACN,iEAAiE;gBACjE,2DAA2D;gBAC3D,OAAO,IAAI,CAAA;YACb,CAAC;YACD,SAAS,CAAC,eAAe,CAAC,CAAA;YAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;YAClC,IAAI,OAAO,EAAE,CAAC;gBACZ,aAAa,CAAC,OAAO,CAAC,CAAA;YACxB,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAA;QAC/B,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;IAErC,wEAAwE;IACxE,yEAAyE;IACzE,wEAAwE;IACxE,sEAAsE;IACtE,qCAAqC;IACrC,eAAe,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QACD,kBAAkB,EAAE,CAAA;QACpB,MAAM,MAAM,GAAG,QAAQ,CAAA;QACvB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE;YACrC,aAAa,CAAC,OAAO,EAAE,CAAC,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAA;QAC/B,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IACd,SAAS,CAAC,UAAU,EAAE,eAAe,EAAE,YAAY,CAAC,CAAA;IACpD,sEAAsE;IACtE,wCAAwC;IACxC,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAA;IACxE,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAA;IAExE,OAAO,CACL,KAAC,iBAAiB,IAChB,GAAG,EAAE,CAAC,MAAiC,EAAE,EAAE;YACzC,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAA;YACzB,WAAW,CAAC,MAAM,CAAC,CAAA;QACrB,CAAC,EACD,IAAI,EAAE,MAAM,YAEZ,KAAC,MAAM,IAAC,GAAG,EAAE,UAAU,YACrB,KAAC,eAAe,CAAC,QAAQ,IACvB,KAAK,EAAE;oBACL,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE,UAAU;iBACtB,YAED,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,cAAc,CAAC,OAAO,YAC1D,SAAS,CAAC,MAAM,KAAK,CAAC;wBACrB,CAAC,CAAC,QAAQ;wBACV,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAC9C,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAC,UAAU,IAET,SAAS,EAAE,SAAS,KAAK,EAAE,YAE1B,KAAK,IAHD,eAAe,KAAK,EAAE,CAIhB,CACd,CAAC,CAAC,CAAC,CACF,KAAK,CACN,CACF,GAC0B,GACR,GACpB,GACS,CACrB,CAAA;AACH,CAAC,CACF,CAAA;AACD,UAAU,CAAC,WAAW,GAAG,YAAY,CAAA","sourcesContent":["import {\n Children,\n createContext,\n forwardRef,\n useContext,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkBox,\n GtkScrolledWindow,\n queueAllocate,\n queueResize,\n useSignal,\n} from \"../gtkx/bridge/index\"\nimport {\n ensurePerfReporter,\n perfAddTime,\n perfCount,\n perfEnabled,\n perfFrameTick,\n perfNow,\n} from \"../perf\"\nimport { HostNodeContext } from \"./host-node\"\nimport { deferDuringAllocate, setStoredOffset } from \"./rect-store\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\nexport type ScrollViewHandle = {\n scrollTo(options: { x?: number; y?: number; animated?: boolean }): void\n scrollToEnd(options?: { animated?: boolean }): void\n}\n\nexport type ScrollEvent = {\n nativeEvent: {\n contentOffset: { x: number; y: number }\n contentSize: { width: number; height: number }\n }\n}\n\nexport type ScrollViewProps = {\n style?: StyleProp\n contentContainerStyle?: StyleProp\n horizontal?: boolean\n // RN sticky headers (vertical lists): the children at these indices pin to\n // the top while scrolled past, each pushed out by the next one.\n stickyHeaderIndices?: readonly number[]\n onScroll?: (event: ScrollEvent) => void\n // RN onContentSizeChange(contentWidth, contentHeight): fires when the\n // scrollable content changes size. GTK's adjustments emit \"changed\" right\n // after the allocation that resized their range — exactly the moment the\n // new scroll extent is real, which windowed lists rely on to reposition.\n onContentSizeChange?: (width: number, height: number) => void\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n testID?: string\n}\n\ntype StickyRecord = { y: number; height: number; widget: Gtk.Widget }\n\n// The sticky registry lives on the nearest ScrollView: any descendant may\n// register a slot with its content-relative geometry (measured children of\n// the ScrollView itself, or windowed list cells with engine-known offsets).\nexport type StickyRegistry = {\n register(key: string, record: StickyRecord): void\n unregister(key: string): void\n}\n\nexport const StickyRegistryContext = createContext<StickyRegistry | null>(null)\n\n// A wrapper around a sticky child: a plain container that reports its layout\n// and widget into the registry, so the scroll handler can translate/reorder\n// the REAL instance (RN semantics — no duplicate is ever rendered, external\n// margins travel with the header exactly as designed). An explicit `top`\n// (windowed cells) overrides the measured position.\nexport const StickySlot = ({\n stickyKey,\n style,\n top,\n onLayout,\n children,\n}: {\n stickyKey: string\n style?: StyleProp\n top?: number\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n}) => {\n const registry = useContext(StickyRegistryContext)\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { host, node } = useLayoutChild(widgetRef, {\n style,\n onLayout: (event) => {\n onLayout?.(event)\n const widget = widgetRef.current\n if (registry && widget) {\n registry.register(stickyKey, {\n y: top ?? event.nativeEvent.layout.y,\n height: event.nativeEvent.layout.height,\n widget,\n })\n }\n },\n })\n useRnContainer(widgetRef, node)\n useLayoutEffect(() => {\n return () => {\n registry?.unregister(stickyKey)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stickyKey])\n return (\n <GtkBox ref={widgetRef}>\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\n// GtkScrolledWindow whose child is a content GtkBox backed by its own Yoga\n// node inside the same engine: the content's RnGtkxLayout measures the engine\n// content size (which grows past the viewport — that IS the scroll range;\n// overflow: scroll on the outer node) and the scrolled window pans it.\nexport const ScrollView = forwardRef<ScrollViewHandle, ScrollViewProps>(\n (\n {\n style,\n contentContainerStyle,\n horizontal = false,\n stickyHeaderIndices,\n onScroll,\n onContentSizeChange,\n onLayout,\n children,\n testID,\n },\n handleRef,\n ) => {\n const outerRef = useRef<Gtk.ScrolledWindow | null>(null)\n const contentRef = useRef<Gtk.Box | null>(null)\n const [scrolled, setScrolled] = useState<Gtk.ScrolledWindow | null>(null)\n\n const { host, node: outerNode } = useLayoutChild(outerRef, {\n // Yoga unconstrains a scroll node's MAIN axis — align it with the\n // scroll direction or a horizontal list's content clamps to the\n // viewport width (hadjustment upper == page).\n style: [\n style,\n { overflow: \"scroll\", flexDirection: horizontal ? \"row\" : \"column\" },\n ],\n onLayout,\n })\n\n const [contentNode] = useState(() => host.engine.createNode())\n // Sticky positions are computed INSIDE the same allocation pass that\n // places the children (beforeAllocate): the viewport has already settled\n // on this frame's scroll offset, so the pinned header lands exactly —\n // reacting to the adjustment signal instead lags a frame and jitters.\n useRnContainer(contentRef, contentNode, {\n beforeAllocate: () => {\n if (stickyRecords.current.size > 0) {\n updateSticky(outerRef.current?.getVadjustment()?.getValue() ?? 0)\n }\n },\n })\n\n // RN semantics: a ScrollView CLIPS its content. Branch B made containers\n // paint-overflow by default, so without this the scrolled-away content\n // (e.g. the original of a pinned sticky header) keeps drawing past the\n // scroll area's edges.\n useLayoutEffect(() => {\n outerRef.current?.setOverflow(Gtk.Overflow.HIDDEN)\n }, [])\n\n useLayoutEffect(() => {\n outerNode.insertChild(contentNode, 0)\n contentNode.setCommit(() => {\n // The content size IS this widget's measure (scroll range) — the\n // ScrolledWindow itself allocates the content widget.\n const widget = contentRef.current\n if (!widget) {\n return\n }\n const queue = (): void => {\n queueResize(widget)\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n contentNode.setCommit(null)\n outerNode.removeChild(contentNode)\n contentNode.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const contentLayout = splitStyle(\n StyleSheet.flatten(contentContainerStyle),\n ).layout\n const contentKey = JSON.stringify({ horizontal, contentLayout })\n useLayoutEffect(() => {\n contentNode.setStyle({\n flexDirection: horizontal ? \"row\" : \"column\",\n alignItems: \"flex-start\",\n ...contentLayout,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [contentNode, contentKey])\n\n useImperativeHandle(handleRef, () => ({\n scrollTo({ x, y }) {\n const widget = outerRef.current\n if (!widget) {\n return\n }\n if (y !== undefined) {\n widget.getVadjustment()?.setValue(y)\n }\n if (x !== undefined) {\n widget.getHadjustment()?.setValue(x)\n }\n },\n scrollToEnd() {\n const widget = outerRef.current\n const adjustment = horizontal\n ? widget?.getHadjustment()\n : widget?.getVadjustment()\n if (adjustment) {\n adjustment.setValue(adjustment.getUpper() - adjustment.getPageSize())\n }\n },\n }))\n\n // --- sticky headers -------------------------------------------------\n // The RN model, faithfully: the REAL child is translated (no duplicate,\n // state preserved). RN gives the pinned cell a zIndex; GTK's z-order is\n // sibling paint order, so the active slot is reordered to be the LAST\n // content child while pinned and restored afterwards. Per-frame movement\n // goes through the rect-store offset fast path — zero React work while\n // scrolling.\n const stickySet = stickyHeaderIndices ?? []\n const stickyRecords = useRef(new Map<string, StickyRecord>())\n const restoreSibling = useRef(new Map<string, Gtk.Widget | null>())\n const activeStickyRef = useRef<string | null>(null)\n const [hasSticky, setHasSticky] = useState(false)\n\n const stickyRegistry = useRef<StickyRegistry>({\n register: (key, record) => {\n stickyRecords.current.set(key, record)\n setHasSticky(true)\n const parent = record.widget.getParent()\n if (parent) {\n queueAllocate(parent)\n }\n },\n unregister: (key) => {\n stickyRecords.current.delete(key)\n restoreSibling.current.delete(key)\n if (activeStickyRef.current === key) {\n activeStickyRef.current = null\n }\n if (stickyRecords.current.size === 0) {\n setHasSticky(false)\n }\n },\n })\n\n const updateSticky = (rawScrollTop: number): void => {\n if (stickyRecords.current.size === 0) {\n return\n }\n // The viewport translates the content by the FRACTIONAL adjustment\n // value while widget allocations are integer — an unquantized pin\n // disagrees with the translation by ±1px and shimmers every frame.\n // Frame telemetry (docs/research/sticky-probe.md) proved the viewport quantizes\n // like floor: with Math.floor the header's window-relative position is\n // a flat 0.00 across every frame; round oscillates 0/1, ceil sits at 1.\n const scrollTop = Math.floor(rawScrollTop)\n let active: string | null = null\n let next: StickyRecord | null = null\n for (const [key, record] of stickyRecords.current) {\n if (record.y <= scrollTop) {\n if (\n active === null ||\n record.y >= stickyRecords.current.get(active)!.y\n ) {\n active = key\n }\n } else if (next === null || record.y < next.y) {\n next = record\n }\n }\n\n const previous = activeStickyRef.current\n if (previous !== active) {\n activeStickyRef.current = active\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n if (record) {\n setStoredOffset(record.widget, 0, 0)\n }\n }\n // Reordering widgets queues GTK work — not allowed mid-allocation.\n // The z-switch lands a frame later; the POSITION is already exact.\n setTimeout(() => {\n applyStickyReorder(previous, active)\n }, 0)\n }\n\n if (active !== null) {\n const record = stickyRecords.current.get(active)!\n // Pin at the viewport top; the next sticky header pushes it out.\n const pinned = next\n ? Math.min(scrollTop, next.y - record.height)\n : scrollTop\n setStoredOffset(record.widget, 0, Math.max(0, pinned - record.y))\n }\n }\n\n const applyStickyReorder = (\n previous: string | null,\n active: string | null,\n ): void => {\n if (previous !== null) {\n const record = stickyRecords.current.get(previous)\n // Slot parents are always our GtkBox containers.\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n // Put the slot back where the reconciler expects it.\n parent.reorderChildAfter(\n record.widget,\n restoreSibling.current.get(previous) ?? null,\n )\n queueAllocate(parent)\n }\n }\n if (active !== null) {\n const record = stickyRecords.current.get(active)\n const parent = record?.widget.getParent() as Gtk.Box | null\n if (record && parent) {\n restoreSibling.current.set(active, record.widget.getPrevSibling())\n parent.reorderChildAfter(record.widget, parent.getLastChild())\n queueAllocate(parent)\n }\n }\n }\n\n const emitScroll = (): void => {\n if (!onScroll) {\n return\n }\n const widget = outerRef.current\n const contentRect = contentNode.getRect()\n if (!widget || !contentRect) {\n return\n }\n onScroll({\n nativeEvent: {\n contentOffset: {\n x: widget.getHadjustment()?.getValue() ?? 0,\n y: widget.getVadjustment()?.getValue() ?? 0,\n },\n contentSize: { width: contentRect.width, height: contentRect.height },\n },\n })\n }\n\n const adjustment = horizontal\n ? (scrolled?.getHadjustment() ?? null)\n : (scrolled?.getVadjustment() ?? null)\n const onAdjustment = (): void => {\n if (!perfEnabled) {\n emitScroll()\n return\n }\n // Perf: full wall time of one scroll tick's JS work — the FFI reads in\n // emitScroll plus the app/VirtualizedList onScroll handler (windowing,\n // viewability, endReached) — everything that blocks the GTK frame.\n perfCount(\"scroll.events\")\n const start = perfNow()\n emitScroll()\n perfAddTime(\"scroll.js\", perfNow() - start)\n }\n\n // Content-size reports dedupe on the engine rect: \"changed\" also fires\n // for pure viewport (page-size) changes, which RN does not report.\n const lastContentSize = useRef({ width: -1, height: -1 })\n const onRangeChanged = (): void => {\n if (!onContentSizeChange) {\n return\n }\n const rect = contentNode.getRect()\n if (!rect) {\n return\n }\n const last = lastContentSize.current\n if (rect.width === last.width && rect.height === last.height) {\n return\n }\n lastContentSize.current = { width: rect.width, height: rect.height }\n onContentSizeChange(rect.width, rect.height)\n }\n\n // Frame-synced sticky driver: a pure scroll TRANSLATES the content\n // without re-allocating it (same size → GTK skips the vfunc), so signal\n // handlers land a frame late and the pinned header jitters. A tick\n // callback runs in the frame's UPDATE phase, before layout: when the\n // scroll offset moved, queue an allocation for THIS frame — the\n // translation and the pin correction then paint atomically.\n useLayoutEffect(() => {\n if (!hasSticky || horizontal) {\n return\n }\n const widget = scrolled\n if (!widget) {\n return\n }\n const vadjustment = widget.getVadjustment()\n let lastValue = vadjustment?.getValue() ?? 0\n // Frames to keep requeueing after the last observed move. The scrolled\n // window's own kinetic tick may run AFTER ours, so this tick's read can\n // be one frame stale: without the grace window the first frame of a\n // deceleration (its value change lands after our read) would miss its\n // correction. Kinetic deceleration changes the value every frame, so\n // three frames of slack cover the handoff at both ends of the motion.\n const graceFrames = 3\n let remaining = graceFrames\n const id = widget.addTickCallback(() => {\n perfCount(\"sticky.ticks\")\n const value = vadjustment?.getValue() ?? 0\n if (value !== lastValue) {\n lastValue = value\n remaining = graceFrames\n } else if (remaining > 0) {\n remaining -= 1\n } else {\n // At rest: the pin is already correct and nothing translated it,\n // so an allocation pass per frame would be pure idle cost.\n return true\n }\n perfCount(\"sticky.queues\")\n const content = contentRef.current\n if (content) {\n queueAllocate(content)\n }\n return true\n })\n return () => {\n widget.removeTickCallback(id)\n }\n }, [scrolled, hasSticky, horizontal])\n\n // Perf: observe the GTK frame clock through a tick callback — the delta\n // between consecutive ticks is the real frame interval (late frames show\n // up directly). Note: registering a tick callback keeps the frame clock\n // running, so idle seconds show ~60 ticks too; the reporter separates\n // load by the accompanying counters.\n useLayoutEffect(() => {\n if (!perfEnabled) {\n return\n }\n ensurePerfReporter()\n const widget = scrolled\n if (!widget) {\n return\n }\n const id = widget.addTickCallback(() => {\n perfFrameTick(perfNow())\n return true\n })\n return () => {\n widget.removeTickCallback(id)\n }\n }, [scrolled])\n useSignal(adjustment, \"value-changed\", onAdjustment)\n // Both axes report into the same handler — RN's callback carries both\n // dimensions no matter which one moved.\n useSignal(scrolled?.getVadjustment() ?? null, \"changed\", onRangeChanged)\n useSignal(scrolled?.getHadjustment() ?? null, \"changed\", onRangeChanged)\n\n return (\n <GtkScrolledWindow\n ref={(widget: Gtk.ScrolledWindow | null) => {\n outerRef.current = widget\n setScrolled(widget)\n }}\n name={testID}\n >\n <GtkBox ref={contentRef}>\n <HostNodeContext.Provider\n value={{\n engine: host.engine,\n node: contentNode,\n widgetRef: contentRef,\n }}\n >\n <StickyRegistryContext.Provider value={stickyRegistry.current}>\n {stickySet.length === 0\n ? children\n : Children.toArray(children).map((child, index) =>\n stickySet.includes(index) ? (\n <StickySlot\n key={`sticky-slot-${index}`}\n stickyKey={`index-${index}`}\n >\n {child}\n </StickySlot>\n ) : (\n child\n ),\n )}\n </StickyRegistryContext.Provider>\n </HostNodeContext.Provider>\n </GtkBox>\n </GtkScrolledWindow>\n )\n },\n)\nScrollView.displayName = \"ScrollView\"\n"]}
|
|
@@ -16,6 +16,7 @@ export type TextInputProps = {
|
|
|
16
16
|
editable?: boolean;
|
|
17
17
|
keyboardType?: "default" | "numeric" | "email-address" | "phone-pad" | "url";
|
|
18
18
|
multiline?: boolean;
|
|
19
|
+
clearButtonMode?: "never" | "while-editing" | "unless-editing" | "always";
|
|
19
20
|
style?: StyleProp;
|
|
20
21
|
onLayout?: (event: LayoutEvent) => void;
|
|
21
22
|
testID?: string;
|
|
@@ -35,8 +35,9 @@ const useFocusController = (widgetRef, onFocus, onBlur) => {
|
|
|
35
35
|
// Single-line input over GtkEntry. gtkx's controlled-text behavior keeps the
|
|
36
36
|
// widget in sync with the `text` prop (RN controlled semantics); uncontrolled
|
|
37
37
|
// usage passes defaultValue once.
|
|
38
|
-
const SingleLineTextInput = ({ value, defaultValue, onChangeText, onSubmitEditing, onFocus, onBlur, placeholder, secureTextEntry = false, editable = true, keyboardType = "default", style, onLayout, testID, }) => {
|
|
38
|
+
const SingleLineTextInput = ({ value, defaultValue, onChangeText, onSubmitEditing, onFocus, onBlur, placeholder, secureTextEntry = false, editable = true, keyboardType = "default", clearButtonMode = "never", style, onLayout, testID, }) => {
|
|
39
39
|
const widgetRef = useRef(null);
|
|
40
|
+
const [focused, setFocused] = useState(false);
|
|
40
41
|
useLayoutChild(widgetRef, {
|
|
41
42
|
style,
|
|
42
43
|
onLayout,
|
|
@@ -46,8 +47,35 @@ const SingleLineTextInput = ({ value, defaultValue, onChangeText, onSubmitEditin
|
|
|
46
47
|
extraLayout: { minWidth: 60 },
|
|
47
48
|
});
|
|
48
49
|
const controlled = value !== undefined;
|
|
49
|
-
useFocusController(widgetRef,
|
|
50
|
-
|
|
50
|
+
useFocusController(widgetRef, () => {
|
|
51
|
+
setFocused(true);
|
|
52
|
+
onFocus?.();
|
|
53
|
+
}, () => {
|
|
54
|
+
setFocused(false);
|
|
55
|
+
onBlur?.();
|
|
56
|
+
});
|
|
57
|
+
// RN semantics: the affordance only shows when there is something to
|
|
58
|
+
// clear, and while-editing / unless-editing follow focus.
|
|
59
|
+
const text = controlled ? value : undefined;
|
|
60
|
+
const hasText = text !== undefined
|
|
61
|
+
? text.length > 0
|
|
62
|
+
: (widgetRef.current?.getText().length ?? 0) > 0;
|
|
63
|
+
const showClear = hasText &&
|
|
64
|
+
(clearButtonMode === "always" ||
|
|
65
|
+
(clearButtonMode === "while-editing" && focused) ||
|
|
66
|
+
(clearButtonMode === "unless-editing" && !focused));
|
|
67
|
+
return (_jsx(GtkEntry, { ref: widgetRef, name: testID, secondaryIconName: showClear ? "edit-clear-symbolic" : null, secondaryIconActivatable: showClear, secondaryIconTooltipText: showClear ? "Clear" : null, onIconRelease: () => {
|
|
68
|
+
const widget = widgetRef.current;
|
|
69
|
+
if (!widget) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Uncontrolled inputs clear themselves; controlled ones report an
|
|
73
|
+
// empty string and let the owner drive the value (RN contract).
|
|
74
|
+
if (!controlled) {
|
|
75
|
+
widget.setText("");
|
|
76
|
+
}
|
|
77
|
+
onChangeText?.("");
|
|
78
|
+
}, text: controlled ? value : (defaultValue ?? ""), placeholderText: placeholder ?? "", visibility: !secureTextEntry, editable: editable, sensitive: editable, inputPurpose: INPUT_PURPOSE[keyboardType], onChanged: () => {
|
|
51
79
|
const widget = widgetRef.current;
|
|
52
80
|
if (widget) {
|
|
53
81
|
onChangeText?.(widget.getText());
|