@gtkx/react 1.4.0 → 1.6.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.
- package/README.md +1 -1
- package/dist/adw/element-behaviors.js +35 -120
- package/dist/adw/element-behaviors.js.map +1 -1
- package/dist/components/element.d.ts +6 -1
- package/dist/components/element.d.ts.map +1 -1
- package/dist/components/element.js +6 -3
- package/dist/components/element.js.map +1 -1
- package/dist/element-behaviors.js +29 -124
- package/dist/element-behaviors.js.map +1 -1
- package/dist/reconciler/behaviors.d.ts +27 -8
- package/dist/reconciler/behaviors.d.ts.map +1 -1
- package/dist/reconciler/behaviors.js +60 -31
- package/dist/reconciler/behaviors.js.map +1 -1
- package/dist/reconciler/instance.d.ts.map +1 -1
- package/dist/reconciler/instance.js +5 -4
- package/dist/reconciler/instance.js.map +1 -1
- package/dist/reconciler/metadata.d.ts.map +1 -1
- package/dist/reconciler/metadata.js +17 -3
- package/dist/reconciler/metadata.js.map +1 -1
- package/package.json +5 -5
- package/src/adw/element-behaviors.ts +40 -177
- package/src/components/element.tsx +11 -3
- package/src/element-behaviors.ts +35 -175
- package/src/reconciler/behaviors.ts +114 -56
- package/src/reconciler/instance.ts +5 -4
- package/src/reconciler/metadata.ts +25 -3
package/src/element-behaviors.ts
CHANGED
|
@@ -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
|
-
|
|
52
|
-
|
|
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", Gtk.Widget, "packStart", "remove"),
|
|
51
|
+
methodSlot<Gtk.HeaderBar | Gtk.ActionBar, Gtk.Widget>("end", Gtk.Widget, "packEnd", "remove"),
|
|
71
52
|
],
|
|
72
53
|
}),
|
|
73
54
|
GtkWindow: {
|
|
@@ -75,7 +56,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
75
56
|
},
|
|
76
57
|
GtkWidget: {
|
|
77
58
|
behaviors: [
|
|
78
|
-
slot<Gtk.Widget, Gtk.Popover>("children",
|
|
59
|
+
slot<Gtk.Widget, Gtk.Popover>("children", Gtk.Popover, {
|
|
79
60
|
attach: (parent, popover) => {
|
|
80
61
|
popover.setParent(parent);
|
|
81
62
|
},
|
|
@@ -83,25 +64,11 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
83
64
|
popover.unparent();
|
|
84
65
|
},
|
|
85
66
|
}),
|
|
86
|
-
|
|
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", Gtk.EventController, "addController", "removeController",
|
|
95
69
|
),
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
widget.setLayoutManager(manager);
|
|
99
|
-
},
|
|
100
|
-
detach: (widget) => {
|
|
101
|
-
widget.setLayoutManager(null);
|
|
102
|
-
},
|
|
103
|
-
}),
|
|
104
|
-
slot<Gtk.Widget, Gio.ActionGroup>("actionGroups", "GActionGroup", {
|
|
70
|
+
setterSlot<Gtk.Widget, Gtk.LayoutManager>("layoutManager", Gtk.LayoutManager, "setLayoutManager"),
|
|
71
|
+
slot<Gtk.Widget, Gio.ActionGroup>("actionGroups", Gio.ActionGroup, {
|
|
105
72
|
attach: (widget, group, info) => {
|
|
106
73
|
widget.insertActionGroup((info.props.prefix as string | null) ?? "", group);
|
|
107
74
|
},
|
|
@@ -133,7 +100,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
133
100
|
GtkOverlay: {
|
|
134
101
|
behaviors: [
|
|
135
102
|
childSetterSlot<Gtk.Overlay>(),
|
|
136
|
-
slot<Gtk.Overlay, Gtk.Widget>("overlays",
|
|
103
|
+
slot<Gtk.Overlay, Gtk.Widget>("overlays", Gtk.Widget, {
|
|
137
104
|
attach: (overlay, child) => {
|
|
138
105
|
overlay.addOverlay(child);
|
|
139
106
|
},
|
|
@@ -146,15 +113,8 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
146
113
|
},
|
|
147
114
|
GtkShortcutController: {
|
|
148
115
|
behaviors: [
|
|
149
|
-
|
|
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", Gtk.Shortcut, "addShortcut", "removeShortcut",
|
|
158
118
|
),
|
|
159
119
|
],
|
|
160
120
|
},
|
|
@@ -162,20 +122,11 @@ 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", Gtk.TextBuffer, "setBuffer")],
|
|
175
126
|
},
|
|
176
127
|
GActionMap: {
|
|
177
128
|
behaviors: [
|
|
178
|
-
slot<Gio.ActionMap, Gio.Action>("actions",
|
|
129
|
+
slot<Gio.ActionMap, Gio.Action>("actions", Gio.Action, {
|
|
179
130
|
attach: (map, action) => {
|
|
180
131
|
map.addAction(action);
|
|
181
132
|
},
|
|
@@ -199,7 +150,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
199
150
|
},
|
|
200
151
|
GtkColumnView: {
|
|
201
152
|
behaviors: [
|
|
202
|
-
slot<Gtk.ColumnView, Gtk.ColumnViewColumn>("children",
|
|
153
|
+
slot<Gtk.ColumnView, Gtk.ColumnViewColumn>("children", Gtk.ColumnViewColumn, {
|
|
203
154
|
attach: (view, column, info) => {
|
|
204
155
|
view.insertColumn(info.index, column);
|
|
205
156
|
},
|
|
@@ -211,7 +162,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
211
162
|
},
|
|
212
163
|
GtkGrid: {
|
|
213
164
|
behaviors: [
|
|
214
|
-
slot<Gtk.Grid, Gtk.Widget>("children",
|
|
165
|
+
slot<Gtk.Grid, Gtk.Widget>("children", Gtk.Widget, {
|
|
215
166
|
attach: (grid, child) => {
|
|
216
167
|
grid.attach(child, 0, 0, 1, 1);
|
|
217
168
|
},
|
|
@@ -224,7 +175,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
224
175
|
},
|
|
225
176
|
GtkFixed: {
|
|
226
177
|
behaviors: [
|
|
227
|
-
slot<Gtk.Fixed, Gtk.Widget>("children",
|
|
178
|
+
slot<Gtk.Fixed, Gtk.Widget>("children", Gtk.Widget, {
|
|
228
179
|
attach: (fixed, child) => {
|
|
229
180
|
fixed.put(child, 0, 0);
|
|
230
181
|
},
|
|
@@ -249,25 +200,11 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
249
200
|
},
|
|
250
201
|
GtkConstraintLayout: {
|
|
251
202
|
behaviors: [
|
|
252
|
-
|
|
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", Gtk.Constraint, "addConstraint", "removeConstraint",
|
|
261
205
|
),
|
|
262
|
-
|
|
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", Gtk.ConstraintGuide, "addGuide", "removeGuide",
|
|
271
208
|
),
|
|
272
209
|
list<Gtk.ConstraintLayout, VflConstraints, Gtk.Constraint[]>("vfl", {
|
|
273
210
|
add: (layout, item) => [
|
|
@@ -288,19 +225,13 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
288
225
|
},
|
|
289
226
|
GtkStack: {
|
|
290
227
|
behaviors: [
|
|
291
|
-
|
|
292
|
-
"GtkWidget",
|
|
293
|
-
(stack, child) => stack.addChild(child),
|
|
294
|
-
(stack, child) => {
|
|
295
|
-
stack.remove(child);
|
|
296
|
-
},
|
|
297
|
-
),
|
|
228
|
+
methodSlot<Gtk.Stack, Gtk.Widget>("children", Gtk.Widget, "addChild", "remove"),
|
|
298
229
|
deferred<Gtk.Stack, string>("visibleChildName", (stack, name) => stack.getChildByName(name) !== null),
|
|
299
230
|
],
|
|
300
231
|
},
|
|
301
232
|
GtkNotebook: {
|
|
302
233
|
behaviors: [
|
|
303
|
-
slot<Gtk.Notebook, Gtk.Widget>("children",
|
|
234
|
+
slot<Gtk.Notebook, Gtk.Widget>("children", Gtk.Widget, {
|
|
304
235
|
attach: (notebook, child, info) => notebook.insertPage(child, null, info.index),
|
|
305
236
|
reorder: (notebook, child, info) => {
|
|
306
237
|
notebook.reorderChild(child, info.index);
|
|
@@ -315,16 +246,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
315
246
|
GtkApplication: {
|
|
316
247
|
behaviors: [
|
|
317
248
|
applicationCreator(Gtk.Application),
|
|
318
|
-
|
|
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", Gtk.Window, "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
|
|
498
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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 => {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
|
-
import
|
|
2
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
3
3
|
import {
|
|
4
|
-
type AnyClass,
|
|
5
4
|
type ApplicationClass,
|
|
6
5
|
type CommandLineApplication,
|
|
7
6
|
createApplication,
|
|
8
7
|
getClassType,
|
|
8
|
+
getInstanceType,
|
|
9
9
|
TYPE_INVALID,
|
|
10
|
-
typeFromName,
|
|
11
10
|
typeIsA,
|
|
12
11
|
} from "@gtkx/runtime";
|
|
13
|
-
import {
|
|
12
|
+
import { isDeepEqual, kebabCase, structuredClone, unsanitizeIdentifier } from "@gtkx/utils";
|
|
14
13
|
import type { DetachInfo, ElementBehavior, PlaceInfo, Props } from "./registry.js";
|
|
15
14
|
import { getPropertyName } from "./metadata.js";
|
|
16
15
|
import { applyWrite } from "./signals.js";
|
|
@@ -35,8 +34,24 @@ type ListEntry = { item: unknown; handle: unknown };
|
|
|
35
34
|
type ListState = { snapshot: unknown[]; entries: ListEntry[] };
|
|
36
35
|
type DeferredState = { desired: unknown; isPresent: boolean; isScheduled: boolean; disconnect: (() => void) | null };
|
|
37
36
|
type CanApply<P extends GObject.Object, V> = (object: P, value: V) => boolean;
|
|
37
|
+
|
|
38
|
+
type DeferredOps<P extends GObject.Object, V> = {
|
|
39
|
+
canApply?: CanApply<P, V> | undefined;
|
|
40
|
+
parse?: ((value: unknown) => V | undefined) | undefined;
|
|
41
|
+
read: (object: P) => unknown;
|
|
42
|
+
write: (object: P, value: V) => void;
|
|
43
|
+
signal?: string | undefined;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type DeferredHooks<P extends GObject.Object, V> = Omit<DeferredOps<P, V>, "read" | "write"> & {
|
|
47
|
+
read?: ((object: P) => unknown) | undefined;
|
|
48
|
+
write?: ((object: P, value: V) => void) | undefined;
|
|
49
|
+
};
|
|
50
|
+
|
|
38
51
|
type ChildSetter = GObject.Object & { setChild: (child: Gtk.Widget | null) => void };
|
|
39
52
|
type ContentSetter<C extends Gtk.Widget> = GObject.Object & { setContent: (content: C | null) => void };
|
|
53
|
+
type MatchingKey<P, F> = keyof P & string & { [K in keyof P]: P[K] extends F ? K : never }[keyof P];
|
|
54
|
+
type MethodKey<P, A> = MatchingKey<P, (argument: A) => unknown>;
|
|
40
55
|
|
|
41
56
|
type BoxLike = GObject.Object & {
|
|
42
57
|
remove: (child: Gtk.Widget) => void;
|
|
@@ -51,22 +66,32 @@ type IndexedChildHost<C extends GObject.Object> = GObject.Object & {
|
|
|
51
66
|
insert: (child: C, position: number) => unknown;
|
|
52
67
|
};
|
|
53
68
|
|
|
54
|
-
|
|
69
|
+
type ChildClass<C extends GObject.Object> =
|
|
70
|
+
(abstract new (...args: never[]) => C) |
|
|
71
|
+
{ [Symbol.hasInstance]: (value: unknown) => value is C };
|
|
55
72
|
|
|
56
|
-
const
|
|
73
|
+
const childClassType = (cls: ChildClass<GObject.Object>): bigint =>
|
|
74
|
+
typeof cls === "function" ? getClassType(cls) : TYPE_INVALID;
|
|
57
75
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
const isChildInstance = <C extends GObject.Object>(child: GObject.Object, cls: ChildClass<C>): child is C => {
|
|
77
|
+
if (child instanceof cls) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
|
|
81
|
+
const type = childClassType(cls);
|
|
82
|
+
|
|
83
|
+
return type !== TYPE_INVALID && typeIsA(getInstanceType(child), type);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const childMatcher =
|
|
87
|
+
<C extends GObject.Object>(cls: ChildClass<C> | undefined): ((child: GObject.Object) => child is C) =>
|
|
88
|
+
(child): child is C =>
|
|
89
|
+
cls !== undefined && isChildInstance(child, cls);
|
|
65
90
|
|
|
66
91
|
const slotAttach =
|
|
67
92
|
<P extends GObject.Object, C extends GObject.Object>(
|
|
68
93
|
slotName: string,
|
|
69
|
-
isMatch: (child: GObject.Object) =>
|
|
94
|
+
isMatch: (child: GObject.Object) => child is C,
|
|
70
95
|
attach: SlotHooks<P, C>["attach"],
|
|
71
96
|
): NonNullable<ElementBehavior["attach"]> =>
|
|
72
97
|
(object, child, info) => {
|
|
@@ -74,15 +99,15 @@ const slotAttach =
|
|
|
74
99
|
return;
|
|
75
100
|
}
|
|
76
101
|
|
|
77
|
-
return attach(object as P, child
|
|
102
|
+
return attach(object as P, child, info) ?? true;
|
|
78
103
|
};
|
|
79
104
|
|
|
80
105
|
const slot = <P extends GObject.Object, C extends GObject.Object>(
|
|
81
106
|
slotName: string,
|
|
82
|
-
|
|
107
|
+
childClass: ChildClass<C> | undefined,
|
|
83
108
|
hooks: SlotHooks<P, C>,
|
|
84
109
|
): ElementBehavior => {
|
|
85
|
-
const matches = childMatcher(
|
|
110
|
+
const matches = childMatcher(childClass);
|
|
86
111
|
const { attach, detach, reorder, resolve } = hooks;
|
|
87
112
|
const behavior: ElementBehavior = { attach: slotAttach(slotName, matches, attach) };
|
|
88
113
|
|
|
@@ -172,29 +197,31 @@ const list = <P extends GObject.Object, I, H = void>(
|
|
|
172
197
|
};
|
|
173
198
|
|
|
174
199
|
const settleDeferred = <P extends GObject.Object, V>(
|
|
175
|
-
object:
|
|
200
|
+
object: P,
|
|
176
201
|
state: DeferredState,
|
|
177
202
|
prop: string,
|
|
178
|
-
|
|
203
|
+
ops: DeferredOps<P, V>,
|
|
179
204
|
): void => {
|
|
180
|
-
if (!state.isPresent || Object.is(
|
|
205
|
+
if (!state.isPresent || Object.is(ops.read(object), state.desired)) {
|
|
181
206
|
return;
|
|
182
207
|
}
|
|
183
208
|
|
|
184
|
-
|
|
209
|
+
const desired = state.desired as V;
|
|
210
|
+
|
|
211
|
+
if (ops.canApply !== undefined && !ops.canApply(object, desired)) {
|
|
185
212
|
return;
|
|
186
213
|
}
|
|
187
214
|
|
|
188
215
|
applyWrite(prop, () => {
|
|
189
|
-
|
|
216
|
+
ops.write(object, desired);
|
|
190
217
|
});
|
|
191
218
|
};
|
|
192
219
|
|
|
193
220
|
const scheduleSettle = <P extends GObject.Object, V>(
|
|
194
|
-
object:
|
|
221
|
+
object: P,
|
|
195
222
|
state: DeferredState,
|
|
196
223
|
prop: string,
|
|
197
|
-
|
|
224
|
+
ops: DeferredOps<P, V>,
|
|
198
225
|
): void => {
|
|
199
226
|
if (state.isScheduled) {
|
|
200
227
|
return;
|
|
@@ -206,25 +233,25 @@ const scheduleSettle = <P extends GObject.Object, V>(
|
|
|
206
233
|
state.isScheduled = false;
|
|
207
234
|
|
|
208
235
|
if (state.disconnect !== null) {
|
|
209
|
-
settleDeferred(object, state, prop,
|
|
236
|
+
settleDeferred(object, state, prop, ops);
|
|
210
237
|
}
|
|
211
238
|
});
|
|
212
239
|
};
|
|
213
240
|
|
|
214
241
|
const watchDrift = <P extends GObject.Object, V>(
|
|
215
|
-
object:
|
|
242
|
+
object: P,
|
|
216
243
|
state: DeferredState,
|
|
217
244
|
prop: string,
|
|
218
|
-
|
|
245
|
+
ops: DeferredOps<P, V>,
|
|
219
246
|
): void => {
|
|
220
247
|
if (state.disconnect !== null) {
|
|
221
248
|
return;
|
|
222
249
|
}
|
|
223
250
|
|
|
224
|
-
const signal = `notify::${getPropertyName(object, prop) ?? unsanitizeIdentifier(kebabCase(prop))}`;
|
|
251
|
+
const signal = ops.signal ?? `notify::${getPropertyName(object, prop) ?? unsanitizeIdentifier(kebabCase(prop))}`;
|
|
225
252
|
|
|
226
253
|
const handler = (): undefined => {
|
|
227
|
-
scheduleSettle(object, state, prop,
|
|
254
|
+
scheduleSettle(object, state, prop, ops);
|
|
228
255
|
};
|
|
229
256
|
|
|
230
257
|
object.on(signal, handler);
|
|
@@ -234,23 +261,20 @@ const watchDrift = <P extends GObject.Object, V>(
|
|
|
234
261
|
};
|
|
235
262
|
};
|
|
236
263
|
|
|
237
|
-
const
|
|
238
|
-
prop: string,
|
|
239
|
-
canApply?: CanApply<P, V>,
|
|
240
|
-
): ElementBehavior<P> => ({
|
|
264
|
+
const deferredBehavior = <P extends GObject.Object, V>(prop: string, ops: DeferredOps<P, V>): ElementBehavior<P> => ({
|
|
241
265
|
deferred: [prop],
|
|
242
266
|
initialize: (): DeferredState => ({ desired: undefined, isPresent: false, isScheduled: false, disconnect: null }),
|
|
243
267
|
update: (_object, _prev, next, context) => {
|
|
244
268
|
const state = context as DeferredState;
|
|
245
|
-
state.desired = next[prop];
|
|
246
|
-
state.isPresent =
|
|
269
|
+
state.desired = ops.parse === undefined ? next[prop] : ops.parse(next[prop]);
|
|
270
|
+
state.isPresent = state.desired !== undefined;
|
|
247
271
|
|
|
248
272
|
return [prop];
|
|
249
273
|
},
|
|
250
274
|
flush: (object, context) => {
|
|
251
275
|
const state = context as DeferredState;
|
|
252
|
-
settleDeferred(object, state, prop,
|
|
253
|
-
watchDrift(object, state, prop,
|
|
276
|
+
settleDeferred(object, state, prop, ops);
|
|
277
|
+
watchDrift(object, state, prop, ops);
|
|
254
278
|
},
|
|
255
279
|
teardown: (_object, context) => {
|
|
256
280
|
const state = context as DeferredState;
|
|
@@ -259,6 +283,18 @@ const deferred = <P extends GObject.Object, V>(
|
|
|
259
283
|
},
|
|
260
284
|
});
|
|
261
285
|
|
|
286
|
+
const deferredWith = <P extends GObject.Object, V>(prop: string, hooks: DeferredHooks<P, V>): ElementBehavior<P> =>
|
|
287
|
+
deferredBehavior<P, V>(prop, {
|
|
288
|
+
...hooks,
|
|
289
|
+
read: hooks.read ?? ((object) => Reflect.get(object, prop)),
|
|
290
|
+
write: hooks.write ?? ((object, value) => {
|
|
291
|
+
Reflect.set(object, prop, value);
|
|
292
|
+
}),
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const deferred = <P extends GObject.Object, V>(prop: string, canApply?: CanApply<P, V>): ElementBehavior<P> =>
|
|
296
|
+
deferredWith<P, V>(prop, { canApply });
|
|
297
|
+
|
|
262
298
|
const controlledText = (prop: string): ElementBehavior =>
|
|
263
299
|
value(prop, (object, next) => {
|
|
264
300
|
if (!hasSameText(object, prop, next)) {
|
|
@@ -269,7 +305,7 @@ const controlledText = (prop: string): ElementBehavior =>
|
|
|
269
305
|
});
|
|
270
306
|
|
|
271
307
|
const childSetterSlot = <P extends ChildSetter>(): ElementBehavior<P> =>
|
|
272
|
-
slot<P, Gtk.Widget>("children",
|
|
308
|
+
slot<P, Gtk.Widget>("children", Gtk.Widget, {
|
|
273
309
|
attach: (parent, child) => {
|
|
274
310
|
parent.setChild(child);
|
|
275
311
|
},
|
|
@@ -279,9 +315,9 @@ const childSetterSlot = <P extends ChildSetter>(): ElementBehavior<P> =>
|
|
|
279
315
|
});
|
|
280
316
|
|
|
281
317
|
const contentSetterSlot = <P extends ContentSetter<C>, C extends Gtk.Widget = Gtk.Widget>(
|
|
282
|
-
|
|
318
|
+
childClass: ChildClass<C>,
|
|
283
319
|
): ElementBehavior<P> =>
|
|
284
|
-
slot<P, C>("children",
|
|
320
|
+
slot<P, C>("children", childClass, {
|
|
285
321
|
attach: (parent, child) => {
|
|
286
322
|
parent.setContent(child);
|
|
287
323
|
},
|
|
@@ -291,7 +327,7 @@ const contentSetterSlot = <P extends ContentSetter<C>, C extends Gtk.Widget = Gt
|
|
|
291
327
|
});
|
|
292
328
|
|
|
293
329
|
const boxSlot = <P extends BoxLike>(): ElementBehavior<P> =>
|
|
294
|
-
slot<P, Gtk.Widget>("children",
|
|
330
|
+
slot<P, Gtk.Widget>("children", Gtk.Widget, {
|
|
295
331
|
attach: (box, child, info) => box.insertChildAfter(child, info.sibling as Gtk.Widget | null),
|
|
296
332
|
detach: (box, child) => {
|
|
297
333
|
box.remove(child);
|
|
@@ -301,18 +337,45 @@ const boxSlot = <P extends BoxLike>(): ElementBehavior<P> =>
|
|
|
301
337
|
},
|
|
302
338
|
});
|
|
303
339
|
|
|
304
|
-
const
|
|
340
|
+
const callMethod = <P extends GObject.Object, A>(parent: P, method: MethodKey<P, A>, argument: A): unknown =>
|
|
341
|
+
(parent[method] as (argument: A) => unknown)(argument);
|
|
342
|
+
|
|
343
|
+
const methodSlot = <P extends GObject.Object, C extends GObject.Object>(
|
|
344
|
+
slotName: string,
|
|
345
|
+
childClass: ChildClass<C> | undefined,
|
|
346
|
+
add: MethodKey<P, C>,
|
|
347
|
+
remove?: MethodKey<P, C>,
|
|
348
|
+
): ElementBehavior => {
|
|
349
|
+
const hooks: SlotHooks<P, C> = { attach: (parent, child) => callMethod(parent, add, child) };
|
|
350
|
+
|
|
351
|
+
if (remove !== undefined) {
|
|
352
|
+
hooks.detach = (parent, child) => {
|
|
353
|
+
callMethod(parent, remove, child);
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return slot<P, C>(slotName, childClass, hooks);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const setterSlot = <P extends GObject.Object, C extends GObject.Object>(
|
|
305
361
|
slotName: string,
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
362
|
+
childClass: ChildClass<C> | undefined,
|
|
363
|
+
setter: MethodKey<P, C | null>,
|
|
364
|
+
): ElementBehavior =>
|
|
365
|
+
slot<P, C>(slotName, childClass, {
|
|
366
|
+
attach: (parent, child) => {
|
|
367
|
+
callMethod<P, C | null>(parent, setter, child);
|
|
368
|
+
},
|
|
369
|
+
detach: (parent) => {
|
|
370
|
+
callMethod<P, C | null>(parent, setter, null);
|
|
371
|
+
},
|
|
372
|
+
});
|
|
310
373
|
|
|
311
374
|
const indexedSlot = <P extends IndexedChildHost<C>, C extends GObject.Object>(
|
|
312
375
|
slotName: string,
|
|
313
|
-
|
|
376
|
+
childClass: ChildClass<C> | undefined,
|
|
314
377
|
): ElementBehavior<P> =>
|
|
315
|
-
slot<P, C>(slotName,
|
|
378
|
+
slot<P, C>(slotName, childClass, {
|
|
316
379
|
attach: (parent, child, info) => {
|
|
317
380
|
parent.insert(child, info.index);
|
|
318
381
|
},
|
|
@@ -325,12 +388,6 @@ const indexedSlot = <P extends IndexedChildHost<C>, C extends GObject.Object>(
|
|
|
325
388
|
},
|
|
326
389
|
});
|
|
327
390
|
|
|
328
|
-
const adoptedChildrenSlot = <P extends GObject.Object, C extends GObject.Object>(
|
|
329
|
-
childType: string,
|
|
330
|
-
add: (parent: P, item: C) => unknown,
|
|
331
|
-
remove: (parent: P, item: C) => void,
|
|
332
|
-
): ElementBehavior => addRemoveSlot<C, P>("children", childType, add, remove);
|
|
333
|
-
|
|
334
391
|
const wrappedRow = <W extends Gtk.Widget>(
|
|
335
392
|
Wrapper: new (props: Props) => W,
|
|
336
393
|
setChild: (wrapper: W, inner: Gtk.Widget) => void,
|
|
@@ -371,7 +428,7 @@ const wrappingIndexedSlot = <W extends Gtk.Widget, P extends IndexedChildHost<Gt
|
|
|
371
428
|
Wrapper: new (props: Props) => W,
|
|
372
429
|
setChild: (wrapper: W, inner: Gtk.Widget) => void,
|
|
373
430
|
): ElementBehavior<P> => ({
|
|
374
|
-
...slot<P, Gtk.Widget>("children",
|
|
431
|
+
...slot<P, Gtk.Widget>("children", Gtk.Widget, {
|
|
375
432
|
attach: (parent, child, info) =>
|
|
376
433
|
parent.insert(wrappedRow(Wrapper, setChild, info.context as RowCache, child), info.index),
|
|
377
434
|
detach: (parent, child, info) => {
|
|
@@ -394,12 +451,13 @@ export {
|
|
|
394
451
|
value,
|
|
395
452
|
list,
|
|
396
453
|
deferred,
|
|
454
|
+
deferredWith,
|
|
397
455
|
controlledText,
|
|
398
456
|
childSetterSlot,
|
|
399
457
|
contentSetterSlot,
|
|
400
458
|
boxSlot,
|
|
401
|
-
|
|
402
|
-
|
|
459
|
+
methodSlot,
|
|
460
|
+
setterSlot,
|
|
403
461
|
indexedSlot,
|
|
404
462
|
wrappingIndexedSlot,
|
|
405
463
|
};
|