@gtkx/components 2.0.0-beta.11 → 2.0.0-beta.13

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 (92) hide show
  1. package/README.md +4 -4
  2. package/dist/column-view.d.ts.map +1 -1
  3. package/dist/column-view.js +8 -4
  4. package/dist/column-view.js.map +1 -1
  5. package/dist/combo-row.d.ts.map +1 -1
  6. package/dist/combo-row.js +3 -1
  7. package/dist/combo-row.js.map +1 -1
  8. package/dist/grid-view.d.ts.map +1 -1
  9. package/dist/grid-view.js +4 -3
  10. package/dist/grid-view.js.map +1 -1
  11. package/dist/internal/cells.d.ts +8 -9
  12. package/dist/internal/cells.d.ts.map +1 -1
  13. package/dist/internal/cells.js +98 -83
  14. package/dist/internal/cells.js.map +1 -1
  15. package/dist/internal/collection-index.d.ts +3 -5
  16. package/dist/internal/collection-index.d.ts.map +1 -1
  17. package/dist/internal/collection-index.js +3 -7
  18. package/dist/internal/collection-index.js.map +1 -1
  19. package/dist/internal/collection-model.d.ts +15 -4
  20. package/dist/internal/collection-model.d.ts.map +1 -1
  21. package/dist/internal/collection-model.js +154 -73
  22. package/dist/internal/collection-model.js.map +1 -1
  23. package/dist/internal/collection.d.ts +3 -3
  24. package/dist/internal/collection.d.ts.map +1 -1
  25. package/dist/internal/collection.js +11 -9
  26. package/dist/internal/collection.js.map +1 -1
  27. package/dist/internal/controlled-sync.d.ts +2 -1
  28. package/dist/internal/controlled-sync.d.ts.map +1 -1
  29. package/dist/internal/controlled-sync.js +6 -1
  30. package/dist/internal/controlled-sync.js.map +1 -1
  31. package/dist/internal/drop-down.d.ts +10 -4
  32. package/dist/internal/drop-down.d.ts.map +1 -1
  33. package/dist/internal/drop-down.js +61 -9
  34. package/dist/internal/drop-down.js.map +1 -1
  35. package/dist/internal/expansion.d.ts.map +1 -1
  36. package/dist/internal/expansion.js +46 -19
  37. package/dist/internal/expansion.js.map +1 -1
  38. package/dist/internal/first-header.d.ts +11 -0
  39. package/dist/internal/first-header.d.ts.map +1 -0
  40. package/dist/internal/first-header.js +21 -0
  41. package/dist/internal/first-header.js.map +1 -0
  42. package/dist/internal/keys.d.ts.map +1 -1
  43. package/dist/internal/level-splice.d.ts +27 -0
  44. package/dist/internal/level-splice.d.ts.map +1 -0
  45. package/dist/internal/level-splice.js +98 -0
  46. package/dist/internal/level-splice.js.map +1 -0
  47. package/dist/internal/selection.d.ts.map +1 -1
  48. package/dist/internal/selection.js +23 -16
  49. package/dist/internal/selection.js.map +1 -1
  50. package/dist/internal/tree-expansion.d.ts +3 -1
  51. package/dist/internal/tree-expansion.d.ts.map +1 -1
  52. package/dist/internal/tree-expansion.js +31 -2
  53. package/dist/internal/tree-expansion.js.map +1 -1
  54. package/dist/internal/tree-order.d.ts +2 -1
  55. package/dist/internal/tree-order.d.ts.map +1 -1
  56. package/dist/internal/tree-order.js +3 -2
  57. package/dist/internal/tree-order.js.map +1 -1
  58. package/dist/internal/use-collection.d.ts +1 -0
  59. package/dist/internal/use-collection.d.ts.map +1 -1
  60. package/dist/internal/use-collection.js +6 -2
  61. package/dist/internal/use-collection.js.map +1 -1
  62. package/dist/internal/use-widget-ref.d.ts.map +1 -1
  63. package/dist/list-item-factory.d.ts +1 -1
  64. package/dist/list-item-factory.d.ts.map +1 -1
  65. package/dist/list-item-factory.js +3 -3
  66. package/dist/list-item-factory.js.map +1 -1
  67. package/dist/list-view.d.ts.map +1 -1
  68. package/dist/list-view.js +9 -4
  69. package/dist/list-view.js.map +1 -1
  70. package/dist/types.d.ts +35 -12
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/types.js.map +1 -1
  73. package/package.json +10 -20
  74. package/src/column-view.tsx +8 -4
  75. package/src/combo-row.tsx +4 -1
  76. package/src/grid-view.tsx +3 -2
  77. package/src/internal/cells.tsx +174 -151
  78. package/src/internal/collection-index.ts +7 -14
  79. package/src/internal/collection-model.ts +211 -76
  80. package/src/internal/collection.ts +14 -13
  81. package/src/internal/controlled-sync.ts +8 -1
  82. package/src/internal/drop-down.tsx +112 -19
  83. package/src/internal/expansion.ts +52 -20
  84. package/src/internal/first-header.ts +23 -0
  85. package/src/internal/level-splice.ts +157 -0
  86. package/src/internal/selection.tsx +24 -19
  87. package/src/internal/tree-expansion.ts +43 -1
  88. package/src/internal/tree-order.ts +4 -10
  89. package/src/internal/use-collection.tsx +8 -2
  90. package/src/list-item-factory.tsx +2 -1
  91. package/src/list-view.tsx +10 -2
  92. package/src/types.ts +54 -24
@@ -1,6 +1,7 @@
1
1
  import type * as Gtk from "@gtkx/gi/gtk";
2
2
  import type { ReactElement } from "react";
3
3
  import { GtkFlattenListModel } from "@gtkx/jsx/gtk";
4
+ import { useLatestRef } from "@gtkx/react/internal";
4
5
  import { useLayoutEffect, useMemo, useState } from "react";
5
6
  import type { ExpansionProps, ListItem, ListSection, SelectionProps } from "../types.js";
6
7
  import type { Collection } from "./collection.js";
@@ -14,6 +15,7 @@ type CollectionDataOptions = {
14
15
  items?: ListItem[] | undefined;
15
16
  sections?: ListSection[] | undefined;
16
17
  isFlat?: boolean | undefined;
18
+ onSectionsFilled?: (() => void) | undefined;
17
19
  };
18
20
 
19
21
  type CollectionOptions = CollectionDataOptions & SelectionProps & ExpansionProps;
@@ -44,9 +46,13 @@ function useCollectionData(options: CollectionDataOptions): CollectionDataResult
44
46
  return gtkModel.clear;
45
47
  }, [gtkModel, root, model]);
46
48
 
49
+ const onSectionsFilled = useLatestRef(options.onSectionsFilled);
50
+
47
51
  useLayoutEffect(() => {
48
- gtkModel.sync(index);
49
- }, [gtkModel, index, root, model]);
52
+ gtkModel.sync(index, () => {
53
+ onSectionsFilled.current?.();
54
+ });
55
+ }, [gtkModel, index, root, model, onSectionsFilled]);
50
56
 
51
57
  return {
52
58
  collection,
@@ -10,6 +10,7 @@ import { NativeItemPortals, useItemCells } from "./internal/cells.js";
10
10
  */
11
11
  function ListItemFactory<T extends GObject.Object>({
12
12
  renderItem,
13
+ rowProps,
13
14
  estimatedItemHeight = -1,
14
15
  estimatedItemWidth = -1,
15
16
  }: ListItemFactoryProps<T>): ReactNode {
@@ -19,7 +20,7 @@ function ListItemFactory<T extends GObject.Object>({
19
20
  return (
20
21
  <>
21
22
  <GtkSignalListItemFactory {...cells.handlers} />
22
- <NativeItemPortals registry={cells} render={renderItem} size={size} />
23
+ <NativeItemPortals registry={cells} render={renderItem} rowProps={rowProps} size={size} />
23
24
  </>
24
25
  );
25
26
  }
package/src/list-view.tsx CHANGED
@@ -1,9 +1,12 @@
1
+ import type * as Gtk from "@gtkx/gi/gtk";
1
2
  import type { ReactNode } from "react";
2
3
  import { GtkListView, GtkSignalListItemFactory } from "@gtkx/jsx/gtk";
3
4
  import { omit } from "@gtkx/utils";
4
5
  import type { ListViewProps } from "./types.js";
5
6
  import { ItemPortals, useItemCells, useSectionHeader } from "./internal/cells.js";
7
+ import { showFirstHeader } from "./internal/first-header.js";
6
8
  import { useCollection } from "./internal/use-collection.js";
9
+ import { useWidgetRef } from "./internal/use-widget-ref.js";
7
10
 
8
11
  const LIST_VIEW_PROPS = [
9
12
  "items",
@@ -11,6 +14,7 @@ const LIST_VIEW_PROPS = [
11
14
  "isFlat",
12
15
  "renderItem",
13
16
  "renderHeader",
17
+ "rowProps",
14
18
  "selectedIds",
15
19
  "onSelectionChanged",
16
20
  "selectionMode",
@@ -19,6 +23,7 @@ const LIST_VIEW_PROPS = [
19
23
  "expanderDescriptions",
20
24
  "estimatedItemHeight",
21
25
  "estimatedItemWidth",
26
+ "ref",
22
27
  ] as const satisfies (keyof ListViewProps)[];
23
28
 
24
29
  /**
@@ -26,17 +31,19 @@ const LIST_VIEW_PROPS = [
26
31
  * controlled selection, controlled tree expansion, and estimated item sizing.
27
32
  */
28
33
  function ListView<T = unknown, S = unknown>(props: ListViewProps<T, S>): ReactNode {
29
- const { renderItem, renderHeader, expandedIds, expanderDescriptions } = props;
34
+ const { renderItem, renderHeader, rowProps, expandedIds, expanderDescriptions, ref } = props;
30
35
  const { estimatedItemHeight, estimatedItemWidth } = props;
31
36
  const rest = omit(props, LIST_VIEW_PROPS);
32
37
  const size = { width: estimatedItemWidth ?? -1, height: estimatedItemHeight ?? -1 };
33
- const { collection, selection } = useCollection(props);
38
+ const [view, refCallback] = useWidgetRef<Gtk.ListView>(ref);
39
+ const { collection, selection } = useCollection({ ...props, onSectionsFilled: () => showFirstHeader(view) });
34
40
  const itemCells = useItemCells(size);
35
41
  const header = useSectionHeader(renderHeader, collection, size);
36
42
 
37
43
  return (
38
44
  <>
39
45
  <GtkListView
46
+ ref={refCallback}
40
47
  model={selection}
41
48
  factory={<GtkSignalListItemFactory {...itemCells.handlers} />}
42
49
  {...header.factoryProps}
@@ -45,6 +52,7 @@ function ListView<T = unknown, S = unknown>(props: ListViewProps<T, S>): ReactNo
45
52
  <ItemPortals
46
53
  registry={itemCells}
47
54
  render={renderItem}
55
+ rowProps={rowProps}
48
56
  collection={collection}
49
57
  expandedIds={expandedIds}
50
58
  expanderDescriptions={expanderDescriptions}
package/src/types.ts CHANGED
@@ -17,7 +17,10 @@ import type { ReactNode, RefObject } from "react";
17
17
  * arbitrary value. Nested items form a tree.
18
18
  */
19
19
  type ListItem<T = unknown> = {
20
- /** Stable identifier, unique across the collection, used to preserve identity across updates and selection. */
20
+ /**
21
+ * Stable identifier that names the item in selection and expansion, so keep it unique across the collection.
22
+ * A row keeps its component state while its id stays among the same siblings.
23
+ */
21
24
  id: string;
22
25
  /** Payload handed to the cell renderer as `ListItemRenderArgs.item`. */
23
26
  value: T;
@@ -45,7 +48,10 @@ type ListSection<S = unknown, T = unknown> = {
45
48
  type ListItemRenderArgs<T> = {
46
49
  /** Value of the `ListItem` being rendered. */
47
50
  item: T;
48
- /** Position of the item in the flattened item list, which excludes section headers and collapsed tree rows. */
51
+ /**
52
+ * Position of the item in the flattened item list, which excludes section headers and collapsed tree rows.
53
+ * A drop-down popup filtered by `enableSearch` still passes this position, not the row's place in the results.
54
+ */
49
55
  index: number;
50
56
  /** Depth of the item within a tree, starting at zero for top-level items. */
51
57
  depth?: number | undefined;
@@ -54,9 +60,10 @@ type ListItemRenderArgs<T> = {
54
60
  };
55
61
 
56
62
  /**
57
- * Properties applied to the row that carries one item's cells. A Gtk.ColumnViewRow is not a widget, so
58
- * these are the only handles it offers; anything omitted falls back to the row's own default, which
59
- * leaves the accessibility strings unset rather than setting them to an empty string.
63
+ * Properties applied to the row that carries one item: the Gtk.ListItem of a list or grid, or the
64
+ * Gtk.ColumnViewRow of a table. Neither is a widget, so these are the only handles they offer; anything
65
+ * omitted falls back to the row's own default, which leaves the accessibility strings unset rather than
66
+ * setting them to an empty string.
60
67
  */
61
68
  type ListRowProps = {
62
69
  /** Name a screen reader announces for the row, through `accessible-label`. */
@@ -94,6 +101,14 @@ type ItemSizeProps = {
94
101
 
95
102
  type ListItemFactoryProps<T extends GObject.Object> = ItemSizeProps & {
96
103
  renderItem: ListItemRenderer<T>;
104
+ /** Resolves the props of the row carrying one model object, such as its screen-reader label. */
105
+ rowProps?: ListRowPropsResolver<T> | null | undefined;
106
+ };
107
+
108
+ /** Per-row properties shared by the collection views. */
109
+ type RowPropsProps<T> = {
110
+ /** Resolves the props of the row carrying one item, such as its screen-reader label. */
111
+ rowProps?: ListRowPropsResolver<T> | null | undefined;
97
112
  };
98
113
 
99
114
  /** The flat-collection hint shared by {@link ListView} and {@link ColumnView}. */
@@ -113,7 +128,10 @@ type SelectionProps = {
113
128
  * user's selection is adopted into it.
114
129
  */
115
130
  selectedIds?: string[] | null | undefined;
116
- /** Called with one id per selected row whenever the selection changes, and once on mount. */
131
+ /**
132
+ * Called with one id per selected row when the user or the widget changes the selection, or when an item
133
+ * `selectedIds` names is not in the collection; a `selectedIds` change is not reported back.
134
+ */
117
135
  onSelectionChanged?: ((ids: string[]) => void) | null | undefined;
118
136
  /** How much the user may select, one item at a time unless `MULTIPLE` or `NONE` is given. */
119
137
  selectionMode?: Gtk.SelectionMode | null | undefined;
@@ -138,7 +156,10 @@ type ExpansionProps = {
138
156
  * user's expansion is adopted into it.
139
157
  */
140
158
  expandedIds?: string[] | null | undefined;
141
- /** Called with one id per expanded row, in visible order, whenever expansion changes. */
159
+ /**
160
+ * Called with one id per expanded row, in visible order, when the user or the widget changes expansion, or
161
+ * when a row `expandedIds` names cannot expand; an `expandedIds` change is not reported back.
162
+ */
142
163
  onExpandedChange?: ((ids: string[]) => void) | null | undefined;
143
164
  /**
144
165
  * Wording announced for the expander of every row that can expand, describing what activating it does.
@@ -159,15 +180,18 @@ type SortProps = {
159
180
  };
160
181
 
161
182
  /** The data a collection view renders, either as a plain item list or grouped into sections. */
162
- type SourceProps<T, S> = ({
163
- /** Items to render, nesting through `ListItem.children` for a tree. */
164
- items?: ListItem<T>[] | undefined;
165
- } & Partial<Record<"sections", undefined>> & Partial<Record<"renderHeader", null | undefined>>) | ({
166
- /** Items grouped under section headers. */
167
- sections: ListSection<S, T>[];
168
- /** Renders the header shown above each section. */
169
- renderHeader?: ListSectionRenderer<S> | null | undefined;
170
- } & Partial<Record<"items", undefined>>);
183
+ type SourceProps<T, S> =
184
+ | ({
185
+ /** Items to render, nesting through `ListItem.children` for a tree. */
186
+ items?: ListItem<T>[] | undefined;
187
+ } & Partial<Record<"sections", undefined>> &
188
+ Partial<Record<"renderHeader", null | undefined>>)
189
+ | ({
190
+ /** Items grouped under section headers. */
191
+ sections: ListSection<S, T>[];
192
+ /** Renders the header shown above each section. */
193
+ renderHeader?: ListSectionRenderer<S> | null | undefined;
194
+ } & Partial<Record<"items", undefined>>);
171
195
 
172
196
  /** One column of a {@link ColumnView}, pairing Gtk.ColumnViewColumn props with a cell renderer. */
173
197
  type ColumnViewColumn<T = unknown> = Omit<GtkColumnViewColumnProps, "factory" | "sorter" | "id" | "title"> & {
@@ -179,6 +203,11 @@ type ColumnViewColumn<T = unknown> = Omit<GtkColumnViewColumnProps, "factory" |
179
203
  renderCell: ListItemRenderer<T>;
180
204
  /** Makes the column header clickable, reporting the choice through `onSortChanged`. */
181
205
  isSortable?: boolean | undefined;
206
+ /**
207
+ * Draws the tree expander and depth indentation in this column. Without a visible column marked this way,
208
+ * the first visible column draws them.
209
+ */
210
+ hasExpander?: boolean | undefined;
182
211
  /** Menu element popped up as the column header's context menu, on a right-click. */
183
212
  headerMenu?: ReactNode;
184
213
  };
@@ -189,11 +218,10 @@ type ColumnViewOwnProps<T, S> = SelectionProps &
189
218
  SortProps &
190
219
  SourceProps<T, S> &
191
220
  FlatnessProps &
221
+ RowPropsProps<T> &
192
222
  Omit<ItemSizeProps, "estimatedItemWidth"> & {
193
223
  /** Columns to render, in order; each carries its own cell renderer. */
194
224
  columns: ColumnViewColumn<T>[];
195
- /** Resolves the props of the row carrying one item's cells, such as its screen-reader label. */
196
- rowProps?: ListRowPropsResolver<T> | null | undefined;
197
225
  };
198
226
 
199
227
  /**
@@ -203,7 +231,7 @@ type ColumnViewProps<T = unknown, S = unknown> = Omit<
203
231
  GtkColumnViewProps,
204
232
  "children" | "columns" | "model" | "headerFactory" | "rowFactory" | keyof ColumnViewOwnProps<T, S>
205
233
  > &
206
- ColumnViewOwnProps<T, S>;
234
+ ColumnViewOwnProps<T, S>;
207
235
 
208
236
  /** The declarative collection props {@link DropDown} and `ComboRow` add on top of their widget's own. */
209
237
  type DropDownOwnProps<T, S> = SourceProps<T, S> & {
@@ -222,8 +250,8 @@ type DropDownWidgetProps<Widget, T, S> = Omit<
222
250
  Widget,
223
251
  "model" | "factory" | "listFactory" | "headerFactory" | keyof DropDownOwnProps<T, S>
224
252
  > &
225
- DropDownOwnProps<T, S> &
226
- (SourceProps<T & Primitive, S> | Record<"renderItem", ListItemRenderer<T>>);
253
+ DropDownOwnProps<T, S> &
254
+ (SourceProps<T & Primitive, S> | Record<"renderItem", ListItemRenderer<T>>);
227
255
 
228
256
  /**
229
257
  * Native `Gtk.DropDown` props with declarative collections, controlled selection, and display/popup renderers.
@@ -232,7 +260,8 @@ type DropDownProps<T = unknown, S = unknown> = DropDownWidgetProps<GtkDropDownPr
232
260
 
233
261
  /** The declarative collection props {@link GridView} adds on top of Gtk.GridView's own. */
234
262
  type GridViewOwnProps<T> = ItemSizeProps &
235
- SelectionProps & {
263
+ SelectionProps &
264
+ RowPropsProps<T> & {
236
265
  /** Items to render as cells; a grid is always flat, so `ListItem.children` is ignored. */
237
266
  items?: ListItem<T>[] | undefined;
238
267
  /** Renders the contents of one cell. */
@@ -250,7 +279,8 @@ type ListViewOwnProps<T, S> = ItemSizeProps &
250
279
  SelectionProps &
251
280
  ExpansionProps &
252
281
  SourceProps<T, S> &
253
- FlatnessProps & {
282
+ FlatnessProps &
283
+ RowPropsProps<T> & {
254
284
  /** Renders the contents of one row. */
255
285
  renderItem: ListItemRenderer<T>;
256
286
  };
@@ -263,7 +293,7 @@ type ListViewProps<T = unknown, S = unknown> = Omit<
263
293
  GtkListViewProps,
264
294
  "model" | "factory" | "headerFactory" | keyof ListViewOwnProps<T, S>
265
295
  > &
266
- ListViewOwnProps<T, S>;
296
+ ListViewOwnProps<T, S>;
267
297
 
268
298
  /**
269
299
  * Native `Adw.ComboRow` props with declarative collections, controlled selection, and display/popup renderers.