@gtkx/react 1.4.0 → 1.5.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.
@@ -2,8 +2,6 @@ import type * as Gtk from "@gtkx/gi/gtk";
2
2
  import * as Adw from "@gtkx/gi/adw";
3
3
  import type { AlertDialogResponse } from "./prop-types.js";
4
4
  import {
5
- addRemoveSlot,
6
- adoptedChildrenSlot,
7
5
  applicationCreator,
8
6
  boxSlot,
9
7
  childMatcher,
@@ -12,6 +10,8 @@ import {
12
10
  deferred,
13
11
  indexedSlot,
14
12
  list,
13
+ methodSlot,
14
+ setterSlot,
15
15
  slot,
16
16
  } from "../reconciler/behaviors.js";
17
17
  import { type ElementBehavior, type ElementConfig, forTypes, registerElements } from "../reconciler/registry.js";
@@ -36,56 +36,18 @@ type PrefixSuffixRow = Adw.ActionRow | Adw.EntryRow | Adw.ExpanderRow;
36
36
  const SLOT_SUFFIX = "Slot";
37
37
  const childSetter = childSetterSlot<AdwChildSetter>();
38
38
  const contentSetter = contentSetterSlot<AdwContentSetter>();
39
-
40
- const breakpoints = slot<BreakpointHost, Adw.Breakpoint>("breakpoints", "AdwBreakpoint", {
41
- attach: (host, breakpoint) => {
42
- host.addBreakpoint(breakpoint);
43
- },
44
- });
39
+ const breakpoints = methodSlot<BreakpointHost, Adw.Breakpoint>("breakpoints", "AdwBreakpoint", "addBreakpoint");
45
40
 
46
41
  const prefixSuffix = [
47
- addRemoveSlot<Gtk.Widget, PrefixSuffixRow>(
48
- "prefix",
49
- "GtkWidget",
50
- (row, child) => {
51
- row.addPrefix(child);
52
- },
53
- (row, child) => {
54
- row.remove(child);
55
- },
56
- ),
57
- addRemoveSlot<Gtk.Widget, PrefixSuffixRow>(
58
- "suffix",
59
- "GtkWidget",
60
- (row, child) => {
61
- row.addSuffix(child);
62
- },
63
- (row, child) => {
64
- row.remove(child);
65
- },
66
- ),
42
+ methodSlot<PrefixSuffixRow, Gtk.Widget>("prefix", "GtkWidget", "addPrefix", "remove"),
43
+ methodSlot<PrefixSuffixRow, Gtk.Widget>("suffix", "GtkWidget", "addSuffix", "remove"),
67
44
  ];
68
45
 
69
- const preferencesDialogChildren = addRemoveSlot<Adw.PreferencesPage, Adw.PreferencesDialog>(
70
- "children",
71
- "AdwPreferencesPage",
72
- (dialog, page) => {
73
- dialog.add(page);
74
- },
75
- (dialog, page) => {
76
- dialog.remove(page);
77
- },
46
+ const preferencesDialogChildren = methodSlot<Adw.PreferencesDialog, Adw.PreferencesPage>(
47
+ "children", "AdwPreferencesPage", "add", "remove",
78
48
  );
79
49
 
80
- const alertDialogExtraChild = slot<Adw.AlertDialog, Gtk.Widget>("children", "GtkWidget", {
81
- attach: (dialog, child) => {
82
- dialog.setExtraChild(child);
83
- },
84
- detach: (dialog) => {
85
- dialog.setExtraChild(null);
86
- },
87
- });
88
-
50
+ const alertDialogExtraChild = setterSlot<Adw.AlertDialog, Gtk.Widget>("children", "GtkWidget", "setExtraChild");
89
51
  const sidebarSections = indexedSlot<Adw.Sidebar, Adw.SidebarSection>("children", "AdwSidebarSection");
90
52
  const sidebarItems = indexedSlot<Adw.SidebarSection, Adw.SidebarItem>("children", "AdwSidebarItem");
91
53
  const isWidget = childMatcher("GtkWidget");
@@ -151,14 +113,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
151
113
  },
152
114
  AdwClampScrollable: {
153
115
  behaviors: [
154
- slot<Adw.ClampScrollable, Gtk.Scrollable & Gtk.Widget>("children", "GtkScrollable", {
155
- attach: (clamp, child) => {
156
- clamp.setChild(child);
157
- },
158
- detach: (clamp) => {
159
- clamp.setChild(null);
160
- },
161
- }),
116
+ setterSlot<Adw.ClampScrollable, Gtk.Scrollable & Gtk.Widget>("children", "GtkScrollable", "setChild"),
162
117
  ],
163
118
  },
164
119
  ...forTypes(CHILD_SETTER_TYPES, {
@@ -179,15 +134,8 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
179
134
  AdwBreakpointBin: {
180
135
  behaviors: [
181
136
  childSetter,
182
- addRemoveSlot<Adw.Breakpoint, Adw.BreakpointBin>(
183
- "breakpoints",
184
- "AdwBreakpoint",
185
- (bin, breakpoint) => {
186
- bin.addBreakpoint(breakpoint);
187
- },
188
- (bin, breakpoint) => {
189
- bin.removeBreakpoint(breakpoint);
190
- },
137
+ methodSlot<Adw.BreakpointBin, Adw.Breakpoint>(
138
+ "breakpoints", "AdwBreakpoint", "addBreakpoint", "removeBreakpoint",
191
139
  ),
192
140
  ],
193
141
  },
@@ -200,16 +148,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
200
148
  AdwExpanderRow: {
201
149
  behaviors: [
202
150
  ...prefixSuffix,
203
- addRemoveSlot<Gtk.Widget, Adw.ExpanderRow>(
204
- "rows",
205
- "GtkWidget",
206
- (row, child) => {
207
- row.addRow(child);
208
- },
209
- (row, child) => {
210
- row.remove(child);
211
- },
212
- ),
151
+ methodSlot<Adw.ExpanderRow, Gtk.Widget>("rows", "GtkWidget", "addRow", "remove"),
213
152
  ],
214
153
  },
215
154
  AdwNavigationSplitView: {
@@ -249,18 +188,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
249
188
  behaviors: [preferencesDialogChildren],
250
189
  },
251
190
  AdwPreferencesGroup: {
252
- behaviors: [
253
- addRemoveSlot<Gtk.Widget, Adw.PreferencesGroup>(
254
- "children",
255
- "GtkWidget",
256
- (group, child) => {
257
- group.add(child);
258
- },
259
- (group, child) => {
260
- group.remove(child);
261
- },
262
- ),
263
- ],
191
+ behaviors: [methodSlot<Adw.PreferencesGroup, Gtk.Widget>("children", "GtkWidget", "add", "remove")],
264
192
  },
265
193
  AdwTabView: {
266
194
  behaviors: [
@@ -282,105 +210,37 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
282
210
  },
283
211
  AdwNavigationView: {
284
212
  behaviors: [
285
- addRemoveSlot<Adw.NavigationPage, Adw.NavigationView>(
286
- "children",
287
- "AdwNavigationPage",
288
- (view, page) => {
289
- view.add(page);
290
- },
291
- (view, page) => {
292
- view.remove(page);
293
- },
294
- ),
213
+ methodSlot<Adw.NavigationView, Adw.NavigationPage>("children", "AdwNavigationPage", "add", "remove"),
295
214
  ],
296
215
  },
297
216
  AdwViewStack: {
298
217
  behaviors: [
299
- adoptedChildrenSlot<Adw.ViewStack, Gtk.Widget>(
300
- "GtkWidget",
301
- (stack, child) => stack.add(child),
302
- (stack, child) => {
303
- stack.remove(child);
304
- },
305
- ),
218
+ methodSlot<Adw.ViewStack, Gtk.Widget>("children", "GtkWidget", "add", "remove"),
306
219
  deferred<Adw.ViewStack, string>("visibleChildName", (stack, name) => stack.getChildByName(name) !== null),
307
220
  ],
308
221
  },
309
222
  AdwToolbarView: {
310
223
  behaviors: [
311
224
  contentSetterSlot<Adw.ToolbarView>(),
312
- addRemoveSlot<Gtk.Widget, Adw.ToolbarView>(
313
- "topBar",
314
- "GtkWidget",
315
- (view, child) => {
316
- view.addTopBar(child);
317
- },
318
- (view, child) => {
319
- view.remove(child);
320
- },
321
- ),
322
- addRemoveSlot<Gtk.Widget, Adw.ToolbarView>(
323
- "bottomBar",
324
- "GtkWidget",
325
- (view, child) => {
326
- view.addBottomBar(child);
327
- },
328
- (view, child) => {
329
- view.remove(child);
330
- },
331
- ),
225
+ methodSlot<Adw.ToolbarView, Gtk.Widget>("topBar", "GtkWidget", "addTopBar", "remove"),
226
+ methodSlot<Adw.ToolbarView, Gtk.Widget>("bottomBar", "GtkWidget", "addBottomBar", "remove"),
332
227
  ],
333
228
  },
334
229
  AdwHeaderBar: {
335
230
  behaviors: [
336
- slot<Adw.HeaderBar, Gtk.Widget>("start", "GtkWidget", {
337
- attach: (bar, child) => {
338
- bar.packStart(child);
339
- },
340
- detach: (bar, child) => {
341
- bar.remove(child);
342
- },
343
- }),
344
- slot<Adw.HeaderBar, Gtk.Widget>("end", "GtkWidget", {
345
- attach: (bar, child) => {
346
- bar.packEnd(child);
347
- },
348
- detach: (bar, child) => {
349
- bar.remove(child);
350
- },
351
- }),
231
+ methodSlot<Adw.HeaderBar, Gtk.Widget>("start", "GtkWidget", "packStart", "remove"),
232
+ methodSlot<Adw.HeaderBar, Gtk.Widget>("end", "GtkWidget", "packEnd", "remove"),
352
233
  ],
353
234
  },
354
235
  AdwShortcutsDialog: {
355
- behaviors: [
356
- slot<Adw.ShortcutsDialog, Adw.ShortcutsSection>("children", "AdwShortcutsSection", {
357
- attach: (dialog, section) => {
358
- dialog.add(section);
359
- },
360
- }),
361
- ],
236
+ behaviors: [methodSlot<Adw.ShortcutsDialog, Adw.ShortcutsSection>("children", "AdwShortcutsSection", "add")],
362
237
  },
363
238
  AdwShortcutsSection: {
364
- behaviors: [
365
- slot<Adw.ShortcutsSection, Adw.ShortcutsItem>("children", "AdwShortcutsItem", {
366
- attach: (section, item) => {
367
- section.add(item);
368
- },
369
- }),
370
- ],
239
+ behaviors: [methodSlot<Adw.ShortcutsSection, Adw.ShortcutsItem>("children", "AdwShortcutsItem", "add")],
371
240
  },
372
241
  AdwToggleGroup: {
373
242
  behaviors: [
374
- addRemoveSlot<Adw.Toggle, Adw.ToggleGroup>(
375
- "children",
376
- "AdwToggle",
377
- (group, toggle) => {
378
- group.add(toggle);
379
- },
380
- (group, toggle) => {
381
- group.remove(toggle);
382
- },
383
- ),
243
+ methodSlot<Adw.ToggleGroup, Adw.Toggle>("children", "AdwToggle", "add", "remove"),
384
244
  deferred<Adw.ToggleGroup, string>("activeName", (group, name) => group.getToggleByName(name) !== null),
385
245
  deferred("active"),
386
246
  ],
@@ -14,14 +14,15 @@ import type {
14
14
  } from "./prop-types.js";
15
15
  import { BUILTIN_ELEMENTS, SINGLE_CHILD_TYPES } from "./element-config.js";
16
16
  import {
17
- addRemoveSlot,
18
- adoptedChildrenSlot,
19
17
  applicationCreator,
20
18
  boxSlot,
21
19
  childSetterSlot,
22
20
  controlledText,
23
21
  deferred,
22
+ deferredWith,
24
23
  list,
24
+ methodSlot,
25
+ setterSlot,
25
26
  slot,
26
27
  value,
27
28
  wrappingIndexedSlot,
@@ -36,8 +37,6 @@ import {
36
37
  import { applyWrite } from "./reconciler/signals.js";
37
38
  import { applyStyle, CSS_CLASSES_PROP, styleClass } from "./reconciler/style.js";
38
39
 
39
- type SelectedIndexState = { desired: number | undefined; isScheduled: boolean; disconnect: (() => void) | null };
40
-
41
40
  const SELECTED_INDEX_PROP = "selectedIndex";
42
41
  const SELECTION_SIGNAL = "selected-rows-changed";
43
42
  const NO_SELECTION = -1;
@@ -48,26 +47,8 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
48
47
  }),
49
48
  ...forTypes(["GtkHeaderBar", "GtkActionBar"], {
50
49
  behaviors: [
51
- addRemoveSlot<Gtk.Widget, Gtk.HeaderBar | Gtk.ActionBar>(
52
- "start",
53
- "GtkWidget",
54
- (bar, child) => {
55
- bar.packStart(child);
56
- },
57
- (bar, child) => {
58
- bar.remove(child);
59
- },
60
- ),
61
- addRemoveSlot<Gtk.Widget, Gtk.HeaderBar | Gtk.ActionBar>(
62
- "end",
63
- "GtkWidget",
64
- (bar, child) => {
65
- bar.packEnd(child);
66
- },
67
- (bar, child) => {
68
- bar.remove(child);
69
- },
70
- ),
50
+ methodSlot<Gtk.HeaderBar | Gtk.ActionBar, Gtk.Widget>("start", "GtkWidget", "packStart", "remove"),
51
+ methodSlot<Gtk.HeaderBar | Gtk.ActionBar, Gtk.Widget>("end", "GtkWidget", "packEnd", "remove"),
71
52
  ],
72
53
  }),
73
54
  GtkWindow: {
@@ -83,24 +64,10 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
83
64
  popover.unparent();
84
65
  },
85
66
  }),
86
- addRemoveSlot<Gtk.EventController, Gtk.Widget>(
87
- "controllers",
88
- "GtkEventController",
89
- (widget, controller) => {
90
- widget.addController(controller);
91
- },
92
- (widget, controller) => {
93
- widget.removeController(controller);
94
- },
67
+ methodSlot<Gtk.Widget, Gtk.EventController>(
68
+ "controllers", "GtkEventController", "addController", "removeController",
95
69
  ),
96
- slot<Gtk.Widget, Gtk.LayoutManager>("layoutManager", "GtkLayoutManager", {
97
- attach: (widget, manager) => {
98
- widget.setLayoutManager(manager);
99
- },
100
- detach: (widget) => {
101
- widget.setLayoutManager(null);
102
- },
103
- }),
70
+ setterSlot<Gtk.Widget, Gtk.LayoutManager>("layoutManager", "GtkLayoutManager", "setLayoutManager"),
104
71
  slot<Gtk.Widget, Gio.ActionGroup>("actionGroups", "GActionGroup", {
105
72
  attach: (widget, group, info) => {
106
73
  widget.insertActionGroup((info.props.prefix as string | null) ?? "", group);
@@ -146,15 +113,8 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
146
113
  },
147
114
  GtkShortcutController: {
148
115
  behaviors: [
149
- addRemoveSlot<Gtk.Shortcut, Gtk.ShortcutController>(
150
- "shortcuts",
151
- "GtkShortcut",
152
- (controller, shortcut) => {
153
- controller.addShortcut(shortcut);
154
- },
155
- (controller, shortcut) => {
156
- controller.removeShortcut(shortcut);
157
- },
116
+ methodSlot<Gtk.ShortcutController, Gtk.Shortcut>(
117
+ "shortcuts", "GtkShortcut", "addShortcut", "removeShortcut",
158
118
  ),
159
119
  ],
160
120
  },
@@ -162,16 +122,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
162
122
  behaviors: [{ create: () => Gtk.TextChildAnchor.new() }],
163
123
  },
164
124
  GtkTextView: {
165
- behaviors: [
166
- slot<Gtk.TextView, Gtk.TextBuffer>("children", "GtkTextBuffer", {
167
- attach: (view, buffer) => {
168
- view.setBuffer(buffer);
169
- },
170
- detach: (view) => {
171
- view.setBuffer(null);
172
- },
173
- }),
174
- ],
125
+ behaviors: [setterSlot<Gtk.TextView, Gtk.TextBuffer>("children", "GtkTextBuffer", "setBuffer")],
175
126
  },
176
127
  GActionMap: {
177
128
  behaviors: [
@@ -249,25 +200,11 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
249
200
  },
250
201
  GtkConstraintLayout: {
251
202
  behaviors: [
252
- addRemoveSlot<Gtk.Constraint, Gtk.ConstraintLayout>(
253
- "constraints",
254
- "GtkConstraint",
255
- (layout, constraint) => {
256
- layout.addConstraint(constraint);
257
- },
258
- (layout, constraint) => {
259
- layout.removeConstraint(constraint);
260
- },
203
+ methodSlot<Gtk.ConstraintLayout, Gtk.Constraint>(
204
+ "constraints", "GtkConstraint", "addConstraint", "removeConstraint",
261
205
  ),
262
- addRemoveSlot<Gtk.ConstraintGuide, Gtk.ConstraintLayout>(
263
- "guides",
264
- "GtkConstraintGuide",
265
- (layout, guide) => {
266
- layout.addGuide(guide);
267
- },
268
- (layout, guide) => {
269
- layout.removeGuide(guide);
270
- },
206
+ methodSlot<Gtk.ConstraintLayout, Gtk.ConstraintGuide>(
207
+ "guides", "GtkConstraintGuide", "addGuide", "removeGuide",
271
208
  ),
272
209
  list<Gtk.ConstraintLayout, VflConstraints, Gtk.Constraint[]>("vfl", {
273
210
  add: (layout, item) => [
@@ -288,13 +225,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
288
225
  },
289
226
  GtkStack: {
290
227
  behaviors: [
291
- adoptedChildrenSlot<Gtk.Stack, Gtk.Widget>(
292
- "GtkWidget",
293
- (stack, child) => stack.addChild(child),
294
- (stack, child) => {
295
- stack.remove(child);
296
- },
297
- ),
228
+ methodSlot<Gtk.Stack, Gtk.Widget>("children", "GtkWidget", "addChild", "remove"),
298
229
  deferred<Gtk.Stack, string>("visibleChildName", (stack, name) => stack.getChildByName(name) !== null),
299
230
  ],
300
231
  },
@@ -315,16 +246,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
315
246
  GtkApplication: {
316
247
  behaviors: [
317
248
  applicationCreator(Gtk.Application),
318
- addRemoveSlot<Gtk.Window, Gtk.Application>(
319
- "children",
320
- "GtkWindow",
321
- (application, window) => {
322
- application.addWindow(window);
323
- },
324
- (application, window) => {
325
- application.removeWindow(window);
326
- },
327
- ),
249
+ methodSlot<Gtk.Application, Gtk.Window>("children", "GtkWindow", "addWindow", "removeWindow"),
328
250
  list<Gtk.Application, ActionAccel>("actionAccels", {
329
251
  add: (application, item) => {
330
252
  application.setAccelsForAction(item.detailedActionName, item.accels);
@@ -494,89 +416,27 @@ function desiredIndex(value: unknown): number | undefined {
494
416
  return value;
495
417
  }
496
418
 
497
- function selectRowAt(box: Gtk.ListBox, row: Gtk.ListBoxRow): void {
498
- applyWrite(SELECTED_INDEX_PROP, () => {
499
- box.selectRow(row);
500
- });
501
- }
502
-
503
- function clearSelection(box: Gtk.ListBox): void {
504
- applyWrite(SELECTED_INDEX_PROP, () => {
419
+ function applySelectedIndex(box: Gtk.ListBox, index: number): void {
420
+ if (index < 0) {
505
421
  box.unselectAll();
506
- });
507
- }
508
-
509
- function applySelectedIndex(box: Gtk.ListBox, state: SelectedIndexState): void {
510
- const { desired } = state;
511
422
 
512
- if (desired === undefined || selectedRowIndex(box) === desired) {
513
423
  return;
514
424
  }
515
425
 
516
- if (desired < 0) {
517
- clearSelection(box);
518
-
519
- return;
520
- }
521
-
522
- const row = box.getRowAtIndex(desired);
426
+ const row = box.getRowAtIndex(index);
523
427
 
524
428
  if (row !== null) {
525
- selectRowAt(box, row);
526
- }
527
- }
528
-
529
- function scheduleSelectedIndex(box: Gtk.ListBox, state: SelectedIndexState): void {
530
- if (state.isScheduled) {
531
- return;
532
- }
533
-
534
- state.isScheduled = true;
535
-
536
- queueMicrotask(() => {
537
- state.isScheduled = false;
538
-
539
- if (state.disconnect !== null) {
540
- applySelectedIndex(box, state);
541
- }
542
- });
543
- }
544
-
545
- function watchSelectionDrift(box: Gtk.ListBox, state: SelectedIndexState): void {
546
- if (state.disconnect !== null) {
547
- return;
429
+ box.selectRow(row);
548
430
  }
549
-
550
- const handler = (): undefined => {
551
- scheduleSelectedIndex(box, state);
552
- };
553
-
554
- box.on(SELECTION_SIGNAL, handler);
555
-
556
- state.disconnect = (): void => {
557
- box.off(SELECTION_SIGNAL, handler);
558
- };
559
431
  }
560
432
 
561
433
  function selectedIndexBehavior(): ElementBehavior<Gtk.ListBox> {
562
- return {
563
- deferred: [SELECTED_INDEX_PROP],
564
- initialize: (): SelectedIndexState => ({ desired: undefined, isScheduled: false, disconnect: null }),
565
- update: (_box, _prev, next, context) => {
566
- (context as SelectedIndexState).desired = desiredIndex(next[SELECTED_INDEX_PROP]);
567
-
568
- return [SELECTED_INDEX_PROP];
569
- },
570
- flush: (box, context) => {
571
- applySelectedIndex(box, context as SelectedIndexState);
572
- watchSelectionDrift(box, context as SelectedIndexState);
573
- },
574
- teardown: (_box, context) => {
575
- const state = context as SelectedIndexState;
576
- state.disconnect?.();
577
- state.disconnect = null;
578
- },
579
- };
434
+ return deferredWith<Gtk.ListBox, number>(SELECTED_INDEX_PROP, {
435
+ parse: desiredIndex,
436
+ read: selectedRowIndex,
437
+ write: applySelectedIndex,
438
+ signal: SELECTION_SIGNAL,
439
+ });
580
440
  }
581
441
 
582
442
  const addMainOption = (application: Gtk.Application, option: MainOption): void => {