@gtkx/react 0.18.9 → 0.20.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 (212) hide show
  1. package/dist/components/list.d.ts +35 -0
  2. package/dist/components/list.d.ts.map +1 -0
  3. package/dist/components/list.js +40 -0
  4. package/dist/components/list.js.map +1 -0
  5. package/dist/generated/internal.d.ts +8 -3
  6. package/dist/generated/internal.d.ts.map +1 -1
  7. package/dist/generated/internal.js +3553 -53
  8. package/dist/generated/internal.js.map +1 -1
  9. package/dist/generated/jsx.d.ts +178 -326
  10. package/dist/generated/jsx.d.ts.map +1 -1
  11. package/dist/generated/jsx.js +0 -324
  12. package/dist/generated/jsx.js.map +1 -1
  13. package/dist/host-config.d.ts.map +1 -1
  14. package/dist/host-config.js +48 -10
  15. package/dist/host-config.js.map +1 -1
  16. package/dist/jsx.d.ts +111 -54
  17. package/dist/jsx.d.ts.map +1 -1
  18. package/dist/jsx.js +3 -28
  19. package/dist/jsx.js.map +1 -1
  20. package/dist/metadata.d.ts +1 -0
  21. package/dist/metadata.d.ts.map +1 -1
  22. package/dist/metadata.js +7 -1
  23. package/dist/metadata.js.map +1 -1
  24. package/dist/node.d.ts +0 -2
  25. package/dist/node.d.ts.map +1 -1
  26. package/dist/node.js +19 -25
  27. package/dist/node.js.map +1 -1
  28. package/dist/nodes/application.d.ts.map +1 -1
  29. package/dist/nodes/application.js +4 -0
  30. package/dist/nodes/application.js.map +1 -1
  31. package/dist/nodes/column-view-column.d.ts +19 -16
  32. package/dist/nodes/column-view-column.d.ts.map +1 -1
  33. package/dist/nodes/column-view-column.js +129 -97
  34. package/dist/nodes/column-view-column.js.map +1 -1
  35. package/dist/nodes/event-controller.d.ts +1 -0
  36. package/dist/nodes/event-controller.d.ts.map +1 -1
  37. package/dist/nodes/event-controller.js +9 -7
  38. package/dist/nodes/event-controller.js.map +1 -1
  39. package/dist/nodes/fixed-child.d.ts +1 -2
  40. package/dist/nodes/fixed-child.d.ts.map +1 -1
  41. package/dist/nodes/fixed-child.js +21 -21
  42. package/dist/nodes/fixed-child.js.map +1 -1
  43. package/dist/nodes/font-dialog-button.d.ts +1 -1
  44. package/dist/nodes/font-dialog-button.d.ts.map +1 -1
  45. package/dist/nodes/font-dialog-button.js +8 -0
  46. package/dist/nodes/font-dialog-button.js.map +1 -1
  47. package/dist/nodes/internal/accessible.d.ts +5 -0
  48. package/dist/nodes/internal/accessible.d.ts.map +1 -0
  49. package/dist/nodes/internal/accessible.js +119 -0
  50. package/dist/nodes/internal/accessible.js.map +1 -0
  51. package/dist/nodes/internal/bound-item.d.ts +4 -0
  52. package/dist/nodes/internal/bound-item.d.ts.map +1 -0
  53. package/dist/nodes/internal/bound-item.js +2 -0
  54. package/dist/nodes/internal/bound-item.js.map +1 -0
  55. package/dist/nodes/internal/construct.d.ts +3 -0
  56. package/dist/nodes/internal/construct.d.ts.map +1 -0
  57. package/dist/nodes/internal/construct.js +44 -0
  58. package/dist/nodes/internal/construct.js.map +1 -0
  59. package/dist/nodes/internal/text-buffer-controller.d.ts +4 -0
  60. package/dist/nodes/internal/text-buffer-controller.d.ts.map +1 -1
  61. package/dist/nodes/internal/text-buffer-controller.js +49 -9
  62. package/dist/nodes/internal/text-buffer-controller.js.map +1 -1
  63. package/dist/nodes/internal/widget.d.ts.map +1 -1
  64. package/dist/nodes/internal/widget.js +4 -1
  65. package/dist/nodes/internal/widget.js.map +1 -1
  66. package/dist/nodes/list-item-node.d.ts +12 -0
  67. package/dist/nodes/list-item-node.d.ts.map +1 -0
  68. package/dist/nodes/list-item-node.js +23 -0
  69. package/dist/nodes/list-item-node.js.map +1 -0
  70. package/dist/nodes/list.d.ts +100 -0
  71. package/dist/nodes/list.d.ts.map +1 -0
  72. package/dist/nodes/list.js +950 -0
  73. package/dist/nodes/list.js.map +1 -0
  74. package/dist/nodes/notebook-page.d.ts.map +1 -1
  75. package/dist/nodes/notebook-page.js +4 -0
  76. package/dist/nodes/notebook-page.js.map +1 -1
  77. package/dist/nodes/shortcut.d.ts +3 -2
  78. package/dist/nodes/shortcut.d.ts.map +1 -1
  79. package/dist/nodes/shortcut.js +19 -4
  80. package/dist/nodes/shortcut.js.map +1 -1
  81. package/dist/nodes/text-anchor.d.ts.map +1 -1
  82. package/dist/nodes/text-anchor.js +7 -1
  83. package/dist/nodes/text-anchor.js.map +1 -1
  84. package/dist/nodes/text-tag.d.ts.map +1 -1
  85. package/dist/nodes/text-tag.js +5 -1
  86. package/dist/nodes/text-tag.js.map +1 -1
  87. package/dist/nodes/text-view.d.ts +1 -0
  88. package/dist/nodes/text-view.d.ts.map +1 -1
  89. package/dist/nodes/text-view.js +4 -0
  90. package/dist/nodes/text-view.js.map +1 -1
  91. package/dist/nodes/widget.d.ts +0 -2
  92. package/dist/nodes/widget.d.ts.map +1 -1
  93. package/dist/nodes/widget.js +51 -67
  94. package/dist/nodes/widget.js.map +1 -1
  95. package/dist/nodes/window.d.ts.map +1 -1
  96. package/dist/nodes/window.js +2 -2
  97. package/dist/nodes/window.js.map +1 -1
  98. package/dist/registry.d.ts +0 -2
  99. package/dist/registry.d.ts.map +1 -1
  100. package/dist/registry.js +4 -13
  101. package/dist/registry.js.map +1 -1
  102. package/dist/types.d.ts +2 -2
  103. package/dist/types.d.ts.map +1 -1
  104. package/package.json +5 -4
  105. package/src/components/list.tsx +83 -0
  106. package/src/generated/internal.ts +3559 -49
  107. package/src/generated/jsx.ts +178 -326
  108. package/src/host-config.ts +43 -10
  109. package/src/jsx.ts +121 -62
  110. package/src/metadata.ts +8 -1
  111. package/src/node.ts +23 -25
  112. package/src/nodes/application.ts +5 -0
  113. package/src/nodes/column-view-column.ts +125 -104
  114. package/src/nodes/event-controller.ts +8 -8
  115. package/src/nodes/fixed-child.ts +24 -23
  116. package/src/nodes/font-dialog-button.ts +10 -0
  117. package/src/nodes/internal/accessible.ts +155 -0
  118. package/src/nodes/internal/bound-item.ts +4 -0
  119. package/src/nodes/internal/construct.ts +60 -0
  120. package/src/nodes/internal/text-buffer-controller.ts +51 -8
  121. package/src/nodes/internal/widget.ts +3 -1
  122. package/src/nodes/list-item-node.ts +29 -0
  123. package/src/nodes/list.ts +1082 -0
  124. package/src/nodes/notebook-page.ts +4 -0
  125. package/src/nodes/shortcut.ts +22 -5
  126. package/src/nodes/text-anchor.ts +6 -1
  127. package/src/nodes/text-tag.ts +7 -1
  128. package/src/nodes/text-view.ts +5 -0
  129. package/src/nodes/widget.ts +47 -69
  130. package/src/nodes/window.ts +2 -2
  131. package/src/registry.ts +11 -17
  132. package/src/types.ts +7 -2
  133. package/dist/fiber-root.d.ts +0 -4
  134. package/dist/fiber-root.d.ts.map +0 -1
  135. package/dist/fiber-root.js +0 -6
  136. package/dist/fiber-root.js.map +0 -1
  137. package/dist/nodes/column-view.d.ts +0 -36
  138. package/dist/nodes/column-view.d.ts.map +0 -1
  139. package/dist/nodes/column-view.js +0 -175
  140. package/dist/nodes/column-view.js.map +0 -1
  141. package/dist/nodes/drop-down.d.ts +0 -27
  142. package/dist/nodes/drop-down.d.ts.map +0 -1
  143. package/dist/nodes/drop-down.js +0 -85
  144. package/dist/nodes/drop-down.js.map +0 -1
  145. package/dist/nodes/grid-view.d.ts +0 -29
  146. package/dist/nodes/grid-view.d.ts.map +0 -1
  147. package/dist/nodes/grid-view.js +0 -85
  148. package/dist/nodes/grid-view.js.map +0 -1
  149. package/dist/nodes/internal/base-item-renderer.d.ts +0 -28
  150. package/dist/nodes/internal/base-item-renderer.d.ts.map +0 -1
  151. package/dist/nodes/internal/base-item-renderer.js +0 -86
  152. package/dist/nodes/internal/base-item-renderer.js.map +0 -1
  153. package/dist/nodes/internal/grid-item-renderer.d.ts +0 -20
  154. package/dist/nodes/internal/grid-item-renderer.d.ts.map +0 -1
  155. package/dist/nodes/internal/grid-item-renderer.js +0 -66
  156. package/dist/nodes/internal/grid-item-renderer.js.map +0 -1
  157. package/dist/nodes/internal/list-item-renderer.d.ts +0 -27
  158. package/dist/nodes/internal/list-item-renderer.d.ts.map +0 -1
  159. package/dist/nodes/internal/list-item-renderer.js +0 -131
  160. package/dist/nodes/internal/list-item-renderer.js.map +0 -1
  161. package/dist/nodes/internal/list-store.d.ts +0 -22
  162. package/dist/nodes/internal/list-store.d.ts.map +0 -1
  163. package/dist/nodes/internal/list-store.js +0 -91
  164. package/dist/nodes/internal/list-store.js.map +0 -1
  165. package/dist/nodes/internal/selection-model-controller.d.ts +0 -26
  166. package/dist/nodes/internal/selection-model-controller.d.ts.map +0 -1
  167. package/dist/nodes/internal/selection-model-controller.js +0 -79
  168. package/dist/nodes/internal/selection-model-controller.js.map +0 -1
  169. package/dist/nodes/internal/simple-list-store.d.ts +0 -20
  170. package/dist/nodes/internal/simple-list-store.d.ts.map +0 -1
  171. package/dist/nodes/internal/simple-list-store.js +0 -87
  172. package/dist/nodes/internal/simple-list-store.js.map +0 -1
  173. package/dist/nodes/internal/tree-store.d.ts +0 -34
  174. package/dist/nodes/internal/tree-store.d.ts.map +0 -1
  175. package/dist/nodes/internal/tree-store.js +0 -208
  176. package/dist/nodes/internal/tree-store.js.map +0 -1
  177. package/dist/nodes/list-item.d.ts +0 -24
  178. package/dist/nodes/list-item.d.ts.map +0 -1
  179. package/dist/nodes/list-item.js +0 -83
  180. package/dist/nodes/list-item.js.map +0 -1
  181. package/dist/nodes/list-view.d.ts +0 -29
  182. package/dist/nodes/list-view.d.ts.map +0 -1
  183. package/dist/nodes/list-view.js +0 -83
  184. package/dist/nodes/list-view.js.map +0 -1
  185. package/dist/nodes/models/grid.d.ts +0 -28
  186. package/dist/nodes/models/grid.d.ts.map +0 -1
  187. package/dist/nodes/models/grid.js +0 -69
  188. package/dist/nodes/models/grid.js.map +0 -1
  189. package/dist/nodes/models/list.d.ts +0 -31
  190. package/dist/nodes/models/list.d.ts.map +0 -1
  191. package/dist/nodes/models/list.js +0 -93
  192. package/dist/nodes/models/list.js.map +0 -1
  193. package/dist/nodes/shortcut-controller.d.ts +0 -10
  194. package/dist/nodes/shortcut-controller.d.ts.map +0 -1
  195. package/dist/nodes/shortcut-controller.js +0 -23
  196. package/dist/nodes/shortcut-controller.js.map +0 -1
  197. package/src/fiber-root.ts +0 -20
  198. package/src/nodes/column-view.ts +0 -217
  199. package/src/nodes/drop-down.ts +0 -108
  200. package/src/nodes/grid-view.ts +0 -109
  201. package/src/nodes/internal/base-item-renderer.ts +0 -108
  202. package/src/nodes/internal/grid-item-renderer.ts +0 -78
  203. package/src/nodes/internal/list-item-renderer.ts +0 -162
  204. package/src/nodes/internal/list-store.ts +0 -105
  205. package/src/nodes/internal/selection-model-controller.ts +0 -115
  206. package/src/nodes/internal/simple-list-store.ts +0 -99
  207. package/src/nodes/internal/tree-store.ts +0 -237
  208. package/src/nodes/list-item.ts +0 -107
  209. package/src/nodes/list-view.ts +0 -113
  210. package/src/nodes/models/grid.ts +0 -105
  211. package/src/nodes/models/list.ts +0 -140
  212. package/src/nodes/shortcut-controller.ts +0 -27
@@ -1,17 +1,34 @@
1
+ import { getNativeId } from "@gtkx/ffi";
1
2
  import * as Gio from "@gtkx/ffi/gio";
3
+ import type * as GObject from "@gtkx/ffi/gobject";
2
4
  import * as Gtk from "@gtkx/ffi/gtk";
3
- import type { ColumnViewColumnProps } from "../jsx.js";
5
+ import type { ColumnViewColumnProps, ListItem } from "../jsx.js";
4
6
  import type { Node } from "../node.js";
5
7
  import type { Container } from "../types.js";
6
- import { ListItemRenderer } from "./internal/list-item-renderer.js";
8
+ import type { BoundItem } from "./internal/bound-item.js";
7
9
  import { hasChanged } from "./internal/props.js";
8
- import type { TreeStore } from "./internal/tree-store.js";
9
10
  import { MenuNode } from "./menu.js";
10
11
  import { MenuModel } from "./models/menu.js";
11
12
  import { VirtualNode } from "./virtual.js";
12
13
  import { WidgetNode } from "./widget.js";
13
14
 
14
- export class ColumnViewColumnNode extends VirtualNode<ColumnViewColumnProps, WidgetNode<Gtk.ColumnView>, MenuNode> {
15
+ const UNBOUND_POSITION = -1;
16
+
17
+ export class ColumnViewColumnNode extends VirtualNode<ColumnViewColumnProps, WidgetNode, MenuNode> {
18
+ private column: Gtk.ColumnViewColumn | null = null;
19
+ private columnFactory: Gtk.SignalListItemFactory | null = null;
20
+ private containers = new Map<Gtk.ListItem, number>();
21
+ private containerKeys = new Map<Gtk.ListItem, string>();
22
+ private menu: MenuModel;
23
+ private actionGroup: Gio.SimpleActionGroup;
24
+
25
+ constructor(typeName: string, props: ColumnViewColumnProps, container: undefined, rootContainer: Container) {
26
+ super(typeName, props, container, rootContainer);
27
+ this.actionGroup = new Gio.SimpleActionGroup();
28
+ this.menu = new MenuModel("root", {}, rootContainer, this.actionGroup);
29
+ this.menu.setActionMap(this.actionGroup, props.id);
30
+ }
31
+
15
32
  public override isValidChild(child: Node): boolean {
16
33
  return child instanceof MenuNode;
17
34
  }
@@ -19,150 +36,154 @@ export class ColumnViewColumnNode extends VirtualNode<ColumnViewColumnProps, Wid
19
36
  public override isValidParent(parent: Node): boolean {
20
37
  return parent instanceof WidgetNode && parent.container instanceof Gtk.ColumnView;
21
38
  }
22
- private column: Gtk.ColumnViewColumn;
23
- private itemRenderer: ListItemRenderer;
24
- private menu: MenuModel | null = null;
25
- private actionGroup: Gio.SimpleActionGroup | null = null;
26
- private columnView: Gtk.ColumnView | null = null;
27
39
 
28
- constructor(typeName: string, props: ColumnViewColumnProps, container: undefined, rootContainer: Container) {
29
- super(typeName, props, container, rootContainer);
30
- this.itemRenderer = new ListItemRenderer(this.signalStore);
31
- this.column = new Gtk.ColumnViewColumn();
32
- this.column.setFactory(this.itemRenderer.getFactory());
40
+ public override finalizeInitialChildren(props: ColumnViewColumnProps): boolean {
41
+ this.setupFactory();
42
+ this.setupColumn(props);
43
+ this.updateHeaderMenu();
44
+ return false;
45
+ }
46
+
47
+ public override commitUpdate(oldProps: ColumnViewColumnProps | null, newProps: ColumnViewColumnProps): void {
48
+ super.commitUpdate(oldProps, newProps);
49
+ if (oldProps === null) return;
50
+ this.applyColumnProps(oldProps, newProps);
33
51
  }
34
52
 
35
53
  public override appendChild(child: MenuNode): void {
36
- this.initMenu();
37
- this.menu?.appendChild(child);
54
+ this.menu.appendChild(child);
55
+ this.updateHeaderMenu();
38
56
  }
39
57
 
40
58
  public override insertBefore(child: MenuNode, before: MenuNode): void {
41
- this.initMenu();
42
- if (before instanceof MenuNode) {
43
- this.menu?.insertBefore(child, before);
44
- } else {
45
- this.menu?.appendChild(child);
46
- }
59
+ this.menu.insertBefore(child, before);
60
+ this.updateHeaderMenu();
47
61
  }
48
62
 
49
63
  public override removeChild(child: MenuNode): void {
50
- this.menu?.removeChild(child);
51
-
52
- if (this.menu && this.menu.getMenu().getNItems() === 0) {
53
- this.cleanupMenu();
54
- }
55
- }
56
-
57
- public override commitUpdate(oldProps: ColumnViewColumnProps | null, newProps: ColumnViewColumnProps): void {
58
- super.commitUpdate(oldProps, newProps);
59
- this.applyOwnProps(oldProps, newProps);
64
+ this.menu.removeChild(child);
65
+ this.updateHeaderMenu();
60
66
  }
61
67
 
62
68
  public override detachDeletedInstance(): void {
63
- this.cleanupMenu();
64
- this.itemRenderer.dispose();
65
69
  super.detachDeletedInstance();
66
70
  }
67
71
 
68
72
  public getColumn(): Gtk.ColumnViewColumn {
73
+ if (!this.column) throw new Error("ColumnViewColumn not initialized");
69
74
  return this.column;
70
75
  }
71
76
 
72
- public rebindItem(id: string): void {
73
- this.itemRenderer.rebindItem(id);
74
- }
75
-
76
- public setStore(model: TreeStore | null): void {
77
- this.itemRenderer.setStore(model);
78
- }
77
+ public collectBoundItems(flatItems: ListItem[]): BoundItem[] {
78
+ const { renderCell } = this.props;
79
+ if (!renderCell) return [];
79
80
 
80
- public setEstimatedRowHeight(height: number | null): void {
81
- this.itemRenderer.setEstimatedItemHeight(height);
82
- }
81
+ const items: BoundItem[] = [];
83
82
 
84
- public attachToColumnView(columnView: Gtk.ColumnView): void {
85
- this.columnView = columnView;
83
+ for (const [container, position] of this.containers) {
84
+ if (position === UNBOUND_POSITION) continue;
86
85
 
87
- if (this.actionGroup) {
88
- this.columnView.insertActionGroup(this.props.id, this.actionGroup);
89
- }
90
- }
86
+ const key = this.containerKeys.get(container);
87
+ if (!key) continue;
91
88
 
92
- public detachFromColumnView(): void {
93
- if (this.columnView && this.actionGroup) {
94
- this.columnView.insertActionGroup(this.props.id, null);
89
+ const item = flatItems[position];
90
+ if (!item) continue;
91
+ const content = renderCell(item.value);
92
+ items.push([content, container, key]);
95
93
  }
96
94
 
97
- this.columnView = null;
95
+ return items;
98
96
  }
99
97
 
100
- private initMenu(): void {
101
- if (this.menu) return;
102
-
103
- this.actionGroup = new Gio.SimpleActionGroup();
104
- this.menu = new MenuModel("root", {}, this.rootContainer);
105
- this.menu.setActionMap(this.actionGroup, this.props.id);
106
- this.column.setHeaderMenu(this.menu.getMenu());
98
+ public installActionGroup(widget: Gtk.Widget): void {
99
+ widget.insertActionGroup(this.props.id, this.actionGroup);
100
+ }
107
101
 
108
- if (this.columnView) {
109
- this.columnView.insertActionGroup(this.props.id, this.actionGroup);
110
- }
102
+ public uninstallActionGroup(widget: Gtk.Widget): void {
103
+ widget.insertActionGroup(this.props.id, null);
111
104
  }
112
105
 
113
- private cleanupMenu(): void {
114
- if (!this.menu) return;
106
+ private setupFactory(): void {
107
+ this.columnFactory = new Gtk.SignalListItemFactory();
115
108
 
116
- this.column.setHeaderMenu(null);
109
+ this.columnFactory.connect("setup", (_self: GObject.Object, obj: GObject.Object) => {
110
+ const listItem = obj as unknown as Gtk.ListItem;
111
+ const key = String(getNativeId(listItem.handle));
112
+ const placeholder = new Gtk.Box();
113
+ const { width, height } = this.getParentEstimatedItemSize();
114
+ placeholder.setSizeRequest(width, height);
115
+ listItem.setChild(placeholder);
116
+ this.containers.set(listItem, UNBOUND_POSITION);
117
+ this.containerKeys.set(listItem, key);
118
+ });
117
119
 
118
- if (this.columnView && this.actionGroup) {
119
- this.columnView.insertActionGroup(this.props.id, null);
120
- }
120
+ this.columnFactory.connect("bind", (_self: GObject.Object, obj: GObject.Object) => {
121
+ const listItem = obj as unknown as Gtk.ListItem;
122
+ this.containers.set(listItem, listItem.getPosition());
123
+ this.scheduleParentUpdate();
124
+ });
121
125
 
122
- this.menu = null;
123
- this.actionGroup = null;
124
- }
126
+ this.columnFactory.connect("unbind", (_self: GObject.Object, obj: GObject.Object) => {
127
+ const listItem = obj as unknown as Gtk.ListItem;
128
+ this.containers.set(listItem, UNBOUND_POSITION);
129
+ this.scheduleParentUpdate();
130
+ });
125
131
 
126
- private applyOwnProps(oldProps: ColumnViewColumnProps | null, newProps: ColumnViewColumnProps): void {
127
- if (hasChanged(oldProps, newProps, "renderCell")) {
128
- this.itemRenderer.setRenderFn(newProps.renderCell);
129
- }
132
+ this.columnFactory.connect("teardown", (_self: GObject.Object, obj: GObject.Object) => {
133
+ const listItem = obj as unknown as Gtk.ListItem;
134
+ this.containers.delete(listItem);
135
+ this.containerKeys.delete(listItem);
136
+ listItem.setChild(null);
137
+ });
138
+ }
130
139
 
131
- if (hasChanged(oldProps, newProps, "title")) {
132
- this.column.setTitle(newProps.title);
133
- }
140
+ private setupColumn(props: ColumnViewColumnProps): void {
141
+ this.column = new Gtk.ColumnViewColumn(props.title, this.columnFactory);
142
+ this.column.setId(props.id);
134
143
 
135
- if (hasChanged(oldProps, newProps, "expand")) {
136
- this.column.setExpand(newProps.expand ?? false);
137
- }
144
+ if (props.expand !== undefined) this.column.setExpand(props.expand);
145
+ if (props.resizable !== undefined) this.column.setResizable(props.resizable);
146
+ if (props.fixedWidth !== undefined) this.column.setFixedWidth(props.fixedWidth);
147
+ if (props.visible !== undefined) this.column.setVisible(props.visible);
148
+ if (props.sortable) this.column.setSorter(new Gtk.Sorter());
149
+ }
138
150
 
139
- if (hasChanged(oldProps, newProps, "resizable")) {
140
- this.column.setResizable(newProps.resizable ?? false);
141
- }
151
+ private applyColumnProps(oldProps: ColumnViewColumnProps, newProps: ColumnViewColumnProps): void {
152
+ if (!this.column) return;
142
153
 
143
- if (hasChanged(oldProps, newProps, "fixedWidth")) {
144
- this.column.setFixedWidth(newProps.fixedWidth ?? -1);
154
+ if (hasChanged(oldProps, newProps, "title")) this.column.setTitle(newProps.title);
155
+ if (hasChanged(oldProps, newProps, "expand")) this.column.setExpand(newProps.expand ?? false);
156
+ if (hasChanged(oldProps, newProps, "resizable")) this.column.setResizable(newProps.resizable ?? false);
157
+ if (hasChanged(oldProps, newProps, "fixedWidth")) this.column.setFixedWidth(newProps.fixedWidth ?? -1);
158
+ if (hasChanged(oldProps, newProps, "visible")) this.column.setVisible(newProps.visible ?? true);
159
+ if (hasChanged(oldProps, newProps, "sortable")) {
160
+ this.column.setSorter(newProps.sortable ? new Gtk.Sorter() : null);
145
161
  }
162
+ if (hasChanged(oldProps, newProps, "renderCell")) this.scheduleParentUpdate();
163
+ }
146
164
 
147
- if (hasChanged(oldProps, newProps, "id")) {
148
- if (this.columnView && this.actionGroup && oldProps?.id) {
149
- this.columnView.insertActionGroup(oldProps.id, null);
150
- this.columnView.insertActionGroup(newProps.id, this.actionGroup);
151
- }
152
-
153
- this.column.setId(newProps.id);
165
+ private updateHeaderMenu(): void {
166
+ if (!this.column) return;
167
+ const menu = this.menu.getMenu();
168
+ this.column.setHeaderMenu(menu.getNItems() > 0 ? menu : null);
169
+ }
154
170
 
155
- if (oldProps && this.menu && this.actionGroup) {
156
- this.menu.setActionMap(this.actionGroup, newProps.id);
157
- }
171
+ private getParentEstimatedItemSize(): { width: number; height: number } {
172
+ if (this.parent && "getEstimatedItemSize" in this.parent) {
173
+ return (
174
+ this.parent as { getEstimatedItemSize(): { width: number; height: number } }
175
+ ).getEstimatedItemSize();
158
176
  }
177
+ return { width: -1, height: -1 };
178
+ }
159
179
 
160
- if (hasChanged(oldProps, newProps, "sortable")) {
161
- if (newProps.sortable) {
162
- this.column.setSorter(new Gtk.StringSorter());
163
- } else {
164
- this.column.setSorter(null);
165
- }
180
+ private scheduleParentUpdate(): void {
181
+ if (
182
+ this.parent &&
183
+ "scheduleBoundItemsUpdate" in this.parent &&
184
+ typeof this.parent.scheduleBoundItemsUpdate === "function"
185
+ ) {
186
+ (this.parent as { scheduleBoundItemsUpdate(): void }).scheduleBoundItemsUpdate();
166
187
  }
167
188
  }
168
189
  }
@@ -1,8 +1,8 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import { CONSTRUCTOR_PROPS } from "../generated/internal.js";
3
- import { resolvePropMeta, resolveSignal } from "../metadata.js";
2
+ import { isConstructOnlyProp, resolvePropMeta, resolveSignal } from "../metadata.js";
4
3
  import { Node } from "../node.js";
5
4
  import type { Props } from "../types.js";
5
+ import { createContainerWithProperties } from "./internal/construct.js";
6
6
  import type { SignalHandler } from "./internal/signal-store.js";
7
7
  import { WidgetNode } from "./widget.js";
8
8
 
@@ -17,17 +17,16 @@ export class EventControllerNode<
17
17
  props: Props,
18
18
  containerClass: typeof Gtk.EventController,
19
19
  ): Gtk.EventController {
20
- const typeName = containerClass.glibTypeName;
21
-
22
- if (typeName === "GtkDropTarget") {
20
+ if (containerClass.glibTypeName === "GtkDropTarget") {
23
21
  const actions = (props.actions as number | undefined) ?? 0;
24
22
  return new Gtk.DropTarget(G_TYPE_INVALID, actions);
25
23
  }
26
24
 
27
- const args = (CONSTRUCTOR_PROPS[typeName] ?? []).map((name) => props[name]);
25
+ return createContainerWithProperties(containerClass, props) as Gtk.EventController;
26
+ }
28
27
 
29
- // biome-ignore lint/suspicious/noExplicitAny: Dynamic constructor invocation
30
- return new (containerClass as any)(...args);
28
+ public override isValidChild(child: Node): boolean {
29
+ return this.container instanceof Gtk.ShortcutController && child.typeName === "Shortcut";
31
30
  }
32
31
 
33
32
  public override isValidParent(parent: Node): boolean {
@@ -63,6 +62,7 @@ export class EventControllerNode<
63
62
 
64
63
  for (const name of propNames) {
65
64
  if (name === "children") continue;
65
+ if (isConstructOnlyProp(this.container, name)) continue;
66
66
 
67
67
  const oldValue = oldProps?.[name];
68
68
  const newValue = newProps[name];
@@ -1,3 +1,5 @@
1
+ import * as Graphene from "@gtkx/ffi/graphene";
2
+ import * as Gsk from "@gtkx/ffi/gsk";
1
3
  import * as Gtk from "@gtkx/ffi/gtk";
2
4
  import type { FixedChildProps } from "../jsx.js";
3
5
  import type { Node } from "../node.js";
@@ -23,7 +25,7 @@ export class FixedChildNode extends VirtualNode<FixedChildProps, WidgetNode<Gtk.
23
25
 
24
26
  if (parent && this.children[0]) {
25
27
  this.attachToParent(parent.container, this.children[0].container);
26
- this.applyTransform();
28
+ this.applyLayoutTransform();
27
29
  }
28
30
  }
29
31
 
@@ -32,7 +34,7 @@ export class FixedChildNode extends VirtualNode<FixedChildProps, WidgetNode<Gtk.
32
34
 
33
35
  if (this.parent) {
34
36
  this.attachToParent(this.parent.container, child.container);
35
- this.applyTransform();
37
+ this.applyLayoutTransform();
36
38
  }
37
39
  }
38
40
 
@@ -51,12 +53,12 @@ export class FixedChildNode extends VirtualNode<FixedChildProps, WidgetNode<Gtk.
51
53
  return;
52
54
  }
53
55
 
54
- const positionChanged = hasChanged(oldProps, newProps, "x") || hasChanged(oldProps, newProps, "y");
55
-
56
- if (positionChanged) {
57
- this.repositionChild();
58
- } else if (hasChanged(oldProps, newProps, "transform")) {
59
- this.applyTransform();
56
+ if (
57
+ hasChanged(oldProps, newProps, "x") ||
58
+ hasChanged(oldProps, newProps, "y") ||
59
+ hasChanged(oldProps, newProps, "transform")
60
+ ) {
61
+ this.applyLayoutTransform();
60
62
  }
61
63
  }
62
64
 
@@ -80,29 +82,28 @@ export class FixedChildNode extends VirtualNode<FixedChildProps, WidgetNode<Gtk.
80
82
  }
81
83
  }
82
84
 
83
- private repositionChild(): void {
85
+ private applyLayoutTransform(): void {
84
86
  if (!this.parent || !this.children[0]) return;
85
87
 
88
+ const layoutManager = this.parent.container.getLayoutManager();
89
+ if (!layoutManager) return;
90
+
91
+ const layoutChild = layoutManager.getLayoutChild(this.children[0].container) as Gtk.FixedLayoutChild;
92
+
86
93
  const x = this.props.x ?? 0;
87
94
  const y = this.props.y ?? 0;
95
+ const position = new Graphene.Point();
96
+ position.init(x, y);
88
97
 
89
- this.parent.container.remove(this.children[0].container);
90
- this.parent.container.put(this.children[0].container, x, y);
91
- this.applyTransform();
92
- }
98
+ let transform: Gsk.Transform | null = new Gsk.Transform();
99
+ transform = transform.translate(position);
93
100
 
94
- private applyTransform(): void {
95
- if (!this.parent || !this.children[0] || !this.props.transform) {
96
- return;
101
+ if (this.props.transform && transform) {
102
+ transform = transform.transform(this.props.transform);
97
103
  }
98
104
 
99
- const layoutManager = this.parent.container.getLayoutManager();
100
-
101
- if (!layoutManager) {
102
- return;
105
+ if (transform) {
106
+ layoutChild.setTransform(transform);
103
107
  }
104
-
105
- const layoutChild = layoutManager.getLayoutChild(this.children[0].container) as Gtk.FixedLayoutChild;
106
- layoutChild.setTransform(this.props.transform);
107
108
  }
108
109
  }
@@ -10,6 +10,8 @@ const OWN_PROPS = [
10
10
  "title",
11
11
  "modal",
12
12
  "language",
13
+ "filter",
14
+ "fontMap",
13
15
  "useFont",
14
16
  "useSize",
15
17
  "level",
@@ -61,6 +63,14 @@ export class FontDialogButtonNode extends WidgetNode<Gtk.FontDialogButton, FontD
61
63
  this.dialog.setLanguage(newProps.language);
62
64
  }
63
65
 
66
+ if (hasChanged(oldProps, newProps, "filter")) {
67
+ this.dialog.setFilter(newProps.filter);
68
+ }
69
+
70
+ if (hasChanged(oldProps, newProps, "fontMap")) {
71
+ this.dialog.setFontMap(newProps.fontMap);
72
+ }
73
+
64
74
  if (hasChanged(oldProps, newProps, "useFont")) {
65
75
  this.container.setUseFont(newProps.useFont ?? false);
66
76
  }
@@ -0,0 +1,155 @@
1
+ import type * as GObject from "@gtkx/ffi/gobject";
2
+ import { Value } from "@gtkx/ffi/gobject";
3
+ import * as Gtk from "@gtkx/ffi/gtk";
4
+ import type { Props } from "../../types.js";
5
+
6
+ type CreateValue = (jsValue: unknown) => Value;
7
+
8
+ type PropertyDef = {
9
+ kind: "property";
10
+ enumValue: Gtk.AccessibleProperty;
11
+ createValue: CreateValue;
12
+ };
13
+
14
+ type StateDef = {
15
+ kind: "state";
16
+ enumValue: Gtk.AccessibleState;
17
+ createValue: CreateValue;
18
+ };
19
+
20
+ type RelationDef = {
21
+ kind: "relation";
22
+ enumValue: Gtk.AccessibleRelation;
23
+ createValue: CreateValue;
24
+ };
25
+
26
+ type AccessiblePropDef = PropertyDef | StateDef | RelationDef;
27
+
28
+ const fromString: CreateValue = (val) => Value.newFromString(val as string);
29
+ const fromBoolean: CreateValue = (val) => Value.newFromBoolean(val as boolean);
30
+ const fromInt: CreateValue = (val) => Value.newFromInt(val as number);
31
+ const fromDouble: CreateValue = (val) => Value.newFromDouble(val as number);
32
+ const fromObject: CreateValue = (val) => Value.newFromObject((val as GObject.Object) ?? null);
33
+
34
+ const fromRefList: CreateValue = (val) => {
35
+ const widgets = val as Gtk.Accessible[];
36
+ const list = Gtk.AccessibleList.newFromList(widgets);
37
+ return Value.newFromBoxed(list);
38
+ };
39
+
40
+ const prop = (enumValue: Gtk.AccessibleProperty, createValue: CreateValue): PropertyDef => ({
41
+ kind: "property",
42
+ enumValue,
43
+ createValue,
44
+ });
45
+
46
+ const state = (enumValue: Gtk.AccessibleState, createValue: CreateValue): StateDef => ({
47
+ kind: "state",
48
+ enumValue,
49
+ createValue,
50
+ });
51
+
52
+ const relation = (enumValue: Gtk.AccessibleRelation, createValue: CreateValue): RelationDef => ({
53
+ kind: "relation",
54
+ enumValue,
55
+ createValue,
56
+ });
57
+
58
+ const ACCESSIBLE_PROP_MAP: Record<string, AccessiblePropDef> = {
59
+ accessibleAutocomplete: prop(Gtk.AccessibleProperty.AUTOCOMPLETE, fromInt),
60
+ accessibleDescription: prop(Gtk.AccessibleProperty.DESCRIPTION, fromString),
61
+ accessibleHasPopup: prop(Gtk.AccessibleProperty.HAS_POPUP, fromBoolean),
62
+ accessibleKeyShortcuts: prop(Gtk.AccessibleProperty.KEY_SHORTCUTS, fromString),
63
+ accessibleLabel: prop(Gtk.AccessibleProperty.LABEL, fromString),
64
+ accessibleLevel: prop(Gtk.AccessibleProperty.LEVEL, fromInt),
65
+ accessibleModal: prop(Gtk.AccessibleProperty.MODAL, fromBoolean),
66
+ accessibleMultiLine: prop(Gtk.AccessibleProperty.MULTI_LINE, fromBoolean),
67
+ accessibleMultiSelectable: prop(Gtk.AccessibleProperty.MULTI_SELECTABLE, fromBoolean),
68
+ accessibleOrientation: prop(Gtk.AccessibleProperty.ORIENTATION, fromInt),
69
+ accessiblePlaceholder: prop(Gtk.AccessibleProperty.PLACEHOLDER, fromString),
70
+ accessibleReadOnly: prop(Gtk.AccessibleProperty.READ_ONLY, fromBoolean),
71
+ accessibleRequired: prop(Gtk.AccessibleProperty.REQUIRED, fromBoolean),
72
+ accessibleRoleDescription: prop(Gtk.AccessibleProperty.ROLE_DESCRIPTION, fromString),
73
+ accessibleSort: prop(Gtk.AccessibleProperty.SORT, fromInt),
74
+ accessibleValueMax: prop(Gtk.AccessibleProperty.VALUE_MAX, fromDouble),
75
+ accessibleValueMin: prop(Gtk.AccessibleProperty.VALUE_MIN, fromDouble),
76
+ accessibleValueNow: prop(Gtk.AccessibleProperty.VALUE_NOW, fromDouble),
77
+ accessibleValueText: prop(Gtk.AccessibleProperty.VALUE_TEXT, fromString),
78
+ accessibleHelpText: prop(Gtk.AccessibleProperty.HELP_TEXT, fromString),
79
+
80
+ accessibleBusy: state(Gtk.AccessibleState.BUSY, fromBoolean),
81
+ accessibleChecked: state(Gtk.AccessibleState.CHECKED, fromInt),
82
+ accessibleDisabled: state(Gtk.AccessibleState.DISABLED, fromBoolean),
83
+ accessibleExpanded: state(Gtk.AccessibleState.EXPANDED, fromInt),
84
+ accessibleHidden: state(Gtk.AccessibleState.HIDDEN, fromBoolean),
85
+ accessibleInvalid: state(Gtk.AccessibleState.INVALID, fromInt),
86
+ accessiblePressed: state(Gtk.AccessibleState.PRESSED, fromInt),
87
+ accessibleSelected: state(Gtk.AccessibleState.SELECTED, fromInt),
88
+ accessibleVisited: state(Gtk.AccessibleState.VISITED, fromInt),
89
+
90
+ accessibleActiveDescendant: relation(Gtk.AccessibleRelation.ACTIVE_DESCENDANT, fromObject),
91
+ accessibleColCount: relation(Gtk.AccessibleRelation.COL_COUNT, fromInt),
92
+ accessibleColIndex: relation(Gtk.AccessibleRelation.COL_INDEX, fromInt),
93
+ accessibleColIndexText: relation(Gtk.AccessibleRelation.COL_INDEX_TEXT, fromString),
94
+ accessibleColSpan: relation(Gtk.AccessibleRelation.COL_SPAN, fromInt),
95
+ accessibleControls: relation(Gtk.AccessibleRelation.CONTROLS, fromRefList),
96
+ accessibleDescribedBy: relation(Gtk.AccessibleRelation.DESCRIBED_BY, fromRefList),
97
+ accessibleDetails: relation(Gtk.AccessibleRelation.DETAILS, fromRefList),
98
+ accessibleErrorMessage: relation(Gtk.AccessibleRelation.ERROR_MESSAGE, fromRefList),
99
+ accessibleFlowTo: relation(Gtk.AccessibleRelation.FLOW_TO, fromRefList),
100
+ accessibleLabelledBy: relation(Gtk.AccessibleRelation.LABELLED_BY, fromRefList),
101
+ accessibleOwns: relation(Gtk.AccessibleRelation.OWNS, fromRefList),
102
+ accessiblePosInSet: relation(Gtk.AccessibleRelation.POS_IN_SET, fromInt),
103
+ accessibleRowCount: relation(Gtk.AccessibleRelation.ROW_COUNT, fromInt),
104
+ accessibleRowIndex: relation(Gtk.AccessibleRelation.ROW_INDEX, fromInt),
105
+ accessibleRowIndexText: relation(Gtk.AccessibleRelation.ROW_INDEX_TEXT, fromString),
106
+ accessibleRowSpan: relation(Gtk.AccessibleRelation.ROW_SPAN, fromInt),
107
+ accessibleSetSize: relation(Gtk.AccessibleRelation.SET_SIZE, fromInt),
108
+ };
109
+
110
+ export const isAccessibleProp = (name: string): boolean => name in ACCESSIBLE_PROP_MAP;
111
+
112
+ function applyDef(widget: Gtk.Widget, def: AccessiblePropDef, newValue: unknown): void {
113
+ const gvalue = def.createValue(newValue);
114
+
115
+ switch (def.kind) {
116
+ case "property":
117
+ widget.updatePropertyValue(1, [def.enumValue], [gvalue]);
118
+ break;
119
+ case "state":
120
+ widget.updateStateValue(1, [def.enumValue], [gvalue]);
121
+ break;
122
+ case "relation":
123
+ widget.updateRelationValue(1, [def.enumValue], [gvalue]);
124
+ break;
125
+ }
126
+ }
127
+
128
+ function resetDef(widget: Gtk.Widget, def: AccessiblePropDef): void {
129
+ switch (def.kind) {
130
+ case "property":
131
+ widget.resetProperty(def.enumValue);
132
+ break;
133
+ case "state":
134
+ widget.resetState(def.enumValue);
135
+ break;
136
+ case "relation":
137
+ widget.resetRelation(def.enumValue);
138
+ break;
139
+ }
140
+ }
141
+
142
+ export const applyAccessibleProps = (widget: Gtk.Widget, oldProps: Props | null, newProps: Props): void => {
143
+ for (const [name, def] of Object.entries(ACCESSIBLE_PROP_MAP)) {
144
+ const oldValue = oldProps?.[name];
145
+ const newValue = newProps[name];
146
+
147
+ if (oldValue === newValue) continue;
148
+
149
+ if (newValue === undefined) {
150
+ resetDef(widget, def);
151
+ } else {
152
+ applyDef(widget, def, newValue);
153
+ }
154
+ }
155
+ };
@@ -0,0 +1,4 @@
1
+ import type { ReactNode } from "react";
2
+ import type { Container } from "../../types.js";
3
+
4
+ export type BoundItem = [ReactNode, Container, string];
@@ -0,0 +1,60 @@
1
+ import type { NativeClass, Type } from "@gtkx/ffi";
2
+ import { Object as GObject, toValue, type Value } from "@gtkx/ffi/gobject";
3
+ import { CONSTRUCTION_META } from "../../generated/internal.js";
4
+ import type { Container, ContainerClass, Props } from "../../types.js";
5
+
6
+ type ConstructionPropMeta = {
7
+ girName: string;
8
+ ffiType: Type;
9
+ constructOnly?: true;
10
+ };
11
+
12
+ function collectConstructionProps(
13
+ containerClass: ContainerClass,
14
+ props: Props,
15
+ ): Array<{ girName: string; ffiType: Type; value: unknown }> {
16
+ const result: Array<{ girName: string; ffiType: Type; value: unknown }> = [];
17
+ const seen = new Set<string>();
18
+
19
+ // biome-ignore lint/complexity/noBannedTypes: Walking prototype chain requires Function type
20
+ let current: Function | null = containerClass;
21
+ while (current) {
22
+ const typeName = (current as NativeClass).glibTypeName;
23
+ if (!typeName) break;
24
+
25
+ const meta: Record<string, ConstructionPropMeta> | undefined = CONSTRUCTION_META[typeName];
26
+ if (meta) {
27
+ for (const [camelName, propMeta] of Object.entries(meta)) {
28
+ if (seen.has(camelName)) continue;
29
+ seen.add(camelName);
30
+ if (props[camelName] !== undefined) {
31
+ result.push({
32
+ girName: propMeta.girName,
33
+ ffiType: propMeta.ffiType,
34
+ value: props[camelName],
35
+ });
36
+ }
37
+ }
38
+ }
39
+
40
+ current = Object.getPrototypeOf(current);
41
+ if (current === Object || current === Function) break;
42
+ }
43
+
44
+ return result;
45
+ }
46
+
47
+ export function createContainerWithProperties(containerClass: ContainerClass, props: Props): Container {
48
+ const gtype = containerClass.getGType();
49
+ const constructionProps = collectConstructionProps(containerClass, props);
50
+
51
+ const names: string[] = [];
52
+ const values: Value[] = [];
53
+
54
+ for (const { girName, ffiType, value } of constructionProps) {
55
+ names.push(girName);
56
+ values.push(toValue(ffiType, value));
57
+ }
58
+
59
+ return GObject.newWithProperties(gtype, names, values) as unknown as Container;
60
+ }