@gtkx/testing 0.20.0 → 1.0.0-rc.1
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 +122 -55
- package/dist/act.d.ts +19 -0
- package/dist/act.d.ts.map +1 -0
- package/dist/act.js +48 -0
- package/dist/act.js.map +1 -0
- package/dist/bound-queries.d.ts +32 -0
- package/dist/bound-queries.d.ts.map +1 -0
- package/dist/bound-queries.js +2 -0
- package/dist/bound-queries.js.map +1 -0
- package/dist/build-queries.d.ts +16 -0
- package/dist/build-queries.d.ts.map +1 -0
- package/dist/build-queries.js +103 -0
- package/dist/build-queries.js.map +1 -0
- package/dist/cleanup-registry.d.ts +4 -0
- package/dist/cleanup-registry.d.ts.map +1 -0
- package/dist/cleanup-registry.js +11 -0
- package/dist/cleanup-registry.js.map +1 -0
- package/dist/config.d.ts +18 -51
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -40
- package/dist/config.js.map +1 -1
- package/dist/editable.d.ts +7 -0
- package/dist/editable.d.ts.map +1 -0
- package/dist/editable.js +24 -0
- package/dist/editable.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +119 -0
- package/dist/errors.js.map +1 -0
- package/dist/fire-event.d.ts +7 -25
- package/dist/fire-event.d.ts.map +1 -1
- package/dist/fire-event.js +9 -29
- package/dist/fire-event.js.map +1 -1
- package/dist/frame-sync.d.ts +3 -0
- package/dist/frame-sync.d.ts.map +1 -0
- package/dist/frame-sync.js +30 -0
- package/dist/frame-sync.js.map +1 -0
- package/dist/index.d.ts +16 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/matchers.d.ts +55 -0
- package/dist/matchers.d.ts.map +1 -0
- package/dist/matchers.js +103 -0
- package/dist/matchers.js.map +1 -0
- package/dist/pretty-widget.d.ts +21 -25
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +69 -115
- package/dist/pretty-widget.js.map +1 -1
- package/dist/queries.d.ts +130 -177
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +212 -325
- package/dist/queries.js.map +1 -1
- package/dist/register-test-hooks.d.ts +2 -0
- package/dist/register-test-hooks.d.ts.map +1 -0
- package/dist/register-test-hooks.js +15 -0
- package/dist/register-test-hooks.js.map +1 -0
- package/dist/render-hook.d.ts +14 -35
- package/dist/render-hook.d.ts.map +1 -1
- package/dist/render-hook.js +8 -45
- package/dist/render-hook.js.map +1 -1
- package/dist/render.d.ts +11 -41
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +129 -118
- package/dist/render.js.map +1 -1
- package/dist/role-helpers.d.ts +16 -51
- package/dist/role-helpers.d.ts.map +1 -1
- package/dist/role-helpers.js +39 -58
- package/dist/role-helpers.js.map +1 -1
- package/dist/screen.d.ts +6 -63
- package/dist/screen.d.ts.map +1 -1
- package/dist/screen.js +21 -109
- package/dist/screen.js.map +1 -1
- package/dist/screenshot.d.ts +20 -23
- package/dist/screenshot.d.ts.map +1 -1
- package/dist/screenshot.js +89 -48
- package/dist/screenshot.js.map +1 -1
- package/dist/suggestions.d.ts +22 -0
- package/dist/suggestions.d.ts.map +1 -0
- package/dist/suggestions.js +56 -0
- package/dist/suggestions.js.map +1 -0
- package/dist/traversal.d.ts +10 -8
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +28 -13
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +103 -172
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +8 -0
- package/dist/user-event/adjustment.d.ts.map +1 -0
- package/dist/user-event/adjustment.js +33 -0
- package/dist/user-event/adjustment.js.map +1 -0
- package/dist/user-event/click.d.ts +7 -0
- package/dist/user-event/click.d.ts.map +1 -0
- package/dist/user-event/click.js +65 -0
- package/dist/user-event/click.js.map +1 -0
- package/dist/user-event/controller.d.ts +7 -0
- package/dist/user-event/controller.d.ts.map +1 -0
- package/dist/user-event/controller.js +28 -0
- package/dist/user-event/controller.js.map +1 -0
- package/dist/user-event/dispatch.d.ts +7 -0
- package/dist/user-event/dispatch.d.ts.map +1 -0
- package/dist/user-event/dispatch.js +10 -0
- package/dist/user-event/dispatch.js.map +1 -0
- package/dist/user-event/event-wrapper.d.ts +3 -0
- package/dist/user-event/event-wrapper.d.ts.map +1 -0
- package/dist/user-event/event-wrapper.js +48 -0
- package/dist/user-event/event-wrapper.js.map +1 -0
- package/dist/user-event/gesture.d.ts +31 -0
- package/dist/user-event/gesture.d.ts.map +1 -0
- package/dist/user-event/gesture.js +105 -0
- package/dist/user-event/gesture.js.map +1 -0
- package/dist/user-event/index.d.ts +44 -0
- package/dist/user-event/index.d.ts.map +1 -0
- package/dist/user-event/index.js +38 -0
- package/dist/user-event/index.js.map +1 -0
- package/dist/user-event/keyboard.d.ts +9 -0
- package/dist/user-event/keyboard.d.ts.map +1 -0
- package/dist/user-event/keyboard.js +173 -0
- package/dist/user-event/keyboard.js.map +1 -0
- package/dist/user-event/pointer.d.ts +6 -0
- package/dist/user-event/pointer.d.ts.map +1 -0
- package/dist/user-event/pointer.js +27 -0
- package/dist/user-event/pointer.js.map +1 -0
- package/dist/user-event/selection.d.ts +4 -0
- package/dist/user-event/selection.d.ts.map +1 -0
- package/dist/user-event/selection.js +106 -0
- package/dist/user-event/selection.js.map +1 -0
- package/dist/user-event/state.d.ts +6 -0
- package/dist/user-event/state.d.ts.map +1 -0
- package/dist/user-event/state.js +2 -0
- package/dist/user-event/state.js.map +1 -0
- package/dist/user-event/text.d.ts +17 -0
- package/dist/user-event/text.d.ts.map +1 -0
- package/dist/user-event/text.js +107 -0
- package/dist/user-event/text.js.map +1 -0
- package/dist/wait-for.d.ts +13 -32
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js +62 -73
- package/dist/wait-for.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +33 -0
- package/dist/widget-accessible-properties.d.ts.map +1 -0
- package/dist/widget-accessible-properties.js +215 -0
- package/dist/widget-accessible-properties.js.map +1 -0
- package/dist/within.d.ts +9 -26
- package/dist/within.d.ts.map +1 -1
- package/dist/within.js +15 -25
- package/dist/within.js.map +1 -1
- package/package.json +21 -12
- package/src/act.ts +68 -0
- package/src/bound-queries.ts +36 -0
- package/src/build-queries.ts +185 -0
- package/src/cleanup-registry.ts +14 -0
- package/src/config.ts +28 -59
- package/src/editable.ts +30 -0
- package/src/errors.ts +130 -0
- package/src/fire-event.ts +11 -38
- package/src/frame-sync.ts +34 -0
- package/src/index.ts +60 -18
- package/src/matchers.ts +200 -0
- package/src/pretty-widget.ts +99 -138
- package/src/queries.ts +321 -425
- package/src/register-test-hooks.ts +16 -0
- package/src/render-hook.tsx +31 -44
- package/src/render.tsx +161 -149
- package/src/role-helpers.ts +47 -67
- package/src/screen.ts +21 -114
- package/src/screenshot.ts +104 -55
- package/src/suggestions.ts +87 -0
- package/src/traversal.ts +32 -18
- package/src/types.ts +115 -176
- package/src/user-event/adjustment.ts +49 -0
- package/src/user-event/click.ts +70 -0
- package/src/user-event/controller.ts +44 -0
- package/src/user-event/dispatch.ts +23 -0
- package/src/user-event/event-wrapper.ts +54 -0
- package/src/user-event/gesture.ts +154 -0
- package/src/user-event/index.ts +74 -0
- package/src/user-event/keyboard.ts +204 -0
- package/src/user-event/pointer.ts +34 -0
- package/src/user-event/selection.ts +122 -0
- package/src/user-event/state.ts +6 -0
- package/src/user-event/text.ts +137 -0
- package/src/wait-for.ts +79 -80
- package/src/widget-accessible-properties.ts +244 -0
- package/src/within.ts +26 -27
- package/dist/bind-queries.d.ts +0 -14
- package/dist/bind-queries.d.ts.map +0 -1
- package/dist/bind-queries.js +0 -29
- package/dist/bind-queries.js.map +0 -1
- package/dist/error-builder.d.ts +0 -28
- package/dist/error-builder.d.ts.map +0 -1
- package/dist/error-builder.js +0 -81
- package/dist/error-builder.js.map +0 -1
- package/dist/timing.d.ts +0 -18
- package/dist/timing.d.ts.map +0 -1
- package/dist/timing.js +0 -18
- package/dist/timing.js.map +0 -1
- package/dist/user-event.d.ts +0 -138
- package/dist/user-event.d.ts.map +0 -1
- package/dist/user-event.js +0 -411
- package/dist/user-event.js.map +0 -1
- package/dist/widget-text.d.ts +0 -69
- package/dist/widget-text.d.ts.map +0 -1
- package/dist/widget-text.js +0 -177
- package/dist/widget-text.js.map +0 -1
- package/dist/widget.d.ts +0 -3
- package/dist/widget.d.ts.map +0 -1
- package/dist/widget.js +0 -13
- package/dist/widget.js.map +0 -1
- package/src/bind-queries.ts +0 -52
- package/src/error-builder.ts +0 -102
- package/src/timing.ts +0 -17
- package/src/user-event.ts +0 -492
- package/src/widget-text.ts +0 -202
- package/src/widget.ts +0 -15
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import { getAccessibleMetadata } from "@gtkx/react/internal";
|
|
3
|
+
import { EDITABLE_ROLES, isEditable, readEditableText } from "./editable.js";
|
|
4
|
+
import { descendants } from "./traversal.js";
|
|
5
|
+
const callStringGetter = (widget, method) => {
|
|
6
|
+
const fn = Reflect.get(widget, method);
|
|
7
|
+
if (typeof fn !== "function")
|
|
8
|
+
return null;
|
|
9
|
+
const value = fn.call(widget);
|
|
10
|
+
return value ?? null;
|
|
11
|
+
};
|
|
12
|
+
const readAccessibleString = (widget, key) => {
|
|
13
|
+
const value = getAccessibleMetadata(widget, key);
|
|
14
|
+
return typeof value === "string" ? value : null;
|
|
15
|
+
};
|
|
16
|
+
const readAccessibleNumber = (widget, key) => {
|
|
17
|
+
const value = getAccessibleMetadata(widget, key);
|
|
18
|
+
return typeof value === "number" ? value : null;
|
|
19
|
+
};
|
|
20
|
+
const readAccessibleBoolean = (widget, key) => {
|
|
21
|
+
const value = getAccessibleMetadata(widget, key);
|
|
22
|
+
return typeof value === "boolean" ? value : null;
|
|
23
|
+
};
|
|
24
|
+
const getLabelText = (widget) => {
|
|
25
|
+
if (widget instanceof Gtk.Label)
|
|
26
|
+
return widget.getLabel();
|
|
27
|
+
if (widget instanceof Gtk.Inscription)
|
|
28
|
+
return widget.getText() ?? null;
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
const DEFAULT_TEXT_GETTERS = ["getLabel", "getText", "getTitle"];
|
|
32
|
+
/**
|
|
33
|
+
* Returns a widget's own text by trying its label, text, and title getters in
|
|
34
|
+
* order, or null when none produce a value.
|
|
35
|
+
*
|
|
36
|
+
* @param widget The widget to read text from.
|
|
37
|
+
*/
|
|
38
|
+
export const getWidgetNodeText = (widget) => {
|
|
39
|
+
for (const getter of DEFAULT_TEXT_GETTERS) {
|
|
40
|
+
const value = callStringGetter(widget, getter);
|
|
41
|
+
if (value)
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
};
|
|
46
|
+
const stripMnemonic = (text) => text.replace(/_(.)/g, "$1");
|
|
47
|
+
const namingLabelText = (widget) => {
|
|
48
|
+
const text = getLabelText(widget);
|
|
49
|
+
if (text === null)
|
|
50
|
+
return null;
|
|
51
|
+
return widget instanceof Gtk.Label && widget.getUseUnderline() ? stripMnemonic(text) : text;
|
|
52
|
+
};
|
|
53
|
+
const isNamingLabelRole = (role, includePresentation) => role === Gtk.AccessibleRole.LABEL || (includePresentation && role === Gtk.AccessibleRole.PRESENTATION);
|
|
54
|
+
const collectLabels = (widget) => {
|
|
55
|
+
const includePresentation = widget.getAccessibleRole() === Gtk.AccessibleRole.MENU_ITEM;
|
|
56
|
+
const labels = [];
|
|
57
|
+
for (const descendant of descendants(widget)) {
|
|
58
|
+
if (!isNamingLabelRole(descendant.getAccessibleRole(), includePresentation))
|
|
59
|
+
continue;
|
|
60
|
+
const labelText = namingLabelText(descendant);
|
|
61
|
+
if (labelText)
|
|
62
|
+
labels.push(labelText);
|
|
63
|
+
}
|
|
64
|
+
return labels;
|
|
65
|
+
};
|
|
66
|
+
export const getWidgetLabelText = (widget) => {
|
|
67
|
+
if (widget.getAccessibleRole() !== Gtk.AccessibleRole.LABEL)
|
|
68
|
+
return null;
|
|
69
|
+
return getLabelText(widget);
|
|
70
|
+
};
|
|
71
|
+
export const getWidgetAccessibleName = (widget) => {
|
|
72
|
+
const role = widget.getAccessibleRole();
|
|
73
|
+
if (role === Gtk.AccessibleRole.TAB_PANEL) {
|
|
74
|
+
const parent = widget.getParent();
|
|
75
|
+
if (parent instanceof Gtk.Stack) {
|
|
76
|
+
const page = parent.getPage(widget);
|
|
77
|
+
return page.getTitle() ?? null;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const accessibleLabel = getAccessibleMetadata(widget, "accessibleLabel");
|
|
82
|
+
if (accessibleLabel)
|
|
83
|
+
return accessibleLabel;
|
|
84
|
+
const ownText = getWidgetNodeText(widget);
|
|
85
|
+
if (ownText)
|
|
86
|
+
return ownText;
|
|
87
|
+
const childLabels = collectLabels(widget);
|
|
88
|
+
if (childLabels.length > 0)
|
|
89
|
+
return childLabels.join(" ");
|
|
90
|
+
return callStringGetter(widget, "getTooltipText");
|
|
91
|
+
};
|
|
92
|
+
export const getWidgetName = (widget) => {
|
|
93
|
+
return widget.getName();
|
|
94
|
+
};
|
|
95
|
+
export const getWidgetPlaceholderText = (widget) => {
|
|
96
|
+
if (!EDITABLE_ROLES.has(widget.getAccessibleRole()) || !(widget instanceof Gtk.Editable)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return callStringGetter(widget, "getPlaceholderText");
|
|
100
|
+
};
|
|
101
|
+
export const getWidgetDisplayValue = (widget) => {
|
|
102
|
+
if (EDITABLE_ROLES.has(widget.getAccessibleRole()) && isEditable(widget)) {
|
|
103
|
+
return readEditableText(widget);
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
};
|
|
107
|
+
export const getWidgetCheckedState = (widget) => {
|
|
108
|
+
if (widget instanceof Gtk.CheckButton)
|
|
109
|
+
return widget.getActive();
|
|
110
|
+
if (widget instanceof Gtk.Switch)
|
|
111
|
+
return widget.getActive();
|
|
112
|
+
if (widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO) {
|
|
113
|
+
return widget.getActive();
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
};
|
|
117
|
+
export const getWidgetPressedState = (widget) => {
|
|
118
|
+
if (widget instanceof Gtk.ToggleButton)
|
|
119
|
+
return widget.getActive();
|
|
120
|
+
return null;
|
|
121
|
+
};
|
|
122
|
+
export const getWidgetExpandedState = (widget) => {
|
|
123
|
+
if (widget instanceof Gtk.Expander) {
|
|
124
|
+
return widget.getExpanded();
|
|
125
|
+
}
|
|
126
|
+
if (widget instanceof Gtk.TreeExpander) {
|
|
127
|
+
return widget.getListRow()?.getExpanded() ?? null;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
};
|
|
131
|
+
export const getWidgetSelectedState = (widget) => {
|
|
132
|
+
if (widget instanceof Gtk.ListBoxRow) {
|
|
133
|
+
return widget.isSelected();
|
|
134
|
+
}
|
|
135
|
+
if (widget.getAccessibleRole() === Gtk.AccessibleRole.ROW) {
|
|
136
|
+
return (widget.getStateFlags() & Gtk.StateFlags.SELECTED) !== 0;
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
};
|
|
140
|
+
export const getWidgetLevel = (widget) => {
|
|
141
|
+
return readAccessibleNumber(widget, "accessibleLevel");
|
|
142
|
+
};
|
|
143
|
+
export const getWidgetInvalidState = (widget) => {
|
|
144
|
+
return getAccessibleMetadata(widget, "accessibleInvalid");
|
|
145
|
+
};
|
|
146
|
+
export const getWidgetErrorMessage = (widget) => {
|
|
147
|
+
const targets = getAccessibleMetadata(widget, "accessibleErrorMessage");
|
|
148
|
+
return Array.isArray(targets) && targets.length > 0 ? targets : null;
|
|
149
|
+
};
|
|
150
|
+
export const getWidgetBusyState = (widget) => {
|
|
151
|
+
return readAccessibleBoolean(widget, "accessibleBusy");
|
|
152
|
+
};
|
|
153
|
+
export const getWidgetDescription = (widget) => {
|
|
154
|
+
return readAccessibleString(widget, "accessibleDescription");
|
|
155
|
+
};
|
|
156
|
+
const adjustmentValue = (adjustment) => ({
|
|
157
|
+
now: adjustment.getValue(),
|
|
158
|
+
min: adjustment.getLower(),
|
|
159
|
+
max: adjustment.getUpper(),
|
|
160
|
+
});
|
|
161
|
+
const getWidgetLiveValue = (widget) => {
|
|
162
|
+
if (widget instanceof Gtk.Range)
|
|
163
|
+
return adjustmentValue(widget.getAdjustment());
|
|
164
|
+
if (widget instanceof Gtk.Scrollbar)
|
|
165
|
+
return adjustmentValue(widget.getAdjustment());
|
|
166
|
+
if (widget instanceof Gtk.SpinButton)
|
|
167
|
+
return adjustmentValue(widget.getAdjustment());
|
|
168
|
+
if (widget instanceof Gtk.ScaleButton)
|
|
169
|
+
return adjustmentValue(widget.getAdjustment());
|
|
170
|
+
if (widget instanceof Gtk.LevelBar) {
|
|
171
|
+
return { now: widget.getValue(), min: widget.getMinValue(), max: widget.getMaxValue() };
|
|
172
|
+
}
|
|
173
|
+
if (widget instanceof Gtk.ProgressBar)
|
|
174
|
+
return { now: widget.getFraction(), min: 0, max: 1 };
|
|
175
|
+
return null;
|
|
176
|
+
};
|
|
177
|
+
export const getWidgetValue = (widget) => {
|
|
178
|
+
const text = readAccessibleString(widget, "accessibleValueText");
|
|
179
|
+
const live = getWidgetLiveValue(widget);
|
|
180
|
+
if (live)
|
|
181
|
+
return { ...live, text };
|
|
182
|
+
return {
|
|
183
|
+
now: readAccessibleNumber(widget, "accessibleValueNow"),
|
|
184
|
+
min: readAccessibleNumber(widget, "accessibleValueMin"),
|
|
185
|
+
max: readAccessibleNumber(widget, "accessibleValueMax"),
|
|
186
|
+
text,
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
export const getWidgetOwnLabel = (widget) => {
|
|
190
|
+
return readAccessibleString(widget, "accessibleLabel");
|
|
191
|
+
};
|
|
192
|
+
export const getWidgetLabelledByText = (widget) => {
|
|
193
|
+
const targets = getAccessibleMetadata(widget, "accessibleLabelledBy");
|
|
194
|
+
if (!Array.isArray(targets) || targets.length === 0)
|
|
195
|
+
return null;
|
|
196
|
+
const texts = [];
|
|
197
|
+
for (const target of targets) {
|
|
198
|
+
const text = getWidgetAccessibleName(target);
|
|
199
|
+
if (text !== null)
|
|
200
|
+
texts.push(text);
|
|
201
|
+
}
|
|
202
|
+
return texts.length > 0 ? texts.join(" ") : null;
|
|
203
|
+
};
|
|
204
|
+
export const isInaccessible = (widget) => {
|
|
205
|
+
let current = widget;
|
|
206
|
+
while (current) {
|
|
207
|
+
if (!current.getVisible())
|
|
208
|
+
return true;
|
|
209
|
+
if (readAccessibleBoolean(current, "accessibleHidden") === true)
|
|
210
|
+
return true;
|
|
211
|
+
current = current.getParent();
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
};
|
|
215
|
+
//# sourceMappingURL=widget-accessible-properties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-accessible-properties.js","sourceRoot":"","sources":["../src/widget-accessible-properties.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { getAccessibleMetadata } from \"@gtkx/react/internal\";\nimport { EDITABLE_ROLES, isEditable, readEditableText } from \"./editable.js\";\nimport { descendants } from \"./traversal.js\";\n\nconst callStringGetter = (widget: Gtk.Widget, method: string): string | null => {\n const fn: unknown = Reflect.get(widget, method);\n if (typeof fn !== \"function\") return null;\n const value = (fn as () => string | null).call(widget);\n return value ?? null;\n};\n\nconst readAccessibleString = (widget: Gtk.Widget, key: string): string | null => {\n const value = getAccessibleMetadata<string>(widget, key);\n return typeof value === \"string\" ? value : null;\n};\n\nconst readAccessibleNumber = (widget: Gtk.Widget, key: string): number | null => {\n const value = getAccessibleMetadata<number>(widget, key);\n return typeof value === \"number\" ? value : null;\n};\n\nconst readAccessibleBoolean = (widget: Gtk.Widget, key: string): boolean | null => {\n const value = getAccessibleMetadata<boolean>(widget, key);\n return typeof value === \"boolean\" ? value : null;\n};\n\nconst getLabelText = (widget: Gtk.Widget): string | null => {\n if (widget instanceof Gtk.Label) return widget.getLabel();\n if (widget instanceof Gtk.Inscription) return widget.getText() ?? null;\n return null;\n};\n\nconst DEFAULT_TEXT_GETTERS = [\"getLabel\", \"getText\", \"getTitle\"] as const;\n\n/**\n * Returns a widget's own text by trying its label, text, and title getters in\n * order, or null when none produce a value.\n *\n * @param widget The widget to read text from.\n */\nexport const getWidgetNodeText = (widget: Gtk.Widget): string | null => {\n for (const getter of DEFAULT_TEXT_GETTERS) {\n const value = callStringGetter(widget, getter);\n if (value) return value;\n }\n return null;\n};\n\nconst stripMnemonic = (text: string): string => text.replace(/_(.)/g, \"$1\");\n\nconst namingLabelText = (widget: Gtk.Widget): string | null => {\n const text = getLabelText(widget);\n if (text === null) return null;\n return widget instanceof Gtk.Label && widget.getUseUnderline() ? stripMnemonic(text) : text;\n};\n\nconst isNamingLabelRole = (role: Gtk.AccessibleRole, includePresentation: boolean): boolean =>\n role === Gtk.AccessibleRole.LABEL || (includePresentation && role === Gtk.AccessibleRole.PRESENTATION);\n\nconst collectLabels = (widget: Gtk.Widget): string[] => {\n const includePresentation = widget.getAccessibleRole() === Gtk.AccessibleRole.MENU_ITEM;\n const labels: string[] = [];\n for (const descendant of descendants(widget)) {\n if (!isNamingLabelRole(descendant.getAccessibleRole(), includePresentation)) continue;\n const labelText = namingLabelText(descendant);\n if (labelText) labels.push(labelText);\n }\n return labels;\n};\n\nexport const getWidgetLabelText = (widget: Gtk.Widget): string | null => {\n if (widget.getAccessibleRole() !== Gtk.AccessibleRole.LABEL) return null;\n return getLabelText(widget);\n};\n\nexport const getWidgetAccessibleName = (widget: Gtk.Widget): string | null => {\n const role = widget.getAccessibleRole();\n\n if (role === Gtk.AccessibleRole.TAB_PANEL) {\n const parent = widget.getParent();\n if (parent instanceof Gtk.Stack) {\n const page = parent.getPage(widget);\n return page.getTitle() ?? null;\n }\n return null;\n }\n\n const accessibleLabel = getAccessibleMetadata<string>(widget, \"accessibleLabel\");\n if (accessibleLabel) return accessibleLabel;\n\n const ownText = getWidgetNodeText(widget);\n if (ownText) return ownText;\n\n const childLabels = collectLabels(widget);\n if (childLabels.length > 0) return childLabels.join(\" \");\n\n return callStringGetter(widget, \"getTooltipText\");\n};\n\nexport const getWidgetName = (widget: Gtk.Widget): string | null => {\n return widget.getName();\n};\n\nexport const getWidgetPlaceholderText = (widget: Gtk.Widget): string | null => {\n if (!EDITABLE_ROLES.has(widget.getAccessibleRole()) || !(widget instanceof Gtk.Editable)) {\n return null;\n }\n\n return callStringGetter(widget, \"getPlaceholderText\");\n};\n\nexport const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {\n if (EDITABLE_ROLES.has(widget.getAccessibleRole()) && isEditable(widget)) {\n return readEditableText(widget);\n }\n\n return null;\n};\n\nexport const getWidgetCheckedState = (widget: Gtk.Widget): boolean | null => {\n if (widget instanceof Gtk.CheckButton) return widget.getActive();\n if (widget instanceof Gtk.Switch) return widget.getActive();\n if (widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO) {\n return widget.getActive();\n }\n return null;\n};\n\nexport const getWidgetPressedState = (widget: Gtk.Widget): boolean | null => {\n if (widget instanceof Gtk.ToggleButton) return widget.getActive();\n return null;\n};\n\nexport const getWidgetExpandedState = (widget: Gtk.Widget): boolean | null => {\n if (widget instanceof Gtk.Expander) {\n return widget.getExpanded();\n }\n\n if (widget instanceof Gtk.TreeExpander) {\n return widget.getListRow()?.getExpanded() ?? null;\n }\n\n return null;\n};\n\nexport const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {\n if (widget instanceof Gtk.ListBoxRow) {\n return widget.isSelected();\n }\n\n if (widget.getAccessibleRole() === Gtk.AccessibleRole.ROW) {\n return (widget.getStateFlags() & Gtk.StateFlags.SELECTED) !== 0;\n }\n\n return null;\n};\n\nexport const getWidgetLevel = (widget: Gtk.Widget): number | null => {\n return readAccessibleNumber(widget, \"accessibleLevel\");\n};\n\nexport const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null => {\n return getAccessibleMetadata<Gtk.AccessibleInvalidState>(widget, \"accessibleInvalid\");\n};\n\nexport const getWidgetErrorMessage = (widget: Gtk.Widget): Gtk.Widget[] | null => {\n const targets = getAccessibleMetadata<Gtk.Widget[]>(widget, \"accessibleErrorMessage\");\n return Array.isArray(targets) && targets.length > 0 ? targets : null;\n};\n\nexport const getWidgetBusyState = (widget: Gtk.Widget): boolean | null => {\n return readAccessibleBoolean(widget, \"accessibleBusy\");\n};\n\nexport const getWidgetDescription = (widget: Gtk.Widget): string | null => {\n return readAccessibleString(widget, \"accessibleDescription\");\n};\n\nexport type WidgetValue = {\n now: number | null;\n min: number | null;\n max: number | null;\n text: string | null;\n};\n\ntype ValueTriplet = { now: number | null; min: number | null; max: number | null };\n\nconst adjustmentValue = (adjustment: Gtk.Adjustment): ValueTriplet => ({\n now: adjustment.getValue(),\n min: adjustment.getLower(),\n max: adjustment.getUpper(),\n});\n\nconst getWidgetLiveValue = (widget: Gtk.Widget): ValueTriplet | null => {\n if (widget instanceof Gtk.Range) return adjustmentValue(widget.getAdjustment());\n if (widget instanceof Gtk.Scrollbar) return adjustmentValue(widget.getAdjustment());\n if (widget instanceof Gtk.SpinButton) return adjustmentValue(widget.getAdjustment());\n if (widget instanceof Gtk.ScaleButton) return adjustmentValue(widget.getAdjustment());\n if (widget instanceof Gtk.LevelBar) {\n return { now: widget.getValue(), min: widget.getMinValue(), max: widget.getMaxValue() };\n }\n if (widget instanceof Gtk.ProgressBar) return { now: widget.getFraction(), min: 0, max: 1 };\n return null;\n};\n\nexport const getWidgetValue = (widget: Gtk.Widget): WidgetValue => {\n const text = readAccessibleString(widget, \"accessibleValueText\");\n const live = getWidgetLiveValue(widget);\n if (live) return { ...live, text };\n return {\n now: readAccessibleNumber(widget, \"accessibleValueNow\"),\n min: readAccessibleNumber(widget, \"accessibleValueMin\"),\n max: readAccessibleNumber(widget, \"accessibleValueMax\"),\n text,\n };\n};\n\nexport const getWidgetOwnLabel = (widget: Gtk.Widget): string | null => {\n return readAccessibleString(widget, \"accessibleLabel\");\n};\n\nexport const getWidgetLabelledByText = (widget: Gtk.Widget): string | null => {\n const targets = getAccessibleMetadata<Gtk.Widget[]>(widget, \"accessibleLabelledBy\");\n if (!Array.isArray(targets) || targets.length === 0) return null;\n\n const texts: string[] = [];\n for (const target of targets) {\n const text = getWidgetAccessibleName(target);\n if (text !== null) texts.push(text);\n }\n\n return texts.length > 0 ? texts.join(\" \") : null;\n};\n\nexport const isInaccessible = (widget: Gtk.Widget): boolean => {\n let current: Gtk.Widget | null = widget;\n while (current) {\n if (!current.getVisible()) return true;\n if (readAccessibleBoolean(current, \"accessibleHidden\") === true) return true;\n current = current.getParent();\n }\n return false;\n};\n"]}
|
package/dist/within.d.ts
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type {
|
|
1
|
+
import type { BoundQueries } from "./bound-queries.js";
|
|
2
|
+
import type { Container } from "./traversal.js";
|
|
3
|
+
import type { BoundCustomQueries, QueryMap } from "./types.js";
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
+
* Binds the built-in queries, and any custom queries, to a specific container
|
|
6
|
+
* so they search only within that scope.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
* the
|
|
8
|
-
*
|
|
9
|
-
* @param container - The widget to scope queries to
|
|
10
|
-
* @returns Object with query methods bound to the container
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```tsx
|
|
14
|
-
* import { render, within } from "@gtkx/testing";
|
|
15
|
-
*
|
|
16
|
-
* test("scoped queries", async () => {
|
|
17
|
-
* await render(<MyPage />);
|
|
18
|
-
*
|
|
19
|
-
* const sidebar = await screen.findByRole(Gtk.AccessibleRole.NAVIGATION);
|
|
20
|
-
* const sidebarQueries = within(sidebar);
|
|
21
|
-
*
|
|
22
|
-
* // Only searches within the sidebar
|
|
23
|
-
* const navButton = await sidebarQueries.findByRole(Gtk.AccessibleRole.BUTTON);
|
|
24
|
-
* });
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* @see {@link screen} for global queries
|
|
8
|
+
* @param container The scope the returned queries operate on.
|
|
9
|
+
* @param queries Optional custom queries to bind alongside the built-in ones.
|
|
10
|
+
* @returns The queries bound to the container.
|
|
28
11
|
*/
|
|
29
|
-
export declare const within: (container:
|
|
12
|
+
export declare const within: <Q extends QueryMap = Record<never, never>>(container: Container, queries?: Q) => BoundQueries & BoundCustomQueries<Q>;
|
|
30
13
|
//# sourceMappingURL=within.d.ts.map
|
package/dist/within.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"within.d.ts","sourceRoot":"","sources":["../src/within.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"within.d.ts","sourceRoot":"","sources":["../src/within.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAY/D;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,QAAQ,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,aACjD,SAAS,YACV,CAAC,KACZ,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAGpC,CAAC"}
|
package/dist/within.js
CHANGED
|
@@ -1,29 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { builtinQueries } from "./queries.js";
|
|
2
|
+
const bindQuery = (query, container) => (...args) => query(container, ...args);
|
|
3
|
+
const bindCustomQueries = (customQueries, container) => {
|
|
4
|
+
const entries = Object.entries(customQueries).map(([key, query]) => [key, bindQuery(query, container)]);
|
|
5
|
+
return Object.fromEntries(entries);
|
|
6
|
+
};
|
|
2
7
|
/**
|
|
3
|
-
*
|
|
8
|
+
* Binds the built-in queries, and any custom queries, to a specific container
|
|
9
|
+
* so they search only within that scope.
|
|
4
10
|
*
|
|
5
|
-
*
|
|
6
|
-
* the
|
|
7
|
-
*
|
|
8
|
-
* @param container - The widget to scope queries to
|
|
9
|
-
* @returns Object with query methods bound to the container
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```tsx
|
|
13
|
-
* import { render, within } from "@gtkx/testing";
|
|
14
|
-
*
|
|
15
|
-
* test("scoped queries", async () => {
|
|
16
|
-
* await render(<MyPage />);
|
|
17
|
-
*
|
|
18
|
-
* const sidebar = await screen.findByRole(Gtk.AccessibleRole.NAVIGATION);
|
|
19
|
-
* const sidebarQueries = within(sidebar);
|
|
20
|
-
*
|
|
21
|
-
* // Only searches within the sidebar
|
|
22
|
-
* const navButton = await sidebarQueries.findByRole(Gtk.AccessibleRole.BUTTON);
|
|
23
|
-
* });
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* @see {@link screen} for global queries
|
|
11
|
+
* @param container The scope the returned queries operate on.
|
|
12
|
+
* @param queries Optional custom queries to bind alongside the built-in ones.
|
|
13
|
+
* @returns The queries bound to the container.
|
|
27
14
|
*/
|
|
28
|
-
export const within = (container) =>
|
|
15
|
+
export const within = (container, queries) => ({
|
|
16
|
+
...bindCustomQueries(builtinQueries, container),
|
|
17
|
+
...(queries ? bindCustomQueries(queries, container) : {}),
|
|
18
|
+
});
|
|
29
19
|
//# sourceMappingURL=within.js.map
|
package/dist/within.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"within.js","sourceRoot":"","sources":["../src/within.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"within.js","sourceRoot":"","sources":["../src/within.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,SAAS,GACX,CAAiC,KAAsD,EAAE,SAAoB,EAAE,EAAE,CACjH,CAAC,GAAG,IAAU,EAAU,EAAE,CACtB,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;AAElC,MAAM,iBAAiB,GAAG,CAAqB,aAAgB,EAAE,SAAoB,EAAyB,EAAE;IAC5G,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAU,CAAC,CAAC;IACjH,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAA0B,CAAC;AAChE,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAClB,SAAoB,EACpB,OAAW,EACyB,EAAE,CAAC,CAAC;IACxC,GAAG,iBAAiB,CAAC,cAAc,EAAE,SAAS,CAAC;IAC/C,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAE,EAA4B,CAAC;CACvF,CAAC,CAAC","sourcesContent":["import type { BoundQueries } from \"./bound-queries.js\";\nimport { builtinQueries } from \"./queries.js\";\nimport type { Container } from \"./traversal.js\";\nimport type { BoundCustomQueries, QueryMap } from \"./types.js\";\n\nconst bindQuery =\n <Args extends unknown[], Result>(query: (container: Container, ...args: Args) => Result, container: Container) =>\n (...args: Args): Result =>\n query(container, ...args);\n\nconst bindCustomQueries = <Q extends QueryMap>(customQueries: Q, container: Container): BoundCustomQueries<Q> => {\n const entries = Object.entries(customQueries).map(([key, query]) => [key, bindQuery(query, container)] as const);\n return Object.fromEntries(entries) as BoundCustomQueries<Q>;\n};\n\n/**\n * Binds the built-in queries, and any custom queries, to a specific container\n * so they search only within that scope.\n *\n * @param container The scope the returned queries operate on.\n * @param queries Optional custom queries to bind alongside the built-in ones.\n * @returns The queries bound to the container.\n */\nexport const within = <Q extends QueryMap = Record<never, never>>(\n container: Container,\n queries?: Q,\n): BoundQueries & BoundCustomQueries<Q> => ({\n ...bindCustomQueries(builtinQueries, container),\n ...(queries ? bindCustomQueries(queries, container) : ({} as BoundCustomQueries<Q>)),\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/testing",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Testing
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
|
+
"description": "Testing Library-style queries, user events, and screenshots for GTK4 widget trees rendered by GTKX",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtkx",
|
|
7
7
|
"gtk",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/gtkx-org/gtkx.git",
|
|
22
|
+
"url": "git+https://github.com/gtkx-org/gtkx.git",
|
|
23
23
|
"directory": "packages/testing"
|
|
24
24
|
},
|
|
25
25
|
"license": "MPL-2.0",
|
|
@@ -32,23 +32,32 @@
|
|
|
32
32
|
"default": "./dist/index.js"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
|
-
"sideEffects":
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./src/register-test-hooks.ts",
|
|
37
|
+
"./dist/register-test-hooks.js"
|
|
38
|
+
],
|
|
36
39
|
"files": [
|
|
37
40
|
"dist",
|
|
38
41
|
"src"
|
|
39
42
|
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=24"
|
|
45
|
+
},
|
|
40
46
|
"dependencies": {
|
|
41
|
-
"@gtkx/
|
|
42
|
-
"@gtkx/
|
|
47
|
+
"@gtkx/runtime": "1.0.0-rc.1",
|
|
48
|
+
"@gtkx/utils": "1.0.0-rc.1",
|
|
49
|
+
"@gtkx/react": "1.0.0-rc.1"
|
|
43
50
|
},
|
|
44
51
|
"devDependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"
|
|
47
|
-
"@gtkx/
|
|
52
|
+
"@vitest/expect": "^4.1.10",
|
|
53
|
+
"vitest": "^4.1.10",
|
|
54
|
+
"@gtkx/config": "1.0.0-rc.1",
|
|
55
|
+
"@gtkx/components": "1.0.0-rc.1",
|
|
56
|
+
"@gtkx/vitest": "1.0.0-rc.1"
|
|
48
57
|
},
|
|
49
58
|
"scripts": {
|
|
50
|
-
"build": "tsc -b
|
|
51
|
-
"
|
|
52
|
-
"
|
|
59
|
+
"build": "tsc -b tsconfig.lib.json",
|
|
60
|
+
"typecheck": "tsc -b --emitDeclarationOnly",
|
|
61
|
+
"release": "tsx ../../scripts/release-package.ts"
|
|
53
62
|
}
|
|
54
63
|
}
|
package/src/act.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { act as reactAct } from "react";
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
var IS_REACT_ACT_ENVIRONMENT: boolean | undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const getGlobalThis = (): typeof globalThis => {
|
|
8
|
+
if (typeof globalThis !== "undefined") return globalThis;
|
|
9
|
+
throw new Error("unable to locate global object");
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const getIsReactActEnvironment = (): boolean | undefined => getGlobalThis().IS_REACT_ACT_ENVIRONMENT;
|
|
13
|
+
|
|
14
|
+
export const setIsReactActEnvironment = (value: boolean | undefined): void => {
|
|
15
|
+
getGlobalThis().IS_REACT_ACT_ENVIRONMENT = value;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type ActCallback<T> = () => T | PromiseLike<T>;
|
|
19
|
+
type ActImplementation = <T>(callback: ActCallback<T>) => PromiseLike<T>;
|
|
20
|
+
|
|
21
|
+
const isThenable = <T>(value: unknown): value is PromiseLike<T> =>
|
|
22
|
+
value !== null && typeof value === "object" && typeof (value as PromiseLike<T>).then === "function";
|
|
23
|
+
|
|
24
|
+
export const runWithActEnvironment = <T>(forced: boolean, fn: () => T | PromiseLike<T>): T | PromiseLike<T> => {
|
|
25
|
+
const previousActEnvironment = getIsReactActEnvironment();
|
|
26
|
+
setIsReactActEnvironment(forced);
|
|
27
|
+
try {
|
|
28
|
+
const result = fn();
|
|
29
|
+
if (isThenable<T>(result)) {
|
|
30
|
+
return Promise.resolve(result).then(
|
|
31
|
+
(value) => {
|
|
32
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
33
|
+
return value;
|
|
34
|
+
},
|
|
35
|
+
(error) => {
|
|
36
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
37
|
+
throw error;
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
42
|
+
return result;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const withGlobalActEnvironment =
|
|
50
|
+
(actImplementation: ActImplementation) =>
|
|
51
|
+
<T>(callback: ActCallback<T>): PromiseLike<T> => {
|
|
52
|
+
const settled = runWithActEnvironment(true, () => actImplementation(() => callback()));
|
|
53
|
+
return Promise.resolve(settled);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const actImplementation: ActImplementation = reactAct as ActImplementation;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Runs a callback inside React's act environment, flushing pending state
|
|
60
|
+
* updates and effects, and resolves once the work has settled.
|
|
61
|
+
*
|
|
62
|
+
* @param callback Work to run within the act environment.
|
|
63
|
+
* @returns A promise that resolves with the callback's result after updates flush.
|
|
64
|
+
*/
|
|
65
|
+
export const act: ActImplementation = withGlobalActEnvironment(actImplementation);
|
|
66
|
+
|
|
67
|
+
export const runInAct = (callback: () => unknown): Promise<void> =>
|
|
68
|
+
Promise.resolve(act(() => callback())).then(() => undefined);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import type { builtinQueries } from "./queries.js";
|
|
4
|
+
import type { Container } from "./traversal.js";
|
|
5
|
+
import type { BoundCustomQueries, DebugUtilities, QueryMap } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The set of built-in queries (getBy, findBy, queryBy, and their All variants)
|
|
9
|
+
* bound to a specific container.
|
|
10
|
+
*/
|
|
11
|
+
export type BoundQueries = BoundCustomQueries<typeof builtinQueries>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The global screen object's shape: built-in queries scoped to the current
|
|
15
|
+
* toplevels, plus debug utilities.
|
|
16
|
+
*/
|
|
17
|
+
export type Screen = BoundQueries & DebugUtilities;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The result of a render call: queries scoped to the rendered tree, debug
|
|
21
|
+
* utilities, and controls for updating or tearing down the render.
|
|
22
|
+
*
|
|
23
|
+
* @typeParam Q Custom queries provided at render time, merged with the built-in ones.
|
|
24
|
+
*/
|
|
25
|
+
export type RenderResult<Q extends QueryMap = Record<never, never>> = BoundQueries &
|
|
26
|
+
BoundCustomQueries<Q> &
|
|
27
|
+
DebugUtilities & {
|
|
28
|
+
/** The top-level widget the element was rendered into. */
|
|
29
|
+
container: Gtk.Widget;
|
|
30
|
+
/** The root the queries are scoped to (defaults to all toplevels). */
|
|
31
|
+
baseElement: Container;
|
|
32
|
+
/** Unmounts the rendered tree and disposes its resources. */
|
|
33
|
+
unmount: () => Promise<void>;
|
|
34
|
+
/** Re-renders the tree with a new element, reusing the same root. */
|
|
35
|
+
rerender: (element: ReactNode) => Promise<void>;
|
|
36
|
+
};
|