@gtkx/components 1.6.0 → 2.0.0-beta.10
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 +47 -44
- package/dist/column-view.d.ts.map +1 -1
- package/dist/column-view.js +1 -0
- package/dist/column-view.js.map +1 -1
- package/dist/combo-row.d.ts.map +1 -0
- package/dist/{adw/combo-row.js → combo-row.js} +1 -1
- package/dist/combo-row.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/cells.d.ts +11 -1
- package/dist/internal/cells.d.ts.map +1 -1
- package/dist/internal/cells.js +124 -26
- package/dist/internal/cells.js.map +1 -1
- package/dist/internal/collection-index.d.ts +1 -2
- package/dist/internal/collection-index.d.ts.map +1 -1
- package/dist/internal/collection-index.js +1 -2
- package/dist/internal/collection-index.js.map +1 -1
- package/dist/internal/collection-model.d.ts +5 -5
- package/dist/internal/collection-model.d.ts.map +1 -1
- package/dist/internal/collection-model.js +38 -43
- package/dist/internal/collection-model.js.map +1 -1
- package/dist/internal/expansion.d.ts.map +1 -1
- package/dist/internal/expansion.js +2 -8
- package/dist/internal/expansion.js.map +1 -1
- package/dist/internal/slots.d.ts.map +1 -1
- package/dist/internal/slots.js +1 -6
- package/dist/internal/slots.js.map +1 -1
- package/dist/internal/tree-expansion.js +2 -2
- package/dist/internal/tree-expansion.js.map +1 -1
- package/dist/internal/tree-order.d.ts +1 -2
- package/dist/internal/tree-order.d.ts.map +1 -1
- package/dist/internal/tree-order.js +1 -4
- package/dist/internal/tree-order.js.map +1 -1
- package/dist/internal/use-widget-ref.d.ts +2 -2
- package/dist/internal/use-widget-ref.d.ts.map +1 -1
- package/dist/internal/use-widget-ref.js.map +1 -1
- package/dist/list-view.d.ts.map +1 -1
- package/dist/list-view.js +1 -0
- package/dist/list-view.js.map +1 -1
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js.map +1 -0
- package/dist/types.d.ts +45 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +13 -14
- package/src/column-view.tsx +1 -0
- package/src/{adw/combo-row.tsx → combo-row.tsx} +2 -2
- package/src/index.ts +7 -0
- package/src/internal/cells.tsx +200 -40
- package/src/internal/collection-index.ts +1 -2
- package/src/internal/collection-model.ts +44 -50
- package/src/internal/expansion.ts +2 -10
- package/src/internal/slots.ts +1 -9
- package/src/internal/tree-expansion.ts +2 -2
- package/src/internal/tree-order.ts +0 -5
- package/src/internal/use-widget-ref.ts +2 -2
- package/src/list-view.tsx +1 -0
- package/src/types.ts +55 -3
- package/dist/adw/combo-row.d.ts.map +0 -1
- package/dist/adw/combo-row.js.map +0 -1
- package/dist/adw/index.d.ts +0 -4
- package/dist/adw/index.d.ts.map +0 -1
- package/dist/adw/index.js +0 -3
- package/dist/adw/index.js.map +0 -1
- package/dist/adw/toast.d.ts.map +0 -1
- package/dist/adw/toast.js.map +0 -1
- package/dist/adw/types.d.ts +0 -36
- package/dist/adw/types.d.ts.map +0 -1
- package/dist/adw/types.js +0 -2
- package/dist/adw/types.js.map +0 -1
- package/src/adw/index.ts +0 -9
- package/src/adw/types.ts +0 -46
- /package/dist/{adw/combo-row.d.ts → combo-row.d.ts} +0 -0
- /package/dist/{adw/toast.d.ts → toast.d.ts} +0 -0
- /package/dist/{adw/toast.js → toast.js} +0 -0
- /package/src/{adw/toast.tsx → toast.tsx} +0 -0
package/README.md
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
<h1 align="center">GTKX</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
The React framework for Linux
|
|
9
|
-
Write native
|
|
10
|
-
Real
|
|
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">
|
|
14
14
|
<a href="https://www.npmjs.com/package/create-gtkx"><img src="https://img.shields.io/npm/v/create-gtkx?color=cb3837&logo=npm&label=create-gtkx" alt="npm version" /></a>
|
|
15
15
|
<a href="https://www.npmjs.com/package/create-gtkx"><img src="https://img.shields.io/npm/dm/create-gtkx?color=cb3837&logo=npm&label=downloads" alt="npm downloads" /></a>
|
|
16
|
-
<img src="https://img.shields.io/badge/node-%E2%89%
|
|
16
|
+
<img src="https://img.shields.io/badge/node-%E2%89%A526.7-339933?logo=node.js&logoColor=white" alt="Node >= 26.7" />
|
|
17
17
|
<a href="https://github.com/gtkx-org/gtkx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MPL--2.0-blue.svg" alt="License: MPL-2.0" /></a>
|
|
18
18
|
<a href="https://github.com/gtkx-org/gtkx/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/gtkx-org/gtkx/ci.yml?branch=main&logo=github&label=CI" alt="CI status" /></a>
|
|
19
19
|
<img src="https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white" alt="TypeScript" />
|
|
@@ -38,11 +38,12 @@
|
|
|
38
38
|
|
|
39
39
|
## Demo
|
|
40
40
|
|
|
41
|
-
|
|
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 {
|
|
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
|
-
<
|
|
54
|
+
<AdwApplicationWindow
|
|
54
55
|
title="Hello GTKX"
|
|
55
56
|
defaultWidth={400}
|
|
56
57
|
defaultHeight={300}
|
|
57
58
|
onCloseRequest={quit}
|
|
58
59
|
>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
<
|
|
85
|
+
<AdwApplication>
|
|
83
86
|
<Counter />
|
|
84
|
-
</
|
|
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
|
-
###
|
|
97
|
+
### Adwaita-first application development
|
|
95
98
|
|
|
96
|
-
|
|
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,29 +105,29 @@ 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
|
-
###
|
|
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
|
|
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
|
|
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
|
|
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
|
|
|
119
|
-
GTKX is Linux-only and needs Node.js
|
|
122
|
+
GTKX is Linux-only and needs Node.js 26.7 or later. See [Requirements](#requirements).
|
|
120
123
|
|
|
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,8 +148,8 @@ 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
|
|
149
|
-
- Node.js
|
|
151
|
+
- Linux with the Adwaita (1.8 or later), GTK4 (4.20 or later), and GLib development libraries
|
|
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.
|
|
152
155
|
|
|
@@ -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):
|
|
159
|
-
- [`browser`](https://github.com/gtkx-org/gtkx/tree/main/examples/browser):
|
|
160
|
-
- [`animations`](https://github.com/gtkx-org/gtkx/tree/main/examples/animations):
|
|
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
|
|
|
@@ -167,7 +170,7 @@ GTKX is stable and ready for production use.
|
|
|
167
170
|
|
|
168
171
|
## Contributing
|
|
169
172
|
|
|
170
|
-
Contributions are welcome. See [CONTRIBUTING.md](https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md), the [Code of Conduct](https://github.com/gtkx-org/gtkx/blob/main/CODE_OF_CONDUCT.md), and the [security policy](https://github.com/gtkx-org/gtkx/blob/main/SECURITY.md). Building the repo needs Node.js
|
|
173
|
+
Contributions are welcome. See [CONTRIBUTING.md](https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md), the [Code of Conduct](https://github.com/gtkx-org/gtkx/blob/main/CODE_OF_CONDUCT.md), and the [security policy](https://github.com/gtkx-org/gtkx/blob/main/SECURITY.md). Building the repo needs Node.js 26.7 or later, pnpm, and a Rust toolchain.
|
|
171
174
|
|
|
172
175
|
## License
|
|
173
176
|
|
|
@@ -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;
|
|
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"}
|
package/dist/column-view.js
CHANGED
package/dist/column-view.js.map
CHANGED
|
@@ -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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combo-row.d.ts","sourceRoot":"","sources":["../src/combo-row.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,uFAAuF;AACvF,KAAK,iBAAiB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;AAE7F;;;;GAIG;AACH,QAAA,MAAM,QAAQ,EAAE,iBAAqD,CAAC;AAMtE,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { AdwComboRow } from "@gtkx/jsx/adw";
|
|
3
|
-
import { DropDownBase } from "
|
|
3
|
+
import { DropDownBase } from "./internal/drop-down.js";
|
|
4
4
|
/**
|
|
5
5
|
* Renders an `Adw.ComboRow` backed by a collection model, presenting the same choice as a
|
|
6
6
|
* `DropDown` in the shape of a preferences row, with customizable renderers for the row
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combo-row.js","sourceRoot":"","sources":["../src/combo-row.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAKvD;;;;GAIG;AACH,MAAM,QAAQ,GAAsB,YAAiC,CAAC;AAEtE,SAAS,YAAY,CAAC,KAAwB;IAC1C,OAAO,KAAC,YAAY,OAAK,KAAK,EAAE,SAAS,EAAE,WAAW,GAAI,CAAC;AAC/D,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["import type { ReactNode } from \"react\";\nimport { AdwComboRow } from \"@gtkx/jsx/adw\";\nimport type { DropDownBaseProps } from \"./internal/drop-down.js\";\nimport type { ComboRowProps } from \"./types.js\";\nimport { DropDownBase } from \"./internal/drop-down.js\";\n\n/** Call signature of {@link ComboRow}, generic in the item and section value types. */\ntype ComboRowComponent = <T = unknown, S = unknown>(props: ComboRowProps<T, S>) => ReactNode;\n\n/**\n * Renders an `Adw.ComboRow` backed by a collection model, presenting the same choice as a\n * `DropDown` in the shape of a preferences row, with customizable renderers for the row\n * display, popup rows, and popup section headers, and controlled selection.\n */\nconst ComboRow: ComboRowComponent = ComboRowImpl as ComboRowComponent;\n\nfunction ComboRowImpl(props: DropDownBaseProps): ReactNode {\n return <DropDownBase {...props} component={AdwComboRow} />;\n}\n\nexport { ComboRow };\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { ColumnView } from "./column-view.js";
|
|
2
|
+
export { ComboRow } from "./combo-row.js";
|
|
2
3
|
export { DropDown } from "./drop-down.js";
|
|
3
4
|
export { GridView } from "./grid-view.js";
|
|
4
5
|
export { ListView } from "./list-view.js";
|
|
5
|
-
export
|
|
6
|
+
export { ToastProvider, useToast, useToastOverlay } from "./toast.js";
|
|
7
|
+
export type { ColumnViewColumn, ColumnViewProps, ComboRowProps, DropDownProps, ExpanderDescriptions, GridViewProps, ListItem, ListItemRenderArgs, ListItemRenderer, ListRowProps, ListRowPropsResolver, ListSection, ListSectionRenderArgs, ListSectionRenderer, ListViewProps, ToastController, ToastOptions, ToastOverlayController, ToastProviderProps, } from "./types.js";
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACtE,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,GACrB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { ColumnView } from "./column-view.js";
|
|
2
|
+
export { ComboRow } from "./combo-row.js";
|
|
2
3
|
export { DropDown } from "./drop-down.js";
|
|
3
4
|
export { GridView } from "./grid-view.js";
|
|
4
5
|
export { ListView } from "./list-view.js";
|
|
6
|
+
export { ToastProvider, useToast, useToastOverlay } from "./toast.js";
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { ColumnView } from \"./column-view.js\";\nexport { DropDown } from \"./drop-down.js\";\nexport { GridView } from \"./grid-view.js\";\nexport { ListView } from \"./list-view.js\";\nexport type {\n ColumnViewColumn,\n ColumnViewProps,\n DropDownProps,\n ExpanderDescriptions,\n GridViewProps,\n ListItem,\n ListItemRenderArgs,\n ListItemRenderer,\n ListRowProps,\n ListRowPropsResolver,\n ListSection,\n ListSectionRenderArgs,\n ListSectionRenderer,\n ListViewProps,\n} from \"./types.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { ColumnView } from \"./column-view.js\";\nexport { ComboRow } from \"./combo-row.js\";\nexport { DropDown } from \"./drop-down.js\";\nexport { GridView } from \"./grid-view.js\";\nexport { ListView } from \"./list-view.js\";\nexport { ToastProvider, useToast, useToastOverlay } from \"./toast.js\";\nexport type {\n ColumnViewColumn,\n ColumnViewProps,\n ComboRowProps,\n DropDownProps,\n ExpanderDescriptions,\n GridViewProps,\n ListItem,\n ListItemRenderArgs,\n ListItemRenderer,\n ListRowProps,\n ListRowPropsResolver,\n ListSection,\n ListSectionRenderArgs,\n ListSectionRenderer,\n ListViewProps,\n ToastController,\n ToastOptions,\n ToastOverlayController,\n ToastProviderProps,\n} from \"./types.js\";\n"]}
|
package/dist/internal/cells.d.ts
CHANGED
|
@@ -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":"AAAA,OAAO,KAAK,KAAK,OAAO,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAKpC,OAAO,KAAK,EACR,oBAAoB,
|
|
1
|
+
{"version":3,"file":"cells.d.ts","sourceRoot":"","sources":["../../src/internal/cells.tsx"],"names":[],"mappings":"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"}
|
package/dist/internal/cells.js
CHANGED
|
@@ -2,11 +2,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
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
|
-
import {
|
|
6
|
-
import { memo, useLayoutEffect, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { setProperty, t } from "@gtkx/runtime";
|
|
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,
|
|
121
|
-
const args = { item: item.value, index:
|
|
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 =
|
|
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 {
|
|
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,
|
|
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) {
|
|
@@ -184,26 +260,40 @@ function rowPropsFor(slot, rowProps) {
|
|
|
184
260
|
};
|
|
185
261
|
}
|
|
186
262
|
function setRowText(host, name, value) {
|
|
187
|
-
|
|
263
|
+
setProperty(host, name, ROW_TEXT_DESCRIPTOR, value);
|
|
188
264
|
}
|
|
189
|
-
function applyRowProps(host, props) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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,
|
|
197
|
-
const slot = useItemSlot(entry,
|
|
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,
|
|
202
|
-
const slot = useItemSlot(entry,
|
|
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, }) =>
|
|
220
|
-
const
|
|
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);
|