@gtkx/react 0.6.1 → 0.7.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 (84) hide show
  1. package/dist/batch.d.ts +4 -1
  2. package/dist/batch.js +19 -10
  3. package/dist/codegen/jsx-generator.d.ts +4 -4
  4. package/dist/codegen/jsx-generator.js +24 -27
  5. package/dist/container-interfaces.d.ts +19 -6
  6. package/dist/container-interfaces.js +26 -6
  7. package/dist/errors.d.ts +8 -0
  8. package/dist/errors.js +38 -0
  9. package/dist/factory.js +9 -3
  10. package/dist/generated/jsx.d.ts +38 -26
  11. package/dist/generated/jsx.js +12 -2
  12. package/dist/index.js +3 -1
  13. package/dist/node.d.ts +5 -0
  14. package/dist/node.js +62 -6
  15. package/dist/nodes/action-bar.d.ts +2 -6
  16. package/dist/nodes/action-bar.js +3 -12
  17. package/dist/nodes/column-view.d.ts +19 -44
  18. package/dist/nodes/column-view.js +70 -243
  19. package/dist/nodes/combo-row.d.ts +5 -0
  20. package/dist/nodes/combo-row.js +6 -0
  21. package/dist/nodes/drop-down.d.ts +9 -0
  22. package/dist/nodes/drop-down.js +12 -0
  23. package/dist/nodes/flow-box.d.ts +4 -6
  24. package/dist/nodes/flow-box.js +8 -16
  25. package/dist/nodes/grid.d.ts +15 -15
  26. package/dist/nodes/grid.js +21 -64
  27. package/dist/nodes/header-bar.d.ts +34 -11
  28. package/dist/nodes/header-bar.js +52 -24
  29. package/dist/nodes/indexed-child-container.d.ts +16 -0
  30. package/dist/nodes/indexed-child-container.js +22 -0
  31. package/dist/nodes/list-box.d.ts +3 -6
  32. package/dist/nodes/list-box.js +6 -14
  33. package/dist/nodes/list-item-factory.d.ts +19 -0
  34. package/dist/nodes/list-item-factory.js +58 -0
  35. package/dist/nodes/list-view.d.ts +24 -0
  36. package/dist/nodes/list-view.js +46 -0
  37. package/dist/nodes/menu.d.ts +25 -19
  38. package/dist/nodes/menu.js +30 -59
  39. package/dist/nodes/notebook.d.ts +13 -14
  40. package/dist/nodes/notebook.js +18 -56
  41. package/dist/nodes/paged-stack.d.ts +39 -0
  42. package/dist/nodes/paged-stack.js +54 -0
  43. package/dist/nodes/selectable-list.d.ts +41 -0
  44. package/dist/nodes/selectable-list.js +228 -0
  45. package/dist/nodes/stack-page-props.d.ts +11 -0
  46. package/dist/nodes/stack-page-props.js +23 -0
  47. package/dist/nodes/stack.d.ts +14 -28
  48. package/dist/nodes/stack.js +30 -142
  49. package/dist/nodes/string-list-container.d.ts +41 -0
  50. package/dist/nodes/string-list-container.js +90 -0
  51. package/dist/nodes/string-list-item.d.ts +15 -0
  52. package/dist/nodes/string-list-item.js +48 -0
  53. package/dist/nodes/string-list-store.d.ts +13 -0
  54. package/dist/nodes/string-list-store.js +44 -0
  55. package/dist/nodes/text-view.d.ts +1 -1
  56. package/dist/nodes/text-view.js +1 -5
  57. package/dist/nodes/toggle-button.d.ts +1 -1
  58. package/dist/nodes/toggle-button.js +1 -3
  59. package/dist/nodes/view-stack.d.ts +9 -0
  60. package/dist/nodes/view-stack.js +28 -0
  61. package/dist/nodes/virtual-item.d.ts +20 -0
  62. package/dist/nodes/virtual-item.js +57 -0
  63. package/dist/nodes/virtual-slot.d.ts +25 -0
  64. package/dist/nodes/virtual-slot.js +71 -0
  65. package/dist/nodes/widget.d.ts +0 -3
  66. package/dist/nodes/widget.js +0 -28
  67. package/dist/nodes/window.d.ts +1 -1
  68. package/dist/nodes/window.js +9 -15
  69. package/dist/predicates.d.ts +8 -0
  70. package/dist/predicates.js +8 -0
  71. package/dist/props.d.ts +7 -5
  72. package/dist/props.js +11 -9
  73. package/dist/reconciler/host-config.d.ts +19 -0
  74. package/dist/reconciler/host-config.js +89 -0
  75. package/dist/reconciler.d.ts +2 -26
  76. package/dist/reconciler.js +15 -106
  77. package/dist/render.d.ts +1 -2
  78. package/dist/render.js +16 -4
  79. package/dist/types.d.ts +19 -16
  80. package/package.json +4 -4
  81. package/dist/nodes/dropdown.d.ts +0 -39
  82. package/dist/nodes/dropdown.js +0 -103
  83. package/dist/nodes/list.d.ts +0 -43
  84. package/dist/nodes/list.js +0 -153
@@ -1,67 +1,47 @@
1
- import { getInterface, getObject, getObjectId } from "@gtkx/ffi";
2
- import * as Gio from "@gtkx/ffi/gio";
1
+ import { getObject } from "@gtkx/ffi";
3
2
  import * as GObject from "@gtkx/ffi/gobject";
4
3
  import * as Gtk from "@gtkx/ffi/gtk";
5
- import { scheduleFlush } from "../batch.js";
6
- import { isColumnContainer, isItemContainer, } from "../container-interfaces.js";
7
- import { createFiberRoot } from "../fiber-root.js";
4
+ import { isColumnContainer } from "../container-interfaces.js";
8
5
  import { Node } from "../node.js";
9
- import { reconciler } from "../reconciler.js";
10
- export class ColumnViewNode extends Node {
6
+ import { connectListItemFactorySignals } from "./list-item-factory.js";
7
+ import { SelectableListNode } from "./selectable-list.js";
8
+ import { VirtualItemNode } from "./virtual-item.js";
9
+ export class ColumnViewNode extends SelectableListNode {
10
+ static consumedPropNames = [
11
+ "sortColumn",
12
+ "sortOrder",
13
+ "onSortChange",
14
+ "selected",
15
+ "onSelectionChanged",
16
+ "selectionMode",
17
+ ];
11
18
  static matches(type) {
12
19
  return type === "ColumnView.Root";
13
20
  }
14
21
  initialize(props) {
15
- this.initializeStateWithPlaceholders(props);
16
- super.initialize(props);
17
- this.createGtkModels();
18
- this.connectSorterChangedSignal();
19
- }
20
- initializeStateWithPlaceholders(props) {
22
+ const selectionState = this.initializeSelectionState(props);
21
23
  this.state = {
22
- stringList: null,
23
- selectionModel: null,
24
- sortListModel: null,
25
- items: [],
24
+ ...selectionState,
26
25
  columns: [],
27
- committedLength: 0,
28
26
  sortColumn: props.sortColumn ?? null,
29
27
  sortOrder: props.sortOrder ?? Gtk.SortType.ASCENDING,
30
- sortFn: props.sortFn ?? null,
31
- isSorting: false,
32
28
  onSortChange: props.onSortChange ?? null,
33
29
  sorterChangedHandlerId: null,
34
30
  lastNotifiedColumn: null,
35
31
  lastNotifiedOrder: Gtk.SortType.ASCENDING,
36
32
  };
37
- }
38
- createGtkModels() {
39
- const stringList = new Gtk.StringList([]);
40
- const sortListModel = new Gtk.SortListModel(getInterface(stringList, Gio.ListModel), this.widget.getSorter());
41
- sortListModel.setIncremental(true);
42
- const selectionModel = new Gtk.SingleSelection(getInterface(sortListModel, Gio.ListModel));
43
- this.widget.setModel(selectionModel);
44
- this.state.stringList = stringList;
45
- this.state.sortListModel = sortListModel;
46
- this.state.selectionModel = selectionModel;
33
+ super.initialize(props);
34
+ this.applySelectionModel();
35
+ this.connectSorterChangedSignal();
47
36
  }
48
37
  connectSorterChangedSignal() {
49
38
  const sorter = this.widget.getSorter();
50
39
  if (!sorter || !this.state.onSortChange)
51
40
  return;
52
41
  this.state.sorterChangedHandlerId = sorter.connect("changed", () => {
53
- this.waitForSortComplete(() => this.notifySortChange());
42
+ this.notifySortChange();
54
43
  });
55
44
  }
56
- waitForSortComplete(callback) {
57
- const sortingInProgress = this.state.sortListModel.getPending() > 0;
58
- if (sortingInProgress) {
59
- setTimeout(() => this.waitForSortComplete(callback), 0);
60
- }
61
- else {
62
- callback();
63
- }
64
- }
65
45
  disconnectSorterChangedSignal() {
66
46
  if (this.state.sorterChangedHandlerId === null)
67
47
  return;
@@ -81,41 +61,42 @@ export class ColumnViewNode extends Node {
81
61
  const column = sorter.getPrimarySortColumn();
82
62
  const order = sorter.getPrimarySortOrder();
83
63
  const columnId = column?.getId() ?? null;
84
- const sortStateUnchanged = columnId === this.state.lastNotifiedColumn && order === this.state.lastNotifiedOrder;
85
- if (sortStateUnchanged) {
64
+ if (columnId === this.state.lastNotifiedColumn && order === this.state.lastNotifiedOrder) {
86
65
  return;
87
66
  }
88
67
  this.state.lastNotifiedColumn = columnId;
89
68
  this.state.lastNotifiedOrder = order;
90
69
  this.state.onSortChange(columnId, order);
91
70
  }
92
- getItems() {
93
- return this.state.items;
94
- }
95
- getSortFn() {
96
- return this.state.sortFn;
71
+ detachFromParent(parent) {
72
+ this.disconnectSorterChangedSignal();
73
+ this.cleanupSelection();
74
+ super.detachFromParent(parent);
97
75
  }
98
- compareItems(a, b, columnId) {
99
- if (this.state.isSorting || !this.state.sortFn)
100
- return 0;
101
- this.state.isSorting = true;
102
- try {
103
- return this.state.sortFn(a, b, columnId);
104
- }
105
- finally {
106
- this.state.isSorting = false;
76
+ updateProps(oldProps, newProps) {
77
+ super.updateProps(oldProps, newProps);
78
+ const newSortColumn = newProps.sortColumn ?? null;
79
+ const newSortOrder = newProps.sortOrder ?? Gtk.SortType.ASCENDING;
80
+ const newOnSortChange = newProps.onSortChange ?? null;
81
+ if (oldProps.onSortChange !== newProps.onSortChange) {
82
+ const hadCallback = this.state.onSortChange !== null;
83
+ this.state.onSortChange = newOnSortChange;
84
+ const hasCallback = this.state.onSortChange !== null;
85
+ if (!hadCallback && hasCallback) {
86
+ this.connectSorterChangedSignal();
87
+ }
88
+ else if (hadCallback && !hasCallback) {
89
+ this.disconnectSorterChangedSignal();
90
+ }
107
91
  }
108
- }
109
- addColumn(columnNode) {
110
- this.state.columns.push(columnNode);
111
- const column = columnNode.getColumn();
112
- this.widget.appendColumn(column);
113
- columnNode.setColumnView(this);
114
- if (columnNode.getId() === this.state.sortColumn && this.state.sortColumn !== null) {
115
- this.applySortByColumn();
92
+ if (oldProps.sortColumn !== newProps.sortColumn || oldProps.sortOrder !== newProps.sortOrder) {
93
+ this.state.sortColumn = newSortColumn;
94
+ this.state.sortOrder = newSortOrder;
95
+ this.applySortIndicator();
116
96
  }
97
+ this.updateSelectionProps(oldProps, newProps);
117
98
  }
118
- applySortByColumn() {
99
+ applySortIndicator() {
119
100
  if (this.state.sortColumn === null) {
120
101
  this.widget.sortByColumn(this.state.sortOrder, null);
121
102
  return;
@@ -125,15 +106,12 @@ export class ColumnViewNode extends Node {
125
106
  this.widget.sortByColumn(this.state.sortOrder, column.getColumn());
126
107
  }
127
108
  }
128
- findColumnById(id) {
129
- return this.state.columns.find((c) => c.getId() === id);
130
- }
131
- removeColumn(column) {
132
- const index = this.state.columns.indexOf(column);
133
- if (index !== -1) {
134
- this.state.columns.splice(index, 1);
135
- this.widget.removeColumn(column.getColumn());
136
- column.setColumnView(null);
109
+ addColumn(columnNode) {
110
+ this.state.columns.push(columnNode);
111
+ this.widget.appendColumn(columnNode.getColumn());
112
+ columnNode.setColumnView(this);
113
+ if (columnNode.getId() === this.state.sortColumn) {
114
+ this.applySortIndicator();
137
115
  }
138
116
  }
139
117
  insertColumnBefore(column, before) {
@@ -146,76 +124,17 @@ export class ColumnViewNode extends Node {
146
124
  this.widget.insertColumn(beforeIndex, column.getColumn());
147
125
  column.setColumnView(this);
148
126
  }
149
- syncStringList = () => {
150
- const newLength = this.state.items.length;
151
- if (newLength === this.state.committedLength)
152
- return;
153
- const itemIndicesForSorter = Array.from({ length: newLength }, (_, i) => String(i));
154
- this.state.stringList.splice(0, this.state.committedLength, itemIndicesForSorter);
155
- this.state.committedLength = newLength;
156
- };
157
- addItem(item) {
158
- this.state.items.push(item);
159
- scheduleFlush(this.syncStringList);
160
- }
161
- insertItemBefore(item, beforeItem) {
162
- const beforeIndex = this.state.items.indexOf(beforeItem);
163
- if (beforeIndex === -1) {
164
- this.state.items.push(item);
165
- }
166
- else {
167
- this.state.items.splice(beforeIndex, 0, item);
168
- }
169
- scheduleFlush(this.syncStringList);
170
- }
171
- removeItem(item) {
172
- const index = this.state.items.indexOf(item);
127
+ removeColumn(column) {
128
+ const index = this.state.columns.indexOf(column);
173
129
  if (index !== -1) {
174
- this.state.items.splice(index, 1);
175
- scheduleFlush(this.syncStringList);
176
- }
177
- }
178
- consumedProps() {
179
- const consumed = super.consumedProps();
180
- consumed.add("sortColumn");
181
- consumed.add("sortOrder");
182
- consumed.add("onSortChange");
183
- consumed.add("sortFn");
184
- return consumed;
185
- }
186
- updateProps(oldProps, newProps) {
187
- super.updateProps(oldProps, newProps);
188
- const newSortColumn = newProps.sortColumn ?? null;
189
- const newSortOrder = newProps.sortOrder ?? Gtk.SortType.ASCENDING;
190
- const newSortFn = newProps.sortFn ?? null;
191
- const newOnSortChange = newProps.onSortChange ?? null;
192
- if (oldProps.onSortChange !== newProps.onSortChange) {
193
- const hadCallback = this.state.onSortChange !== null;
194
- this.state.onSortChange = newOnSortChange;
195
- const hasCallback = this.state.onSortChange !== null;
196
- const callbackAdded = !hadCallback && hasCallback;
197
- const callbackRemoved = hadCallback && !hasCallback;
198
- if (callbackAdded) {
199
- this.connectSorterChangedSignal();
200
- }
201
- else if (callbackRemoved) {
202
- this.disconnectSorterChangedSignal();
203
- }
204
- }
205
- if (oldProps.sortFn !== newProps.sortFn) {
206
- this.state.sortFn = newSortFn;
207
- for (const column of this.state.columns) {
208
- column.updateSorterFromRoot();
209
- }
210
- }
211
- if (oldProps.sortColumn !== newProps.sortColumn || oldProps.sortOrder !== newProps.sortOrder) {
212
- this.state.sortColumn = newSortColumn;
213
- this.state.sortOrder = newSortOrder;
214
- this.applySortByColumn();
130
+ this.state.columns.splice(index, 1);
131
+ this.widget.removeColumn(column.getColumn());
132
+ column.setColumnView(null);
215
133
  }
216
134
  }
217
135
  }
218
136
  export class ColumnViewColumnNode extends Node {
137
+ static consumedPropNames = ["renderCell", "title", "expand", "resizable", "fixedWidth", "id"];
219
138
  static matches(type) {
220
139
  return type === "ColumnView.Column";
221
140
  }
@@ -230,6 +149,7 @@ export class ColumnViewColumnNode extends Node {
230
149
  this.state = {
231
150
  column,
232
151
  factory,
152
+ factoryHandlers: null,
233
153
  renderCell: props.renderCell,
234
154
  columnId,
235
155
  sorter: null,
@@ -248,44 +168,11 @@ export class ColumnViewColumnNode extends Node {
248
168
  if (props.fixedWidth !== undefined) {
249
169
  column.setFixedWidth(props.fixedWidth);
250
170
  }
251
- factory.connect("setup", (_self, listItemObj) => {
252
- const listItem = getObject(listItemObj.id);
253
- const id = getObjectId(listItemObj.id);
254
- const box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
255
- listItem.setChild(box);
256
- const fiberRoot = createFiberRoot(box);
257
- this.state.listItemCache.set(id, { box, fiberRoot });
258
- const element = this.state.renderCell(null);
259
- reconciler.getInstance().updateContainer(element, fiberRoot, null, () => { });
260
- });
261
- factory.connect("bind", (_self, listItemObj) => {
262
- const listItem = getObject(listItemObj.id);
263
- const id = getObjectId(listItemObj.id);
264
- const info = this.state.listItemCache.get(id);
265
- if (!info)
266
- return;
267
- const position = listItem.getPosition();
268
- if (this.columnView) {
269
- const items = this.columnView.getItems();
270
- const item = items[position];
271
- const element = this.state.renderCell(item ?? null);
272
- reconciler.getInstance().updateContainer(element, info.fiberRoot, null, () => { });
273
- }
274
- });
275
- factory.connect("unbind", (_self, listItemObj) => {
276
- const id = getObjectId(listItemObj.id);
277
- const info = this.state.listItemCache.get(id);
278
- if (!info)
279
- return;
280
- reconciler.getInstance().updateContainer(null, info.fiberRoot, null, () => { });
281
- });
282
- factory.connect("teardown", (_self, listItemObj) => {
283
- const id = getObjectId(listItemObj.id);
284
- const info = this.state.listItemCache.get(id);
285
- if (info) {
286
- reconciler.getInstance().updateContainer(null, info.fiberRoot, null, () => { });
287
- this.state.listItemCache.delete(id);
288
- }
171
+ this.state.factoryHandlers = connectListItemFactorySignals({
172
+ factory,
173
+ listItemCache: this.state.listItemCache,
174
+ getRenderFn: () => this.state.renderCell,
175
+ getItemAtPosition: (position) => this.columnView?.getItems()[position] ?? null,
289
176
  });
290
177
  }
291
178
  getColumn() {
@@ -296,38 +183,16 @@ export class ColumnViewColumnNode extends Node {
296
183
  }
297
184
  setColumnView(columnView) {
298
185
  this.columnView = columnView;
299
- this.updateSorterFromRoot();
186
+ this.updateSorter();
300
187
  }
301
- updateSorterFromRoot() {
188
+ updateSorter() {
302
189
  if (!this.columnView || this.state.columnId === null) {
303
190
  this.state.column.setSorter(null);
304
191
  this.state.sorter = null;
305
192
  return;
306
193
  }
307
- const rootSortFn = this.columnView.getSortFn();
308
- if (rootSortFn === null) {
309
- this.state.column.setSorter(null);
310
- this.state.sorter = null;
311
- return;
312
- }
313
- const columnId = this.state.columnId;
314
- const columnView = this.columnView;
315
- const wrappedSortFn = (stringObjPtrA, stringObjPtrB) => {
316
- const items = columnView.getItems();
317
- const stringObjA = getObject(stringObjPtrA);
318
- const stringObjB = getObject(stringObjPtrB);
319
- const indexA = Number.parseInt(stringObjA.getString(), 10);
320
- const indexB = Number.parseInt(stringObjB.getString(), 10);
321
- if (Number.isNaN(indexA) || Number.isNaN(indexB))
322
- return 0;
323
- const itemA = items[indexA] ?? null;
324
- const itemB = items[indexB] ?? null;
325
- if (itemA === null || itemB === null)
326
- return 0;
327
- const result = columnView.compareItems(itemA, itemB, columnId);
328
- return typeof result === "number" ? result : 0;
329
- };
330
- this.state.sorter = new Gtk.CustomSorter(wrappedSortFn);
194
+ const noOpSortFn = () => 0;
195
+ this.state.sorter = new Gtk.CustomSorter(noOpSortFn);
331
196
  this.state.column.setSorter(this.state.sorter);
332
197
  }
333
198
  attachToParent(parent) {
@@ -344,20 +209,11 @@ export class ColumnViewColumnNode extends Node {
344
209
  }
345
210
  }
346
211
  detachFromParent(parent) {
212
+ this.state.factoryHandlers?.disconnect();
347
213
  if (isColumnContainer(parent)) {
348
214
  parent.removeColumn(this);
349
215
  }
350
216
  }
351
- consumedProps() {
352
- const consumed = super.consumedProps();
353
- consumed.add("renderCell");
354
- consumed.add("title");
355
- consumed.add("expand");
356
- consumed.add("resizable");
357
- consumed.add("fixedWidth");
358
- consumed.add("id");
359
- return consumed;
360
- }
361
217
  updateProps(oldProps, newProps) {
362
218
  if (oldProps.renderCell !== newProps.renderCell) {
363
219
  this.state.renderCell = newProps.renderCell;
@@ -380,37 +236,8 @@ export class ColumnViewColumnNode extends Node {
380
236
  }
381
237
  }
382
238
  }
383
- export class ColumnViewItemNode extends Node {
239
+ export class ColumnViewItemNode extends VirtualItemNode {
384
240
  static matches(type) {
385
241
  return type === "ColumnView.Item";
386
242
  }
387
- isVirtual() {
388
- return true;
389
- }
390
- item;
391
- initialize(props) {
392
- this.item = props.item;
393
- super.initialize(props);
394
- }
395
- getItem() {
396
- return this.item;
397
- }
398
- attachToParent(parent) {
399
- if (isItemContainer(parent)) {
400
- parent.addItem(this.item);
401
- }
402
- }
403
- attachToParentBefore(parent, before) {
404
- if (isItemContainer(parent) && before instanceof ColumnViewItemNode) {
405
- parent.insertItemBefore(this.item, before.getItem());
406
- }
407
- else {
408
- this.attachToParent(parent);
409
- }
410
- }
411
- detachFromParent(parent) {
412
- if (isItemContainer(parent)) {
413
- parent.removeItem(this.item);
414
- }
415
- }
416
243
  }
@@ -0,0 +1,5 @@
1
+ import type * as Adw from "@gtkx/ffi/adw";
2
+ import { StringListContainerNode } from "./string-list-container.js";
3
+ export declare class ComboRowNode extends StringListContainerNode<Adw.ComboRow> {
4
+ static matches(type: string): boolean;
5
+ }
@@ -0,0 +1,6 @@
1
+ import { StringListContainerNode } from "./string-list-container.js";
2
+ export class ComboRowNode extends StringListContainerNode {
3
+ static matches(type) {
4
+ return type === "AdwComboRow.Root";
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import { StringListContainerNode } from "./string-list-container.js";
3
+ import { StringListItemNode } from "./string-list-item.js";
4
+ export declare class DropDownNode extends StringListContainerNode<Gtk.DropDown> {
5
+ static matches(type: string): boolean;
6
+ }
7
+ export declare class DropDownItemNode extends StringListItemNode {
8
+ static matches(type: string): boolean;
9
+ }
@@ -0,0 +1,12 @@
1
+ import { StringListContainerNode } from "./string-list-container.js";
2
+ import { StringListItemNode } from "./string-list-item.js";
3
+ export class DropDownNode extends StringListContainerNode {
4
+ static matches(type) {
5
+ return type === "DropDown.Root";
6
+ }
7
+ }
8
+ export class DropDownItemNode extends StringListItemNode {
9
+ static matches(type) {
10
+ return type === "DropDown.Item" || type === "AdwComboRow.Item";
11
+ }
12
+ }
@@ -1,9 +1,7 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
- import type { ChildContainer } from "../container-interfaces.js";
3
- import { Node } from "../node.js";
4
- export declare class FlowBoxNode extends Node<Gtk.FlowBox> implements ChildContainer {
2
+ import { IndexedChildContainerNode } from "./indexed-child-container.js";
3
+ export declare class FlowBoxNode extends IndexedChildContainerNode<Gtk.FlowBox> {
5
4
  static matches(type: string): boolean;
6
- attachChild(child: Gtk.Widget): void;
7
- insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
8
- detachChild(child: Gtk.Widget): void;
5
+ protected getInsertionIndex(before: Gtk.Widget): number;
6
+ protected getWidgetToRemove(child: Gtk.Widget): Gtk.Widget;
9
7
  }
@@ -1,25 +1,17 @@
1
- import { Node } from "../node.js";
2
- const isFlowBoxChild = (widget) => "getIndex" in widget && "getChild" in widget && typeof widget.getIndex === "function";
3
- export class FlowBoxNode extends Node {
1
+ import { isFlowBoxChild } from "../predicates.js";
2
+ import { IndexedChildContainerNode } from "./indexed-child-container.js";
3
+ export class FlowBoxNode extends IndexedChildContainerNode {
4
4
  static matches(type) {
5
5
  return type === "FlowBox";
6
6
  }
7
- attachChild(child) {
8
- this.widget.append(child);
9
- }
10
- insertChildBefore(child, before) {
7
+ getInsertionIndex(before) {
11
8
  const beforeParent = before.getParent();
12
9
  if (beforeParent && isFlowBoxChild(beforeParent)) {
13
- this.widget.insert(child, beforeParent.getIndex());
14
- }
15
- else {
16
- this.widget.append(child);
10
+ return beforeParent.getIndex();
17
11
  }
12
+ return -1;
18
13
  }
19
- detachChild(child) {
20
- const flowBoxChild = child.getParent();
21
- if (flowBoxChild) {
22
- this.widget.remove(flowBoxChild);
23
- }
14
+ getWidgetToRemove(child) {
15
+ return child.getParent() ?? child;
24
16
  }
25
17
  }
@@ -2,26 +2,26 @@ import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import { type GridContainer } from "../container-interfaces.js";
3
3
  import type { Props } from "../factory.js";
4
4
  import { Node } from "../node.js";
5
+ import { VirtualSlotNode } from "./virtual-slot.js";
5
6
  export declare class GridNode extends Node<Gtk.Grid> implements GridContainer {
6
7
  static matches(type: string): boolean;
7
8
  attachToGrid(child: Gtk.Widget, column: number, row: number, colSpan: number, rowSpan: number): void;
8
9
  removeFromGrid(child: Gtk.Widget): void;
9
10
  }
10
- export declare class GridChildNode extends Node<never> {
11
+ type GridChildProps = {
12
+ column: number;
13
+ row: number;
14
+ columnSpan: number;
15
+ rowSpan: number;
16
+ };
17
+ export declare class GridChildNode extends VirtualSlotNode<GridContainer, GridChildProps> {
11
18
  static matches(type: string): boolean;
12
- protected isVirtual(): boolean;
13
- private column;
14
- private row;
15
- private columnSpan;
16
- private rowSpan;
17
- private childWidget;
18
- private parentContainer;
19
- initialize(props: Props): void;
20
- appendChild(child: Node): void;
21
- removeChild(child: Node): void;
22
- private attachChildToGrid;
23
- private detachChildFromGrid;
24
- attachToParent(parent: Node): void;
25
- detachFromParent(parent: Node): void;
19
+ protected isValidContainer(parent: Node): parent is Node & GridContainer;
20
+ protected extractSlotProps(props: Props): GridChildProps;
21
+ protected addToContainer(container: GridContainer, child: Gtk.Widget, props: GridChildProps): void;
22
+ protected insertBeforeInContainer(container: GridContainer, child: Gtk.Widget, props: GridChildProps, _before: Gtk.Widget): void;
23
+ protected removeFromContainer(container: GridContainer, child: Gtk.Widget): void;
24
+ protected updateInContainer(container: GridContainer, child: Gtk.Widget, props: GridChildProps): void;
26
25
  updateProps(oldProps: Props, newProps: Props): void;
27
26
  }
27
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { isGridContainer } from "../container-interfaces.js";
2
2
  import { Node } from "../node.js";
3
- import { getNumberProp } from "../props.js";
3
+ import { VirtualSlotNode } from "./virtual-slot.js";
4
4
  export class GridNode extends Node {
5
5
  static matches(type) {
6
6
  return type === "Grid.Root";
@@ -12,78 +12,35 @@ export class GridNode extends Node {
12
12
  this.widget.remove(child);
13
13
  }
14
14
  }
15
- export class GridChildNode extends Node {
15
+ export class GridChildNode extends VirtualSlotNode {
16
16
  static matches(type) {
17
17
  return type === "Grid.Child";
18
18
  }
19
- isVirtual() {
20
- return true;
19
+ isValidContainer(parent) {
20
+ return isGridContainer(parent);
21
21
  }
22
- column = 0;
23
- row = 0;
24
- columnSpan = 1;
25
- rowSpan = 1;
26
- childWidget = null;
27
- parentContainer = null;
28
- initialize(props) {
29
- this.column = getNumberProp(props, "column", 0);
30
- this.row = getNumberProp(props, "row", 0);
31
- this.columnSpan = getNumberProp(props, "columnSpan", 1);
32
- this.rowSpan = getNumberProp(props, "rowSpan", 1);
33
- super.initialize(props);
22
+ extractSlotProps(props) {
23
+ return {
24
+ column: props.column ?? 0,
25
+ row: props.row ?? 0,
26
+ columnSpan: props.columnSpan ?? 1,
27
+ rowSpan: props.rowSpan ?? 1,
28
+ };
34
29
  }
35
- appendChild(child) {
36
- const widget = child.getWidget();
37
- if (widget) {
38
- this.childWidget = widget;
39
- if (this.parentContainer) {
40
- this.attachChildToGrid();
41
- }
42
- }
30
+ addToContainer(container, child, props) {
31
+ container.attachToGrid(child, props.column, props.row, props.columnSpan, props.rowSpan);
43
32
  }
44
- removeChild(child) {
45
- const widget = child.getWidget();
46
- if (widget && this.childWidget === widget) {
47
- this.detachChildFromGrid();
48
- this.childWidget = null;
49
- }
33
+ insertBeforeInContainer(container, child, props, _before) {
34
+ this.addToContainer(container, child, props);
50
35
  }
51
- attachChildToGrid() {
52
- if (!this.parentContainer || !this.childWidget)
53
- return;
54
- this.parentContainer.attachToGrid(this.childWidget, this.column, this.row, this.columnSpan, this.rowSpan);
36
+ removeFromContainer(container, child) {
37
+ container.removeFromGrid(child);
55
38
  }
56
- detachChildFromGrid() {
57
- if (!this.parentContainer || !this.childWidget)
58
- return;
59
- this.parentContainer.removeFromGrid(this.childWidget);
60
- }
61
- attachToParent(parent) {
62
- if (isGridContainer(parent)) {
63
- this.parentContainer = parent;
64
- if (this.childWidget) {
65
- this.attachChildToGrid();
66
- }
67
- }
68
- }
69
- detachFromParent(parent) {
70
- if (isGridContainer(parent)) {
71
- this.detachChildFromGrid();
72
- this.parentContainer = null;
73
- }
39
+ updateInContainer(container, child, props) {
40
+ container.removeFromGrid(child);
41
+ container.attachToGrid(child, props.column, props.row, props.columnSpan, props.rowSpan);
74
42
  }
75
43
  updateProps(oldProps, newProps) {
76
- const positionChanged = oldProps.column !== newProps.column ||
77
- oldProps.row !== newProps.row ||
78
- oldProps.columnSpan !== newProps.columnSpan ||
79
- oldProps.rowSpan !== newProps.rowSpan;
80
- if (positionChanged) {
81
- this.detachChildFromGrid();
82
- this.column = getNumberProp(newProps, "column", 0);
83
- this.row = getNumberProp(newProps, "row", 0);
84
- this.columnSpan = getNumberProp(newProps, "columnSpan", 1);
85
- this.rowSpan = getNumberProp(newProps, "rowSpan", 1);
86
- this.attachChildToGrid();
87
- }
44
+ this.updateSlotPropsIfChanged(oldProps, newProps, ["column", "row", "columnSpan", "rowSpan"]);
88
45
  }
89
46
  }