@gtkx/react 0.12.1 → 0.13.1

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 (81) hide show
  1. package/README.md +1 -1
  2. package/dist/generated/internal.js +2 -0
  3. package/dist/generated/jsx.d.ts +32 -18
  4. package/dist/host-config.js +3 -3
  5. package/dist/jsx.d.ts +524 -366
  6. package/dist/jsx.js +401 -353
  7. package/dist/nodes/action-row-child.d.ts +4 -11
  8. package/dist/nodes/action-row-child.js +10 -66
  9. package/dist/nodes/action-row.js +21 -4
  10. package/dist/nodes/application.js +22 -3
  11. package/dist/nodes/autowrapped.js +13 -3
  12. package/dist/nodes/calendar-mark.d.ts +15 -0
  13. package/dist/nodes/calendar-mark.js +29 -0
  14. package/dist/nodes/calendar.d.ts +1 -0
  15. package/dist/nodes/calendar.js +70 -0
  16. package/dist/nodes/column-view-column.d.ts +1 -0
  17. package/dist/nodes/column-view-column.js +4 -0
  18. package/dist/nodes/column-view.js +24 -7
  19. package/dist/nodes/expander-row-child.d.ts +15 -0
  20. package/dist/nodes/expander-row-child.js +20 -0
  21. package/dist/nodes/expander-row.d.ts +1 -0
  22. package/dist/nodes/expander-row.js +54 -0
  23. package/dist/nodes/fixed-child.js +10 -8
  24. package/dist/nodes/grid-child.js +10 -8
  25. package/dist/nodes/index.d.ts +12 -0
  26. package/dist/nodes/index.js +12 -0
  27. package/dist/nodes/internal/list-item-renderer.d.ts +3 -0
  28. package/dist/nodes/internal/list-item-renderer.js +25 -9
  29. package/dist/nodes/internal/list-store.js +2 -2
  30. package/dist/nodes/internal/tree-list-item-renderer.d.ts +8 -0
  31. package/dist/nodes/internal/tree-list-item-renderer.js +68 -24
  32. package/dist/nodes/internal/tree-store.js +3 -4
  33. package/dist/nodes/level-bar-offset.d.ts +13 -0
  34. package/dist/nodes/level-bar-offset.js +35 -0
  35. package/dist/nodes/level-bar.d.ts +1 -0
  36. package/dist/nodes/level-bar.js +82 -0
  37. package/dist/nodes/list-view.js +14 -7
  38. package/dist/nodes/menu.js +4 -4
  39. package/dist/nodes/models/list.d.ts +2 -1
  40. package/dist/nodes/models/list.js +21 -12
  41. package/dist/nodes/models/menu.d.ts +1 -0
  42. package/dist/nodes/models/menu.js +24 -17
  43. package/dist/nodes/models/tree-list.d.ts +2 -1
  44. package/dist/nodes/models/tree-list.js +43 -24
  45. package/dist/nodes/navigation-page.d.ts +16 -0
  46. package/dist/nodes/navigation-page.js +58 -0
  47. package/dist/nodes/navigation-view.d.ts +1 -0
  48. package/dist/nodes/navigation-view.js +105 -0
  49. package/dist/nodes/notebook-page-tab.js +1 -1
  50. package/dist/nodes/notebook-page.js +3 -2
  51. package/dist/nodes/notebook.js +3 -3
  52. package/dist/nodes/overlay-child.js +29 -14
  53. package/dist/nodes/pack-child.d.ts +4 -11
  54. package/dist/nodes/pack-child.js +10 -66
  55. package/dist/nodes/pack.js +21 -4
  56. package/dist/nodes/popover-menu.js +15 -12
  57. package/dist/nodes/scale-mark.d.ts +17 -0
  58. package/dist/nodes/scale-mark.js +38 -0
  59. package/dist/nodes/scale.d.ts +1 -0
  60. package/dist/nodes/scale.js +70 -0
  61. package/dist/nodes/simple-list-view.js +3 -3
  62. package/dist/nodes/slot.js +2 -2
  63. package/dist/nodes/stack-page.js +7 -7
  64. package/dist/nodes/stack.js +5 -5
  65. package/dist/nodes/toggle-group.d.ts +1 -0
  66. package/dist/nodes/toggle-group.js +48 -0
  67. package/dist/nodes/toggle.d.ts +15 -0
  68. package/dist/nodes/toggle.js +70 -0
  69. package/dist/nodes/toolbar-child.js +18 -16
  70. package/dist/nodes/tree-list-view.js +16 -7
  71. package/dist/nodes/virtual-child.d.ts +18 -0
  72. package/dist/nodes/virtual-child.js +62 -0
  73. package/dist/nodes/widget.js +22 -8
  74. package/dist/nodes/window.d.ts +22 -0
  75. package/dist/nodes/window.js +11 -2
  76. package/dist/render.d.ts +3 -5
  77. package/dist/render.js +3 -5
  78. package/dist/scheduler.d.ts +13 -1
  79. package/dist/scheduler.js +26 -6
  80. package/dist/types.d.ts +25 -0
  81. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  import { batch, isObjectEqual } from "@gtkx/ffi";
2
2
  import * as Gio from "@gtkx/ffi/gio";
3
- import { scheduleAfterCommit } from "../../scheduler.js";
3
+ import { CommitPriority, scheduleAfterCommit } from "../../scheduler.js";
4
4
  import { signalStore } from "../internal/signal-store.js";
5
5
  import { VirtualNode } from "../virtual.js";
6
6
  export class Menu extends VirtualNode {
@@ -90,7 +90,9 @@ export class Menu extends VirtualNode {
90
90
  });
91
91
  }
92
92
  getPosition() {
93
- const parent = this.getParent();
93
+ return this.findPositionIn(this.getParent());
94
+ }
95
+ findPositionIn(parent) {
94
96
  for (let i = 0; i < parent.getNItems(); i++) {
95
97
  if (this.type === "item") {
96
98
  const actionName = parent.getItemAttributeValue(i, "action")?.getString();
@@ -105,7 +107,7 @@ export class Menu extends VirtualNode {
105
107
  }
106
108
  }
107
109
  }
108
- return 0;
110
+ return -1;
109
111
  }
110
112
  setParent(parent) {
111
113
  this.parent = parent;
@@ -122,10 +124,14 @@ export class Menu extends VirtualNode {
122
124
  removeFromParent() {
123
125
  if (!this.parent)
124
126
  return;
125
- const position = this.getPosition();
126
127
  const parent = this.parent;
127
128
  this.parent = undefined;
128
- batch(() => parent.remove(position));
129
+ scheduleAfterCommit(() => {
130
+ const position = this.findPositionIn(parent);
131
+ if (position >= 0) {
132
+ parent.remove(position);
133
+ }
134
+ }, CommitPriority.HIGH);
129
135
  }
130
136
  insertInParentBefore(before) {
131
137
  if (this.type === "item" && this.actionMap) {
@@ -244,23 +250,24 @@ export class Menu extends VirtualNode {
244
250
  return;
245
251
  }
246
252
  if (!oldProps || oldProps.label !== newProps.label) {
247
- const position = this.getPosition();
248
253
  const parent = this.parent;
249
- this.removeFromParent();
250
- if (this.type === "section") {
251
- parent.insertSection(position, this.menu, newProps.label);
252
- }
253
- else if (this.type === "submenu") {
254
- parent.insertSubmenu(position, this.menu, newProps.label);
255
- }
254
+ batch(() => {
255
+ const position = this.findPositionIn(parent);
256
+ if (position >= 0) {
257
+ parent.remove(position);
258
+ if (this.type === "section") {
259
+ parent.insertSection(position, this.menu, this.props.label);
260
+ }
261
+ else if (this.type === "submenu") {
262
+ parent.insertSubmenu(position, this.menu, this.props.label);
263
+ }
264
+ }
265
+ });
256
266
  }
257
267
  }
258
268
  unmount() {
259
269
  this.removeAction();
260
- if (this.parent) {
261
- this.removeFromParent();
262
- this.parent = undefined;
263
- }
270
+ this.removeFromParent();
264
271
  super.unmount();
265
272
  }
266
273
  }
@@ -13,7 +13,8 @@ export declare class TreeList extends VirtualNode<TreeListProps> {
13
13
  private treeListModel;
14
14
  private selectionModel;
15
15
  private handleSelectionChange?;
16
- constructor(autoexpand?: boolean, selectionMode?: Gtk.SelectionMode);
16
+ constructor(props?: TreeListProps);
17
+ private initSelectionHandler;
17
18
  private createChildModel;
18
19
  getStore(): TreeStore;
19
20
  getTreeListModel(): Gtk.TreeListModel;
@@ -1,4 +1,5 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { scheduleAfterCommit } from "../../scheduler.js";
2
3
  import { signalStore } from "../internal/signal-store.js";
3
4
  import { TreeStore } from "../internal/tree-store.js";
4
5
  import { TreeListItemNode } from "../tree-list-item.js";
@@ -8,12 +9,23 @@ export class TreeList extends VirtualNode {
8
9
  treeListModel;
9
10
  selectionModel;
10
11
  handleSelectionChange;
11
- constructor(autoexpand = false, selectionMode) {
12
+ constructor(props = {}) {
12
13
  super("", {}, undefined);
13
14
  this.store = new TreeStore();
14
- this.treeListModel = new Gtk.TreeListModel(this.store.getRootModel(), false, autoexpand, (item) => this.createChildModel(item));
15
- this.selectionModel = this.createSelectionModel(selectionMode);
15
+ this.treeListModel = new Gtk.TreeListModel(this.store.getRootModel(), false, props.autoexpand ?? false, (item) => this.createChildModel(item));
16
+ this.selectionModel = this.createSelectionModel(props.selectionMode);
16
17
  this.selectionModel.setModel(this.treeListModel);
18
+ this.initSelectionHandler(props.onSelectionChanged);
19
+ }
20
+ initSelectionHandler(onSelectionChanged) {
21
+ if (!onSelectionChanged) {
22
+ signalStore.set(this, this.selectionModel, "selection-changed", null);
23
+ return;
24
+ }
25
+ this.handleSelectionChange = () => {
26
+ onSelectionChanged(this.getSelection());
27
+ };
28
+ signalStore.set(this, this.selectionModel, "selection-changed", this.handleSelectionChange);
17
29
  }
18
30
  createChildModel(item) {
19
31
  if (!(item instanceof Gtk.StringObject))
@@ -37,12 +49,15 @@ export class TreeList extends VirtualNode {
37
49
  if (!child.props.id) {
38
50
  throw new Error("Cannot append 'TreeListItem' to 'TreeList': missing required 'id' prop");
39
51
  }
52
+ const id = child.props.id;
40
53
  child.setStore(this.store);
41
- this.store.addItem(child.props.id, {
42
- value: child.props.value,
43
- indentForDepth: child.props.indentForDepth,
44
- indentForIcon: child.props.indentForIcon,
45
- hideExpander: child.props.hideExpander,
54
+ scheduleAfterCommit(() => {
55
+ this.store.addItem(id, {
56
+ value: child.props.value,
57
+ indentForDepth: child.props.indentForDepth,
58
+ indentForIcon: child.props.indentForIcon,
59
+ hideExpander: child.props.hideExpander,
60
+ });
46
61
  });
47
62
  }
48
63
  insertBefore(child, before) {
@@ -55,12 +70,16 @@ export class TreeList extends VirtualNode {
55
70
  if (!before.props.id) {
56
71
  throw new Error("Cannot insert 'TreeListItem' into 'TreeList': 'before' node missing required 'id' prop");
57
72
  }
73
+ const id = child.props.id;
74
+ const beforeId = before.props.id;
58
75
  child.setStore(this.store);
59
- this.store.insertItemBefore(child.props.id, before.props.id, {
60
- value: child.props.value,
61
- indentForDepth: child.props.indentForDepth,
62
- indentForIcon: child.props.indentForIcon,
63
- hideExpander: child.props.hideExpander,
76
+ scheduleAfterCommit(() => {
77
+ this.store.insertItemBefore(id, beforeId, {
78
+ value: child.props.value,
79
+ indentForDepth: child.props.indentForDepth,
80
+ indentForIcon: child.props.indentForIcon,
81
+ hideExpander: child.props.hideExpander,
82
+ });
64
83
  });
65
84
  }
66
85
  removeChild(child) {
@@ -70,7 +89,10 @@ export class TreeList extends VirtualNode {
70
89
  if (!child.props.id) {
71
90
  throw new Error("Cannot remove 'TreeListItem' from 'TreeList': missing required 'id' prop");
72
91
  }
73
- this.store.removeItem(child.props.id);
92
+ const id = child.props.id;
93
+ scheduleAfterCommit(() => {
94
+ this.store.removeItem(id);
95
+ });
74
96
  child.setStore(null);
75
97
  }
76
98
  updateProps(oldProps, newProps) {
@@ -78,21 +100,18 @@ export class TreeList extends VirtualNode {
78
100
  if (!oldProps || oldProps.autoexpand !== newProps.autoexpand) {
79
101
  this.treeListModel.setAutoexpand(newProps.autoexpand ?? false);
80
102
  }
81
- if (!oldProps || oldProps.selectionMode !== newProps.selectionMode) {
103
+ if (oldProps && oldProps.selectionMode !== newProps.selectionMode) {
82
104
  signalStore.set(this, this.selectionModel, "selection-changed", null);
83
105
  this.selectionModel = this.createSelectionModel(newProps.selectionMode);
84
106
  this.selectionModel.setModel(this.treeListModel);
107
+ this.initSelectionHandler(newProps.onSelectionChanged);
108
+ this.setSelection(newProps.selected);
109
+ return;
85
110
  }
86
- if (!oldProps ||
87
- oldProps.onSelectionChanged !== newProps.onSelectionChanged ||
88
- oldProps.selectionMode !== newProps.selectionMode) {
89
- const onSelectionChanged = newProps.onSelectionChanged;
90
- this.handleSelectionChange = () => {
91
- onSelectionChanged?.(this.getSelection());
92
- };
93
- signalStore.set(this, this.selectionModel, "selection-changed", newProps.onSelectionChanged ? this.handleSelectionChange : null);
111
+ if (!oldProps || oldProps.onSelectionChanged !== newProps.onSelectionChanged) {
112
+ this.initSelectionHandler(newProps.onSelectionChanged);
94
113
  }
95
- if (!oldProps || oldProps.selected !== newProps.selected || oldProps.selectionMode !== newProps.selectionMode) {
114
+ if (!oldProps || oldProps.selected !== newProps.selected) {
96
115
  this.setSelection(newProps.selected);
97
116
  }
98
117
  }
@@ -0,0 +1,16 @@
1
+ import * as Adw from "@gtkx/ffi/adw";
2
+ import type * as Gtk from "@gtkx/ffi/gtk";
3
+ import type { NavigationPageProps } from "../jsx.js";
4
+ import { SlotNode } from "./slot.js";
5
+ type Props = Partial<NavigationPageProps>;
6
+ export declare class NavigationPageNode extends SlotNode<Props> {
7
+ static priority: number;
8
+ private page?;
9
+ static matches(type: string): boolean;
10
+ getPage(): Adw.NavigationPage | undefined;
11
+ updateProps(oldProps: Props | null, newProps: Props): void;
12
+ private addPage;
13
+ private removePage;
14
+ protected onChildChange(oldChild: Gtk.Widget | null): void;
15
+ }
16
+ export {};
@@ -0,0 +1,58 @@
1
+ import { isObjectEqual } from "@gtkx/ffi";
2
+ import * as Adw from "@gtkx/ffi/adw";
3
+ import { registerNodeClass } from "../registry.js";
4
+ import { SlotNode } from "./slot.js";
5
+ export class NavigationPageNode extends SlotNode {
6
+ static priority = 1;
7
+ page;
8
+ static matches(type) {
9
+ return type === "NavigationPage";
10
+ }
11
+ getPage() {
12
+ return this.page;
13
+ }
14
+ updateProps(oldProps, newProps) {
15
+ super.updateProps(oldProps, newProps);
16
+ if (!this.page) {
17
+ return;
18
+ }
19
+ if (newProps.id !== undefined && (!oldProps || oldProps.id !== newProps.id)) {
20
+ this.page.setTag(newProps.id);
21
+ }
22
+ if (newProps.title !== undefined && (!oldProps || oldProps.title !== newProps.title)) {
23
+ this.page.setTitle(newProps.title);
24
+ }
25
+ if (newProps.canPop !== undefined && (!oldProps || oldProps.canPop !== newProps.canPop)) {
26
+ this.page.setCanPop(newProps.canPop);
27
+ }
28
+ }
29
+ addPage() {
30
+ const child = this.getChild();
31
+ const parent = this.getParent();
32
+ const title = this.props.title ?? "";
33
+ const page = this.props.id
34
+ ? Adw.NavigationPage.newWithTag(child, title, this.props.id)
35
+ : new Adw.NavigationPage(child, title);
36
+ parent.add(page);
37
+ this.page = page;
38
+ this.updateProps(null, this.props);
39
+ }
40
+ removePage(oldChild) {
41
+ const parent = this.getParent();
42
+ if (!oldChild || !this.page) {
43
+ return;
44
+ }
45
+ const pageChild = this.page.getChild();
46
+ if (pageChild && isObjectEqual(pageChild, oldChild)) {
47
+ parent.remove(this.page);
48
+ this.page = undefined;
49
+ }
50
+ }
51
+ onChildChange(oldChild) {
52
+ this.removePage(oldChild);
53
+ if (this.child) {
54
+ this.addPage();
55
+ }
56
+ }
57
+ }
58
+ registerNodeClass(NavigationPageNode);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,105 @@
1
+ import * as Adw from "@gtkx/ffi/adw";
2
+ import { registerNodeClass } from "../registry.js";
3
+ import { scheduleAfterCommit } from "../scheduler.js";
4
+ import { signalStore } from "./internal/signal-store.js";
5
+ import { filterProps, isContainerType } from "./internal/utils.js";
6
+ import { NavigationPageNode } from "./navigation-page.js";
7
+ import { SlotNode } from "./slot.js";
8
+ import { WidgetNode } from "./widget.js";
9
+ const PROPS = ["history", "onHistoryChanged"];
10
+ class NavigationViewNode extends WidgetNode {
11
+ static priority = 1;
12
+ static matches(_type, containerOrClass) {
13
+ return isContainerType(Adw.NavigationView, containerOrClass);
14
+ }
15
+ appendChild(child) {
16
+ if (child instanceof NavigationPageNode) {
17
+ child.setParent(this.container);
18
+ return;
19
+ }
20
+ if (child instanceof SlotNode || child instanceof WidgetNode) {
21
+ super.appendChild(child);
22
+ return;
23
+ }
24
+ throw new Error(`Cannot append '${child.typeName}' to 'NavigationView': expected x.NavigationPage or Widget`);
25
+ }
26
+ insertBefore(child, before) {
27
+ if (child instanceof NavigationPageNode) {
28
+ child.setParent(this.container);
29
+ return;
30
+ }
31
+ if (child instanceof SlotNode || child instanceof WidgetNode) {
32
+ super.insertBefore(child, before);
33
+ return;
34
+ }
35
+ throw new Error(`Cannot insert '${child.typeName}' into 'NavigationView': expected x.NavigationPage or Widget`);
36
+ }
37
+ removeChild(child) {
38
+ if (child instanceof NavigationPageNode) {
39
+ return;
40
+ }
41
+ if (child instanceof SlotNode || child instanceof WidgetNode) {
42
+ super.removeChild(child);
43
+ return;
44
+ }
45
+ throw new Error(`Cannot remove '${child.typeName}' from 'NavigationView': expected x.NavigationPage or Widget`);
46
+ }
47
+ updateProps(oldProps, newProps) {
48
+ const oldHistory = oldProps?.history;
49
+ const newHistory = newProps.history;
50
+ if (newHistory && !this.arraysEqual(oldHistory, newHistory)) {
51
+ this.syncHistory(newHistory);
52
+ }
53
+ if (!oldProps || oldProps.onHistoryChanged !== newProps.onHistoryChanged) {
54
+ const onHistoryChanged = newProps.onHistoryChanged;
55
+ if (onHistoryChanged) {
56
+ const handleHistoryChanged = () => {
57
+ const history = this.getCurrentHistory();
58
+ onHistoryChanged(history);
59
+ };
60
+ signalStore.set(this, this.container, "popped", handleHistoryChanged);
61
+ signalStore.set(this, this.container, "pushed", handleHistoryChanged);
62
+ signalStore.set(this, this.container, "replaced", handleHistoryChanged);
63
+ }
64
+ else {
65
+ signalStore.set(this, this.container, "popped", null);
66
+ signalStore.set(this, this.container, "pushed", null);
67
+ signalStore.set(this, this.container, "replaced", null);
68
+ }
69
+ }
70
+ super.updateProps(filterProps(oldProps ?? {}, PROPS), filterProps(newProps, PROPS));
71
+ }
72
+ syncHistory(history) {
73
+ const container = this.container;
74
+ scheduleAfterCommit(() => {
75
+ container.replaceWithTags(history, history.length);
76
+ });
77
+ }
78
+ getCurrentHistory() {
79
+ const stack = this.container.getNavigationStack();
80
+ const history = [];
81
+ const nItems = stack.getNItems();
82
+ for (let i = 0; i < nItems; i++) {
83
+ const page = stack.getObject(i);
84
+ const tag = page?.getTag();
85
+ if (tag) {
86
+ history.push(tag);
87
+ }
88
+ }
89
+ return history;
90
+ }
91
+ arraysEqual(a, b) {
92
+ if (a === b)
93
+ return true;
94
+ if (!a || !b)
95
+ return false;
96
+ if (a.length !== b.length)
97
+ return false;
98
+ for (let i = 0; i < a.length; i++) {
99
+ if (a[i] !== b[i])
100
+ return false;
101
+ }
102
+ return true;
103
+ }
104
+ }
105
+ registerNodeClass(NavigationViewNode);
@@ -5,7 +5,7 @@ export class NotebookPageTabNode extends SlotNode {
5
5
  notebook;
6
6
  page;
7
7
  static matches(type) {
8
- return type === "Notebook.PageTab";
8
+ return type === "NotebookPageTab";
9
9
  }
10
10
  setPage(notebook, page) {
11
11
  this.notebook = notebook;
@@ -9,7 +9,7 @@ export class NotebookPageNode extends SlotNode {
9
9
  position;
10
10
  tabNode;
11
11
  static matches(type) {
12
- return type === "Notebook.Page";
12
+ return type === "NotebookPage";
13
13
  }
14
14
  setNotebook(notebook) {
15
15
  this.setParent(notebook);
@@ -38,7 +38,7 @@ export class NotebookPageNode extends SlotNode {
38
38
  return;
39
39
  }
40
40
  if (!(child instanceof WidgetNode)) {
41
- throw new Error(`Cannot append '${child.typeName}' to 'Notebook.Page': expected Widget or Notebook.PageTab`);
41
+ throw new Error(`Cannot append '${child.typeName}' to 'x.NotebookPage': expected Widget or x.NotebookPageTab`);
42
42
  }
43
43
  const oldChild = this.child;
44
44
  this.child = child.container;
@@ -61,6 +61,7 @@ export class NotebookPageNode extends SlotNode {
61
61
  super.unmount();
62
62
  }
63
63
  updateProps(oldProps, newProps) {
64
+ super.updateProps(oldProps, newProps);
64
65
  if (!oldProps || oldProps.label !== newProps.label) {
65
66
  if (this.child && this.parent && !this.tabNode?.child) {
66
67
  const tabLabel = this.getNotebook().getTabLabel(this.child);
@@ -10,13 +10,13 @@ class NotebookNode extends WidgetNode {
10
10
  }
11
11
  appendChild(child) {
12
12
  if (!(child instanceof NotebookPageNode)) {
13
- throw new Error(`Cannot append '${child.typeName}' to 'Notebook': expected Notebook.Page`);
13
+ throw new Error(`Cannot append '${child.typeName}' to 'Notebook': expected x.NotebookPage`);
14
14
  }
15
15
  child.setNotebook(this.container);
16
16
  }
17
17
  insertBefore(child, before) {
18
18
  if (!(child instanceof NotebookPageNode) || !(before instanceof NotebookPageNode)) {
19
- throw new Error(`Cannot insert '${child.typeName}' to 'Notebook': expected Notebook.Page`);
19
+ throw new Error(`Cannot insert '${child.typeName}' into 'Notebook': expected x.NotebookPage`);
20
20
  }
21
21
  const beforePosition = this.container.pageNum(before.getChild());
22
22
  child.setPosition(beforePosition);
@@ -24,7 +24,7 @@ class NotebookNode extends WidgetNode {
24
24
  }
25
25
  removeChild(child) {
26
26
  if (!(child instanceof NotebookPageNode)) {
27
- throw new Error(`Cannot remove '${child.typeName}' from 'Notebook': expected Notebook.Page`);
27
+ throw new Error(`Cannot remove '${child.typeName}' from 'Notebook': expected x.NotebookPage`);
28
28
  }
29
29
  child.setPosition(null);
30
30
  }
@@ -1,4 +1,4 @@
1
- import { isObjectEqual } from "@gtkx/ffi";
1
+ import { batch, isObjectEqual } from "@gtkx/ffi";
2
2
  import { registerNodeClass } from "../registry.js";
3
3
  import { SlotNode } from "./slot.js";
4
4
  class OverlayChildNode extends SlotNode {
@@ -12,23 +12,38 @@ class OverlayChildNode extends SlotNode {
12
12
  }
13
13
  return this.parent;
14
14
  }
15
- onChildChange(oldChild) {
15
+ updateProps(oldProps, newProps) {
16
+ super.updateProps(oldProps, newProps);
17
+ if (!this.parent || !this.child) {
18
+ return;
19
+ }
16
20
  const overlay = this.getOverlay();
17
- if (oldChild) {
18
- const parent = oldChild.getParent();
19
- if (parent && isObjectEqual(parent, overlay)) {
20
- overlay.removeOverlay(oldChild);
21
- }
21
+ if (!oldProps || oldProps.measure !== newProps.measure) {
22
+ overlay.setMeasureOverlay(this.child, newProps.measure ?? false);
23
+ }
24
+ if (!oldProps || oldProps.clipOverlay !== newProps.clipOverlay) {
25
+ overlay.setClipOverlay(this.child, newProps.clipOverlay ?? false);
22
26
  }
23
- if (this.child) {
24
- overlay.addOverlay(this.child);
25
- if (this.props.measure !== undefined) {
26
- overlay.setMeasureOverlay(this.child, this.props.measure);
27
+ }
28
+ onChildChange(oldChild) {
29
+ const overlay = this.getOverlay();
30
+ batch(() => {
31
+ if (oldChild) {
32
+ const parent = oldChild.getParent();
33
+ if (parent && isObjectEqual(parent, overlay)) {
34
+ overlay.removeOverlay(oldChild);
35
+ }
27
36
  }
28
- if (this.props.clipOverlay !== undefined) {
29
- overlay.setClipOverlay(this.child, this.props.clipOverlay);
37
+ if (this.child) {
38
+ overlay.addOverlay(this.child);
39
+ if (this.props.measure !== undefined) {
40
+ overlay.setMeasureOverlay(this.child, this.props.measure);
41
+ }
42
+ if (this.props.clipOverlay !== undefined) {
43
+ overlay.setClipOverlay(this.child, this.props.clipOverlay);
44
+ }
30
45
  }
31
- }
46
+ });
32
47
  }
33
48
  }
34
49
  registerNodeClass(OverlayChildNode);
@@ -1,21 +1,14 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
- import type { Node } from "../node.js";
3
- import { VirtualNode } from "./virtual.js";
2
+ import { VirtualChildNode } from "./virtual-child.js";
4
3
  type PackableWidget = Gtk.Widget & {
5
4
  packStart(child: Gtk.Widget): void;
6
5
  packEnd(child: Gtk.Widget): void;
7
6
  remove(child: Gtk.Widget): void;
8
7
  };
9
- export declare class PackChild extends VirtualNode {
8
+ export declare class PackChild extends VirtualChildNode<PackableWidget> {
10
9
  static priority: number;
11
10
  static matches(type: string): boolean;
12
- private parent?;
13
- private children;
14
- private getPosition;
15
- setParent(newParent?: PackableWidget): void;
16
- unmount(): void;
17
- appendChild(child: Node): void;
18
- insertBefore(child: Node): void;
19
- removeChild(child: Node): void;
11
+ protected getPositionLabel(): string;
12
+ protected attachChild(parent: PackableWidget, widget: Gtk.Widget): void;
20
13
  }
21
14
  export {};
@@ -1,76 +1,20 @@
1
- import { isObjectEqual } from "@gtkx/ffi";
2
1
  import { registerNodeClass } from "../registry.js";
3
- import { scheduleAfterCommit } from "../scheduler.js";
4
- import { VirtualNode } from "./virtual.js";
5
- import { WidgetNode } from "./widget.js";
6
- export class PackChild extends VirtualNode {
2
+ import { VirtualChildNode } from "./virtual-child.js";
3
+ export class PackChild extends VirtualChildNode {
7
4
  static priority = 1;
8
5
  static matches(type) {
9
- return type === "Pack.Start" || type === "Pack.End";
6
+ return type === "PackStart" || type === "PackEnd";
10
7
  }
11
- parent;
12
- children = [];
13
- getPosition() {
14
- return this.typeName === "Pack.Start" ? "start" : "end";
8
+ getPositionLabel() {
9
+ return this.typeName === "PackStart" ? "start" : "end";
15
10
  }
16
- setParent(newParent) {
17
- this.parent = newParent;
18
- }
19
- unmount() {
20
- const parent = this.parent;
21
- const childrenToRemove = [...this.children];
22
- if (parent && childrenToRemove.length > 0) {
23
- scheduleAfterCommit(() => {
24
- for (const widget of childrenToRemove) {
25
- const currentParent = widget.getParent();
26
- if (currentParent && isObjectEqual(currentParent, parent)) {
27
- parent.remove(widget);
28
- }
29
- }
30
- });
31
- }
32
- this.children = [];
33
- this.parent = undefined;
34
- super.unmount();
35
- }
36
- appendChild(child) {
37
- if (!(child instanceof WidgetNode)) {
38
- throw new Error(`Cannot append '${child.typeName}' to '${this.typeName}': expected Widget`);
39
- }
40
- const widget = child.container;
41
- this.children.push(widget);
42
- scheduleAfterCommit(() => {
43
- if (this.parent) {
44
- if (this.getPosition() === "start") {
45
- this.parent.packStart(widget);
46
- }
47
- else {
48
- this.parent.packEnd(widget);
49
- }
50
- }
51
- });
52
- }
53
- insertBefore(child) {
54
- this.appendChild(child);
55
- }
56
- removeChild(child) {
57
- if (!(child instanceof WidgetNode)) {
58
- throw new Error(`Cannot remove '${child.typeName}' from '${this.typeName}': expected Widget`);
11
+ attachChild(parent, widget) {
12
+ if (this.getPositionLabel() === "start") {
13
+ parent.packStart(widget);
59
14
  }
60
- const widget = child.container;
61
- const parent = this.parent;
62
- const index = this.children.indexOf(widget);
63
- if (index !== -1) {
64
- this.children.splice(index, 1);
15
+ else {
16
+ parent.packEnd(widget);
65
17
  }
66
- scheduleAfterCommit(() => {
67
- if (parent) {
68
- const currentParent = widget.getParent();
69
- if (currentParent && isObjectEqual(currentParent, parent)) {
70
- parent.remove(widget);
71
- }
72
- }
73
- });
74
18
  }
75
19
  }
76
20
  registerNodeClass(PackChild);