@gtkx/react 0.17.2 → 0.18.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 (194) hide show
  1. package/README.md +7 -7
  2. package/dist/factory.d.ts +0 -1
  3. package/dist/factory.js +21 -8
  4. package/dist/generated/internal.d.ts +4 -51
  5. package/dist/generated/internal.js +626 -412
  6. package/dist/generated/jsx.d.ts +453 -958
  7. package/dist/host-config.d.ts +1 -1
  8. package/dist/host-config.js +18 -23
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/jsx.d.ts +579 -302
  12. package/dist/jsx.js +37 -179
  13. package/dist/metadata.d.ts +3 -0
  14. package/dist/metadata.js +26 -0
  15. package/dist/node.d.ts +20 -12
  16. package/dist/node.js +72 -17
  17. package/dist/nodes/adjustable.d.ts +3 -16
  18. package/dist/nodes/adjustable.js +5 -22
  19. package/dist/nodes/alert-dialog-response.d.ts +14 -1
  20. package/dist/nodes/alert-dialog-response.js +36 -62
  21. package/dist/nodes/animation.d.ts +37 -1
  22. package/dist/nodes/animation.js +162 -105
  23. package/dist/nodes/application.d.ts +11 -1
  24. package/dist/nodes/application.js +17 -38
  25. package/dist/nodes/calendar.d.ts +13 -0
  26. package/dist/nodes/calendar.js +10 -16
  27. package/dist/nodes/color-dialog-button.d.ts +13 -0
  28. package/dist/nodes/color-dialog-button.js +10 -38
  29. package/dist/nodes/column-view-column.d.ts +13 -11
  30. package/dist/nodes/column-view-column.js +27 -23
  31. package/dist/nodes/column-view.d.ts +31 -0
  32. package/dist/nodes/column-view.js +44 -44
  33. package/dist/nodes/container-slot.d.ts +15 -0
  34. package/dist/nodes/container-slot.js +68 -0
  35. package/dist/nodes/dialog.d.ts +6 -8
  36. package/dist/nodes/dialog.js +12 -13
  37. package/dist/nodes/drawing-area.d.ts +12 -0
  38. package/dist/nodes/drawing-area.js +24 -24
  39. package/dist/nodes/drop-down.d.ts +22 -0
  40. package/dist/nodes/drop-down.js +72 -0
  41. package/dist/nodes/event-controller.d.ts +8 -17
  42. package/dist/nodes/event-controller.js +20 -42
  43. package/dist/nodes/fixed-child.d.ts +18 -1
  44. package/dist/nodes/fixed-child.js +52 -36
  45. package/dist/nodes/font-dialog-button.d.ts +13 -0
  46. package/dist/nodes/font-dialog-button.js +12 -35
  47. package/dist/nodes/grid-child.d.ts +17 -1
  48. package/dist/nodes/grid-child.js +57 -37
  49. package/dist/nodes/grid-view.d.ts +24 -0
  50. package/dist/nodes/grid-view.js +73 -0
  51. package/dist/nodes/internal/base-item-renderer.d.ts +7 -9
  52. package/dist/nodes/internal/base-item-renderer.js +15 -18
  53. package/dist/nodes/internal/grid-item-renderer.d.ts +17 -0
  54. package/dist/nodes/internal/grid-item-renderer.js +59 -0
  55. package/dist/nodes/internal/list-item-renderer.d.ts +14 -9
  56. package/dist/nodes/internal/list-item-renderer.js +96 -35
  57. package/dist/nodes/internal/list-store.d.ts +5 -0
  58. package/dist/nodes/internal/list-store.js +39 -9
  59. package/dist/nodes/internal/predicates.d.ts +4 -19
  60. package/dist/nodes/internal/predicates.js +1 -20
  61. package/dist/nodes/internal/props.d.ts +5 -0
  62. package/dist/nodes/internal/props.js +42 -0
  63. package/dist/nodes/internal/{selection-model.d.ts → selection-model-controller.d.ts} +4 -9
  64. package/dist/nodes/internal/{selection-model.js → selection-model-controller.js} +6 -15
  65. package/dist/nodes/internal/signal-store.js +12 -5
  66. package/dist/nodes/internal/simple-list-store.d.ts +5 -0
  67. package/dist/nodes/internal/simple-list-store.js +42 -13
  68. package/dist/nodes/internal/text-buffer-controller.d.ts +4 -12
  69. package/dist/nodes/internal/text-buffer-controller.js +32 -33
  70. package/dist/nodes/internal/tree-store.d.ts +7 -0
  71. package/dist/nodes/internal/tree-store.js +75 -18
  72. package/dist/nodes/internal/widget.d.ts +7 -0
  73. package/dist/nodes/internal/widget.js +68 -0
  74. package/dist/nodes/level-bar.d.ts +10 -0
  75. package/dist/nodes/level-bar.js +11 -22
  76. package/dist/nodes/list-item.d.ts +17 -9
  77. package/dist/nodes/list-item.js +67 -12
  78. package/dist/nodes/list-view.d.ts +23 -0
  79. package/dist/nodes/list-view.js +27 -31
  80. package/dist/nodes/menu.d.ts +2 -4
  81. package/dist/nodes/menu.js +0 -6
  82. package/dist/nodes/models/grid.d.ts +27 -0
  83. package/dist/nodes/models/grid.js +68 -0
  84. package/dist/nodes/models/list.d.ts +15 -13
  85. package/dist/nodes/models/list.js +48 -26
  86. package/dist/nodes/models/menu.d.ts +15 -16
  87. package/dist/nodes/models/menu.js +63 -93
  88. package/dist/nodes/navigation-page.d.ts +16 -10
  89. package/dist/nodes/navigation-page.js +108 -31
  90. package/dist/nodes/navigation-view.d.ts +15 -0
  91. package/dist/nodes/navigation-view.js +15 -65
  92. package/dist/nodes/notebook-page-tab.d.ts +10 -12
  93. package/dist/nodes/notebook-page-tab.js +24 -27
  94. package/dist/nodes/notebook-page.d.ts +19 -16
  95. package/dist/nodes/notebook-page.js +75 -56
  96. package/dist/nodes/notebook.d.ts +10 -1
  97. package/dist/nodes/notebook.js +10 -22
  98. package/dist/nodes/overlay-child.d.ts +17 -1
  99. package/dist/nodes/overlay-child.js +53 -75
  100. package/dist/nodes/popover-menu.d.ts +15 -0
  101. package/dist/nodes/popover-menu.js +13 -26
  102. package/dist/nodes/scale.d.ts +8 -0
  103. package/dist/nodes/scale.js +2 -11
  104. package/dist/nodes/scrolled-window.d.ts +9 -0
  105. package/dist/nodes/scrolled-window.js +5 -11
  106. package/dist/nodes/search-bar.d.ts +9 -0
  107. package/dist/nodes/search-bar.js +8 -33
  108. package/dist/nodes/shortcut-controller.d.ts +9 -1
  109. package/dist/nodes/shortcut-controller.js +12 -25
  110. package/dist/nodes/shortcut.d.ts +11 -33
  111. package/dist/nodes/shortcut.js +19 -15
  112. package/dist/nodes/slot.d.ts +16 -15
  113. package/dist/nodes/slot.js +63 -57
  114. package/dist/nodes/source-view.d.ts +16 -0
  115. package/dist/nodes/source-view.js +44 -44
  116. package/dist/nodes/stack-page.d.ts +21 -1
  117. package/dist/nodes/stack-page.js +68 -17
  118. package/dist/nodes/stack.d.ts +11 -0
  119. package/dist/nodes/stack.js +8 -26
  120. package/dist/nodes/text-anchor.d.ts +11 -30
  121. package/dist/nodes/text-anchor.js +20 -22
  122. package/dist/nodes/text-content.d.ts +1 -0
  123. package/dist/nodes/text-content.js +1 -1
  124. package/dist/nodes/text-paintable.d.ts +10 -15
  125. package/dist/nodes/text-paintable.js +16 -9
  126. package/dist/nodes/text-segment.d.ts +12 -10
  127. package/dist/nodes/text-segment.js +19 -11
  128. package/dist/nodes/text-tag.d.ts +20 -119
  129. package/dist/nodes/text-tag.js +153 -119
  130. package/dist/nodes/text-view.d.ts +13 -18
  131. package/dist/nodes/text-view.js +17 -17
  132. package/dist/nodes/toggle-group.d.ts +9 -0
  133. package/dist/nodes/toggle-group.js +8 -33
  134. package/dist/nodes/toggle.d.ts +15 -1
  135. package/dist/nodes/toggle.js +34 -52
  136. package/dist/nodes/virtual.d.ts +3 -10
  137. package/dist/nodes/virtual.js +1 -14
  138. package/dist/nodes/web-view.d.ts +9 -0
  139. package/dist/nodes/web-view.js +10 -24
  140. package/dist/nodes/widget.d.ts +17 -13
  141. package/dist/nodes/widget.js +185 -112
  142. package/dist/nodes/window.d.ts +20 -21
  143. package/dist/nodes/window.js +54 -35
  144. package/dist/registry.d.ts +17 -6
  145. package/dist/registry.js +104 -5
  146. package/dist/render.d.ts +1 -10
  147. package/dist/render.js +1 -13
  148. package/package.json +6 -6
  149. package/dist/animation/css-builder.d.ts +0 -3
  150. package/dist/animation/css-builder.js +0 -53
  151. package/dist/animation/types.d.ts +0 -120
  152. package/dist/animation/types.js +0 -1
  153. package/dist/nodes/abstract/positional-child.d.ts +0 -9
  154. package/dist/nodes/abstract/positional-child.js +0 -29
  155. package/dist/nodes/abstract/virtual-container.d.ts +0 -21
  156. package/dist/nodes/abstract/virtual-container.js +0 -68
  157. package/dist/nodes/abstract/virtual-single-child.d.ts +0 -18
  158. package/dist/nodes/abstract/virtual-single-child.js +0 -55
  159. package/dist/nodes/action-row-child.d.ts +0 -1
  160. package/dist/nodes/action-row-child.js +0 -30
  161. package/dist/nodes/autowrapped.d.ts +0 -1
  162. package/dist/nodes/autowrapped.js +0 -115
  163. package/dist/nodes/expander-row-child.d.ts +0 -1
  164. package/dist/nodes/expander-row-child.js +0 -30
  165. package/dist/nodes/grid.d.ts +0 -1
  166. package/dist/nodes/grid.js +0 -41
  167. package/dist/nodes/index.d.ts +0 -56
  168. package/dist/nodes/index.js +0 -56
  169. package/dist/nodes/internal/child-attachment.d.ts +0 -26
  170. package/dist/nodes/internal/child-attachment.js +0 -48
  171. package/dist/nodes/internal/deferred-action.d.ts +0 -9
  172. package/dist/nodes/internal/deferred-action.js +0 -22
  173. package/dist/nodes/internal/text-tag-styles.d.ts +0 -43
  174. package/dist/nodes/internal/text-tag-styles.js +0 -52
  175. package/dist/nodes/internal/tree-list-item-renderer.d.ts +0 -26
  176. package/dist/nodes/internal/tree-list-item-renderer.js +0 -134
  177. package/dist/nodes/internal/utils.d.ts +0 -12
  178. package/dist/nodes/internal/utils.js +0 -92
  179. package/dist/nodes/models/tree-list.d.ts +0 -28
  180. package/dist/nodes/models/tree-list.js +0 -113
  181. package/dist/nodes/pack-child.d.ts +0 -1
  182. package/dist/nodes/pack-child.js +0 -30
  183. package/dist/nodes/simple-list-item.d.ts +0 -9
  184. package/dist/nodes/simple-list-item.js +0 -9
  185. package/dist/nodes/simple-list-view.d.ts +0 -1
  186. package/dist/nodes/simple-list-view.js +0 -74
  187. package/dist/nodes/toolbar-child.d.ts +0 -1
  188. package/dist/nodes/toolbar-child.js +0 -30
  189. package/dist/nodes/tree-list-item.d.ts +0 -22
  190. package/dist/nodes/tree-list-item.js +0 -90
  191. package/dist/nodes/tree-list-view.d.ts +0 -1
  192. package/dist/nodes/tree-list-view.js +0 -77
  193. package/dist/scheduler.d.ts +0 -26
  194. package/dist/scheduler.js +0 -42
package/dist/jsx.js CHANGED
@@ -16,8 +16,8 @@ import { createElement } from "react";
16
16
  * </GtkHeaderBar>
17
17
  *
18
18
  * <GtkDropDown>
19
- * <x.SimpleListItem id="opt1" value="Option 1" />
20
- * <x.SimpleListItem id="opt2" value="Option 2" />
19
+ * <x.ListItem id="opt1" value="Option 1" />
20
+ * <x.ListItem id="opt2" value="Option 2" />
21
21
  * </GtkDropDown>
22
22
  * ```
23
23
  */
@@ -97,40 +97,26 @@ export const x = {
97
97
  */
98
98
  NotebookPageTab: "NotebookPageTab",
99
99
  /**
100
- * Element type for items in a ListView or GridView.
100
+ * Element type for items in a GtkListView, GtkGridView, or GtkColumnView.
101
101
  *
102
- * @example
103
- * ```tsx
104
- * <x.ListView renderItem={(item) => <GtkLabel label={item.name} />}>
105
- * <x.ListItem id="1" value={{ name: "Item 1" }} />
106
- * </x.ListView>
107
- * ```
108
- */
109
- ListItem: "ListItem",
110
- /**
111
- * Element type for items in a TreeListView.
102
+ * Items can be nested to create tree hierarchies inside a GtkListView.
112
103
  *
113
104
  * @example
114
105
  * ```tsx
115
- * <x.TreeListView renderItem={(item) => <GtkLabel label={item.name} />}>
116
- * <x.TreeListItem id="parent" value={{ name: "Parent" }}>
117
- * <x.TreeListItem id="child" value={{ name: "Child" }} />
118
- * </x.TreeListItem>
119
- * </x.TreeListView>
120
- * ```
121
- */
122
- TreeListItem: "TreeListItem",
123
- /**
124
- * Element type for simple string-based list items.
106
+ * // Flat list
107
+ * <GtkListView renderItem={(item) => <GtkLabel label={item.name} />}>
108
+ * <x.ListItem id="1" value={{ name: "Item 1" }} />
109
+ * </GtkListView>
125
110
  *
126
- * @example
127
- * ```tsx
128
- * <GtkDropDown>
129
- * <x.SimpleListItem id="opt1" value="Option 1" />
130
- * </GtkDropDown>
111
+ * // Tree list (nested items)
112
+ * <GtkListView renderItem={(item, row) => <GtkLabel label={item.name} />} autoexpand>
113
+ * <x.ListItem id="parent" value={{ name: "Parent" }}>
114
+ * <x.ListItem id="child" value={{ name: "Child" }} />
115
+ * </x.ListItem>
116
+ * </GtkListView>
131
117
  * ```
132
118
  */
133
- SimpleListItem: "SimpleListItem",
119
+ ListItem: "ListItem",
134
120
  /**
135
121
  * Component for defining columns in a ColumnView (table widget).
136
122
  *
@@ -150,124 +136,39 @@ export const x = {
150
136
  return createElement("ColumnViewColumn", props);
151
137
  },
152
138
  /**
153
- * Virtualized list component with custom item rendering.
154
- *
155
- * @example
156
- * ```tsx
157
- * <x.ListView renderItem={(item) => <GtkLabel label={item?.name ?? ""} />}>
158
- * <x.ListItem id="1" value={{ name: "Apple" }} />
159
- * </x.ListView>
160
- * ```
161
- */
162
- ListView(props) {
163
- return createElement("GtkListView", props);
164
- },
165
- /**
166
- * Virtualized grid component with custom item rendering.
167
- *
168
- * @example
169
- * ```tsx
170
- * <x.GridView renderItem={(item) => <GtkImage iconName={item?.icon ?? ""} />}>
171
- * <x.ListItem id="1" value={{ icon: "folder" }} />
172
- * </x.GridView>
173
- * ```
174
- */
175
- GridView(props) {
176
- return createElement("GtkGridView", props);
177
- },
178
- /**
179
- * Tree list component with hierarchical data and expand/collapse support.
139
+ * Type-safe container slot for placing children via parent widget methods.
180
140
  *
181
- * @example
182
- * ```tsx
183
- * <x.TreeListView renderItem={(item, row) => <GtkLabel label={item.name} />}>
184
- * <x.TreeListItem id="root" value={{ name: "Root" }}>
185
- * <x.TreeListItem id="child" value={{ name: "Child" }} />
186
- * </x.TreeListItem>
187
- * </x.TreeListView>
188
- * ```
189
- */
190
- TreeListView(props) {
191
- return createElement("TreeListView", props);
192
- },
193
- /**
194
- * Place child as a prefix (left side) of AdwActionRow, AdwEntryRow, or AdwExpanderRow.
141
+ * Unlike `x.Slot` (which uses property setters for single-child slots),
142
+ * `x.ContainerSlot` calls attachment methods that support multiple children
143
+ * (e.g., `addPrefix()`, `packStart()`, `addTopBar()`).
195
144
  *
196
- * @example
197
- * ```tsx
198
- * <AdwActionRow title="Setting">
199
- * <x.ActionRowPrefix>
200
- * <GtkCheckButton />
201
- * </x.ActionRowPrefix>
202
- * </AdwActionRow>
203
- * ```
204
- */
205
- ActionRowPrefix: "ActionRowPrefix",
206
- /**
207
- * Place child as a suffix (right side) of AdwActionRow, AdwEntryRow, or AdwExpanderRow.
145
+ * The `for` prop provides TypeScript type narrowing for the `id` prop
146
+ * and is not used at runtime.
208
147
  *
209
148
  * @example
210
149
  * ```tsx
211
- * <AdwActionRow title="Setting">
212
- * <x.ActionRowSuffix>
213
- * <GtkButton iconName="go-next-symbolic" />
214
- * </x.ActionRowSuffix>
215
- * </AdwActionRow>
216
- * ```
217
- */
218
- ActionRowSuffix: "ActionRowSuffix",
219
- /**
220
- * Place child at the start (left in LTR) of HeaderBar or ActionBar.
150
+ * <AdwToolbarView>
151
+ * <x.ContainerSlot for={AdwToolbarView} id="addTopBar">
152
+ * <AdwHeaderBar />
153
+ * </x.ContainerSlot>
154
+ * </AdwToolbarView>
221
155
  *
222
- * @example
223
- * ```tsx
224
156
  * <GtkHeaderBar>
225
- * <x.PackStart>
157
+ * <x.ContainerSlot for={GtkHeaderBar} id="packStart">
226
158
  * <GtkButton label="Back" />
227
- * </x.PackStart>
159
+ * </x.ContainerSlot>
228
160
  * </GtkHeaderBar>
229
- * ```
230
- */
231
- PackStart: "PackStart",
232
- /**
233
- * Place child at the end (right in LTR) of HeaderBar or ActionBar.
234
- *
235
- * @example
236
- * ```tsx
237
- * <GtkHeaderBar>
238
- * <x.PackEnd>
239
- * <GtkMenuButton />
240
- * </x.PackEnd>
241
- * </GtkHeaderBar>
242
- * ```
243
- */
244
- PackEnd: "PackEnd",
245
- /**
246
- * Place toolbar at the top of AdwToolbarView.
247
161
  *
248
- * @example
249
- * ```tsx
250
- * <AdwToolbarView>
251
- * <x.ToolbarTop>
252
- * <AdwHeaderBar />
253
- * </x.ToolbarTop>
254
- * </AdwToolbarView>
255
- * ```
256
- */
257
- ToolbarTop: "ToolbarTop",
258
- /**
259
- * Place toolbar at the bottom of AdwToolbarView.
260
- *
261
- * @example
262
- * ```tsx
263
- * <AdwToolbarView>
264
- * <x.ToolbarBottom>
265
- * <GtkActionBar />
266
- * </x.ToolbarBottom>
267
- * </AdwToolbarView>
162
+ * <AdwActionRow title="Setting">
163
+ * <x.ContainerSlot for={AdwActionRow} id="addPrefix">
164
+ * <GtkCheckButton />
165
+ * </x.ContainerSlot>
166
+ * </AdwActionRow>
268
167
  * ```
269
168
  */
270
- ToolbarBottom: "ToolbarBottom",
169
+ ContainerSlot(props) {
170
+ return createElement("ContainerSlot", { id: props.id }, props.children);
171
+ },
271
172
  /**
272
173
  * Element type for overlay children positioned above the main content.
273
174
  *
@@ -391,33 +292,6 @@ export const x = {
391
292
  * ```
392
293
  */
393
294
  AlertDialogResponse: "AlertDialogResponse",
394
- /**
395
- * Nested rows container for AdwExpanderRow.
396
- *
397
- * @example
398
- * ```tsx
399
- * <AdwExpanderRow title="Settings">
400
- * <ExpanderRow.Row>
401
- * <AdwActionRow title="Option 1" />
402
- * <AdwActionRow title="Option 2" />
403
- * </ExpanderRow.Row>
404
- * </AdwExpanderRow>
405
- * ```
406
- */
407
- ExpanderRowRow: "ExpanderRowRow",
408
- /**
409
- * Action widget container for AdwExpanderRow header.
410
- *
411
- * @example
412
- * ```tsx
413
- * <AdwExpanderRow title="Group">
414
- * <ExpanderRow.Action>
415
- * <GtkButton iconName="emblem-system-symbolic" />
416
- * </ExpanderRow.Action>
417
- * </AdwExpanderRow>
418
- * ```
419
- */
420
- ExpanderRowAction: "ExpanderRowAction",
421
295
  /**
422
296
  * Type-safe page component for AdwNavigationView or AdwNavigationSplitView.
423
297
  *
@@ -446,22 +320,6 @@ export const x = {
446
320
  * ```
447
321
  */
448
322
  NavigationPage: "NavigationPage",
449
- /**
450
- * Declarative keyboard shortcut controller.
451
- *
452
- * Attach keyboard shortcuts to a widget. Must contain `x.Shortcut` children.
453
- *
454
- * @example
455
- * ```tsx
456
- * <GtkBox>
457
- * <GtkShortcutController scope={Gtk.ShortcutScope.GLOBAL}>
458
- * <x.Shortcut trigger="<Control>f" onActivate={() => setSearchMode(s => !s)} />
459
- * <x.Shortcut trigger="<Control>q" onActivate={quit} />
460
- * </GtkShortcutController>
461
- * </GtkBox>
462
- * ```
463
- */
464
- ShortcutController: "GtkShortcutController",
465
323
  /**
466
324
  * A keyboard shortcut definition.
467
325
  *
@@ -483,9 +341,9 @@ export const x = {
483
341
  * @example
484
342
  * ```tsx
485
343
  * <x.Animation
486
- * mode="spring"
487
344
  * initial={{ opacity: 0, scale: 0.9 }}
488
345
  * animate={{ opacity: 1, scale: 1 }}
346
+ * transition={{ mode: "spring", damping: 0.8, stiffness: 200 }}
489
347
  * animateOnMount
490
348
  * >
491
349
  * <GtkButton label="Animated Button" />
@@ -0,0 +1,3 @@
1
+ import type { Container } from "./types.js";
2
+ export declare const resolvePropMeta: (instance: Container, key: string) => [string | null, string] | null;
3
+ export declare const resolveSignal: (instance: Container, propName: string) => string | null;
@@ -0,0 +1,26 @@
1
+ import { PROPS, SIGNALS } from "./generated/internal.js";
2
+ const walkPrototypeChain = (instance, lookup) => {
3
+ // biome-ignore lint/complexity/noBannedTypes: Walking prototype chain requires Function type
4
+ let current = instance.constructor;
5
+ while (current) {
6
+ const typeName = current.glibTypeName;
7
+ if (typeName) {
8
+ const result = lookup(typeName);
9
+ if (result !== null) {
10
+ return result;
11
+ }
12
+ }
13
+ const prototype = Object.getPrototypeOf(current.prototype);
14
+ current = prototype?.constructor ?? null;
15
+ if (current === Object || current === Function) {
16
+ break;
17
+ }
18
+ }
19
+ return null;
20
+ };
21
+ export const resolvePropMeta = (instance, key) => walkPrototypeChain(instance, (typeName) => PROPS[typeName]?.[key] ?? null);
22
+ export const resolveSignal = (instance, propName) => {
23
+ if (propName === "onNotify")
24
+ return "notify";
25
+ return walkPrototypeChain(instance, (typeName) => SIGNALS[typeName]?.[propName] ?? null);
26
+ };
package/dist/node.d.ts CHANGED
@@ -1,18 +1,26 @@
1
1
  import { type SignalStore } from "./nodes/internal/signal-store.js";
2
2
  import type { Container, ContainerClass, Props } from "./types.js";
3
- export declare class Node<T = unknown, P = Props> {
4
- static priority: number;
5
- static matches(_type: string, _containerOrClass?: Container | ContainerClass | null): boolean;
3
+ export declare class Node<TContainer = any, TProps = any, TParent extends Node = any, TChild extends Node = any> {
6
4
  static createContainer(_props: Props, _containerClass: ContainerClass, _rootContainer?: Container): unknown;
7
- container: T;
5
+ container: TContainer;
6
+ props: TProps;
8
7
  typeName: string;
9
8
  signalStore: SignalStore;
10
- constructor(typeName: string, _props: P | undefined, container: T, rootContainer: Container);
11
- appendChild(_child: Node): void;
12
- removeChild(_child: Node): void;
13
- insertBefore(_child: Node, _before: Node): void;
14
- updateProps(_oldProps: P | null, _newProps: P): void;
15
- mount(): void;
16
- commitProps(oldProps: P | null, newProps: P): void;
17
- unmount(): void;
9
+ rootContainer: Container;
10
+ parent: TParent | null;
11
+ children: TChild[];
12
+ private childIndices;
13
+ constructor(typeName: string, props: TProps, container: TContainer, rootContainer: Container);
14
+ isValidChild(_child: Node): boolean;
15
+ isValidParent(_parent: Node): boolean;
16
+ setParent(parent: TParent | null): void;
17
+ appendInitialChild(child: TChild): void;
18
+ appendChild(child: TChild): void;
19
+ removeChild(child: TChild): void;
20
+ insertBefore(child: TChild, before: TChild): void;
21
+ private rebuildChildIndices;
22
+ finalizeInitialChildren(props: TProps): boolean;
23
+ commitUpdate(_oldProps: TProps | null, newProps: TProps): void;
24
+ commitMount(): void;
25
+ detachDeletedInstance(): void;
18
26
  }
package/dist/node.js CHANGED
@@ -1,35 +1,90 @@
1
1
  import { getSignalStore } from "./nodes/internal/signal-store.js";
2
+ // biome-ignore lint/suspicious/noExplicitAny: Self-referential type bounds require any
2
3
  export class Node {
3
- static priority = 0;
4
- static matches(_type, _containerOrClass) {
5
- return false;
6
- }
7
4
  static createContainer(_props, _containerClass, _rootContainer) {
8
5
  throw new Error("Cannot create container: unsupported node type");
9
6
  }
10
7
  container;
8
+ props;
11
9
  typeName;
12
10
  signalStore;
13
- constructor(typeName, _props = {}, container, rootContainer) {
11
+ rootContainer;
12
+ parent = null;
13
+ children = [];
14
+ childIndices = new Map();
15
+ constructor(typeName, props, container, rootContainer) {
14
16
  this.typeName = typeName;
17
+ this.props = props;
15
18
  this.container = container;
19
+ this.rootContainer = rootContainer;
16
20
  this.signalStore = getSignalStore(rootContainer);
17
21
  }
18
- appendChild(_child) { }
19
- removeChild(_child) { }
20
- insertBefore(_child, _before) { }
21
- updateProps(_oldProps, _newProps) { }
22
- mount() { }
23
- commitProps(oldProps, newProps) {
24
- this.signalStore.blockAll();
25
- try {
26
- this.updateProps(oldProps, newProps);
22
+ isValidChild(_child) {
23
+ return false;
24
+ }
25
+ isValidParent(_parent) {
26
+ return true;
27
+ }
28
+ setParent(parent) {
29
+ if (parent !== null && !this.isValidParent(parent)) {
30
+ throw new Error(`Cannot add '${this.typeName}' to '${parent.typeName}'`);
31
+ }
32
+ this.parent = parent;
33
+ }
34
+ appendInitialChild(child) {
35
+ this.appendChild(child);
36
+ }
37
+ appendChild(child) {
38
+ if (!this.isValidChild(child)) {
39
+ throw new Error(`Cannot append '${child.typeName}' to '${this.typeName}'`);
40
+ }
41
+ this.childIndices.set(child, this.children.length);
42
+ this.children.push(child);
43
+ child.setParent(this);
44
+ }
45
+ removeChild(child) {
46
+ const index = this.childIndices.get(child);
47
+ if (index !== undefined) {
48
+ child.setParent(null);
49
+ this.children.splice(index, 1);
50
+ this.childIndices.delete(child);
51
+ this.rebuildChildIndices(index);
52
+ }
53
+ }
54
+ insertBefore(child, before) {
55
+ const beforeIndex = this.childIndices.get(before);
56
+ if (beforeIndex === undefined) {
57
+ throw new Error(`Cannot find 'before' child '${before.typeName}' in '${this.typeName}'`);
27
58
  }
28
- finally {
29
- this.signalStore.unblockAll();
59
+ const existingIndex = this.childIndices.get(child);
60
+ if (existingIndex !== undefined) {
61
+ this.children.splice(existingIndex, 1);
62
+ const adjustedIndex = existingIndex < beforeIndex ? beforeIndex - 1 : beforeIndex;
63
+ this.children.splice(adjustedIndex, 0, child);
64
+ this.rebuildChildIndices(Math.min(existingIndex, adjustedIndex));
65
+ return;
30
66
  }
67
+ if (!this.isValidChild(child)) {
68
+ throw new Error(`Cannot insert '${child.typeName}' into '${this.typeName}'`);
69
+ }
70
+ this.children.splice(beforeIndex, 0, child);
71
+ this.rebuildChildIndices(beforeIndex);
72
+ child.setParent(this);
73
+ }
74
+ rebuildChildIndices(fromIndex) {
75
+ for (let i = fromIndex; i < this.children.length; i++) {
76
+ this.childIndices.set(this.children[i], i);
77
+ }
78
+ }
79
+ finalizeInitialChildren(props) {
80
+ this.commitUpdate(null, props);
81
+ return false;
82
+ }
83
+ commitUpdate(_oldProps, newProps) {
84
+ this.props = newProps;
31
85
  }
32
- unmount() {
86
+ commitMount() { }
87
+ detachDeletedInstance() {
33
88
  this.signalStore.clear(this);
34
89
  }
35
90
  }
@@ -1,23 +1,10 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import type { Container, ContainerClass, Props } from "../types.js";
3
- import type { AdjustableWidget } from "./internal/predicates.js";
2
+ import type { AdjustableProps } from "../jsx.js";
3
+ import type { AdjustableWidget } from "../registry.js";
4
4
  import { WidgetNode } from "./widget.js";
5
- type AdjustableProps = Props & {
6
- value?: number;
7
- lower?: number;
8
- upper?: number;
9
- stepIncrement?: number;
10
- pageIncrement?: number;
11
- pageSize?: number;
12
- onValueChanged?: ((value: number, self: AdjustableWidget) => void) | null;
13
- };
14
5
  export declare class AdjustableNode<T extends AdjustableWidget = AdjustableWidget> extends WidgetNode<T, AdjustableProps> {
15
- static priority: number;
16
6
  private adjustment;
17
- static matches(_type: string, containerOrClass?: Container | ContainerClass | null): boolean;
18
- updateProps(oldProps: AdjustableProps | null, newProps: AdjustableProps): void;
7
+ commitUpdate(oldProps: AdjustableProps | null, newProps: AdjustableProps): void;
19
8
  protected ensureAdjustment(props: AdjustableProps): Gtk.Adjustment;
20
9
  protected applyOwnProps(oldProps: AdjustableProps | null, newProps: AdjustableProps): void;
21
- private updateValueChangedHandler;
22
10
  }
23
- export {};
@@ -1,17 +1,11 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import { ADJUSTABLE_INTERFACE_METHODS } from "../generated/internal.js";
3
- import { registerNodeClass } from "../registry.js";
4
- import { filterProps, hasChanged, matchesInterface } from "./internal/utils.js";
2
+ import { filterProps, hasChanged } from "./internal/props.js";
5
3
  import { WidgetNode } from "./widget.js";
6
4
  const OWN_PROPS = ["value", "lower", "upper", "stepIncrement", "pageIncrement", "pageSize", "onValueChanged"];
7
5
  export class AdjustableNode extends WidgetNode {
8
- static priority = 2;
9
6
  adjustment = null;
10
- static matches(_type, containerOrClass) {
11
- return matchesInterface(ADJUSTABLE_INTERFACE_METHODS, containerOrClass);
12
- }
13
- updateProps(oldProps, newProps) {
14
- super.updateProps(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
7
+ commitUpdate(oldProps, newProps) {
8
+ super.commitUpdate(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
15
9
  this.applyOwnProps(oldProps, newProps);
16
10
  }
17
11
  ensureAdjustment(props) {
@@ -24,7 +18,8 @@ export class AdjustableNode extends WidgetNode {
24
18
  applyOwnProps(oldProps, newProps) {
25
19
  const adjustment = this.ensureAdjustment(newProps);
26
20
  if (hasChanged(oldProps, newProps, "onValueChanged")) {
27
- this.updateValueChangedHandler(newProps);
21
+ const { onValueChanged } = newProps;
22
+ this.signalStore.set(this, this.container, "value-changed", onValueChanged ? (self) => onValueChanged(self.getValue(), self) : undefined);
28
23
  }
29
24
  if (!oldProps)
30
25
  return;
@@ -47,16 +42,4 @@ export class AdjustableNode extends WidgetNode {
47
42
  adjustment.setValue(newProps.value);
48
43
  }
49
44
  }
50
- updateValueChangedHandler(props) {
51
- if (!this.adjustment)
52
- return;
53
- const { onValueChanged } = props;
54
- if (onValueChanged) {
55
- this.signalStore.set(this, this.container, "value-changed", (self) => onValueChanged(self.getValue(), self));
56
- }
57
- else {
58
- this.signalStore.set(this, this.container, "value-changed", null);
59
- }
60
- }
61
45
  }
62
- registerNodeClass(AdjustableNode);
@@ -1 +1,14 @@
1
- export {};
1
+ import * as Adw from "@gtkx/ffi/adw";
2
+ import type { AlertDialogResponseProps } from "../jsx.js";
3
+ import type { Node } from "../node.js";
4
+ import { VirtualNode } from "./virtual.js";
5
+ import { WidgetNode } from "./widget.js";
6
+ export declare class AlertDialogResponseNode extends VirtualNode<AlertDialogResponseProps, WidgetNode<Adw.AlertDialog>> {
7
+ private responseId;
8
+ isValidParent(parent: Node): boolean;
9
+ setParent(parent: WidgetNode<Adw.AlertDialog> | null): void;
10
+ commitUpdate(oldProps: AlertDialogResponseProps | null, newProps: AlertDialogResponseProps): void;
11
+ detachDeletedInstance(): void;
12
+ private removeFromDialog;
13
+ private applyOwnProps;
14
+ }
@@ -1,86 +1,60 @@
1
1
  import * as Adw from "@gtkx/ffi/adw";
2
- import { registerNodeClass } from "../registry.js";
3
- import { CommitPriority, scheduleAfterCommit } from "../scheduler.js";
4
- import { hasChanged } from "./internal/utils.js";
2
+ import { hasChanged } from "./internal/props.js";
5
3
  import { VirtualNode } from "./virtual.js";
6
4
  import { WidgetNode } from "./widget.js";
7
- class AlertDialogResponseNode extends VirtualNode {
8
- static priority = 1;
9
- dialog = null;
5
+ export class AlertDialogResponseNode extends VirtualNode {
10
6
  responseId = null;
11
- static matches(type) {
12
- return type === "AlertDialogResponse";
13
- }
14
- canBeChildOf(parent) {
7
+ isValidParent(parent) {
15
8
  return parent instanceof WidgetNode && parent.container instanceof Adw.AlertDialog;
16
9
  }
17
- attachTo(parent) {
18
- if (!(parent instanceof WidgetNode) || !(parent.container instanceof Adw.AlertDialog)) {
19
- return;
10
+ setParent(parent) {
11
+ if (!parent && this.parent) {
12
+ this.removeFromDialog();
13
+ }
14
+ super.setParent(parent);
15
+ if (parent && !this.responseId) {
16
+ this.responseId = this.props.id;
17
+ parent.container.addResponse(this.responseId, this.props.label);
18
+ this.applyOwnProps(null, this.props);
20
19
  }
21
- if (this.dialog)
22
- return;
23
- this.dialog = parent.container;
24
- this.responseId = this.props.id;
25
- const dialog = this.dialog;
26
- const id = this.responseId;
27
- const label = this.props.label;
28
- scheduleAfterCommit(() => {
29
- if (this.dialog) {
30
- dialog.addResponse(id, label);
31
- this.applyOptionalProps(null, this.props);
32
- }
33
- }, CommitPriority.NORMAL);
34
- }
35
- detachFrom(_parent) {
36
- this.removeFromDialog();
37
- }
38
- removeFromDialog() {
39
- if (!this.dialog || !this.responseId)
40
- return;
41
- const dialog = this.dialog;
42
- const id = this.responseId;
43
- this.dialog = null;
44
- this.responseId = null;
45
- scheduleAfterCommit(() => {
46
- dialog.removeResponse(id);
47
- }, CommitPriority.HIGH);
48
20
  }
49
- updateProps(oldProps, newProps) {
50
- super.updateProps(oldProps, newProps);
51
- if (!this.dialog || !this.responseId)
21
+ commitUpdate(oldProps, newProps) {
22
+ super.commitUpdate(oldProps, newProps);
23
+ if (!this.parent || !this.responseId)
52
24
  return;
53
25
  if (hasChanged(oldProps, newProps, "id")) {
54
26
  const oldId = this.responseId;
55
27
  const newId = newProps.id;
56
- const dialog = this.dialog;
57
28
  const label = newProps.label;
29
+ this.parent.container.removeResponse(oldId);
58
30
  this.responseId = newId;
59
- scheduleAfterCommit(() => {
60
- dialog.removeResponse(oldId);
61
- dialog.addResponse(newId, label);
62
- this.applyOptionalProps(null, newProps);
63
- }, CommitPriority.NORMAL);
31
+ this.parent.container.addResponse(newId, label);
32
+ this.applyOwnProps(null, newProps);
64
33
  return;
65
34
  }
66
35
  if (hasChanged(oldProps, newProps, "label")) {
67
- this.dialog.setResponseLabel(this.responseId, newProps.label);
36
+ this.parent.container.setResponseLabel(this.responseId, newProps.label);
68
37
  }
69
- this.applyOptionalProps(oldProps, newProps);
38
+ this.applyOwnProps(oldProps, newProps);
39
+ }
40
+ detachDeletedInstance() {
41
+ this.removeFromDialog();
42
+ super.detachDeletedInstance();
70
43
  }
71
- applyOptionalProps(oldProps, newProps) {
72
- if (!this.dialog || !this.responseId)
44
+ removeFromDialog() {
45
+ if (!this.parent || !this.responseId)
73
46
  return;
74
- if (hasChanged(oldProps, newProps, "appearance") && newProps.appearance !== undefined) {
75
- this.dialog.setResponseAppearance(this.responseId, newProps.appearance);
47
+ this.parent.container.removeResponse(this.responseId);
48
+ this.responseId = null;
49
+ }
50
+ applyOwnProps(oldProps, newProps) {
51
+ if (!this.parent || !this.responseId)
52
+ return;
53
+ if (hasChanged(oldProps, newProps, "appearance")) {
54
+ this.parent.container.setResponseAppearance(this.responseId, newProps.appearance ?? Adw.ResponseAppearance.DEFAULT);
76
55
  }
77
- if (hasChanged(oldProps, newProps, "enabled") && newProps.enabled !== undefined) {
78
- this.dialog.setResponseEnabled(this.responseId, newProps.enabled);
56
+ if (hasChanged(oldProps, newProps, "enabled")) {
57
+ this.parent.container.setResponseEnabled(this.responseId, newProps.enabled ?? true);
79
58
  }
80
59
  }
81
- unmount() {
82
- this.removeFromDialog();
83
- super.unmount();
84
- }
85
60
  }
86
- registerNodeClass(AlertDialogResponseNode);