@gtkx/react 1.0.0-rc.4 → 1.1.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 +5 -5
- package/dist/adw/dialog.d.ts +3 -4
- package/dist/adw/dialog.d.ts.map +1 -1
- package/dist/adw/dialog.js +18 -21
- package/dist/adw/dialog.js.map +1 -1
- package/dist/adw/element-behaviors.js +102 -54
- package/dist/adw/element-behaviors.js.map +1 -1
- package/dist/adw/element-config.d.ts +0 -6
- package/dist/adw/element-config.d.ts.map +1 -1
- package/dist/adw/element-config.js +15 -17
- package/dist/adw/element-config.js.map +1 -1
- package/dist/adw/prop-types.d.ts +34 -3
- package/dist/adw/prop-types.d.ts.map +1 -1
- package/dist/adw/prop-types.js.map +1 -1
- package/dist/components/application-window.d.ts +5 -0
- package/dist/components/application-window.d.ts.map +1 -0
- package/dist/components/application-window.js +7 -0
- package/dist/components/application-window.js.map +1 -0
- package/dist/components/application.d.ts +2 -8
- package/dist/components/application.d.ts.map +1 -1
- package/dist/components/application.js +31 -7
- package/dist/components/application.js.map +1 -1
- package/dist/components/element.d.ts +13 -1
- package/dist/components/element.d.ts.map +1 -1
- package/dist/components/element.js +39 -14
- package/dist/components/element.js.map +1 -1
- package/dist/components/portaled.d.ts +5 -0
- package/dist/components/portaled.d.ts.map +1 -0
- package/dist/components/portaled.js +8 -0
- package/dist/components/portaled.js.map +1 -0
- package/dist/components/window.d.ts +5 -5
- package/dist/components/window.d.ts.map +1 -1
- package/dist/components/window.js +16 -16
- package/dist/components/window.js.map +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/element-behaviors.js +11 -1
- package/dist/element-behaviors.js.map +1 -1
- package/dist/element-config.d.ts.map +1 -1
- package/dist/element-config.js +7 -4
- package/dist/element-config.js.map +1 -1
- package/dist/hooks/use-merged-refs.d.ts +1 -4
- package/dist/hooks/use-merged-refs.d.ts.map +1 -1
- package/dist/hooks/use-merged-refs.js +1 -1
- package/dist/hooks/use-merged-refs.js.map +1 -1
- package/dist/hooks/use-presented-instance.d.ts +12 -0
- package/dist/hooks/use-presented-instance.d.ts.map +1 -0
- package/dist/hooks/use-presented-instance.js +27 -0
- package/dist/hooks/use-presented-instance.js.map +1 -0
- package/dist/hooks/use-property.d.ts +2 -1
- package/dist/hooks/use-property.d.ts.map +1 -1
- package/dist/hooks/use-property.js.map +1 -1
- package/dist/hooks/use-signal.d.ts +2 -1
- package/dist/hooks/use-signal.d.ts.map +1 -1
- package/dist/hooks/use-signal.js.map +1 -1
- package/dist/internal.d.ts +5 -3
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -2
- package/dist/internal.js.map +1 -1
- package/dist/prop-types.d.ts +29 -5
- package/dist/prop-types.d.ts.map +1 -1
- package/dist/prop-types.js.map +1 -1
- package/dist/reconciler/apply-props.d.ts +4 -4
- package/dist/reconciler/apply-props.d.ts.map +1 -1
- package/dist/reconciler/apply-props.js +62 -20
- package/dist/reconciler/apply-props.js.map +1 -1
- package/dist/reconciler/behaviors.d.ts +9 -5
- package/dist/reconciler/behaviors.d.ts.map +1 -1
- package/dist/reconciler/behaviors.js +40 -22
- package/dist/reconciler/behaviors.js.map +1 -1
- package/dist/reconciler/devtools.d.ts +6 -0
- package/dist/reconciler/devtools.d.ts.map +1 -0
- package/dist/reconciler/devtools.js +11 -0
- package/dist/reconciler/devtools.js.map +1 -0
- package/dist/reconciler/host-config.d.ts.map +1 -1
- package/dist/reconciler/host-config.js +18 -25
- package/dist/reconciler/host-config.js.map +1 -1
- package/dist/reconciler/instance.d.ts.map +1 -1
- package/dist/reconciler/instance.js +5 -3
- package/dist/reconciler/instance.js.map +1 -1
- package/dist/reconciler/metadata.d.ts +1 -1
- package/dist/reconciler/metadata.d.ts.map +1 -1
- package/dist/reconciler/metadata.js +2 -4
- package/dist/reconciler/metadata.js.map +1 -1
- package/dist/reconciler/node.d.ts +3 -2
- package/dist/reconciler/node.d.ts.map +1 -1
- package/dist/reconciler/node.js +7 -6
- package/dist/reconciler/node.js.map +1 -1
- package/dist/reconciler/placement.js +20 -20
- package/dist/reconciler/placement.js.map +1 -1
- package/dist/reconciler/registry.d.ts +9 -7
- package/dist/reconciler/registry.d.ts.map +1 -1
- package/dist/reconciler/registry.js.map +1 -1
- package/dist/reconciler/root-element.d.ts +1 -0
- package/dist/reconciler/root-element.d.ts.map +1 -1
- package/dist/reconciler/root-element.js.map +1 -1
- package/dist/reconciler/root.d.ts +17 -3
- package/dist/reconciler/root.d.ts.map +1 -1
- package/dist/reconciler/root.js +22 -8
- package/dist/reconciler/root.js.map +1 -1
- package/dist/reconciler/signals.d.ts +1 -2
- package/dist/reconciler/signals.d.ts.map +1 -1
- package/dist/reconciler/signals.js +1 -1
- package/dist/reconciler/signals.js.map +1 -1
- package/dist/utils/accessible-props.d.ts +8 -8
- package/dist/utils/accessible-props.d.ts.map +1 -1
- package/dist/utils/accessible-props.js +11 -13
- package/dist/utils/accessible-props.js.map +1 -1
- package/dist/utils/settings.d.ts +2 -1
- package/dist/utils/settings.d.ts.map +1 -1
- package/dist/utils/settings.js.map +1 -1
- package/dist/utils/variant.d.ts +33 -1
- package/dist/utils/variant.d.ts.map +1 -1
- package/dist/utils/variant.js.map +1 -1
- package/package.json +14 -4
- package/src/adw/dialog.tsx +25 -25
- package/src/adw/element-behaviors.ts +129 -57
- package/src/adw/element-config.ts +15 -17
- package/src/adw/prop-types.ts +35 -2
- package/src/components/application-window.tsx +10 -0
- package/src/components/application.tsx +45 -6
- package/src/components/element.tsx +52 -16
- package/src/components/portaled.tsx +14 -0
- package/src/components/window.tsx +24 -23
- package/src/config.ts +10 -1
- package/src/element-behaviors.ts +20 -0
- package/src/element-config.ts +7 -4
- package/src/hooks/use-merged-refs.ts +1 -1
- package/src/hooks/use-presented-instance.tsx +50 -0
- package/src/hooks/use-property.ts +2 -1
- package/src/hooks/use-signal.ts +2 -1
- package/src/internal.ts +5 -3
- package/src/prop-types.ts +34 -7
- package/src/reconciler/apply-props.ts +77 -24
- package/src/reconciler/behaviors.ts +72 -30
- package/src/reconciler/devtools.ts +18 -0
- package/src/reconciler/host-config.ts +20 -30
- package/src/reconciler/instance.ts +6 -3
- package/src/reconciler/metadata.ts +3 -6
- package/src/reconciler/node.ts +10 -7
- package/src/reconciler/placement.ts +25 -25
- package/src/reconciler/registry.ts +9 -7
- package/src/reconciler/root-element.ts +4 -1
- package/src/reconciler/root.ts +38 -12
- package/src/reconciler/signals.ts +0 -1
- package/src/utils/accessible-props.ts +21 -24
- package/src/utils/settings.ts +2 -1
- package/src/utils/variant.ts +33 -1
- package/dist/utils/accessible-metadata.d.ts +0 -5
- package/dist/utils/accessible-metadata.d.ts.map +0 -1
- package/dist/utils/accessible-metadata.js +0 -18
- package/dist/utils/accessible-metadata.js.map +0 -1
- package/src/utils/accessible-metadata.ts +0 -24
|
@@ -4,21 +4,23 @@ import type { AlertDialogResponse } from "./prop-types.js";
|
|
|
4
4
|
import {
|
|
5
5
|
addRemoveSlot,
|
|
6
6
|
adoptedChildrenSlot,
|
|
7
|
+
applicationCreator,
|
|
7
8
|
boxSlot,
|
|
9
|
+
childMatcher,
|
|
8
10
|
childSetterSlot,
|
|
9
11
|
contentSetterSlot,
|
|
10
12
|
deferred,
|
|
13
|
+
indexedSlot,
|
|
11
14
|
list,
|
|
12
15
|
slot,
|
|
13
16
|
} from "../reconciler/behaviors.js";
|
|
14
|
-
import { type ElementConfig, forTypes, registerElements } from "../reconciler/registry.js";
|
|
17
|
+
import { type ElementBehavior, type ElementConfig, forTypes, registerElements } from "../reconciler/registry.js";
|
|
15
18
|
import { BUILTIN_ELEMENTS, CHILD_SETTER_TYPES, CONTENT_SETTER_TYPES } from "./element-config.js";
|
|
16
19
|
|
|
17
20
|
type AdwChildSetter =
|
|
18
21
|
| Adw.Bin |
|
|
19
22
|
Adw.BreakpointBin |
|
|
20
23
|
Adw.Clamp |
|
|
21
|
-
Adw.ClampScrollable |
|
|
22
24
|
Adw.Dialog |
|
|
23
25
|
Adw.NavigationPage |
|
|
24
26
|
Adw.SplitButton |
|
|
@@ -27,11 +29,11 @@ type AdwChildSetter =
|
|
|
27
29
|
Adw.ToastOverlay |
|
|
28
30
|
Adw.Toggle;
|
|
29
31
|
|
|
30
|
-
type AdwContentSetter = Adw.ApplicationWindow | Adw.BottomSheet | Adw.
|
|
32
|
+
type AdwContentSetter = Adw.ApplicationWindow | Adw.BottomSheet | Adw.OverlaySplitView | Adw.Window;
|
|
31
33
|
type BreakpointHost = Adw.ApplicationWindow | Adw.Window | Adw.Dialog;
|
|
32
|
-
type PageHost = Adw.PreferencesDialog | Adw.PreferencesWindow;
|
|
33
34
|
type PrefixSuffixRow = Adw.ActionRow | Adw.EntryRow | Adw.ExpanderRow;
|
|
34
35
|
|
|
36
|
+
const SLOT_SUFFIX = "Slot";
|
|
35
37
|
const childSetter = childSetterSlot<AdwChildSetter>();
|
|
36
38
|
const contentSetter = contentSetterSlot<AdwContentSetter>();
|
|
37
39
|
|
|
@@ -42,36 +44,123 @@ const breakpoints = slot<BreakpointHost, Adw.Breakpoint>("breakpoints", "AdwBrea
|
|
|
42
44
|
});
|
|
43
45
|
|
|
44
46
|
const prefixSuffix = [
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
addRemoveSlot<Gtk.Widget, PrefixSuffixRow>(
|
|
48
|
+
"prefix",
|
|
49
|
+
"GtkWidget",
|
|
50
|
+
(row, child) => {
|
|
47
51
|
row.addPrefix(child);
|
|
48
52
|
},
|
|
49
|
-
|
|
53
|
+
(row, child) => {
|
|
50
54
|
row.remove(child);
|
|
51
55
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
),
|
|
57
|
+
addRemoveSlot<Gtk.Widget, PrefixSuffixRow>(
|
|
58
|
+
"suffix",
|
|
59
|
+
"GtkWidget",
|
|
60
|
+
(row, child) => {
|
|
55
61
|
row.addSuffix(child);
|
|
56
62
|
},
|
|
57
|
-
|
|
63
|
+
(row, child) => {
|
|
58
64
|
row.remove(child);
|
|
59
65
|
},
|
|
60
|
-
|
|
66
|
+
),
|
|
61
67
|
];
|
|
62
68
|
|
|
63
|
-
const
|
|
69
|
+
const preferencesDialogChildren = addRemoveSlot<Adw.PreferencesPage, Adw.PreferencesDialog>(
|
|
64
70
|
"children",
|
|
65
71
|
"AdwPreferencesPage",
|
|
66
|
-
(
|
|
67
|
-
|
|
72
|
+
(dialog, page) => {
|
|
73
|
+
dialog.add(page);
|
|
68
74
|
},
|
|
69
|
-
(
|
|
70
|
-
|
|
75
|
+
(dialog, page) => {
|
|
76
|
+
dialog.remove(page);
|
|
71
77
|
},
|
|
72
78
|
);
|
|
73
79
|
|
|
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
|
+
|
|
89
|
+
const sidebarSections = indexedSlot<Adw.Sidebar, Adw.SidebarSection>("children", "AdwSidebarSection");
|
|
90
|
+
const sidebarItems = indexedSlot<Adw.SidebarSection, Adw.SidebarItem>("children", "AdwSidebarItem");
|
|
91
|
+
const isWidget = childMatcher("GtkWidget");
|
|
92
|
+
|
|
93
|
+
const multiLayoutSlots: ElementBehavior<Adw.MultiLayoutView> = {
|
|
94
|
+
attach: (view, child, info) => {
|
|
95
|
+
const id = getSlotId(info.slot);
|
|
96
|
+
|
|
97
|
+
if (id === null || !isWidget(child)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
view.setChild(id, child as Gtk.Widget);
|
|
102
|
+
|
|
103
|
+
return true;
|
|
104
|
+
},
|
|
105
|
+
detach: (view, child, info) => {
|
|
106
|
+
const id = getSlotId(info.slot);
|
|
107
|
+
|
|
108
|
+
if (id === null || !isWidget(child)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const widget = child as Gtk.Widget;
|
|
113
|
+
|
|
114
|
+
if (view.getChild(id) === widget) {
|
|
115
|
+
widget.unparent();
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const multiLayoutLayouts = slot<Adw.MultiLayoutView, Gtk.Widget>("layouts", "GtkWidget", {
|
|
121
|
+
attach: (view, content) => {
|
|
122
|
+
const layout = new Adw.Layout({ content });
|
|
123
|
+
view.addLayout(layout);
|
|
124
|
+
|
|
125
|
+
return layout;
|
|
126
|
+
},
|
|
127
|
+
reorder: (_view, _content, info) => info.adopted,
|
|
128
|
+
detach: (view, _content, info) => {
|
|
129
|
+
if (info.adopted instanceof Adw.Layout) {
|
|
130
|
+
view.removeLayout(info.adopted);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
74
135
|
const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
136
|
+
AdwApplication: {
|
|
137
|
+
behaviors: [applicationCreator(Adw.Application)],
|
|
138
|
+
},
|
|
139
|
+
AdwSidebar: {
|
|
140
|
+
behaviors: [sidebarSections],
|
|
141
|
+
},
|
|
142
|
+
AdwSidebarSection: {
|
|
143
|
+
behaviors: [sidebarItems],
|
|
144
|
+
},
|
|
145
|
+
AdwMultiLayoutView: {
|
|
146
|
+
behaviors: [
|
|
147
|
+
multiLayoutLayouts,
|
|
148
|
+
multiLayoutSlots,
|
|
149
|
+
deferred<Adw.MultiLayoutView, string>("layoutName", (view, name) => view.getLayoutByName(name) !== null),
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
AdwClampScrollable: {
|
|
153
|
+
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
|
+
}),
|
|
162
|
+
],
|
|
163
|
+
},
|
|
75
164
|
...forTypes(CHILD_SETTER_TYPES, {
|
|
76
165
|
behaviors: [childSetter],
|
|
77
166
|
}),
|
|
@@ -121,26 +210,13 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
121
210
|
row.remove(child);
|
|
122
211
|
},
|
|
123
212
|
),
|
|
124
|
-
addRemoveSlot<Gtk.Widget, Adw.ExpanderRow>(
|
|
125
|
-
"actions",
|
|
126
|
-
"GtkWidget",
|
|
127
|
-
(row, child) => {
|
|
128
|
-
row.addAction(child);
|
|
129
|
-
},
|
|
130
|
-
(row, child) => {
|
|
131
|
-
row.remove(child);
|
|
132
|
-
},
|
|
133
|
-
),
|
|
134
213
|
],
|
|
135
214
|
},
|
|
136
215
|
AdwNavigationSplitView: {
|
|
137
216
|
behaviors: [contentSetterSlot<Adw.NavigationSplitView, Adw.NavigationPage>("AdwNavigationPage")],
|
|
138
217
|
},
|
|
139
|
-
AdwLeaflet: {
|
|
140
|
-
behaviors: [boxSlot<Adw.Leaflet | Adw.WrapBox>()],
|
|
141
|
-
},
|
|
142
218
|
AdwWrapBox: {
|
|
143
|
-
behaviors: [boxSlot<Adw.
|
|
219
|
+
behaviors: [boxSlot<Adw.WrapBox>()],
|
|
144
220
|
},
|
|
145
221
|
AdwCarousel: {
|
|
146
222
|
behaviors: [
|
|
@@ -170,10 +246,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
170
246
|
],
|
|
171
247
|
},
|
|
172
248
|
AdwPreferencesDialog: {
|
|
173
|
-
behaviors: [
|
|
174
|
-
},
|
|
175
|
-
AdwPreferencesWindow: {
|
|
176
|
-
behaviors: [pageHostChildren],
|
|
249
|
+
behaviors: [preferencesDialogChildren],
|
|
177
250
|
},
|
|
178
251
|
AdwPreferencesGroup: {
|
|
179
252
|
behaviors: [
|
|
@@ -189,20 +262,6 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
189
262
|
),
|
|
190
263
|
],
|
|
191
264
|
},
|
|
192
|
-
AdwSqueezer: {
|
|
193
|
-
behaviors: [
|
|
194
|
-
addRemoveSlot<Gtk.Widget, Adw.Squeezer>(
|
|
195
|
-
"children",
|
|
196
|
-
"GtkWidget",
|
|
197
|
-
(squeezer, child) => {
|
|
198
|
-
squeezer.add(child);
|
|
199
|
-
},
|
|
200
|
-
(squeezer, child) => {
|
|
201
|
-
squeezer.remove(child);
|
|
202
|
-
},
|
|
203
|
-
),
|
|
204
|
-
],
|
|
205
|
-
},
|
|
206
265
|
AdwTabView: {
|
|
207
266
|
behaviors: [
|
|
208
267
|
slot<Adw.TabView, Gtk.Widget>("children", "GtkWidget", {
|
|
@@ -250,22 +309,26 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
250
309
|
AdwToolbarView: {
|
|
251
310
|
behaviors: [
|
|
252
311
|
contentSetterSlot<Adw.ToolbarView>(),
|
|
253
|
-
|
|
254
|
-
|
|
312
|
+
addRemoveSlot<Gtk.Widget, Adw.ToolbarView>(
|
|
313
|
+
"topBar",
|
|
314
|
+
"GtkWidget",
|
|
315
|
+
(view, child) => {
|
|
255
316
|
view.addTopBar(child);
|
|
256
317
|
},
|
|
257
|
-
|
|
318
|
+
(view, child) => {
|
|
258
319
|
view.remove(child);
|
|
259
320
|
},
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
321
|
+
),
|
|
322
|
+
addRemoveSlot<Gtk.Widget, Adw.ToolbarView>(
|
|
323
|
+
"bottomBar",
|
|
324
|
+
"GtkWidget",
|
|
325
|
+
(view, child) => {
|
|
263
326
|
view.addBottomBar(child);
|
|
264
327
|
},
|
|
265
|
-
|
|
328
|
+
(view, child) => {
|
|
266
329
|
view.remove(child);
|
|
267
330
|
},
|
|
268
|
-
|
|
331
|
+
),
|
|
269
332
|
],
|
|
270
333
|
},
|
|
271
334
|
AdwHeaderBar: {
|
|
@@ -324,6 +387,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
324
387
|
},
|
|
325
388
|
AdwAlertDialog: {
|
|
326
389
|
behaviors: [
|
|
390
|
+
alertDialogExtraChild,
|
|
327
391
|
list<Adw.AlertDialog, AlertDialogResponse>("responses", {
|
|
328
392
|
add: (dialog, response) => {
|
|
329
393
|
dialog.addResponse(response.id, response.label);
|
|
@@ -344,5 +408,13 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
344
408
|
},
|
|
345
409
|
};
|
|
346
410
|
|
|
411
|
+
function getSlotId(name: string): string | null {
|
|
412
|
+
if (name.length <= SLOT_SUFFIX.length || !name.endsWith(SLOT_SUFFIX)) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return name.slice(0, -SLOT_SUFFIX.length);
|
|
417
|
+
}
|
|
418
|
+
|
|
347
419
|
registerElements(BUILTIN_ELEMENTS);
|
|
348
420
|
registerElements(BUILTIN_BEHAVIORS);
|
|
@@ -3,7 +3,6 @@ import { type ElementConfig, forTypes, internal, type ModuleExport } from "../re
|
|
|
3
3
|
const CHILD_SETTER_TYPES: string[] = [
|
|
4
4
|
"AdwBin",
|
|
5
5
|
"AdwClamp",
|
|
6
|
-
"AdwClampScrollable",
|
|
7
6
|
"AdwNavigationPage",
|
|
8
7
|
"AdwSplitButton",
|
|
9
8
|
"AdwStatusPage",
|
|
@@ -12,17 +11,11 @@ const CHILD_SETTER_TYPES: string[] = [
|
|
|
12
11
|
"AdwToggle",
|
|
13
12
|
];
|
|
14
13
|
|
|
15
|
-
const CONTENT_SETTER_TYPES: string[] = ["AdwBottomSheet", "
|
|
14
|
+
const CONTENT_SETTER_TYPES: string[] = ["AdwBottomSheet", "AdwOverlaySplitView"];
|
|
16
15
|
const childrenProps = internal("ChildrenProps");
|
|
17
16
|
const breakpointsProps = adw("AdwBreakpointsProps");
|
|
18
17
|
const preferencesRowProps = adw("AdwPreferencesRowProps");
|
|
19
18
|
|
|
20
|
-
/**
|
|
21
|
-
* The framework's own element configuration for the Adwaita types it customizes: the base props interface each
|
|
22
|
-
* generated element extends, the component that wraps it, the GObject properties left out of its generated
|
|
23
|
-
* props, and whether its GObject is created by its parent. Carries no behaviors, so importing it never
|
|
24
|
-
* reaches the GObject bindings.
|
|
25
|
-
*/
|
|
26
19
|
const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
27
20
|
...forTypes(CHILD_SETTER_TYPES, {
|
|
28
21
|
props: childrenProps,
|
|
@@ -32,12 +25,25 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
32
25
|
props: childrenProps,
|
|
33
26
|
omittedProps: ["content"],
|
|
34
27
|
}),
|
|
28
|
+
AdwClampScrollable: {
|
|
29
|
+
props: childrenProps,
|
|
30
|
+
omittedProps: ["child"],
|
|
31
|
+
},
|
|
35
32
|
AdwViewStackPage: {
|
|
36
33
|
isLazy: true,
|
|
37
34
|
},
|
|
38
35
|
AdwTabPage: {
|
|
39
36
|
isLazy: true,
|
|
40
37
|
},
|
|
38
|
+
AdwLayout: {
|
|
39
|
+
isLazy: true,
|
|
40
|
+
},
|
|
41
|
+
AdwSidebarSection: {
|
|
42
|
+
props: childrenProps,
|
|
43
|
+
},
|
|
44
|
+
AdwMultiLayoutView: {
|
|
45
|
+
props: adw("AdwMultiLayoutViewProps"),
|
|
46
|
+
},
|
|
41
47
|
AdwPreferencesRow: {
|
|
42
48
|
props: preferencesRowProps,
|
|
43
49
|
},
|
|
@@ -71,9 +77,6 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
71
77
|
props: childrenProps,
|
|
72
78
|
omittedProps: ["content"],
|
|
73
79
|
},
|
|
74
|
-
AdwLeaflet: {
|
|
75
|
-
props: childrenProps,
|
|
76
|
-
},
|
|
77
80
|
AdwWrapBox: {
|
|
78
81
|
props: childrenProps,
|
|
79
82
|
},
|
|
@@ -86,15 +89,9 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
86
89
|
AdwPreferencesDialog: {
|
|
87
90
|
props: childrenProps,
|
|
88
91
|
},
|
|
89
|
-
AdwPreferencesWindow: {
|
|
90
|
-
props: childrenProps,
|
|
91
|
-
},
|
|
92
92
|
AdwPreferencesGroup: {
|
|
93
93
|
props: childrenProps,
|
|
94
94
|
},
|
|
95
|
-
AdwSqueezer: {
|
|
96
|
-
props: childrenProps,
|
|
97
|
-
},
|
|
98
95
|
AdwTabView: {
|
|
99
96
|
props: childrenProps,
|
|
100
97
|
},
|
|
@@ -122,6 +119,7 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
122
119
|
},
|
|
123
120
|
AdwAlertDialog: {
|
|
124
121
|
props: adw("AdwAlertDialogProps"),
|
|
122
|
+
omittedProps: ["extraChild"],
|
|
125
123
|
},
|
|
126
124
|
};
|
|
127
125
|
|
package/src/adw/prop-types.ts
CHANGED
|
@@ -2,36 +2,68 @@ import type * as Adw from "@gtkx/gi/adw";
|
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
import type { ChildrenProps } from "../prop-types.js";
|
|
4
4
|
|
|
5
|
+
/** One button in an `Adw.AlertDialog`'s `responses` prop. */
|
|
5
6
|
type AlertDialogResponse = {
|
|
7
|
+
/** Name the dialog reports on `onResponse` when this button is chosen. */
|
|
6
8
|
id: string;
|
|
9
|
+
/** Text shown on the button. */
|
|
7
10
|
label: string;
|
|
11
|
+
/** Styling the button is given, such as suggested or destructive; defaults to the plain appearance. */
|
|
8
12
|
appearance?: Adw.ResponseAppearance;
|
|
13
|
+
/** Whether the button can be activated; defaults to true. */
|
|
9
14
|
isEnabled?: boolean;
|
|
10
15
|
};
|
|
11
16
|
|
|
17
|
+
/** Props of an `Adw.AlertDialog` element. */
|
|
12
18
|
type AdwAlertDialogProps = {
|
|
19
|
+
/** Buttons the dialog offers, added and removed as the list changes. */
|
|
13
20
|
responses?: AlertDialogResponse[] | null | undefined;
|
|
14
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Widget set as the dialog's extra child, shown below the `heading` and `body` and above the
|
|
23
|
+
* response buttons, leaving the dialog's own chrome in place.
|
|
24
|
+
*/
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
};
|
|
15
27
|
|
|
28
|
+
/** Props of an `Adw.PreferencesRow` element. */
|
|
16
29
|
type AdwPreferencesRowProps = {
|
|
30
|
+
/** Widgets added at the start of the row, before its title. */
|
|
17
31
|
prefix?: ReactNode | null | undefined;
|
|
32
|
+
/** Widgets added at the end of the row. */
|
|
18
33
|
suffix?: ReactNode | null | undefined;
|
|
19
34
|
};
|
|
20
35
|
|
|
36
|
+
/** Props of an `Adw.ExpanderRow` element. */
|
|
21
37
|
type AdwExpanderRowProps = {
|
|
38
|
+
/** Widgets added to the area the row reveals when it expands. */
|
|
22
39
|
rows?: ReactNode | null | undefined;
|
|
23
|
-
actions?: ReactNode | null | undefined;
|
|
24
40
|
} & AdwPreferencesRowProps;
|
|
25
41
|
|
|
42
|
+
/** Props of an `Adw.ToolbarView` element, whose `children` is the content the bars surround. */
|
|
26
43
|
type AdwToolbarViewProps = {
|
|
44
|
+
/** Widgets stacked above the content. */
|
|
27
45
|
topBar?: ReactNode | null | undefined;
|
|
46
|
+
/** Widgets stacked below the content. */
|
|
28
47
|
bottomBar?: ReactNode | null | undefined;
|
|
29
48
|
} & ChildrenProps;
|
|
30
49
|
|
|
50
|
+
/** Props of an element that hosts breakpoints, such as `Adw.Window` or `Adw.BreakpointBin`. */
|
|
31
51
|
type AdwBreakpointsProps = {
|
|
52
|
+
/** `Adw.Breakpoint` elements added to the element, each applying while its condition holds. */
|
|
32
53
|
breakpoints?: ReactNode | null | undefined;
|
|
33
54
|
} & ChildrenProps;
|
|
34
55
|
|
|
56
|
+
/** Props of an `Adw.MultiLayoutView` element. */
|
|
57
|
+
type AdwMultiLayoutViewProps = {
|
|
58
|
+
/** `Adw.Layout` elements added to the view, each holding the content it lays out. */
|
|
59
|
+
layouts?: ReactNode | null | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Widget the view places in the `Adw.LayoutSlot` whose `id` is the prop name without its `Slot`
|
|
62
|
+
* suffix, so `sidebarSlot` fills the slot with id `sidebar` in whichever layout is current.
|
|
63
|
+
*/
|
|
64
|
+
[slot: `${string}Slot`]: ReactNode | null | undefined;
|
|
65
|
+
};
|
|
66
|
+
|
|
35
67
|
export {
|
|
36
68
|
type AlertDialogResponse,
|
|
37
69
|
type AdwAlertDialogProps,
|
|
@@ -39,4 +71,5 @@ export {
|
|
|
39
71
|
type AdwExpanderRowProps,
|
|
40
72
|
type AdwToolbarViewProps,
|
|
41
73
|
type AdwBreakpointsProps,
|
|
74
|
+
type AdwMultiLayoutViewProps,
|
|
42
75
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ElementType, ReactNode } from "react";
|
|
2
|
+
import { useApplication } from "../hooks/use-application.js";
|
|
3
|
+
import { createPortaledComponent } from "./portaled.js";
|
|
4
|
+
import { createPresentedWindowComponent } from "./window.js";
|
|
5
|
+
|
|
6
|
+
const createApplicationWindowComponent = (Component: ElementType): ((props: unknown) => ReactNode) =>
|
|
7
|
+
createPortaledComponent(createPresentedWindowComponent(Component), useApplication);
|
|
8
|
+
|
|
9
|
+
/** @internal */
|
|
10
|
+
export { createApplicationWindowComponent };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
2
|
import { quitApplication, runApplication } from "@gtkx/runtime";
|
|
3
|
-
import { pickBy } from "@gtkx/utils";
|
|
3
|
+
import { pickBy, warn } from "@gtkx/utils";
|
|
4
|
+
import process from "node:process";
|
|
4
5
|
import { type ElementType, type ReactNode, type Ref, useLayoutEffect, useState } from "react";
|
|
5
6
|
import { applicationId as defaultApplicationId } from "virtual:gtkx-config";
|
|
6
7
|
import { ApplicationContext } from "../hooks/use-application.js";
|
|
7
8
|
import { useMergedRef } from "../hooks/use-merged-refs.js";
|
|
9
|
+
import { createPortaledComponent } from "./portaled.js";
|
|
8
10
|
|
|
9
11
|
type ApplicationComponentProps = {
|
|
10
12
|
applicationId?: string | null | undefined;
|
|
@@ -14,23 +16,57 @@ type ApplicationComponentProps = {
|
|
|
14
16
|
|
|
15
17
|
const POST_ACTIVATE_PROPS = new Set(["menubar"]);
|
|
16
18
|
|
|
19
|
+
const commandLine = (applicationId: string | null): string[] => [
|
|
20
|
+
applicationId?.split(".").at(-1) ?? "gtkx",
|
|
21
|
+
...process.argv.slice(2),
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const reportOwnedApplicationId = (application: Gtk.Application): void => {
|
|
25
|
+
if (!application.getIsRegistered() || !application.getIsRemote()) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
warn(
|
|
30
|
+
`Another process already owns ${application.applicationId ?? "this application ID"}, so this process ` +
|
|
31
|
+
"registered as a remote instance and can never show a window. Quit that instance or change " +
|
|
32
|
+
"applicationId, then start this application again.",
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const startApplication = (
|
|
37
|
+
application: Gtk.Application,
|
|
38
|
+
setActivated: (isActivated: boolean) => void,
|
|
39
|
+
applicationId: string | null,
|
|
40
|
+
): void => {
|
|
41
|
+
application.on("activate", () => {
|
|
42
|
+
setActivated(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const { exitStatus } = runApplication(application, commandLine(applicationId));
|
|
46
|
+
reportOwnedApplicationId(application);
|
|
47
|
+
|
|
48
|
+
if (exitStatus !== 0) {
|
|
49
|
+
process.exitCode = exitStatus;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
17
53
|
const useApplicationLifecycle = (
|
|
18
54
|
application: Gtk.Application | null,
|
|
19
55
|
setActivated: (isActivated: boolean) => void,
|
|
56
|
+
applicationId: string | null,
|
|
20
57
|
): void => {
|
|
21
58
|
useLayoutEffect(() => {
|
|
22
59
|
if (!application) {
|
|
23
60
|
return;
|
|
24
61
|
}
|
|
25
62
|
|
|
26
|
-
|
|
27
|
-
setActivated(true);
|
|
63
|
+
startApplication(application, setActivated, applicationId);
|
|
28
64
|
|
|
29
65
|
return () => {
|
|
30
66
|
quitApplication(application);
|
|
31
67
|
setActivated(false);
|
|
32
68
|
};
|
|
33
|
-
}, [application, setActivated]);
|
|
69
|
+
}, [application, setActivated, applicationId]);
|
|
34
70
|
};
|
|
35
71
|
|
|
36
72
|
const applicationChildren = (application: Gtk.Application | null, children: ReactNode): ReactNode => {
|
|
@@ -41,13 +77,13 @@ const applicationChildren = (application: Gtk.Application | null, children: Reac
|
|
|
41
77
|
return <ApplicationContext.Provider value={application}>{children}</ApplicationContext.Provider>;
|
|
42
78
|
};
|
|
43
79
|
|
|
44
|
-
const
|
|
80
|
+
const createApplicationElement = (
|
|
45
81
|
Component: ElementType,
|
|
46
82
|
): ((props: ApplicationComponentProps) => ReactNode) => {
|
|
47
83
|
return ({ applicationId = defaultApplicationId, children, ref, ...rest }: ApplicationComponentProps): ReactNode => {
|
|
48
84
|
const [application, setApplication] = useState<Gtk.Application | null>(null);
|
|
49
85
|
const [activated, setActivated] = useState(false);
|
|
50
|
-
useApplicationLifecycle(application, setActivated);
|
|
86
|
+
useApplicationLifecycle(application, setActivated, applicationId);
|
|
51
87
|
const mergedRef = useMergedRef(ref, setApplication);
|
|
52
88
|
const appliedProps = activated ? rest : pickBy(rest, (_value, key) => !POST_ACTIVATE_PROPS.has(key));
|
|
53
89
|
|
|
@@ -59,5 +95,8 @@ const createApplicationComponent = (
|
|
|
59
95
|
};
|
|
60
96
|
};
|
|
61
97
|
|
|
98
|
+
const createApplicationComponent = (Component: ElementType): ((props: unknown) => ReactNode) =>
|
|
99
|
+
createPortaledComponent(createApplicationElement(Component));
|
|
100
|
+
|
|
62
101
|
/** @internal */
|
|
63
102
|
export { createApplicationComponent };
|
|
@@ -3,44 +3,80 @@ import { createElement, type ElementType, isValidElement, type ReactElement, typ
|
|
|
3
3
|
import type { Props } from "../reconciler/registry.js";
|
|
4
4
|
|
|
5
5
|
const Prop = "gtkx:prop";
|
|
6
|
+
const NO_PROP_CHILDREN: ReactNode[] = [];
|
|
6
7
|
|
|
7
8
|
const hasElement = (value: unknown): boolean =>
|
|
8
9
|
isValidElement(value) || (Array.isArray(value) && value.some((item: unknown) => hasElement(item)));
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
const isRoutedProp = (key: string, value: unknown): boolean =>
|
|
12
|
+
key !== "children" && key !== "ref" && hasElement(value);
|
|
13
|
+
|
|
14
|
+
const collectPropChildren = (record: Props): ReactNode[] | null => {
|
|
15
|
+
let propChildren: ReactNode[] | null = null;
|
|
16
|
+
|
|
17
|
+
for (const key in record) {
|
|
18
|
+
if (!isRoutedProp(key, record[key])) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
propChildren ??= [];
|
|
23
|
+
|
|
12
24
|
propChildren.push(
|
|
13
|
-
createElement(Prop, { propName: key, key: `${Prop}:${key}` },
|
|
25
|
+
createElement(Prop, { propName: key, key: `${Prop}:${key}` }, record[key] as ReactNode),
|
|
14
26
|
);
|
|
15
|
-
} else {
|
|
16
|
-
hostProps[key] = value;
|
|
17
27
|
}
|
|
28
|
+
|
|
29
|
+
return propChildren;
|
|
18
30
|
};
|
|
19
31
|
|
|
20
|
-
const
|
|
21
|
-
const Host = typeName as ElementType;
|
|
32
|
+
const hostPropsWithout = (record: Props): Props => {
|
|
22
33
|
const hostProps: Props = {};
|
|
23
|
-
const propChildren: ReactNode[] = [];
|
|
24
34
|
|
|
25
35
|
for (const key in record) {
|
|
26
|
-
if (key
|
|
27
|
-
|
|
36
|
+
if (key !== "children" && !isRoutedProp(key, record[key])) {
|
|
37
|
+
hostProps[key] = record[key];
|
|
28
38
|
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return hostProps;
|
|
42
|
+
};
|
|
29
43
|
|
|
30
|
-
|
|
44
|
+
const buildElement = (typeName: string, record: Props): ReactElement => {
|
|
45
|
+
const Host = typeName as ElementType;
|
|
46
|
+
const propChildren = collectPropChildren(record);
|
|
47
|
+
|
|
48
|
+
if (propChildren === null) {
|
|
49
|
+
return (
|
|
50
|
+
<Host {...record}>
|
|
51
|
+
{NO_PROP_CHILDREN}
|
|
52
|
+
{record.children as ReactNode}
|
|
53
|
+
</Host>
|
|
54
|
+
);
|
|
31
55
|
}
|
|
32
56
|
|
|
33
57
|
return (
|
|
34
|
-
<Host {...
|
|
58
|
+
<Host {...hostPropsWithout(record)}>
|
|
35
59
|
{propChildren}
|
|
36
60
|
{record.children as ReactNode}
|
|
37
61
|
</Host>
|
|
38
62
|
);
|
|
39
63
|
};
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Builds the component that renders the element of a GLib type, which is how the generated `@gtkx/jsx`
|
|
67
|
+
* store exposes every widget. Reach for it to render a type codegen does not cover, such as one
|
|
68
|
+
* `registerClass` created: the element name is the GType name, and the component routes each prop whose
|
|
69
|
+
* value is an element into that prop's slot, which a bare intrinsic element cannot do.
|
|
70
|
+
*
|
|
71
|
+
* Name the props the element takes as the type argument, since the GType name says nothing about them.
|
|
72
|
+
* Left out, the component takes `unknown`, which accepts no attributes at all.
|
|
73
|
+
*
|
|
74
|
+
* @param typeName GType name to render, such as `GtkButton` or the `typeName` given to `registerClass`.
|
|
75
|
+
* @returns A component taking that type's props.
|
|
76
|
+
*/
|
|
77
|
+
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- callers name the props */
|
|
78
|
+
function createElementComponent<P = unknown>(typeName: string): (props: P) => ReactNode {
|
|
79
|
+
return (props: P): ReactNode => buildElement(typeName, isRecord(props) ? props : {});
|
|
80
|
+
}
|
|
45
81
|
|
|
46
82
|
export { Prop, createElementComponent };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ElementType, ReactNode } from "react";
|
|
2
|
+
import { isRecord } from "@gtkx/utils";
|
|
3
|
+
import type { Container } from "../reconciler/host-config.js";
|
|
4
|
+
import { rootElement } from "../reconciler/root-element.js";
|
|
5
|
+
import { createPortal } from "../reconciler/root.js";
|
|
6
|
+
|
|
7
|
+
const useRootContainer = (): Container => rootElement;
|
|
8
|
+
|
|
9
|
+
const createPortaledComponent =
|
|
10
|
+
(Component: ElementType, useContainer: () => Container = useRootContainer): ((props: unknown) => ReactNode) =>
|
|
11
|
+
(props: unknown): ReactNode =>
|
|
12
|
+
createPortal(<Component {...(isRecord(props) ? props : {})} />, useContainer());
|
|
13
|
+
|
|
14
|
+
export { createPortaledComponent };
|