@gtkx/react 0.18.9 → 0.19.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 (174) hide show
  1. package/dist/generated/internal.d.ts +6 -0
  2. package/dist/generated/internal.d.ts.map +1 -1
  3. package/dist/generated/internal.js +331 -44
  4. package/dist/generated/internal.js.map +1 -1
  5. package/dist/generated/jsx.d.ts +178 -2
  6. package/dist/generated/jsx.d.ts.map +1 -1
  7. package/dist/generated/jsx.js.map +1 -1
  8. package/dist/host-config.d.ts.map +1 -1
  9. package/dist/host-config.js +46 -10
  10. package/dist/host-config.js.map +1 -1
  11. package/dist/jsx.d.ts +133 -13
  12. package/dist/jsx.d.ts.map +1 -1
  13. package/dist/jsx.js +41 -2
  14. package/dist/jsx.js.map +1 -1
  15. package/dist/metadata.d.ts +1 -0
  16. package/dist/metadata.d.ts.map +1 -1
  17. package/dist/metadata.js +3 -1
  18. package/dist/metadata.js.map +1 -1
  19. package/dist/node.d.ts +2 -0
  20. package/dist/node.d.ts.map +1 -1
  21. package/dist/node.js +22 -6
  22. package/dist/node.js.map +1 -1
  23. package/dist/nodes/column-view-column.d.ts +4 -1
  24. package/dist/nodes/column-view-column.d.ts.map +1 -1
  25. package/dist/nodes/column-view-column.js +29 -8
  26. package/dist/nodes/column-view-column.js.map +1 -1
  27. package/dist/nodes/column-view.d.ts +4 -3
  28. package/dist/nodes/column-view.d.ts.map +1 -1
  29. package/dist/nodes/column-view.js +44 -14
  30. package/dist/nodes/column-view.js.map +1 -1
  31. package/dist/nodes/drop-down.d.ts +12 -2
  32. package/dist/nodes/drop-down.d.ts.map +1 -1
  33. package/dist/nodes/drop-down.js +151 -5
  34. package/dist/nodes/drop-down.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 +11 -3
  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/grid-view.d.ts +6 -5
  48. package/dist/nodes/grid-view.d.ts.map +1 -1
  49. package/dist/nodes/grid-view.js +23 -18
  50. package/dist/nodes/grid-view.js.map +1 -1
  51. package/dist/nodes/internal/accessible.d.ts +5 -0
  52. package/dist/nodes/internal/accessible.d.ts.map +1 -0
  53. package/dist/nodes/internal/accessible.js +119 -0
  54. package/dist/nodes/internal/accessible.js.map +1 -0
  55. package/dist/nodes/internal/base-item-renderer.d.ts.map +1 -1
  56. package/dist/nodes/internal/base-item-renderer.js +0 -1
  57. package/dist/nodes/internal/base-item-renderer.js.map +1 -1
  58. package/dist/nodes/internal/construct.d.ts +10 -0
  59. package/dist/nodes/internal/construct.d.ts.map +1 -0
  60. package/dist/nodes/internal/construct.js +68 -0
  61. package/dist/nodes/internal/construct.js.map +1 -0
  62. package/dist/nodes/internal/header-item-renderer.d.ts +23 -0
  63. package/dist/nodes/internal/header-item-renderer.d.ts.map +1 -0
  64. package/dist/nodes/internal/header-item-renderer.js +87 -0
  65. package/dist/nodes/internal/header-item-renderer.js.map +1 -0
  66. package/dist/nodes/internal/header-renderer-manager.d.ts +13 -0
  67. package/dist/nodes/internal/header-renderer-manager.d.ts.map +1 -0
  68. package/dist/nodes/internal/header-renderer-manager.js +20 -0
  69. package/dist/nodes/internal/header-renderer-manager.js.map +1 -0
  70. package/dist/nodes/internal/list-store.d.ts +10 -11
  71. package/dist/nodes/internal/list-store.d.ts.map +1 -1
  72. package/dist/nodes/internal/list-store.js +28 -29
  73. package/dist/nodes/internal/list-store.js.map +1 -1
  74. package/dist/nodes/internal/sectioned-list-store.d.ts +50 -0
  75. package/dist/nodes/internal/sectioned-list-store.d.ts.map +1 -0
  76. package/dist/nodes/internal/sectioned-list-store.js +250 -0
  77. package/dist/nodes/internal/sectioned-list-store.js.map +1 -0
  78. package/dist/nodes/internal/selection-helpers.d.ts +12 -0
  79. package/dist/nodes/internal/selection-helpers.d.ts.map +1 -0
  80. package/dist/nodes/internal/selection-helpers.js +25 -0
  81. package/dist/nodes/internal/selection-helpers.js.map +1 -0
  82. package/dist/nodes/internal/selection-model-controller.d.ts.map +1 -1
  83. package/dist/nodes/internal/selection-model-controller.js +3 -0
  84. package/dist/nodes/internal/selection-model-controller.js.map +1 -1
  85. package/dist/nodes/internal/simple-list-store.d.ts +7 -12
  86. package/dist/nodes/internal/simple-list-store.d.ts.map +1 -1
  87. package/dist/nodes/internal/simple-list-store.js +58 -35
  88. package/dist/nodes/internal/simple-list-store.js.map +1 -1
  89. package/dist/nodes/internal/text-buffer-controller.d.ts +4 -0
  90. package/dist/nodes/internal/text-buffer-controller.d.ts.map +1 -1
  91. package/dist/nodes/internal/text-buffer-controller.js +49 -9
  92. package/dist/nodes/internal/text-buffer-controller.js.map +1 -1
  93. package/dist/nodes/internal/tree-store.d.ts +3 -0
  94. package/dist/nodes/internal/tree-store.d.ts.map +1 -1
  95. package/dist/nodes/internal/tree-store.js +55 -10
  96. package/dist/nodes/internal/tree-store.js.map +1 -1
  97. package/dist/nodes/list-section.d.ts +27 -0
  98. package/dist/nodes/list-section.d.ts.map +1 -0
  99. package/dist/nodes/list-section.js +43 -0
  100. package/dist/nodes/list-section.js.map +1 -0
  101. package/dist/nodes/list-view.d.ts +6 -3
  102. package/dist/nodes/list-view.d.ts.map +1 -1
  103. package/dist/nodes/list-view.js +54 -14
  104. package/dist/nodes/list-view.js.map +1 -1
  105. package/dist/nodes/models/list.d.ts +13 -5
  106. package/dist/nodes/models/list.d.ts.map +1 -1
  107. package/dist/nodes/models/list.js +135 -21
  108. package/dist/nodes/models/list.js.map +1 -1
  109. package/dist/nodes/shortcut.d.ts +3 -2
  110. package/dist/nodes/shortcut.d.ts.map +1 -1
  111. package/dist/nodes/shortcut.js +19 -4
  112. package/dist/nodes/shortcut.js.map +1 -1
  113. package/dist/nodes/text-anchor.d.ts.map +1 -1
  114. package/dist/nodes/text-anchor.js +7 -1
  115. package/dist/nodes/text-anchor.js.map +1 -1
  116. package/dist/nodes/text-tag.d.ts.map +1 -1
  117. package/dist/nodes/text-tag.js +5 -1
  118. package/dist/nodes/text-tag.js.map +1 -1
  119. package/dist/nodes/text-view.d.ts +1 -0
  120. package/dist/nodes/text-view.d.ts.map +1 -1
  121. package/dist/nodes/text-view.js +4 -0
  122. package/dist/nodes/text-view.js.map +1 -1
  123. package/dist/nodes/widget.d.ts +0 -2
  124. package/dist/nodes/widget.d.ts.map +1 -1
  125. package/dist/nodes/widget.js +44 -61
  126. package/dist/nodes/widget.js.map +1 -1
  127. package/dist/registry.d.ts.map +1 -1
  128. package/dist/registry.js +2 -2
  129. package/dist/registry.js.map +1 -1
  130. package/package.json +3 -3
  131. package/src/generated/internal.ts +333 -44
  132. package/src/generated/jsx.ts +178 -2
  133. package/src/host-config.ts +41 -10
  134. package/src/jsx.ts +166 -15
  135. package/src/metadata.ts +5 -1
  136. package/src/node.ts +20 -6
  137. package/src/nodes/column-view-column.ts +32 -8
  138. package/src/nodes/column-view.ts +59 -14
  139. package/src/nodes/drop-down.ts +182 -6
  140. package/src/nodes/event-controller.ts +11 -3
  141. package/src/nodes/fixed-child.ts +24 -23
  142. package/src/nodes/font-dialog-button.ts +10 -0
  143. package/src/nodes/grid-view.ts +29 -19
  144. package/src/nodes/internal/accessible.ts +156 -0
  145. package/src/nodes/internal/base-item-renderer.ts +0 -1
  146. package/src/nodes/internal/construct.ts +90 -0
  147. package/src/nodes/internal/header-item-renderer.ts +105 -0
  148. package/src/nodes/internal/header-renderer-manager.ts +33 -0
  149. package/src/nodes/internal/list-store.ts +32 -30
  150. package/src/nodes/internal/sectioned-list-store.ts +287 -0
  151. package/src/nodes/internal/selection-helpers.ts +35 -0
  152. package/src/nodes/internal/selection-model-controller.ts +4 -0
  153. package/src/nodes/internal/simple-list-store.ts +60 -43
  154. package/src/nodes/internal/text-buffer-controller.ts +51 -8
  155. package/src/nodes/internal/tree-store.ts +61 -9
  156. package/src/nodes/list-section.ts +64 -0
  157. package/src/nodes/list-view.ts +65 -14
  158. package/src/nodes/models/list.ts +147 -37
  159. package/src/nodes/shortcut.ts +22 -5
  160. package/src/nodes/text-anchor.ts +6 -1
  161. package/src/nodes/text-tag.ts +7 -1
  162. package/src/nodes/text-view.ts +5 -0
  163. package/src/nodes/widget.ts +45 -62
  164. package/src/registry.ts +4 -2
  165. package/dist/nodes/models/grid.d.ts +0 -28
  166. package/dist/nodes/models/grid.d.ts.map +0 -1
  167. package/dist/nodes/models/grid.js +0 -69
  168. package/dist/nodes/models/grid.js.map +0 -1
  169. package/dist/nodes/shortcut-controller.d.ts +0 -10
  170. package/dist/nodes/shortcut-controller.d.ts.map +0 -1
  171. package/dist/nodes/shortcut-controller.js +0 -23
  172. package/dist/nodes/shortcut-controller.js.map +0 -1
  173. package/src/nodes/models/grid.ts +0 -105
  174. package/src/nodes/shortcut-controller.ts +0 -27
@@ -2,10 +2,13 @@ import type * as Gio from "@gtkx/ffi/gio";
2
2
  import type * as GObject from "@gtkx/ffi/gobject";
3
3
  import * as Gtk from "@gtkx/ffi/gtk";
4
4
  import type { GtkListViewProps } from "../../jsx.js";
5
+ import { ListStore } from "../internal/list-store.js";
6
+ import { getSelectionFromStore, resolveSelectionIndices } from "../internal/selection-helpers.js";
5
7
  import { SelectionModelController } from "../internal/selection-model-controller.js";
6
8
  import type { SignalStore } from "../internal/signal-store.js";
7
9
  import { TreeStore } from "../internal/tree-store.js";
8
10
  import { ListItemNode } from "../list-item.js";
11
+ import { ListSectionNode } from "../list-section.js";
9
12
 
10
13
  export type ListModelProps = Pick<GtkListViewProps, "autoexpand" | "selectionMode" | "selected" | "onSelectionChanged">;
11
14
 
@@ -16,101 +19,203 @@ type ListModelConfig = {
16
19
 
17
20
  export class ListModel {
18
21
  private config: ListModelConfig;
19
- private store: TreeStore;
20
- private treeListModel: Gtk.TreeListModel;
21
- private selectionManager: SelectionModelController;
22
+ private flatMode: boolean;
23
+
24
+ private treeStore: TreeStore | null = null;
25
+ private treeListModel: Gtk.TreeListModel | null = null;
26
+
27
+ private flatStore: ListStore | null = null;
22
28
 
29
+ private selectionManager: SelectionModelController;
23
30
  private initialSelected: string[] | null | undefined;
24
31
 
25
- constructor(config: ListModelConfig, props: ListModelProps = {}) {
32
+ constructor(config: ListModelConfig, props: ListModelProps = {}, flat = false) {
26
33
  this.config = config;
27
- this.store = new TreeStore();
28
- this.store.beginBatch();
34
+ this.flatMode = flat;
29
35
  this.initialSelected = props.selected;
30
36
 
31
- this.treeListModel = new Gtk.TreeListModel(
32
- this.store.getRootModel(),
33
- false,
34
- props.autoexpand ?? false,
35
- (item: GObject.Object) => this.createChildModel(item),
36
- );
37
+ let model: Gio.ListModel;
38
+
39
+ if (flat) {
40
+ const store = new ListStore();
41
+ store.beginBatch();
42
+ this.flatStore = store;
43
+ model = store.getModel();
44
+ } else {
45
+ const store = new TreeStore();
46
+ store.beginBatch();
47
+ this.treeStore = store;
48
+ this.treeListModel = new Gtk.TreeListModel(
49
+ store.getRootModel(),
50
+ false,
51
+ props.autoexpand ?? false,
52
+ (item: GObject.Object) => this.createChildModel(item),
53
+ );
54
+ model = this.treeListModel;
55
+ }
37
56
 
38
57
  this.selectionManager = new SelectionModelController(
39
58
  { ...config, ...props },
40
- this.treeListModel,
59
+ model,
41
60
  () => this.getSelection(),
42
61
  (ids) => this.resolveSelectionIndices(ids),
43
- () => this.treeListModel.getNItems(),
62
+ () => this.getNItems(),
44
63
  );
45
64
  }
46
65
 
66
+ public isFlatMode(): boolean {
67
+ return this.flatMode;
68
+ }
69
+
47
70
  public flushBatch(): void {
48
- this.store.flushBatch();
71
+ if (this.flatStore) {
72
+ this.flatStore.flushBatch();
73
+ const model = this.flatStore.getModel();
74
+ if (this.selectionManager.getSelectionModel().getModel() !== model) {
75
+ this.selectionManager.update(null, { ...this.config }, model);
76
+ }
77
+ } else if (this.treeStore) {
78
+ this.treeStore.flushBatch();
79
+ }
49
80
  this.selectionManager.reapplySelection(this.initialSelected);
50
81
  this.initialSelected = undefined;
51
82
  }
52
83
 
53
84
  private createChildModel(item: GObject.Object): Gio.ListModel | null {
85
+ if (!this.treeStore) return null;
54
86
  if (!(item instanceof Gtk.StringObject)) return null;
55
87
  const parentId = item.getString();
56
- return this.store.getChildrenModel(parentId);
88
+ return this.treeStore.getChildrenModel(parentId);
57
89
  }
58
90
 
59
91
  public getStore(): TreeStore {
60
- return this.store;
92
+ if (!this.treeStore) {
93
+ throw new Error("getStore() called in flat mode. Use getFlatStore() instead.");
94
+ }
95
+ return this.treeStore;
96
+ }
97
+
98
+ public getFlatStore(): ListStore {
99
+ if (!this.flatStore) {
100
+ throw new Error("getFlatStore() called in tree mode. Use getStore() instead.");
101
+ }
102
+ return this.flatStore;
103
+ }
104
+
105
+ public setOnItemUpdated(callback: (id: string) => void): void {
106
+ if (this.flatStore) {
107
+ this.flatStore.setOnItemUpdated(callback);
108
+ } else if (this.treeStore) {
109
+ this.treeStore.setOnItemUpdated(callback);
110
+ }
61
111
  }
62
112
 
63
113
  public getSelectionModel(): Gtk.NoSelection | Gtk.SingleSelection | Gtk.MultiSelection {
64
114
  return this.selectionManager.getSelectionModel();
65
115
  }
66
116
 
67
- public appendChild(child: ListItemNode): void {
68
- child.setStore(this.store);
69
- this.addItemWithChildren(child);
117
+ public appendChild(child: ListItemNode | ListSectionNode): void {
118
+ if (this.flatStore) {
119
+ if (child instanceof ListSectionNode) {
120
+ this.flatStore.addSection(child.props.id, child.props.value);
121
+ child.setStore(this.flatStore);
122
+ } else {
123
+ child.setStore(this.flatStore);
124
+ this.flatStore.addItem(child.props.id, child.props.value);
125
+ }
126
+ } else if (child instanceof ListItemNode && this.treeStore) {
127
+ child.setStore(this.treeStore);
128
+ this.addItemWithChildren(child);
129
+ }
70
130
  }
71
131
 
72
132
  private addItemWithChildren(node: ListItemNode, parentId?: string): void {
133
+ if (!this.treeStore) return;
73
134
  const id = node.props.id;
74
135
 
75
136
  for (const child of node.getChildNodes()) {
76
137
  this.addItemWithChildren(child, id);
77
138
  }
78
139
 
79
- this.store.addItem(id, ListItemNode.createItemData(node.props), parentId);
140
+ this.treeStore.addItem(id, ListItemNode.createItemData(node.props), parentId);
80
141
  }
81
142
 
82
- public insertBefore(child: ListItemNode, before: ListItemNode): void {
83
- child.setStore(this.store);
84
- this.store.insertItemBefore(child.props.id, before.props.id, ListItemNode.createItemData(child.props));
143
+ public insertBefore(child: ListItemNode | ListSectionNode, before: ListItemNode | ListSectionNode): void {
144
+ if (this.flatStore) {
145
+ if (child instanceof ListSectionNode) {
146
+ this.flatStore.addSection(child.props.id, child.props.value);
147
+ child.setStore(this.flatStore);
148
+ return;
149
+ }
150
+ if (before instanceof ListSectionNode) {
151
+ child.setStore(this.flatStore);
152
+ this.flatStore.addItem(child.props.id, child.props.value);
153
+ return;
154
+ }
155
+ child.setStore(this.flatStore);
156
+ this.flatStore.insertItemBefore(child.props.id, before.props.id, child.props.value);
157
+ } else if (child instanceof ListItemNode && before instanceof ListItemNode && this.treeStore) {
158
+ child.setStore(this.treeStore);
159
+ this.treeStore.insertItemBefore(child.props.id, before.props.id, ListItemNode.createItemData(child.props));
160
+ }
85
161
  }
86
162
 
87
- public removeChild(child: ListItemNode): void {
88
- this.store.removeItem(child.props.id);
89
- child.setStore(null);
163
+ public removeChild(child: ListItemNode | ListSectionNode): void {
164
+ if (this.flatStore) {
165
+ if (child instanceof ListSectionNode) {
166
+ this.flatStore.removeSection(child.props.id);
167
+ child.setStore(null);
168
+ } else {
169
+ this.flatStore.removeItem(child.props.id);
170
+ child.setStore(null);
171
+ }
172
+ } else if (child instanceof ListItemNode && this.treeStore) {
173
+ this.treeStore.removeItem(child.props.id);
174
+ child.setStore(null);
175
+ }
90
176
  }
91
177
 
92
178
  public updateProps(oldProps: ListModelProps | null, newProps: ListModelProps): void {
93
- if (!oldProps || oldProps.autoexpand !== newProps.autoexpand) {
94
- this.treeListModel.setAutoexpand(newProps.autoexpand ?? false);
179
+ if (this.treeListModel) {
180
+ if (!oldProps || oldProps.autoexpand !== newProps.autoexpand) {
181
+ this.treeListModel.setAutoexpand(newProps.autoexpand ?? false);
182
+ }
95
183
  }
96
184
 
97
- this.selectionManager.update(
98
- oldProps ? { ...this.config, ...oldProps } : null,
99
- { ...this.config, ...newProps },
100
- this.treeListModel,
101
- );
185
+ const model = this.flatStore ? this.flatStore.getModel() : this.treeListModel;
186
+ if (model) {
187
+ this.selectionManager.update(
188
+ oldProps ? { ...this.config, ...oldProps } : null,
189
+ { ...this.config, ...newProps },
190
+ model,
191
+ );
192
+ }
193
+ }
194
+
195
+ private getNItems(): number {
196
+ if (this.flatStore) {
197
+ return this.flatStore.getNItems();
198
+ }
199
+ if (this.treeListModel) {
200
+ return this.treeListModel.getNItems();
201
+ }
202
+ return 0;
102
203
  }
103
204
 
104
205
  private getSelection(): string[] {
105
206
  const selection = this.selectionManager.getSelectionModel().getSelection();
207
+
208
+ if (this.flatStore) {
209
+ return getSelectionFromStore(selection, this.flatStore);
210
+ }
211
+
106
212
  const size = selection.getSize();
107
213
  const ids: string[] = [];
108
-
109
214
  for (let i = 0; i < size; i++) {
110
215
  const index = selection.getNth(i);
216
+ if (!this.treeListModel) continue;
111
217
  const row = this.treeListModel.getRow(index);
112
218
  if (!row) continue;
113
-
114
219
  const item = row.getItem();
115
220
  if (item instanceof Gtk.StringObject) {
116
221
  ids.push(item.getString());
@@ -121,8 +226,13 @@ export class ListModel {
121
226
  }
122
227
 
123
228
  private resolveSelectionIndices(ids: string[]): Gtk.Bitset {
124
- const nItems = this.treeListModel.getNItems();
229
+ if (this.flatStore) {
230
+ return resolveSelectionIndices(ids, this.flatStore);
231
+ }
232
+
125
233
  const selected = new Gtk.Bitset();
234
+ if (!this.treeListModel) return selected;
235
+ const nItems = this.treeListModel.getNItems();
126
236
  const idSet = new Set(ids);
127
237
 
128
238
  for (let i = 0; i < nItems; i++) {
@@ -13,25 +13,42 @@ export class ShortcutNode extends VirtualNode<ShortcutProps, EventControllerNode
13
13
  public override isValidParent(parent: Node): boolean {
14
14
  return parent instanceof EventControllerNode && parent.container instanceof Gtk.ShortcutController;
15
15
  }
16
+
16
17
  private shortcut: Gtk.Shortcut | null = null;
17
18
  private action: Gtk.CallbackAction | null = null;
18
19
 
20
+ public override setParent(parent: EventControllerNode<Gtk.ShortcutController> | null): void {
21
+ if (!parent && this.parent) {
22
+ this.removeFromController();
23
+ }
24
+
25
+ super.setParent(parent);
26
+
27
+ if (parent && !this.shortcut) {
28
+ this.createShortcut();
29
+ const shortcut = this.shortcut;
30
+ if (shortcut) parent.container.addShortcut(shortcut);
31
+ }
32
+ }
33
+
19
34
  public override commitUpdate(oldProps: ShortcutProps | null, newProps: ShortcutProps): void {
20
35
  super.commitUpdate(oldProps, newProps);
21
36
  this.applyOwnProps(oldProps, newProps);
22
37
  }
23
38
 
24
39
  public override detachDeletedInstance(): void {
25
- this.shortcut = null;
26
- this.action = null;
40
+ this.removeFromController();
27
41
  super.detachDeletedInstance();
28
42
  }
29
43
 
30
- public getShortcut(): Gtk.Shortcut | null {
31
- return this.shortcut;
44
+ private removeFromController(): void {
45
+ if (!this.parent || !this.shortcut) return;
46
+ this.parent.container.removeShortcut(this.shortcut);
47
+ this.shortcut = null;
48
+ this.action = null;
32
49
  }
33
50
 
34
- public createShortcut(): void {
51
+ private createShortcut(): void {
35
52
  const trigger = this.createTrigger();
36
53
  this.action = new Gtk.CallbackAction(() => {
37
54
  const result = this.props.onActivate();
@@ -49,7 +49,12 @@ export class TextAnchorNode extends VirtualNode<TextAnchorProps, Node & TextCont
49
49
  const iter = new Gtk.TextIter();
50
50
  this.buffer.getIterAtOffset(iter, this.bufferOffset);
51
51
 
52
- this.anchor = this.buffer.createChildAnchor(iter);
52
+ if (this.props.replacementChar) {
53
+ this.anchor = Gtk.TextChildAnchor.newWithReplacement(this.props.replacementChar);
54
+ this.buffer.insertChildAnchor(iter, this.anchor);
55
+ } else {
56
+ this.anchor = this.buffer.createChildAnchor(iter);
57
+ }
53
58
 
54
59
  const widgetChild = this.children[0];
55
60
  if (widgetChild?.container && this.anchor) {
@@ -4,6 +4,7 @@ import type { Node } from "../node.js";
4
4
  import { hasChanged } from "./internal/props.js";
5
5
  import { TextAnchorNode } from "./text-anchor.js";
6
6
  import type { TextContentChild, TextContentParent } from "./text-content.js";
7
+ import { TextPaintableNode } from "./text-paintable.js";
7
8
  import { isTextContentParent, TextSegmentNode } from "./text-segment.js";
8
9
  import { VirtualNode } from "./virtual.js";
9
10
 
@@ -282,6 +283,11 @@ export class TextTagNode
282
283
  }
283
284
 
284
285
  private isTextContentChild(child: Node): child is TextContentChild {
285
- return child instanceof TextSegmentNode || child instanceof TextTagNode || child instanceof TextAnchorNode;
286
+ return (
287
+ child instanceof TextSegmentNode ||
288
+ child instanceof TextTagNode ||
289
+ child instanceof TextAnchorNode ||
290
+ child instanceof TextPaintableNode
291
+ );
286
292
  }
287
293
  }
@@ -52,6 +52,11 @@ export class TextViewNode extends WidgetNode<Gtk.TextView, TextViewProps, TextVi
52
52
  return new TextBufferController(this, this.container, () => new Gtk.TextBuffer());
53
53
  }
54
54
 
55
+ public override finalizeInitialChildren(props: TextViewProps): boolean {
56
+ this.bufferController?.finalizeInitialMount();
57
+ return super.finalizeInitialChildren(props);
58
+ }
59
+
55
60
  public override commitUpdate(oldProps: TextViewProps | null, newProps: TextViewProps): void {
56
61
  super.commitUpdate(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
57
62
  this.ensureBufferController().applyOwnProps(oldProps, newProps);
@@ -12,9 +12,11 @@ import {
12
12
  } from "@gtkx/ffi/gobject";
13
13
  import * as Gtk from "@gtkx/ffi/gtk";
14
14
  import { CONSTRUCTOR_PROPS } from "../generated/internal.js";
15
- import { resolvePropMeta, resolveSignal } from "../metadata.js";
15
+ import { isConstructOnlyProp, resolvePropMeta, resolveSignal } from "../metadata.js";
16
16
  import { Node } from "../node.js";
17
17
  import type { Container, Props } from "../types.js";
18
+ import { applyAccessibleProps, isAccessibleProp } from "./internal/accessible.js";
19
+ import { createContainerWithConstructOnly } from "./internal/construct.js";
18
20
  import {
19
21
  type InsertableWidget,
20
22
  isAddable,
@@ -30,7 +32,7 @@ import { filterProps } from "./internal/props.js";
30
32
  import type { SignalHandler } from "./internal/signal-store.js";
31
33
  import { attachChild, detachChild } from "./internal/widget.js";
32
34
 
33
- const EXCLUDED_PROPS = ["children", "widthRequest", "heightRequest", "grabFocus"];
35
+ const EXCLUDED_PROPS = ["children"];
34
36
 
35
37
  function findProperty(obj: NativeObject, key: string): GObject.ParamSpec | null {
36
38
  const propertyName = key.replace(/([A-Z])/g, "-$1").toLowerCase();
@@ -58,7 +60,11 @@ export class WidgetNode<
58
60
  const typeName = WidgetClass.glibTypeName;
59
61
  const args = (CONSTRUCTOR_PROPS[typeName] ?? []).map((name) => props[name]);
60
62
 
61
- return new WidgetClass(...(args as ConstructorParameters<typeof Gtk.Widget>));
63
+ return createContainerWithConstructOnly(
64
+ WidgetClass,
65
+ props,
66
+ () => new WidgetClass(...(args as ConstructorParameters<typeof Gtk.Widget>)),
67
+ );
62
68
  }
63
69
 
64
70
  public override isValidChild(_child: Node): boolean {
@@ -123,57 +129,54 @@ export class WidgetNode<
123
129
  throw new Error(`Container is undefined for '${this.typeName}'`);
124
130
  }
125
131
 
126
- this.signalStore.blockAll();
127
- try {
128
- this.updateSizeRequest(oldProps, newProps);
129
- this.updateGrabFocus(oldProps, newProps);
132
+ applyAccessibleProps(this.container, oldProps, newProps);
130
133
 
131
- const propNames = new Set([
132
- ...Object.keys(filterProps(oldProps ?? {}, EXCLUDED_PROPS)),
133
- ...Object.keys(filterProps(newProps ?? {}, EXCLUDED_PROPS)),
134
- ]);
134
+ const propNames = new Set([
135
+ ...Object.keys(filterProps(oldProps ?? {}, EXCLUDED_PROPS)),
136
+ ...Object.keys(filterProps(newProps ?? {}, EXCLUDED_PROPS)),
137
+ ]);
135
138
 
136
- const pendingSignals: Array<{ name: string; newValue: unknown }> = [];
137
- const pendingProperties: Array<{ name: string; oldValue: unknown; newValue: unknown }> = [];
139
+ const pendingSignals: Array<{ name: string; newValue: unknown }> = [];
140
+ const pendingProperties: Array<{ name: string; oldValue: unknown; newValue: unknown }> = [];
138
141
 
139
- for (const name of propNames) {
140
- const oldValue = oldProps?.[name];
141
- const newValue = newProps[name];
142
+ for (const name of propNames) {
143
+ if (isAccessibleProp(name)) continue;
144
+ if (isConstructOnlyProp(this.container, name)) continue;
142
145
 
143
- if (oldValue === newValue) continue;
146
+ const oldValue = oldProps?.[name];
147
+ const newValue = newProps[name];
144
148
 
145
- const signalName = resolveSignal(this.container, name);
149
+ if (oldValue === newValue) continue;
146
150
 
147
- if (signalName) {
148
- pendingSignals.push({ name, newValue });
149
- } else if (newValue !== undefined) {
150
- pendingProperties.push({ name, oldValue, newValue });
151
- } else if (oldValue !== undefined) {
152
- const defaultValue = this.getPropertyDefaultValue(name);
153
- if (defaultValue !== undefined) {
154
- pendingProperties.push({ name, oldValue, newValue: defaultValue });
155
- }
151
+ const signalName = resolveSignal(this.container, name);
152
+
153
+ if (signalName) {
154
+ pendingSignals.push({ name, newValue });
155
+ } else if (newValue !== undefined) {
156
+ pendingProperties.push({ name, oldValue, newValue });
157
+ } else if (oldValue !== undefined) {
158
+ const defaultValue = this.getPropertyDefaultValue(name);
159
+ if (defaultValue !== undefined) {
160
+ pendingProperties.push({ name, oldValue, newValue: defaultValue });
156
161
  }
157
162
  }
163
+ }
158
164
 
159
- for (const { name, newValue } of pendingSignals) {
160
- const signalName = resolveSignal(this.container, name);
161
- if (!signalName) continue;
162
- const handler = typeof newValue === "function" ? (newValue as SignalHandler) : undefined;
163
- this.signalStore.set(this, this.container, signalName, handler);
164
- }
165
+ for (const { name, newValue } of pendingSignals) {
166
+ const signalName = resolveSignal(this.container, name);
167
+ if (!signalName) continue;
168
+ const handler = typeof newValue === "function" ? (newValue as SignalHandler) : undefined;
169
+ this.signalStore.set(this, this.container, signalName, handler);
170
+ }
165
171
 
166
- for (const { name, oldValue, newValue } of pendingProperties) {
167
- if (name === "text" && oldValue !== undefined && isEditable(this.container)) {
168
- if (oldValue !== this.container.getText()) {
169
- continue;
170
- }
172
+ for (const { name, oldValue, newValue } of pendingProperties) {
173
+ if (name === "text" && oldValue !== undefined && isEditable(this.container)) {
174
+ if (oldValue !== this.container.getText()) {
175
+ continue;
171
176
  }
172
-
173
- this.setProperty(name, newValue);
174
177
  }
175
- } finally {
176
- this.signalStore.unblockAll();
178
+
179
+ this.setProperty(name, newValue);
177
180
  }
178
181
  }
179
182
 
@@ -276,26 +279,6 @@ export class WidgetNode<
276
279
  }
277
280
  }
278
281
 
279
- private updateSizeRequest(oldProps: P | null, newProps: P): void {
280
- const oldWidth = oldProps?.widthRequest as number | undefined;
281
- const oldHeight = oldProps?.heightRequest as number | undefined;
282
- const newWidth = newProps.widthRequest as number | undefined;
283
- const newHeight = newProps.heightRequest as number | undefined;
284
-
285
- if (oldWidth !== newWidth || oldHeight !== newHeight) {
286
- this.container.setSizeRequest(newWidth ?? -1, newHeight ?? -1);
287
- }
288
- }
289
-
290
- private updateGrabFocus(oldProps: P | null, newProps: P): void {
291
- const oldGrabFocus = oldProps?.grabFocus as boolean | undefined;
292
- const newGrabFocus = newProps.grabFocus as boolean | undefined;
293
-
294
- if (!oldGrabFocus && newGrabFocus) {
295
- this.container.grabFocus();
296
- }
297
- }
298
-
299
282
  private getPropertyDefaultValue(key: string): unknown {
300
283
  if (!resolvePropMeta(this.container, key)) return undefined;
301
284
 
package/src/registry.ts CHANGED
@@ -23,6 +23,7 @@ import { GridChildNode } from "./nodes/grid-child.js";
23
23
  import { GridViewNode } from "./nodes/grid-view.js";
24
24
  import { LevelBarNode } from "./nodes/level-bar.js";
25
25
  import { ListItemNode } from "./nodes/list-item.js";
26
+ import { ListSectionNode } from "./nodes/list-section.js";
26
27
  import { ListViewNode } from "./nodes/list-view.js";
27
28
  import { MenuNode } from "./nodes/menu.js";
28
29
  import { NavigationPageNode } from "./nodes/navigation-page.js";
@@ -36,7 +37,6 @@ import { ScaleNode } from "./nodes/scale.js";
36
37
  import { ScrolledWindowNode } from "./nodes/scrolled-window.js";
37
38
  import { SearchBarNode } from "./nodes/search-bar.js";
38
39
  import { ShortcutNode } from "./nodes/shortcut.js";
39
- import { ShortcutControllerNode } from "./nodes/shortcut-controller.js";
40
40
  import { SlotNode } from "./nodes/slot.js";
41
41
  import { SourceViewNode } from "./nodes/source-view.js";
42
42
  import { StackNode } from "./nodes/stack.js";
@@ -80,11 +80,13 @@ export const NODE_REGISTRY: NodeRegistryEntry[] = [
80
80
  ["FixedChild", FixedChildNode],
81
81
  ["GridChild", GridChildNode],
82
82
  ["ListItem", ListItemNode],
83
+ ["ListSection", ListSectionNode],
83
84
  [["MenuItem", "MenuSection", "MenuSubmenu"], MenuNode],
84
85
  ["NavigationPage", NavigationPageNode],
85
86
  ["NotebookPage", NotebookPageNode],
86
87
  ["NotebookPageTab", NotebookPageTabNode],
87
88
  ["OverlayChild", OverlayChildNode],
89
+
88
90
  ["Shortcut", ShortcutNode],
89
91
  ["Slot", SlotNode],
90
92
  ["StackPage", StackPageNode],
@@ -94,7 +96,7 @@ export const NODE_REGISTRY: NodeRegistryEntry[] = [
94
96
  ["TextTag", TextTagNode],
95
97
  ["Toggle", ToggleNode],
96
98
  [Gtk.Application, ApplicationNode],
97
- [Gtk.ShortcutController, ShortcutControllerNode],
99
+
98
100
  [Gtk.EventController, EventControllerNode],
99
101
  [GtkSource.View, SourceViewNode],
100
102
  [Gtk.TextView, TextViewNode],
@@ -1,28 +0,0 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
2
- import type { GtkGridViewProps } from "../../jsx.js";
3
- import { ListStore } from "../internal/list-store.js";
4
- import type { SignalStore } from "../internal/signal-store.js";
5
- import type { ListItemNode } from "../list-item.js";
6
- export type GridModelProps = Pick<GtkGridViewProps, "selectionMode" | "selected" | "onSelectionChanged">;
7
- type GridModelConfig = {
8
- owner: object;
9
- signalStore: SignalStore;
10
- };
11
- export declare class GridModel {
12
- private config;
13
- private store;
14
- private selectionManager;
15
- private initialSelected;
16
- constructor(config: GridModelConfig, props?: GridModelProps);
17
- flushBatch(): void;
18
- getStore(): ListStore;
19
- getSelectionModel(): Gtk.NoSelection | Gtk.SingleSelection | Gtk.MultiSelection;
20
- appendChild(child: ListItemNode): void;
21
- insertBefore(child: ListItemNode, before: ListItemNode): void;
22
- removeChild(child: ListItemNode): void;
23
- updateProps(oldProps: GridModelProps | null, newProps: GridModelProps): void;
24
- private getSelection;
25
- private resolveSelectionIndices;
26
- }
27
- export {};
28
- //# sourceMappingURL=grid.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/nodes/models/grid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,EAAE,eAAe,GAAG,UAAU,GAAG,oBAAoB,CAAC,CAAC;AAEzG,KAAK,eAAe,GAAG;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,WAAW,CAAC;CAC5B,CAAC;AAEF,qBAAa,SAAS;IAClB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,gBAAgB,CAA2B;IAEnD,OAAO,CAAC,eAAe,CAA8B;gBAEzC,MAAM,EAAE,eAAe,EAAE,KAAK,GAAE,cAAmB;IAcxD,UAAU,IAAI,IAAI;IAMlB,QAAQ,IAAI,SAAS;IAIrB,iBAAiB,IAAI,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,eAAe,GAAG,GAAG,CAAC,cAAc;IAI/E,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAKtC,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IAK7D,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAKtC,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAQnF,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,uBAAuB;CAclC"}
@@ -1,69 +0,0 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
2
- import { ListStore } from "../internal/list-store.js";
3
- import { SelectionModelController } from "../internal/selection-model-controller.js";
4
- export class GridModel {
5
- config;
6
- store;
7
- selectionManager;
8
- initialSelected;
9
- constructor(config, props = {}) {
10
- this.config = config;
11
- this.store = new ListStore();
12
- this.store.beginBatch();
13
- this.initialSelected = props.selected;
14
- this.selectionManager = new SelectionModelController({ ...config, ...props }, this.store.getModel(), () => this.getSelection(), (ids) => this.resolveSelectionIndices(ids), () => this.store.getModel().getNItems());
15
- }
16
- flushBatch() {
17
- this.store.flushBatch();
18
- this.selectionManager.reapplySelection(this.initialSelected);
19
- this.initialSelected = undefined;
20
- }
21
- getStore() {
22
- return this.store;
23
- }
24
- getSelectionModel() {
25
- return this.selectionManager.getSelectionModel();
26
- }
27
- appendChild(child) {
28
- child.setStore(this.store);
29
- this.store.addItem(child.props.id, child.props.value);
30
- }
31
- insertBefore(child, before) {
32
- child.setStore(this.store);
33
- this.store.insertItemBefore(child.props.id, before.props.id, child.props.value);
34
- }
35
- removeChild(child) {
36
- this.store.removeItem(child.props.id);
37
- child.setStore(null);
38
- }
39
- updateProps(oldProps, newProps) {
40
- this.selectionManager.update(oldProps ? { ...this.config, ...oldProps } : null, { ...this.config, ...newProps }, this.store.getModel());
41
- }
42
- getSelection() {
43
- const model = this.store.getModel();
44
- const selection = this.selectionManager.getSelectionModel().getSelection();
45
- const size = selection.getSize();
46
- const ids = [];
47
- for (let i = 0; i < size; i++) {
48
- const index = selection.getNth(i);
49
- const id = model.getString(index);
50
- if (id !== null) {
51
- ids.push(id);
52
- }
53
- }
54
- return ids;
55
- }
56
- resolveSelectionIndices(ids) {
57
- const model = this.store.getModel();
58
- const nItems = model.getNItems();
59
- const selected = new Gtk.Bitset();
60
- for (const id of ids) {
61
- const index = model.find(id);
62
- if (index < nItems) {
63
- selected.add(index);
64
- }
65
- }
66
- return selected;
67
- }
68
- }
69
- //# sourceMappingURL=grid.js.map