@gtkx/components 1.0.0-rc.4 → 1.0.0

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 +5 -5
  2. package/dist/column-view.d.ts +2 -2
  3. package/dist/column-view.d.ts.map +1 -1
  4. package/dist/column-view.js +14 -12
  5. package/dist/column-view.js.map +1 -1
  6. package/dist/grid-view.js +1 -1
  7. package/dist/grid-view.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal/cells.d.ts +31 -23
  12. package/dist/internal/cells.d.ts.map +1 -1
  13. package/dist/internal/cells.js +168 -77
  14. package/dist/internal/cells.js.map +1 -1
  15. package/dist/internal/collection-index.d.ts +6 -10
  16. package/dist/internal/collection-index.d.ts.map +1 -1
  17. package/dist/internal/collection-index.js +32 -69
  18. package/dist/internal/collection-index.js.map +1 -1
  19. package/dist/internal/collection-model.d.ts +23 -2
  20. package/dist/internal/collection-model.d.ts.map +1 -1
  21. package/dist/internal/collection-model.js +210 -95
  22. package/dist/internal/collection-model.js.map +1 -1
  23. package/dist/internal/collection.d.ts +8 -11
  24. package/dist/internal/collection.d.ts.map +1 -1
  25. package/dist/internal/collection.js +38 -49
  26. package/dist/internal/collection.js.map +1 -1
  27. package/dist/internal/controlled-sync.d.ts +11 -0
  28. package/dist/internal/controlled-sync.d.ts.map +1 -0
  29. package/dist/internal/controlled-sync.js +19 -0
  30. package/dist/internal/controlled-sync.js.map +1 -0
  31. package/dist/internal/drop-down.d.ts.map +1 -1
  32. package/dist/internal/drop-down.js +27 -15
  33. package/dist/internal/drop-down.js.map +1 -1
  34. package/dist/internal/expansion.d.ts +3 -2
  35. package/dist/internal/expansion.d.ts.map +1 -1
  36. package/dist/internal/expansion.js +80 -47
  37. package/dist/internal/expansion.js.map +1 -1
  38. package/dist/internal/keys.d.ts +5 -0
  39. package/dist/internal/keys.d.ts.map +1 -0
  40. package/dist/internal/keys.js +13 -0
  41. package/dist/internal/keys.js.map +1 -0
  42. package/dist/internal/selection.d.ts +3 -2
  43. package/dist/internal/selection.d.ts.map +1 -1
  44. package/dist/internal/selection.js +68 -35
  45. package/dist/internal/selection.js.map +1 -1
  46. package/dist/internal/slots.d.ts +10 -0
  47. package/dist/internal/slots.d.ts.map +1 -0
  48. package/dist/internal/slots.js +43 -0
  49. package/dist/internal/slots.js.map +1 -0
  50. package/dist/internal/tree-expansion.d.ts +20 -0
  51. package/dist/internal/tree-expansion.d.ts.map +1 -0
  52. package/dist/internal/tree-expansion.js +68 -0
  53. package/dist/internal/tree-expansion.js.map +1 -0
  54. package/dist/internal/tree-order.d.ts +27 -0
  55. package/dist/internal/tree-order.d.ts.map +1 -0
  56. package/dist/internal/tree-order.js +71 -0
  57. package/dist/internal/tree-order.js.map +1 -0
  58. package/dist/internal/use-collection.d.ts +1 -1
  59. package/dist/internal/use-collection.d.ts.map +1 -1
  60. package/dist/internal/use-collection.js +4 -4
  61. package/dist/internal/use-collection.js.map +1 -1
  62. package/dist/list-view.d.ts.map +1 -1
  63. package/dist/list-view.js +6 -6
  64. package/dist/list-view.js.map +1 -1
  65. package/dist/types.d.ts +70 -21
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/types.js.map +1 -1
  68. package/package.json +7 -7
  69. package/src/column-view.tsx +28 -25
  70. package/src/grid-view.tsx +1 -1
  71. package/src/index.ts +3 -0
  72. package/src/internal/cells.tsx +339 -117
  73. package/src/internal/collection-index.ts +44 -92
  74. package/src/internal/collection-model.ts +259 -107
  75. package/src/internal/collection.ts +45 -67
  76. package/src/internal/controlled-sync.ts +34 -0
  77. package/src/internal/drop-down.tsx +41 -20
  78. package/src/internal/expansion.ts +104 -67
  79. package/src/internal/keys.ts +18 -0
  80. package/src/internal/selection.tsx +100 -51
  81. package/src/internal/slots.ts +67 -0
  82. package/src/internal/tree-expansion.ts +110 -0
  83. package/src/internal/tree-order.ts +138 -0
  84. package/src/internal/use-collection.tsx +5 -5
  85. package/src/list-view.tsx +14 -10
  86. package/src/types.ts +76 -19
@@ -1,13 +1,14 @@
1
1
  import type { ReactElement } from "react";
2
2
  import * as Gtk from "@gtkx/gi/gtk";
3
3
  import type { Collection } from "./collection.js";
4
+ import type { ItemsChangeHandler } from "./expansion.js";
4
5
  type SelectionOptions = {
5
6
  collection: Collection;
6
7
  selectedIds?: string[] | null | undefined;
7
8
  onSelectionChanged?: ((ids: string[]) => void) | null | undefined;
8
9
  selectionMode?: Gtk.SelectionMode | null | undefined;
9
- onItemsChanged: () => void;
10
+ onItemsChanged: ItemsChangeHandler;
10
11
  };
11
12
  declare function useSelection(options: SelectionOptions): ReactElement;
12
- export { useSelection, type SelectionOptions };
13
+ export { useSelection };
13
14
  //# sourceMappingURL=selection.d.ts.map
@@ -1 +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"}
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;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAKzD,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,kBAAkB,CAAC;CACtC,CAAC;AAwKF,iBAAS,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAuB7D;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -1,20 +1,39 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import * as Gtk from "@gtkx/gi/gtk";
3
3
  import { GtkMultiSelection, GtkNoSelection, GtkSingleSelection } from "@gtkx/jsx/gtk";
4
- import { useEffectEvent, useLayoutEffect, useState } from "react";
5
- function getSelectedIds(selection, collection) {
4
+ import { useState } from "react";
5
+ import { isCollectionIdle } from "./collection.js";
6
+ import { useControlledSync } from "./controlled-sync.js";
7
+ import { joinParts } from "./keys.js";
8
+ function selectedPositions(selection) {
6
9
  const bitset = selection.getSelection();
7
10
  const size = Number(bitset.getSize());
8
- const ids = [];
11
+ const positions = [];
9
12
  for (let index = 0; index < size; index++) {
10
- pushId(collection.idAt(bitset.getNth(index)), ids);
13
+ positions.push(bitset.getNth(index));
14
+ }
15
+ return positions;
16
+ }
17
+ function idsAt(collection, positions) {
18
+ const ids = [];
19
+ for (const position of positions) {
20
+ const id = collection.idAt(position);
21
+ if (id !== null) {
22
+ ids.push(id);
23
+ }
11
24
  }
12
25
  return ids;
13
26
  }
14
- function pushId(id, ids) {
15
- if (id !== null) {
16
- ids.push(id);
27
+ function plannedPositions(context, ids) {
28
+ const { selection, collection } = context;
29
+ if (selection === null || selection instanceof Gtk.NoSelection) {
30
+ return null;
31
+ }
32
+ const positions = collection.positionsFor(ids);
33
+ if (ids.length > 0 && positions.length === 0) {
34
+ return null;
17
35
  }
36
+ return selection instanceof Gtk.SingleSelection ? positions.slice(0, 1) : positions;
18
37
  }
19
38
  function applySingleSelection(selection, positions) {
20
39
  const [first] = positions;
@@ -31,32 +50,24 @@ function applyMultiSelection(selection, positions) {
31
50
  }
32
51
  selection.setSelection(selected, Gtk.Bitset.newRange(0, selection.getNItems()));
33
52
  }
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
- }
53
+ function applySelection(selection, positions) {
42
54
  if (selection instanceof Gtk.SingleSelection) {
43
55
  applySingleSelection(selection, positions);
44
56
  return;
45
57
  }
46
58
  applyMultiSelection(selection, positions);
47
59
  }
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) {
60
+ function reportSelection(context, ids) {
61
+ const key = joinParts(ids);
62
+ if (context.last.selection === context.selection && context.last.key === key) {
55
63
  return;
56
64
  }
57
- last.selection = selection;
58
- last.key = key;
59
- onSelectionChanged?.(ids);
65
+ context.last.selection = context.selection;
66
+ context.last.key = key;
67
+ context.onSelectionChanged?.(ids);
68
+ }
69
+ function hasSelectionDrifted(actual, planned) {
70
+ return actual.length !== planned.length || planned.some((position, index) => actual[index] !== position);
60
71
  }
61
72
  function selectionElement(mode, props) {
62
73
  if (mode === Gtk.SelectionMode.MULTIPLE) {
@@ -67,11 +78,31 @@ function selectionElement(mode, props) {
67
78
  }
68
79
  return _jsx(GtkSingleSelection, { ...props, autoselect: false, canUnselect: true });
69
80
  }
70
- function syncSelection(selection, collection, selectedIds) {
71
- if (selection === null || selectedIds == null) {
81
+ function applyControlledSelection(context, selectedIds) {
82
+ const { selection, collection } = context;
83
+ if (selection === null) {
84
+ return;
85
+ }
86
+ const planned = plannedPositions(context, selectedIds ?? []);
87
+ if (planned !== null) {
88
+ applySelection(selection, planned);
89
+ }
90
+ reportSelection(context, idsAt(collection, selectedPositions(selection)));
91
+ }
92
+ function observeSelection(context, selectedIds, onDrift) {
93
+ const { selection, collection } = context;
94
+ if (selection === null) {
72
95
  return;
73
96
  }
74
- applySelection(selection, collection, selectedIds);
97
+ const positions = selectedPositions(selection);
98
+ reportSelection(context, idsAt(collection, positions));
99
+ if (!isCollectionIdle(collection)) {
100
+ return;
101
+ }
102
+ const planned = plannedPositions(context, selectedIds ?? []);
103
+ if (planned !== null && hasSelectionDrifted(positions, planned)) {
104
+ onDrift();
105
+ }
75
106
  }
76
107
  function newLastSelection() {
77
108
  return { selection: null, key: null };
@@ -80,18 +111,20 @@ function useSelection(options) {
80
111
  const { collection, selectedIds, onSelectionChanged, selectionMode } = options;
81
112
  const [selection, setSelection] = useState(null);
82
113
  const [last] = useState(newLastSelection);
83
- const report = useEffectEvent(() => {
84
- reportSelection(selection, collection, last, onSelectionChanged);
114
+ const context = { selection, collection, last, onSelectionChanged };
115
+ const markDrift = useControlledSync({
116
+ ids: selectedIds,
117
+ collection,
118
+ widget: selection,
119
+ apply: (ids) => {
120
+ applyControlledSelection(context, ids);
121
+ },
85
122
  });
86
- useLayoutEffect(() => {
87
- syncSelection(selection, collection, selectedIds);
88
- report();
89
- }, [selection, collection, selectedIds]);
90
123
  return selectionElement(selectionMode, {
91
124
  ref: setSelection,
92
125
  model: collection.model,
93
126
  onSelectionChanged: () => {
94
- reportSelection(selection, collection, last, onSelectionChanged);
127
+ observeSelection(context, selectedIds, markDrift);
95
128
  },
96
129
  onItemsChanged: options.onItemsChanged,
97
130
  });
@@ -1 +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"]}
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 { useState } from \"react\";\nimport type { Collection } from \"./collection.js\";\nimport type { ItemsChangeHandler } from \"./expansion.js\";\nimport { isCollectionIdle } from \"./collection.js\";\nimport { useControlledSync } from \"./controlled-sync.js\";\nimport { joinParts } from \"./keys.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: ItemsChangeHandler;\n};\n\ntype LastSelection = {\n selection: Gtk.SelectionModel | null;\n key: string | null;\n};\n\ntype SelectionContext = {\n selection: Gtk.SelectionModel | null;\n collection: Collection;\n last: LastSelection;\n onSelectionChanged?: ((ids: string[]) => void) | null | undefined;\n};\n\ntype SelectionElementProps = {\n ref: (value: Gtk.SelectionModel | null) => void;\n model: Gio.ListModel;\n onSelectionChanged: () => void;\n onItemsChanged: ItemsChangeHandler;\n};\n\nfunction selectedPositions(selection: Gtk.SelectionModel): number[] {\n const bitset = selection.getSelection();\n const size = Number(bitset.getSize());\n const positions: number[] = [];\n\n for (let index = 0; index < size; index++) {\n positions.push(bitset.getNth(index));\n }\n\n return positions;\n}\n\nfunction idsAt(collection: Collection, positions: number[]): string[] {\n const ids: string[] = [];\n\n for (const position of positions) {\n const id = collection.idAt(position);\n\n if (id !== null) {\n ids.push(id);\n }\n }\n\n return ids;\n}\n\nfunction plannedPositions(context: SelectionContext, ids: string[]): number[] | null {\n const { selection, collection } = context;\n\n if (selection === null || selection instanceof Gtk.NoSelection) {\n return null;\n }\n\n const positions = collection.positionsFor(ids);\n\n if (ids.length > 0 && positions.length === 0) {\n return null;\n }\n\n return selection instanceof Gtk.SingleSelection ? positions.slice(0, 1) : positions;\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, positions: number[]): void {\n if (selection instanceof Gtk.SingleSelection) {\n applySingleSelection(selection, positions);\n\n return;\n }\n\n applyMultiSelection(selection, positions);\n}\n\nfunction reportSelection(context: SelectionContext, ids: string[]): void {\n const key = joinParts(ids);\n\n if (context.last.selection === context.selection && context.last.key === key) {\n return;\n }\n\n context.last.selection = context.selection;\n context.last.key = key;\n context.onSelectionChanged?.(ids);\n}\n\nfunction hasSelectionDrifted(actual: number[], planned: number[]): boolean {\n return actual.length !== planned.length || planned.some((position, index) => actual[index] !== position);\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 applyControlledSelection(context: SelectionContext, selectedIds: string[] | null | undefined): void {\n const { selection, collection } = context;\n\n if (selection === null) {\n return;\n }\n\n const planned = plannedPositions(context, selectedIds ?? []);\n\n if (planned !== null) {\n applySelection(selection, planned);\n }\n\n reportSelection(context, idsAt(collection, selectedPositions(selection)));\n}\n\nfunction observeSelection(\n context: SelectionContext,\n selectedIds: string[] | null | undefined,\n onDrift: () => void,\n): void {\n const { selection, collection } = context;\n\n if (selection === null) {\n return;\n }\n\n const positions = selectedPositions(selection);\n reportSelection(context, idsAt(collection, positions));\n\n if (!isCollectionIdle(collection)) {\n return;\n }\n\n const planned = plannedPositions(context, selectedIds ?? []);\n\n if (planned !== null && hasSelectionDrifted(positions, planned)) {\n onDrift();\n }\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 const context: SelectionContext = { selection, collection, last, onSelectionChanged };\n\n const markDrift = useControlledSync({\n ids: selectedIds,\n collection,\n widget: selection,\n apply: (ids) => {\n applyControlledSelection(context, ids);\n },\n });\n\n return selectionElement(selectionMode, {\n ref: setSelection,\n model: collection.model,\n onSelectionChanged: () => {\n observeSelection(context, selectedIds, markDrift);\n },\n onItemsChanged: options.onItemsChanged,\n });\n}\n\nexport { useSelection };\n"]}
@@ -0,0 +1,10 @@
1
+ type SlotKey = {
2
+ levelPath: string;
3
+ slot: number;
4
+ };
5
+ type SlotMap = Map<string, Set<number>>;
6
+ declare function getSlotKey(path: string): SlotKey | null;
7
+ declare function trackPath(slots: SlotMap, path: string): void;
8
+ declare function trackPaths(paths: Iterable<string>): SlotMap;
9
+ export { getSlotKey, trackPath, trackPaths, type SlotMap };
10
+ //# sourceMappingURL=slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../src/internal/slots.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAoBxC,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAShD;AAED,iBAAS,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBrD;AAED,iBAAS,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAQpD;AAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { decodePartAt, encodePart } from "./keys.js";
2
+ function getLevelBoundary(path) {
3
+ let offset = 0;
4
+ let boundary = 0;
5
+ while (offset < path.length) {
6
+ const part = decodePartAt(path, offset);
7
+ if (part === null) {
8
+ return boundary;
9
+ }
10
+ boundary = offset;
11
+ offset += encodePart(part).length;
12
+ }
13
+ return boundary;
14
+ }
15
+ function getSlotKey(path) {
16
+ const boundary = getLevelBoundary(path);
17
+ const part = decodePartAt(path, boundary);
18
+ if (part === null) {
19
+ return null;
20
+ }
21
+ return { levelPath: path.slice(0, boundary), slot: Number(part) };
22
+ }
23
+ function trackPath(slots, path) {
24
+ const key = getSlotKey(path);
25
+ if (key === null) {
26
+ return;
27
+ }
28
+ const level = slots.get(key.levelPath);
29
+ if (level === undefined) {
30
+ slots.set(key.levelPath, new Set([key.slot]));
31
+ return;
32
+ }
33
+ level.add(key.slot);
34
+ }
35
+ function trackPaths(paths) {
36
+ const slots = new Map();
37
+ for (const path of paths) {
38
+ trackPath(slots, path);
39
+ }
40
+ return slots;
41
+ }
42
+ export { getSlotKey, trackPath, trackPaths };
43
+ //# sourceMappingURL=slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots.js","sourceRoot":"","sources":["../../src/internal/slots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AASrD,SAAS,gBAAgB,CAAC,IAAY;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAExC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAChB,OAAO,QAAQ,CAAC;QACpB,CAAC;QAED,QAAQ,GAAG,MAAM,CAAC;QAClB,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IACtC,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC5B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE1C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,SAAS,SAAS,CAAC,KAAc,EAAE,IAAY;IAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACf,OAAO;IACX,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE9C,OAAO;IACX,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,KAAuB;IACvC,MAAM,KAAK,GAAY,IAAI,GAAG,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAgB,CAAC","sourcesContent":["import { decodePartAt, encodePart } from \"./keys.js\";\n\ntype SlotKey = {\n levelPath: string;\n slot: number;\n};\n\ntype SlotMap = Map<string, Set<number>>;\n\nfunction getLevelBoundary(path: string): number {\n let offset = 0;\n let boundary = 0;\n\n while (offset < path.length) {\n const part = decodePartAt(path, offset);\n\n if (part === null) {\n return boundary;\n }\n\n boundary = offset;\n offset += encodePart(part).length;\n }\n\n return boundary;\n}\n\nfunction getSlotKey(path: string): SlotKey | null {\n const boundary = getLevelBoundary(path);\n const part = decodePartAt(path, boundary);\n\n if (part === null) {\n return null;\n }\n\n return { levelPath: path.slice(0, boundary), slot: Number(part) };\n}\n\nfunction trackPath(slots: SlotMap, path: string): void {\n const key = getSlotKey(path);\n\n if (key === null) {\n return;\n }\n\n const level = slots.get(key.levelPath);\n\n if (level === undefined) {\n slots.set(key.levelPath, new Set([key.slot]));\n\n return;\n }\n\n level.add(key.slot);\n}\n\nfunction trackPaths(paths: Iterable<string>): SlotMap {\n const slots: SlotMap = new Map();\n\n for (const path of paths) {\n trackPath(slots, path);\n }\n\n return slots;\n}\n\nexport { getSlotKey, trackPath, trackPaths, type SlotMap };\n"]}
@@ -0,0 +1,20 @@
1
+ import type { CollectionIndex } from "./collection-index.js";
2
+ import type { SlotMap } from "./slots.js";
3
+ import type { VisibleOrder } from "./tree-order.js";
4
+ type TreeExpansion = {
5
+ index: CollectionIndex;
6
+ expanded: Set<string>;
7
+ slots: SlotMap;
8
+ order: VisibleOrder | null;
9
+ isApplying: boolean;
10
+ isSyncing: boolean;
11
+ };
12
+ declare function createTreeExpansion(index: CollectionIndex): TreeExpansion;
13
+ declare function orderFor(expansion: TreeExpansion): VisibleOrder;
14
+ declare function adoptOrder(expansion: TreeExpansion, order: VisibleOrder): void;
15
+ declare function pruneSlots(expansion: TreeExpansion, levelPath: string, isPruned: (slot: number) => boolean): void;
16
+ declare function markExpanded(expansion: TreeExpansion, path: string, isExpanded: boolean): void;
17
+ declare function resetExpansion(expansion: TreeExpansion): void;
18
+ declare function adoptIndex(expansion: TreeExpansion, index: CollectionIndex): void;
19
+ export { adoptIndex, adoptOrder, createTreeExpansion, markExpanded, orderFor, pruneSlots, resetExpansion, type TreeExpansion, };
20
+ //# sourceMappingURL=tree-expansion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-expansion.d.ts","sourceRoot":"","sources":["../../src/internal/tree-expansion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD,KAAK,aAAa,GAAG;IACjB,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACtB,CAAC;AAiBF,iBAAS,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,CAElE;AAED,iBAAS,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,YAAY,CAIxD;AAED,iBAAS,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAIvE;AAaD,iBAAS,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAiB1G;AAED,iBAAS,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAUvF;AAED,iBAAS,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAItD;AAED,iBAAS,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAG1E;AAED,OAAO,EACH,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,cAAc,EACd,KAAK,aAAa,GACrB,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { encodePart } from "./keys.js";
2
+ import { getSlotKey, trackPath, trackPaths } from "./slots.js";
3
+ import { buildVisibleOrder } from "./tree-order.js";
4
+ function dropSubtree(expansion, path) {
5
+ expansion.expanded.delete(path);
6
+ const level = expansion.slots.get(path);
7
+ if (level === undefined) {
8
+ return;
9
+ }
10
+ expansion.slots.delete(path);
11
+ for (const slot of level) {
12
+ dropSubtree(expansion, path + encodePart(String(slot)));
13
+ }
14
+ }
15
+ function createTreeExpansion(index) {
16
+ return { index, expanded: new Set(), slots: new Map(), order: null, isApplying: false, isSyncing: false };
17
+ }
18
+ function orderFor(expansion) {
19
+ expansion.order ??= buildVisibleOrder(expansion.index, expansion.slots);
20
+ return expansion.order;
21
+ }
22
+ function adoptOrder(expansion, order) {
23
+ expansion.expanded = new Set(order.expandedPaths);
24
+ expansion.slots = trackPaths(order.expandedPaths);
25
+ expansion.order = order;
26
+ }
27
+ function prunePath(expansion, path) {
28
+ const key = getSlotKey(path);
29
+ if (key !== null) {
30
+ expansion.slots.get(key.levelPath)?.delete(key.slot);
31
+ }
32
+ dropSubtree(expansion, path);
33
+ expansion.order = null;
34
+ }
35
+ function pruneSlots(expansion, levelPath, isPruned) {
36
+ const level = expansion.slots.get(levelPath);
37
+ if (level === undefined) {
38
+ return;
39
+ }
40
+ for (const slot of level) {
41
+ if (!isPruned(slot)) {
42
+ continue;
43
+ }
44
+ level.delete(slot);
45
+ dropSubtree(expansion, levelPath + encodePart(String(slot)));
46
+ }
47
+ expansion.order = null;
48
+ }
49
+ function markExpanded(expansion, path, isExpanded) {
50
+ if (isExpanded) {
51
+ expansion.expanded.add(path);
52
+ trackPath(expansion.slots, path);
53
+ expansion.order = null;
54
+ return;
55
+ }
56
+ prunePath(expansion, path);
57
+ }
58
+ function resetExpansion(expansion) {
59
+ expansion.expanded = new Set();
60
+ expansion.slots = new Map();
61
+ expansion.order = null;
62
+ }
63
+ function adoptIndex(expansion, index) {
64
+ expansion.index = index;
65
+ expansion.order = null;
66
+ }
67
+ export { adoptIndex, adoptOrder, createTreeExpansion, markExpanded, orderFor, pruneSlots, resetExpansion, };
68
+ //# sourceMappingURL=tree-expansion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-expansion.js","sourceRoot":"","sources":["../../src/internal/tree-expansion.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAWpD,SAAS,WAAW,CAAC,SAAwB,EAAE,IAAY;IACvD,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAExC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;IACX,CAAC;IAED,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,WAAW,CAAC,SAAS,EAAE,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAsB;IAC/C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9G,CAAC;AAED,SAAS,QAAQ,CAAC,SAAwB;IACtC,SAAS,CAAC,KAAK,KAAK,iBAAiB,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IAExE,OAAO,SAAS,CAAC,KAAK,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,SAAwB,EAAE,KAAmB;IAC7D,SAAS,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClD,SAAS,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClD,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC;AAC5B,CAAC;AAED,SAAS,SAAS,CAAC,SAAwB,EAAE,IAAY;IACrD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACf,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;IAED,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC7B,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,SAAwB,EAAE,SAAiB,EAAE,QAAmC;IAChG,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAE7C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;IACX,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,SAAS;QACb,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;AAC3B,CAAC;AAED,SAAS,YAAY,CAAC,SAAwB,EAAE,IAAY,EAAE,UAAmB;IAC7E,IAAI,UAAU,EAAE,CAAC;QACb,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7B,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACjC,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;QAEvB,OAAO;IACX,CAAC;IAED,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,cAAc,CAAC,SAAwB;IAC5C,SAAS,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;IAC/B,SAAS,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IAC5B,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,SAAwB,EAAE,KAAsB;IAChE,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC;IACxB,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;AAC3B,CAAC;AAED,OAAO,EACH,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,cAAc,GAEjB,CAAC","sourcesContent":["import type { CollectionIndex } from \"./collection-index.js\";\nimport type { SlotMap } from \"./slots.js\";\nimport type { VisibleOrder } from \"./tree-order.js\";\nimport { encodePart } from \"./keys.js\";\nimport { getSlotKey, trackPath, trackPaths } from \"./slots.js\";\nimport { buildVisibleOrder } from \"./tree-order.js\";\n\ntype TreeExpansion = {\n index: CollectionIndex;\n expanded: Set<string>;\n slots: SlotMap;\n order: VisibleOrder | null;\n isApplying: boolean;\n isSyncing: boolean;\n};\n\nfunction dropSubtree(expansion: TreeExpansion, path: string): void {\n expansion.expanded.delete(path);\n const level = expansion.slots.get(path);\n\n if (level === undefined) {\n return;\n }\n\n expansion.slots.delete(path);\n\n for (const slot of level) {\n dropSubtree(expansion, path + encodePart(String(slot)));\n }\n}\n\nfunction createTreeExpansion(index: CollectionIndex): TreeExpansion {\n return { index, expanded: new Set(), slots: new Map(), order: null, isApplying: false, isSyncing: false };\n}\n\nfunction orderFor(expansion: TreeExpansion): VisibleOrder {\n expansion.order ??= buildVisibleOrder(expansion.index, expansion.slots);\n\n return expansion.order;\n}\n\nfunction adoptOrder(expansion: TreeExpansion, order: VisibleOrder): void {\n expansion.expanded = new Set(order.expandedPaths);\n expansion.slots = trackPaths(order.expandedPaths);\n expansion.order = order;\n}\n\nfunction prunePath(expansion: TreeExpansion, path: string): void {\n const key = getSlotKey(path);\n\n if (key !== null) {\n expansion.slots.get(key.levelPath)?.delete(key.slot);\n }\n\n dropSubtree(expansion, path);\n expansion.order = null;\n}\n\nfunction pruneSlots(expansion: TreeExpansion, levelPath: string, isPruned: (slot: number) => boolean): void {\n const level = expansion.slots.get(levelPath);\n\n if (level === undefined) {\n return;\n }\n\n for (const slot of level) {\n if (!isPruned(slot)) {\n continue;\n }\n\n level.delete(slot);\n dropSubtree(expansion, levelPath + encodePart(String(slot)));\n }\n\n expansion.order = null;\n}\n\nfunction markExpanded(expansion: TreeExpansion, path: string, isExpanded: boolean): void {\n if (isExpanded) {\n expansion.expanded.add(path);\n trackPath(expansion.slots, path);\n expansion.order = null;\n\n return;\n }\n\n prunePath(expansion, path);\n}\n\nfunction resetExpansion(expansion: TreeExpansion): void {\n expansion.expanded = new Set();\n expansion.slots = new Map();\n expansion.order = null;\n}\n\nfunction adoptIndex(expansion: TreeExpansion, index: CollectionIndex): void {\n expansion.index = index;\n expansion.order = null;\n}\n\nexport {\n adoptIndex,\n adoptOrder,\n createTreeExpansion,\n markExpanded,\n orderFor,\n pruneSlots,\n resetExpansion,\n type TreeExpansion,\n};\n"]}
@@ -0,0 +1,27 @@
1
+ import type { ListItem } from "../types.js";
2
+ import type { CollectionIndex, Level } from "./collection-index.js";
3
+ import type { SlotMap } from "./slots.js";
4
+ type VisibleRow = {
5
+ level: Level;
6
+ slot: number;
7
+ item: ListItem;
8
+ position: number;
9
+ isOpen: boolean;
10
+ isMarked: boolean;
11
+ };
12
+ type VisibleOrder = {
13
+ expandedPaths: string[];
14
+ expandedIds: string[];
15
+ };
16
+ type RowVisitor = (row: VisibleRow) => void;
17
+ type WalkOptions = {
18
+ index: CollectionIndex;
19
+ slots: SlotMap;
20
+ marks?: SlotMap | undefined;
21
+ visit?: RowVisitor | undefined;
22
+ };
23
+ declare function walkVisible(options: WalkOptions): VisibleOrder;
24
+ declare function buildVisibleOrder(index: CollectionIndex, slots: SlotMap): VisibleOrder;
25
+ declare function findPositions(index: CollectionIndex, slots: SlotMap, ids: Set<string>): number[];
26
+ export { buildVisibleOrder, findPositions, walkVisible, type VisibleOrder, type WalkOptions, };
27
+ //# sourceMappingURL=tree-order.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-order.d.ts","sourceRoot":"","sources":["../../src/internal/tree-order.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,KAAK,UAAU,GAAG;IACd,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,KAAK,YAAY,GAAG;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC;AAE5C,KAAK,WAAW,GAAG;IACf,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAClC,CAAC;AAwEF,iBAAS,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAWvD;AAED,iBAAS,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAE/E;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAczF;AAED,OAAO,EACH,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,WAAW,GACnB,CAAC"}
@@ -0,0 +1,71 @@
1
+ import { encodePart } from "./keys.js";
2
+ const NO_LEVEL = { path: "", items: [], expandableFlags: [] };
3
+ const NO_ITEM = { id: "", value: undefined };
4
+ const getRowPath = (row) => row.level.path + encodePart(String(row.slot));
5
+ function frameFor(options, level) {
6
+ return { level, cursor: 0, open: options.slots.get(level.path), marked: options.marks?.get(level.path) };
7
+ }
8
+ function descend(state, path) {
9
+ const child = state.options.index.children.get(path);
10
+ if (child === undefined || child.items.length === 0) {
11
+ return;
12
+ }
13
+ state.order.expandedPaths.push(path);
14
+ state.order.expandedIds.push(state.row.item.id);
15
+ state.stack.push(frameFor(state.options, child));
16
+ }
17
+ function visitSlot(state, frame, slot) {
18
+ const item = frame.level.items[slot];
19
+ if (item === undefined) {
20
+ return;
21
+ }
22
+ const { row } = state;
23
+ row.level = frame.level;
24
+ row.slot = slot;
25
+ row.item = item;
26
+ row.isOpen = frame.open?.has(slot) ?? false;
27
+ row.isMarked = frame.marked?.has(slot) ?? false;
28
+ state.options.visit?.(row);
29
+ row.position += 1;
30
+ if (row.isOpen) {
31
+ descend(state, getRowPath(row));
32
+ }
33
+ }
34
+ function advanceFrame(state) {
35
+ const frame = state.stack.at(-1);
36
+ if (frame === undefined || frame.cursor >= frame.level.items.length) {
37
+ state.stack.pop();
38
+ return;
39
+ }
40
+ const slot = frame.cursor;
41
+ frame.cursor += 1;
42
+ visitSlot(state, frame, slot);
43
+ }
44
+ function walkVisible(options) {
45
+ const order = { expandedPaths: [], expandedIds: [] };
46
+ const row = { level: NO_LEVEL, slot: 0, item: NO_ITEM, position: 0, isOpen: false, isMarked: false };
47
+ const frames = options.index.groups.map((level) => frameFor(options, level));
48
+ const state = { options, stack: frames.toReversed(), row, order };
49
+ while (state.stack.length > 0) {
50
+ advanceFrame(state);
51
+ }
52
+ return order;
53
+ }
54
+ function buildVisibleOrder(index, slots) {
55
+ return walkVisible({ index, slots });
56
+ }
57
+ function findPositions(index, slots, ids) {
58
+ const found = [];
59
+ walkVisible({
60
+ index,
61
+ slots,
62
+ visit: (row) => {
63
+ if (ids.has(row.item.id)) {
64
+ found.push(row.position);
65
+ }
66
+ },
67
+ });
68
+ return found;
69
+ }
70
+ export { buildVisibleOrder, findPositions, walkVisible, };
71
+ //# sourceMappingURL=tree-order.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-order.js","sourceRoot":"","sources":["../../src/internal/tree-order.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ListItem } from \"../types.js\";\nimport type { CollectionIndex, Level } from \"./collection-index.js\";\nimport type { SlotMap } from \"./slots.js\";\nimport { encodePart } from \"./keys.js\";\n\ntype VisibleRow = {\n level: Level;\n slot: number;\n item: ListItem;\n position: number;\n isOpen: boolean;\n isMarked: boolean;\n};\n\ntype VisibleOrder = {\n expandedPaths: string[];\n expandedIds: string[];\n};\n\ntype RowVisitor = (row: VisibleRow) => void;\n\ntype WalkOptions = {\n index: CollectionIndex;\n slots: SlotMap;\n marks?: SlotMap | undefined;\n visit?: RowVisitor | undefined;\n};\n\ntype WalkFrame = {\n level: Level;\n cursor: number;\n open: Set<number> | undefined;\n marked: Set<number> | undefined;\n};\n\ntype WalkState = {\n options: WalkOptions;\n stack: WalkFrame[];\n row: VisibleRow;\n order: VisibleOrder;\n};\n\nconst NO_LEVEL: Level = { path: \"\", items: [], expandableFlags: [] };\nconst NO_ITEM: ListItem = { id: \"\", value: undefined };\n\nconst getRowPath = (row: VisibleRow): string => row.level.path + encodePart(String(row.slot));\n\nfunction frameFor(options: WalkOptions, level: Level): WalkFrame {\n return { level, cursor: 0, open: options.slots.get(level.path), marked: options.marks?.get(level.path) };\n}\n\nfunction descend(state: WalkState, path: string): void {\n const child = state.options.index.children.get(path);\n\n if (child === undefined || child.items.length === 0) {\n return;\n }\n\n state.order.expandedPaths.push(path);\n state.order.expandedIds.push(state.row.item.id);\n state.stack.push(frameFor(state.options, child));\n}\n\nfunction visitSlot(state: WalkState, frame: WalkFrame, slot: number): void {\n const item = frame.level.items[slot];\n\n if (item === undefined) {\n return;\n }\n\n const { row } = state;\n row.level = frame.level;\n row.slot = slot;\n row.item = item;\n row.isOpen = frame.open?.has(slot) ?? false;\n row.isMarked = frame.marked?.has(slot) ?? false;\n state.options.visit?.(row);\n row.position += 1;\n\n if (row.isOpen) {\n descend(state, getRowPath(row));\n }\n}\n\nfunction advanceFrame(state: WalkState): void {\n const frame = state.stack.at(-1);\n\n if (frame === undefined || frame.cursor >= frame.level.items.length) {\n state.stack.pop();\n\n return;\n }\n\n const slot = frame.cursor;\n frame.cursor += 1;\n visitSlot(state, frame, slot);\n}\n\nfunction walkVisible(options: WalkOptions): VisibleOrder {\n const order: VisibleOrder = { expandedPaths: [], expandedIds: [] };\n const row: VisibleRow = { level: NO_LEVEL, slot: 0, item: NO_ITEM, position: 0, isOpen: false, isMarked: false };\n const frames = options.index.groups.map((level) => frameFor(options, level));\n const state: WalkState = { options, stack: frames.toReversed(), row, order };\n\n while (state.stack.length > 0) {\n advanceFrame(state);\n }\n\n return order;\n}\n\nfunction buildVisibleOrder(index: CollectionIndex, slots: SlotMap): VisibleOrder {\n return walkVisible({ index, slots });\n}\n\nfunction findPositions(index: CollectionIndex, slots: SlotMap, ids: Set<string>): number[] {\n const found: number[] = [];\n\n walkVisible({\n index,\n slots,\n visit: (row) => {\n if (ids.has(row.item.id)) {\n found.push(row.position);\n }\n },\n });\n\n return found;\n}\n\nexport {\n buildVisibleOrder,\n findPositions,\n walkVisible,\n type VisibleOrder,\n type WalkOptions,\n};\n"]}
@@ -13,5 +13,5 @@ type CollectionResult = {
13
13
  };
14
14
  declare function useCollectionData(options: CollectionDataOptions): Collection;
15
15
  declare function useCollection(options: CollectionOptions): CollectionResult;
16
- export { useCollection, useCollectionData, type CollectionDataOptions, type CollectionOptions };
16
+ export { useCollection, useCollectionData };
17
17
  //# sourceMappingURL=use-collection.d.ts.map
@@ -1 +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,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOlD,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC,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"}
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,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOlD,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC,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,CAAC"}
@@ -6,12 +6,12 @@ import { useExpansion } from "./expansion.js";
6
6
  import { useSelection } from "./selection.js";
7
7
  function useCollectionData(options) {
8
8
  const { items, sections, isFlat } = options;
9
- const [gtk] = useState(createCollectionModel);
9
+ const [collectionModel] = useState(createCollectionModel);
10
10
  const index = useMemo(() => createCollectionIndex(items, sections, isFlat === true), [items, sections, isFlat]);
11
- const collection = useMemo(() => createCollection(gtk, index), [gtk, index]);
11
+ const collection = useMemo(() => createCollection(collectionModel, index), [collectionModel, index]);
12
12
  useLayoutEffect(() => {
13
- gtk.sync(index);
14
- }, [gtk, index]);
13
+ collectionModel.sync(index);
14
+ }, [collectionModel, index]);
15
15
  return collection;
16
16
  }
17
17
  function useCollection(options) {
@@ -1 +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,MAAM,EAAE,GAAG,OAAO,CAAC;IAC5C,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,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAChH,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, ListItem, ListSection, 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?: ListItem[] | undefined;\n sections?: ListSection[] | undefined;\n isFlat?: 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, isFlat } = options;\n const [gtk] = useState(createCollectionModel);\n const index = useMemo(() => createCollectionIndex(items, sections, isFlat === true), [items, sections, isFlat]);\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"]}
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,MAAM,EAAE,GAAG,OAAO,CAAC;IAC5C,MAAM,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAChH,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC;IAErG,eAAe,CAAC,GAAG,EAAE;QACjB,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC;IAE7B,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,EAAE,CAAC","sourcesContent":["import type { ReactElement } from \"react\";\nimport { useLayoutEffect, useMemo, useState } from \"react\";\nimport type { ExpansionProps, ListItem, ListSection, 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?: ListItem[] | undefined;\n sections?: ListSection[] | undefined;\n isFlat?: 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, isFlat } = options;\n const [collectionModel] = useState(createCollectionModel);\n const index = useMemo(() => createCollectionIndex(items, sections, isFlat === true), [items, sections, isFlat]);\n const collection = useMemo(() => createCollection(collectionModel, index), [collectionModel, index]);\n\n useLayoutEffect(() => {\n collectionModel.sync(index);\n }, [collectionModel, 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 };\n"]}
@@ -1 +1 @@
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"}
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;AAmBhD;;;GAGG;AACH,iBAAS,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CA2BjF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
package/dist/list-view.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { GtkListView, GtkSignalListItemFactory } from "@gtkx/jsx/gtk";
3
3
  import { omit } from "@gtkx/utils";
4
- import { HeaderPortals, ItemPortals, useHeaderCells, useItemCells } from "./internal/cells.js";
4
+ import { ItemPortals, useItemCells, useSectionHeader } from "./internal/cells.js";
5
5
  import { useCollection } from "./internal/use-collection.js";
6
6
  const LIST_VIEW_PROPS = [
7
7
  "items",
@@ -13,6 +13,7 @@ const LIST_VIEW_PROPS = [
13
13
  "selectionMode",
14
14
  "expandedIds",
15
15
  "onExpandedChange",
16
+ "expanderDescriptions",
16
17
  "estimatedItemHeight",
17
18
  "estimatedItemWidth",
18
19
  ];
@@ -21,15 +22,14 @@ const LIST_VIEW_PROPS = [
21
22
  * controlled selection, controlled tree expansion, and estimated item sizing.
22
23
  */
23
24
  function ListView(props) {
24
- const { renderItem, renderHeader, expandedIds, estimatedItemHeight, estimatedItemWidth } = props;
25
+ const { renderItem, renderHeader, expandedIds, expanderDescriptions } = props;
26
+ const { estimatedItemHeight, estimatedItemWidth } = props;
25
27
  const rest = omit(props, LIST_VIEW_PROPS);
26
28
  const size = { width: estimatedItemWidth ?? -1, height: estimatedItemHeight ?? -1 };
27
29
  const { collection, selection } = useCollection(props);
28
30
  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 }))] }));
31
+ const header = useSectionHeader(renderHeader, collection, size);
32
+ return (_jsxs(_Fragment, { children: [_jsx(GtkListView, { model: selection, factory: _jsx(GtkSignalListItemFactory, { ...itemCells.handlers }), ...header.factoryProps, ...rest }), _jsx(ItemPortals, { registry: itemCells, render: renderItem, collection: collection, expandedIds: expandedIds, expanderDescriptions: expanderDescriptions }), header.portals] }));
33
33
  }
34
34
  export { ListView };
35
35
  //# sourceMappingURL=list-view.js.map