@gtkx/react 1.0.0-rc.3 → 1.0.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 +8 -9
- package/dist/adw/config.d.ts +1 -0
- package/dist/adw/config.d.ts.map +1 -1
- package/dist/adw/config.js +1 -0
- package/dist/adw/config.js.map +1 -1
- package/dist/adw/dialog.d.ts +4 -4
- package/dist/adw/dialog.d.ts.map +1 -1
- package/dist/adw/dialog.js +16 -21
- package/dist/adw/dialog.js.map +1 -1
- package/dist/adw/element-behaviors.js +104 -57
- package/dist/adw/element-behaviors.js.map +1 -1
- package/dist/adw/element-config.d.ts +0 -5
- package/dist/adw/element-config.d.ts.map +1 -1
- package/dist/adw/element-config.js +25 -26
- package/dist/adw/element-config.js.map +1 -1
- package/dist/adw/index.d.ts +1 -0
- package/dist/adw/index.d.ts.map +1 -1
- package/dist/adw/index.js +1 -0
- package/dist/adw/index.js.map +1 -1
- package/dist/adw/prop-types.d.ts +35 -4
- package/dist/adw/prop-types.d.ts.map +1 -1
- package/dist/adw/prop-types.js.map +1 -1
- package/dist/bootstrap.js +1 -1
- package/dist/bootstrap.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 +3 -8
- package/dist/components/application.d.ts.map +1 -1
- package/dist/components/application.js +22 -6
- package/dist/components/application.js.map +1 -1
- package/dist/components/element.d.ts +13 -2
- package/dist/components/element.d.ts.map +1 -1
- package/dist/components/element.js +39 -15
- 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 +6 -5
- package/dist/components/window.d.ts.map +1 -1
- package/dist/components/window.js +17 -16
- package/dist/components/window.js.map +1 -1
- package/dist/config.d.ts +7 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/element-behaviors.js +11 -2
- package/dist/element-behaviors.js.map +1 -1
- package/dist/element-config.d.ts +4 -3
- package/dist/element-config.d.ts.map +1 -1
- package/dist/element-config.js +19 -15
- package/dist/element-config.js.map +1 -1
- package/dist/hooks/use-bind-setting.d.ts +8 -7
- package/dist/hooks/use-bind-setting.d.ts.map +1 -1
- package/dist/hooks/use-bind-setting.js +2 -7
- package/dist/hooks/use-bind-setting.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-parent-window.d.ts +3 -1
- package/dist/hooks/use-parent-window.d.ts.map +1 -1
- package/dist/hooks/use-parent-window.js +3 -1
- package/dist/hooks/use-parent-window.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 +4 -3
- package/dist/hooks/use-property.d.ts.map +1 -1
- package/dist/hooks/use-property.js +1 -2
- package/dist/hooks/use-property.js.map +1 -1
- package/dist/hooks/use-setting.d.ts +2 -3
- package/dist/hooks/use-setting.d.ts.map +1 -1
- package/dist/hooks/use-setting.js +2 -3
- package/dist/hooks/use-setting.js.map +1 -1
- package/dist/hooks/use-signal.d.ts +15 -8
- package/dist/hooks/use-signal.d.ts.map +1 -1
- package/dist/hooks/use-signal.js +6 -8
- package/dist/hooks/use-signal.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +8 -5
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +7 -5
- package/dist/internal.js.map +1 -1
- package/dist/prop-types.d.ts +88 -4
- 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 -20
- package/dist/reconciler/behaviors.d.ts.map +1 -1
- package/dist/reconciler/behaviors.js +44 -41
- 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 +1 -1
- package/dist/reconciler/host-config.d.ts.map +1 -1
- package/dist/reconciler/host-config.js +17 -26
- package/dist/reconciler/host-config.js.map +1 -1
- package/dist/reconciler/instance.d.ts.map +1 -1
- package/dist/reconciler/instance.js +6 -4
- package/dist/reconciler/instance.js.map +1 -1
- package/dist/reconciler/metadata.d.ts +2 -2
- package/dist/reconciler/metadata.d.ts.map +1 -1
- package/dist/reconciler/metadata.js +9 -11
- package/dist/reconciler/metadata.js.map +1 -1
- package/dist/reconciler/node.d.ts +4 -3
- package/dist/reconciler/node.d.ts.map +1 -1
- package/dist/reconciler/node.js +8 -7
- 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 +46 -32
- package/dist/reconciler/registry.d.ts.map +1 -1
- package/dist/reconciler/registry.js +10 -19
- package/dist/reconciler/registry.js.map +1 -1
- package/dist/reconciler/root-element.d.ts +1 -1
- package/dist/reconciler/root-element.d.ts.map +1 -1
- package/dist/reconciler/root-element.js +0 -1
- package/dist/reconciler/root-element.js.map +1 -1
- package/dist/reconciler/root.d.ts +9 -20
- package/dist/reconciler/root.d.ts.map +1 -1
- package/dist/reconciler/root.js +6 -19
- 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 +3 -3
- package/dist/reconciler/signals.js.map +1 -1
- package/dist/reconciler/text.js +5 -5
- package/dist/reconciler/text.js.map +1 -1
- package/dist/utils/accessible-props.d.ts +57 -9
- 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/ref-prop.d.ts +0 -6
- package/dist/utils/ref-prop.d.ts.map +1 -1
- package/dist/utils/ref-prop.js +0 -6
- package/dist/utils/ref-prop.js.map +1 -1
- package/dist/utils/settings.d.ts +7 -0
- 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/env.d.ts +11 -4
- package/package.json +5 -5
- package/src/adw/config.ts +1 -0
- package/src/adw/dialog.tsx +23 -25
- package/src/adw/element-behaviors.ts +131 -60
- package/src/adw/element-config.ts +25 -26
- package/src/adw/index.ts +1 -0
- package/src/adw/prop-types.ts +36 -3
- package/src/bootstrap.ts +1 -1
- package/src/components/application-window.tsx +10 -0
- package/src/components/application.tsx +32 -5
- package/src/components/element.tsx +52 -17
- package/src/components/portaled.tsx +14 -0
- package/src/components/window.tsx +25 -23
- package/src/config.ts +13 -8
- package/src/element-behaviors.ts +20 -1
- package/src/element-config.ts +19 -15
- package/src/hooks/use-bind-setting.ts +8 -7
- package/src/hooks/use-merged-refs.ts +1 -1
- package/src/hooks/use-parent-window.ts +3 -1
- package/src/hooks/use-presented-instance.tsx +50 -0
- package/src/hooks/use-property.ts +4 -3
- package/src/hooks/use-setting.ts +2 -3
- package/src/hooks/use-signal.ts +18 -11
- package/src/index.ts +10 -2
- package/src/internal.ts +8 -5
- package/src/prop-types.ts +119 -11
- package/src/reconciler/apply-props.ts +77 -24
- package/src/reconciler/behaviors.ts +77 -50
- package/src/reconciler/devtools.ts +18 -0
- package/src/reconciler/host-config.ts +20 -32
- package/src/reconciler/instance.ts +7 -4
- package/src/reconciler/metadata.ts +11 -14
- package/src/reconciler/node.ts +12 -9
- package/src/reconciler/placement.ts +25 -25
- package/src/reconciler/registry.ts +56 -39
- package/src/reconciler/root-element.ts +4 -2
- package/src/reconciler/root.ts +12 -20
- package/src/reconciler/signals.ts +2 -3
- package/src/reconciler/text.ts +6 -6
- package/src/utils/accessible-props.ts +70 -25
- package/src/utils/ref-prop.ts +0 -6
- package/src/utils/settings.ts +7 -0
- package/src/utils/variant.ts +33 -1
- package/dist/utils/accessible-metadata.d.ts +0 -12
- package/dist/utils/accessible-metadata.d.ts.map +0 -1
- package/dist/utils/accessible-metadata.js +0 -25
- package/dist/utils/accessible-metadata.js.map +0 -1
- package/src/utils/accessible-metadata.ts +0 -31
|
@@ -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,30 +11,38 @@ 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 static, runtime-free half of the built-in element configuration: which base props interface each
|
|
22
|
-
* generated element extends, which component wraps it, and whether its GObject is created lazily by its
|
|
23
|
-
* parent. Codegen imports this module, so it must never reach the GObject bindings.
|
|
24
|
-
*/
|
|
25
19
|
const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
26
20
|
...forTypes(CHILD_SETTER_TYPES, {
|
|
27
21
|
props: childrenProps,
|
|
28
|
-
|
|
22
|
+
omittedProps: ["child"],
|
|
29
23
|
}),
|
|
30
24
|
...forTypes(CONTENT_SETTER_TYPES, {
|
|
31
25
|
props: childrenProps,
|
|
32
|
-
|
|
26
|
+
omittedProps: ["content"],
|
|
33
27
|
}),
|
|
28
|
+
AdwClampScrollable: {
|
|
29
|
+
props: childrenProps,
|
|
30
|
+
omittedProps: ["child"],
|
|
31
|
+
},
|
|
34
32
|
AdwViewStackPage: {
|
|
35
|
-
|
|
33
|
+
isLazy: true,
|
|
36
34
|
},
|
|
37
35
|
AdwTabPage: {
|
|
38
|
-
|
|
36
|
+
isLazy: true,
|
|
37
|
+
},
|
|
38
|
+
AdwLayout: {
|
|
39
|
+
isLazy: true,
|
|
40
|
+
},
|
|
41
|
+
AdwSidebarSection: {
|
|
42
|
+
props: childrenProps,
|
|
43
|
+
},
|
|
44
|
+
AdwMultiLayoutView: {
|
|
45
|
+
props: adw("AdwMultiLayoutViewProps"),
|
|
39
46
|
},
|
|
40
47
|
AdwPreferencesRow: {
|
|
41
48
|
props: preferencesRowProps,
|
|
@@ -43,19 +50,19 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
43
50
|
AdwDialog: {
|
|
44
51
|
props: breakpointsProps,
|
|
45
52
|
component: adw("createDialogComponent"),
|
|
46
|
-
|
|
53
|
+
omittedProps: ["child"],
|
|
47
54
|
},
|
|
48
55
|
AdwApplicationWindow: {
|
|
49
56
|
props: breakpointsProps,
|
|
50
|
-
|
|
57
|
+
omittedProps: ["content"],
|
|
51
58
|
},
|
|
52
59
|
AdwWindow: {
|
|
53
60
|
props: breakpointsProps,
|
|
54
|
-
|
|
61
|
+
omittedProps: ["content"],
|
|
55
62
|
},
|
|
56
63
|
AdwBreakpointBin: {
|
|
57
64
|
props: breakpointsProps,
|
|
58
|
-
|
|
65
|
+
omittedProps: ["child"],
|
|
59
66
|
},
|
|
60
67
|
AdwActionRow: {
|
|
61
68
|
props: preferencesRowProps,
|
|
@@ -68,10 +75,7 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
68
75
|
},
|
|
69
76
|
AdwNavigationSplitView: {
|
|
70
77
|
props: childrenProps,
|
|
71
|
-
|
|
72
|
-
},
|
|
73
|
-
AdwLeaflet: {
|
|
74
|
-
props: childrenProps,
|
|
78
|
+
omittedProps: ["content"],
|
|
75
79
|
},
|
|
76
80
|
AdwWrapBox: {
|
|
77
81
|
props: childrenProps,
|
|
@@ -85,15 +89,9 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
85
89
|
AdwPreferencesDialog: {
|
|
86
90
|
props: childrenProps,
|
|
87
91
|
},
|
|
88
|
-
AdwPreferencesWindow: {
|
|
89
|
-
props: childrenProps,
|
|
90
|
-
},
|
|
91
92
|
AdwPreferencesGroup: {
|
|
92
93
|
props: childrenProps,
|
|
93
94
|
},
|
|
94
|
-
AdwSqueezer: {
|
|
95
|
-
props: childrenProps,
|
|
96
|
-
},
|
|
97
95
|
AdwTabView: {
|
|
98
96
|
props: childrenProps,
|
|
99
97
|
},
|
|
@@ -105,7 +103,7 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
105
103
|
},
|
|
106
104
|
AdwToolbarView: {
|
|
107
105
|
props: adw("AdwToolbarViewProps"),
|
|
108
|
-
|
|
106
|
+
omittedProps: ["content"],
|
|
109
107
|
},
|
|
110
108
|
AdwHeaderBar: {
|
|
111
109
|
props: internal("GtkHeaderBarProps"),
|
|
@@ -121,6 +119,7 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
121
119
|
},
|
|
122
120
|
AdwAlertDialog: {
|
|
123
121
|
props: adw("AdwAlertDialogProps"),
|
|
122
|
+
omittedProps: ["extraChild"],
|
|
124
123
|
},
|
|
125
124
|
};
|
|
126
125
|
|
package/src/adw/index.ts
CHANGED
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;
|
|
9
|
-
|
|
13
|
+
/** Whether the button can be activated; defaults to true. */
|
|
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
|
};
|
package/src/bootstrap.ts
CHANGED
|
@@ -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
3
|
import { pickBy } 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,44 @@ 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 startApplication = (
|
|
25
|
+
application: Gtk.Application,
|
|
26
|
+
setActivated: (isActivated: boolean) => void,
|
|
27
|
+
applicationId: string | null,
|
|
28
|
+
): void => {
|
|
29
|
+
application.on("activate", () => {
|
|
30
|
+
setActivated(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { exitStatus } = runApplication(application, commandLine(applicationId));
|
|
34
|
+
|
|
35
|
+
if (exitStatus !== 0) {
|
|
36
|
+
process.exitCode = exitStatus;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
17
40
|
const useApplicationLifecycle = (
|
|
18
41
|
application: Gtk.Application | null,
|
|
19
42
|
setActivated: (isActivated: boolean) => void,
|
|
43
|
+
applicationId: string | null,
|
|
20
44
|
): void => {
|
|
21
45
|
useLayoutEffect(() => {
|
|
22
46
|
if (!application) {
|
|
23
47
|
return;
|
|
24
48
|
}
|
|
25
49
|
|
|
26
|
-
|
|
27
|
-
setActivated(true);
|
|
50
|
+
startApplication(application, setActivated, applicationId);
|
|
28
51
|
|
|
29
52
|
return () => {
|
|
30
53
|
quitApplication(application);
|
|
31
54
|
setActivated(false);
|
|
32
55
|
};
|
|
33
|
-
}, [application, setActivated]);
|
|
56
|
+
}, [application, setActivated, applicationId]);
|
|
34
57
|
};
|
|
35
58
|
|
|
36
59
|
const applicationChildren = (application: Gtk.Application | null, children: ReactNode): ReactNode => {
|
|
@@ -41,13 +64,13 @@ const applicationChildren = (application: Gtk.Application | null, children: Reac
|
|
|
41
64
|
return <ApplicationContext.Provider value={application}>{children}</ApplicationContext.Provider>;
|
|
42
65
|
};
|
|
43
66
|
|
|
44
|
-
const
|
|
67
|
+
const createApplicationElement = (
|
|
45
68
|
Component: ElementType,
|
|
46
69
|
): ((props: ApplicationComponentProps) => ReactNode) => {
|
|
47
70
|
return ({ applicationId = defaultApplicationId, children, ref, ...rest }: ApplicationComponentProps): ReactNode => {
|
|
48
71
|
const [application, setApplication] = useState<Gtk.Application | null>(null);
|
|
49
72
|
const [activated, setActivated] = useState(false);
|
|
50
|
-
useApplicationLifecycle(application, setActivated);
|
|
73
|
+
useApplicationLifecycle(application, setActivated, applicationId);
|
|
51
74
|
const mergedRef = useMergedRef(ref, setApplication);
|
|
52
75
|
const appliedProps = activated ? rest : pickBy(rest, (_value, key) => !POST_ACTIVATE_PROPS.has(key));
|
|
53
76
|
|
|
@@ -59,4 +82,8 @@ const createApplicationComponent = (
|
|
|
59
82
|
};
|
|
60
83
|
};
|
|
61
84
|
|
|
85
|
+
const createApplicationComponent = (Component: ElementType): ((props: unknown) => ReactNode) =>
|
|
86
|
+
createPortaledComponent(createApplicationElement(Component));
|
|
87
|
+
|
|
88
|
+
/** @internal */
|
|
62
89
|
export { createApplicationComponent };
|
|
@@ -2,46 +2,81 @@ import { isRecord } from "@gtkx/utils";
|
|
|
2
2
|
import { createElement, type ElementType, isValidElement, type ReactElement, type ReactNode } from "react";
|
|
3
3
|
import type { Props } from "../reconciler/registry.js";
|
|
4
4
|
|
|
5
|
-
/** The intrinsic element that carries an object-valued prop's element into its parent's named property. */
|
|
6
5
|
const Prop = "gtkx:prop";
|
|
6
|
+
const NO_PROP_CHILDREN: ReactNode[] = [];
|
|
7
7
|
|
|
8
8
|
const hasElement = (value: unknown): boolean =>
|
|
9
9
|
isValidElement(value) || (Array.isArray(value) && value.some((item: unknown) => hasElement(item)));
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
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
|
+
|
|
13
24
|
propChildren.push(
|
|
14
|
-
createElement(Prop, { propName: key, key: `${Prop}:${key}` },
|
|
25
|
+
createElement(Prop, { propName: key, key: `${Prop}:${key}` }, record[key] as ReactNode),
|
|
15
26
|
);
|
|
16
|
-
} else {
|
|
17
|
-
hostProps[key] = value;
|
|
18
27
|
}
|
|
28
|
+
|
|
29
|
+
return propChildren;
|
|
19
30
|
};
|
|
20
31
|
|
|
21
|
-
const
|
|
22
|
-
const Host = typeName as ElementType;
|
|
32
|
+
const hostPropsWithout = (record: Props): Props => {
|
|
23
33
|
const hostProps: Props = {};
|
|
24
|
-
const propChildren: ReactNode[] = [];
|
|
25
34
|
|
|
26
35
|
for (const key in record) {
|
|
27
|
-
if (key
|
|
28
|
-
|
|
36
|
+
if (key !== "children" && !isRoutedProp(key, record[key])) {
|
|
37
|
+
hostProps[key] = record[key];
|
|
29
38
|
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return hostProps;
|
|
42
|
+
};
|
|
30
43
|
|
|
31
|
-
|
|
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
|
+
);
|
|
32
55
|
}
|
|
33
56
|
|
|
34
57
|
return (
|
|
35
|
-
<Host {...
|
|
58
|
+
<Host {...hostPropsWithout(record)}>
|
|
36
59
|
{propChildren}
|
|
37
60
|
{record.children as ReactNode}
|
|
38
61
|
</Host>
|
|
39
62
|
);
|
|
40
63
|
};
|
|
41
64
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
+
}
|
|
46
81
|
|
|
47
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 };
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import { type ElementType, type
|
|
3
|
-
import { useMergedRef } from "../hooks/use-merged-refs.js";
|
|
2
|
+
import { type ElementType, type ReactElement, type ReactNode, use } from "react";
|
|
4
3
|
import { ParentWindowContext } from "../hooks/use-parent-window.js";
|
|
4
|
+
import { createPresentedComponent, type PresentedProps } from "../hooks/use-presented-instance.js";
|
|
5
5
|
import { applyWrite } from "../reconciler/signals.js";
|
|
6
|
+
import { createPortaledComponent } from "./portaled.js";
|
|
6
7
|
|
|
7
|
-
type WindowComponentProps = {
|
|
8
|
-
|
|
8
|
+
type WindowComponentProps = PresentedProps<Gtk.Window> & {
|
|
9
|
+
// eslint-disable-next-line gtkx/accessor-naming
|
|
10
|
+
transientFor?: Gtk.Window | ReactElement | null | undefined;
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
const presentWindow = (window: Gtk.Window): void => {
|
|
@@ -20,29 +22,29 @@ const destroyWindow = (window: Gtk.Window): void => {
|
|
|
20
22
|
});
|
|
21
23
|
};
|
|
22
24
|
|
|
23
|
-
const
|
|
24
|
-
return ({ ref, ...rest }: WindowComponentProps): ReactNode => {
|
|
25
|
-
const [window, setWindow] = useState<Gtk.Window | null>(null);
|
|
26
|
-
const mergedRef = useMergedRef(ref, setWindow);
|
|
25
|
+
const usePresentWindow = (): ((window: Gtk.Window) => void) => presentWindow;
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const createPresentedWindowComponent = (Component: ElementType): ((props: PresentedProps<Gtk.Window>) => ReactNode) =>
|
|
28
|
+
createPresentedComponent<Gtk.Window>(Component, {
|
|
29
|
+
usePresent: usePresentWindow,
|
|
30
|
+
dismiss: destroyWindow,
|
|
31
|
+
wrap: (element, window) => (
|
|
32
|
+
<ParentWindowContext.Provider value={window}>{element}</ParentWindowContext.Provider>
|
|
33
|
+
),
|
|
34
|
+
});
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const withDefaultTransientFor = (Component: ElementType): ((props: WindowComponentProps) => ReactNode) => {
|
|
37
|
+
return (props: WindowComponentProps): ReactNode => {
|
|
38
|
+
const parent = use(ParentWindowContext);
|
|
39
|
+
const isDefaulted = props.transientFor === undefined && parent !== null;
|
|
39
40
|
|
|
40
|
-
return (
|
|
41
|
-
<ParentWindowContext.Provider value={window}>
|
|
42
|
-
<Component ref={mergedRef} {...rest} />
|
|
43
|
-
</ParentWindowContext.Provider>
|
|
44
|
-
);
|
|
41
|
+
return <Component {...(isDefaulted ? { ...props, transientFor: parent } : props)} />;
|
|
45
42
|
};
|
|
46
43
|
};
|
|
47
44
|
|
|
45
|
+
const createWindowComponent = (Component: ElementType): ((props: unknown) => ReactNode) =>
|
|
46
|
+
createPortaledComponent(withDefaultTransientFor(createPresentedWindowComponent(Component)));
|
|
47
|
+
|
|
48
|
+
export { createPresentedWindowComponent };
|
|
49
|
+
/** @internal */
|
|
48
50
|
export { createWindowComponent };
|
package/src/config.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
/** @public */
|
|
2
|
+
export { createElementComponent } from "./components/element.js";
|
|
3
|
+
/** @public */
|
|
1
4
|
export { BUILTIN_ELEMENTS } from "./element-config.js";
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/** @public */
|
|
6
|
+
export type {
|
|
7
|
+
DetachInfo,
|
|
8
|
+
ElementBehavior,
|
|
9
|
+
ElementConfig,
|
|
10
|
+
ModuleExport,
|
|
11
|
+
PlaceInfo,
|
|
12
|
+
Props,
|
|
10
13
|
} from "./reconciler/registry.js";
|
|
14
|
+
/** @public */
|
|
15
|
+
export { defineBehavior, defineElements, ELEMENTS, mergeElementConfigs } from "./reconciler/registry.js";
|
package/src/element-behaviors.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
2
|
import * as Gio from "@gtkx/gi/gio";
|
|
3
|
+
import * as GLib from "@gtkx/gi/glib";
|
|
3
4
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
5
|
import type {
|
|
5
6
|
ActionAccel,
|
|
6
7
|
CreditSection,
|
|
7
8
|
DragSourceIcon,
|
|
8
9
|
LevelBarOffset,
|
|
10
|
+
MainOption,
|
|
9
11
|
MenuItem,
|
|
10
12
|
ScaleMark,
|
|
11
13
|
VflConstraints,
|
|
@@ -14,6 +16,7 @@ import { BUILTIN_ELEMENTS, SINGLE_CHILD_TYPES } from "./element-config.js";
|
|
|
14
16
|
import {
|
|
15
17
|
addRemoveSlot,
|
|
16
18
|
adoptedChildrenSlot,
|
|
19
|
+
applicationCreator,
|
|
17
20
|
boxSlot,
|
|
18
21
|
childSetterSlot,
|
|
19
22
|
controlledText,
|
|
@@ -25,7 +28,6 @@ import {
|
|
|
25
28
|
} from "./reconciler/behaviors.js";
|
|
26
29
|
import { type ElementConfig, forTypes, registerElements } from "./reconciler/registry.js";
|
|
27
30
|
|
|
28
|
-
/** The runtime half of the built-in element configuration: the behaviors bound to each GObject type. */
|
|
29
31
|
const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
30
32
|
...forTypes(SINGLE_CHILD_TYPES, {
|
|
31
33
|
behaviors: [childSetterSlot()],
|
|
@@ -296,6 +298,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
296
298
|
},
|
|
297
299
|
GtkApplication: {
|
|
298
300
|
behaviors: [
|
|
301
|
+
applicationCreator(Gtk.Application),
|
|
299
302
|
addRemoveSlot<Gtk.Window, Gtk.Application>(
|
|
300
303
|
"children",
|
|
301
304
|
"GtkWindow",
|
|
@@ -314,6 +317,11 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
314
317
|
application.setAccelsForAction(item.detailedActionName, []);
|
|
315
318
|
},
|
|
316
319
|
}),
|
|
320
|
+
list<Gtk.Application, MainOption>("mainOptions", {
|
|
321
|
+
add: (application, option) => {
|
|
322
|
+
addMainOption(application, option);
|
|
323
|
+
},
|
|
324
|
+
}),
|
|
317
325
|
],
|
|
318
326
|
},
|
|
319
327
|
GtkAboutDialog: {
|
|
@@ -392,6 +400,17 @@ function layoutChild(parent: Gtk.Widget, child: Gtk.Widget): GObject.Object | nu
|
|
|
392
400
|
return parent.getLayoutManager()?.getLayoutChild(child) ?? null;
|
|
393
401
|
}
|
|
394
402
|
|
|
403
|
+
const addMainOption = (application: Gtk.Application, option: MainOption): void => {
|
|
404
|
+
application.addMainOption(
|
|
405
|
+
option.longName,
|
|
406
|
+
option.shortName?.codePointAt(0) ?? 0,
|
|
407
|
+
option.flags ?? GLib.OptionFlags.NONE,
|
|
408
|
+
option.arg ?? GLib.OptionArg.NONE,
|
|
409
|
+
option.description,
|
|
410
|
+
option.argDescription ?? null,
|
|
411
|
+
);
|
|
412
|
+
};
|
|
413
|
+
|
|
395
414
|
const buildMenu = (items: MenuItem[]): Gio.Menu => {
|
|
396
415
|
const menu = Gio.Menu.new();
|
|
397
416
|
|