@gtkx/react 1.0.0-rc.3 → 1.0.0-rc.4
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 +4 -5
- 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 +1 -0
- package/dist/adw/dialog.d.ts.map +1 -1
- package/dist/adw/dialog.js +1 -0
- package/dist/adw/dialog.js.map +1 -1
- package/dist/adw/element-behaviors.js +2 -3
- package/dist/adw/element-behaviors.js.map +1 -1
- package/dist/adw/element-config.d.ts +4 -3
- package/dist/adw/element-config.d.ts.map +1 -1
- package/dist/adw/element-config.js +14 -13
- 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 +1 -1
- 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.d.ts +1 -0
- package/dist/components/application.d.ts.map +1 -1
- package/dist/components/application.js +1 -0
- package/dist/components/application.js.map +1 -1
- package/dist/components/element.d.ts +0 -1
- package/dist/components/element.d.ts.map +1 -1
- package/dist/components/element.js +0 -1
- package/dist/components/element.js.map +1 -1
- package/dist/components/window.d.ts +1 -0
- package/dist/components/window.d.ts.map +1 -1
- package/dist/components/window.js +1 -0
- package/dist/components/window.js.map +1 -1
- package/dist/config.d.ts +5 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -1
- package/dist/config.js.map +1 -1
- package/dist/element-behaviors.js +0 -1
- 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 +12 -11
- 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-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-property.d.ts +2 -2
- 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 +13 -7
- 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 +4 -3
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -3
- package/dist/internal.js.map +1 -1
- package/dist/prop-types.d.ts +60 -0
- package/dist/prop-types.d.ts.map +1 -1
- package/dist/prop-types.js.map +1 -1
- package/dist/reconciler/behaviors.d.ts +0 -15
- package/dist/reconciler/behaviors.d.ts.map +1 -1
- package/dist/reconciler/behaviors.js +5 -20
- package/dist/reconciler/behaviors.js.map +1 -1
- 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.map +1 -1
- package/dist/reconciler/instance.js +1 -1
- 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 +7 -7
- package/dist/reconciler/metadata.js.map +1 -1
- package/dist/reconciler/node.d.ts +2 -2
- package/dist/reconciler/node.d.ts.map +1 -1
- package/dist/reconciler/node.js +1 -1
- package/dist/reconciler/node.js.map +1 -1
- package/dist/reconciler/placement.js +6 -6
- package/dist/reconciler/placement.js.map +1 -1
- package/dist/reconciler/registry.d.ts +42 -30
- 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 +0 -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 +6 -20
- package/dist/reconciler/root.d.ts.map +1 -1
- package/dist/reconciler/root.js +4 -19
- package/dist/reconciler/root.js.map +1 -1
- package/dist/reconciler/signals.js +2 -2
- 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-metadata.d.ts +0 -7
- package/dist/utils/accessible-metadata.d.ts.map +1 -1
- package/dist/utils/accessible-metadata.js +0 -7
- package/dist/utils/accessible-metadata.js.map +1 -1
- package/dist/utils/accessible-props.d.ts +49 -1
- package/dist/utils/accessible-props.d.ts.map +1 -1
- 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 +6 -0
- package/dist/utils/settings.d.ts.map +1 -1
- package/dist/utils/settings.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 +1 -0
- package/src/adw/element-behaviors.ts +2 -3
- package/src/adw/element-config.ts +14 -13
- package/src/adw/index.ts +1 -0
- package/src/adw/prop-types.ts +1 -1
- package/src/bootstrap.ts +1 -1
- package/src/components/application.tsx +1 -0
- package/src/components/element.tsx +0 -1
- package/src/components/window.tsx +1 -0
- package/src/config.ts +5 -9
- package/src/element-behaviors.ts +0 -1
- package/src/element-config.ts +12 -11
- package/src/hooks/use-bind-setting.ts +8 -7
- package/src/hooks/use-parent-window.ts +3 -1
- package/src/hooks/use-property.ts +2 -2
- package/src/hooks/use-setting.ts +2 -3
- package/src/hooks/use-signal.ts +16 -10
- package/src/index.ts +10 -2
- package/src/internal.ts +4 -3
- package/src/prop-types.ts +86 -5
- package/src/reconciler/behaviors.ts +6 -21
- package/src/reconciler/host-config.ts +1 -1
- package/src/reconciler/instance.ts +1 -1
- package/src/reconciler/metadata.ts +8 -8
- package/src/reconciler/node.ts +3 -3
- package/src/reconciler/placement.ts +6 -6
- package/src/reconciler/registry.ts +52 -37
- package/src/reconciler/root-element.ts +0 -1
- package/src/reconciler/root.ts +6 -20
- package/src/reconciler/signals.ts +2 -2
- package/src/reconciler/text.ts +6 -6
- package/src/utils/accessible-metadata.ts +0 -7
- package/src/utils/accessible-props.ts +49 -1
- package/src/utils/ref-prop.ts +0 -6
- package/src/utils/settings.ts +6 -0
|
@@ -27,7 +27,7 @@ const createEntry = (slot: string, node: PlaceableNode): PlacedChild | null => {
|
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
return { node, object, adopted: null, slot, behavior: null,
|
|
30
|
+
return { node, object, adopted: null, slot, behavior: null, isAttached: false };
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
const siblingAt = (entries: PlacedChild[], index: number): GObject.Object | null =>
|
|
@@ -80,7 +80,7 @@ const setObjectSlot = (parent: ElementNode, entry: PlacedChild): void => {
|
|
|
80
80
|
writeSlot(parent, entry, entry.object);
|
|
81
81
|
wireBufferView(entry.node, parent);
|
|
82
82
|
entry.behavior = null;
|
|
83
|
-
entry.
|
|
83
|
+
entry.isAttached = true;
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
const didAttach = (ctx: AttachContext, behavior: ElementBehavior): boolean => {
|
|
@@ -99,7 +99,7 @@ const didAttach = (ctx: AttachContext, behavior: ElementBehavior): boolean => {
|
|
|
99
99
|
|
|
100
100
|
ctx.entry.behavior = behavior;
|
|
101
101
|
adoptedFrom(ctx.parent, ctx.entry, behavior, claim);
|
|
102
|
-
ctx.entry.
|
|
102
|
+
ctx.entry.isAttached = true;
|
|
103
103
|
applyLazyProps(ctx.entry);
|
|
104
104
|
|
|
105
105
|
return true;
|
|
@@ -147,11 +147,11 @@ const runDetach = (parent: ElementNode, entry: PlacedChild): void => {
|
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
const detachEntry = (parent: ElementNode, entry: PlacedChild): void => {
|
|
150
|
-
if (!entry.
|
|
150
|
+
if (!entry.isAttached) {
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
entry.
|
|
154
|
+
entry.isAttached = false;
|
|
155
155
|
|
|
156
156
|
applyWrite(() => {
|
|
157
157
|
runDetach(parent, entry);
|
|
@@ -175,7 +175,7 @@ const getPosition = (entries: PlacedChild[], before: PlaceableNode | null): numb
|
|
|
175
175
|
const placeNew = (parent: ElementNode, entry: PlacedChild, entries: PlacedChild[], index: number): void => {
|
|
176
176
|
attachEntry(parent, entry, index, siblingAt(entries, index));
|
|
177
177
|
|
|
178
|
-
if (!entry.
|
|
178
|
+
if (!entry.isAttached) {
|
|
179
179
|
remove(entries, entry);
|
|
180
180
|
|
|
181
181
|
return;
|
|
@@ -5,62 +5,86 @@ type Props = Record<string, unknown>;
|
|
|
5
5
|
|
|
6
6
|
/** Per-child values a slot hook receives while placing or moving one child. */
|
|
7
7
|
type PlaceInfo = {
|
|
8
|
+
/** Name of the slot being filled: `children`, or the prop the child was nested under. */
|
|
8
9
|
slot: string;
|
|
10
|
+
/** Position of the child among the slot's children. */
|
|
9
11
|
index: number;
|
|
12
|
+
/** Object of the preceding child in the slot, or null when the child comes first. */
|
|
10
13
|
sibling: GObject.Object | null;
|
|
14
|
+
/** Object adopted for this child by an earlier attach, or null before it has one. */
|
|
11
15
|
adopted: GObject.Object | null;
|
|
16
|
+
/** Props of the child element. */
|
|
12
17
|
props: Props;
|
|
18
|
+
/** Value `initialize` returned for this behavior on the parent. */
|
|
13
19
|
context: unknown;
|
|
14
20
|
};
|
|
15
21
|
|
|
16
22
|
/** Per-child values a slot hook receives while removing one child. */
|
|
17
23
|
type DetachInfo = {
|
|
24
|
+
/** Name of the slot the child is leaving. */
|
|
18
25
|
slot: string;
|
|
26
|
+
/** Object the container adopted for this child, or null when it adopted none. */
|
|
19
27
|
adopted: GObject.Object | null;
|
|
28
|
+
/** Props of the child element. */
|
|
20
29
|
props: Props;
|
|
30
|
+
/** Value `initialize` returned for this behavior on the parent. */
|
|
21
31
|
context: unknown;
|
|
22
32
|
};
|
|
23
33
|
|
|
24
34
|
/**
|
|
25
|
-
* Customizes how one element type places children and applies props.
|
|
26
|
-
* GObject instance
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* are not also set as plain GObject properties. `create` builds the GObject for types whose
|
|
30
|
-
* constructor does more than set properties, and is consulted for its own type only, never
|
|
31
|
-
* inherited by subtypes.
|
|
35
|
+
* Customizes how one element type places children and applies props. Hooks other than `create` receive the
|
|
36
|
+
* GObject instance; `update`, `flush`, `mount` and `unmount` also take the private per-node context
|
|
37
|
+
* `initialize` built, and `attach`, `reorder` and `detach` read it off their info object. Subtypes inherit a
|
|
38
|
+
* type's behaviors, except for `create`, which is consulted only for the type it is registered on.
|
|
32
39
|
*/
|
|
33
40
|
type ElementBehavior<T extends GObject.Object = GObject.Object> = {
|
|
41
|
+
/** Builds the GObject from its construct props, for types whose constructor does more than set properties. */
|
|
34
42
|
create?: (props: Props) => GObject.Object;
|
|
35
|
-
|
|
43
|
+
/** Builds the private per-node context the other hooks receive, once per node. */
|
|
44
|
+
initialize?: (object: T) => unknown;
|
|
45
|
+
/** Places a child, claiming it by returning anything other than `undefined`. */
|
|
36
46
|
attach?: (object: T, child: GObject.Object, info: PlaceInfo) => unknown;
|
|
47
|
+
/** Moves an already-attached child; without it, the whole slot is detached and re-attached in order. */
|
|
37
48
|
reorder?: (object: T, child: GObject.Object, info: PlaceInfo) => unknown;
|
|
49
|
+
/** Removes a child this behavior attached. */
|
|
38
50
|
detach?: (object: T, child: GObject.Object, info: DetachInfo) => void;
|
|
51
|
+
/** Returns the object the container adopts for a child, overriding whatever `attach` returned. */
|
|
39
52
|
resolve?: (object: T, child: GObject.Object) => GObject.Object | null;
|
|
53
|
+
/** Applies changed props and returns the names it consumed, which are then not set as GObject properties. */
|
|
40
54
|
update?: (object: T, prev: Props, next: Props, context: unknown) => Iterable<string> | undefined;
|
|
55
|
+
/** Runs after the commit that touched the node, once every child has been placed. */
|
|
41
56
|
flush?: (object: T, context: unknown) => void;
|
|
57
|
+
/** Runs once the node and its initial children are attached. */
|
|
42
58
|
mount?: (object: T, context: unknown) => void;
|
|
59
|
+
/** Runs when React deletes the node. */
|
|
43
60
|
unmount?: (object: T, context: unknown) => void;
|
|
61
|
+
/** Props to withhold from the constructor, leaving them for a later hook to apply. */
|
|
44
62
|
deferred?: string[];
|
|
45
63
|
};
|
|
46
64
|
|
|
47
65
|
/** A named export in a module, referenced as plain data (the module is never imported at runtime). */
|
|
48
|
-
type ModuleExport = {
|
|
66
|
+
type ModuleExport = {
|
|
67
|
+
/** Specifier the export is imported from. */
|
|
68
|
+
module: string;
|
|
69
|
+
/** Identifier the module exports it under. */
|
|
70
|
+
export: string;
|
|
71
|
+
};
|
|
49
72
|
|
|
50
73
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* its type, an optional component that wraps the generated element, the base props interface its
|
|
54
|
-
* generated props extend, and the GObject properties to leave out of the generated props (those a
|
|
55
|
-
* behavior already writes from children, such as the `child` and `content` properties). `component`,
|
|
56
|
-
* `props` and `omitProps` are inert at runtime; they are read only by codegen.
|
|
74
|
+
* How one GLib type is rendered. `component`, `props` and `omittedProps` are inert at runtime; they are
|
|
75
|
+
* read only by codegen.
|
|
57
76
|
*/
|
|
58
77
|
type ElementConfig<T extends GObject.Object = GObject.Object> = {
|
|
59
|
-
|
|
78
|
+
/** The element has no GObject of its own; its parent container creates one, as it does for pages. */
|
|
79
|
+
isLazy?: boolean;
|
|
80
|
+
/** Behaviors bound to the type, consulted in registration order and inherited by its subtypes. */
|
|
60
81
|
behaviors?: ElementBehavior<T>[];
|
|
82
|
+
/** Component that wraps the generated element. */
|
|
61
83
|
component?: ModuleExport;
|
|
84
|
+
/** Base props interface the generated props extend. */
|
|
62
85
|
props?: ModuleExport;
|
|
63
|
-
|
|
86
|
+
/** GObject properties to leave out of the generated props, such as those a behavior writes from children. */
|
|
87
|
+
omittedProps?: string[];
|
|
64
88
|
};
|
|
65
89
|
|
|
66
90
|
/**
|
|
@@ -69,7 +93,6 @@ type ElementConfig<T extends GObject.Object = GObject.Object> = {
|
|
|
69
93
|
*/
|
|
70
94
|
const ELEMENTS: Record<string, ElementConfig> = {};
|
|
71
95
|
|
|
72
|
-
/** Props a behavior applies after construction; the constructor is never given them. */
|
|
73
96
|
const deferredProps = (behavior: ElementBehavior): string[] => behavior.deferred ?? [];
|
|
74
97
|
|
|
75
98
|
const mergeBehaviors = (base: ElementConfig, added: ElementBehavior[], isPrepended: boolean): ElementBehavior[] => {
|
|
@@ -79,19 +102,19 @@ const mergeBehaviors = (base: ElementConfig, added: ElementBehavior[], isPrepend
|
|
|
79
102
|
};
|
|
80
103
|
|
|
81
104
|
const mergeConfigEntry = (base: ElementConfig, added: ElementConfig<never>, isPrepended = false): ElementConfig => {
|
|
82
|
-
const { behaviors,
|
|
105
|
+
const { behaviors, isLazy, omittedProps, ...rest } = added;
|
|
83
106
|
const entry: ElementConfig = { ...base, ...rest };
|
|
84
107
|
|
|
85
108
|
if (behaviors !== undefined) {
|
|
86
109
|
entry.behaviors = mergeBehaviors(base, behaviors as ElementBehavior[], isPrepended);
|
|
87
110
|
}
|
|
88
111
|
|
|
89
|
-
if (
|
|
90
|
-
entry.
|
|
112
|
+
if (omittedProps !== undefined) {
|
|
113
|
+
entry.omittedProps = [...(base.omittedProps ?? []), ...omittedProps];
|
|
91
114
|
}
|
|
92
115
|
|
|
93
|
-
if (
|
|
94
|
-
entry.
|
|
116
|
+
if (isLazy === true) {
|
|
117
|
+
entry.isLazy = true;
|
|
95
118
|
}
|
|
96
119
|
|
|
97
120
|
return entry;
|
|
@@ -99,9 +122,9 @@ const mergeConfigEntry = (base: ElementConfig, added: ElementConfig<never>, isPr
|
|
|
99
122
|
|
|
100
123
|
/**
|
|
101
124
|
* Merges maps of {@link ElementConfig} keyed by GLib type name into one, concatenating each type's
|
|
102
|
-
* behaviors and omitted props in the order the maps are given (an earlier map's behaviors come first)
|
|
103
|
-
*
|
|
104
|
-
* with its behaviors.
|
|
125
|
+
* behaviors and omitted props in the order the maps are given (an earlier map's behaviors come first),
|
|
126
|
+
* taking the last component and props seen, and marking a type lazy if any map does. Use it to combine
|
|
127
|
+
* an app's element config with its behaviors.
|
|
105
128
|
*/
|
|
106
129
|
const mergeElementConfigs = (...maps: Record<string, ElementConfig<never>>[]): Record<string, ElementConfig> => {
|
|
107
130
|
const merged: Record<string, ElementConfig> = {};
|
|
@@ -115,23 +138,17 @@ const mergeElementConfigs = (...maps: Record<string, ElementConfig<never>>[]): R
|
|
|
115
138
|
return merged;
|
|
116
139
|
};
|
|
117
140
|
|
|
118
|
-
/**
|
|
119
|
-
* Registers a map of {@link ElementConfig} keyed by GLib type name, merging each entry into the
|
|
120
|
-
* registry. Behaviors are appended by default (the framework's built-ins register this way); pass
|
|
121
|
-
* `{ prepend: true }` for an app's own configuration so its behaviors are consulted before the
|
|
122
|
-
* built-ins for the same slot, letting it override them regardless of registration order.
|
|
123
|
-
*/
|
|
124
141
|
const registerElements = (
|
|
125
142
|
map: Record<string, ElementConfig<never>>,
|
|
126
|
-
options: {
|
|
143
|
+
options: { isPrepended?: boolean } = {},
|
|
127
144
|
): void => {
|
|
128
145
|
for (const [type, config] of Object.entries(map)) {
|
|
129
|
-
ELEMENTS[type] = mergeConfigEntry(ELEMENTS[type] ?? {}, config, options.
|
|
146
|
+
ELEMENTS[type] = mergeConfigEntry(ELEMENTS[type] ?? {}, config, options.isPrepended === true);
|
|
130
147
|
}
|
|
131
148
|
};
|
|
132
149
|
|
|
133
150
|
/**
|
|
134
|
-
* Identity helper that types the module named by
|
|
151
|
+
* Identity helper that types the module named by `elements.behaviors` in `gtkx.config.ts`, enabling
|
|
135
152
|
* editor autocompletion and type checking. Key each entry by GLib type name and write each behavior
|
|
136
153
|
* with {@link defineBehavior} so its hooks receive the concrete GObject class.
|
|
137
154
|
*/
|
|
@@ -150,11 +167,9 @@ const defineElements = (elements: Record<string, ElementConfig<never>>): Record<
|
|
|
150
167
|
*/
|
|
151
168
|
const defineBehavior = <T extends GObject.Object>(hooks: ElementBehavior<T>): ElementBehavior<never> => hooks;
|
|
152
169
|
|
|
153
|
-
/** Spreads one config across many GLib type names. */
|
|
154
170
|
const forTypes = (types: string[], config: ElementConfig<never>): Record<string, ElementConfig<never>> =>
|
|
155
171
|
Object.fromEntries(types.map((type) => [type, config]));
|
|
156
172
|
|
|
157
|
-
/** References a base props interface exported from `@gtkx/react/internal`. */
|
|
158
173
|
const internal = (name: string): ModuleExport => ({ module: "@gtkx/react/internal", export: name });
|
|
159
174
|
|
|
160
175
|
export {
|
|
@@ -5,7 +5,6 @@ const ROOT_ELEMENT_BRAND: unique symbol = Symbol.for("gtkx:root-element");
|
|
|
5
5
|
/** A shared marker value used as the default top-level container for rendering and portals. */
|
|
6
6
|
const rootElement: RootElement = { [ROOT_ELEMENT_BRAND]: true };
|
|
7
7
|
|
|
8
|
-
/** Reports whether an arbitrary value is a {@link rootElement} marker. */
|
|
9
8
|
const isRootElement = (value: unknown): value is RootElement =>
|
|
10
9
|
typeof value === "object" && value !== null && Object.hasOwn(value, ROOT_ELEMENT_BRAND);
|
|
11
10
|
|
package/src/reconciler/root.ts
CHANGED
|
@@ -15,7 +15,6 @@ type RootErrorCallbacks = {
|
|
|
15
15
|
|
|
16
16
|
type ReconcilerRootOptions = RootErrorCallbacks & { containerInfo: Container };
|
|
17
17
|
|
|
18
|
-
/** A root that mounts an element tree into an explicit container and reports render errors. */
|
|
19
18
|
type ReconcilerRoot = {
|
|
20
19
|
update: (element: ReactNode) => void;
|
|
21
20
|
unmount: (teardown: (root: ReconcilerRoot) => Promise<void>) => Promise<void>;
|
|
@@ -23,7 +22,9 @@ type ReconcilerRoot = {
|
|
|
23
22
|
|
|
24
23
|
/** The object {@link createRoot} returns: it renders an element tree into a container and can tear it down. */
|
|
25
24
|
type Root = {
|
|
25
|
+
/** Mounts an element tree into the container, or updates the tree already mounted there. */
|
|
26
26
|
render: (element: ReactNode) => void;
|
|
27
|
+
/** Unmounts the rendered tree and runs its effect cleanups. */
|
|
27
28
|
unmount: () => void;
|
|
28
29
|
};
|
|
29
30
|
|
|
@@ -49,12 +50,6 @@ function createErrorHandlerSlot(): ErrorHandlerSlot {
|
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
/**
|
|
53
|
-
* Installs a process-wide handler for errors thrown while rendering or applying an update.
|
|
54
|
-
*
|
|
55
|
-
* @param handler The handler to install.
|
|
56
|
-
* @returns The previously installed handler, or null.
|
|
57
|
-
*/
|
|
58
53
|
const setReconcilerErrorHandler = (handler: ErrorHandler): ErrorHandler | null => errorHandlerSlot.set(handler);
|
|
59
54
|
|
|
60
55
|
const rethrowUncaughtRenderError = (error: unknown): never => {
|
|
@@ -97,12 +92,6 @@ const unmountContainer = (container: OpaqueRoot): void => {
|
|
|
97
92
|
activeRoots.delete(container);
|
|
98
93
|
};
|
|
99
94
|
|
|
100
|
-
/**
|
|
101
|
-
* Creates a root that mounts an element tree into a container, routing render errors to the supplied callbacks.
|
|
102
|
-
*
|
|
103
|
-
* @param options The container to render into and the error callbacks to route failures to.
|
|
104
|
-
* @returns A {@link ReconcilerRoot}.
|
|
105
|
-
*/
|
|
106
95
|
const createReconcilerRoot = (options: ReconcilerRootOptions): ReconcilerRoot => {
|
|
107
96
|
const container = openContainer(options.containerInfo, options);
|
|
108
97
|
|
|
@@ -120,10 +109,10 @@ const createReconcilerRoot = (options: ReconcilerRootOptions): ReconcilerRoot =>
|
|
|
120
109
|
};
|
|
121
110
|
|
|
122
111
|
/**
|
|
123
|
-
* Creates a render root for a GTKX application.
|
|
112
|
+
* Creates a render root for a GTKX application. Uncaught render errors are rethrown and errors caught by an
|
|
113
|
+
* error boundary are logged.
|
|
124
114
|
*
|
|
125
|
-
* @param container The
|
|
126
|
-
* @returns A {@link Root} exposing render and unmount.
|
|
115
|
+
* @param container The GObject to render into; defaults to the shared {@link rootElement}, which holds no object.
|
|
127
116
|
*/
|
|
128
117
|
const createRoot = (container: Container = rootElement): Root => {
|
|
129
118
|
const opaque = openContainer(container, {
|
|
@@ -153,10 +142,7 @@ const quit = (): typeof Gdk.EVENT_STOP => {
|
|
|
153
142
|
/**
|
|
154
143
|
* Renders children into a container other than the surrounding tree.
|
|
155
144
|
*
|
|
156
|
-
* @param
|
|
157
|
-
* @param container The GObject, application, or {@link rootElement} to render into.
|
|
158
|
-
* @param key An optional stable key.
|
|
159
|
-
* @returns A React portal.
|
|
145
|
+
* @param container The GObject to render into, or {@link rootElement} to render at the top level.
|
|
160
146
|
*/
|
|
161
147
|
const createPortal = (children: ReactNode, container: Container, key?: string): ReactPortal =>
|
|
162
148
|
reconciler.createPortal(children, container, null, key ?? null) as unknown as ReactPortal;
|
|
@@ -36,7 +36,7 @@ const invokeHandler = (
|
|
|
36
36
|
|
|
37
37
|
const wrapHandler = (target: SignalTarget, record: HandlerRecord, notifyProperty: string | null): SignalHandler =>
|
|
38
38
|
(...args: unknown[]): unknown => {
|
|
39
|
-
if (record.
|
|
39
|
+
if (record.isBlockable && isApplyingWrite()) {
|
|
40
40
|
return undefined;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -58,7 +58,7 @@ const connectHandler = (target: SignalTarget, prop: string, signal: string, hand
|
|
|
58
58
|
|
|
59
59
|
const isBlockable = isBlockableSignal(typeInfoFor(target.typeName), signal);
|
|
60
60
|
const notifyProperty = getNotifyProperty(signal);
|
|
61
|
-
const record: HandlerRecord = { signal, handler, wrapped: (): undefined => undefined,
|
|
61
|
+
const record: HandlerRecord = { signal, handler, wrapped: (): undefined => undefined, isBlockable };
|
|
62
62
|
record.wrapped = wrapHandler(target, record, notifyProperty);
|
|
63
63
|
target.object.on(signal, record.wrapped);
|
|
64
64
|
target.handlers.set(prop, record);
|
package/src/reconciler/text.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { Props } from "./registry.js";
|
|
|
7
7
|
import { ELEMENT_KIND, TEXT_KIND } from "./node.js";
|
|
8
8
|
import { applyWrite } from "./signals.js";
|
|
9
9
|
|
|
10
|
-
type OffsetResult = {
|
|
10
|
+
type OffsetResult = { wasFound: boolean; offset: number };
|
|
11
11
|
|
|
12
12
|
type BufferBuild = {
|
|
13
13
|
buffer: Gtk.TextBuffer;
|
|
@@ -76,14 +76,14 @@ const isTagElement = (node: ContentChild): node is ElementNode =>
|
|
|
76
76
|
|
|
77
77
|
const stepOffset = (node: ContentChild, target: TextNode, offset: number): OffsetResult => {
|
|
78
78
|
if (node === target) {
|
|
79
|
-
return {
|
|
79
|
+
return { wasFound: true, offset };
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
if (isTagElement(node)) {
|
|
83
83
|
return getOffset(node.content, target, offset);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
return {
|
|
86
|
+
return { wasFound: false, offset: offset + contentTextLength(node) };
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
const getOffset = (nodes: ContentChild[], target: TextNode, start: number): OffsetResult => {
|
|
@@ -92,14 +92,14 @@ const getOffset = (nodes: ContentChild[], target: TextNode, start: number): Offs
|
|
|
92
92
|
for (const node of nodes) {
|
|
93
93
|
const step = stepOffset(node, target, offset);
|
|
94
94
|
|
|
95
|
-
if (step.
|
|
95
|
+
if (step.wasFound) {
|
|
96
96
|
return step;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
offset = step.offset;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
return {
|
|
102
|
+
return { wasFound: false, offset };
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
const enclosingTagNodes = (node: TextNode): ElementNode[] => {
|
|
@@ -379,7 +379,7 @@ const didUpdateTextSurgically = (host: ElementNode, node: TextNode, oldText: str
|
|
|
379
379
|
|
|
380
380
|
const located = getOffset(host.content, node, 0);
|
|
381
381
|
|
|
382
|
-
if (!located.
|
|
382
|
+
if (!located.wasFound) {
|
|
383
383
|
return false;
|
|
384
384
|
}
|
|
385
385
|
|
|
@@ -15,13 +15,6 @@ const deleteAccessibleMetadata = (widget: object, name: string): void => {
|
|
|
15
15
|
metadataStore.get(widget)?.delete(name);
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Returns the last value applied for an accessible prop on a widget, or null when none was applied.
|
|
20
|
-
*
|
|
21
|
-
* @param widget The widget to read from.
|
|
22
|
-
* @param name The accessible prop name.
|
|
23
|
-
* @returns The last applied value, or null.
|
|
24
|
-
*/
|
|
25
18
|
const getAccessibleMetadata = (widget: object, name: string): unknown => {
|
|
26
19
|
const value = metadataStore.get(widget)?.get(name);
|
|
27
20
|
|
|
@@ -6,55 +6,103 @@ import { deleteAccessibleMetadata, setAccessibleMetadata } from "./accessible-me
|
|
|
6
6
|
/**
|
|
7
7
|
* Accessibility props available on every widget. Each member maps to a GTK4 accessible attribute
|
|
8
8
|
* (a `Gtk.AccessibleProperty`, `Gtk.AccessibleState`, or `Gtk.AccessibleRelation`) and is applied
|
|
9
|
-
* to the widget's accessible interface
|
|
9
|
+
* to the widget's accessible interface. Setting a member to `null` or `undefined`, or dropping it from the
|
|
10
|
+
* props, resets that attribute to its default.
|
|
10
11
|
*/
|
|
11
12
|
type AccessibleProps = {
|
|
13
|
+
/** How the widget completes the text being typed into it. */
|
|
12
14
|
accessibleAutocomplete?: Gtk.AccessibleAutocomplete | null | undefined;
|
|
15
|
+
/** Longer description announced after the label. */
|
|
13
16
|
accessibleDescription?: string | null | undefined;
|
|
17
|
+
/** Whether activating the widget opens a popup. */
|
|
14
18
|
accessibleHasPopup?: boolean | null | undefined;
|
|
19
|
+
/** Keyboard shortcuts that activate the widget. */
|
|
15
20
|
accessibleKeyShortcuts?: string | null | undefined;
|
|
21
|
+
/** Short name announced for the widget. */
|
|
16
22
|
accessibleLabel?: string | null | undefined;
|
|
23
|
+
/** Depth of the widget within a hierarchy of headings, list items, or tree rows. */
|
|
17
24
|
accessibleLevel?: number | null | undefined;
|
|
25
|
+
/** Whether the widget blocks interaction with everything behind it. */
|
|
18
26
|
accessibleModal?: boolean | null | undefined;
|
|
27
|
+
/** Whether the text input accepts more than one line. */
|
|
19
28
|
accessibleMultiLine?: boolean | null | undefined;
|
|
29
|
+
/** Whether more than one of the widget's items can be selected at a time. */
|
|
20
30
|
accessibleMultiSelectable?: boolean | null | undefined;
|
|
31
|
+
/** Whether the widget arranges its items horizontally or vertically. */
|
|
21
32
|
accessibleOrientation?: Gtk.Orientation | null | undefined;
|
|
33
|
+
/** Hint announced while the input is empty. */
|
|
22
34
|
accessiblePlaceholder?: string | null | undefined;
|
|
35
|
+
/** Whether the value can be read but not changed. */
|
|
23
36
|
accessibleReadOnly?: boolean | null | undefined;
|
|
37
|
+
/** Whether a value has to be supplied before the form can be submitted. */
|
|
24
38
|
accessibleRequired?: boolean | null | undefined;
|
|
39
|
+
/** Wording that replaces the default announcement of the widget's role. */
|
|
25
40
|
accessibleRoleDescription?: string | null | undefined;
|
|
41
|
+
/** Direction the widget's items are sorted in. */
|
|
26
42
|
accessibleSort?: Gtk.AccessibleSort | null | undefined;
|
|
43
|
+
/** Upper bound of the widget's value range. */
|
|
27
44
|
accessibleValueMax?: number | null | undefined;
|
|
45
|
+
/** Lower bound of the widget's value range. */
|
|
28
46
|
accessibleValueMin?: number | null | undefined;
|
|
47
|
+
/** Current value within the widget's range. */
|
|
29
48
|
accessibleValueNow?: number | null | undefined;
|
|
49
|
+
/** Wording announced in place of the numeric value. */
|
|
30
50
|
accessibleValueText?: string | null | undefined;
|
|
51
|
+
/** Help text describing how to use the widget. */
|
|
31
52
|
accessibleHelpText?: string | null | undefined;
|
|
53
|
+
/** Whether the widget is still loading and its content may yet change. */
|
|
32
54
|
accessibleBusy?: boolean | null | undefined;
|
|
55
|
+
/** Checked state of a check button or menu item, which may be mixed. */
|
|
33
56
|
accessibleChecked?: Gtk.AccessibleTristate | null | undefined;
|
|
57
|
+
/** Whether the widget is visible but cannot be edited or operated. */
|
|
34
58
|
accessibleDisabled?: boolean | null | undefined;
|
|
59
|
+
/** Whether the content the widget discloses is showing. */
|
|
35
60
|
accessibleExpanded?: boolean | null | undefined;
|
|
61
|
+
/** Whether the widget is kept out of the accessibility tree. */
|
|
36
62
|
accessibleHidden?: boolean | null | undefined;
|
|
63
|
+
/** Whether the entered value fails validation, and in what way. */
|
|
37
64
|
accessibleInvalid?: Gtk.AccessibleInvalidState | null | undefined;
|
|
65
|
+
/** Pressed state of a toggle button, which may be mixed. */
|
|
38
66
|
accessiblePressed?: Gtk.AccessibleTristate | null | undefined;
|
|
67
|
+
/** Whether the widget is selected within its container. */
|
|
39
68
|
accessibleSelected?: boolean | null | undefined;
|
|
69
|
+
/** Whether the link has already been followed. */
|
|
40
70
|
accessibleVisited?: boolean | null | undefined;
|
|
71
|
+
/** Descendant that holds the focus while the widget itself keeps it. */
|
|
41
72
|
accessibleActiveDescendant?: Gtk.Widget | null | undefined;
|
|
73
|
+
/** Total number of columns in the table, including any that are not rendered. */
|
|
42
74
|
accessibleColCount?: number | null | undefined;
|
|
75
|
+
/** One-based column position of the cell within its table. */
|
|
43
76
|
accessibleColIndex?: number | null | undefined;
|
|
77
|
+
/** Wording announced in place of the numeric column position. */
|
|
44
78
|
accessibleColIndexText?: string | null | undefined;
|
|
79
|
+
/** Number of columns the cell spans. */
|
|
45
80
|
accessibleColSpan?: number | null | undefined;
|
|
81
|
+
/** Widgets whose content or presence this widget controls. */
|
|
46
82
|
accessibleControls?: Gtk.Widget[] | null | undefined;
|
|
83
|
+
/** Widgets that describe this one. */
|
|
47
84
|
accessibleDescribedBy?: Gtk.Widget[] | null | undefined;
|
|
85
|
+
/** Widgets holding extended detail about this one. */
|
|
48
86
|
accessibleDetails?: Gtk.Widget[] | null | undefined;
|
|
87
|
+
/** Widgets holding the message that explains why the value is invalid. */
|
|
49
88
|
accessibleErrorMessage?: Gtk.Widget[] | null | undefined;
|
|
89
|
+
/** Widgets to read next, overriding the default reading order. */
|
|
50
90
|
accessibleFlowTo?: Gtk.Widget[] | null | undefined;
|
|
91
|
+
/** Widgets that label this one. */
|
|
51
92
|
accessibleLabelledBy?: Gtk.Widget[] | null | undefined;
|
|
93
|
+
/** Widgets this one owns that the widget hierarchy does not already imply. */
|
|
52
94
|
accessibleOwns?: Gtk.Widget[] | null | undefined;
|
|
95
|
+
/** One-based position of the widget within its set. */
|
|
53
96
|
accessiblePosInSet?: number | null | undefined;
|
|
97
|
+
/** Total number of rows in the table, including any that are not rendered. */
|
|
54
98
|
accessibleRowCount?: number | null | undefined;
|
|
99
|
+
/** One-based row position of the cell within its table. */
|
|
55
100
|
accessibleRowIndex?: number | null | undefined;
|
|
101
|
+
/** Wording announced in place of the numeric row position. */
|
|
56
102
|
accessibleRowIndexText?: string | null | undefined;
|
|
103
|
+
/** Number of rows the cell spans. */
|
|
57
104
|
accessibleRowSpan?: number | null | undefined;
|
|
105
|
+
/** Total number of items in the set the widget belongs to. */
|
|
58
106
|
accessibleSetSize?: number | null | undefined;
|
|
59
107
|
};
|
|
60
108
|
|
package/src/utils/ref-prop.ts
CHANGED
|
@@ -9,12 +9,6 @@ type RefProp<T extends object> = T | RefObject<T | null> | null | undefined;
|
|
|
9
9
|
const isRefObject = <T extends object>(value: T | RefObject<T | null>): value is RefObject<T | null> =>
|
|
10
10
|
typeof value === "object" && "current" in value;
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Resolves a {@link RefProp} to the concrete object it points at, or null when it is absent or unresolved.
|
|
14
|
-
*
|
|
15
|
-
* @param prop The target object, a ref to one, or null/undefined.
|
|
16
|
-
* @returns The resolved object, or null.
|
|
17
|
-
*/
|
|
18
12
|
const resolveRefProp = <T extends object>(prop: RefProp<T>): T | null => {
|
|
19
13
|
if (prop === null || prop === undefined) {
|
|
20
14
|
return null;
|
package/src/utils/settings.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type * as Gio from "@gtkx/gi/gio";
|
|
2
2
|
import { packVariant, parseVariantType, unpackVariant, type VariantValue } from "./variant.js";
|
|
3
3
|
|
|
4
|
+
/** Maps each key of a GSettings schema to its kind: a GVariant type string, or `enum` or `flags`. */
|
|
4
5
|
type SettingsSchemaKeys = Record<string, string>;
|
|
5
6
|
type SettingKindValue<S extends string> = S extends "enum" | "flags" ? number : VariantValue<S>;
|
|
7
|
+
/** The JavaScript type key `P` holds: `number` for `enum` and `flags`, otherwise the unpacked GVariant. */
|
|
6
8
|
type SettingValue<K extends SettingsSchemaKeys, P extends keyof K> = SettingKindValue<K[P] & string>;
|
|
7
9
|
|
|
10
|
+
/** A GSettings schema, as described by the modules GTKX generates from a project's `.gschema.xml` files. */
|
|
8
11
|
type SettingsSchema<K extends SettingsSchemaKeys = SettingsSchemaKeys> = {
|
|
12
|
+
/** Schema id it is looked up by, such as `org.gtkx.Example`. */
|
|
9
13
|
id: string;
|
|
14
|
+
/** Path a relocatable schema is instantiated at, or `null` to use the schema's own path. */
|
|
10
15
|
path: string | null;
|
|
16
|
+
/** Kind of every key the schema declares, which types reads and writes of that key. */
|
|
11
17
|
keys: K;
|
|
12
18
|
};
|
|
13
19
|
|