@homebound/beam 2.309.1 → 2.309.3
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/dist/hooks/useComputed.js +9 -7
- package/dist/utils/rtl.d.ts +4 -1
- package/dist/utils/rtl.js +46 -42
- package/package.json +2 -2
|
@@ -26,21 +26,23 @@ function useComputed(fn, deps) {
|
|
|
26
26
|
// If deps has changed, we're already re-running, so don't trigger a 2nd one
|
|
27
27
|
current.hasRan = false;
|
|
28
28
|
current.runner = (0, mobx_1.autorun)(() => {
|
|
29
|
-
const { value: oldValue, hasRan
|
|
29
|
+
const { value: oldValue, hasRan } = current;
|
|
30
30
|
// Always eval fn() (even on 1st render) to register our observable.
|
|
31
31
|
const newValue = fn(oldValue);
|
|
32
|
+
// If we've already run and the value hasn't changed, don't trigger a re-render
|
|
33
|
+
//
|
|
34
|
+
// Also, we avoid a deep equality, b/c if a `useComputed` is returning something complicated/cyclic,
|
|
35
|
+
// like ReactElement, deep equality will crawl into the guts of React/ReactFiber and cycle/infinite loop.
|
|
36
|
+
if (hasRan && (0, shallowEqual_1.shallowEqual)(newValue, oldValue))
|
|
37
|
+
return;
|
|
38
|
+
// Only change the identity of `current.value` after we've checked that it's not shallow equal
|
|
32
39
|
current.value = newValue;
|
|
33
40
|
current.hasRan = true;
|
|
34
41
|
// Only trigger a re-render if this is not the 1st autorun. Note
|
|
35
42
|
// that if deps has changed, we're inherently in a re-render so also
|
|
36
43
|
// don't need to trigger an additional re-render.
|
|
37
|
-
|
|
38
|
-
// Also, we avoid a deep equality, b/c if a `useComputed` is returning something
|
|
39
|
-
// complicated/cyclic, like ReactElement, deep equality will crawl into the guts
|
|
40
|
-
// of React/ReactFiber and cycle/infinite loop.
|
|
41
|
-
if (oldHasRun && !(0, shallowEqual_1.shallowEqual)(newValue, oldValue)) {
|
|
44
|
+
if (hasRan)
|
|
42
45
|
setTick((tick) => tick + 1);
|
|
43
|
-
}
|
|
44
46
|
});
|
|
45
47
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
46
48
|
}, deps);
|
package/dist/utils/rtl.d.ts
CHANGED
|
@@ -32,8 +32,11 @@ export declare function rowAnd(r: RenderResult, rowNum: number, testId: string):
|
|
|
32
32
|
export declare function tableSnapshot(r: RenderResult): string;
|
|
33
33
|
/** RTL wrapper for Beam's SuperDrawer/Modal context. */
|
|
34
34
|
export declare const withBeamRTL: Wrapper;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.
|
|
37
|
+
*
|
|
36
38
|
* For select fields that support multiple selections, subsequent calls to this function will toggle the selection state of an option.
|
|
39
|
+
*
|
|
37
40
|
* @param value The value or label of the option.
|
|
38
41
|
* */
|
|
39
42
|
export declare function select(element: HTMLElement, value: string | string[]): void;
|
package/dist/utils/rtl.js
CHANGED
|
@@ -135,44 +135,50 @@ function getTextFromTableCellNode(node) {
|
|
|
135
135
|
exports.withBeamRTL = {
|
|
136
136
|
wrap: (c) => (0, jsx_runtime_1.jsx)(components_1.BeamProvider, { children: c }),
|
|
137
137
|
};
|
|
138
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.
|
|
140
|
+
*
|
|
139
141
|
* For select fields that support multiple selections, subsequent calls to this function will toggle the selection state of an option.
|
|
142
|
+
*
|
|
140
143
|
* @param value The value or label of the option.
|
|
141
144
|
* */
|
|
142
145
|
function select(element, value) {
|
|
143
146
|
const select = resolveIfNeeded(element);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
if (!isInputElement(select)) {
|
|
148
|
-
throw new Error(`Expected element to be INPUT, but got ${select.nodeName}. This field may be read-only.`);
|
|
149
|
-
}
|
|
150
|
-
function maybeOpenAndSelect(optionValue) {
|
|
151
|
-
const expanded = select.getAttribute("aria-expanded") === "true";
|
|
152
|
-
if (!expanded) {
|
|
153
|
-
(0, rtl_utils_1.click)(select);
|
|
154
|
-
}
|
|
155
|
-
const body = select.closest("body");
|
|
156
|
-
const listboxId = select.getAttribute("aria-controls");
|
|
157
|
-
const listbox = body.querySelector(`#${listboxId}`);
|
|
158
|
-
const options = listbox.querySelectorAll("[role=option]");
|
|
159
|
-
// Allow searching for options by their data-key (value) or textContent (label)
|
|
160
|
-
const optionToSelect = Array.from(options).find((o) => o.dataset.key === optionValue || o.dataset.label === optionValue);
|
|
161
|
-
if (!optionToSelect) {
|
|
162
|
-
throw new Error(`Could not find option with value or text content of ${optionValue}`);
|
|
163
|
-
}
|
|
164
|
-
(0, rtl_utils_1.click)(optionToSelect);
|
|
165
|
-
}
|
|
147
|
+
assertListBoxInput(select);
|
|
148
|
+
ensureListBoxOpen(select);
|
|
166
149
|
const optionValues = Array.isArray(value) ? value : [value];
|
|
167
|
-
optionValues.forEach((optionValue) =>
|
|
168
|
-
maybeOpenAndSelect(optionValue);
|
|
169
|
-
});
|
|
150
|
+
optionValues.forEach((optionValue) => selectOption(select, optionValue));
|
|
170
151
|
}
|
|
171
152
|
exports.select = select;
|
|
172
|
-
function selectAndWait(input, value) {
|
|
173
|
-
|
|
153
|
+
async function selectAndWait(input, value) {
|
|
154
|
+
const select = resolveIfNeeded(input);
|
|
155
|
+
// To work with React 18, we need to execute these as separate steps, otherwise
|
|
156
|
+
// the `ensureListBoxOpen` async render won't flush, and the `selectOption` will fail.
|
|
157
|
+
await (0, rtl_utils_1.allowAndWaitForAsyncBehavior)(() => ensureListBoxOpen(select));
|
|
158
|
+
return (0, rtl_utils_1.allowAndWaitForAsyncBehavior)(() => {
|
|
159
|
+
const optionValues = Array.isArray(value) ? value : [value];
|
|
160
|
+
optionValues.forEach((optionValue) => selectOption(select, optionValue));
|
|
161
|
+
});
|
|
174
162
|
}
|
|
175
163
|
exports.selectAndWait = selectAndWait;
|
|
164
|
+
function ensureListBoxOpen(select) {
|
|
165
|
+
const expanded = select.getAttribute("aria-expanded") === "true";
|
|
166
|
+
if (!expanded) {
|
|
167
|
+
(0, rtl_utils_1.click)(select);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function selectOption(select, optionValue) {
|
|
171
|
+
const body = select.closest("body");
|
|
172
|
+
const listboxId = select.getAttribute("aria-controls");
|
|
173
|
+
const listbox = body.querySelector(`#${listboxId}`);
|
|
174
|
+
const options = listbox.querySelectorAll("[role=option]");
|
|
175
|
+
// Allow searching for options by their data-key (value) or textContent (label)
|
|
176
|
+
const optionToSelect = Array.from(options).find((o) => o.dataset.key === optionValue || o.dataset.label === optionValue);
|
|
177
|
+
if (!optionToSelect) {
|
|
178
|
+
throw new Error(`Could not find option with value or text content of ${optionValue}`);
|
|
179
|
+
}
|
|
180
|
+
(0, rtl_utils_1.click)(optionToSelect);
|
|
181
|
+
}
|
|
176
182
|
function getSelected(element) {
|
|
177
183
|
var _a;
|
|
178
184
|
const select = resolveIfNeeded(element);
|
|
@@ -183,10 +189,7 @@ function getSelected(element) {
|
|
|
183
189
|
// For read-only fields that render as a 'div'
|
|
184
190
|
return (_a = select.textContent) !== null && _a !== void 0 ? _a : undefined;
|
|
185
191
|
}
|
|
186
|
-
|
|
187
|
-
if (!expanded) {
|
|
188
|
-
(0, rtl_utils_1.click)(select);
|
|
189
|
-
}
|
|
192
|
+
ensureListBoxOpen(select);
|
|
190
193
|
const body = select.closest("body");
|
|
191
194
|
const listboxId = select.getAttribute("aria-controls");
|
|
192
195
|
const listbox = body.querySelector(`#${listboxId}`);
|
|
@@ -201,16 +204,8 @@ function getSelected(element) {
|
|
|
201
204
|
exports.getSelected = getSelected;
|
|
202
205
|
function getOptions(element) {
|
|
203
206
|
const select = resolveIfNeeded(element);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
if (!isInputElement(select)) {
|
|
208
|
-
throw new Error(`Expected element to be INPUT, but got ${select.nodeName}. This field may be read-only. In that case we cannot get the list of options`);
|
|
209
|
-
}
|
|
210
|
-
const expanded = select.getAttribute("aria-expanded") === "true";
|
|
211
|
-
if (!expanded) {
|
|
212
|
-
(0, rtl_utils_1.click)(select);
|
|
213
|
-
}
|
|
207
|
+
assertListBoxInput(select);
|
|
208
|
+
ensureListBoxOpen(select);
|
|
214
209
|
const body = select.closest("body");
|
|
215
210
|
const listboxId = select.getAttribute("aria-controls");
|
|
216
211
|
const listbox = body.querySelector(`#${listboxId}`);
|
|
@@ -220,6 +215,15 @@ function getOptions(element) {
|
|
|
220
215
|
.filter((o) => !!o);
|
|
221
216
|
}
|
|
222
217
|
exports.getOptions = getOptions;
|
|
218
|
+
function assertListBoxInput(select) {
|
|
219
|
+
if (isSelectElement(select)) {
|
|
220
|
+
throw new Error("Beam getOptions helper does not support <select> elements");
|
|
221
|
+
}
|
|
222
|
+
if (!isInputElement(select)) {
|
|
223
|
+
throw new Error(`Expected element to be INPUT, but got ${select.nodeName}. This field may be read-only. In that case we cannot get the list of options`);
|
|
224
|
+
}
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
223
227
|
function resolveIfNeeded(element) {
|
|
224
228
|
const maybeProxy = element;
|
|
225
229
|
return maybeProxy instanceof Function ? maybeProxy() : element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homebound/beam",
|
|
3
|
-
"version": "2.309.
|
|
3
|
+
"version": "2.309.3",
|
|
4
4
|
"author": "Homebound",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@emotion/react": "^11.10.6",
|
|
77
77
|
"@homebound/eslint-config": "1.6.1",
|
|
78
78
|
"@homebound/rtl-react-router-utils": "1.0.3",
|
|
79
|
-
"@homebound/rtl-utils": "^2.
|
|
79
|
+
"@homebound/rtl-utils": "^2.63.1",
|
|
80
80
|
"@homebound/truss": "^1.129.0",
|
|
81
81
|
"@homebound/tsconfig": "^1.0.3",
|
|
82
82
|
"@semantic-release/exec": "^6.0.3",
|