@gtkx/react 0.8.0 → 0.9.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 (62) hide show
  1. package/dist/{container-interfaces.d.ts → containers.d.ts} +10 -37
  2. package/dist/containers.js +1 -0
  3. package/dist/factory.d.ts +1 -1
  4. package/dist/factory.js +3 -3
  5. package/dist/{reconciler/host-config.d.ts → host-config.d.ts} +2 -2
  6. package/dist/{reconciler/host-config.js → host-config.js} +2 -2
  7. package/dist/node.d.ts +5 -6
  8. package/dist/node.js +54 -72
  9. package/dist/nodes/about-dialog.d.ts +2 -3
  10. package/dist/nodes/about-dialog.js +6 -4
  11. package/dist/nodes/column-view.d.ts +10 -9
  12. package/dist/nodes/column-view.js +53 -40
  13. package/dist/nodes/flow-box.js +1 -1
  14. package/dist/nodes/grid.d.ts +4 -1
  15. package/dist/nodes/grid.js +39 -1
  16. package/dist/nodes/header-bar.d.ts +15 -14
  17. package/dist/nodes/header-bar.js +79 -39
  18. package/dist/nodes/indexed-child-container.d.ts +1 -1
  19. package/dist/nodes/list-box.js +2 -2
  20. package/dist/nodes/list-item-factory.js +3 -3
  21. package/dist/nodes/list-view.d.ts +1 -2
  22. package/dist/nodes/list-view.js +2 -2
  23. package/dist/nodes/menu.d.ts +28 -12
  24. package/dist/nodes/menu.js +64 -37
  25. package/dist/nodes/notebook.d.ts +4 -1
  26. package/dist/nodes/notebook.js +48 -4
  27. package/dist/nodes/overlay.d.ts +1 -1
  28. package/dist/nodes/overlay.js +1 -1
  29. package/dist/nodes/paged-stack.d.ts +7 -3
  30. package/dist/nodes/paged-stack.js +47 -2
  31. package/dist/nodes/root.d.ts +1 -1
  32. package/dist/nodes/root.js +2 -2
  33. package/dist/nodes/selectable-list.d.ts +7 -3
  34. package/dist/nodes/selectable-list.js +37 -5
  35. package/dist/nodes/slot.d.ts +3 -4
  36. package/dist/nodes/slot.js +11 -10
  37. package/dist/nodes/stack-page-props.d.ts +1 -1
  38. package/dist/nodes/stack.d.ts +1 -1
  39. package/dist/nodes/stack.js +2 -2
  40. package/dist/nodes/string-list-container.d.ts +5 -12
  41. package/dist/nodes/string-list-container.js +34 -6
  42. package/dist/nodes/string-list-item.d.ts +10 -6
  43. package/dist/nodes/string-list-item.js +19 -17
  44. package/dist/nodes/toggle-button.d.ts +0 -3
  45. package/dist/nodes/toggle-button.js +0 -28
  46. package/dist/nodes/toolbar-view.d.ts +2 -3
  47. package/dist/nodes/toolbar-view.js +10 -9
  48. package/dist/nodes/view-stack.d.ts +1 -1
  49. package/dist/nodes/view-stack.js +2 -2
  50. package/dist/nodes/virtual-item.d.ts +9 -5
  51. package/dist/nodes/virtual-item.js +16 -20
  52. package/dist/nodes/virtual-slot.d.ts +4 -4
  53. package/dist/nodes/virtual-slot.js +12 -26
  54. package/dist/nodes/window.d.ts +2 -1
  55. package/dist/nodes/window.js +7 -3
  56. package/dist/predicates.d.ts +9 -18
  57. package/dist/predicates.js +31 -18
  58. package/dist/reconciler.d.ts +1 -1
  59. package/dist/reconciler.js +1 -1
  60. package/dist/types.d.ts +2 -0
  61. package/package.json +5 -5
  62. package/dist/container-interfaces.js +0 -26
@@ -1,27 +1,15 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
- import type { Node } from "./node.js";
3
- /**
4
- * Type for containers that manage child widgets with attach/detach semantics.
5
- * Used by ActionBar, FlowBox, ListBox, Overlay.
6
- */
7
2
  export type ChildContainer = {
8
3
  attachChild(child: Gtk.Widget): void;
9
4
  insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
10
5
  detachChild(child: Gtk.Widget): void;
11
6
  };
12
- /**
13
- * Type for page-based containers like Notebook.
14
- */
15
7
  export type PageContainer = {
16
8
  addPage(child: Gtk.Widget, label: string): void;
17
9
  insertPageBefore(child: Gtk.Widget, label: string, beforeChild: Gtk.Widget): void;
18
10
  removePage(child: Gtk.Widget): void;
19
11
  updatePageLabel(child: Gtk.Widget, label: string): void;
20
12
  };
21
- /**
22
- * Props for Stack pages.
23
- * Used by Gtk.Stack and Adw.ViewStack.
24
- */
25
13
  export type StackPageProps = {
26
14
  name?: string;
27
15
  title?: string;
@@ -31,55 +19,40 @@ export type StackPageProps = {
31
19
  useUnderline?: boolean;
32
20
  badgeNumber?: number;
33
21
  };
34
- /**
35
- * Type for Stack containers.
36
- */
37
22
  export type StackPageContainer = {
38
23
  addStackPage(child: Gtk.Widget, props: StackPageProps): void;
39
24
  insertStackPageBefore(child: Gtk.Widget, props: StackPageProps, beforeChild: Gtk.Widget): void;
40
25
  removeStackPage(child: Gtk.Widget): void;
41
26
  updateStackPageProps(child: Gtk.Widget, props: StackPageProps): void;
42
27
  };
43
- /**
44
- * Type for grid-based containers.
45
- */
46
28
  export type GridContainer = {
47
29
  attachToGrid(child: Gtk.Widget, column: number, row: number, colSpan: number, rowSpan: number): void;
48
30
  removeFromGrid(child: Gtk.Widget): void;
49
31
  };
50
- /**
51
- * Type for item-based containers like ListView, GridView, ColumnView.
52
- * Items are identified by string IDs for selection support.
53
- */
54
32
  export type ItemContainer<T> = {
55
33
  addItem(id: string, item: T): void;
56
34
  insertItemBefore(id: string, item: T, beforeId: string): void;
57
35
  removeItem(id: string): void;
58
36
  updateItem(id: string, item: T): void;
59
37
  };
60
- /**
61
- * Type for column-based containers like ColumnView.
62
- * Note: Column type is generic to support both raw Gtk.ColumnViewColumn and wrapper nodes.
63
- */
64
38
  export type ColumnContainer = {
65
39
  addColumn(column: unknown): void;
66
40
  insertColumnBefore(column: unknown, beforeColumn: unknown): void;
67
41
  removeColumn(column: unknown): void;
68
42
  getItems(): unknown[];
69
43
  };
70
- export declare const isChildContainer: (node: Node) => node is Node & ChildContainer;
71
- export declare const isPageContainer: (node: Node) => node is Node & PageContainer;
72
- export declare const isStackPageContainer: (node: Node) => node is Node & StackPageContainer;
73
- export declare const isGridContainer: (node: Node) => node is Node & GridContainer;
74
- export declare const isItemContainer: (node: Node) => node is Node & ItemContainer<unknown>;
75
- export declare const isColumnContainer: (node: Node) => node is Node & ColumnContainer;
76
- /**
77
- * Type for containers that support packStart/packEnd semantics.
78
- * Used by HeaderBar, ActionBar.
79
- */
80
44
  export type PackContainer = {
81
45
  packStart(child: Gtk.Widget): void;
82
46
  packEnd(child: Gtk.Widget): void;
83
47
  removeFromPack(child: Gtk.Widget): void;
84
48
  };
85
- export declare const isPackContainer: (node: Node) => node is Node & PackContainer;
49
+ export type StringListItem = {
50
+ id: string;
51
+ label: string;
52
+ };
53
+ export type StringListContainer = {
54
+ addStringListItem(id: string, label: string): void;
55
+ insertStringListItemBefore(id: string, label: string, beforeId: string): void;
56
+ removeStringListItem(id: string): void;
57
+ updateStringListItem(oldId: string, newId: string, newLabel: string): void;
58
+ };
@@ -0,0 +1 @@
1
+ export {};
package/dist/factory.d.ts CHANGED
@@ -10,4 +10,4 @@ export { ROOT_NODE_CONTAINER } from "./nodes/root.js";
10
10
  * Creates a Node instance for the given JSX element type.
11
11
  * Matches the type against registered node classes and initializes with props.
12
12
  */
13
- export declare const createNode: (type: string, props: Props, existingWidget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER) => Node;
13
+ export declare const createNode: (type: string, props: Props, widget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER) => Node;
package/dist/factory.js CHANGED
@@ -67,10 +67,10 @@ const NODE_CLASSES = [RootNode, ...VIRTUAL_NODES, ...SPECIALIZED_NODES, ...CONTA
67
67
  * Creates a Node instance for the given JSX element type.
68
68
  * Matches the type against registered node classes and initializes with props.
69
69
  */
70
- export const createNode = (type, props, existingWidget) => {
70
+ export const createNode = (type, props, widget) => {
71
71
  for (const NodeClass of NODE_CLASSES) {
72
- if (NodeClass.matches(type, existingWidget)) {
73
- const node = new NodeClass(type, existingWidget);
72
+ if (NodeClass.matches(type, widget)) {
73
+ const node = new NodeClass(type, widget);
74
74
  node.initialize(props);
75
75
  return node;
76
76
  }
@@ -1,7 +1,7 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type ReactReconciler from "react-reconciler";
3
- import { type Props, type ROOT_NODE_CONTAINER } from "../factory.js";
4
- import type { Node } from "../node.js";
3
+ import { type Props, type ROOT_NODE_CONTAINER } from "./factory.js";
4
+ import type { Node } from "./node.js";
5
5
  type Container = Gtk.Widget | typeof ROOT_NODE_CONTAINER;
6
6
  type TextInstance = Node;
7
7
  type SuspenseInstance = never;
@@ -1,7 +1,7 @@
1
1
  import { beginBatch, endBatch } from "@gtkx/ffi";
2
2
  import React from "react";
3
- import { beginCommit, endCommit } from "../batch.js";
4
- import { createNode } from "../factory.js";
3
+ import { beginCommit, endCommit } from "./batch.js";
4
+ import { createNode } from "./factory.js";
5
5
  export function createHostConfig(createNodeFromContainer) {
6
6
  return {
7
7
  supportsMutation: true,
package/dist/node.d.ts CHANGED
@@ -2,18 +2,19 @@ import * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { Props, ROOT_NODE_CONTAINER } from "./factory.js";
3
3
  export declare const normalizeWidgetType: (type: string) => string;
4
4
  export declare abstract class Node<T extends Gtk.Widget | undefined = Gtk.Widget | undefined, S extends object | undefined = object | undefined> {
5
- static matches(_type: string, _existingWidget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER): boolean;
5
+ static matches(_type: string, _widget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER): boolean;
6
6
  static consumedPropNames: string[];
7
7
  protected signalHandlers: Map<string, number>;
8
8
  protected widget: T;
9
9
  protected widgetType: string;
10
10
  protected nodeType: string;
11
- protected parent: Node | null;
11
+ parent: Node | null;
12
12
  private _state;
13
13
  protected get state(): S;
14
14
  protected set state(value: S);
15
15
  protected isVirtual(): boolean;
16
- constructor(type: string, existingWidget?: Gtk.Widget);
16
+ protected isStandalone(): boolean;
17
+ constructor(type: string, widget?: Gtk.Widget);
17
18
  /**
18
19
  * Initializes the node with props. Called by the reconciler after construction.
19
20
  * Subclasses can override to perform custom initialization.
@@ -24,11 +25,9 @@ export declare abstract class Node<T extends Gtk.Widget | undefined = Gtk.Widget
24
25
  appendChild(child: Node): void;
25
26
  removeChild(child: Node): void;
26
27
  insertBefore(child: Node, before: Node): void;
27
- attachToParent(parent: Node): void;
28
- detachFromParent(parent: Node): void;
28
+ unmount(): void;
29
29
  protected disconnectAllSignals(): void;
30
30
  hasParent(): boolean;
31
- attachToParentBefore(parent: Node, before: Node): void;
32
31
  protected consumedProps(): Set<string>;
33
32
  updateProps(oldProps: Props, newProps: Props): void;
34
33
  protected propKeyToEventName(key: string): string;
package/dist/node.js CHANGED
@@ -4,9 +4,8 @@ import * as Gtk from "@gtkx/ffi/gtk";
4
4
  import * as GtkSource from "@gtkx/ffi/gtksource";
5
5
  import * as Vte from "@gtkx/ffi/vte";
6
6
  import * as WebKit from "@gtkx/ffi/webkit";
7
- import { isChildContainer } from "./container-interfaces.js";
8
7
  import { CONSTRUCTOR_PARAMS, PROP_SETTERS, SETTER_GETTERS } from "./generated/internal.js";
9
- import { isAddable, isAppendable, isRemovable, isSingleChild } from "./predicates.js";
8
+ import { isAddable, isAppendable, isChildContainer, isRemovable, isSingleChild } from "./predicates.js";
10
9
  export const normalizeWidgetType = (type) => type.split(".")[0] || type;
11
10
  const NAMESPACE_REGISTRY = [
12
11
  ["GtkSource", GtkSource],
@@ -31,7 +30,7 @@ const extractConstructorArgs = (type, props) => {
31
30
  return params.map((p) => props[p.name]);
32
31
  };
33
32
  export class Node {
34
- static matches(_type, _existingWidget) {
33
+ static matches(_type, _widget) {
35
34
  return false;
36
35
  }
37
36
  static consumedPropNames = [];
@@ -53,11 +52,14 @@ export class Node {
53
52
  isVirtual() {
54
53
  return false;
55
54
  }
56
- constructor(type, existingWidget) {
55
+ isStandalone() {
56
+ return false;
57
+ }
58
+ constructor(type, widget) {
57
59
  this.nodeType = type;
58
60
  this.widgetType = normalizeWidgetType(type);
59
- if (existingWidget) {
60
- this.widget = existingWidget;
61
+ if (widget) {
62
+ this.widget = widget;
61
63
  }
62
64
  }
63
65
  /**
@@ -82,55 +84,62 @@ export class Node {
82
84
  return this.widget;
83
85
  }
84
86
  appendChild(child) {
85
- child.attachToParent(this);
86
- }
87
- removeChild(child) {
88
- child.detachFromParent(this);
89
- }
90
- insertBefore(child, before) {
91
- child.attachToParentBefore(this, before);
92
- }
93
- attachToParent(parent) {
94
- this.parent = parent;
95
- if (isChildContainer(parent)) {
96
- const widget = this.getWidget();
97
- if (widget)
98
- parent.attachChild(widget);
87
+ child.parent = this;
88
+ const childWidget = child.getWidget();
89
+ if (!childWidget || child.isStandalone())
99
90
  return;
91
+ if (isChildContainer(this)) {
92
+ this.attachChild(childWidget);
100
93
  }
101
- const parentWidget = parent.getWidget();
102
- const widget = this.getWidget();
103
- if (!parentWidget || !widget)
104
- return;
105
- if (isAppendable(parentWidget)) {
106
- widget.insertBefore(parentWidget, null);
94
+ else if (this.widget && isAppendable(this.widget)) {
95
+ childWidget.insertBefore(this.widget);
107
96
  }
108
- else if (isAddable(parentWidget)) {
109
- parentWidget.add(widget);
97
+ else if (this.widget && isAddable(this.widget)) {
98
+ this.widget.add(childWidget);
110
99
  }
111
- else if (isSingleChild(parentWidget)) {
112
- parentWidget.setChild(widget);
100
+ else if (this.widget && isSingleChild(this.widget)) {
101
+ this.widget.setChild(childWidget);
113
102
  }
114
103
  }
115
- detachFromParent(parent) {
116
- this.parent = null;
117
- this.disconnectAllSignals();
118
- if (isChildContainer(parent)) {
119
- const widget = this.getWidget();
120
- if (widget)
121
- parent.detachChild(widget);
122
- return;
104
+ removeChild(child) {
105
+ child.unmount();
106
+ const childWidget = child.getWidget();
107
+ if (childWidget) {
108
+ if (isChildContainer(this)) {
109
+ this.detachChild(childWidget);
110
+ }
111
+ else if (this.widget && isRemovable(this.widget)) {
112
+ this.widget.remove(childWidget);
113
+ }
114
+ else if (this.widget && isSingleChild(this.widget)) {
115
+ this.widget.setChild(null);
116
+ }
123
117
  }
124
- const parentWidget = parent.getWidget();
125
- const widget = this.getWidget();
126
- if (!parentWidget || !widget)
118
+ child.parent = null;
119
+ }
120
+ insertBefore(child, before) {
121
+ child.parent = this;
122
+ const childWidget = child.getWidget();
123
+ const beforeWidget = before.getWidget();
124
+ if (!childWidget || child.isStandalone())
127
125
  return;
128
- if (isRemovable(parentWidget)) {
129
- parentWidget.remove(widget);
126
+ if (isChildContainer(this)) {
127
+ if (beforeWidget) {
128
+ this.insertChildBefore(childWidget, beforeWidget);
129
+ }
130
+ else {
131
+ this.attachChild(childWidget);
132
+ }
130
133
  }
131
- else if (isSingleChild(parentWidget)) {
132
- parentWidget.setChild(null);
134
+ else if (this.widget && isAppendable(this.widget) && beforeWidget) {
135
+ childWidget.insertBefore(this.widget, beforeWidget);
133
136
  }
137
+ else {
138
+ this.appendChild(child);
139
+ }
140
+ }
141
+ unmount() {
142
+ this.disconnectAllSignals();
134
143
  }
135
144
  disconnectAllSignals() {
136
145
  const widget = this.getWidget();
@@ -144,33 +153,6 @@ export class Node {
144
153
  hasParent() {
145
154
  return this.parent !== null;
146
155
  }
147
- attachToParentBefore(parent, before) {
148
- this.parent = parent;
149
- if (isChildContainer(parent)) {
150
- const widget = this.getWidget();
151
- const beforeWidget = before.getWidget();
152
- if (widget) {
153
- if (beforeWidget) {
154
- parent.insertChildBefore(widget, beforeWidget);
155
- }
156
- else {
157
- parent.attachChild(widget);
158
- }
159
- }
160
- return;
161
- }
162
- const parentWidget = parent.getWidget();
163
- const widget = this.getWidget();
164
- const beforeWidget = before.getWidget();
165
- if (!parentWidget || !widget)
166
- return;
167
- if (isAppendable(parentWidget) && beforeWidget) {
168
- widget.insertBefore(parentWidget, beforeWidget);
169
- }
170
- else {
171
- this.attachToParent(parent);
172
- }
173
- }
174
156
  consumedProps() {
175
157
  const consumed = new Set(["children"]);
176
158
  let proto = Object.getPrototypeOf(this);
@@ -2,8 +2,7 @@ import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import { Node } from "../node.js";
3
3
  export declare class AboutDialogNode extends Node<Gtk.AboutDialog> {
4
4
  static matches(type: string): boolean;
5
- attachToParent(_parent: Node): void;
6
- attachToParentBefore(_parent: Node, _before: Node): void;
7
- detachFromParent(_parent: Node): void;
5
+ protected isStandalone(): boolean;
8
6
  mount(): void;
7
+ unmount(): void;
9
8
  }
@@ -3,12 +3,14 @@ export class AboutDialogNode extends Node {
3
3
  static matches(type) {
4
4
  return type === "AboutDialog";
5
5
  }
6
- attachToParent(_parent) { }
7
- attachToParentBefore(_parent, _before) { }
8
- detachFromParent(_parent) {
9
- this.widget.destroy();
6
+ isStandalone() {
7
+ return true;
10
8
  }
11
9
  mount() {
12
10
  this.widget.present();
13
11
  }
12
+ unmount() {
13
+ this.widget.destroy();
14
+ super.unmount();
15
+ }
14
16
  }
@@ -1,5 +1,6 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import { type ColumnContainer } from "../container-interfaces.js";
2
+ import { StringSorter } from "@gtkx/ffi/gtk";
3
+ import type { ColumnContainer } from "../containers.js";
3
4
  import type { Props } from "../factory.js";
4
5
  import { Node } from "../node.js";
5
6
  import type { RenderItemFn } from "../types.js";
@@ -22,7 +23,10 @@ export declare class ColumnViewNode extends SelectableListNode<Gtk.ColumnView, C
22
23
  private connectSorterChangedSignal;
23
24
  private disconnectSorterChangedSignal;
24
25
  private notifySortChange;
25
- detachFromParent(parent: Node): void;
26
+ unmount(): void;
27
+ appendChild(child: Node): void;
28
+ insertBefore(child: Node, before: Node): void;
29
+ removeChild(child: Node): void;
26
30
  updateProps(oldProps: Props, newProps: Props): void;
27
31
  private applySortIndicator;
28
32
  addColumn(columnNode: ColumnViewColumnNode): void;
@@ -34,9 +38,9 @@ type ColumnViewColumnState = {
34
38
  factory: Gtk.SignalListItemFactory;
35
39
  factoryHandlers: ListItemFactoryHandlers | null;
36
40
  renderCell: RenderItemFn<unknown>;
37
- columnId: string | null;
38
- sorter: Gtk.CustomSorter | null;
41
+ columnId?: string;
39
42
  listItemCache: Map<number, ListItemInfo>;
43
+ sorter?: StringSorter;
40
44
  };
41
45
  export declare class ColumnViewColumnNode extends Node<never, ColumnViewColumnState> {
42
46
  static consumedPropNames: string[];
@@ -45,12 +49,9 @@ export declare class ColumnViewColumnNode extends Node<never, ColumnViewColumnSt
45
49
  private columnView;
46
50
  initialize(props: Props): void;
47
51
  getColumn(): Gtk.ColumnViewColumn;
48
- getId(): string | null;
52
+ getId(): string | undefined;
49
53
  setColumnView(columnView: ColumnViewNode | null): void;
50
- updateSorter(): void;
51
- attachToParent(parent: Node): void;
52
- attachToParentBefore(parent: Node, before: Node): void;
53
- detachFromParent(parent: Node): void;
54
+ unmount(): void;
54
55
  updateProps(oldProps: Props, newProps: Props): void;
55
56
  }
56
57
  export declare class ColumnViewItemNode extends VirtualItemNode {
@@ -1,7 +1,6 @@
1
- import { getObject } from "@gtkx/ffi";
2
1
  import * as GObject from "@gtkx/ffi/gobject";
3
2
  import * as Gtk from "@gtkx/ffi/gtk";
4
- import { isColumnContainer } from "../container-interfaces.js";
3
+ import { StringSorter } from "@gtkx/ffi/gtk";
5
4
  import { Node } from "../node.js";
6
5
  import { connectListItemFactorySignals } from "./list-item-factory.js";
7
6
  import { SelectableListNode } from "./selectable-list.js";
@@ -54,10 +53,9 @@ export class ColumnViewNode extends SelectableListNode {
54
53
  notifySortChange() {
55
54
  if (!this.state.onSortChange)
56
55
  return;
57
- const baseSorter = this.widget.getSorter();
58
- if (!baseSorter)
56
+ const sorter = this.widget.getSorter();
57
+ if (!sorter)
59
58
  return;
60
- const sorter = getObject(baseSorter.id);
61
59
  const column = sorter.getPrimarySortColumn();
62
60
  const order = sorter.getPrimarySortOrder();
63
61
  const columnId = column?.getId() ?? null;
@@ -68,10 +66,35 @@ export class ColumnViewNode extends SelectableListNode {
68
66
  this.state.lastNotifiedOrder = order;
69
67
  this.state.onSortChange(columnId, order);
70
68
  }
71
- detachFromParent(parent) {
69
+ unmount() {
72
70
  this.disconnectSorterChangedSignal();
73
71
  this.cleanupSelection();
74
- super.detachFromParent(parent);
72
+ super.unmount();
73
+ }
74
+ appendChild(child) {
75
+ if (child instanceof ColumnViewColumnNode) {
76
+ child.parent = this;
77
+ this.addColumn(child);
78
+ return;
79
+ }
80
+ super.appendChild(child);
81
+ }
82
+ insertBefore(child, before) {
83
+ if (child instanceof ColumnViewColumnNode && before instanceof ColumnViewColumnNode) {
84
+ child.parent = this;
85
+ this.insertColumnBefore(child, before);
86
+ return;
87
+ }
88
+ super.insertBefore(child, before);
89
+ }
90
+ removeChild(child) {
91
+ if (child instanceof ColumnViewColumnNode) {
92
+ this.removeColumn(child);
93
+ child.unmount();
94
+ child.parent = null;
95
+ return;
96
+ }
97
+ super.removeChild(child);
75
98
  }
76
99
  updateProps(oldProps, newProps) {
77
100
  super.updateProps(oldProps, newProps);
@@ -98,7 +121,7 @@ export class ColumnViewNode extends SelectableListNode {
98
121
  }
99
122
  applySortIndicator() {
100
123
  if (this.state.sortColumn === null) {
101
- this.widget.sortByColumn(this.state.sortOrder, null);
124
+ this.widget.sortByColumn(this.state.sortOrder);
102
125
  return;
103
126
  }
104
127
  const column = this.state.columns.find((c) => c.getId() === this.state.sortColumn);
@@ -134,7 +157,7 @@ export class ColumnViewNode extends SelectableListNode {
134
157
  }
135
158
  }
136
159
  export class ColumnViewColumnNode extends Node {
137
- static consumedPropNames = ["renderCell", "title", "expand", "resizable", "fixedWidth", "id"];
160
+ static consumedPropNames = ["renderCell", "title", "expand", "resizable", "fixedWidth", "id", "sortable"];
138
161
  static matches(type) {
139
162
  return type === "ColumnView.Column";
140
163
  }
@@ -145,16 +168,21 @@ export class ColumnViewColumnNode extends Node {
145
168
  initialize(props) {
146
169
  const factory = new Gtk.SignalListItemFactory();
147
170
  const column = new Gtk.ColumnViewColumn(props.title, factory);
148
- const columnId = props.id ?? null;
171
+ const columnId = props.id ?? undefined;
172
+ const sortable = props.sortable;
173
+ const sorter = sortable ? new StringSorter() : undefined;
149
174
  this.state = {
150
175
  column,
151
176
  factory,
152
177
  factoryHandlers: null,
153
178
  renderCell: props.renderCell,
154
179
  columnId,
155
- sorter: null,
156
180
  listItemCache: new Map(),
181
+ sorter,
157
182
  };
183
+ if (sorter) {
184
+ column.setSorter(sorter);
185
+ }
158
186
  super.initialize(props);
159
187
  if (columnId !== null) {
160
188
  column.setId(columnId);
@@ -183,36 +211,10 @@ export class ColumnViewColumnNode extends Node {
183
211
  }
184
212
  setColumnView(columnView) {
185
213
  this.columnView = columnView;
186
- this.updateSorter();
187
214
  }
188
- updateSorter() {
189
- if (!this.columnView || this.state.columnId === null) {
190
- this.state.column.setSorter(null);
191
- this.state.sorter = null;
192
- return;
193
- }
194
- const noOpSortFn = () => 0;
195
- this.state.sorter = new Gtk.CustomSorter(noOpSortFn);
196
- this.state.column.setSorter(this.state.sorter);
197
- }
198
- attachToParent(parent) {
199
- if (isColumnContainer(parent)) {
200
- parent.addColumn(this);
201
- }
202
- }
203
- attachToParentBefore(parent, before) {
204
- if (isColumnContainer(parent) && before instanceof ColumnViewColumnNode) {
205
- parent.insertColumnBefore(this, before);
206
- }
207
- else {
208
- this.attachToParent(parent);
209
- }
210
- }
211
- detachFromParent(parent) {
215
+ unmount() {
212
216
  this.state.factoryHandlers?.disconnect();
213
- if (isColumnContainer(parent)) {
214
- parent.removeColumn(this);
215
- }
217
+ super.unmount();
216
218
  }
217
219
  updateProps(oldProps, newProps) {
218
220
  if (oldProps.renderCell !== newProps.renderCell) {
@@ -231,9 +233,20 @@ export class ColumnViewColumnNode extends Node {
231
233
  this.state.column.setFixedWidth(newProps.fixedWidth);
232
234
  }
233
235
  if (oldProps.id !== newProps.id) {
234
- this.state.columnId = newProps.id ?? null;
236
+ this.state.columnId = newProps.id ?? undefined;
235
237
  this.state.column.setId(this.state.columnId);
236
238
  }
239
+ if (oldProps.sortable !== newProps.sortable) {
240
+ const sortable = newProps.sortable;
241
+ if (sortable && !this.state.sorter) {
242
+ this.state.sorter = new StringSorter();
243
+ this.state.column.setSorter(this.state.sorter);
244
+ }
245
+ else if (!sortable && this.state.sorter) {
246
+ this.state.column.setSorter(undefined);
247
+ this.state.sorter = undefined;
248
+ }
249
+ }
237
250
  }
238
251
  }
239
252
  export class ColumnViewItemNode extends VirtualItemNode {
@@ -16,7 +16,7 @@ export class FlowBoxNode extends IndexedChildContainerNode {
16
16
  const parent = child.getParent();
17
17
  if (parent && isFlowBoxChild(parent)) {
18
18
  beginBatch();
19
- parent.setChild(null);
19
+ parent.setChild(undefined);
20
20
  this.widget.remove(parent);
21
21
  endBatch();
22
22
  }
@@ -1,5 +1,5 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
- import { type GridContainer } from "../container-interfaces.js";
2
+ import type { GridContainer } from "../containers.js";
3
3
  import type { Props } from "../factory.js";
4
4
  import { Node } from "../node.js";
5
5
  import { VirtualSlotNode } from "./virtual-slot.js";
@@ -7,6 +7,9 @@ export declare class GridNode extends Node<Gtk.Grid> implements GridContainer {
7
7
  static matches(type: string): boolean;
8
8
  attachToGrid(child: Gtk.Widget, column: number, row: number, colSpan: number, rowSpan: number): void;
9
9
  removeFromGrid(child: Gtk.Widget): void;
10
+ appendChild(child: Node): void;
11
+ insertBefore(child: Node, before: Node): void;
12
+ removeChild(child: Node): void;
10
13
  }
11
14
  type GridChildProps = {
12
15
  column: number;
@@ -1,5 +1,5 @@
1
- import { isGridContainer } from "../container-interfaces.js";
2
1
  import { Node } from "../node.js";
2
+ import { isGridContainer } from "../predicates.js";
3
3
  import { VirtualSlotNode } from "./virtual-slot.js";
4
4
  export class GridNode extends Node {
5
5
  static matches(type) {
@@ -11,6 +11,44 @@ export class GridNode extends Node {
11
11
  removeFromGrid(child) {
12
12
  this.widget.remove(child);
13
13
  }
14
+ appendChild(child) {
15
+ if (child instanceof GridChildNode) {
16
+ child.parent = this;
17
+ const childWidget = child.getChildWidget();
18
+ const props = child.getSlotProps();
19
+ if (childWidget) {
20
+ this.attachToGrid(childWidget, props.column, props.row, props.columnSpan, props.rowSpan);
21
+ child.setParentContainer(this);
22
+ }
23
+ return;
24
+ }
25
+ super.appendChild(child);
26
+ }
27
+ insertBefore(child, before) {
28
+ if (child instanceof GridChildNode) {
29
+ child.parent = this;
30
+ const childWidget = child.getChildWidget();
31
+ const props = child.getSlotProps();
32
+ if (childWidget) {
33
+ this.attachToGrid(childWidget, props.column, props.row, props.columnSpan, props.rowSpan);
34
+ child.setParentContainer(this);
35
+ }
36
+ return;
37
+ }
38
+ super.insertBefore(child, before);
39
+ }
40
+ removeChild(child) {
41
+ if (child instanceof GridChildNode) {
42
+ const childWidget = child.getChildWidget();
43
+ if (childWidget) {
44
+ this.removeFromGrid(childWidget);
45
+ }
46
+ child.unmount();
47
+ child.parent = null;
48
+ return;
49
+ }
50
+ super.removeChild(child);
51
+ }
14
52
  }
15
53
  export class GridChildNode extends VirtualSlotNode {
16
54
  static matches(type) {