@gtkx/components 2.0.0-beta.5 → 2.0.0-beta.7

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 CHANGED
@@ -5,9 +5,9 @@
5
5
  <h1 align="center">GTKX</h1>
6
6
 
7
7
  <p align="center">
8
- The React framework for Linux, built on GTK.<br />
9
- Write native GTK4 desktop applications with React and TypeScript.
10
- Real GTK widgets, the GNOME stack, and standard web tooling.
8
+ The React framework for Linux.<br />
9
+ Write native GNOME applications with React and TypeScript.
10
+ Real Adwaita and GTK4 widgets with standard web tooling.
11
11
  </p>
12
12
 
13
13
  <p align="center">
@@ -38,11 +38,12 @@
38
38
 
39
39
  ## Demo
40
40
 
41
- The intrinsic elements in this snippet render GTK4 widgets, and ordinary React hooks and events drive them:
41
+ This app starts with an Adwaita application shell, renders native GTK4 widgets inside it, and uses ordinary React hooks and events:
42
42
 
43
43
  ```tsx
44
44
  import * as Gtk from "@gtkx/gi/gtk";
45
- import { GtkApplication, GtkApplicationWindow, GtkBox, GtkButton, GtkLabel } from "@gtkx/jsx/gtk";
45
+ import { AdwApplication, AdwApplicationWindow, AdwHeaderBar, AdwToolbarView } from "@gtkx/jsx/adw";
46
+ import { GtkBox, GtkButton, GtkLabel } from "@gtkx/jsx/gtk";
46
47
  import { createRoot, quit } from "@gtkx/react";
47
48
  import { useState } from "react";
48
49
 
@@ -50,38 +51,40 @@ const Counter = () => {
50
51
  const [count, setCount] = useState(0);
51
52
 
52
53
  return (
53
- <GtkApplicationWindow
54
+ <AdwApplicationWindow
54
55
  title="Hello GTKX"
55
56
  defaultWidth={400}
56
57
  defaultHeight={300}
57
58
  onCloseRequest={quit}
58
59
  >
59
- <GtkBox
60
- orientation={Gtk.Orientation.VERTICAL}
61
- spacing={20}
62
- marginTop={40}
63
- marginBottom={40}
64
- marginStart={40}
65
- marginEnd={40}
66
- valign={Gtk.Align.CENTER}
67
- halign={Gtk.Align.CENTER}
68
- >
69
- <GtkLabel cssClasses={["title-1"]}>Welcome to GTKX!</GtkLabel>
70
- <GtkLabel cssClasses={["title-2"]}>{`Count: ${count}`}</GtkLabel>
71
- <GtkButton
72
- label="Increment"
73
- onClicked={() => setCount((c) => c + 1)}
74
- cssClasses={["suggested-action", "pill"]}
75
- />
76
- </GtkBox>
77
- </GtkApplicationWindow>
60
+ <AdwToolbarView topBar={<AdwHeaderBar />}>
61
+ <GtkBox
62
+ orientation={Gtk.Orientation.VERTICAL}
63
+ spacing={20}
64
+ marginTop={40}
65
+ marginBottom={40}
66
+ marginStart={40}
67
+ marginEnd={40}
68
+ valign={Gtk.Align.CENTER}
69
+ halign={Gtk.Align.CENTER}
70
+ >
71
+ <GtkLabel cssClasses={["title-1"]}>Welcome to GTKX!</GtkLabel>
72
+ <GtkLabel cssClasses={["title-2"]}>{`Count: ${String(count)}`}</GtkLabel>
73
+ <GtkButton
74
+ label="Increment"
75
+ onClicked={() => setCount((c) => c + 1)}
76
+ cssClasses={["suggested-action", "pill"]}
77
+ />
78
+ </GtkBox>
79
+ </AdwToolbarView>
80
+ </AdwApplicationWindow>
78
81
  );
79
82
  };
80
83
 
81
84
  const App = () => (
82
- <GtkApplication>
85
+ <AdwApplication>
83
86
  <Counter />
84
- </GtkApplication>
87
+ </AdwApplication>
85
88
  );
86
89
 
87
90
  createRoot().render(<App />);
@@ -91,9 +94,9 @@ This is the [`hello-world`](https://github.com/gtkx-org/gtkx/tree/main/examples/
91
94
 
92
95
  ## Why GTKX
93
96
 
94
- ### A declarative layer for the GNOME stack
97
+ ### Adwaita-first application development
95
98
 
96
- GTK4 is mature, and GtkBuilder XML can lay out a static interface, but nothing re-renders that interface when your application state changes, and nothing hot-reloads it as you work. GTKX adds that missing layer, and the tooling around it, on top of the stack you already know:
99
+ GTKX uses Adwaita as the foundation for applications, windows, navigation, dialogs, and adaptive layouts, with the complete GTK4 toolkit underneath. It adds a declarative React layer and an integrated TypeScript toolchain to the GNOME platform:
97
100
 
98
101
  - a React reconciler that exposes every GObject as a JSX element,
99
102
  - a CLI for scaffolding, development, and production builds,
@@ -102,17 +105,17 @@ GTK4 is mature, and GtkBuilder XML can lay out a static interface, but nothing r
102
105
  - a Testing Library-style API for querying and driving your widgets in tests,
103
106
  - and a Model Context Protocol (MCP) server that exposes your live app to AI agents.
104
107
 
105
- ### The full GNOME API surface
108
+ ### Native GNOME widgets, without a compatibility layer
106
109
 
107
- React Native and similar frameworks hide the native toolkit so one API can run everywhere. GTKX exposes it: GTK4, Adwaita, and any other GObject-Introspection library on your system. Linux-only by design.
110
+ React Native and similar frameworks hide the native toolkit so one API can run everywhere. GTKX renders real Adwaita and GTK4 widgets and exposes any other GObject-Introspection library on your system. It is GNOME-native and Linux-only by design.
108
111
 
109
112
  ### Why Node.js, and why generated bindings
110
113
 
111
114
  GTKX runs on Node.js, which puts native modules, the npm ecosystem, and the tooling built for Node.js APIs within reach. GJS is GNOME's own runtime, built on SpiderMonkey rather than V8; node-gtk runs on Node.js but is lightly maintained, on the older nan/V8 ABI rather than N-API, and still centered on GTK3. The [Why GTKX guide](https://gtkx.dev/guide/why-gtkx) covers what running on Node.js means day to day.
112
115
 
113
- GTKX generates the TypeScript types and the native FFI calls from the same GObject-Introspection data, so the types cannot drift from the calls they back. Codegen covers the whole GTK4 and Adwaita surface.
116
+ GTKX generates the TypeScript types and native FFI calls from the same GObject-Introspection data, so the types cannot drift from the calls they back. `Adw-1` is the sole default GIR root; its GIR include pulls in `Gtk-4.0`, so codegen covers both complete API surfaces. Neither belongs in a GTKX 2 `libraries` list.
114
117
 
115
- At runtime, the native Rust core calls straight into the system GTK4, Adwaita, and GLib libraries through libffi, without loading libgirepository at all.
118
+ At runtime, the native Rust core calls straight into the system Adwaita, GTK4, and GLib libraries through libffi, without loading libgirepository at all.
116
119
 
117
120
  ## Quick start
118
121
 
@@ -121,10 +124,10 @@ GTKX is Linux-only and needs Node.js 26.7 or later. See [Requirements](#requirem
121
124
  Scaffold a new app with the `create-gtkx` initializer:
122
125
 
123
126
  ```sh
124
- npm create gtkx
127
+ npm create gtkx@beta
125
128
  ```
126
129
 
127
- The same command works with other package managers: `pnpm create gtkx` or `yarn create gtkx`.
130
+ The same command works with other package managers: `pnpm create gtkx@beta` or `yarn create gtkx@beta`.
128
131
 
129
132
  Then run your new app:
130
133
 
@@ -145,7 +148,7 @@ The documentation at **[gtkx.dev](https://gtkx.dev)** includes a step-by-step tu
145
148
 
146
149
  GTKX is Linux-only. You need:
147
150
 
148
- - Linux with the GTK4 (4.20 or later), Adwaita (1.8 or later), and GLib development libraries
151
+ - Linux with the Adwaita (1.8 or later), GTK4 (4.20 or later), and GLib development libraries
149
152
  - Node.js 26.7 or later
150
153
 
151
154
  The `@gtkx/native` addon ships prebuilt for x64 and arm64 glibc Linux; other targets need to build it from the GTKX repository, which requires a Rust toolchain.
@@ -154,10 +157,10 @@ The `@gtkx/native` addon ships prebuilt for x64 and arm64 glibc Linux; other tar
154
157
 
155
158
  Explore the [example apps](https://github.com/gtkx-org/gtkx/tree/main/examples):
156
159
 
157
- - [`hello-world`](https://github.com/gtkx-org/gtkx/tree/main/examples/hello-world): the counter above.
158
- - [`gtk-demo`](https://github.com/gtkx-org/gtkx/tree/main/examples/gtk-demo): a React port of the official GTK4 widget showcase, covering lists, dialogs, gestures, CSS, and OpenGL.
159
- - [`browser`](https://github.com/gtkx-org/gtkx/tree/main/examples/browser): a WebKitWebView-based web browser.
160
- - [`animations`](https://github.com/gtkx-org/gtkx/tree/main/examples/animations): a tour of `@gtkx/animated`, React Spring animations driven by the GTK frame clock.
160
+ - [`hello-world`](https://github.com/gtkx-org/gtkx/tree/main/examples/hello-world): the Adwaita counter above.
161
+ - [`gtk-demo`](https://github.com/gtkx-org/gtkx/tree/main/examples/gtk-demo): the official GTK4 widget showcase in an Adwaita application shell, covering lists, dialogs, gestures, CSS, and OpenGL.
162
+ - [`browser`](https://github.com/gtkx-org/gtkx/tree/main/examples/browser): an Adwaita browser built around `WebKitWebView`.
163
+ - [`animations`](https://github.com/gtkx-org/gtkx/tree/main/examples/animations): an Adwaita showcase for `@gtkx/animated`, with React Spring animations driven by the GTK frame clock.
161
164
  - [`navigation`](https://github.com/gtkx-org/gtkx/tree/main/examples/navigation): a tour of `@gtkx/navigation`, React Navigation's stack, tab, and drawer navigators rendered with libadwaita.
162
165
  - [`tutorial`](https://github.com/gtkx-org/gtkx/tree/main/examples/tutorial): the Tasks app the documentation builds.
163
166
 
@@ -1 +1 @@
1
- {"version":3,"file":"column-view.d.ts","sourceRoot":"","sources":["../src/column-view.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAQlD,OAAO,KAAK,EAAoB,eAAe,EAAmC,MAAM,YAAY,CAAC;AAgLrG;;;;GAIG;AACH,iBAAS,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAiCrF;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"column-view.d.ts","sourceRoot":"","sources":["../src/column-view.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAQlD,OAAO,KAAK,EAAoB,eAAe,EAAmC,MAAM,YAAY,CAAC;AAiLrG;;;;GAIG;AACH,iBAAS,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAiCrF;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -10,6 +10,7 @@ import { useWidgetRef } from "./internal/use-widget-ref.js";
10
10
  const COLUMN_VIEW_PROPS = [
11
11
  "items",
12
12
  "sections",
13
+ "isFlat",
13
14
  "renderHeader",
14
15
  "rowProps",
15
16
  "columns",
@@ -1 +1 @@
1
- {"version":3,"file":"column-view.js","sourceRoot":"","sources":["../src/column-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { ReactNode, RefObject } from \"react\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { GtkColumnView, GtkColumnViewColumn, GtkCustomSorter, GtkSignalListItemFactory } from \"@gtkx/jsx/gtk\";\nimport { useSignal } from \"@gtkx/react\";\nimport { omit } from \"@gtkx/utils\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport type { CellSize } from \"./internal/cells.js\";\nimport type { Collection } from \"./internal/collection.js\";\nimport type { ColumnViewColumn, ColumnViewProps, ExpanderDescriptions, SortProps } from \"./types.js\";\nimport { ItemPortals, useItemCells, useRowProps, useSectionHeader } from \"./internal/cells.js\";\nimport { useCollection } from \"./internal/use-collection.js\";\nimport { useWidgetRef } from \"./internal/use-widget-ref.js\";\n\ntype SortTarget = { view: Gtk.ColumnView; column: Gtk.ColumnViewColumn | null };\n\ntype ColumnCellsProps = {\n column: ColumnViewColumn<never>;\n hasExpander: boolean;\n collection: Collection;\n expandedIds: string[] | null | undefined;\n expanderDescriptions: ExpanderDescriptions | null | undefined;\n size: CellSize;\n};\n\ntype ColumnListProps = Omit<ColumnCellsProps, \"column\" | \"hasExpander\"> & {\n columns: ColumnViewColumn<never>[];\n};\n\nconst COLUMN_VIEW_PROPS = [\n \"items\",\n \"sections\",\n \"renderHeader\",\n \"rowProps\",\n \"columns\",\n \"selectedIds\",\n \"onSelectionChanged\",\n \"selectionMode\",\n \"expandedIds\",\n \"onExpandedChange\",\n \"expanderDescriptions\",\n \"sortColumn\",\n \"sortOrder\",\n \"onSortChanged\",\n \"estimatedItemHeight\",\n \"children\",\n \"ref\",\n] as const satisfies (keyof ColumnViewProps)[];\n\nconst expanderIndexFor = (columns: ColumnViewColumn<never>[]): number =>\n columns.findIndex((column) => column.visible !== false);\n\nconst columnById = (view: Gtk.ColumnView, id: string): Gtk.ColumnViewColumn | null => {\n const columns = view.getColumns();\n\n for (let index = 0; index < columns.getNItems(); index++) {\n const column = columns.getItem(index);\n\n if (column instanceof Gtk.ColumnViewColumn && column.getId() === id) {\n return column;\n }\n }\n\n return null;\n};\n\nconst getSortTarget = (view: Gtk.ColumnView | null, sortColumn: string | null | undefined): SortTarget | null => {\n if (view === null || sortColumn === undefined) {\n return null;\n }\n\n if (sortColumn === null) {\n return { view, column: null };\n }\n\n const column = columnById(view, sortColumn);\n\n return column === null ? null : { view, column };\n};\n\nconst applySort = (\n sorting: RefObject<boolean>,\n view: Gtk.ColumnView,\n column: Gtk.ColumnViewColumn | null,\n order: Gtk.SortType | null | undefined,\n): void => {\n sorting.current = true;\n\n try {\n view.sortByColumn(column, order ?? Gtk.SortType.ASCENDING);\n } finally {\n sorting.current = false;\n }\n};\n\nconst emitSortChanged = (\n sorter: Gtk.ColumnViewSorter | null,\n sorting: RefObject<boolean>,\n sort: SortProps,\n): void => {\n if (sorter === null || sorting.current) {\n return;\n }\n\n sort.onSortChanged?.(sorter.getPrimarySortColumn()?.getId() ?? null, sorter.getPrimarySortOrder());\n};\n\nconst syncSort = (\n sorting: RefObject<boolean>,\n view: Gtk.ColumnView | null,\n sortColumn: string | null | undefined,\n sortOrder: Gtk.SortType | null | undefined,\n): void => {\n const target = getSortTarget(view, sortColumn);\n\n if (target === null) {\n return;\n }\n\n applySort(sorting, target.view, target.column, sortOrder);\n};\n\nconst useColumnSorting = (view: Gtk.ColumnView | null, sort: SortProps, columns: ColumnViewColumn<never>[]): void => {\n const sorting = useRef(false);\n const sorter = view?.getSorter() ?? null;\n const columnSorter = sorter instanceof Gtk.ColumnViewSorter ? sorter : null;\n\n useSignal(columnSorter, \"changed\", (): void => {\n emitSortChanged(columnSorter, sorting, sort);\n });\n\n const { sortColumn, sortOrder } = sort;\n\n useLayoutEffect(() => {\n syncSort(sorting, view, sortColumn, sortOrder);\n }, [view, sortColumn, sortOrder, columns]);\n};\n\nconst ColumnCells = ({\n column,\n hasExpander,\n collection,\n expandedIds,\n expanderDescriptions,\n size,\n}: ColumnCellsProps): ReactNode => {\n const cells = useItemCells(size);\n const rest = omit(column, [\"id\", \"renderCell\", \"isSortable\"]);\n\n return (\n <>\n <GtkColumnViewColumn\n id={column.id}\n factory={<GtkSignalListItemFactory {...cells.handlers} />}\n sorter={column.isSortable === true ? <GtkCustomSorter /> : null}\n {...rest}\n />\n <ItemPortals\n registry={cells}\n render={column.renderCell}\n collection={collection}\n hasExpander={hasExpander}\n expandedIds={expandedIds}\n expanderDescriptions={expanderDescriptions}\n />\n </>\n );\n};\n\nconst ColumnList = ({ columns, collection, expandedIds, expanderDescriptions, size }: ColumnListProps): ReactNode => {\n const expanderIndex = expanderIndexFor(columns);\n\n return columns.map((column, index) => (\n <ColumnCells\n key={column.id}\n column={column}\n hasExpander={index === expanderIndex}\n collection={collection}\n expandedIds={expandedIds}\n expanderDescriptions={expanderDescriptions}\n size={size}\n />\n ));\n};\n\n/**\n * Renders a Gtk.ColumnView from declarative items or sections and a columns array,\n * with controlled selection, expansion, and sorting, per-column header menus,\n * section header rendering, and per-row props such as a screen-reader label.\n */\nfunction ColumnView<T = unknown, S = unknown>(props: ColumnViewProps<T, S>): ReactNode {\n const { renderHeader, rowProps, columns, expandedIds, expanderDescriptions } = props;\n const { sortColumn, sortOrder, onSortChanged, ref } = props;\n const rest = omit(props, COLUMN_VIEW_PROPS);\n const size = { width: -1, height: props.estimatedItemHeight ?? -1 };\n const [view, refCallback] = useWidgetRef<Gtk.ColumnView>(ref);\n const { collection, selection } = useCollection(props);\n const header = useSectionHeader(renderHeader, collection, size);\n const rows = useRowProps(rowProps, collection, expandedIds);\n const columnList = columns as ColumnViewColumn<never>[];\n useColumnSorting(view, { sortColumn, sortOrder, onSortChanged }, columnList);\n\n return (\n <>\n <GtkColumnView\n ref={refCallback}\n model={selection}\n {...header.factoryProps}\n {...rows.factoryProps}\n {...rest}\n >\n <ColumnList\n columns={columnList}\n collection={collection}\n expandedIds={expandedIds}\n expanderDescriptions={expanderDescriptions}\n size={size}\n />\n </GtkColumnView>\n {header.portals}\n {rows.portals}\n </>\n );\n}\n\nexport { ColumnView };\n"]}
1
+ {"version":3,"file":"column-view.js","sourceRoot":"","sources":["../src/column-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { ReactNode, RefObject } from \"react\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { GtkColumnView, GtkColumnViewColumn, GtkCustomSorter, GtkSignalListItemFactory } from \"@gtkx/jsx/gtk\";\nimport { useSignal } from \"@gtkx/react\";\nimport { omit } from \"@gtkx/utils\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport type { CellSize } from \"./internal/cells.js\";\nimport type { Collection } from \"./internal/collection.js\";\nimport type { ColumnViewColumn, ColumnViewProps, ExpanderDescriptions, SortProps } from \"./types.js\";\nimport { ItemPortals, useItemCells, useRowProps, useSectionHeader } from \"./internal/cells.js\";\nimport { useCollection } from \"./internal/use-collection.js\";\nimport { useWidgetRef } from \"./internal/use-widget-ref.js\";\n\ntype SortTarget = { view: Gtk.ColumnView; column: Gtk.ColumnViewColumn | null };\n\ntype ColumnCellsProps = {\n column: ColumnViewColumn<never>;\n hasExpander: boolean;\n collection: Collection;\n expandedIds: string[] | null | undefined;\n expanderDescriptions: ExpanderDescriptions | null | undefined;\n size: CellSize;\n};\n\ntype ColumnListProps = Omit<ColumnCellsProps, \"column\" | \"hasExpander\"> & {\n columns: ColumnViewColumn<never>[];\n};\n\nconst COLUMN_VIEW_PROPS = [\n \"items\",\n \"sections\",\n \"isFlat\",\n \"renderHeader\",\n \"rowProps\",\n \"columns\",\n \"selectedIds\",\n \"onSelectionChanged\",\n \"selectionMode\",\n \"expandedIds\",\n \"onExpandedChange\",\n \"expanderDescriptions\",\n \"sortColumn\",\n \"sortOrder\",\n \"onSortChanged\",\n \"estimatedItemHeight\",\n \"children\",\n \"ref\",\n] as const satisfies (keyof ColumnViewProps)[];\n\nconst expanderIndexFor = (columns: ColumnViewColumn<never>[]): number =>\n columns.findIndex((column) => column.visible !== false);\n\nconst columnById = (view: Gtk.ColumnView, id: string): Gtk.ColumnViewColumn | null => {\n const columns = view.getColumns();\n\n for (let index = 0; index < columns.getNItems(); index++) {\n const column = columns.getItem(index);\n\n if (column instanceof Gtk.ColumnViewColumn && column.getId() === id) {\n return column;\n }\n }\n\n return null;\n};\n\nconst getSortTarget = (view: Gtk.ColumnView | null, sortColumn: string | null | undefined): SortTarget | null => {\n if (view === null || sortColumn === undefined) {\n return null;\n }\n\n if (sortColumn === null) {\n return { view, column: null };\n }\n\n const column = columnById(view, sortColumn);\n\n return column === null ? null : { view, column };\n};\n\nconst applySort = (\n sorting: RefObject<boolean>,\n view: Gtk.ColumnView,\n column: Gtk.ColumnViewColumn | null,\n order: Gtk.SortType | null | undefined,\n): void => {\n sorting.current = true;\n\n try {\n view.sortByColumn(column, order ?? Gtk.SortType.ASCENDING);\n } finally {\n sorting.current = false;\n }\n};\n\nconst emitSortChanged = (\n sorter: Gtk.ColumnViewSorter | null,\n sorting: RefObject<boolean>,\n sort: SortProps,\n): void => {\n if (sorter === null || sorting.current) {\n return;\n }\n\n sort.onSortChanged?.(sorter.getPrimarySortColumn()?.getId() ?? null, sorter.getPrimarySortOrder());\n};\n\nconst syncSort = (\n sorting: RefObject<boolean>,\n view: Gtk.ColumnView | null,\n sortColumn: string | null | undefined,\n sortOrder: Gtk.SortType | null | undefined,\n): void => {\n const target = getSortTarget(view, sortColumn);\n\n if (target === null) {\n return;\n }\n\n applySort(sorting, target.view, target.column, sortOrder);\n};\n\nconst useColumnSorting = (view: Gtk.ColumnView | null, sort: SortProps, columns: ColumnViewColumn<never>[]): void => {\n const sorting = useRef(false);\n const sorter = view?.getSorter() ?? null;\n const columnSorter = sorter instanceof Gtk.ColumnViewSorter ? sorter : null;\n\n useSignal(columnSorter, \"changed\", (): void => {\n emitSortChanged(columnSorter, sorting, sort);\n });\n\n const { sortColumn, sortOrder } = sort;\n\n useLayoutEffect(() => {\n syncSort(sorting, view, sortColumn, sortOrder);\n }, [view, sortColumn, sortOrder, columns]);\n};\n\nconst ColumnCells = ({\n column,\n hasExpander,\n collection,\n expandedIds,\n expanderDescriptions,\n size,\n}: ColumnCellsProps): ReactNode => {\n const cells = useItemCells(size);\n const rest = omit(column, [\"id\", \"renderCell\", \"isSortable\"]);\n\n return (\n <>\n <GtkColumnViewColumn\n id={column.id}\n factory={<GtkSignalListItemFactory {...cells.handlers} />}\n sorter={column.isSortable === true ? <GtkCustomSorter /> : null}\n {...rest}\n />\n <ItemPortals\n registry={cells}\n render={column.renderCell}\n collection={collection}\n hasExpander={hasExpander}\n expandedIds={expandedIds}\n expanderDescriptions={expanderDescriptions}\n />\n </>\n );\n};\n\nconst ColumnList = ({ columns, collection, expandedIds, expanderDescriptions, size }: ColumnListProps): ReactNode => {\n const expanderIndex = expanderIndexFor(columns);\n\n return columns.map((column, index) => (\n <ColumnCells\n key={column.id}\n column={column}\n hasExpander={index === expanderIndex}\n collection={collection}\n expandedIds={expandedIds}\n expanderDescriptions={expanderDescriptions}\n size={size}\n />\n ));\n};\n\n/**\n * Renders a Gtk.ColumnView from declarative items or sections and a columns array,\n * with controlled selection, expansion, and sorting, per-column header menus,\n * section header rendering, and per-row props such as a screen-reader label.\n */\nfunction ColumnView<T = unknown, S = unknown>(props: ColumnViewProps<T, S>): ReactNode {\n const { renderHeader, rowProps, columns, expandedIds, expanderDescriptions } = props;\n const { sortColumn, sortOrder, onSortChanged, ref } = props;\n const rest = omit(props, COLUMN_VIEW_PROPS);\n const size = { width: -1, height: props.estimatedItemHeight ?? -1 };\n const [view, refCallback] = useWidgetRef<Gtk.ColumnView>(ref);\n const { collection, selection } = useCollection(props);\n const header = useSectionHeader(renderHeader, collection, size);\n const rows = useRowProps(rowProps, collection, expandedIds);\n const columnList = columns as ColumnViewColumn<never>[];\n useColumnSorting(view, { sortColumn, sortOrder, onSortChanged }, columnList);\n\n return (\n <>\n <GtkColumnView\n ref={refCallback}\n model={selection}\n {...header.factoryProps}\n {...rows.factoryProps}\n {...rest}\n >\n <ColumnList\n columns={columnList}\n collection={collection}\n expandedIds={expandedIds}\n expanderDescriptions={expanderDescriptions}\n size={size}\n />\n </GtkColumnView>\n {header.portals}\n {rows.portals}\n </>\n );\n}\n\nexport { ColumnView };\n"]}
@@ -1,7 +1,7 @@
1
1
  import type * as GObject from "@gtkx/gi/gobject";
2
2
  import type { ReactElement, ReactNode } from "react";
3
3
  import * as Gtk from "@gtkx/gi/gtk";
4
- import type { ExpanderDescriptions, ListItemRenderer, ListRowPropsResolver, ListSectionRenderer } from "../types.js";
4
+ import type { ExpanderDescriptions, ListItem, ListItemRenderer, ListRowPropsResolver, ListSectionRenderer } from "../types.js";
5
5
  import type { Collection } from "./collection.js";
6
6
  type CellSize = {
7
7
  width: number;
@@ -13,6 +13,7 @@ type FactoryHost = GObject.Object & {
13
13
  type CellEntry<H extends FactoryHost> = {
14
14
  key: string;
15
15
  host: H;
16
+ identity: ItemIdentityStore;
16
17
  };
17
18
  type FactoryHandlers = {
18
19
  onSetup: (host: GObject.Object) => void;
@@ -25,6 +26,15 @@ type CellRegistry<H extends FactoryHost> = {
25
26
  subscribe: (onChange: () => void) => () => void;
26
27
  getEntries: () => CellEntry<H>[];
27
28
  };
29
+ type ItemIdentity = {
30
+ item: ListItem | undefined;
31
+ position: number;
32
+ isExpanded: boolean;
33
+ };
34
+ type ItemIdentityStore = {
35
+ read: () => ItemIdentity | null;
36
+ write: (identity: ItemIdentity) => void;
37
+ };
28
38
  type ItemPortalsProps = {
29
39
  registry: CellRegistry<Gtk.ListItem>;
30
40
  render: ListItemRenderer<never>;
@@ -1 +1 @@
1
- {"version":3,"file":"cells.d.ts","sourceRoot":"","sources":["../../src/internal/cells.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cells.d.ts","sourceRoot":"","sources":["../../src/internal/cells.tsx"],"names":[],"mappings":"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"}
@@ -3,10 +3,10 @@ import * as Gtk from "@gtkx/gi/gtk";
3
3
  import { GtkSignalListItemFactory, GtkTreeExpander } from "@gtkx/jsx/gtk";
4
4
  import { createPortal, useProperty } from "@gtkx/react";
5
5
  import { setProperty, t } from "@gtkx/runtime";
6
- import { memo, useLayoutEffect, useState, useSyncExternalStore } from "react";
6
+ import { memo, useInsertionEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
7
7
  import { slotRefFor } from "./collection-model.js";
8
- const ItemCell = memo(ItemCellImpl);
9
- const ItemRow = memo(ItemRowImpl);
8
+ const ItemCell = memo(ItemCellImpl, isSameItemCell);
9
+ const ItemRow = memo(ItemRowImpl, isSameItemRow);
10
10
  const HeaderCell = memo(HeaderCellImpl);
11
11
  const CELL_OPTIONS = { isHost: isListItem, prepare: prepareCell };
12
12
  const HEADER_OPTIONS = { isHost: isListHeader, prepare: prepareCell };
@@ -37,7 +37,7 @@ function notifyRegistry(state) {
37
37
  }
38
38
  function createEntry(state, host) {
39
39
  state.serial += 1;
40
- return { key: `gtkx-cell-${String(state.serial)}`, host };
40
+ return { key: `gtkx-cell-${String(state.serial)}`, host, identity: createItemIdentityStore() };
41
41
  }
42
42
  function setupHost(state, host) {
43
43
  state.prepare?.(host, state.size);
@@ -117,15 +117,14 @@ function useHeaderCells(size) {
117
117
  function isRowWanted(options, item) {
118
118
  return options.expandedIds?.includes(item.id) ?? false;
119
119
  }
120
- function itemArgs(item, options) {
121
- const args = { item: item.value, index: options.position ?? 0 };
122
- const row = options.row;
120
+ function itemArgs(item, position, row, isExpanded) {
121
+ const args = { item: item.value, index: position ?? 0 };
123
122
  if (row === null) {
124
123
  return args;
125
124
  }
126
125
  args.depth = row.getDepth();
127
126
  if (row.isExpandable()) {
128
- args.isExpanded = isRowWanted(options, item);
127
+ args.isExpanded = isExpanded;
129
128
  }
130
129
  return args;
131
130
  }
@@ -135,14 +134,91 @@ function slotFor(options) {
135
134
  if (item === undefined) {
136
135
  return null;
137
136
  }
138
- return { item, row: options.row, args: itemArgs(item, options) };
137
+ return {
138
+ item,
139
+ row: options.row,
140
+ args: itemArgs(item, options.position, options.row, isRowWanted(options, item)),
141
+ };
139
142
  }
140
- function useItemSlot(entry, collection, expandedIds) {
143
+ function useItemSlot(entry, state, identity) {
141
144
  const position = useProperty(entry.host, "position");
142
145
  const item = useProperty(entry.host, "item") ?? null;
143
146
  const row = item instanceof Gtk.TreeListRow ? item : null;
147
+ if (position === identity.position) {
148
+ return identity.item === undefined
149
+ ? null
150
+ : {
151
+ item: identity.item,
152
+ row,
153
+ args: itemArgs(identity.item, position, row, identity.isExpanded),
154
+ };
155
+ }
156
+ const { collection, expandedIds } = state.read();
144
157
  return slotFor({ item, position, row, collection, expandedIds });
145
158
  }
159
+ function itemIdentity(entry, collection, expandedIds) {
160
+ const ref = slotRefFor(entry.host.getItem());
161
+ const item = ref === null ? undefined : collection.itemAt(ref);
162
+ return {
163
+ item,
164
+ position: entry.host.getPosition(),
165
+ isExpanded: item === undefined ? false : (expandedIds?.includes(item.id) ?? false),
166
+ };
167
+ }
168
+ function isSameItemIdentity(previous, next) {
169
+ return (previous.item === next.item &&
170
+ previous.position === next.position &&
171
+ previous.isExpanded === next.isExpanded);
172
+ }
173
+ function isSameItemCell(previous, next) {
174
+ const identity = previous.entry.identity.read() ?? previous;
175
+ return (previous.entry === next.entry &&
176
+ previous.render === next.render &&
177
+ previous.hasExpander === next.hasExpander &&
178
+ previous.expanderDescriptions === next.expanderDescriptions &&
179
+ isSameItemIdentity(identity, next));
180
+ }
181
+ function isSameItemRow(previous, next) {
182
+ const identity = previous.entry.identity.read() ?? previous;
183
+ return previous.entry === next.entry && previous.rowProps === next.rowProps && isSameItemIdentity(identity, next);
184
+ }
185
+ function createItemIdentityStore() {
186
+ let current = null;
187
+ return {
188
+ read: () => current,
189
+ write: (identity) => {
190
+ current = identity;
191
+ },
192
+ };
193
+ }
194
+ function renderedIdentity(entry, slot) {
195
+ return {
196
+ item: slot?.item,
197
+ position: slot?.args.index ?? entry.host.getPosition(),
198
+ isExpanded: slot?.args.isExpanded ?? false,
199
+ };
200
+ }
201
+ function useRememberIdentity(entry, slot) {
202
+ useLayoutEffect(() => {
203
+ entry.identity.write(renderedIdentity(entry, slot));
204
+ });
205
+ }
206
+ function createCollectionStateStore(initial) {
207
+ let current = initial;
208
+ return {
209
+ read: () => current,
210
+ write: (state) => {
211
+ current = state;
212
+ },
213
+ };
214
+ }
215
+ function useCollectionState(collection, expandedIds) {
216
+ const [state] = useState(() => createCollectionStateStore({ collection, expandedIds }));
217
+ useInsertionEffect(() => {
218
+ state.write({ collection, expandedIds });
219
+ }, [state, collection, expandedIds]);
220
+ return state;
221
+ }
146
222
  function expanderDescriptionFor(slot, descriptions) {
147
223
  const { isExpanded } = slot.args;
148
224
  if (isExpanded === undefined || descriptions == null) {
@@ -186,24 +262,38 @@ function rowPropsFor(slot, rowProps) {
186
262
  function setRowText(host, name, value) {
187
263
  setProperty(host, name, ROW_TEXT_DESCRIPTOR, value);
188
264
  }
189
- function applyRowProps(host, props) {
190
- setRowText(host, "accessible-label", props.accessibleLabel);
191
- setRowText(host, "accessible-description", props.accessibleDescription);
192
- host.setActivatable(props.isActivatable);
193
- host.setFocusable(props.isFocusable);
194
- host.setSelectable(props.isSelectable);
265
+ function applyRowProps(host, props, previous) {
266
+ if (previous?.accessibleLabel !== props.accessibleLabel) {
267
+ setRowText(host, "accessible-label", props.accessibleLabel);
268
+ }
269
+ if (previous?.accessibleDescription !== props.accessibleDescription) {
270
+ setRowText(host, "accessible-description", props.accessibleDescription);
271
+ }
272
+ if (previous?.isActivatable !== props.isActivatable) {
273
+ host.setActivatable(props.isActivatable);
274
+ }
275
+ if (previous?.isFocusable !== props.isFocusable) {
276
+ host.setFocusable(props.isFocusable);
277
+ }
278
+ if (previous?.isSelectable !== props.isSelectable) {
279
+ host.setSelectable(props.isSelectable);
280
+ }
195
281
  }
196
- function ItemCellImpl({ entry, render, collection, hasExpander, expandedIds, expanderDescriptions, }) {
197
- const slot = useItemSlot(entry, collection, expandedIds);
282
+ function ItemCellImpl({ entry, render, state, hasExpander, expanderDescriptions, ...identity }) {
283
+ const slot = useItemSlot(entry, state, identity);
284
+ useRememberIdentity(entry, slot);
198
285
  const body = itemBody(slot, render, hasExpander, expanderDescriptions);
199
286
  return createPortal(body, entry.host, entry.key);
200
287
  }
201
- function ItemRowImpl({ entry, rowProps, collection, expandedIds }) {
202
- const slot = useItemSlot(entry, collection, expandedIds);
288
+ function ItemRowImpl({ entry, rowProps, state, ...identity }) {
289
+ const slot = useItemSlot(entry, state, identity);
290
+ useRememberIdentity(entry, slot);
203
291
  const props = rowPropsFor(slot, rowProps);
292
+ const previous = useRef(null);
204
293
  useLayoutEffect(() => {
205
- applyRowProps(entry.host, props);
206
- });
294
+ applyRowProps(entry.host, props, previous.current);
295
+ previous.current = props;
296
+ }, [entry.host, props]);
207
297
  return null;
208
298
  }
209
299
  function HeaderCellImpl({ entry, render, collection }) {
@@ -216,8 +306,16 @@ function HeaderCellImpl({ entry, render, collection }) {
216
306
  function usePortalEntries(registry) {
217
307
  return useSyncExternalStore(registry.subscribe, registry.getEntries);
218
308
  }
219
- const ItemPortals = ({ registry, render, collection, hasExpander, expandedIds, expanderDescriptions, }) => usePortalEntries(registry).map((entry) => (_jsx(ItemCell, { entry: entry, render: render, collection: collection, hasExpander: hasExpander ?? true, expandedIds: expandedIds, expanderDescriptions: expanderDescriptions }, entry.key)));
220
- const RowPortals = ({ registry, rowProps, collection, expandedIds }) => usePortalEntries(registry).map((entry) => (_jsx(ItemRow, { entry: entry, rowProps: rowProps, collection: collection, expandedIds: expandedIds }, entry.key)));
309
+ const ItemPortals = ({ registry, render, collection, hasExpander, expandedIds, expanderDescriptions, }) => {
310
+ const entries = usePortalEntries(registry);
311
+ const state = useCollectionState(collection, expandedIds);
312
+ return entries.map((entry) => (_jsx(ItemCell, { entry: entry, render: render, state: state, hasExpander: hasExpander ?? true, expanderDescriptions: expanderDescriptions, ...itemIdentity(entry, collection, expandedIds) }, entry.key)));
313
+ };
314
+ const RowPortals = ({ registry, rowProps, collection, expandedIds }) => {
315
+ const entries = usePortalEntries(registry);
316
+ const state = useCollectionState(collection, expandedIds);
317
+ return entries.map((entry) => (_jsx(ItemRow, { entry: entry, rowProps: rowProps, state: state, ...itemIdentity(entry, collection, expandedIds) }, entry.key)));
318
+ };
221
319
  const HeaderPortals = ({ registry, render, collection }) => usePortalEntries(registry).map((entry) => (_jsx(HeaderCell, { entry: entry, render: render, collection: collection }, entry.key)));
222
320
  const useSectionHeader = (render, collection, size) => {
223
321
  const registry = useHeaderCells(size);