@gtkx/components 2.0.0-beta.10 → 2.0.0-beta.11
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 +8 -168
- package/dist/column-view.d.ts.map +1 -1
- package/dist/column-view.js +19 -9
- package/dist/column-view.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/cells.d.ts +8 -1
- package/dist/internal/cells.d.ts.map +1 -1
- package/dist/internal/cells.js +84 -19
- package/dist/internal/cells.js.map +1 -1
- package/dist/internal/collection-index.d.ts +3 -2
- package/dist/internal/collection-index.d.ts.map +1 -1
- package/dist/internal/collection-index.js +3 -3
- package/dist/internal/collection-index.js.map +1 -1
- package/dist/internal/collection-model.d.ts +23 -2
- package/dist/internal/collection-model.d.ts.map +1 -1
- package/dist/internal/collection-model.js +118 -98
- package/dist/internal/collection-model.js.map +1 -1
- package/dist/internal/collection.d.ts +5 -4
- package/dist/internal/collection.d.ts.map +1 -1
- package/dist/internal/collection.js +20 -21
- package/dist/internal/collection.js.map +1 -1
- package/dist/internal/controlled-sync.d.ts +6 -8
- package/dist/internal/controlled-sync.d.ts.map +1 -1
- package/dist/internal/controlled-sync.js +3 -3
- package/dist/internal/controlled-sync.js.map +1 -1
- package/dist/internal/drop-down.d.ts.map +1 -1
- package/dist/internal/drop-down.js +43 -44
- package/dist/internal/drop-down.js.map +1 -1
- package/dist/internal/expansion.js +4 -4
- package/dist/internal/expansion.js.map +1 -1
- package/dist/internal/selection.d.ts +1 -0
- package/dist/internal/selection.d.ts.map +1 -1
- package/dist/internal/selection.js +6 -6
- package/dist/internal/selection.js.map +1 -1
- package/dist/internal/tree-expansion.d.ts.map +1 -1
- package/dist/internal/tree-expansion.js +2 -11
- package/dist/internal/tree-expansion.js.map +1 -1
- package/dist/internal/tree-order.d.ts.map +1 -1
- package/dist/internal/tree-order.js +32 -76
- package/dist/internal/tree-order.js.map +1 -1
- package/dist/internal/use-collection.d.ts +5 -1
- package/dist/internal/use-collection.d.ts.map +1 -1
- package/dist/internal/use-collection.js +21 -7
- package/dist/internal/use-collection.js.map +1 -1
- package/dist/list-item-factory.d.ts +10 -0
- package/dist/list-item-factory.d.ts.map +1 -0
- package/dist/list-item-factory.js +14 -0
- package/dist/list-item-factory.js.map +1 -0
- package/dist/toast.d.ts +3 -5
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +3 -12
- package/dist/toast.js.map +1 -1
- package/dist/types.d.ts +33 -50
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +12 -10
- package/src/column-view.tsx +23 -12
- package/src/index.ts +3 -2
- package/src/internal/cells.tsx +137 -20
- package/src/internal/collection-index.ts +8 -6
- package/src/internal/collection-model.ts +156 -134
- package/src/internal/collection.ts +28 -24
- package/src/internal/controlled-sync.ts +9 -12
- package/src/internal/drop-down.tsx +64 -60
- package/src/internal/expansion.ts +4 -4
- package/src/internal/selection.tsx +8 -8
- package/src/internal/tree-expansion.ts +2 -14
- package/src/internal/tree-order.ts +33 -121
- package/src/internal/use-collection.tsx +29 -8
- package/src/list-item-factory.tsx +27 -0
- package/src/toast.tsx +4 -18
- package/src/types.ts +35 -51
package/README.md
CHANGED
|
@@ -1,177 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="https://raw.githubusercontent.com/gtkx-org/gtkx/main/logo.svg" alt="GTKX" width="100" />
|
|
3
|
-
</p>
|
|
1
|
+
# @gtkx/components
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
Collection views, selection controls, and toasts for GTKX.
|
|
6
4
|
|
|
7
|
-
|
|
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
|
-
</p>
|
|
5
|
+
Use `ListView`, `GridView`, and `ColumnView` with React data and render functions. The package also provides dropdowns, combo rows, and `useToast` for notifications within an application window.
|
|
12
6
|
|
|
13
|
-
|
|
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
|
-
<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%A526.7-339933?logo=node.js&logoColor=white" alt="Node >= 26.7" />
|
|
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
|
-
<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
|
-
<img src="https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white" alt="TypeScript" />
|
|
20
|
-
</p>
|
|
21
|
-
|
|
22
|
-
<p align="center">
|
|
23
|
-
<a href="https://gtkx.dev">Homepage</a> ·
|
|
24
|
-
<a href="https://gtkx.dev/guide/getting-started">Documentation</a> ·
|
|
25
|
-
<a href="https://github.com/gtkx-org/gtkx/tree/main/examples">Examples</a> ·
|
|
26
|
-
<a href="https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md">Contributing</a>
|
|
27
|
-
</p>
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
<p align="center">
|
|
32
|
-
<img src="https://raw.githubusercontent.com/gtkx-org/gtkx/main/examples/tutorial/assets/screenshot.png" alt="The Tasks app: an Adwaita window with a sidebar of smart views and colored lists on the left, and a boxed task list on the right." />
|
|
33
|
-
</p>
|
|
34
|
-
|
|
35
|
-
<p align="center">
|
|
36
|
-
<em>The Tasks app you build in the <a href="https://gtkx.dev/tutorial/">tutorial</a>.</em>
|
|
37
|
-
</p>
|
|
38
|
-
|
|
39
|
-
## Demo
|
|
40
|
-
|
|
41
|
-
This app starts with an Adwaita application shell, renders native GTK4 widgets inside it, and uses ordinary React hooks and events:
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
import * as Gtk from "@gtkx/gi/gtk";
|
|
45
|
-
import { AdwApplication, AdwApplicationWindow, AdwHeaderBar, AdwToolbarView } from "@gtkx/jsx/adw";
|
|
46
|
-
import { GtkBox, GtkButton, GtkLabel } from "@gtkx/jsx/gtk";
|
|
47
|
-
import { createRoot, quit } from "@gtkx/react";
|
|
48
|
-
import { useState } from "react";
|
|
49
|
-
|
|
50
|
-
const Counter = () => {
|
|
51
|
-
const [count, setCount] = useState(0);
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<AdwApplicationWindow
|
|
55
|
-
title="Hello GTKX"
|
|
56
|
-
defaultWidth={400}
|
|
57
|
-
defaultHeight={300}
|
|
58
|
-
onCloseRequest={quit}
|
|
59
|
-
>
|
|
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>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const App = () => (
|
|
85
|
-
<AdwApplication>
|
|
86
|
-
<Counter />
|
|
87
|
-
</AdwApplication>
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
createRoot().render(<App />);
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
This is the [`hello-world`](https://github.com/gtkx-org/gtkx/tree/main/examples/hello-world) example, with `app.tsx` and `index.tsx` combined into a single snippet. `@gtkx/gi` and `@gtkx/jsx` are per-project bindings generated by the CLI, not packages you install from npm.
|
|
94
|
-
|
|
95
|
-
## Why GTKX
|
|
96
|
-
|
|
97
|
-
### Adwaita-first application development
|
|
98
|
-
|
|
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:
|
|
100
|
-
|
|
101
|
-
- a React reconciler that exposes every GObject as a JSX element,
|
|
102
|
-
- a CLI for scaffolding, development, and production builds,
|
|
103
|
-
- a dev server with Fast Refresh that patches your running UI in place,
|
|
104
|
-
- CSS-in-JS styling, React Hook Form-powered Adwaita controls, gettext-backed react-i18next localization, React Spring animations, React Navigation stack, tab, drawer, and split view navigators, and high-level list, grid, and dialog components,
|
|
105
|
-
- a Testing Library-style API for querying and driving your widgets in tests,
|
|
106
|
-
- and a Model Context Protocol (MCP) server that exposes your live app to AI agents.
|
|
107
|
-
|
|
108
|
-
### Native GNOME widgets, without a compatibility layer
|
|
109
|
-
|
|
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.
|
|
111
|
-
|
|
112
|
-
### Why Node.js, and why generated bindings
|
|
113
|
-
|
|
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.
|
|
115
|
-
|
|
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.
|
|
117
|
-
|
|
118
|
-
At runtime, the native Rust core calls straight into the system Adwaita, GTK4, and GLib libraries through libffi, without loading libgirepository at all.
|
|
119
|
-
|
|
120
|
-
## Quick start
|
|
121
|
-
|
|
122
|
-
GTKX is Linux-only and needs Node.js 26.7 or later. See [Requirements](#requirements).
|
|
123
|
-
|
|
124
|
-
Scaffold a new app with the `create-gtkx` initializer:
|
|
7
|
+
In an existing GTKX 2.0 beta app:
|
|
125
8
|
|
|
126
9
|
```sh
|
|
127
|
-
npm
|
|
10
|
+
npm install @gtkx/components@beta
|
|
128
11
|
```
|
|
129
12
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Then run your new app:
|
|
133
|
-
|
|
134
|
-
```sh
|
|
135
|
-
cd my-app
|
|
136
|
-
npm run dev
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
To go further, follow the [tutorial](https://gtkx.dev/tutorial/).
|
|
140
|
-
|
|
141
|
-
## Documentation
|
|
142
|
-
|
|
143
|
-
The documentation at **[gtkx.dev](https://gtkx.dev)** includes a step-by-step tutorial that builds a complete GNOME app, from scaffolding to packaging and shipping, plus guides and a full API reference.
|
|
144
|
-
|
|
145
|
-
**[Read the docs →](https://gtkx.dev/guide/why-gtkx)**
|
|
146
|
-
|
|
147
|
-
## Requirements
|
|
148
|
-
|
|
149
|
-
GTKX is Linux-only. You need:
|
|
150
|
-
|
|
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
|
|
153
|
-
|
|
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.
|
|
155
|
-
|
|
156
|
-
## Examples
|
|
157
|
-
|
|
158
|
-
Explore the [example apps](https://github.com/gtkx-org/gtkx/tree/main/examples):
|
|
159
|
-
|
|
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.
|
|
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.
|
|
165
|
-
- [`tutorial`](https://github.com/gtkx-org/gtkx/tree/main/examples/tutorial): the Tasks app the documentation builds.
|
|
166
|
-
|
|
167
|
-
## Status
|
|
168
|
-
|
|
169
|
-
GTKX is stable and ready for production use.
|
|
170
|
-
|
|
171
|
-
## Contributing
|
|
172
|
-
|
|
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.
|
|
13
|
+
[Guide](https://gtkx.dev/v2/guide/components) · [API reference](https://gtkx.dev/v2/reference/@gtkx/components/) · [GTKX](https://gtkx.dev)
|
|
174
14
|
|
|
175
|
-
|
|
15
|
+
GTKX runs on Linux with Node.js and system native libraries. See [Getting Started](https://gtkx.dev/v2/guide/getting-started) for supported versions and installation. This README describes the 2.0 beta.
|
|
176
16
|
|
|
177
|
-
|
|
17
|
+
[MPL-2.0](https://github.com/gtkx-org/gtkx/blob/main/LICENSE).
|
|
@@ -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;AA4LrG;;;;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
|
@@ -3,8 +3,9 @@ import * as Gtk from "@gtkx/gi/gtk";
|
|
|
3
3
|
import { GtkColumnView, GtkColumnViewColumn, GtkCustomSorter, GtkSignalListItemFactory } from "@gtkx/jsx/gtk";
|
|
4
4
|
import { useSignal } from "@gtkx/react";
|
|
5
5
|
import { omit } from "@gtkx/utils";
|
|
6
|
-
import {
|
|
6
|
+
import { useMemo, useRef } from "react";
|
|
7
7
|
import { ItemPortals, useItemCells, useRowProps, useSectionHeader } from "./internal/cells.js";
|
|
8
|
+
import { useControlledSync } from "./internal/controlled-sync.js";
|
|
8
9
|
import { useCollection } from "./internal/use-collection.js";
|
|
9
10
|
import { useWidgetRef } from "./internal/use-widget-ref.js";
|
|
10
11
|
const COLUMN_VIEW_PROPS = [
|
|
@@ -24,7 +25,6 @@ const COLUMN_VIEW_PROPS = [
|
|
|
24
25
|
"sortOrder",
|
|
25
26
|
"onSortChanged",
|
|
26
27
|
"estimatedItemHeight",
|
|
27
|
-
"children",
|
|
28
28
|
"ref",
|
|
29
29
|
];
|
|
30
30
|
const expanderIndexFor = (columns) => columns.findIndex((column) => column.visible !== false);
|
|
@@ -57,11 +57,12 @@ const applySort = (sorting, view, column, order) => {
|
|
|
57
57
|
sorting.current = false;
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
|
-
const
|
|
60
|
+
const didEmitSortChanged = (sorter, sorting, sort) => {
|
|
61
61
|
if (sorter === null || sorting.current) {
|
|
62
|
-
return;
|
|
62
|
+
return false;
|
|
63
63
|
}
|
|
64
64
|
sort.onSortChanged?.(sorter.getPrimarySortColumn()?.getId() ?? null, sorter.getPrimarySortOrder());
|
|
65
|
+
return true;
|
|
65
66
|
};
|
|
66
67
|
const syncSort = (sorting, view, sortColumn, sortOrder) => {
|
|
67
68
|
const target = getSortTarget(view, sortColumn);
|
|
@@ -74,13 +75,22 @@ const useColumnSorting = (view, sort, columns) => {
|
|
|
74
75
|
const sorting = useRef(false);
|
|
75
76
|
const sorter = view?.getSorter() ?? null;
|
|
76
77
|
const columnSorter = sorter instanceof Gtk.ColumnViewSorter ? sorter : null;
|
|
78
|
+
const { sortColumn, sortOrder } = sort;
|
|
79
|
+
const request = useMemo(() => ({ sortColumn, sortOrder }), [sortColumn, sortOrder]);
|
|
80
|
+
const markDrift = useControlledSync({
|
|
81
|
+
value: request,
|
|
82
|
+
source: columns,
|
|
83
|
+
target: view,
|
|
84
|
+
apply: (value) => {
|
|
85
|
+
syncSort(sorting, view, value.sortColumn, value.sortOrder);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
77
88
|
useSignal(columnSorter, "changed", () => {
|
|
78
|
-
|
|
89
|
+
const didEmit = didEmitSortChanged(columnSorter, sorting, sort);
|
|
90
|
+
if (sortColumn !== undefined && didEmit) {
|
|
91
|
+
markDrift();
|
|
92
|
+
}
|
|
79
93
|
});
|
|
80
|
-
const { sortColumn, sortOrder } = sort;
|
|
81
|
-
useLayoutEffect(() => {
|
|
82
|
-
syncSort(sorting, view, sortColumn, sortOrder);
|
|
83
|
-
}, [view, sortColumn, sortOrder, columns]);
|
|
84
94
|
};
|
|
85
95
|
const ColumnCells = ({ column, hasExpander, collection, expandedIds, expanderDescriptions, size, }) => {
|
|
86
96
|
const cells = useItemCells(size);
|
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 \"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
|
+
{"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 { useMemo, 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 { useControlledSync } from \"./internal/controlled-sync.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 };\ntype SortRequest = Pick<SortProps, \"sortColumn\" | \"sortOrder\">;\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 \"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 didEmitSortChanged = (\n sorter: Gtk.ColumnViewSorter | null,\n sorting: RefObject<boolean>,\n sort: SortProps,\n): boolean => {\n if (sorter === null || sorting.current) {\n return false;\n }\n\n sort.onSortChanged?.(sorter.getPrimarySortColumn()?.getId() ?? null, sorter.getPrimarySortOrder());\n\n return true;\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 const { sortColumn, sortOrder } = sort;\n const request = useMemo<SortRequest>(() => ({ sortColumn, sortOrder }), [sortColumn, sortOrder]);\n const markDrift = useControlledSync({\n value: request,\n source: columns,\n target: view,\n apply: (value) => {\n syncSort(sorting, view, value.sortColumn, value.sortOrder);\n },\n });\n\n useSignal(columnSorter, \"changed\", (): void => {\n const didEmit = didEmitSortChanged(columnSorter, sorting, sort);\n\n if (sortColumn !== undefined && didEmit) {\n markDrift();\n }\n });\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"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ export { ColumnView } from "./column-view.js";
|
|
|
2
2
|
export { ComboRow } from "./combo-row.js";
|
|
3
3
|
export { DropDown } from "./drop-down.js";
|
|
4
4
|
export { GridView } from "./grid-view.js";
|
|
5
|
+
export { ListItemFactory } from "./list-item-factory.js";
|
|
5
6
|
export { ListView } from "./list-view.js";
|
|
6
|
-
export { ToastProvider, useToast
|
|
7
|
-
export type { ColumnViewColumn, ColumnViewProps, ComboRowProps, DropDownProps, ExpanderDescriptions, GridViewProps, ListItem, ListItemRenderArgs, ListItemRenderer, ListRowProps, ListRowPropsResolver, ListSection, ListSectionRenderArgs, ListSectionRenderer, ListViewProps, ToastController, ToastOptions,
|
|
7
|
+
export { ToastProvider, useToast } from "./toast.js";
|
|
8
|
+
export type { ColumnViewColumn, ColumnViewProps, ComboRowProps, DropDownProps, ExpanderDescriptions, GridViewProps, ListItem, ListItemFactoryProps, ListItemRenderArgs, ListItemRenderer, ListRowProps, ListRowPropsResolver, ListSection, ListSectionRenderArgs, ListSectionRenderer, ListViewProps, ToastController, ToastOptions, ToastProviderProps, } from "./types.js";
|
|
8
9
|
//# 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,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,
|
|
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,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,QAAQ,EACR,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,kBAAkB,GACrB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { ColumnView } from "./column-view.js";
|
|
|
2
2
|
export { ComboRow } from "./combo-row.js";
|
|
3
3
|
export { DropDown } from "./drop-down.js";
|
|
4
4
|
export { GridView } from "./grid-view.js";
|
|
5
|
+
export { ListItemFactory } from "./list-item-factory.js";
|
|
5
6
|
export { ListView } from "./list-view.js";
|
|
6
|
-
export { ToastProvider, useToast
|
|
7
|
+
export { ToastProvider, useToast } from "./toast.js";
|
|
7
8
|
//# 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;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,
|
|
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,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,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 { ListItemFactory } from \"./list-item-factory.js\";\nexport { ListView } from \"./list-view.js\";\nexport { ToastProvider, useToast } from \"./toast.js\";\nexport type {\n ColumnViewColumn,\n ColumnViewProps,\n ComboRowProps,\n DropDownProps,\n ExpanderDescriptions,\n GridViewProps,\n ListItem,\n ListItemFactoryProps,\n ListItemRenderArgs,\n ListItemRenderer,\n ListRowProps,\n ListRowPropsResolver,\n ListSection,\n ListSectionRenderArgs,\n ListSectionRenderer,\n ListViewProps,\n ToastController,\n ToastOptions,\n ToastProviderProps,\n} from \"./types.js\";\n"]}
|
package/dist/internal/cells.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ type CellRegistry<H extends FactoryHost> = {
|
|
|
27
27
|
getEntries: () => CellEntry<H>[];
|
|
28
28
|
};
|
|
29
29
|
type ItemIdentity = {
|
|
30
|
+
itemKey: string;
|
|
30
31
|
item: ListItem | undefined;
|
|
31
32
|
position: number;
|
|
32
33
|
isExpanded: boolean;
|
|
@@ -43,6 +44,11 @@ type ItemPortalsProps = {
|
|
|
43
44
|
expandedIds?: string[] | null | undefined;
|
|
44
45
|
expanderDescriptions?: ExpanderDescriptions | null | undefined;
|
|
45
46
|
};
|
|
47
|
+
type NativeItemPortalsProps<T extends GObject.Object> = {
|
|
48
|
+
registry: CellRegistry<Gtk.ListItem>;
|
|
49
|
+
render: ListItemRenderer<T>;
|
|
50
|
+
size: CellSize;
|
|
51
|
+
};
|
|
46
52
|
type SectionHeaderSlot = {
|
|
47
53
|
factoryProps: {
|
|
48
54
|
headerFactory?: ReactElement;
|
|
@@ -57,7 +63,8 @@ type RowSlot = {
|
|
|
57
63
|
};
|
|
58
64
|
declare function useItemCells(size: CellSize): CellRegistry<Gtk.ListItem>;
|
|
59
65
|
declare const ItemPortals: ({ registry, render, collection, hasExpander, expandedIds, expanderDescriptions, }: ItemPortalsProps) => ReactNode;
|
|
66
|
+
declare function NativeItemPortals<T extends GObject.Object>({ registry, render, size }: NativeItemPortalsProps<T>): ReactNode;
|
|
60
67
|
declare const useSectionHeader: (render: ListSectionRenderer<never> | null | undefined, collection: Collection, size: CellSize) => SectionHeaderSlot;
|
|
61
68
|
declare const useRowProps: (rowProps: ListRowPropsResolver<never> | null | undefined, collection: Collection, expandedIds: string[] | null | undefined) => RowSlot;
|
|
62
|
-
export { useItemCells, useRowProps, useSectionHeader, ItemPortals, type CellSize, };
|
|
69
|
+
export { useItemCells, useRowProps, useSectionHeader, ItemPortals, NativeItemPortals, type CellSize, };
|
|
63
70
|
//# sourceMappingURL=cells.d.ts.map
|
|
@@ -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;
|
|
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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
3
|
-
import { GtkSignalListItemFactory, GtkTreeExpander } from "@gtkx/jsx/gtk";
|
|
3
|
+
import { GtkBox, GtkSignalListItemFactory, GtkTreeExpander } from "@gtkx/jsx/gtk";
|
|
4
4
|
import { createPortal, useProperty } from "@gtkx/react";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { Fragment, memo, useInsertionEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
6
|
+
import { slotPathAt, slotRefFor } from "./collection-model.js";
|
|
7
|
+
import { joinParts } from "./keys.js";
|
|
8
8
|
const ItemCell = memo(ItemCellImpl, isSameItemCell);
|
|
9
9
|
const ItemRow = memo(ItemRowImpl, isSameItemRow);
|
|
10
10
|
const HeaderCell = memo(HeaderCellImpl);
|
|
@@ -13,8 +13,12 @@ const HEADER_OPTIONS = { isHost: isListHeader, prepare: prepareCell };
|
|
|
13
13
|
const ROW_OPTIONS = { isHost: isColumnViewRow };
|
|
14
14
|
const NO_SIZE = { width: -1, height: -1 };
|
|
15
15
|
const NO_ROW_PROPS = {};
|
|
16
|
-
const
|
|
17
|
-
const placeholder = (size) =>
|
|
16
|
+
const placeholders = new WeakSet();
|
|
17
|
+
const placeholder = (size) => {
|
|
18
|
+
const widget = new Gtk.Box({ widthRequest: size.width, heightRequest: size.height });
|
|
19
|
+
placeholders.add(widget);
|
|
20
|
+
return widget;
|
|
21
|
+
};
|
|
18
22
|
function isListItem(value) {
|
|
19
23
|
return value instanceof Gtk.ListItem;
|
|
20
24
|
}
|
|
@@ -25,9 +29,13 @@ function isColumnViewRow(value) {
|
|
|
25
29
|
return value instanceof Gtk.ColumnViewRow;
|
|
26
30
|
}
|
|
27
31
|
function prepareCell(host, size) {
|
|
28
|
-
|
|
32
|
+
const child = host.getChild();
|
|
33
|
+
if (child === null) {
|
|
29
34
|
host.setChild(placeholder(size));
|
|
30
35
|
}
|
|
36
|
+
else if (placeholders.has(child)) {
|
|
37
|
+
child.setSizeRequest(size.width, size.height);
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
function notifyRegistry(state) {
|
|
33
41
|
state.snapshot = null;
|
|
@@ -95,7 +103,13 @@ function createCellRegistry(options, size) {
|
|
|
95
103
|
return {
|
|
96
104
|
handlers: createHandlers(state),
|
|
97
105
|
setSize: (next) => {
|
|
106
|
+
if (state.size.width === next.width && state.size.height === next.height) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
98
109
|
state.size = next;
|
|
110
|
+
for (const host of state.entries.keys()) {
|
|
111
|
+
state.prepare?.(host, next);
|
|
112
|
+
}
|
|
99
113
|
},
|
|
100
114
|
subscribe: (onChange) => subscribeRegistry(state, onChange),
|
|
101
115
|
getEntries: () => getRegistryEntries(state),
|
|
@@ -128,13 +142,20 @@ function itemArgs(item, position, row, isExpanded) {
|
|
|
128
142
|
}
|
|
129
143
|
return args;
|
|
130
144
|
}
|
|
145
|
+
function keyForItem(ref, item) {
|
|
146
|
+
return joinParts([slotPathAt(ref.store, ref.slot), item.id]);
|
|
147
|
+
}
|
|
131
148
|
function slotFor(options) {
|
|
132
149
|
const ref = slotRefFor(options.item);
|
|
133
|
-
|
|
150
|
+
if (ref === null) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const item = options.collection.itemAt(ref);
|
|
134
154
|
if (item === undefined) {
|
|
135
155
|
return null;
|
|
136
156
|
}
|
|
137
157
|
return {
|
|
158
|
+
itemKey: keyForItem(ref, item),
|
|
138
159
|
item,
|
|
139
160
|
row: options.row,
|
|
140
161
|
args: itemArgs(item, options.position, options.row, isRowWanted(options, item)),
|
|
@@ -148,6 +169,7 @@ function useItemSlot(entry, state, identity) {
|
|
|
148
169
|
return identity.item === undefined
|
|
149
170
|
? null
|
|
150
171
|
: {
|
|
172
|
+
itemKey: identity.itemKey,
|
|
151
173
|
item: identity.item,
|
|
152
174
|
row,
|
|
153
175
|
args: itemArgs(identity.item, position, row, identity.isExpanded),
|
|
@@ -160,13 +182,15 @@ function itemIdentity(entry, collection, expandedIds) {
|
|
|
160
182
|
const ref = slotRefFor(entry.host.getItem());
|
|
161
183
|
const item = ref === null ? undefined : collection.itemAt(ref);
|
|
162
184
|
return {
|
|
185
|
+
itemKey: ref === null || item === undefined ? "" : keyForItem(ref, item),
|
|
163
186
|
item,
|
|
164
187
|
position: entry.host.getPosition(),
|
|
165
|
-
isExpanded: item
|
|
188
|
+
isExpanded: item !== undefined && (expandedIds?.includes(item.id) ?? false),
|
|
166
189
|
};
|
|
167
190
|
}
|
|
168
191
|
function isSameItemIdentity(previous, next) {
|
|
169
192
|
return (previous.item === next.item &&
|
|
193
|
+
previous.itemKey === next.itemKey &&
|
|
170
194
|
previous.position === next.position &&
|
|
171
195
|
previous.isExpanded === next.isExpanded);
|
|
172
196
|
}
|
|
@@ -191,8 +215,25 @@ function createItemIdentityStore() {
|
|
|
191
215
|
},
|
|
192
216
|
};
|
|
193
217
|
}
|
|
218
|
+
function createNativeItemKeyStore() {
|
|
219
|
+
const keys = new WeakMap();
|
|
220
|
+
let serial = 0;
|
|
221
|
+
return {
|
|
222
|
+
keyFor: (item) => {
|
|
223
|
+
const current = keys.get(item);
|
|
224
|
+
if (current !== undefined) {
|
|
225
|
+
return current;
|
|
226
|
+
}
|
|
227
|
+
serial += 1;
|
|
228
|
+
const key = `gtkx-native-item-${String(serial)}`;
|
|
229
|
+
keys.set(item, key);
|
|
230
|
+
return key;
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
194
234
|
function renderedIdentity(entry, slot) {
|
|
195
235
|
return {
|
|
236
|
+
itemKey: slot?.itemKey ?? "",
|
|
196
237
|
item: slot?.item,
|
|
197
238
|
position: slot?.args.index ?? entry.host.getPosition(),
|
|
198
239
|
isExpanded: slot?.args.isExpanded ?? false,
|
|
@@ -239,7 +280,7 @@ function itemBody(slot, render, hasExpander, descriptions) {
|
|
|
239
280
|
}
|
|
240
281
|
const renderItem = render;
|
|
241
282
|
const content = renderItem(slot.args);
|
|
242
|
-
return hasExpander ? wrapExpander(slot, content, descriptions) : content;
|
|
283
|
+
return (_jsx(Fragment, { children: hasExpander ? wrapExpander(slot, content, descriptions) : content }, slot.itemKey));
|
|
243
284
|
}
|
|
244
285
|
function rowText(value) {
|
|
245
286
|
return value ?? null;
|
|
@@ -259,15 +300,12 @@ function rowPropsFor(slot, rowProps) {
|
|
|
259
300
|
isSelectable: rowFlag(props.isSelectable),
|
|
260
301
|
};
|
|
261
302
|
}
|
|
262
|
-
function setRowText(host, name, value) {
|
|
263
|
-
setProperty(host, name, ROW_TEXT_DESCRIPTOR, value);
|
|
264
|
-
}
|
|
265
303
|
function applyRowProps(host, props, previous) {
|
|
266
304
|
if (previous?.accessibleLabel !== props.accessibleLabel) {
|
|
267
|
-
|
|
305
|
+
host.accessibleLabel = props.accessibleLabel;
|
|
268
306
|
}
|
|
269
307
|
if (previous?.accessibleDescription !== props.accessibleDescription) {
|
|
270
|
-
|
|
308
|
+
host.accessibleDescription = props.accessibleDescription;
|
|
271
309
|
}
|
|
272
310
|
if (previous?.isActivatable !== props.isActivatable) {
|
|
273
311
|
host.setActivatable(props.isActivatable);
|
|
@@ -298,11 +336,33 @@ function ItemRowImpl({ entry, rowProps, state, ...identity }) {
|
|
|
298
336
|
}
|
|
299
337
|
function HeaderCellImpl({ entry, render, collection }) {
|
|
300
338
|
const item = useProperty(entry.host, "item") ?? null;
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
339
|
+
return createPortal(headerBody(slotRefFor(item), render, collection), entry.host, entry.key);
|
|
340
|
+
}
|
|
341
|
+
function NativeItemCell({ entry, render, keys, size, }) {
|
|
342
|
+
const position = useProperty(entry.host, "position");
|
|
343
|
+
const item = useProperty(entry.host, "item") ?? null;
|
|
344
|
+
let body = null;
|
|
345
|
+
if (item !== null && position !== undefined) {
|
|
346
|
+
const content = render({ item: item, index: position });
|
|
347
|
+
const child = content == null || typeof content === "boolean"
|
|
348
|
+
? _jsx(GtkBox, { widthRequest: size.width, heightRequest: size.height })
|
|
349
|
+
: content;
|
|
350
|
+
body = _jsx(Fragment, { children: child }, keys.keyFor(item));
|
|
351
|
+
}
|
|
304
352
|
return createPortal(body, entry.host, entry.key);
|
|
305
353
|
}
|
|
354
|
+
function headerBody(ref, render, collection) {
|
|
355
|
+
if (ref === null) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const section = collection.sectionFor(ref.store.level.path);
|
|
359
|
+
if (section === undefined) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
const renderHeader = render;
|
|
363
|
+
const key = joinParts([ref.store.level.path, section.id]);
|
|
364
|
+
return _jsx(Fragment, { children: renderHeader({ section: section.value }) }, key);
|
|
365
|
+
}
|
|
306
366
|
function usePortalEntries(registry) {
|
|
307
367
|
return useSyncExternalStore(registry.subscribe, registry.getEntries);
|
|
308
368
|
}
|
|
@@ -317,6 +377,11 @@ const RowPortals = ({ registry, rowProps, collection, expandedIds }) => {
|
|
|
317
377
|
return entries.map((entry) => (_jsx(ItemRow, { entry: entry, rowProps: rowProps, state: state, ...itemIdentity(entry, collection, expandedIds) }, entry.key)));
|
|
318
378
|
};
|
|
319
379
|
const HeaderPortals = ({ registry, render, collection }) => usePortalEntries(registry).map((entry) => (_jsx(HeaderCell, { entry: entry, render: render, collection: collection }, entry.key)));
|
|
380
|
+
function NativeItemPortals({ registry, render, size }) {
|
|
381
|
+
const entries = usePortalEntries(registry);
|
|
382
|
+
const [keys] = useState(createNativeItemKeyStore);
|
|
383
|
+
return entries.map((entry) => (_jsx(NativeItemCell, { entry: entry, render: render, keys: keys, size: size }, entry.key)));
|
|
384
|
+
}
|
|
320
385
|
const useSectionHeader = (render, collection, size) => {
|
|
321
386
|
const registry = useHeaderCells(size);
|
|
322
387
|
if (render == null) {
|
|
@@ -337,5 +402,5 @@ const useRowProps = (rowProps, collection, expandedIds) => {
|
|
|
337
402
|
portals: (_jsx(RowPortals, { registry: registry, rowProps: rowProps, collection: collection, expandedIds: expandedIds })),
|
|
338
403
|
};
|
|
339
404
|
};
|
|
340
|
-
export { useItemCells, useRowProps, useSectionHeader, ItemPortals, };
|
|
405
|
+
export { useItemCells, useRowProps, useSectionHeader, ItemPortals, NativeItemPortals, };
|
|
341
406
|
//# sourceMappingURL=cells.js.map
|