@gtkx/components 1.0.0-rc.1 → 1.0.0-rc.3

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 (220) hide show
  1. package/dist/adw/combo-row.d.ts +11 -0
  2. package/dist/adw/combo-row.d.ts.map +1 -0
  3. package/dist/adw/combo-row.js +14 -0
  4. package/dist/adw/combo-row.js.map +1 -0
  5. package/dist/adw/index.d.ts +4 -0
  6. package/dist/adw/index.d.ts.map +1 -0
  7. package/dist/adw/index.js +3 -0
  8. package/dist/adw/index.js.map +1 -0
  9. package/dist/adw/toast.d.ts +10 -0
  10. package/dist/adw/toast.d.ts.map +1 -0
  11. package/dist/adw/toast.js +51 -0
  12. package/dist/adw/toast.js.map +1 -0
  13. package/dist/adw/types.d.ts +35 -0
  14. package/dist/adw/types.d.ts.map +1 -0
  15. package/dist/adw/types.js +2 -0
  16. package/dist/adw/types.js.map +1 -0
  17. package/dist/column-view.d.ts +7 -29
  18. package/dist/column-view.d.ts.map +1 -1
  19. package/dist/column-view.js +98 -70
  20. package/dist/column-view.js.map +1 -1
  21. package/dist/drop-down.d.ts +7 -28
  22. package/dist/drop-down.d.ts.map +1 -1
  23. package/dist/drop-down.js +10 -86
  24. package/dist/drop-down.js.map +1 -1
  25. package/dist/grid-view.d.ts +6 -16
  26. package/dist/grid-view.d.ts.map +1 -1
  27. package/dist/grid-view.js +25 -33
  28. package/dist/grid-view.js.map +1 -1
  29. package/dist/index.d.ts +6 -12
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1 -6
  32. package/dist/index.js.map +1 -1
  33. package/dist/internal/cells.d.ts +50 -0
  34. package/dist/internal/cells.d.ts.map +1 -0
  35. package/dist/internal/cells.js +185 -0
  36. package/dist/internal/cells.js.map +1 -0
  37. package/dist/internal/collection-index.d.ts +21 -0
  38. package/dist/internal/collection-index.d.ts.map +1 -0
  39. package/dist/internal/collection-index.js +106 -0
  40. package/dist/internal/collection-index.js.map +1 -0
  41. package/dist/internal/collection-model.d.ts +12 -0
  42. package/dist/internal/collection-model.d.ts.map +1 -0
  43. package/dist/internal/collection-model.js +164 -0
  44. package/dist/internal/collection-model.js.map +1 -0
  45. package/dist/internal/collection.d.ts +18 -0
  46. package/dist/internal/collection.d.ts.map +1 -0
  47. package/dist/internal/collection.js +64 -0
  48. package/dist/internal/collection.js.map +1 -0
  49. package/dist/internal/drop-down.d.ts +16 -0
  50. package/dist/internal/drop-down.d.ts.map +1 -0
  51. package/dist/internal/drop-down.js +110 -0
  52. package/dist/internal/drop-down.js.map +1 -0
  53. package/dist/internal/expansion.d.ts +9 -0
  54. package/dist/internal/expansion.d.ts.map +1 -0
  55. package/dist/internal/expansion.js +74 -0
  56. package/dist/internal/expansion.js.map +1 -0
  57. package/dist/internal/selection.d.ts +13 -0
  58. package/dist/internal/selection.d.ts.map +1 -0
  59. package/dist/internal/selection.js +100 -0
  60. package/dist/internal/selection.js.map +1 -0
  61. package/dist/internal/use-collection.d.ts +17 -0
  62. package/dist/internal/use-collection.d.ts.map +1 -0
  63. package/dist/internal/use-collection.js +34 -0
  64. package/dist/internal/use-collection.js.map +1 -0
  65. package/dist/internal/use-widget-ref.d.ts +4 -0
  66. package/dist/internal/use-widget-ref.d.ts.map +1 -0
  67. package/dist/internal/use-widget-ref.js +8 -0
  68. package/dist/internal/use-widget-ref.js.map +1 -0
  69. package/dist/list-view.d.ts +5 -20
  70. package/dist/list-view.d.ts.map +1 -1
  71. package/dist/list-view.js +32 -53
  72. package/dist/list-view.js.map +1 -1
  73. package/dist/size-group.d.ts +8 -16
  74. package/dist/size-group.d.ts.map +1 -1
  75. package/dist/size-group.js +35 -51
  76. package/dist/size-group.js.map +1 -1
  77. package/dist/types.d.ts +98 -27
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js.map +1 -1
  80. package/package.json +17 -6
  81. package/src/adw/combo-row.tsx +20 -0
  82. package/src/adw/index.ts +9 -0
  83. package/src/adw/toast.tsx +74 -0
  84. package/src/adw/types.ts +45 -0
  85. package/src/column-view.tsx +176 -160
  86. package/src/drop-down.tsx +12 -185
  87. package/src/grid-view.tsx +29 -73
  88. package/src/index.ts +18 -26
  89. package/src/internal/cells.tsx +345 -0
  90. package/src/internal/collection-index.ts +168 -0
  91. package/src/internal/collection-model.ts +246 -0
  92. package/src/internal/collection.ts +104 -0
  93. package/src/internal/drop-down.tsx +186 -0
  94. package/src/internal/expansion.ts +122 -0
  95. package/src/internal/selection.tsx +162 -0
  96. package/src/internal/use-collection.tsx +57 -0
  97. package/src/internal/use-widget-ref.ts +11 -0
  98. package/src/list-view.tsx +43 -139
  99. package/src/size-group.tsx +63 -82
  100. package/src/types.ts +158 -28
  101. package/dist/cell.d.ts +0 -30
  102. package/dist/cell.d.ts.map +0 -1
  103. package/dist/cell.js +0 -45
  104. package/dist/cell.js.map +0 -1
  105. package/dist/column-view-column.d.ts +0 -27
  106. package/dist/column-view-column.d.ts.map +0 -1
  107. package/dist/column-view-column.js +0 -30
  108. package/dist/column-view-column.js.map +0 -1
  109. package/dist/constraint-layout-apply.d.ts +0 -55
  110. package/dist/constraint-layout-apply.d.ts.map +0 -1
  111. package/dist/constraint-layout-apply.js +0 -107
  112. package/dist/constraint-layout-apply.js.map +0 -1
  113. package/dist/constraint-layout.d.ts +0 -20
  114. package/dist/constraint-layout.d.ts.map +0 -1
  115. package/dist/constraint-layout.js +0 -88
  116. package/dist/constraint-layout.js.map +0 -1
  117. package/dist/fixed.d.ts +0 -26
  118. package/dist/fixed.d.ts.map +0 -1
  119. package/dist/fixed.js +0 -40
  120. package/dist/fixed.js.map +0 -1
  121. package/dist/grid.d.ts +0 -27
  122. package/dist/grid.d.ts.map +0 -1
  123. package/dist/grid.js +0 -48
  124. package/dist/grid.js.map +0 -1
  125. package/dist/hooks/use-cell-containers.d.ts +0 -18
  126. package/dist/hooks/use-cell-containers.d.ts.map +0 -1
  127. package/dist/hooks/use-cell-containers.js +0 -67
  128. package/dist/hooks/use-cell-containers.js.map +0 -1
  129. package/dist/hooks/use-collection-model.d.ts +0 -26
  130. package/dist/hooks/use-collection-model.d.ts.map +0 -1
  131. package/dist/hooks/use-collection-model.js +0 -35
  132. package/dist/hooks/use-collection-model.js.map +0 -1
  133. package/dist/hooks/use-collection-widget.d.ts +0 -28
  134. package/dist/hooks/use-collection-widget.d.ts.map +0 -1
  135. package/dist/hooks/use-collection-widget.js +0 -21
  136. package/dist/hooks/use-collection-widget.js.map +0 -1
  137. package/dist/hooks/use-drop-down-selection.d.ts +0 -16
  138. package/dist/hooks/use-drop-down-selection.d.ts.map +0 -1
  139. package/dist/hooks/use-drop-down-selection.js +0 -35
  140. package/dist/hooks/use-drop-down-selection.js.map +0 -1
  141. package/dist/hooks/use-expansion-model.d.ts +0 -12
  142. package/dist/hooks/use-expansion-model.d.ts.map +0 -1
  143. package/dist/hooks/use-expansion-model.js +0 -71
  144. package/dist/hooks/use-expansion-model.js.map +0 -1
  145. package/dist/hooks/use-header-menu.d.ts +0 -4
  146. package/dist/hooks/use-header-menu.d.ts.map +0 -1
  147. package/dist/hooks/use-header-menu.js +0 -20
  148. package/dist/hooks/use-header-menu.js.map +0 -1
  149. package/dist/hooks/use-installed-model.d.ts +0 -4
  150. package/dist/hooks/use-installed-model.d.ts.map +0 -1
  151. package/dist/hooks/use-installed-model.js +0 -15
  152. package/dist/hooks/use-installed-model.js.map +0 -1
  153. package/dist/hooks/use-list-model.d.ts +0 -19
  154. package/dist/hooks/use-list-model.d.ts.map +0 -1
  155. package/dist/hooks/use-list-model.js +0 -97
  156. package/dist/hooks/use-list-model.js.map +0 -1
  157. package/dist/hooks/use-placed-child.d.ts +0 -18
  158. package/dist/hooks/use-placed-child.d.ts.map +0 -1
  159. package/dist/hooks/use-placed-child.js +0 -47
  160. package/dist/hooks/use-placed-child.js.map +0 -1
  161. package/dist/hooks/use-selection-model.d.ts +0 -13
  162. package/dist/hooks/use-selection-model.d.ts.map +0 -1
  163. package/dist/hooks/use-selection-model.js +0 -103
  164. package/dist/hooks/use-selection-model.js.map +0 -1
  165. package/dist/hooks/use-sort-handler.d.ts +0 -17
  166. package/dist/hooks/use-sort-handler.d.ts.map +0 -1
  167. package/dist/hooks/use-sort-handler.js +0 -87
  168. package/dist/hooks/use-sort-handler.js.map +0 -1
  169. package/dist/menu-items.d.ts +0 -5
  170. package/dist/menu-items.d.ts.map +0 -1
  171. package/dist/menu-items.js +0 -48
  172. package/dist/menu-items.js.map +0 -1
  173. package/dist/menu.d.ts +0 -14
  174. package/dist/menu.d.ts.map +0 -1
  175. package/dist/menu.js +0 -24
  176. package/dist/menu.js.map +0 -1
  177. package/dist/overlay.d.ts +0 -24
  178. package/dist/overlay.d.ts.map +0 -1
  179. package/dist/overlay.js +0 -49
  180. package/dist/overlay.js.map +0 -1
  181. package/dist/utils/cell-container-store.d.ts +0 -28
  182. package/dist/utils/cell-container-store.d.ts.map +0 -1
  183. package/dist/utils/cell-container-store.js +0 -98
  184. package/dist/utils/cell-container-store.js.map +0 -1
  185. package/dist/utils/item-models.d.ts +0 -10
  186. package/dist/utils/item-models.d.ts.map +0 -1
  187. package/dist/utils/item-models.js +0 -82
  188. package/dist/utils/item-models.js.map +0 -1
  189. package/dist/utils/item-resolver.d.ts +0 -25
  190. package/dist/utils/item-resolver.d.ts.map +0 -1
  191. package/dist/utils/item-resolver.js +0 -102
  192. package/dist/utils/item-resolver.js.map +0 -1
  193. package/dist/utils/list-item-flatten.d.ts +0 -24
  194. package/dist/utils/list-item-flatten.d.ts.map +0 -1
  195. package/dist/utils/list-item-flatten.js +0 -68
  196. package/dist/utils/list-item-flatten.js.map +0 -1
  197. package/src/cell.tsx +0 -144
  198. package/src/column-view-column.tsx +0 -82
  199. package/src/constraint-layout-apply.ts +0 -173
  200. package/src/constraint-layout.tsx +0 -135
  201. package/src/fixed.tsx +0 -86
  202. package/src/grid.tsx +0 -88
  203. package/src/hooks/use-cell-containers.ts +0 -93
  204. package/src/hooks/use-collection-model.ts +0 -60
  205. package/src/hooks/use-collection-widget.ts +0 -47
  206. package/src/hooks/use-drop-down-selection.ts +0 -52
  207. package/src/hooks/use-expansion-model.ts +0 -82
  208. package/src/hooks/use-header-menu.ts +0 -34
  209. package/src/hooks/use-installed-model.ts +0 -20
  210. package/src/hooks/use-list-model.ts +0 -161
  211. package/src/hooks/use-placed-child.ts +0 -79
  212. package/src/hooks/use-selection-model.ts +0 -114
  213. package/src/hooks/use-sort-handler.ts +0 -107
  214. package/src/menu-items.ts +0 -48
  215. package/src/menu.tsx +0 -32
  216. package/src/overlay.tsx +0 -88
  217. package/src/utils/cell-container-store.ts +0 -114
  218. package/src/utils/item-models.ts +0 -113
  219. package/src/utils/item-resolver.ts +0 -138
  220. package/src/utils/list-item-flatten.ts +0 -90
@@ -0,0 +1,74 @@
1
+ import { useEffectEvent, useLayoutEffect, useRef, useState } from "react";
2
+ import { eachRow } from "./collection.js";
3
+ function newLastExpansion() {
4
+ return { key: "" };
5
+ }
6
+ function collectExpanded(row, id, ids) {
7
+ if (id !== null && row.getExpanded()) {
8
+ ids.push(id);
9
+ }
10
+ }
11
+ function expandRow(row, id, wanted) {
12
+ const isDesired = id !== null && wanted.has(id);
13
+ if (row.isExpandable() && row.getExpanded() !== isDesired) {
14
+ row.setExpanded(isDesired);
15
+ }
16
+ }
17
+ function applyExpansion(tree, expandedIds) {
18
+ const wanted = new Set(expandedIds);
19
+ eachRow(tree, (row, id) => {
20
+ expandRow(row, id, wanted);
21
+ });
22
+ }
23
+ function reportExpansion(collection, last, onExpandedChange) {
24
+ const tree = collection.treeModel();
25
+ if (tree === null) {
26
+ return;
27
+ }
28
+ const ids = [];
29
+ eachRow(tree, (row, id) => {
30
+ collectExpanded(row, id, ids);
31
+ });
32
+ const key = ids.join(" ");
33
+ if (last.key === key) {
34
+ return;
35
+ }
36
+ last.key = key;
37
+ onExpandedChange?.(ids);
38
+ }
39
+ function reportWhenIdle(collection, last, expanding, onExpandedChange) {
40
+ if (expanding.current) {
41
+ return;
42
+ }
43
+ reportExpansion(collection, last, onExpandedChange);
44
+ }
45
+ function runControlledExpansion(collection, expandedIds, expanding, report) {
46
+ const tree = collection.treeModel();
47
+ if (tree === null || expandedIds == null) {
48
+ return;
49
+ }
50
+ expanding.current = true;
51
+ try {
52
+ applyExpansion(tree, expandedIds);
53
+ }
54
+ finally {
55
+ expanding.current = false;
56
+ }
57
+ report();
58
+ }
59
+ function useExpansion(options) {
60
+ const { collection, expandedIds, onExpandedChange } = options;
61
+ const [last] = useState(newLastExpansion);
62
+ const expanding = useRef(false);
63
+ const report = useEffectEvent(() => {
64
+ reportWhenIdle(collection, last, expanding, onExpandedChange);
65
+ });
66
+ useLayoutEffect(() => {
67
+ runControlledExpansion(collection, expandedIds, expanding, report);
68
+ }, [collection, expandedIds]);
69
+ return () => {
70
+ reportWhenIdle(collection, last, expanding, onExpandedChange);
71
+ };
72
+ }
73
+ export { useExpansion };
74
+ //# sourceMappingURL=expansion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expansion.js","sourceRoot":"","sources":["../../src/internal/expansion.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { RefObject } from \"react\";\nimport { useEffectEvent, useLayoutEffect, useRef, useState } from \"react\";\nimport type { Collection } from \"./collection.js\";\nimport { eachRow } from \"./collection.js\";\n\ntype ExpansionOptions = {\n collection: Collection;\n expandedIds?: string[] | null | undefined;\n onExpandedChange?: ((ids: string[]) => void) | null | undefined;\n};\n\ntype LastExpansion = { key: string };\n\nfunction newLastExpansion(): LastExpansion {\n return { key: \"\" };\n}\n\nfunction collectExpanded(row: Gtk.TreeListRow, id: string | null, ids: string[]): void {\n if (id !== null && row.getExpanded()) {\n ids.push(id);\n }\n}\n\nfunction expandRow(row: Gtk.TreeListRow, id: string | null, wanted: Set<string>): void {\n const isDesired = id !== null && wanted.has(id);\n\n if (row.isExpandable() && row.getExpanded() !== isDesired) {\n row.setExpanded(isDesired);\n }\n}\n\nfunction applyExpansion(tree: Gtk.TreeListModel, expandedIds: string[]): void {\n const wanted = new Set(expandedIds);\n\n eachRow(tree, (row, id) => {\n expandRow(row, id, wanted);\n });\n}\n\nfunction reportExpansion(\n collection: Collection,\n last: LastExpansion,\n onExpandedChange: ((ids: string[]) => void) | null | undefined,\n): void {\n const tree = collection.treeModel();\n\n if (tree === null) {\n return;\n }\n\n const ids: string[] = [];\n\n eachRow(tree, (row, id) => {\n collectExpanded(row, id, ids);\n });\n\n const key = ids.join(\" \");\n\n if (last.key === key) {\n return;\n }\n\n last.key = key;\n onExpandedChange?.(ids);\n}\n\nfunction reportWhenIdle(\n collection: Collection,\n last: LastExpansion,\n expanding: RefObject<boolean>,\n onExpandedChange: ((ids: string[]) => void) | null | undefined,\n): void {\n if (expanding.current) {\n return;\n }\n\n reportExpansion(collection, last, onExpandedChange);\n}\n\nfunction runControlledExpansion(\n collection: Collection,\n expandedIds: string[] | null | undefined,\n expanding: RefObject<boolean>,\n report: () => void,\n): void {\n const tree = collection.treeModel();\n\n if (tree === null || expandedIds == null) {\n return;\n }\n\n expanding.current = true;\n\n try {\n applyExpansion(tree, expandedIds);\n } finally {\n expanding.current = false;\n }\n\n report();\n}\n\nfunction useExpansion(options: ExpansionOptions): () => void {\n const { collection, expandedIds, onExpandedChange } = options;\n const [last] = useState<LastExpansion>(newLastExpansion);\n const expanding = useRef(false);\n\n const report = useEffectEvent((): void => {\n reportWhenIdle(collection, last, expanding, onExpandedChange);\n });\n\n useLayoutEffect(() => {\n runControlledExpansion(collection, expandedIds, expanding, report);\n }, [collection, expandedIds]);\n\n return () => {\n reportWhenIdle(collection, last, expanding, onExpandedChange);\n };\n}\n\nexport { useExpansion, type ExpansionOptions };\n"]}
@@ -0,0 +1,13 @@
1
+ import type { ReactElement } from "react";
2
+ import * as Gtk from "@gtkx/gi/gtk";
3
+ import type { Collection } from "./collection.js";
4
+ type SelectionOptions = {
5
+ collection: Collection;
6
+ selectedIds?: string[] | null | undefined;
7
+ onSelectionChanged?: ((ids: string[]) => void) | null | undefined;
8
+ selectionMode?: Gtk.SelectionMode | null | undefined;
9
+ onItemsChanged: () => void;
10
+ };
11
+ declare function useSelection(options: SelectionOptions): ReactElement;
12
+ export { useSelection, type SelectionOptions };
13
+ //# sourceMappingURL=selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/internal/selection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAGpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,KAAK,gBAAgB,GAAG;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,kBAAkB,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAClE,aAAa,CAAC,EAAE,GAAG,CAAC,aAAa,GAAG,IAAI,GAAG,SAAS,CAAC;IACrD,cAAc,EAAE,MAAM,IAAI,CAAC;CAC9B,CAAC;AA4HF,iBAAS,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAsB7D;AAED,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as Gtk from "@gtkx/gi/gtk";
3
+ import { GtkMultiSelection, GtkNoSelection, GtkSingleSelection } from "@gtkx/jsx/gtk";
4
+ import { useEffectEvent, useLayoutEffect, useState } from "react";
5
+ function getSelectedIds(selection, collection) {
6
+ const bitset = selection.getSelection();
7
+ const size = Number(bitset.getSize());
8
+ const ids = [];
9
+ for (let index = 0; index < size; index++) {
10
+ pushId(collection.idAt(bitset.getNth(index)), ids);
11
+ }
12
+ return ids;
13
+ }
14
+ function pushId(id, ids) {
15
+ if (id !== null) {
16
+ ids.push(id);
17
+ }
18
+ }
19
+ function applySingleSelection(selection, positions) {
20
+ const [first] = positions;
21
+ if (first === undefined) {
22
+ selection.unselectAll();
23
+ return;
24
+ }
25
+ selection.selectItem(first, true);
26
+ }
27
+ function applyMultiSelection(selection, positions) {
28
+ const selected = Gtk.Bitset.newEmpty();
29
+ for (const position of positions) {
30
+ selected.add(position);
31
+ }
32
+ selection.setSelection(selected, Gtk.Bitset.newRange(0, selection.getNItems()));
33
+ }
34
+ function applySelection(selection, collection, ids) {
35
+ if (selection instanceof Gtk.NoSelection) {
36
+ return;
37
+ }
38
+ const positions = collection.positionsFor(ids);
39
+ if (ids.length > 0 && positions.length === 0) {
40
+ return;
41
+ }
42
+ if (selection instanceof Gtk.SingleSelection) {
43
+ applySingleSelection(selection, positions);
44
+ return;
45
+ }
46
+ applyMultiSelection(selection, positions);
47
+ }
48
+ function reportSelection(selection, collection, last, onSelectionChanged) {
49
+ if (selection === null) {
50
+ return;
51
+ }
52
+ const ids = getSelectedIds(selection, collection);
53
+ const key = ids.join(" ");
54
+ if (last.selection === selection && last.key === key) {
55
+ return;
56
+ }
57
+ last.selection = selection;
58
+ last.key = key;
59
+ onSelectionChanged?.(ids);
60
+ }
61
+ function selectionElement(mode, props) {
62
+ if (mode === Gtk.SelectionMode.MULTIPLE) {
63
+ return _jsx(GtkMultiSelection, { ...props });
64
+ }
65
+ if (mode === Gtk.SelectionMode.NONE) {
66
+ return _jsx(GtkNoSelection, { ...props });
67
+ }
68
+ return _jsx(GtkSingleSelection, { ...props, autoselect: false, canUnselect: true });
69
+ }
70
+ function syncSelection(selection, collection, selectedIds) {
71
+ if (selection === null || selectedIds == null) {
72
+ return;
73
+ }
74
+ applySelection(selection, collection, selectedIds);
75
+ }
76
+ function newLastSelection() {
77
+ return { selection: null, key: null };
78
+ }
79
+ function useSelection(options) {
80
+ const { collection, selectedIds, onSelectionChanged, selectionMode } = options;
81
+ const [selection, setSelection] = useState(null);
82
+ const [last] = useState(newLastSelection);
83
+ const report = useEffectEvent(() => {
84
+ reportSelection(selection, collection, last, onSelectionChanged);
85
+ });
86
+ useLayoutEffect(() => {
87
+ syncSelection(selection, collection, selectedIds);
88
+ report();
89
+ }, [selection, collection, selectedIds]);
90
+ return selectionElement(selectionMode, {
91
+ ref: setSelection,
92
+ model: collection.model,
93
+ onSelectionChanged: () => {
94
+ reportSelection(selection, collection, last, onSelectionChanged);
95
+ },
96
+ onItemsChanged: options.onItemsChanged,
97
+ });
98
+ }
99
+ export { useSelection };
100
+ //# sourceMappingURL=selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/internal/selection.tsx"],"names":[],"mappings":"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","sourcesContent":["import type * as Gio from \"@gtkx/gi/gio\";\nimport type { ReactElement } from \"react\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { GtkMultiSelection, GtkNoSelection, GtkSingleSelection } from \"@gtkx/jsx/gtk\";\nimport { useEffectEvent, useLayoutEffect, useState } from \"react\";\nimport type { Collection } from \"./collection.js\";\n\ntype SelectionOptions = {\n collection: Collection;\n selectedIds?: string[] | null | undefined;\n onSelectionChanged?: ((ids: string[]) => void) | null | undefined;\n selectionMode?: Gtk.SelectionMode | null | undefined;\n onItemsChanged: () => void;\n};\n\ntype LastSelection = {\n selection: Gtk.SelectionModel | null;\n key: string | null;\n};\n\ntype SelectionElementProps = {\n ref: (value: Gtk.SelectionModel | null) => void;\n model: Gio.ListModel;\n onSelectionChanged: () => void;\n onItemsChanged: () => void;\n};\n\nfunction getSelectedIds(selection: Gtk.SelectionModel, collection: Collection): string[] {\n const bitset = selection.getSelection();\n const size = Number(bitset.getSize());\n const ids: string[] = [];\n\n for (let index = 0; index < size; index++) {\n pushId(collection.idAt(bitset.getNth(index)), ids);\n }\n\n return ids;\n}\n\nfunction pushId(id: string | null, ids: string[]): void {\n if (id !== null) {\n ids.push(id);\n }\n}\n\nfunction applySingleSelection(selection: Gtk.SingleSelection, positions: number[]): void {\n const [first] = positions;\n\n if (first === undefined) {\n selection.unselectAll();\n\n return;\n }\n\n selection.selectItem(first, true);\n}\n\nfunction applyMultiSelection(selection: Gtk.SelectionModel, positions: number[]): void {\n const selected = Gtk.Bitset.newEmpty();\n\n for (const position of positions) {\n selected.add(position);\n }\n\n selection.setSelection(selected, Gtk.Bitset.newRange(0, selection.getNItems()));\n}\n\nfunction applySelection(selection: Gtk.SelectionModel, collection: Collection, ids: string[]): void {\n if (selection instanceof Gtk.NoSelection) {\n return;\n }\n\n const positions = collection.positionsFor(ids);\n\n if (ids.length > 0 && positions.length === 0) {\n return;\n }\n\n if (selection instanceof Gtk.SingleSelection) {\n applySingleSelection(selection, positions);\n\n return;\n }\n\n applyMultiSelection(selection, positions);\n}\n\nfunction reportSelection(\n selection: Gtk.SelectionModel | null,\n collection: Collection,\n last: LastSelection,\n onSelectionChanged: ((ids: string[]) => void) | null | undefined,\n): void {\n if (selection === null) {\n return;\n }\n\n const ids = getSelectedIds(selection, collection);\n const key = ids.join(\" \");\n\n if (last.selection === selection && last.key === key) {\n return;\n }\n\n last.selection = selection;\n last.key = key;\n onSelectionChanged?.(ids);\n}\n\nfunction selectionElement(mode: Gtk.SelectionMode | null | undefined, props: SelectionElementProps): ReactElement {\n if (mode === Gtk.SelectionMode.MULTIPLE) {\n return <GtkMultiSelection {...props} />;\n }\n\n if (mode === Gtk.SelectionMode.NONE) {\n return <GtkNoSelection {...props} />;\n }\n\n return <GtkSingleSelection {...props} autoselect={false} canUnselect />;\n}\n\nfunction syncSelection(\n selection: Gtk.SelectionModel | null,\n collection: Collection,\n selectedIds: string[] | null | undefined,\n): void {\n if (selection === null || selectedIds == null) {\n return;\n }\n\n applySelection(selection, collection, selectedIds);\n}\n\nfunction newLastSelection(): LastSelection {\n return { selection: null, key: null };\n}\n\nfunction useSelection(options: SelectionOptions): ReactElement {\n const { collection, selectedIds, onSelectionChanged, selectionMode } = options;\n const [selection, setSelection] = useState<Gtk.SelectionModel | null>(null);\n const [last] = useState<LastSelection>(newLastSelection);\n\n const report = useEffectEvent((): void => {\n reportSelection(selection, collection, last, onSelectionChanged);\n });\n\n useLayoutEffect(() => {\n syncSelection(selection, collection, selectedIds);\n report();\n }, [selection, collection, selectedIds]);\n\n return selectionElement(selectionMode, {\n ref: setSelection,\n model: collection.model,\n onSelectionChanged: () => {\n reportSelection(selection, collection, last, onSelectionChanged);\n },\n onItemsChanged: options.onItemsChanged,\n });\n}\n\nexport { useSelection, type SelectionOptions };\n"]}
@@ -0,0 +1,17 @@
1
+ import type { ReactElement } from "react";
2
+ import type { ExpansionProps, Item, Section, SelectionProps } from "../types.js";
3
+ import type { Collection } from "./collection.js";
4
+ type CollectionDataOptions = {
5
+ items?: Item[] | undefined;
6
+ sections?: Section[] | undefined;
7
+ flat?: boolean | undefined;
8
+ };
9
+ type CollectionOptions = CollectionDataOptions & SelectionProps & ExpansionProps;
10
+ type CollectionResult = {
11
+ collection: Collection;
12
+ selection: ReactElement;
13
+ };
14
+ declare function useCollectionData(options: CollectionDataOptions): Collection;
15
+ declare function useCollection(options: CollectionOptions): CollectionResult;
16
+ export { useCollection, useCollectionData, type CollectionDataOptions, type CollectionOptions };
17
+ //# sourceMappingURL=use-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-collection.d.ts","sourceRoot":"","sources":["../../src/internal/use-collection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOlD,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,KAAK,iBAAiB,GAAG,qBAAqB,GAAG,cAAc,GAAG,cAAc,CAAC;AAEjF,KAAK,gBAAgB,GAAG;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAWrE;AAED,iBAAS,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAkBnE;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { useLayoutEffect, useMemo, useState } from "react";
2
+ import { createCollectionIndex } from "./collection-index.js";
3
+ import { createCollectionModel } from "./collection-model.js";
4
+ import { createCollection } from "./collection.js";
5
+ import { useExpansion } from "./expansion.js";
6
+ import { useSelection } from "./selection.js";
7
+ function useCollectionData(options) {
8
+ const { items, sections, flat } = options;
9
+ const [gtk] = useState(createCollectionModel);
10
+ const index = useMemo(() => createCollectionIndex(items, sections, flat === true), [items, sections, flat]);
11
+ const collection = useMemo(() => createCollection(gtk, index), [gtk, index]);
12
+ useLayoutEffect(() => {
13
+ gtk.sync(index);
14
+ }, [gtk, index]);
15
+ return collection;
16
+ }
17
+ function useCollection(options) {
18
+ const collection = useCollectionData(options);
19
+ const onItemsChanged = useExpansion({
20
+ collection,
21
+ expandedIds: options.expandedIds,
22
+ onExpandedChange: options.onExpandedChange,
23
+ });
24
+ const selection = useSelection({
25
+ collection,
26
+ selectedIds: options.selectedIds,
27
+ onSelectionChanged: options.onSelectionChanged,
28
+ selectionMode: options.selectionMode,
29
+ onItemsChanged,
30
+ });
31
+ return { collection, selection };
32
+ }
33
+ export { useCollection, useCollectionData };
34
+ //# sourceMappingURL=use-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-collection.js","sourceRoot":"","sources":["../../src/internal/use-collection.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAe9C,SAAS,iBAAiB,CAAC,OAA8B;IACrD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5G,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAE7E,eAAe,CAAC,GAAG,EAAE;QACjB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAEjB,OAAO,UAAU,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,OAA0B;IAC7C,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE9C,MAAM,cAAc,GAAG,YAAY,CAAC;QAChC,UAAU;QACV,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;KAC7C,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,YAAY,CAAC;QAC3B,UAAU;QACV,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;QAC9C,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,cAAc;KACjB,CAAC,CAAC;IAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAsD,CAAC","sourcesContent":["import type { ReactElement } from \"react\";\nimport { useLayoutEffect, useMemo, useState } from \"react\";\nimport type { ExpansionProps, Item, Section, SelectionProps } from \"../types.js\";\nimport type { Collection } from \"./collection.js\";\nimport { createCollectionIndex } from \"./collection-index.js\";\nimport { createCollectionModel } from \"./collection-model.js\";\nimport { createCollection } from \"./collection.js\";\nimport { useExpansion } from \"./expansion.js\";\nimport { useSelection } from \"./selection.js\";\n\ntype CollectionDataOptions = {\n items?: Item[] | undefined;\n sections?: Section[] | undefined;\n flat?: boolean | undefined;\n};\n\ntype CollectionOptions = CollectionDataOptions & SelectionProps & ExpansionProps;\n\ntype CollectionResult = {\n collection: Collection;\n selection: ReactElement;\n};\n\nfunction useCollectionData(options: CollectionDataOptions): Collection {\n const { items, sections, flat } = options;\n const [gtk] = useState(createCollectionModel);\n const index = useMemo(() => createCollectionIndex(items, sections, flat === true), [items, sections, flat]);\n const collection = useMemo(() => createCollection(gtk, index), [gtk, index]);\n\n useLayoutEffect(() => {\n gtk.sync(index);\n }, [gtk, index]);\n\n return collection;\n}\n\nfunction useCollection(options: CollectionOptions): CollectionResult {\n const collection = useCollectionData(options);\n\n const onItemsChanged = useExpansion({\n collection,\n expandedIds: options.expandedIds,\n onExpandedChange: options.onExpandedChange,\n });\n\n const selection = useSelection({\n collection,\n selectedIds: options.selectedIds,\n onSelectionChanged: options.onSelectionChanged,\n selectionMode: options.selectionMode,\n onItemsChanged,\n });\n\n return { collection, selection };\n}\n\nexport { useCollection, useCollectionData, type CollectionDataOptions, type CollectionOptions };\n"]}
@@ -0,0 +1,4 @@
1
+ import type { Ref, RefCallback } from "react";
2
+ declare const useWidgetRef: <T>(external: Ref<T | null> | null | undefined) => [T | null, RefCallback<T | null>];
3
+ export { useWidgetRef };
4
+ //# sourceMappingURL=use-widget-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-widget-ref.d.ts","sourceRoot":"","sources":["../../src/internal/use-widget-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAI9C,QAAA,MAAM,YAAY,GAAI,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,KAAG,CAAC,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC,GAAG,IAAI,CAAC,CAIrG,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { useMergedRef } from "@gtkx/react/internal";
2
+ import { useState } from "react";
3
+ const useWidgetRef = (external) => {
4
+ const [widget, setWidget] = useState(null);
5
+ return [widget, useMergedRef(external, setWidget)];
6
+ };
7
+ export { useWidgetRef };
8
+ //# sourceMappingURL=use-widget-ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-widget-ref.js","sourceRoot":"","sources":["../../src/internal/use-widget-ref.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,MAAM,YAAY,GAAG,CAAI,QAA0C,EAAqC,EAAE;IACtG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAW,IAAI,CAAC,CAAC;IAErD,OAAO,CAAC,MAAM,EAAE,YAAY,CAAW,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AACjE,CAAC,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC","sourcesContent":["import type { Ref, RefCallback } from \"react\";\nimport { useMergedRef } from \"@gtkx/react/internal\";\nimport { useState } from \"react\";\n\nconst useWidgetRef = <T>(external: Ref<T | null> | null | undefined): [T | null, RefCallback<T | null>] => {\n const [widget, setWidget] = useState<T | null>(null);\n\n return [widget, useMergedRef<T | null>(external, setWidget)];\n};\n\nexport { useWidgetRef };\n"]}
@@ -1,24 +1,9 @@
1
- import { type GtkListViewProps } from "@gtkx/jsx/gtk";
2
1
  import type { ReactNode } from "react";
3
- import type { CollectionItemSizeProps, ControlledExpansionProps, ControlledSelectionProps, ItemNode, RenderItemProps, SectionNode } from "./types.js";
4
- export type ListViewDeclarativeProps<T = unknown, S = unknown> = CollectionItemSizeProps & ControlledSelectionProps & ControlledExpansionProps & {
5
- items?: ItemNode<T>[] | undefined;
6
- sections?: SectionNode<S, T>[] | undefined;
7
- renderItem: (props: RenderItemProps<T>) => ReactNode;
8
- renderHeader?: ((info: {
9
- section: S;
10
- }) => ReactNode) | null | undefined;
11
- };
2
+ import type { ListViewProps } from "./types.js";
12
3
  /**
13
- * Props for {@link ListView}. Combines the underlying Gtk.ListView props with
14
- * declarative collection props: flat items or grouped sections, a per-row renderItem,
15
- * an optional section header renderer, controlled selection and expansion, and
16
- * estimated item sizing.
4
+ * Renders a Gtk.ListView from declarative items or sections, with per-row rendering,
5
+ * controlled selection, controlled tree expansion, and estimated item sizing.
17
6
  */
18
- export type ListViewProps<T = unknown, S = unknown> = Omit<GtkListViewProps, "model" | "factory" | "headerFactory" | keyof ListViewDeclarativeProps<T, S>> & ListViewDeclarativeProps<T, S>;
19
- /**
20
- * Renders a Gtk.ListView: a scrollable, single-column list backed by a collection
21
- * model, with each row drawn by renderItem and optional section headers.
22
- */
23
- export declare const ListView: <T = unknown, S = unknown>(props: ListViewProps<T, S>) => ReactNode;
7
+ declare function ListView<T = unknown, S = unknown>(props: ListViewProps<T, S>): ReactNode;
8
+ export { ListView };
24
9
  //# sourceMappingURL=list-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-view.d.ts","sourceRoot":"","sources":["../src/list-view.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAO,MAAM,OAAO,CAAC;AAW5C,OAAO,KAAK,EACR,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,QAAQ,EACR,eAAe,EACf,WAAW,EACd,MAAM,YAAY,CAAC;AAUpB,MAAM,MAAM,wBAAwB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,IAAI,uBAAuB,GACpF,wBAAwB,GACxB,wBAAwB,GAAG;IACvB,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;IAC3C,UAAU,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACrD,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC,CAAA;KAAE,KAAK,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;CAC3E,CAAC;AAEN;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,IAAI,IAAI,CACtD,gBAAgB,EAChB,OAAO,GAAG,SAAS,GAAG,eAAe,GAAG,MAAM,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAC/E,GACG,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAgDnC;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,SA8C/E,CAAC"}
1
+ {"version":3,"file":"list-view.d.ts","sourceRoot":"","sources":["../src/list-view.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkBhD;;;GAGG;AACH,iBAAS,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAwBjF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
package/dist/list-view.js CHANGED
@@ -1,56 +1,35 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { GtkListView } from "@gtkx/jsx/gtk";
3
- import { CellRenderHost, createTreeRenderContext, HeaderRenderHost, itemRenderer, } from "./cell.js";
4
- import { makeFactoryInstaller, useCellContainers } from "./hooks/use-cell-containers.js";
5
- import { useCollectionWidget } from "./hooks/use-collection-widget.js";
6
- const factoryInstaller = makeFactoryInstaller((widget, factory) => widget.setFactory(factory));
7
- const headerFactoryInstaller = makeFactoryInstaller((widget, factory) => widget.setHeaderFactory(factory));
8
- const useListViewWiring = (props) => {
9
- const { widgetRef, setRef, collection } = useCollectionWidget(props);
10
- const useHeader = collection.useHeader;
11
- const itemStore = useCellContainers({
12
- object: widgetRef,
13
- installer: factoryInstaller,
14
- estimatedHeight: props.estimatedItemHeight,
15
- estimatedWidth: props.estimatedItemWidth,
16
- });
17
- const headerStore = useCellContainers({
18
- object: useHeader ? widgetRef : null,
19
- installer: headerFactoryInstaller,
20
- estimatedHeight: props.estimatedItemHeight,
21
- estimatedWidth: props.estimatedItemWidth,
22
- });
23
- return {
24
- setRef,
25
- resolver: collection.resolver,
26
- headerResolver: collection.headerResolver,
27
- itemStore,
28
- headerStore,
29
- useHeader,
30
- rowId: collection.rowId,
31
- };
32
- };
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { GtkListView, GtkSignalListItemFactory } from "@gtkx/jsx/gtk";
3
+ import { omit } from "@gtkx/utils";
4
+ import { HeaderPortals, ItemPortals, useHeaderCells, useItemCells } from "./internal/cells.js";
5
+ import { useCollection } from "./internal/use-collection.js";
6
+ const LIST_VIEW_PROPS = [
7
+ "items",
8
+ "sections",
9
+ "renderItem",
10
+ "renderHeader",
11
+ "selectedIds",
12
+ "onSelectionChanged",
13
+ "selectionMode",
14
+ "expandedIds",
15
+ "onExpandedChange",
16
+ "estimatedItemHeight",
17
+ "estimatedItemWidth",
18
+ ];
33
19
  /**
34
- * Renders a Gtk.ListView: a scrollable, single-column list backed by a collection
35
- * model, with each row drawn by renderItem and optional section headers.
20
+ * Renders a Gtk.ListView from declarative items or sections, with per-row rendering,
21
+ * controlled selection, controlled tree expansion, and estimated item sizing.
36
22
  */
37
- export const ListView = (props) => {
38
- const { ref, items, sections, renderItem, renderHeader, selectedIds, selectionMode, onSelectionChanged, expandedIds, onExpandedChange, estimatedItemHeight, estimatedItemWidth, ...intrinsicProps } = props;
39
- const wiring = useListViewWiring({
40
- ref,
41
- items,
42
- sections,
43
- renderHeader,
44
- selectedIds,
45
- selectionMode,
46
- onSelectionChanged,
47
- expandedIds,
48
- onExpandedChange,
49
- estimatedItemHeight,
50
- estimatedItemWidth,
51
- });
52
- const treeContext = createTreeRenderContext(expandedIds, wiring.rowId);
53
- const cellRenderer = itemRenderer(renderItem, treeContext);
54
- return (_jsxs(_Fragment, { children: [_jsx(GtkListView, { ...intrinsicProps, ref: wiring.setRef }), _jsx(CellRenderHost, { store: wiring.itemStore, resolver: wiring.resolver, render: cellRenderer }), _jsx(HeaderRenderHost, { useHeader: wiring.useHeader, store: wiring.headerStore, resolver: wiring.headerResolver, renderHeader: renderHeader })] }));
55
- };
23
+ function ListView(props) {
24
+ const { renderItem, renderHeader, expandedIds, estimatedItemHeight, estimatedItemWidth } = props;
25
+ const rest = omit(props, LIST_VIEW_PROPS);
26
+ const size = { width: estimatedItemWidth ?? -1, height: estimatedItemHeight ?? -1 };
27
+ const { collection, selection } = useCollection(props);
28
+ const itemCells = useItemCells(size);
29
+ const headerCells = useHeaderCells(size);
30
+ return (_jsxs(_Fragment, { children: [_jsx(GtkListView, { model: selection, factory: _jsx(GtkSignalListItemFactory, { ...itemCells.handlers }), ...(renderHeader != null && {
31
+ headerFactory: _jsx(GtkSignalListItemFactory, { ...headerCells.handlers }),
32
+ }), ...rest }), _jsx(ItemPortals, { store: itemCells, render: renderItem, collection: collection, expandedIds: expandedIds }), renderHeader != null && (_jsx(HeaderPortals, { store: headerCells, render: renderHeader, collection: collection }))] }));
33
+ }
34
+ export { ListView };
56
35
  //# sourceMappingURL=list-view.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-view.js","sourceRoot":"","sources":["../src/list-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport { GtkListView, type GtkListViewProps } from \"@gtkx/jsx/gtk\";\nimport type { ReactNode, Ref } from \"react\";\nimport {\n type CellRenderer,\n CellRenderHost,\n createTreeRenderContext,\n HeaderRenderHost,\n itemRenderer,\n type TreeRenderContext,\n} from \"./cell.js\";\nimport { makeFactoryInstaller, useCellContainers } from \"./hooks/use-cell-containers.js\";\nimport { useCollectionWidget } from \"./hooks/use-collection-widget.js\";\nimport type {\n CollectionItemSizeProps,\n ControlledExpansionProps,\n ControlledSelectionProps,\n ItemNode,\n RenderItemProps,\n SectionNode,\n} from \"./types.js\";\nimport type { CellContainerStore } from \"./utils/cell-container-store.js\";\nimport type { ItemResolver } from \"./utils/item-resolver.js\";\n\nconst factoryInstaller = makeFactoryInstaller<Gtk.ListView>((widget, factory) => widget.setFactory(factory));\n\nconst headerFactoryInstaller = makeFactoryInstaller<Gtk.ListView>((widget, factory) =>\n widget.setHeaderFactory(factory),\n);\n\nexport type ListViewDeclarativeProps<T = unknown, S = unknown> = CollectionItemSizeProps &\n ControlledSelectionProps &\n ControlledExpansionProps & {\n items?: ItemNode<T>[] | undefined;\n sections?: SectionNode<S, T>[] | undefined;\n renderItem: (props: RenderItemProps<T>) => ReactNode;\n renderHeader?: ((info: { section: S }) => ReactNode) | null | undefined;\n };\n\n/**\n * Props for {@link ListView}. Combines the underlying Gtk.ListView props with\n * declarative collection props: flat items or grouped sections, a per-row renderItem,\n * an optional section header renderer, controlled selection and expansion, and\n * estimated item sizing.\n */\nexport type ListViewProps<T = unknown, S = unknown> = Omit<\n GtkListViewProps,\n \"model\" | \"factory\" | \"headerFactory\" | keyof ListViewDeclarativeProps<T, S>\n> &\n ListViewDeclarativeProps<T, S>;\n\ninterface ListViewWiring<T, S> {\n setRef: (value: Gtk.ListView | null) => void;\n resolver: ItemResolver<T, S>;\n headerResolver: ItemResolver<T, S>;\n itemStore: CellContainerStore;\n headerStore: CellContainerStore;\n useHeader: boolean;\n rowId: (row: Gtk.TreeListRow) => string | undefined;\n}\n\nconst useListViewWiring = <T, S>(props: NormalizedListViewProps<T, S>): ListViewWiring<T, S> => {\n const { widgetRef, setRef, collection } = useCollectionWidget<Gtk.ListView, T, S>(props);\n\n const useHeader = collection.useHeader;\n\n const itemStore = useCellContainers<Gtk.ListView>({\n object: widgetRef,\n installer: factoryInstaller,\n estimatedHeight: props.estimatedItemHeight,\n estimatedWidth: props.estimatedItemWidth,\n });\n const headerStore = useCellContainers<Gtk.ListView>({\n object: useHeader ? widgetRef : null,\n installer: headerFactoryInstaller,\n estimatedHeight: props.estimatedItemHeight,\n estimatedWidth: props.estimatedItemWidth,\n });\n\n return {\n setRef,\n resolver: collection.resolver,\n headerResolver: collection.headerResolver,\n itemStore,\n headerStore,\n useHeader,\n rowId: collection.rowId,\n };\n};\n\ntype NormalizedListViewProps<T, S> = ListViewDeclarativeProps<T, S> & {\n ref?: Ref<Gtk.ListView | null>;\n estimatedItemHeight?: number;\n estimatedItemWidth?: number;\n [key: string]: unknown;\n};\n\n/**\n * Renders a Gtk.ListView: a scrollable, single-column list backed by a collection\n * model, with each row drawn by renderItem and optional section headers.\n */\nexport const ListView = <T = unknown, S = unknown>(props: ListViewProps<T, S>): ReactNode => {\n const {\n ref,\n items,\n sections,\n renderItem,\n renderHeader,\n selectedIds,\n selectionMode,\n onSelectionChanged,\n expandedIds,\n onExpandedChange,\n estimatedItemHeight,\n estimatedItemWidth,\n ...intrinsicProps\n } = props as NormalizedListViewProps<T, S>;\n\n const wiring = useListViewWiring<T, S>({\n ref,\n items,\n sections,\n renderHeader,\n selectedIds,\n selectionMode,\n onSelectionChanged,\n expandedIds,\n onExpandedChange,\n estimatedItemHeight,\n estimatedItemWidth,\n } as NormalizedListViewProps<T, S>);\n\n const treeContext: TreeRenderContext = createTreeRenderContext(expandedIds, wiring.rowId);\n const cellRenderer: CellRenderer<T, S> = itemRenderer<T, S>(renderItem, treeContext);\n\n return (\n <>\n <GtkListView {...intrinsicProps} ref={wiring.setRef} />\n <CellRenderHost store={wiring.itemStore} resolver={wiring.resolver} render={cellRenderer} />\n <HeaderRenderHost\n useHeader={wiring.useHeader}\n store={wiring.headerStore}\n resolver={wiring.headerResolver}\n renderHeader={renderHeader}\n />\n </>\n );\n};\n"]}
1
+ {"version":3,"file":"list-view.js","sourceRoot":"","sources":["../src/list-view.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,MAAM,eAAe,GAAG;IACpB,OAAO;IACP,UAAU;IACV,YAAY;IACZ,cAAc;IACd,aAAa;IACb,oBAAoB;IACpB,eAAe;IACf,aAAa;IACb,kBAAkB;IAClB,qBAAqB;IACrB,oBAAoB;CACoB,CAAC;AAE7C;;;GAGG;AACH,SAAS,QAAQ,CAA2B,KAA0B;IAClE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC;IACjG,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,kBAAkB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,mBAAmB,IAAI,CAAC,CAAC,EAAE,CAAC;IACpF,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAEzC,OAAO,CACH,8BACI,KAAC,WAAW,IACR,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,KAAC,wBAAwB,OAAK,SAAS,CAAC,QAAQ,GAAI,KACzD,CAAC,YAAY,IAAI,IAAI,IAAI;oBACzB,aAAa,EAAE,KAAC,wBAAwB,OAAK,WAAW,CAAC,QAAQ,GAAI;iBACxE,CAAC,KACE,IAAI,GACV,EACF,KAAC,WAAW,IAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAI,EACtG,YAAY,IAAI,IAAI,IAAI,CACrB,KAAC,aAAa,IAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAI,CACtF,IACF,CACN,CAAC;AACN,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["import type { ReactNode } from \"react\";\nimport { GtkListView, GtkSignalListItemFactory } from \"@gtkx/jsx/gtk\";\nimport { omit } from \"@gtkx/utils\";\nimport type { ListViewProps } from \"./types.js\";\nimport { HeaderPortals, ItemPortals, useHeaderCells, useItemCells } from \"./internal/cells.js\";\nimport { useCollection } from \"./internal/use-collection.js\";\n\nconst LIST_VIEW_PROPS = [\n \"items\",\n \"sections\",\n \"renderItem\",\n \"renderHeader\",\n \"selectedIds\",\n \"onSelectionChanged\",\n \"selectionMode\",\n \"expandedIds\",\n \"onExpandedChange\",\n \"estimatedItemHeight\",\n \"estimatedItemWidth\",\n] as const satisfies (keyof ListViewProps)[];\n\n/**\n * Renders a Gtk.ListView from declarative items or sections, with per-row rendering,\n * controlled selection, controlled tree expansion, and estimated item sizing.\n */\nfunction ListView<T = unknown, S = unknown>(props: ListViewProps<T, S>): ReactNode {\n const { renderItem, renderHeader, expandedIds, estimatedItemHeight, estimatedItemWidth } = props;\n const rest = omit(props, LIST_VIEW_PROPS);\n const size = { width: estimatedItemWidth ?? -1, height: estimatedItemHeight ?? -1 };\n const { collection, selection } = useCollection(props);\n const itemCells = useItemCells(size);\n const headerCells = useHeaderCells(size);\n\n return (\n <>\n <GtkListView\n model={selection}\n factory={<GtkSignalListItemFactory {...itemCells.handlers} />}\n {...(renderHeader != null && {\n headerFactory: <GtkSignalListItemFactory {...headerCells.handlers} />,\n })}\n {...rest}\n />\n <ItemPortals store={itemCells} render={renderItem} collection={collection} expandedIds={expandedIds} />\n {renderHeader != null && (\n <HeaderPortals store={headerCells} render={renderHeader} collection={collection} />\n )}\n </>\n );\n}\n\nexport { ListView };\n"]}
@@ -1,20 +1,12 @@
1
- import type * as Gtk from "@gtkx/gi/gtk";
2
- import { type ElementType, type ReactNode, type Ref } from "react";
3
- import type { ChildProps } from "./types.js";
4
- /** Props for {@link SizeGroup}. */
5
- export type SizeGroupProps = {
6
- /** How the group equalizes sizes: horizontal, vertical, or both. */
7
- mode?: Gtk.SizeGroupMode | null | undefined;
8
- ref?: Ref<Gtk.SizeGroup | null>;
9
- children?: ReactNode;
1
+ import type { ElementType, ReactNode } from "react";
2
+ import type { SizeGroupChildProps, SizeGroupProps } from "./types.js";
3
+ type SizeGroupComponent = ((props: SizeGroupProps) => ReactNode) & {
4
+ Child: <C extends ElementType>(props: SizeGroupChildProps<C>) => ReactNode;
10
5
  };
11
- /** Adds a single widget, rendered by the given component, to the enclosing {@link SizeGroup}. */
12
- export type SizeGroupChildProps<C extends ElementType> = ChildProps<C>;
13
6
  /**
14
- * Creates a Gtk.SizeGroup that keeps its member widgets at a common size. Members join the group
15
- * through {@link SizeGroup.Child}.
7
+ * Creates a Gtk.SizeGroup that keeps widgets joined through `SizeGroup.Child`
8
+ * at a common size in the given mode, without contributing a widget of its own.
16
9
  */
17
- export declare const SizeGroup: ((props: SizeGroupProps) => ReactNode) & {
18
- Child: <C extends ElementType>(props: SizeGroupChildProps<C>) => ReactNode;
19
- };
10
+ declare const SizeGroup: SizeGroupComponent;
11
+ export { SizeGroup };
20
12
  //# sourceMappingURL=size-group.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"size-group.d.ts","sourceRoot":"","sources":["../src/size-group.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,cAAc,CAAC;AAGzC,OAAO,EAEH,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,GAAG,EAKX,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgB7C,mCAAmC;AACnC,MAAM,MAAM,cAAc,GAAG;IACzB,oEAAoE;IACpE,IAAI,CAAC,EAAE,GAAG,CAAC,aAAa,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB,CAAC;AAEF,iGAAiG;AACjG,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;AAoCvE;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,KAAK,SAAS,CAAC,GAAG;IAC7D,KAAK,EAAE,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;CAgB9E,CAAC"}
1
+ {"version":3,"file":"size-group.d.ts","sourceRoot":"","sources":["../src/size-group.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAoB,MAAM,OAAO,CAAC;AAItE,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAStE,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,EAAE,cAAc,KAAK,SAAS,CAAC,GAAG;IAC/D,KAAK,EAAE,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;CAC9E,CAAC;AAIF;;;GAGG;AACH,QAAA,MAAM,SAAS,EAAE,kBAA4E,CAAC;AAoD9F,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -1,57 +1,41 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { GtkSizeGroup } from "@gtkx/jsx/gtk";
3
- import { useMergeRefs } from "@gtkx/react/internal";
4
- import { createContext, useCallback, useContext, useRef, } from "react";
3
+ import { useMergedRef } from "@gtkx/react/internal";
4
+ import { createContext, useCallback, useContext, useState } from "react";
5
5
  const SizeGroupContext = createContext(null);
6
- const useSizeGroupRegistry = () => {
7
- const registry = useContext(SizeGroupContext);
8
- if (!registry)
6
+ const SizeGroupChild = SizeGroupChildImpl;
7
+ /**
8
+ * Creates a Gtk.SizeGroup that keeps widgets joined through `SizeGroup.Child`
9
+ * at a common size in the given mode, without contributing a widget of its own.
10
+ */
11
+ const SizeGroup = Object.assign(SizeGroupRoot, { Child: SizeGroupChild });
12
+ const useRegister = () => {
13
+ const register = useContext(SizeGroupContext);
14
+ if (register === null) {
9
15
  throw new Error("<SizeGroup.Child> must be a child of <SizeGroup>");
10
- return registry;
16
+ }
17
+ return register;
11
18
  };
12
- const SizeGroupChild = ({ component, ref, ...rest }) => {
13
- const registry = useSizeGroupRegistry();
14
- const joinGroup = useCallback((widget) => {
15
- if (widget === null)
19
+ function SizeGroupChildImpl(props) {
20
+ const { component: Component, ref, ...rest } = props;
21
+ const refCallback = useMergedRef(ref, useRegister());
22
+ return _jsx(Component, { ...rest, ref: refCallback });
23
+ }
24
+ const addWidget = (widgets, widget) => widgets.includes(widget) ? widgets : [...widgets, widget];
25
+ const removeWidget = (widgets, widget) => widgets.filter((entry) => entry !== widget);
26
+ function SizeGroupRoot(props) {
27
+ const { mode, ref, children } = props;
28
+ const [widgets, setWidgets] = useState([]);
29
+ const register = useCallback((widget) => {
30
+ if (widget === null) {
16
31
  return;
17
- registry.addWidget(widget);
18
- return () => registry.removeWidget(widget);
19
- }, [registry]);
20
- const Component = component;
21
- const setWidget = useMergeRefs(ref, joinGroup);
22
- return _jsx(Component, { ...rest, ref: setWidget });
23
- };
24
- const createRegistry = () => {
25
- const members = new Set();
26
- let group = null;
27
- return {
28
- addWidget: (widget) => {
29
- members.add(widget);
30
- group?.addWidget(widget);
31
- },
32
- removeWidget: (widget) => {
33
- members.delete(widget);
34
- group?.removeWidget(widget);
35
- },
36
- setGroup: (next) => {
37
- group = next;
38
- if (next)
39
- for (const member of members)
40
- next.addWidget(member);
41
- },
42
- };
43
- };
44
- /**
45
- * Creates a Gtk.SizeGroup that keeps its member widgets at a common size. Members join the group
46
- * through {@link SizeGroup.Child}.
47
- */
48
- export const SizeGroup = Object.assign(({ mode, ref, children }) => {
49
- const registryRef = useRef(null);
50
- if (registryRef.current === null)
51
- registryRef.current = createRegistry();
52
- const registry = registryRef.current;
53
- const setGroup = useCallback((group) => registry.setGroup(group), [registry]);
54
- const mergedRef = useMergeRefs(ref, setGroup);
55
- return (_jsxs(_Fragment, { children: [_jsx(GtkSizeGroup, { ref: mergedRef, mode: mode }), _jsx(SizeGroupContext.Provider, { value: registry, children: children })] }));
56
- }, { Child: SizeGroupChild });
32
+ }
33
+ setWidgets((previous) => addWidget(previous, widget));
34
+ return () => {
35
+ setWidgets((previous) => removeWidget(previous, widget));
36
+ };
37
+ }, [setWidgets]);
38
+ return (_jsxs(_Fragment, { children: [_jsx(GtkSizeGroup, { ref: ref, mode: mode, widgets: widgets }), _jsx(SizeGroupContext.Provider, { value: register, children: children })] }));
39
+ }
40
+ export { SizeGroup };
57
41
  //# sourceMappingURL=size-group.js.map