@gtkx/components 2.0.0-beta.10 → 2.0.0-beta.12

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.
Files changed (86) hide show
  1. package/README.md +8 -168
  2. package/dist/column-view.d.ts.map +1 -1
  3. package/dist/column-view.js +20 -10
  4. package/dist/column-view.js.map +1 -1
  5. package/dist/grid-view.js +1 -1
  6. package/dist/index.d.ts +4 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal/cells.d.ts +10 -7
  11. package/dist/internal/cells.d.ts.map +1 -1
  12. package/dist/internal/cells.js +88 -51
  13. package/dist/internal/cells.js.map +1 -1
  14. package/dist/internal/collection-index.d.ts +3 -2
  15. package/dist/internal/collection-index.d.ts.map +1 -1
  16. package/dist/internal/collection-index.js +3 -3
  17. package/dist/internal/collection-index.js.map +1 -1
  18. package/dist/internal/collection-model.d.ts +23 -2
  19. package/dist/internal/collection-model.d.ts.map +1 -1
  20. package/dist/internal/collection-model.js +118 -98
  21. package/dist/internal/collection-model.js.map +1 -1
  22. package/dist/internal/collection.d.ts +5 -4
  23. package/dist/internal/collection.d.ts.map +1 -1
  24. package/dist/internal/collection.js +20 -21
  25. package/dist/internal/collection.js.map +1 -1
  26. package/dist/internal/controlled-sync.d.ts +6 -8
  27. package/dist/internal/controlled-sync.d.ts.map +1 -1
  28. package/dist/internal/controlled-sync.js +3 -3
  29. package/dist/internal/controlled-sync.js.map +1 -1
  30. package/dist/internal/drop-down.d.ts.map +1 -1
  31. package/dist/internal/drop-down.js +44 -45
  32. package/dist/internal/drop-down.js.map +1 -1
  33. package/dist/internal/expansion.js +4 -4
  34. package/dist/internal/expansion.js.map +1 -1
  35. package/dist/internal/keys.d.ts.map +1 -1
  36. package/dist/internal/selection.d.ts +1 -0
  37. package/dist/internal/selection.d.ts.map +1 -1
  38. package/dist/internal/selection.js +6 -6
  39. package/dist/internal/selection.js.map +1 -1
  40. package/dist/internal/tree-expansion.d.ts +1 -1
  41. package/dist/internal/tree-expansion.d.ts.map +1 -1
  42. package/dist/internal/tree-expansion.js +3 -12
  43. package/dist/internal/tree-expansion.js.map +1 -1
  44. package/dist/internal/tree-order.d.ts +1 -1
  45. package/dist/internal/tree-order.d.ts.map +1 -1
  46. package/dist/internal/tree-order.js +33 -77
  47. package/dist/internal/tree-order.js.map +1 -1
  48. package/dist/internal/use-collection.d.ts +5 -1
  49. package/dist/internal/use-collection.d.ts.map +1 -1
  50. package/dist/internal/use-collection.js +21 -7
  51. package/dist/internal/use-collection.js.map +1 -1
  52. package/dist/internal/use-widget-ref.d.ts.map +1 -1
  53. package/dist/list-item-factory.d.ts +10 -0
  54. package/dist/list-item-factory.d.ts.map +1 -0
  55. package/dist/list-item-factory.js +14 -0
  56. package/dist/list-item-factory.js.map +1 -0
  57. package/dist/list-view.js +1 -1
  58. package/dist/tab-collection.d.ts +9 -0
  59. package/dist/tab-collection.d.ts.map +1 -0
  60. package/dist/tab-collection.js +114 -0
  61. package/dist/tab-collection.js.map +1 -0
  62. package/dist/toast.d.ts +3 -5
  63. package/dist/toast.d.ts.map +1 -1
  64. package/dist/toast.js +3 -12
  65. package/dist/toast.js.map +1 -1
  66. package/dist/types.d.ts +67 -51
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/types.js.map +1 -1
  69. package/package.json +13 -21
  70. package/src/column-view.tsx +23 -12
  71. package/src/index.ts +7 -2
  72. package/src/internal/cells.tsx +155 -103
  73. package/src/internal/collection-index.ts +8 -6
  74. package/src/internal/collection-model.ts +156 -134
  75. package/src/internal/collection.ts +28 -24
  76. package/src/internal/controlled-sync.ts +9 -12
  77. package/src/internal/drop-down.tsx +63 -63
  78. package/src/internal/expansion.ts +4 -4
  79. package/src/internal/selection.tsx +8 -8
  80. package/src/internal/tree-expansion.ts +3 -23
  81. package/src/internal/tree-order.ts +34 -130
  82. package/src/internal/use-collection.tsx +29 -8
  83. package/src/list-item-factory.tsx +27 -0
  84. package/src/tab-collection.tsx +124 -0
  85. package/src/toast.tsx +4 -18
  86. package/src/types.ts +81 -55
@@ -0,0 +1,124 @@
1
+ import * as Adw from "@gtkx/gi/adw";
2
+ import { AdwTabPage } from "@gtkx/jsx/adw";
3
+ import { createRoot, flushSync, type Root } from "@gtkx/react";
4
+ import { getClassType } from "@gtkx/runtime";
5
+ import { createRef, type RefObject, useEffect } from "react";
6
+ import type { TabCollection, TabCollectionOptions } from "./types.js";
7
+
8
+ type TabHandle<T> = {
9
+ root: Root;
10
+ page: RefObject<Adw.TabPage | null>;
11
+ getPage: () => Adw.TabPage | null;
12
+ parent: Adw.TabPage | undefined;
13
+ item: T;
14
+ };
15
+
16
+ type ManagedTabProps<T> = {
17
+ handle: TabHandle<T>;
18
+ item: T;
19
+ options: TabCollectionOptions<T>;
20
+ forget: (handle: TabHandle<T>) => void;
21
+ };
22
+
23
+ const ManagedTab = <T,>({ handle, item, options, forget }: ManagedTabProps<T>) => {
24
+ const { page: pageRef, parent, getPage } = handle;
25
+ useEffect(() => () => forget(handle), [handle, forget]);
26
+ return <AdwTabPage {...options.pageProps(item, getPage)} ref={pageRef} parent={parent} />;
27
+ };
28
+
29
+ const ownerOf = (page: Adw.TabPage): Adw.TabView => {
30
+ const owner = page.getChild().getAncestor(getClassType(Adw.TabView));
31
+ if (!(owner instanceof Adw.TabView)) throw new Error("The tab has no native view");
32
+ return owner;
33
+ };
34
+
35
+ /**
36
+ * Creates a collection of JSX pages whose React state survives native transfers and source-window
37
+ * closure. Call append from an event handler because it commits synchronously. Page content lives in
38
+ * independent roots: pass context-dependent values through the item or wrap the content in providers.
39
+ */
40
+ const createTabCollection = <T,>(options: TabCollectionOptions<T>): TabCollection<T> => {
41
+ const handles = new Set<TabHandle<T>>();
42
+ const forget = (handle: TabHandle<T>) => {
43
+ handles.delete(handle);
44
+ };
45
+ const find = (page: Adw.TabPage) => [...handles].find((handle) => handle.page.current === page);
46
+ const render = (handle: TabHandle<T>) => {
47
+ handle.root.render(<ManagedTab handle={handle} item={handle.item} options={options} forget={forget} />);
48
+ };
49
+ const remove = (handle: TabHandle<T>) => {
50
+ handles.delete(handle);
51
+ handle.root.unmount();
52
+ };
53
+
54
+ return {
55
+ append: (view, item, appendOptions = {}) => {
56
+ if (appendOptions.parent && ownerOf(appendOptions.parent) !== view) {
57
+ throw new RangeError("The parent page belongs to another tab view");
58
+ }
59
+ const pageRef = createRef<Adw.TabPage>();
60
+ const handle: TabHandle<T> = {
61
+ root: createRoot(view),
62
+ page: pageRef,
63
+ getPage: () => pageRef.current,
64
+ parent: appendOptions.parent,
65
+ item,
66
+ };
67
+ handles.add(handle);
68
+ try {
69
+ flushSync(() => render(handle));
70
+ } catch (error) {
71
+ remove(handle);
72
+ throw error;
73
+ }
74
+ const page = handle.page.current;
75
+ if (page === null) {
76
+ remove(handle);
77
+ throw new Error("The tab page did not render");
78
+ }
79
+ if (appendOptions.parent === undefined) {
80
+ view.reorderPage(page, page.getPinned() ? view.getNPinnedPages() - 1 : view.getNPages() - 1);
81
+ }
82
+ if (appendOptions.select !== false) view.setSelectedPage(page);
83
+ return page;
84
+ },
85
+ get: (page) => find(page)?.item,
86
+ update: (page, item) => {
87
+ const handle = find(page);
88
+ if (handle === undefined) throw new Error("The tab is not managed by this collection");
89
+ handle.item = item;
90
+ render(handle);
91
+ },
92
+ remove: (page) => {
93
+ const handle = find(page);
94
+ if (handle) remove(handle);
95
+ },
96
+ removeView: (view) => {
97
+ const pages = Array.from({ length: view.getNPages() }, (_, index) => view.getNthPage(index));
98
+ for (const page of pages) {
99
+ const handle = find(page);
100
+ if (handle) remove(handle);
101
+ }
102
+ },
103
+ transfer: (page, target, position) => {
104
+ if (find(page) === undefined) throw new Error("The tab is not managed by this collection");
105
+ const source = ownerOf(page);
106
+ const minimum = page.getPinned() ? 0 : target.getNPinnedPages();
107
+ const maximum = page.getPinned() ? target.getNPinnedPages() : target.getNPages();
108
+ const index = position ?? maximum;
109
+ if (!Number.isInteger(index) || index < minimum || index > maximum) {
110
+ throw new RangeError("The position is outside the tab's pinned or unpinned group");
111
+ }
112
+ if (source === target) {
113
+ target.reorderPage(page, Math.min(index, maximum - 1));
114
+ } else {
115
+ source.transferPage(page, target, index);
116
+ }
117
+ },
118
+ dispose: () => {
119
+ for (const handle of [...handles]) remove(handle);
120
+ },
121
+ };
122
+ };
123
+
124
+ export { createTabCollection };
package/src/toast.tsx CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode, RefObject } from "react";
2
2
  import * as Adw from "@gtkx/gi/adw";
3
3
  import { createContext, useContext, useMemo } from "react";
4
- import type { ToastController, ToastOptions, ToastOverlayController, ToastProviderProps } from "./types.js";
4
+ import type { ToastController, ToastOptions, ToastProviderProps } from "./types.js";
5
5
 
6
6
  type OverlayRef = RefObject<Adw.ToastOverlay | null>;
7
7
 
@@ -11,7 +11,7 @@ const useOverlayRef = (): OverlayRef => {
11
11
  const overlayRef = useContext(ToastContext);
12
12
 
13
13
  if (overlayRef === null) {
14
- throw new Error("useToast and useToastOverlay must be used within a ToastProvider");
14
+ throw new Error("useToast must be used within a ToastProvider");
15
15
  }
16
16
 
17
17
  return overlayRef;
@@ -36,7 +36,7 @@ const buildToast = (options: ToastOptions): Adw.Toast => {
36
36
  return toast;
37
37
  };
38
38
 
39
- /** Shares an Adw.ToastOverlay reference with the toast hooks in every descendant. */
39
+ /** Shares an Adw.ToastOverlay reference with useToast in every descendant. */
40
40
  function ToastProvider(props: ToastProviderProps): ReactNode {
41
41
  return <ToastContext.Provider value={props.overlayRef}>{props.children}</ToastContext.Provider>;
42
42
  }
@@ -53,20 +53,6 @@ function useToast(): ToastController {
53
53
 
54
54
  return toast;
55
55
  },
56
- dismiss: (toast: Adw.Toast) => {
57
- toast.dismiss();
58
- },
59
- }),
60
- [overlayRef],
61
- );
62
- }
63
-
64
- /** Returns a {@link ToastOverlayController} for the nearest provider's overlay as a whole. */
65
- function useToastOverlay(): ToastOverlayController {
66
- const overlayRef = useOverlayRef();
67
-
68
- return useMemo<ToastOverlayController>(
69
- () => ({
70
56
  dismissAll: () => {
71
57
  overlayRef.current?.dismissAll();
72
58
  },
@@ -75,4 +61,4 @@ function useToastOverlay(): ToastOverlayController {
75
61
  );
76
62
  }
77
63
 
78
- export { ToastProvider, useToast, useToastOverlay };
64
+ export { ToastProvider, useToast };
package/src/types.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type * as Adw from "@gtkx/gi/adw";
2
+ import type * as GObject from "@gtkx/gi/gobject";
2
3
  import type * as Gtk from "@gtkx/gi/gtk";
3
- import type { AdwComboRowProps, AdwToastProps } from "@gtkx/jsx/adw";
4
+ import type { AdwComboRowProps, AdwTabPageProps, AdwToastProps } from "@gtkx/jsx/adw";
4
5
  import type {
5
6
  GtkColumnViewColumnProps,
6
7
  GtkColumnViewProps,
@@ -8,6 +9,7 @@ import type {
8
9
  GtkGridViewProps,
9
10
  GtkListViewProps,
10
11
  } from "@gtkx/jsx/gtk";
12
+ import type { Primitive } from "@gtkx/utils";
11
13
  import type { ReactNode, RefObject } from "react";
12
14
 
13
15
  /**
@@ -15,11 +17,11 @@ import type { ReactNode, RefObject } from "react";
15
17
  * arbitrary value. Nested items form a tree.
16
18
  */
17
19
  type ListItem<T = unknown> = {
18
- /** Stable identifier used to track the item across updates and selection, naming every row that carries it. */
20
+ /** Stable identifier, unique across the collection, used to preserve identity across updates and selection. */
19
21
  id: string;
20
22
  /** Payload handed to the cell renderer as `ListItemRenderArgs.item`. */
21
23
  value: T;
22
- /** Child items nested under this one, which turn a plain item list into a tree, read only as rows are drawn. */
24
+ /** Child items in an acyclic tree, read only as rows are drawn. */
23
25
  children?: ListItem<T>[] | undefined;
24
26
  /** Hides the tree expander arrow even when the item has children, through `hide-expander`. */
25
27
  shouldHideExpander?: boolean | undefined;
@@ -31,7 +33,7 @@ type ListItem<T = unknown> = {
31
33
 
32
34
  /** A group of items rendered under a shared section header. */
33
35
  type ListSection<S = unknown, T = unknown> = {
34
- /** Stable identifier used to track the section across updates. */
36
+ /** Stable identifier, unique among sections, used to track the section across updates. */
35
37
  id: string;
36
38
  /** Payload handed to the section header renderer as `ListSectionRenderArgs.section`. */
37
39
  value: S;
@@ -90,6 +92,10 @@ type ItemSizeProps = {
90
92
  estimatedItemWidth?: number | undefined;
91
93
  };
92
94
 
95
+ type ListItemFactoryProps<T extends GObject.Object> = ItemSizeProps & {
96
+ renderItem: ListItemRenderer<T>;
97
+ };
98
+
93
99
  /** The flat-collection hint shared by {@link ListView} and {@link ColumnView}. */
94
100
  type FlatnessProps = {
95
101
  /**
@@ -104,8 +110,7 @@ type FlatnessProps = {
104
110
  type SelectionProps = {
105
111
  /**
106
112
  * Ids of the items to keep selected; omitting it keeps nothing selected, and `onSelectionChanged` is how a
107
- * user's selection is adopted into it. An id repeated in several branches of a tree names every matching row,
108
- * and a single-selection view takes the first of them.
113
+ * user's selection is adopted into it.
109
114
  */
110
115
  selectedIds?: string[] | null | undefined;
111
116
  /** Called with one id per selected row whenever the selection changes, and once on mount. */
@@ -130,9 +135,7 @@ type ExpanderDescriptions = {
130
135
  type ExpansionProps = {
131
136
  /**
132
137
  * Ids of the items to keep expanded; omitting it keeps every row collapsed, and `onExpandedChange` is how a
133
- * user's expansion is adopted into it. An id repeated in several branches names every matching row, so all of
134
- * them expand together. An item whose children lead back to itself expands one level at a time, since a row
135
- * repeating an item already expanded above it stays collapsed.
138
+ * user's expansion is adopted into it.
136
139
  */
137
140
  expandedIds?: string[] | null | undefined;
138
141
  /** Called with one id per expanded row, in visible order, whenever expansion changes. */
@@ -156,12 +159,18 @@ type SortProps = {
156
159
  };
157
160
 
158
161
  /** The data a collection view renders, either as a plain item list or grouped into sections. */
159
- type SourceProps<T, S> = {
160
- /** Items to render, nesting through `ListItem.children` for a tree; ignored once `sections` is given. */
161
- items?: ListItem<T>[] | undefined;
162
- /** Items grouped under section headers, rendered in place of `items`. */
163
- sections?: ListSection<S, T>[] | undefined;
164
- };
162
+ type SourceProps<T, S> =
163
+ | ({
164
+ /** Items to render, nesting through `ListItem.children` for a tree. */
165
+ items?: ListItem<T>[] | undefined;
166
+ } & Partial<Record<"sections", undefined>> &
167
+ Partial<Record<"renderHeader", null | undefined>>)
168
+ | ({
169
+ /** Items grouped under section headers. */
170
+ sections: ListSection<S, T>[];
171
+ /** Renders the header shown above each section. */
172
+ renderHeader?: ListSectionRenderer<S> | null | undefined;
173
+ } & Partial<Record<"items", undefined>>);
165
174
 
166
175
  /** One column of a {@link ColumnView}, pairing Gtk.ColumnViewColumn props with a cell renderer. */
167
176
  type ColumnViewColumn<T = unknown> = Omit<GtkColumnViewColumnProps, "factory" | "sorter" | "id" | "title"> & {
@@ -186,36 +195,29 @@ type ColumnViewOwnProps<T, S> = SelectionProps &
186
195
  Omit<ItemSizeProps, "estimatedItemWidth"> & {
187
196
  /** Columns to render, in order; each carries its own cell renderer. */
188
197
  columns: ColumnViewColumn<T>[];
189
- /** Renders the header shown above each section. */
190
- renderHeader?: ListSectionRenderer<S> | null | undefined;
191
198
  /** Resolves the props of the row carrying one item's cells, such as its screen-reader label. */
192
199
  rowProps?: ListRowPropsResolver<T> | null | undefined;
193
200
  };
194
201
 
195
202
  /**
196
- * Props for {@link ColumnView}. Combines the underlying Gtk.ColumnView props with
197
- * declarative collection props: flat items or grouped sections, controlled selection
198
- * and expansion, sorting (sortColumn, sortOrder, onSortChanged), an optional section
199
- * header renderer, per-row props, and the columns to render.
203
+ * Native `Gtk.ColumnView` props with declarative columns and collections, controlled selection, expansion, and sorting.
200
204
  */
201
205
  type ColumnViewProps<T = unknown, S = unknown> = Omit<
202
206
  GtkColumnViewProps,
203
- "columns" | "model" | "headerFactory" | "rowFactory" | keyof ColumnViewOwnProps<T, S>
207
+ "children" | "columns" | "model" | "headerFactory" | "rowFactory" | keyof ColumnViewOwnProps<T, S>
204
208
  > &
205
- ColumnViewOwnProps<T, S>;
209
+ ColumnViewOwnProps<T, S>;
206
210
 
207
211
  /** The declarative collection props {@link DropDown} and `ComboRow` add on top of their widget's own. */
208
212
  type DropDownOwnProps<T, S> = SourceProps<T, S> & {
209
213
  /** Id of the currently selected item, making the selection controlled. */
210
- selectedId?: string | null | undefined;
211
- /** Called with the id of the item that became selected. */
212
- onSelectionChanged?: ((id: string) => void) | null | undefined;
213
- /** Renders the collapsed display, and the popup rows too unless `renderListItem` is given. */
214
+ selectedId?: string | undefined;
215
+ /** Called with the selected id, or `null` when the model becomes empty. */
216
+ onSelectionChanged?: ((id: string | null) => void) | null | undefined;
217
+ /** Renders the collapsed display and, unless overridden, the popup rows. Required for non-primitive values. */
214
218
  renderItem?: ListItemRenderer<T> | null | undefined;
215
219
  /** Renderer for items in the open popup list, falling back to renderItem when omitted. */
216
220
  renderListItem?: ListItemRenderer<T> | null | undefined;
217
- /** Renderer for section headers in the popup list. */
218
- renderHeader?: ListSectionRenderer<S> | null | undefined;
219
221
  };
220
222
 
221
223
  /** A drop-down-shaped widget's props with its model and factories swapped for the declarative collection props. */
@@ -223,12 +225,11 @@ type DropDownWidgetProps<Widget, T, S> = Omit<
223
225
  Widget,
224
226
  "model" | "factory" | "listFactory" | "headerFactory" | keyof DropDownOwnProps<T, S>
225
227
  > &
226
- DropDownOwnProps<T, S>;
228
+ DropDownOwnProps<T, S> &
229
+ (SourceProps<T & Primitive, S> | Record<"renderItem", ListItemRenderer<T>>);
227
230
 
228
231
  /**
229
- * Props for {@link DropDown}. Combines the underlying Gtk.DropDown props with the declarative
230
- * collection props: flat items or grouped sections, controlled single selection, and renderers
231
- * for the collapsed display, popup rows, and popup section headers.
232
+ * Native `Gtk.DropDown` props with declarative collections, controlled selection, and display/popup renderers.
232
233
  */
233
234
  type DropDownProps<T = unknown, S = unknown> = DropDownWidgetProps<GtkDropDownProps, T, S>;
234
235
 
@@ -242,9 +243,7 @@ type GridViewOwnProps<T> = ItemSizeProps &
242
243
  };
243
244
 
244
245
  /**
245
- * Props for {@link GridView}. Combines the underlying Gtk.GridView props with
246
- * declarative collection props: items, a per-cell renderItem, controlled selection,
247
- * and estimated item sizing.
246
+ * Native `Gtk.GridView` props with declarative cells, controlled selection, and estimated sizing.
248
247
  */
249
248
  type GridViewProps<T = unknown> = Omit<GtkGridViewProps, "model" | "factory" | keyof GridViewOwnProps<T>> &
250
249
  GridViewOwnProps<T>;
@@ -257,26 +256,20 @@ type ListViewOwnProps<T, S> = ItemSizeProps &
257
256
  FlatnessProps & {
258
257
  /** Renders the contents of one row. */
259
258
  renderItem: ListItemRenderer<T>;
260
- /** Renders the header shown above each section. */
261
- renderHeader?: ListSectionRenderer<S> | null | undefined;
262
259
  };
263
260
 
264
261
  /**
265
- * Props for {@link ListView}. Combines the underlying Gtk.ListView props with
266
- * declarative collection props: flat items or grouped sections, a per-row renderItem,
267
- * an optional section header renderer, controlled selection and expansion, and
268
- * estimated item sizing.
262
+ * Native `Gtk.ListView` props with declarative rows and sections, controlled selection and expansion,
263
+ * and estimated sizing.
269
264
  */
270
265
  type ListViewProps<T = unknown, S = unknown> = Omit<
271
266
  GtkListViewProps,
272
267
  "model" | "factory" | "headerFactory" | keyof ListViewOwnProps<T, S>
273
268
  > &
274
- ListViewOwnProps<T, S>;
269
+ ListViewOwnProps<T, S>;
275
270
 
276
271
  /**
277
- * Props for {@link ComboRow}. Combines the underlying Adw.ComboRow props with the declarative
278
- * collection props: flat items or grouped sections, controlled single selection, and renderers
279
- * for the row display, popup rows, and popup section headers.
272
+ * Native `Adw.ComboRow` props with declarative collections, controlled selection, and display/popup renderers.
280
273
  */
281
274
  type ComboRowProps<T = unknown, S = unknown> = DropDownWidgetProps<AdwComboRowProps, T, S>;
282
275
  /**
@@ -285,16 +278,10 @@ type ComboRowProps<T = unknown, S = unknown> = DropDownWidgetProps<AdwComboRowPr
285
278
  */
286
279
  type ToastOptions = Adw.ToastConstructorProps & Pick<AdwToastProps, "onButtonClicked" | "onDismissed">;
287
280
 
288
- /** Imperative controls for individual toasts, returned by {@link useToast}. */
281
+ /** Imperative controls for toasts, returned by {@link useToast}. */
289
282
  type ToastController = {
290
283
  /** Builds a toast, shows it through the overlay, and returns it. */
291
284
  show: (options?: ToastOptions) => Adw.Toast;
292
- /** Dismisses a single toast, typically one returned by `ToastController.show`. */
293
- dismiss: (toast: Adw.Toast) => void;
294
- };
295
-
296
- /** Imperative controls for the overlay as a whole, returned by {@link useToastOverlay}. */
297
- type ToastOverlayController = {
298
285
  /** Dismisses the shown toast and every queued one. */
299
286
  dismissAll: () => void;
300
287
  };
@@ -303,10 +290,46 @@ type ToastOverlayController = {
303
290
  type ToastProviderProps = {
304
291
  /** Ref also given to the `AdwToastOverlay` the toasts appear over. */
305
292
  overlayRef: RefObject<Adw.ToastOverlay | null>;
306
- /** Subtree whose `useToast` and `useToastOverlay` calls target that overlay. */
293
+ /** Subtree whose `useToast` calls target that overlay. */
307
294
  children?: ReactNode | undefined;
308
295
  };
309
296
 
297
+ /** Describes the JSX page rendered for each value in a {@link TabCollection}. */
298
+ type TabCollectionOptions<T> = {
299
+ /** Native page props and JSX content. Call getPage in event handlers to access the mounted page. The collection owns its ref and parent relationship. */
300
+ pageProps: (item: T, getPage: () => Adw.TabPage | null) => Omit<AdwTabPageProps, "ref" | "parent">;
301
+ };
302
+
303
+ /** Options for adding a page to a {@link TabCollection}. */
304
+ type TabAppendOptions = {
305
+ /** Inserts a related page after this parent and its descendants, using native tab ancestry. */
306
+ parent?: Adw.TabPage | undefined;
307
+ /** Selects the new page by default. */
308
+ select?: boolean | undefined;
309
+ };
310
+
311
+ /**
312
+ * Owns independent JSX tab roots across native view transfers. Its lifetime can span several windows.
313
+ * Remove a page after accepting its native close request, remove a view's pages before destroying that
314
+ * view, and dispose the collection when its owner is finished.
315
+ */
316
+ type TabCollection<T> = {
317
+ /** Renders synchronously and returns the native page, including from an overview's create-tab handler. */
318
+ append: (view: Adw.TabView, item: T, options?: TabAppendOptions) => Adw.TabPage;
319
+ /** Returns a managed page's current value, or undefined for an unmanaged page. */
320
+ get: (page: Adw.TabPage) => T | undefined;
321
+ /** Updates the value and rerenders the existing JSX root, preserving component state and native identity. */
322
+ update: (page: Adw.TabPage, item: T) => void;
323
+ /** Unmounts a managed page from its current native owner; already removed pages are ignored. */
324
+ remove: (page: Adw.TabPage) => void;
325
+ /** Unmounts this collection's pages currently belonging to the given view, including transferred pages. */
326
+ removeView: (view: Adw.TabView) => void;
327
+ /** Moves a managed page to another view, appending within its pinned or unpinned group by default. */
328
+ transfer: (page: Adw.TabPage, target: Adw.TabView, position?: number) => void;
329
+ /** Unmounts every managed page. The collection may subsequently be reused. */
330
+ dispose: () => void;
331
+ };
332
+
310
333
  export {
311
334
  type SelectionProps,
312
335
  type ExpanderDescriptions,
@@ -319,6 +342,7 @@ export {
319
342
  type ListRowProps,
320
343
  type ListSectionRenderArgs,
321
344
  type ListItemRenderer,
345
+ type ListItemFactoryProps,
322
346
  type ListRowPropsResolver,
323
347
  type ListSectionRenderer,
324
348
  type ColumnViewColumn,
@@ -329,6 +353,8 @@ export {
329
353
  type ComboRowProps,
330
354
  type ToastOptions,
331
355
  type ToastController,
332
- type ToastOverlayController,
333
356
  type ToastProviderProps,
357
+ type TabAppendOptions,
358
+ type TabCollection,
359
+ type TabCollectionOptions,
334
360
  };