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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +4 -4
  2. package/dist/column-view.d.ts.map +1 -1
  3. package/dist/column-view.js +8 -4
  4. package/dist/column-view.js.map +1 -1
  5. package/dist/combo-row.d.ts.map +1 -1
  6. package/dist/combo-row.js +3 -1
  7. package/dist/combo-row.js.map +1 -1
  8. package/dist/grid-view.d.ts.map +1 -1
  9. package/dist/grid-view.js +4 -3
  10. package/dist/grid-view.js.map +1 -1
  11. package/dist/internal/cells.d.ts +8 -9
  12. package/dist/internal/cells.d.ts.map +1 -1
  13. package/dist/internal/cells.js +98 -83
  14. package/dist/internal/cells.js.map +1 -1
  15. package/dist/internal/collection-index.d.ts +3 -5
  16. package/dist/internal/collection-index.d.ts.map +1 -1
  17. package/dist/internal/collection-index.js +3 -7
  18. package/dist/internal/collection-index.js.map +1 -1
  19. package/dist/internal/collection-model.d.ts +15 -4
  20. package/dist/internal/collection-model.d.ts.map +1 -1
  21. package/dist/internal/collection-model.js +154 -73
  22. package/dist/internal/collection-model.js.map +1 -1
  23. package/dist/internal/collection.d.ts +3 -3
  24. package/dist/internal/collection.d.ts.map +1 -1
  25. package/dist/internal/collection.js +11 -9
  26. package/dist/internal/collection.js.map +1 -1
  27. package/dist/internal/controlled-sync.d.ts +2 -1
  28. package/dist/internal/controlled-sync.d.ts.map +1 -1
  29. package/dist/internal/controlled-sync.js +6 -1
  30. package/dist/internal/controlled-sync.js.map +1 -1
  31. package/dist/internal/drop-down.d.ts +10 -4
  32. package/dist/internal/drop-down.d.ts.map +1 -1
  33. package/dist/internal/drop-down.js +61 -9
  34. package/dist/internal/drop-down.js.map +1 -1
  35. package/dist/internal/expansion.d.ts.map +1 -1
  36. package/dist/internal/expansion.js +46 -19
  37. package/dist/internal/expansion.js.map +1 -1
  38. package/dist/internal/first-header.d.ts +11 -0
  39. package/dist/internal/first-header.d.ts.map +1 -0
  40. package/dist/internal/first-header.js +21 -0
  41. package/dist/internal/first-header.js.map +1 -0
  42. package/dist/internal/keys.d.ts.map +1 -1
  43. package/dist/internal/level-splice.d.ts +27 -0
  44. package/dist/internal/level-splice.d.ts.map +1 -0
  45. package/dist/internal/level-splice.js +98 -0
  46. package/dist/internal/level-splice.js.map +1 -0
  47. package/dist/internal/selection.d.ts.map +1 -1
  48. package/dist/internal/selection.js +23 -16
  49. package/dist/internal/selection.js.map +1 -1
  50. package/dist/internal/tree-expansion.d.ts +3 -1
  51. package/dist/internal/tree-expansion.d.ts.map +1 -1
  52. package/dist/internal/tree-expansion.js +31 -2
  53. package/dist/internal/tree-expansion.js.map +1 -1
  54. package/dist/internal/tree-order.d.ts +2 -1
  55. package/dist/internal/tree-order.d.ts.map +1 -1
  56. package/dist/internal/tree-order.js +3 -2
  57. package/dist/internal/tree-order.js.map +1 -1
  58. package/dist/internal/use-collection.d.ts +1 -0
  59. package/dist/internal/use-collection.d.ts.map +1 -1
  60. package/dist/internal/use-collection.js +6 -2
  61. package/dist/internal/use-collection.js.map +1 -1
  62. package/dist/internal/use-widget-ref.d.ts.map +1 -1
  63. package/dist/list-item-factory.d.ts +1 -1
  64. package/dist/list-item-factory.d.ts.map +1 -1
  65. package/dist/list-item-factory.js +3 -3
  66. package/dist/list-item-factory.js.map +1 -1
  67. package/dist/list-view.d.ts.map +1 -1
  68. package/dist/list-view.js +9 -4
  69. package/dist/list-view.js.map +1 -1
  70. package/dist/types.d.ts +35 -12
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/types.js.map +1 -1
  73. package/package.json +10 -20
  74. package/src/column-view.tsx +8 -4
  75. package/src/combo-row.tsx +4 -1
  76. package/src/grid-view.tsx +3 -2
  77. package/src/internal/cells.tsx +174 -151
  78. package/src/internal/collection-index.ts +7 -14
  79. package/src/internal/collection-model.ts +211 -76
  80. package/src/internal/collection.ts +14 -13
  81. package/src/internal/controlled-sync.ts +8 -1
  82. package/src/internal/drop-down.tsx +112 -19
  83. package/src/internal/expansion.ts +52 -20
  84. package/src/internal/first-header.ts +23 -0
  85. package/src/internal/level-splice.ts +157 -0
  86. package/src/internal/selection.tsx +24 -19
  87. package/src/internal/tree-expansion.ts +43 -1
  88. package/src/internal/tree-order.ts +4 -10
  89. package/src/internal/use-collection.tsx +8 -2
  90. package/src/list-item-factory.tsx +2 -1
  91. package/src/list-view.tsx +10 -2
  92. package/src/types.ts +54 -24
@@ -0,0 +1,98 @@
1
+ import { joinParts } from "./keys.js";
2
+ const NO_MOVES = new Map();
3
+ const NO_SPLICE = { start: 0, removed: 0, added: 0 };
4
+ const MOVE_SEARCH_LIMIT = 1024;
5
+ function findSplice(keys) {
6
+ const { previousLength, nextLength, previousKey, nextKey } = keys;
7
+ const overlap = Math.min(previousLength, nextLength);
8
+ let start = 0;
9
+ while (start < overlap && previousKey(start) === nextKey(start)) {
10
+ start += 1;
11
+ }
12
+ let shared = 0;
13
+ while (shared < overlap - start && previousKey(previousLength - 1 - shared) === nextKey(nextLength - 1 - shared)) {
14
+ shared += 1;
15
+ }
16
+ return { start, removed: previousLength - start - shared, added: nextLength - start - shared };
17
+ }
18
+ function hasSplice(splice) {
19
+ return splice.removed > 0 || splice.added > 0;
20
+ }
21
+ function isRemoved(splice, slot) {
22
+ return slot >= splice.start && slot < splice.start + splice.removed;
23
+ }
24
+ function occurrenceKeys(key, from, length, wanted) {
25
+ const counts = new Map();
26
+ const keys = new Map();
27
+ for (let slot = from; slot < from + length; slot++) {
28
+ const id = key(slot);
29
+ if (!wanted.has(id)) {
30
+ continue;
31
+ }
32
+ const occurrence = counts.get(id) ?? 0;
33
+ counts.set(id, occurrence + 1);
34
+ keys.set(slot, joinParts([id, String(occurrence)]));
35
+ }
36
+ return keys;
37
+ }
38
+ function matchMoves(keys, splice, candidates) {
39
+ const removed = Iterator.from(candidates)
40
+ .filter((slot) => isRemoved(splice, slot))
41
+ .toArray();
42
+ if (removed.length === 0 || splice.added === 0) {
43
+ return NO_MOVES;
44
+ }
45
+ const wanted = new Set(removed.map((slot) => keys.previousKey(slot)));
46
+ const previous = occurrenceKeys(keys.previousKey, splice.start, splice.removed, wanted);
47
+ const bySlotKey = new Map();
48
+ for (const slot of removed) {
49
+ const key = previous.get(slot);
50
+ if (key !== undefined) {
51
+ bySlotKey.set(key, slot);
52
+ }
53
+ }
54
+ const moves = new Map();
55
+ for (const [slot, key] of occurrenceKeys(keys.nextKey, splice.start, splice.added, wanted)) {
56
+ const origin = bySlotKey.get(key);
57
+ if (origin !== undefined) {
58
+ moves.set(origin, slot);
59
+ }
60
+ }
61
+ return moves;
62
+ }
63
+ function relocateSlot(splice, slot, moves = NO_MOVES) {
64
+ if (slot < splice.start) {
65
+ return slot;
66
+ }
67
+ if (isRemoved(splice, slot)) {
68
+ return moves.get(slot);
69
+ }
70
+ return slot + splice.added - splice.removed;
71
+ }
72
+ function relocateEntries(entries, relocate, onDrop) {
73
+ const relocated = new Map();
74
+ for (const [slot, value] of entries) {
75
+ const next = relocate(slot);
76
+ if (next === undefined) {
77
+ onDrop(value);
78
+ }
79
+ else {
80
+ relocated.set(next, value);
81
+ }
82
+ }
83
+ return relocated;
84
+ }
85
+ /**
86
+ * GTK looks up every added item for a moved row whenever a splice removes a row it tracks, such as the scroll
87
+ * anchor or the focus, which makes every lazily created item real. Past a limit, the overlapping slots are
88
+ * rewritten in place instead and only the difference is spliced, so rows that move there remount.
89
+ */
90
+ function searchableSplice(splice, addedRows) {
91
+ if (addedRows <= MOVE_SEARCH_LIMIT) {
92
+ return splice;
93
+ }
94
+ const rewritten = Math.min(splice.removed, splice.added);
95
+ return { start: splice.start + rewritten, removed: splice.removed - rewritten, added: splice.added - rewritten };
96
+ }
97
+ export { NO_SPLICE, findSplice, hasSplice, matchMoves, relocateEntries, relocateSlot, searchableSplice, };
98
+ //# sourceMappingURL=level-splice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level-splice.js","sourceRoot":"","sources":["../../src/internal/level-splice.ts"],"names":[],"mappings":"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","sourcesContent":["import { joinParts } from \"./keys.js\";\n\ntype Splice = {\n start: number;\n removed: number;\n added: number;\n};\n\ntype KeyAt = (slot: number) => string;\n\ntype LevelKeys = {\n previousLength: number;\n nextLength: number;\n previousKey: KeyAt;\n nextKey: KeyAt;\n};\n\ntype Relocate = (slot: number) => number | undefined;\n\nconst NO_MOVES: Map<number, number> = new Map();\nconst NO_SPLICE: Splice = { start: 0, removed: 0, added: 0 };\nconst MOVE_SEARCH_LIMIT = 1024;\n\nfunction findSplice(keys: LevelKeys): Splice {\n const { previousLength, nextLength, previousKey, nextKey } = keys;\n const overlap = Math.min(previousLength, nextLength);\n let start = 0;\n\n while (start < overlap && previousKey(start) === nextKey(start)) {\n start += 1;\n }\n\n let shared = 0;\n\n while (shared < overlap - start && previousKey(previousLength - 1 - shared) === nextKey(nextLength - 1 - shared)) {\n shared += 1;\n }\n\n return { start, removed: previousLength - start - shared, added: nextLength - start - shared };\n}\n\nfunction hasSplice(splice: Splice): boolean {\n return splice.removed > 0 || splice.added > 0;\n}\n\nfunction isRemoved(splice: Splice, slot: number): boolean {\n return slot >= splice.start && slot < splice.start + splice.removed;\n}\n\nfunction occurrenceKeys(key: KeyAt, from: number, length: number, wanted: Set<string>): Map<number, string> {\n const counts: Map<string, number> = new Map();\n const keys: Map<number, string> = new Map();\n\n for (let slot = from; slot < from + length; slot++) {\n const id = key(slot);\n\n if (!wanted.has(id)) {\n continue;\n }\n\n const occurrence = counts.get(id) ?? 0;\n counts.set(id, occurrence + 1);\n keys.set(slot, joinParts([id, String(occurrence)]));\n }\n\n return keys;\n}\n\nfunction matchMoves(keys: LevelKeys, splice: Splice, candidates: Iterable<number>): Map<number, number> {\n const removed = Iterator.from(candidates)\n .filter((slot) => isRemoved(splice, slot))\n .toArray();\n\n if (removed.length === 0 || splice.added === 0) {\n return NO_MOVES;\n }\n\n const wanted = new Set(removed.map((slot) => keys.previousKey(slot)));\n const previous = occurrenceKeys(keys.previousKey, splice.start, splice.removed, wanted);\n const bySlotKey: Map<string, number> = new Map();\n\n for (const slot of removed) {\n const key = previous.get(slot);\n\n if (key !== undefined) {\n bySlotKey.set(key, slot);\n }\n }\n\n const moves: Map<number, number> = new Map();\n\n for (const [slot, key] of occurrenceKeys(keys.nextKey, splice.start, splice.added, wanted)) {\n const origin = bySlotKey.get(key);\n\n if (origin !== undefined) {\n moves.set(origin, slot);\n }\n }\n\n return moves;\n}\n\nfunction relocateSlot(splice: Splice, slot: number, moves: Map<number, number> = NO_MOVES): number | undefined {\n if (slot < splice.start) {\n return slot;\n }\n\n if (isRemoved(splice, slot)) {\n return moves.get(slot);\n }\n\n return slot + splice.added - splice.removed;\n}\n\nfunction relocateEntries<V>(entries: Map<number, V>, relocate: Relocate, onDrop: (value: V) => void): Map<number, V> {\n const relocated: Map<number, V> = new Map();\n\n for (const [slot, value] of entries) {\n const next = relocate(slot);\n\n if (next === undefined) {\n onDrop(value);\n } else {\n relocated.set(next, value);\n }\n }\n\n return relocated;\n}\n\n/**\n * GTK looks up every added item for a moved row whenever a splice removes a row it tracks, such as the scroll\n * anchor or the focus, which makes every lazily created item real. Past a limit, the overlapping slots are\n * rewritten in place instead and only the difference is spliced, so rows that move there remount.\n */\nfunction searchableSplice(splice: Splice, addedRows: number): Splice {\n if (addedRows <= MOVE_SEARCH_LIMIT) {\n return splice;\n }\n\n const rewritten = Math.min(splice.removed, splice.added);\n\n return { start: splice.start + rewritten, removed: splice.removed - rewritten, added: splice.added - rewritten };\n}\n\nexport {\n NO_SPLICE,\n findSplice,\n hasSplice,\n matchMoves,\n relocateEntries,\n relocateSlot,\n searchableSplice,\n type LevelKeys,\n type Relocate,\n type Splice,\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/internal/selection.tsx"],"names":[],"mappings":"AAAA,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;AAMzD,KAAK,gBAAgB,GAAG;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,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;AAyOF,iBAAS,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAwB7D;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/internal/selection.tsx"],"names":[],"mappings":"AAAA,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;AAMzD,KAAK,gBAAgB,GAAG;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,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;AA8OF,iBAAS,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAwB7D;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -3,7 +3,7 @@ import * as Gtk from "@gtkx/gi/gtk";
3
3
  import { GtkMultiSelection, GtkNoSelection, GtkSingleSelection } from "@gtkx/jsx/gtk";
4
4
  import { useState } from "react";
5
5
  import { isCollectionIdle } from "./collection.js";
6
- import { useControlledSync } from "./controlled-sync.js";
6
+ import { hasSameIds, useControlledSync } from "./controlled-sync.js";
7
7
  import { joinParts } from "./keys.js";
8
8
  function contiguousPositions(bitset, size) {
9
9
  const first = bitset.getMinimum();
@@ -34,9 +34,6 @@ function plannedSelection(context, ids) {
34
34
  return null;
35
35
  }
36
36
  const rows = collection.rowsFor(ids);
37
- if (ids.length > 0 && rows.positions.length === 0) {
38
- return null;
39
- }
40
37
  if (selection instanceof Gtk.SingleSelection) {
41
38
  return { positions: rows.positions.slice(0, 1), ids: rows.ids.slice(0, 1) };
42
39
  }
@@ -80,14 +77,25 @@ function applySelection(selection, positions) {
80
77
  }
81
78
  return selected;
82
79
  }
83
- function reportSelection(context, ids) {
80
+ function rememberSelection(context, ids) {
84
81
  const key = joinParts(ids);
85
- if (context.last.selection === context.selection && context.last.key === key) {
86
- return;
87
- }
82
+ const isKnown = context.last.selection === context.selection && context.last.key === key;
88
83
  context.last.selection = context.selection;
89
84
  context.last.key = key;
90
- context.onSelectionChanged?.(ids);
85
+ return isKnown;
86
+ }
87
+ function reportSelection(context, ids) {
88
+ if (!rememberSelection(context, ids)) {
89
+ context.onSelectionChanged?.(ids);
90
+ }
91
+ }
92
+ function settleSelection(context, ids, selectedIds) {
93
+ if (hasSameIds(ids, selectedIds)) {
94
+ rememberSelection(context, ids);
95
+ }
96
+ else {
97
+ reportSelection(context, ids);
98
+ }
91
99
  }
92
100
  function hasSelectionDrifted(actual, planned) {
93
101
  return actual.length !== planned.length || planned.some((position, index) => actual[index] !== position);
@@ -117,12 +125,13 @@ function applyControlledSelection(context, selectedIds) {
117
125
  if (selection === null) {
118
126
  return;
119
127
  }
120
- const planned = plannedSelection(context, selectedIds ?? []);
128
+ const requested = selectedIds ?? [];
129
+ const planned = plannedSelection(context, requested);
121
130
  if (planned !== null && didApplyPlanned(context, selection, planned.positions)) {
122
- reportSelection(context, planned.ids);
131
+ settleSelection(context, planned.ids, requested);
123
132
  return;
124
133
  }
125
- reportSelection(context, collection.idsAt(selectedPositions(selection)));
134
+ settleSelection(context, collection.idsAt(selectedPositions(selection)), requested);
126
135
  }
127
136
  function reportDrift(context, selectedIds, positions, onDrift) {
128
137
  const planned = plannedSelection(context, selectedIds ?? []);
@@ -132,14 +141,12 @@ function reportDrift(context, selectedIds, positions, onDrift) {
132
141
  }
133
142
  function observeSelection(context, selectedIds, onDrift) {
134
143
  const { selection, collection, state } = context;
135
- if (selection === null || state.isApplying) {
144
+ if (selection === null || state.isApplying || !isCollectionIdle(collection)) {
136
145
  return;
137
146
  }
138
147
  const positions = selectedPositions(selection);
139
148
  reportSelection(context, collection.idsAt(positions));
140
- if (isCollectionIdle(collection)) {
141
- reportDrift(context, selectedIds, positions, onDrift);
142
- }
149
+ reportDrift(context, selectedIds, positions, onDrift);
143
150
  }
144
151
  function newLastSelection() {
145
152
  return { selection: null, key: null };
@@ -1 +1 @@
1
- {"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/internal/selection.tsx"],"names":[],"mappings":"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","sourcesContent":["import 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 type { MatchedRows } from \"./tree-order.js\";\nimport { isCollectionIdle } from \"./collection.js\";\nimport { useControlledSync } from \"./controlled-sync.js\";\nimport { joinParts } from \"./keys.js\";\n\ntype SelectionOptions = {\n collection: Collection;\n model: ReactElement;\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 ApplyState = {\n isApplying: boolean;\n};\n\ntype SelectionContext = {\n selection: Gtk.SelectionModel | null;\n collection: Collection;\n last: LastSelection;\n state: ApplyState;\n onSelectionChanged?: ((ids: string[]) => void) | null | undefined;\n};\n\ntype PositionRun = {\n start: number;\n length: number;\n};\n\ntype SelectionElementProps = {\n ref: (value: Gtk.SelectionModel | null) => void;\n model: ReactElement;\n onSelectionChanged: () => void;\n onItemsChanged: ItemsChangeHandler;\n};\n\nfunction contiguousPositions(bitset: Gtk.Bitset, size: number): number[] | null {\n const first = bitset.getMinimum();\n\n if (bitset.getMaximum() - first + 1 !== size) {\n return null;\n }\n\n return Array.from({ length: size }, (_, offset) => first + offset);\n}\n\nfunction selectedPositions(selection: Gtk.SelectionModel): number[] {\n const bitset = selection.getSelection();\n const size = Number(bitset.getSize());\n\n if (size === 0) {\n return [];\n }\n\n const contiguous = contiguousPositions(bitset, size);\n\n if (contiguous !== null) {\n return contiguous;\n }\n\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 plannedSelection(context: SelectionContext, ids: string[]): MatchedRows | null {\n const { selection, collection } = context;\n\n if (selection === null || selection instanceof Gtk.NoSelection) {\n return null;\n }\n\n const rows = collection.rowsFor(ids);\n\n if (ids.length > 0 && rows.positions.length === 0) {\n return null;\n }\n\n if (selection instanceof Gtk.SingleSelection) {\n return { positions: rows.positions.slice(0, 1), ids: rows.ids.slice(0, 1) };\n }\n\n return rows;\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 positionRuns(positions: number[]): PositionRun[] {\n const runs: PositionRun[] = [];\n\n for (const position of positions) {\n const last = runs.at(-1);\n\n if (last !== undefined && last.start + last.length === position) {\n last.length += 1;\n } else {\n runs.push({ start: position, length: 1 });\n }\n }\n\n return runs;\n}\n\nfunction positionBitset(positions: number[]): Gtk.Bitset {\n const selected = Gtk.Bitset.newEmpty();\n\n for (const run of positionRuns(positions)) {\n selected.addRange(run.start, run.length);\n }\n\n return selected;\n}\n\nfunction applySelection(selection: Gtk.SelectionModel, positions: number[]): Gtk.Bitset {\n const selected = positionBitset(positions);\n\n if (selection instanceof Gtk.SingleSelection) {\n applySingleSelection(selection, positions);\n } else {\n selection.setSelection(selected, Gtk.Bitset.newRange(0, selection.getNItems()));\n }\n\n return selected;\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 didApplyPlanned(context: SelectionContext, selection: Gtk.SelectionModel, positions: number[]): boolean {\n const { state } = context;\n state.isApplying = true;\n\n try {\n const selected = applySelection(selection, positions);\n\n return selection.getSelection().equals(selected);\n } finally {\n state.isApplying = false;\n }\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 = plannedSelection(context, selectedIds ?? []);\n\n if (planned !== null && didApplyPlanned(context, selection, planned.positions)) {\n reportSelection(context, planned.ids);\n\n return;\n }\n\n reportSelection(context, collection.idsAt(selectedPositions(selection)));\n}\n\nfunction reportDrift(\n context: SelectionContext,\n selectedIds: string[] | null | undefined,\n positions: number[],\n onDrift: () => void,\n): void {\n const planned = plannedSelection(context, selectedIds ?? []);\n\n if (planned !== null && hasSelectionDrifted(positions, planned.positions)) {\n onDrift();\n }\n}\n\nfunction observeSelection(\n context: SelectionContext,\n selectedIds: string[] | null | undefined,\n onDrift: () => void,\n): void {\n const { selection, collection, state } = context;\n\n if (selection === null || state.isApplying) {\n return;\n }\n\n const positions = selectedPositions(selection);\n reportSelection(context, collection.idsAt(positions));\n\n if (isCollectionIdle(collection)) {\n reportDrift(context, selectedIds, positions, onDrift);\n }\n}\n\nfunction newLastSelection(): LastSelection {\n return { selection: null, key: null };\n}\n\nfunction newApplyState(): ApplyState {\n return { isApplying: false };\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 [state] = useState<ApplyState>(newApplyState);\n const context: SelectionContext = { selection, collection, last, state, onSelectionChanged };\n\n const markDrift = useControlledSync({\n value: selectedIds,\n source: collection,\n target: selection,\n apply: (value) => {\n applyControlledSelection(context, value);\n },\n });\n\n return selectionElement(selectionMode, {\n ref: setSelection,\n model: options.model,\n onSelectionChanged: () => {\n observeSelection(context, selectedIds, markDrift);\n },\n onItemsChanged: options.onItemsChanged,\n });\n}\n\nexport { useSelection };\n"]}
1
+ {"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/internal/selection.tsx"],"names":[],"mappings":"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","sourcesContent":["import 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 type { MatchedRows } from \"./tree-order.js\";\nimport { isCollectionIdle } from \"./collection.js\";\nimport { hasSameIds, useControlledSync } from \"./controlled-sync.js\";\nimport { joinParts } from \"./keys.js\";\n\ntype SelectionOptions = {\n collection: Collection;\n model: ReactElement;\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 ApplyState = {\n isApplying: boolean;\n};\n\ntype SelectionContext = {\n selection: Gtk.SelectionModel | null;\n collection: Collection;\n last: LastSelection;\n state: ApplyState;\n onSelectionChanged?: ((ids: string[]) => void) | null | undefined;\n};\n\ntype PositionRun = {\n start: number;\n length: number;\n};\n\ntype SelectionElementProps = {\n ref: (value: Gtk.SelectionModel | null) => void;\n model: ReactElement;\n onSelectionChanged: () => void;\n onItemsChanged: ItemsChangeHandler;\n};\n\nfunction contiguousPositions(bitset: Gtk.Bitset, size: number): number[] | null {\n const first = bitset.getMinimum();\n\n if (bitset.getMaximum() - first + 1 !== size) {\n return null;\n }\n\n return Array.from({ length: size }, (_, offset) => first + offset);\n}\n\nfunction selectedPositions(selection: Gtk.SelectionModel): number[] {\n const bitset = selection.getSelection();\n const size = Number(bitset.getSize());\n\n if (size === 0) {\n return [];\n }\n\n const contiguous = contiguousPositions(bitset, size);\n\n if (contiguous !== null) {\n return contiguous;\n }\n\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 plannedSelection(context: SelectionContext, ids: string[]): MatchedRows | null {\n const { selection, collection } = context;\n\n if (selection === null || selection instanceof Gtk.NoSelection) {\n return null;\n }\n\n const rows = collection.rowsFor(ids);\n\n if (selection instanceof Gtk.SingleSelection) {\n return { positions: rows.positions.slice(0, 1), ids: rows.ids.slice(0, 1) };\n }\n\n return rows;\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 positionRuns(positions: number[]): PositionRun[] {\n const runs: PositionRun[] = [];\n\n for (const position of positions) {\n const last = runs.at(-1);\n\n if (last !== undefined && last.start + last.length === position) {\n last.length += 1;\n } else {\n runs.push({ start: position, length: 1 });\n }\n }\n\n return runs;\n}\n\nfunction positionBitset(positions: number[]): Gtk.Bitset {\n const selected = Gtk.Bitset.newEmpty();\n\n for (const run of positionRuns(positions)) {\n selected.addRange(run.start, run.length);\n }\n\n return selected;\n}\n\nfunction applySelection(selection: Gtk.SelectionModel, positions: number[]): Gtk.Bitset {\n const selected = positionBitset(positions);\n\n if (selection instanceof Gtk.SingleSelection) {\n applySingleSelection(selection, positions);\n } else {\n selection.setSelection(selected, Gtk.Bitset.newRange(0, selection.getNItems()));\n }\n\n return selected;\n}\n\nfunction rememberSelection(context: SelectionContext, ids: string[]): boolean {\n const key = joinParts(ids);\n const isKnown = context.last.selection === context.selection && context.last.key === key;\n context.last.selection = context.selection;\n context.last.key = key;\n\n return isKnown;\n}\n\nfunction reportSelection(context: SelectionContext, ids: string[]): void {\n if (!rememberSelection(context, ids)) {\n context.onSelectionChanged?.(ids);\n }\n}\n\nfunction settleSelection(context: SelectionContext, ids: string[], selectedIds: string[]): void {\n if (hasSameIds(ids, selectedIds)) {\n rememberSelection(context, ids);\n } else {\n reportSelection(context, ids);\n }\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 didApplyPlanned(context: SelectionContext, selection: Gtk.SelectionModel, positions: number[]): boolean {\n const { state } = context;\n state.isApplying = true;\n\n try {\n const selected = applySelection(selection, positions);\n\n return selection.getSelection().equals(selected);\n } finally {\n state.isApplying = false;\n }\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 requested = selectedIds ?? [];\n const planned = plannedSelection(context, requested);\n\n if (planned !== null && didApplyPlanned(context, selection, planned.positions)) {\n settleSelection(context, planned.ids, requested);\n\n return;\n }\n\n settleSelection(context, collection.idsAt(selectedPositions(selection)), requested);\n}\n\nfunction reportDrift(\n context: SelectionContext,\n selectedIds: string[] | null | undefined,\n positions: number[],\n onDrift: () => void,\n): void {\n const planned = plannedSelection(context, selectedIds ?? []);\n\n if (planned !== null && hasSelectionDrifted(positions, planned.positions)) {\n onDrift();\n }\n}\n\nfunction observeSelection(\n context: SelectionContext,\n selectedIds: string[] | null | undefined,\n onDrift: () => void,\n): void {\n const { selection, collection, state } = context;\n\n if (selection === null || state.isApplying || !isCollectionIdle(collection)) {\n return;\n }\n\n const positions = selectedPositions(selection);\n reportSelection(context, collection.idsAt(positions));\n reportDrift(context, selectedIds, positions, onDrift);\n}\n\nfunction newLastSelection(): LastSelection {\n return { selection: null, key: null };\n}\n\nfunction newApplyState(): ApplyState {\n return { isApplying: false };\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 [state] = useState<ApplyState>(newApplyState);\n const context: SelectionContext = { selection, collection, last, state, onSelectionChanged };\n\n const markDrift = useControlledSync({\n value: selectedIds,\n source: collection,\n target: selection,\n apply: (value) => {\n applyControlledSelection(context, value);\n },\n });\n\n return selectionElement(selectionMode, {\n ref: setSelection,\n model: options.model,\n onSelectionChanged: () => {\n observeSelection(context, selectedIds, markDrift);\n },\n onItemsChanged: options.onItemsChanged,\n });\n}\n\nexport { useSelection };\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { CollectionIndex } from "./collection-index.js";
2
2
  import type { SlotMap } from "./slots.js";
3
3
  import type { VisibleOrder } from "./tree-order.js";
4
+ import type { Relocate } from "./level-splice.js";
4
5
  type TreeExpansion = {
5
6
  index: CollectionIndex;
6
7
  expanded: Set<string>;
@@ -13,7 +14,8 @@ declare function createTreeExpansion(index: CollectionIndex): TreeExpansion;
13
14
  declare function orderFor(expansion: TreeExpansion): VisibleOrder;
14
15
  declare function adoptOrder(expansion: TreeExpansion, order: VisibleOrder): void;
15
16
  declare function pruneSlots(expansion: TreeExpansion, levelPath: string, isPruned: (slot: number) => boolean): void;
17
+ declare function relocateSlots(expansion: TreeExpansion, levelPath: string, relocate: Relocate): void;
16
18
  declare function markExpanded(expansion: TreeExpansion, path: string, isExpanded: boolean): void;
17
19
  declare function adoptIndex(expansion: TreeExpansion, index: CollectionIndex): void;
18
- export { adoptIndex, adoptOrder, createTreeExpansion, markExpanded, orderFor, pruneSlots, type TreeExpansion, };
20
+ export { adoptIndex, adoptOrder, createTreeExpansion, markExpanded, orderFor, pruneSlots, relocateSlots, type TreeExpansion, };
19
21
  //# sourceMappingURL=tree-expansion.d.ts.map
@@ -1 +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,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,KAAK,aAAa,GACrB,CAAC"}
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;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAKlD,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;AAsBD,iBAAS,aAAa,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAkB5F;AAED,iBAAS,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAUvF;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,aAAa,EACb,KAAK,aAAa,GACrB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { encodePart } from "./keys.js";
1
+ import { decodePartAt, encodePart } from "./keys.js";
2
2
  import { getSlotKey, trackPath, trackPaths } from "./slots.js";
3
3
  import { walkVisible } from "./tree-order.js";
4
4
  function dropSubtree(expansion, path) {
@@ -46,6 +46,35 @@ function pruneSlots(expansion, levelPath, isPruned) {
46
46
  }
47
47
  expansion.order = null;
48
48
  }
49
+ function relocatePath(path, levelPath, relocate) {
50
+ if (path.length === levelPath.length || !path.startsWith(levelPath)) {
51
+ return path;
52
+ }
53
+ const part = decodePartAt(path, levelPath.length);
54
+ if (part === null) {
55
+ return path;
56
+ }
57
+ const slot = relocate(Number(part));
58
+ if (slot === undefined) {
59
+ return null;
60
+ }
61
+ return levelPath + encodePart(String(slot)) + path.slice(levelPath.length + encodePart(part).length);
62
+ }
63
+ function relocateSlots(expansion, levelPath, relocate) {
64
+ if (expansion.expanded.size === 0) {
65
+ return;
66
+ }
67
+ const expanded = new Set();
68
+ for (const path of expansion.expanded) {
69
+ const relocated = relocatePath(path, levelPath, relocate);
70
+ if (relocated !== null) {
71
+ expanded.add(relocated);
72
+ }
73
+ }
74
+ expansion.expanded = expanded;
75
+ expansion.slots = trackPaths(expanded);
76
+ expansion.order = null;
77
+ }
49
78
  function markExpanded(expansion, path, isExpanded) {
50
79
  if (isExpanded) {
51
80
  expansion.expanded.add(path);
@@ -59,5 +88,5 @@ function adoptIndex(expansion, index) {
59
88
  expansion.index = index;
60
89
  expansion.order = null;
61
90
  }
62
- export { adoptIndex, adoptOrder, createTreeExpansion, markExpanded, orderFor, pruneSlots, };
91
+ export { adoptIndex, adoptOrder, createTreeExpansion, markExpanded, orderFor, pruneSlots, relocateSlots, };
63
92
  //# sourceMappingURL=tree-expansion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-expansion.js","sourceRoot":"","sources":["../../src/internal/tree-expansion.ts"],"names":[],"mappings":"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","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 { walkVisible } 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 ??= walkVisible({ index: expansion.index, slots: 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 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 type TreeExpansion,\n};\n"]}
1
+ {"version":3,"file":"tree-expansion.js","sourceRoot":"","sources":["../../src/internal/tree-expansion.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CollectionIndex } from \"./collection-index.js\";\nimport type { SlotMap } from \"./slots.js\";\nimport type { VisibleOrder } from \"./tree-order.js\";\nimport type { Relocate } from \"./level-splice.js\";\nimport { decodePartAt, encodePart } from \"./keys.js\";\nimport { getSlotKey, trackPath, trackPaths } from \"./slots.js\";\nimport { walkVisible } 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 ??= walkVisible({ index: expansion.index, slots: 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 relocatePath(path: string, levelPath: string, relocate: Relocate): string | null {\n if (path.length === levelPath.length || !path.startsWith(levelPath)) {\n return path;\n }\n\n const part = decodePartAt(path, levelPath.length);\n\n if (part === null) {\n return path;\n }\n\n const slot = relocate(Number(part));\n\n if (slot === undefined) {\n return null;\n }\n\n return levelPath + encodePart(String(slot)) + path.slice(levelPath.length + encodePart(part).length);\n}\n\nfunction relocateSlots(expansion: TreeExpansion, levelPath: string, relocate: Relocate): void {\n if (expansion.expanded.size === 0) {\n return;\n }\n\n const expanded: Set<string> = new Set();\n\n for (const path of expansion.expanded) {\n const relocated = relocatePath(path, levelPath, relocate);\n\n if (relocated !== null) {\n expanded.add(relocated);\n }\n }\n\n expansion.expanded = expanded;\n expansion.slots = trackPaths(expanded);\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 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 relocateSlots,\n type TreeExpansion,\n};\n"]}
@@ -10,6 +10,7 @@ type VisibleRow = {
10
10
  type VisibleOrder = {
11
11
  expandedPaths: string[];
12
12
  expandedIds: string[];
13
+ positions: Map<string, number>;
13
14
  };
14
15
  type MatchedRows = {
15
16
  positions: number[];
@@ -26,5 +27,5 @@ declare function walkVisible(options: WalkOptions): VisibleOrder;
26
27
  declare function expandedPathsFor(index: CollectionIndex, ids: Set<string>): Set<string>;
27
28
  declare function findRows(index: CollectionIndex, slots: SlotMap, ids: Set<string>): MatchedRows;
28
29
  declare function findIds(index: CollectionIndex, slots: SlotMap, positions: Set<number>): string[];
29
- export { expandedPathsFor, findIds, findRows, walkVisible, type MatchedRows, type VisibleOrder, type WalkOptions, };
30
+ export { expandedPathsFor, findIds, findRows, walkVisible, type MatchedRows, type VisibleOrder, type WalkOptions };
30
31
  //# sourceMappingURL=tree-order.d.ts.map
@@ -1 +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,EAAS,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,KAAK,UAAU,GAAG;IACd,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,WAAW,GAAG;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,EAAE,CAAC;CACjB,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;AA8BF,iBAAS,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAQvD;AAiBD,iBAAS,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAY/E;AAED,iBAAS,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,WAAW,CAkBvF;AAED,iBAAS,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAgBzF;AAED,OAAO,EACH,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,GACnB,CAAC"}
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,EAAS,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,KAAK,UAAU,GAAG;IACd,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;IACtB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF,KAAK,WAAW,GAAG;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,EAAE,CAAC;CACjB,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;AA+BF,iBAAS,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAQvD;AAiBD,iBAAS,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAY/E;AAED,iBAAS,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,WAAW,CAkBvF;AAED,iBAAS,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAgBzF;AAED,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,CAAC"}
@@ -3,6 +3,7 @@ function walkLevel(options, level, state) {
3
3
  const marked = options.marks?.get(level.path);
4
4
  for (const [slot, item] of level.items.entries()) {
5
5
  const isOpen = open?.has(slot) ?? false;
6
+ state.order.positions.set(item.id, state.position);
6
7
  options.visit?.({ item, position: state.position, isOpen, isMarked: marked?.has(slot) ?? false });
7
8
  state.position += 1;
8
9
  if (!isOpen) {
@@ -17,7 +18,7 @@ function walkLevel(options, level, state) {
17
18
  }
18
19
  }
19
20
  function walkVisible(options) {
20
- const state = { position: 0, order: { expandedPaths: [], expandedIds: [] } };
21
+ const state = { position: 0, order: { expandedPaths: [], expandedIds: [], positions: new Map() } };
21
22
  for (const level of options.index.groups) {
22
23
  walkLevel(options, level, state);
23
24
  }
@@ -75,5 +76,5 @@ function findIds(index, slots, positions) {
75
76
  });
76
77
  return found;
77
78
  }
78
- export { expandedPathsFor, findIds, findRows, walkVisible, };
79
+ export { expandedPathsFor, findIds, findRows, walkVisible };
79
80
  //# sourceMappingURL=tree-order.js.map
@@ -1 +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\";\n\ntype VisibleRow = {\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 MatchedRows = {\n positions: number[];\n ids: 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 WalkState = {\n position: number;\n order: VisibleOrder;\n};\n\nfunction walkLevel(options: WalkOptions, level: Level, state: WalkState): void {\n const open = options.slots.get(level.path);\n const marked = options.marks?.get(level.path);\n\n for (const [slot, item] of level.items.entries()) {\n const isOpen = open?.has(slot) ?? false;\n options.visit?.({ item, position: state.position, isOpen, isMarked: marked?.has(slot) ?? false });\n state.position += 1;\n\n if (!isOpen) {\n continue;\n }\n\n const child = options.index.childLevel(level, slot);\n\n if (child !== undefined) {\n state.order.expandedPaths.push(child.path);\n state.order.expandedIds.push(item.id);\n walkLevel(options, child, state);\n }\n }\n}\n\nfunction walkVisible(options: WalkOptions): VisibleOrder {\n const state: WalkState = { position: 0, order: { expandedPaths: [], expandedIds: [] } };\n\n for (const level of options.index.groups) {\n walkLevel(options, level, state);\n }\n\n return state.order;\n}\n\nfunction expandLevel(index: CollectionIndex, level: Level, ids: Set<string>, paths: Set<string>): void {\n for (const [slot, item] of level.items.entries()) {\n if (!ids.has(item.id)) {\n continue;\n }\n\n const child = index.childLevel(level, slot);\n\n if (child !== undefined) {\n paths.add(child.path);\n expandLevel(index, child, ids, paths);\n }\n }\n}\n\nfunction expandedPathsFor(index: CollectionIndex, ids: Set<string>): Set<string> {\n const paths: Set<string> = new Set();\n\n if (ids.size === 0 || !index.isTree) {\n return paths;\n }\n\n for (const level of index.groups) {\n expandLevel(index, level, ids, paths);\n }\n\n return paths;\n}\n\nfunction findRows(index: CollectionIndex, slots: SlotMap, ids: Set<string>): MatchedRows {\n const positions: number[] = [];\n const found: string[] = [];\n\n walkVisible({\n index,\n slots,\n visit: (row) => {\n if (!ids.has(row.item.id)) {\n return;\n }\n\n positions.push(row.position);\n found.push(row.item.id);\n },\n });\n\n return { positions, ids: found };\n}\n\nfunction findIds(index: CollectionIndex, slots: SlotMap, positions: Set<number>): string[] {\n const found: string[] = [];\n\n walkVisible({\n index,\n slots,\n visit: (row) => {\n if (!positions.has(row.position)) {\n return;\n }\n\n found.push(row.item.id);\n },\n });\n\n return found;\n}\n\nexport {\n expandedPathsFor,\n findIds,\n findRows,\n walkVisible,\n type MatchedRows,\n type VisibleOrder,\n type WalkOptions,\n};\n"]}
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\";\n\ntype VisibleRow = {\n item: ListItem;\n position: number;\n isOpen: boolean;\n isMarked: boolean;\n};\n\ntype VisibleOrder = {\n expandedPaths: string[];\n expandedIds: string[];\n positions: Map<string, number>;\n};\n\ntype MatchedRows = {\n positions: number[];\n ids: 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 WalkState = {\n position: number;\n order: VisibleOrder;\n};\n\nfunction walkLevel(options: WalkOptions, level: Level, state: WalkState): void {\n const open = options.slots.get(level.path);\n const marked = options.marks?.get(level.path);\n\n for (const [slot, item] of level.items.entries()) {\n const isOpen = open?.has(slot) ?? false;\n state.order.positions.set(item.id, state.position);\n options.visit?.({ item, position: state.position, isOpen, isMarked: marked?.has(slot) ?? false });\n state.position += 1;\n\n if (!isOpen) {\n continue;\n }\n\n const child = options.index.childLevel(level, slot);\n\n if (child !== undefined) {\n state.order.expandedPaths.push(child.path);\n state.order.expandedIds.push(item.id);\n walkLevel(options, child, state);\n }\n }\n}\n\nfunction walkVisible(options: WalkOptions): VisibleOrder {\n const state: WalkState = { position: 0, order: { expandedPaths: [], expandedIds: [], positions: new Map() } };\n\n for (const level of options.index.groups) {\n walkLevel(options, level, state);\n }\n\n return state.order;\n}\n\nfunction expandLevel(index: CollectionIndex, level: Level, ids: Set<string>, paths: Set<string>): void {\n for (const [slot, item] of level.items.entries()) {\n if (!ids.has(item.id)) {\n continue;\n }\n\n const child = index.childLevel(level, slot);\n\n if (child !== undefined) {\n paths.add(child.path);\n expandLevel(index, child, ids, paths);\n }\n }\n}\n\nfunction expandedPathsFor(index: CollectionIndex, ids: Set<string>): Set<string> {\n const paths: Set<string> = new Set();\n\n if (ids.size === 0 || !index.isTree) {\n return paths;\n }\n\n for (const level of index.groups) {\n expandLevel(index, level, ids, paths);\n }\n\n return paths;\n}\n\nfunction findRows(index: CollectionIndex, slots: SlotMap, ids: Set<string>): MatchedRows {\n const positions: number[] = [];\n const found: string[] = [];\n\n walkVisible({\n index,\n slots,\n visit: (row) => {\n if (!ids.has(row.item.id)) {\n return;\n }\n\n positions.push(row.position);\n found.push(row.item.id);\n },\n });\n\n return { positions, ids: found };\n}\n\nfunction findIds(index: CollectionIndex, slots: SlotMap, positions: Set<number>): string[] {\n const found: string[] = [];\n\n walkVisible({\n index,\n slots,\n visit: (row) => {\n if (!positions.has(row.position)) {\n return;\n }\n\n found.push(row.item.id);\n },\n });\n\n return found;\n}\n\nexport { expandedPathsFor, findIds, findRows, walkVisible, type MatchedRows, type VisibleOrder, type WalkOptions };\n"]}
@@ -5,6 +5,7 @@ type CollectionDataOptions = {
5
5
  items?: ListItem[] | undefined;
6
6
  sections?: ListSection[] | undefined;
7
7
  isFlat?: boolean | undefined;
8
+ onSectionsFilled?: (() => void) | undefined;
8
9
  };
9
10
  type CollectionOptions = CollectionDataOptions & SelectionProps & ExpansionProps;
10
11
  type CollectionResult = {
@@ -1 +1 @@
1
- {"version":3,"file":"use-collection.d.ts","sourceRoot":"","sources":["../../src/internal/use-collection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,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,KAAK,oBAAoB,GAAG;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAwB/E;AAED,iBAAS,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAmBnE;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"use-collection.d.ts","sourceRoot":"","sources":["../../src/internal/use-collection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAI1C,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;IAC7B,gBAAgB,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAC/C,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,KAAK,oBAAoB,GAAG;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CA4B/E;AAED,iBAAS,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAmBnE;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { GtkFlattenListModel } from "@gtkx/jsx/gtk";
3
+ import { useLatestRef } from "@gtkx/react/internal";
3
4
  import { useLayoutEffect, useMemo, useState } from "react";
4
5
  import { createCollectionIndex } from "./collection-index.js";
5
6
  import { CollectionRoot, createCollectionModel } from "./collection-model.js";
@@ -19,9 +20,12 @@ function useCollectionData(options) {
19
20
  }
20
21
  return gtkModel.clear;
21
22
  }, [gtkModel, root, model]);
23
+ const onSectionsFilled = useLatestRef(options.onSectionsFilled);
22
24
  useLayoutEffect(() => {
23
- gtkModel.sync(index);
24
- }, [gtkModel, index, root, model]);
25
+ gtkModel.sync(index, () => {
26
+ onSectionsFilled.current?.();
27
+ });
28
+ }, [gtkModel, index, root, model, onSectionsFilled]);
25
29
  return {
26
30
  collection,
27
31
  model: _jsx(GtkFlattenListModel, { ref: setModel, model: _jsx(CollectionRoot, { ref: setRoot }) }),
@@ -1 +1 @@
1
- {"version":3,"file":"use-collection.js","sourceRoot":"","sources":["../../src/internal/use-collection.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAA4B,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACxG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAoB9C,SAAS,iBAAiB,CAAC,OAA8B;IACrD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC5C,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IACnD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAA6B,IAAI,CAAC,CAAC;IACnE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAA8B,IAAI,CAAC,CAAC;IACtE,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,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAErG,eAAe,CAAC,GAAG,EAAE;QACjB,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,QAAQ,CAAC,KAAK,CAAC;IAC1B,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAE5B,eAAe,CAAC,GAAG,EAAE;QACjB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAEnC,OAAO;QACH,UAAU;QACV,KAAK,EAAE,KAAC,mBAAmB,IAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAC,cAAc,IAAC,GAAG,EAAE,OAAO,GAAI,GAAI;KACzF,CAAC;AACN,CAAC;AAED,SAAS,aAAa,CAAC,OAA0B;IAC7C,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEzD,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,KAAK;QACL,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 * as Gtk from \"@gtkx/gi/gtk\";\nimport type { ReactElement } from \"react\";\nimport { GtkFlattenListModel } from \"@gtkx/jsx/gtk\";\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 { CollectionRoot, type CollectionRootStore, 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\ntype CollectionDataResult = {\n collection: Collection;\n model: ReactElement;\n};\n\nfunction useCollectionData(options: CollectionDataOptions): CollectionDataResult {\n const { items, sections, isFlat } = options;\n const [gtkModel] = useState(createCollectionModel);\n const [root, setRoot] = useState<CollectionRootStore | null>(null);\n const [model, setModel] = useState<Gtk.FlattenListModel | null>(null);\n const index = useMemo(() => createCollectionIndex(items, sections, isFlat === true), [items, sections, isFlat]);\n const collection = useMemo(() => createCollection(gtkModel, index, model), [gtkModel, index, model]);\n\n useLayoutEffect(() => {\n if (root !== null && model !== null) {\n gtkModel.bind(root, model);\n }\n\n return gtkModel.clear;\n }, [gtkModel, root, model]);\n\n useLayoutEffect(() => {\n gtkModel.sync(index);\n }, [gtkModel, index, root, model]);\n\n return {\n collection,\n model: <GtkFlattenListModel ref={setModel} model={<CollectionRoot ref={setRoot} />} />,\n };\n}\n\nfunction useCollection(options: CollectionOptions): CollectionResult {\n const { collection, model } = 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 model,\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
+ {"version":3,"file":"use-collection.js","sourceRoot":"","sources":["../../src/internal/use-collection.tsx"],"names":[],"mappings":"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","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { ReactElement } from \"react\";\nimport { GtkFlattenListModel } from \"@gtkx/jsx/gtk\";\nimport { useLatestRef } from \"@gtkx/react/internal\";\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 { CollectionRoot, type CollectionRootStore, 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 onSectionsFilled?: (() => void) | undefined;\n};\n\ntype CollectionOptions = CollectionDataOptions & SelectionProps & ExpansionProps;\n\ntype CollectionResult = {\n collection: Collection;\n selection: ReactElement;\n};\n\ntype CollectionDataResult = {\n collection: Collection;\n model: ReactElement;\n};\n\nfunction useCollectionData(options: CollectionDataOptions): CollectionDataResult {\n const { items, sections, isFlat } = options;\n const [gtkModel] = useState(createCollectionModel);\n const [root, setRoot] = useState<CollectionRootStore | null>(null);\n const [model, setModel] = useState<Gtk.FlattenListModel | null>(null);\n const index = useMemo(() => createCollectionIndex(items, sections, isFlat === true), [items, sections, isFlat]);\n const collection = useMemo(() => createCollection(gtkModel, index, model), [gtkModel, index, model]);\n\n useLayoutEffect(() => {\n if (root !== null && model !== null) {\n gtkModel.bind(root, model);\n }\n\n return gtkModel.clear;\n }, [gtkModel, root, model]);\n\n const onSectionsFilled = useLatestRef(options.onSectionsFilled);\n\n useLayoutEffect(() => {\n gtkModel.sync(index, () => {\n onSectionsFilled.current?.();\n });\n }, [gtkModel, index, root, model, onSectionsFilled]);\n\n return {\n collection,\n model: <GtkFlattenListModel ref={setModel} model={<CollectionRoot ref={setRoot} />} />,\n };\n}\n\nfunction useCollection(options: CollectionOptions): CollectionResult {\n const { collection, model } = 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 model,\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":"use-widget-ref.d.ts","sourceRoot":"","sources":["../../src/internal/use-widget-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAIjC,QAAA,MAAM,YAAY,GAAI,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,KAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAI7F,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
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,MAAM,OAAO,CAAC;AAIjC,QAAA,MAAM,YAAY,GAAI,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,KAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAI7F,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -5,6 +5,6 @@ import type { ListItemFactoryProps } from "./types.js";
5
5
  * Creates a Gtk.SignalListItemFactory that renders objects from an existing native model with React.
6
6
  * Estimated dimensions keep cells stable until their content mounts.
7
7
  */
8
- declare function ListItemFactory<T extends GObject.Object>({ renderItem, estimatedItemHeight, estimatedItemWidth, }: ListItemFactoryProps<T>): ReactNode;
8
+ declare function ListItemFactory<T extends GObject.Object>({ renderItem, rowProps, estimatedItemHeight, estimatedItemWidth, }: ListItemFactoryProps<T>): ReactNode;
9
9
  export { ListItemFactory };
10
10
  //# sourceMappingURL=list-item-factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-item-factory.d.ts","sourceRoot":"","sources":["../src/list-item-factory.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,OAAO,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD;;;GAGG;AACH,iBAAS,eAAe,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,EAAE,EAC/C,UAAU,EACV,mBAAwB,EACxB,kBAAuB,GAC1B,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,SAAS,CAUrC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"list-item-factory.d.ts","sourceRoot":"","sources":["../src/list-item-factory.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,OAAO,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD;;;GAGG;AACH,iBAAS,eAAe,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,EAAE,EAC/C,UAAU,EACV,QAAQ,EACR,mBAAwB,EACxB,kBAAuB,GAC1B,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,SAAS,CAUrC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -1,14 +1,14 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { GtkSignalListItemFactory } from "@gtkx/jsx/gtk";
3
3
  import { NativeItemPortals, useItemCells } from "./internal/cells.js";
4
4
  /**
5
5
  * Creates a Gtk.SignalListItemFactory that renders objects from an existing native model with React.
6
6
  * Estimated dimensions keep cells stable until their content mounts.
7
7
  */
8
- function ListItemFactory({ renderItem, estimatedItemHeight = -1, estimatedItemWidth = -1, }) {
8
+ function ListItemFactory({ renderItem, rowProps, estimatedItemHeight = -1, estimatedItemWidth = -1, }) {
9
9
  const size = { width: estimatedItemWidth, height: estimatedItemHeight };
10
10
  const cells = useItemCells(size);
11
- return (_jsxs(_Fragment, { children: [_jsx(GtkSignalListItemFactory, { ...cells.handlers }), _jsx(NativeItemPortals, { registry: cells, render: renderItem, size: size })] }));
11
+ return (_jsxs(_Fragment, { children: [_jsx(GtkSignalListItemFactory, { ...cells.handlers }), _jsx(NativeItemPortals, { registry: cells, render: renderItem, rowProps: rowProps, size: size })] }));
12
12
  }
13
13
  export { ListItemFactory };
14
14
  //# sourceMappingURL=list-item-factory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-item-factory.js","sourceRoot":"","sources":["../src/list-item-factory.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;;GAGG;AACH,SAAS,eAAe,CAA2B,EAC/C,UAAU,EACV,mBAAmB,GAAG,CAAC,CAAC,EACxB,kBAAkB,GAAG,CAAC,CAAC,GACD;IACtB,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACxE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,CACH,8BACI,KAAC,wBAAwB,OAAK,KAAK,CAAC,QAAQ,GAAI,EAChD,KAAC,iBAAiB,IAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAI,IACvE,CACN,CAAC;AACN,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import type * as GObject from \"@gtkx/gi/gobject\";\nimport type { ReactNode } from \"react\";\nimport { GtkSignalListItemFactory } from \"@gtkx/jsx/gtk\";\nimport type { ListItemFactoryProps } from \"./types.js\";\nimport { NativeItemPortals, useItemCells } from \"./internal/cells.js\";\n\n/**\n * Creates a Gtk.SignalListItemFactory that renders objects from an existing native model with React.\n * Estimated dimensions keep cells stable until their content mounts.\n */\nfunction ListItemFactory<T extends GObject.Object>({\n renderItem,\n estimatedItemHeight = -1,\n estimatedItemWidth = -1,\n}: ListItemFactoryProps<T>): ReactNode {\n const size = { width: estimatedItemWidth, height: estimatedItemHeight };\n const cells = useItemCells(size);\n\n return (\n <>\n <GtkSignalListItemFactory {...cells.handlers} />\n <NativeItemPortals registry={cells} render={renderItem} size={size} />\n </>\n );\n}\n\nexport { ListItemFactory };\n"]}
1
+ {"version":3,"file":"list-item-factory.js","sourceRoot":"","sources":["../src/list-item-factory.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;;GAGG;AACH,SAAS,eAAe,CAA2B,EAC/C,UAAU,EACV,QAAQ,EACR,mBAAmB,GAAG,CAAC,CAAC,EACxB,kBAAkB,GAAG,CAAC,CAAC,GACD;IACtB,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACxE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,CACH,8BACI,KAAC,wBAAwB,OAAK,KAAK,CAAC,QAAQ,GAAI,EAChD,KAAC,iBAAiB,IAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAI,IAC3F,CACN,CAAC;AACN,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import type * as GObject from \"@gtkx/gi/gobject\";\nimport type { ReactNode } from \"react\";\nimport { GtkSignalListItemFactory } from \"@gtkx/jsx/gtk\";\nimport type { ListItemFactoryProps } from \"./types.js\";\nimport { NativeItemPortals, useItemCells } from \"./internal/cells.js\";\n\n/**\n * Creates a Gtk.SignalListItemFactory that renders objects from an existing native model with React.\n * Estimated dimensions keep cells stable until their content mounts.\n */\nfunction ListItemFactory<T extends GObject.Object>({\n renderItem,\n rowProps,\n estimatedItemHeight = -1,\n estimatedItemWidth = -1,\n}: ListItemFactoryProps<T>): ReactNode {\n const size = { width: estimatedItemWidth, height: estimatedItemHeight };\n const cells = useItemCells(size);\n\n return (\n <>\n <GtkSignalListItemFactory {...cells.handlers} />\n <NativeItemPortals registry={cells} render={renderItem} rowProps={rowProps} size={size} />\n </>\n );\n}\n\nexport { ListItemFactory };\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;AAoBhD;;;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"}
1
+ {"version":3,"file":"list-view.d.ts","sourceRoot":"","sources":["../src/list-view.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwBhD;;;GAGG;AACH,iBAAS,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CA8BjF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}