@gtkx/react 1.0.0-rc.4 → 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 +5 -5
- package/dist/adw/dialog.d.ts +3 -4
- package/dist/adw/dialog.d.ts.map +1 -1
- package/dist/adw/dialog.js +15 -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 +21 -6
- 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 +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 +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 +3 -0
- package/dist/reconciler/root.d.ts.map +1 -1
- package/dist/reconciler/root.js +2 -0
- 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 +4 -4
- package/src/adw/dialog.tsx +22 -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 +31 -5
- 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 +19 -31
- 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 +6 -0
- 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
|
@@ -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,30 +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 };
|
|
48
49
|
/** @internal */
|
|
49
50
|
export { createWindowComponent };
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/** @public */
|
|
2
|
+
export { createElementComponent } from "./components/element.js";
|
|
3
|
+
/** @public */
|
|
2
4
|
export { BUILTIN_ELEMENTS } from "./element-config.js";
|
|
3
5
|
/** @public */
|
|
4
|
-
export type {
|
|
6
|
+
export type {
|
|
7
|
+
DetachInfo,
|
|
8
|
+
ElementBehavior,
|
|
9
|
+
ElementConfig,
|
|
10
|
+
ModuleExport,
|
|
11
|
+
PlaceInfo,
|
|
12
|
+
Props,
|
|
13
|
+
} from "./reconciler/registry.js";
|
|
5
14
|
/** @public */
|
|
6
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,
|
|
@@ -295,6 +298,7 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
295
298
|
},
|
|
296
299
|
GtkApplication: {
|
|
297
300
|
behaviors: [
|
|
301
|
+
applicationCreator(Gtk.Application),
|
|
298
302
|
addRemoveSlot<Gtk.Window, Gtk.Application>(
|
|
299
303
|
"children",
|
|
300
304
|
"GtkWindow",
|
|
@@ -313,6 +317,11 @@ const BUILTIN_BEHAVIORS: Record<string, ElementConfig<never>> = {
|
|
|
313
317
|
application.setAccelsForAction(item.detailedActionName, []);
|
|
314
318
|
},
|
|
315
319
|
}),
|
|
320
|
+
list<Gtk.Application, MainOption>("mainOptions", {
|
|
321
|
+
add: (application, option) => {
|
|
322
|
+
addMainOption(application, option);
|
|
323
|
+
},
|
|
324
|
+
}),
|
|
316
325
|
],
|
|
317
326
|
},
|
|
318
327
|
GtkAboutDialog: {
|
|
@@ -391,6 +400,17 @@ function layoutChild(parent: Gtk.Widget, child: Gtk.Widget): GObject.Object | nu
|
|
|
391
400
|
return parent.getLayoutManager()?.getLayoutChild(child) ?? null;
|
|
392
401
|
}
|
|
393
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
|
+
|
|
394
414
|
const buildMenu = (items: MenuItem[]): Gio.Menu => {
|
|
395
415
|
const menu = Gio.Menu.new();
|
|
396
416
|
|
package/src/element-config.ts
CHANGED
|
@@ -4,7 +4,6 @@ const SINGLE_CHILD_TYPES: string[] = [
|
|
|
4
4
|
"GtkAspectFrame",
|
|
5
5
|
"GtkButton",
|
|
6
6
|
"GtkCheckButton",
|
|
7
|
-
"GtkComboBox",
|
|
8
7
|
"GtkDragIcon",
|
|
9
8
|
"GtkExpander",
|
|
10
9
|
"GtkFlowBoxChild",
|
|
@@ -43,6 +42,9 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
43
42
|
component: internal("createWindowComponent"),
|
|
44
43
|
omittedProps: ["child"],
|
|
45
44
|
},
|
|
45
|
+
GtkApplicationWindow: {
|
|
46
|
+
component: internal("createApplicationWindowComponent"),
|
|
47
|
+
},
|
|
46
48
|
GtkLabel: {
|
|
47
49
|
props: internal("ChildrenProps"),
|
|
48
50
|
},
|
|
@@ -71,7 +73,7 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
71
73
|
isLazy: true,
|
|
72
74
|
},
|
|
73
75
|
GActionGroup: {
|
|
74
|
-
props: internal("
|
|
76
|
+
props: internal("ActionGroupProps"),
|
|
75
77
|
},
|
|
76
78
|
GtkWidget: {
|
|
77
79
|
props: internal("GtkWidgetProps"),
|
|
@@ -96,10 +98,10 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
96
98
|
props: internal("ChildrenProps"),
|
|
97
99
|
},
|
|
98
100
|
GActionMap: {
|
|
99
|
-
props: internal("
|
|
101
|
+
props: internal("ActionMapProps"),
|
|
100
102
|
},
|
|
101
103
|
GMenu: {
|
|
102
|
-
props: internal("
|
|
104
|
+
props: internal("MenuProps"),
|
|
103
105
|
},
|
|
104
106
|
GtkColumnView: {
|
|
105
107
|
props: internal("ChildrenProps"),
|
|
@@ -112,6 +114,7 @@ const BUILTIN_ELEMENTS: Record<string, ElementConfig> = {
|
|
|
112
114
|
},
|
|
113
115
|
GtkSizeGroup: {
|
|
114
116
|
props: internal("GtkSizeGroupProps"),
|
|
117
|
+
component: internal("createPortaledComponent"),
|
|
115
118
|
},
|
|
116
119
|
GtkConstraintLayout: {
|
|
117
120
|
props: internal("GtkConstraintLayoutProps"),
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ElementType, type ReactNode, type Ref, type RefCallback, useLayoutEffect, useState } from "react";
|
|
2
|
+
import { useMergedRef } from "./use-merged-refs.js";
|
|
3
|
+
|
|
4
|
+
type PresentedProps<T> = {
|
|
5
|
+
ref?: Ref<T | null> | undefined;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type PresentedOptions<T> = {
|
|
9
|
+
usePresent: () => (instance: T) => void;
|
|
10
|
+
dismiss: (instance: T) => void;
|
|
11
|
+
wrap?: (element: ReactNode, instance: T | null) => ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const usePresentedInstance = <T,>(
|
|
15
|
+
ref: Ref<T | null> | undefined,
|
|
16
|
+
present: (instance: T) => void,
|
|
17
|
+
dismiss: (instance: T) => void,
|
|
18
|
+
): [T | null, RefCallback<T>] => {
|
|
19
|
+
const [instance, setInstance] = useState<T | null>(null);
|
|
20
|
+
const mergedRef = useMergedRef(ref, setInstance);
|
|
21
|
+
|
|
22
|
+
useLayoutEffect(() => {
|
|
23
|
+
if (!instance) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
present(instance);
|
|
28
|
+
|
|
29
|
+
return () => {
|
|
30
|
+
dismiss(instance);
|
|
31
|
+
};
|
|
32
|
+
}, [instance, present, dismiss]);
|
|
33
|
+
|
|
34
|
+
return [instance, mergedRef];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const createPresentedComponent = <T,>(
|
|
38
|
+
Component: ElementType,
|
|
39
|
+
options: PresentedOptions<T>,
|
|
40
|
+
): ((props: PresentedProps<T>) => ReactNode) => {
|
|
41
|
+
return ({ ref, ...rest }: PresentedProps<T>): ReactNode => {
|
|
42
|
+
const present = options.usePresent();
|
|
43
|
+
const [instance, mergedRef] = usePresentedInstance(ref, present, options.dismiss);
|
|
44
|
+
const element = <Component ref={mergedRef} {...rest} />;
|
|
45
|
+
|
|
46
|
+
return options.wrap ? options.wrap(element, instance) : element;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { createPresentedComponent, type PresentedProps };
|
|
@@ -3,6 +3,7 @@ import { kebabCase } from "@gtkx/utils";
|
|
|
3
3
|
import type { RefProp } from "../utils/ref-prop.js";
|
|
4
4
|
import { useObjectValue } from "./use-object-value.js";
|
|
5
5
|
|
|
6
|
+
/** The property map `T` declares, from camelCase property name to value type. */
|
|
6
7
|
type Properties<T extends GObject.Object> = NonNullable<T["__properties__"]>;
|
|
7
8
|
/** Every property `T` declares that is also readable off the instance, in camelCase. */
|
|
8
9
|
type PropertyName<T extends GObject.Object> = keyof Properties<T> & keyof T;
|
|
@@ -20,4 +21,4 @@ function useProperty<T extends GObject.Object, P extends PropertyName<T>>(
|
|
|
20
21
|
return useObjectValue(object, `notify::${kebabCase(propertyName)}`, (obj) => obj?.[propertyName]);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export { useProperty
|
|
24
|
+
export { useProperty };
|
package/src/hooks/use-signal.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { SignalHandler } from "@gtkx/runtime";
|
|
|
3
3
|
import { useEffectEvent, useLayoutEffect } from "react";
|
|
4
4
|
import { type RefProp, resolveRefProp } from "../utils/ref-prop.js";
|
|
5
5
|
|
|
6
|
+
/** The signal map `T` declares, from signal name to handler signature. */
|
|
6
7
|
type Signals<T extends GObject.Object> = NonNullable<T["__signals__"]>;
|
|
7
8
|
/** Every signal name `T` declares, on its own or narrowed by a `::detail` suffix. */
|
|
8
9
|
type SignalName<T extends GObject.Object> = keyof Signals<T> | `${keyof Signals<T> & string}::${string}`;
|
|
@@ -67,4 +68,4 @@ function useSignal<T extends GObject.Object, S extends SignalName<T> & string>(
|
|
|
67
68
|
}, [object, signal, isAfter, isImmediate]);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
export { useSignal
|
|
71
|
+
export { useSignal };
|
package/src/internal.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import "./bootstrap.js";
|
|
2
2
|
|
|
3
|
+
/** @internal */
|
|
4
|
+
export { createApplicationWindowComponent } from "./components/application-window.js";
|
|
3
5
|
/** @internal */
|
|
4
6
|
export { createApplicationComponent } from "./components/application.js";
|
|
5
7
|
export { createElementComponent } from "./components/element.js";
|
|
6
8
|
/** @internal */
|
|
9
|
+
export { createPortaledComponent } from "./components/portaled.js";
|
|
10
|
+
/** @internal */
|
|
7
11
|
export { createWindowComponent } from "./components/window.js";
|
|
8
12
|
export { useMergedRef } from "./hooks/use-merged-refs.js";
|
|
9
13
|
export type * from "./prop-types.js";
|
|
10
|
-
export
|
|
14
|
+
export { settleAccessible } from "./reconciler/apply-props.js";
|
|
11
15
|
export { isRootElement } from "./reconciler/root-element.js";
|
|
12
16
|
export { createReconcilerRoot, type ReconcilerRoot, setReconcilerErrorHandler } from "./reconciler/root.js";
|
|
13
|
-
export { applyWrite } from "./reconciler/signals.js";
|
|
14
|
-
export { getAccessibleMetadata } from "./utils/accessible-metadata.js";
|
|
15
17
|
export type { SettingsSchema, SettingsSchemaKeys, SettingValue } from "./utils/settings.js";
|
package/src/prop-types.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/* eslint-disable gtkx/no-library-prefix */
|
|
1
2
|
import type * as Gdk from "@gtkx/gi/gdk";
|
|
3
|
+
import type * as GLib from "@gtkx/gi/glib";
|
|
2
4
|
import type * as GObject from "@gtkx/gi/gobject";
|
|
3
5
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
4
6
|
import type { ReactNode } from "react";
|
|
@@ -53,6 +55,22 @@ type CreditSection = {
|
|
|
53
55
|
people: string[];
|
|
54
56
|
};
|
|
55
57
|
|
|
58
|
+
/** One command-line option a `Gtk.Application` accepts. */
|
|
59
|
+
type MainOption = {
|
|
60
|
+
/** Name the option is spelled with after two dashes, such as `verbose` for `--verbose`. */
|
|
61
|
+
longName: string;
|
|
62
|
+
/** Single character the option is spelled with after one dash, such as `v` for `-v`; defaults to none. */
|
|
63
|
+
shortName?: string | null;
|
|
64
|
+
/** How the option itself is parsed and listed; defaults to `GLib.OptionFlags.NONE`. */
|
|
65
|
+
flags?: GLib.OptionFlags;
|
|
66
|
+
/** Type of argument the option takes; defaults to `GLib.OptionArg.NONE`, meaning it takes none. */
|
|
67
|
+
arg?: GLib.OptionArg;
|
|
68
|
+
/** Text describing the option in `--help`. */
|
|
69
|
+
description: string;
|
|
70
|
+
/** Placeholder standing for the option's argument in `--help`; defaults to none. */
|
|
71
|
+
argDescription?: string | null;
|
|
72
|
+
};
|
|
73
|
+
|
|
56
74
|
/** One accelerator binding on a `Gtk.Application`. */
|
|
57
75
|
type ActionAccel = {
|
|
58
76
|
/** Action the accelerators activate, such as `app.quit` or `win.open('file')`. */
|
|
@@ -86,19 +104,19 @@ type GtkWidgetProps = {
|
|
|
86
104
|
} & ChildrenProps;
|
|
87
105
|
|
|
88
106
|
/** Props of an action group placed in a widget's `actionGroups` slot. */
|
|
89
|
-
type
|
|
107
|
+
type ActionGroupProps = {
|
|
90
108
|
/** Prefix the group's actions are addressed by, such as `win`; defaults to the empty string. */
|
|
91
109
|
prefix?: string | null | undefined;
|
|
92
110
|
};
|
|
93
111
|
|
|
94
112
|
/** Props of an element implementing `Gio.ActionMap`. */
|
|
95
|
-
type
|
|
113
|
+
type ActionMapProps = {
|
|
96
114
|
/** `Gio.Action` elements added to the map, removed again by their `name`. */
|
|
97
115
|
actions?: ReactNode | null | undefined;
|
|
98
116
|
};
|
|
99
117
|
|
|
100
118
|
/** Props of a `Gio.Menu` element. */
|
|
101
|
-
type
|
|
119
|
+
type MenuProps = {
|
|
102
120
|
/** Entries the menu is rebuilt from whenever they change. */
|
|
103
121
|
items?: MenuItem[] | null | undefined;
|
|
104
122
|
};
|
|
@@ -165,7 +183,10 @@ type GtkSizeGroupProps = {
|
|
|
165
183
|
|
|
166
184
|
/** Props of a `Gtk.AboutDialog` element. */
|
|
167
185
|
type GtkAboutDialogProps = {
|
|
168
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* Extra sections appended to the dialog's credits. GTK offers no way to remove one, so the list
|
|
188
|
+
* cannot change once it has been applied.
|
|
189
|
+
*/
|
|
169
190
|
creditSections?: CreditSection[] | null | undefined;
|
|
170
191
|
};
|
|
171
192
|
|
|
@@ -173,6 +194,11 @@ type GtkAboutDialogProps = {
|
|
|
173
194
|
type GtkApplicationProps = {
|
|
174
195
|
/** Accelerators bound to the application's actions. */
|
|
175
196
|
actionAccels?: ActionAccel[] | null | undefined;
|
|
197
|
+
/**
|
|
198
|
+
* Command-line options the application parses, registered before it starts. GLib offers no way to
|
|
199
|
+
* unregister one, so the list cannot change once it has been applied.
|
|
200
|
+
*/
|
|
201
|
+
mainOptions?: MainOption[] | null | undefined;
|
|
176
202
|
} & ChildrenProps;
|
|
177
203
|
|
|
178
204
|
/** Props of a `Gtk.DropTarget` element. */
|
|
@@ -199,13 +225,14 @@ export {
|
|
|
199
225
|
type ScaleMark,
|
|
200
226
|
type LevelBarOffset,
|
|
201
227
|
type CreditSection,
|
|
228
|
+
type MainOption,
|
|
202
229
|
type ActionAccel,
|
|
203
230
|
type DragSourceIcon,
|
|
204
231
|
type ChildrenProps,
|
|
205
232
|
type GtkWidgetProps,
|
|
206
|
-
type
|
|
207
|
-
type
|
|
208
|
-
type
|
|
233
|
+
type ActionGroupProps,
|
|
234
|
+
type ActionMapProps,
|
|
235
|
+
type MenuProps,
|
|
209
236
|
type GtkShortcutControllerProps,
|
|
210
237
|
type GtkOverlayProps,
|
|
211
238
|
type GtkTextChildAnchorProps,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
2
|
import type { SignalHandler } from "@gtkx/runtime";
|
|
3
3
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
|
-
import { drain, kebabCase } from "@gtkx/utils";
|
|
4
|
+
import { drain, isDeepEqual, kebabCase } from "@gtkx/utils";
|
|
5
5
|
import type { ElementBehavior, Props } from "./registry.js";
|
|
6
6
|
import { applyAccessibleProps, isAccessibleProp } from "../utils/accessible-props.js";
|
|
7
7
|
import { type TypeInfo, typeInfoFor } from "./metadata.js";
|
|
@@ -16,9 +16,13 @@ type PropChange = { prev: Props; next: Props };
|
|
|
16
16
|
const REACT_RESERVED_PROPS = new Set(["children", "ref", "key"]);
|
|
17
17
|
const NOTIFY_PREFIX = "onNotify";
|
|
18
18
|
const HANDLER_PREFIX = "on";
|
|
19
|
+
const HANDLER_NAME = /^on[A-Z]/;
|
|
19
20
|
const flushDirty: Set<ElementNode> = new Set();
|
|
21
|
+
const accessibleDirty: Map<ElementNode, Props> = new Map();
|
|
22
|
+
const mapWatched: WeakSet<ElementNode> = new WeakSet();
|
|
23
|
+
const pendingMap: Set<ElementNode> = new Set();
|
|
20
24
|
|
|
21
|
-
const isHandlerName = (name: string): boolean =>
|
|
25
|
+
const isHandlerName = (name: string): boolean => HANDLER_NAME.test(name);
|
|
22
26
|
|
|
23
27
|
const signalForProp = (info: TypeInfo, name: string): string => {
|
|
24
28
|
if (name === NOTIFY_PREFIX) {
|
|
@@ -102,29 +106,42 @@ const applyEntry = (node: ElementNode, info: TypeInfo, delta: PropDelta): void =
|
|
|
102
106
|
};
|
|
103
107
|
|
|
104
108
|
const eachChangedName = (prev: Props, next: Props, visit: (name: string) => void): void => {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
for (const name of names) {
|
|
109
|
+
for (const name in prev) {
|
|
108
110
|
visit(name);
|
|
109
111
|
}
|
|
112
|
+
|
|
113
|
+
for (const name in next) {
|
|
114
|
+
if (!Object.hasOwn(prev, name)) {
|
|
115
|
+
visit(name);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
110
118
|
};
|
|
111
119
|
|
|
112
|
-
const
|
|
120
|
+
const propChangeError = (typeName: string, name: string): Error =>
|
|
113
121
|
new Error(
|
|
114
122
|
`Cannot change the construct-only prop '${name}' of <${typeName}> after it is created. ` +
|
|
115
|
-
"
|
|
123
|
+
"It is only accepted while the element is being built, so give the element a key that " +
|
|
116
124
|
`changes with '${name}' and React will build a new one.`,
|
|
117
125
|
);
|
|
118
126
|
|
|
119
|
-
const
|
|
127
|
+
const hasAppliedValue = (value: unknown): boolean => (Array.isArray(value) ? value.length > 0 : value !== undefined);
|
|
128
|
+
|
|
129
|
+
const isConstructOnlyChange = (info: TypeInfo, name: string, change: PropChange): boolean =>
|
|
130
|
+
info.constructOnly.has(name) && !Object.is(change.prev[name], change.next[name]);
|
|
131
|
+
|
|
132
|
+
const isDeclaredConstructOnlyChange = (info: TypeInfo, name: string, change: PropChange): boolean =>
|
|
133
|
+
info.declaredConstructOnly.has(name) &&
|
|
134
|
+
hasAppliedValue(change.prev[name]) &&
|
|
135
|
+
!isDeepEqual(change.prev[name], change.next[name]);
|
|
136
|
+
|
|
137
|
+
const assertPropsCanChange = (typeName: string, prev: Props, next: Props): void => {
|
|
120
138
|
const info = typeInfoFor(typeName);
|
|
139
|
+
const change: PropChange = { prev, next };
|
|
121
140
|
|
|
122
141
|
eachChangedName(prev, next, (name) => {
|
|
123
|
-
if (
|
|
124
|
-
|
|
142
|
+
if (isConstructOnlyChange(info, name, change) || isDeclaredConstructOnlyChange(info, name, change)) {
|
|
143
|
+
throw propChangeError(typeName, name);
|
|
125
144
|
}
|
|
126
|
-
|
|
127
|
-
throw constructOnlyChangeError(typeName, name);
|
|
128
145
|
});
|
|
129
146
|
};
|
|
130
147
|
|
|
@@ -213,22 +230,58 @@ const flushBehaviors = (): void => {
|
|
|
213
230
|
});
|
|
214
231
|
};
|
|
215
232
|
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
233
|
+
const applyAccessible = (object: GObject.Object, prev: Props | null, next: Props): void => {
|
|
234
|
+
if (object instanceof Gtk.Accessible) {
|
|
235
|
+
applyAccessibleProps(object, prev, next);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const markAccessible = (node: ElementNode, prev: Props): void => {
|
|
240
|
+
if (!accessibleDirty.has(node)) {
|
|
241
|
+
accessibleDirty.set(node, prev);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const hasAccessibleProp = (props: Props): boolean => {
|
|
246
|
+
for (const name in props) {
|
|
247
|
+
if (isAccessibleProp(name)) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return false;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const watchMap = (node: ElementNode): void => {
|
|
256
|
+
const { object } = node;
|
|
257
|
+
|
|
258
|
+
if (mapWatched.has(node) || !(object instanceof Gtk.Widget) || !hasAccessibleProp(node.props)) {
|
|
218
259
|
return;
|
|
219
260
|
}
|
|
220
261
|
|
|
221
|
-
|
|
262
|
+
mapWatched.add(node);
|
|
263
|
+
|
|
264
|
+
object.connect("map", () => {
|
|
265
|
+
pendingMap.add(node);
|
|
266
|
+
setTimeout(settleAccessible, 0);
|
|
267
|
+
});
|
|
222
268
|
};
|
|
223
269
|
|
|
224
|
-
const
|
|
225
|
-
|
|
270
|
+
const settleAccessible = (): void => {
|
|
271
|
+
drain(pendingMap, (node) => {
|
|
272
|
+
if (node.object instanceof Gtk.Widget && node.object.getMapped()) {
|
|
273
|
+
applyAccessible(node.object, null, node.props);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
226
276
|
};
|
|
227
277
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
278
|
+
const flushAccessible = (): void => {
|
|
279
|
+
for (const [node, prev] of accessibleDirty) {
|
|
280
|
+
applyAccessible(node.object, prev, node.props);
|
|
281
|
+
watchMap(node);
|
|
231
282
|
}
|
|
283
|
+
|
|
284
|
+
accessibleDirty.clear();
|
|
232
285
|
};
|
|
233
286
|
|
|
234
287
|
const applyElementProps = (node: ElementNode, prev: Props, next: Props): void => {
|
|
@@ -236,8 +289,8 @@ const applyElementProps = (node: ElementNode, prev: Props, next: Props): void =>
|
|
|
236
289
|
const consumed = runBehaviorUpdates(node, info, prev, next);
|
|
237
290
|
applyValueEntries(node, info, { prev, next }, consumed);
|
|
238
291
|
restoreActionableSensitivity(node, info, prev, next);
|
|
239
|
-
applyAccessible(node.object, prev, next);
|
|
240
292
|
applyHandlers(node, info, prev, next);
|
|
293
|
+
markAccessible(node, prev);
|
|
241
294
|
markFlush(node);
|
|
242
295
|
node.props = next;
|
|
243
296
|
};
|
|
@@ -262,10 +315,10 @@ const applyAdoptedProps = (target: SignalTarget, prev: Props, next: Props): void
|
|
|
262
315
|
|
|
263
316
|
export {
|
|
264
317
|
markFlush,
|
|
318
|
+
flushAccessible,
|
|
319
|
+
settleAccessible,
|
|
265
320
|
flushBehaviors,
|
|
266
|
-
mountBehaviors,
|
|
267
|
-
unmountBehaviors,
|
|
268
321
|
applyElementProps,
|
|
269
322
|
applyAdoptedProps,
|
|
270
|
-
|
|
323
|
+
assertPropsCanChange,
|
|
271
324
|
};
|