@geometra/proxy 1.61.3 → 1.62.2
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/dom-actions.d.ts.map +1 -1
- package/dist/dom-actions.js +201 -31
- package/dist/dom-actions.js.map +1 -1
- package/dist/index.js +11 -8
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +90 -12
- package/dist/runtime.js.map +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAwB,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEnE,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;AA0CvE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;IACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;IACrC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;CACvC;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAMvD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAIjE;
|
|
1
|
+
{"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"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"}
|
package/dist/dom-actions.js
CHANGED
|
@@ -1986,6 +1986,108 @@ async function pressEnterToCommitListbox(page, handle) {
|
|
|
1986
1986
|
return false;
|
|
1987
1987
|
}
|
|
1988
1988
|
}
|
|
1989
|
+
/**
|
|
1990
|
+
* After a custom listbox option click, make the committed value visible to
|
|
1991
|
+
* framework state managers that listen on the backing input/select instead of
|
|
1992
|
+
* the popup option. This covers React controlled inputs, react-hook-form
|
|
1993
|
+
* hidden inputs, and intl-tel-input country pickers without site branching.
|
|
1994
|
+
*/
|
|
1995
|
+
async function dispatchListboxCommitEvents(handle) {
|
|
1996
|
+
if (!handle)
|
|
1997
|
+
return false;
|
|
1998
|
+
try {
|
|
1999
|
+
return await handle.evaluate((el) => {
|
|
2000
|
+
if (!(el instanceof Element))
|
|
2001
|
+
return false;
|
|
2002
|
+
function clearReactTracker(target) {
|
|
2003
|
+
const tracker = target._valueTracker;
|
|
2004
|
+
if (!tracker || typeof tracker.setValue !== 'function')
|
|
2005
|
+
return;
|
|
2006
|
+
try {
|
|
2007
|
+
if (target instanceof HTMLInputElement && (target.type === 'checkbox' || target.type === 'radio')) {
|
|
2008
|
+
tracker.setValue(String(!target.checked));
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
const current = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement
|
|
2012
|
+
? target.value
|
|
2013
|
+
: target instanceof HTMLSelectElement
|
|
2014
|
+
? target.value
|
|
2015
|
+
: target.textContent ?? '';
|
|
2016
|
+
tracker.setValue(current === '' ? '__geometra_empty__' : '');
|
|
2017
|
+
}
|
|
2018
|
+
catch { /* ignore */ }
|
|
2019
|
+
}
|
|
2020
|
+
function dispatchCommit(target) {
|
|
2021
|
+
clearReactTracker(target);
|
|
2022
|
+
const inputType = target instanceof HTMLInputElement ? target.type.toLowerCase() : '';
|
|
2023
|
+
const isSearchQueryInput = target instanceof HTMLInputElement &&
|
|
2024
|
+
!['hidden', 'checkbox', 'radio', 'tel'].includes(inputType) &&
|
|
2025
|
+
(target.getAttribute('role') === 'combobox' ||
|
|
2026
|
+
target.hasAttribute('aria-autocomplete') ||
|
|
2027
|
+
target.hasAttribute('aria-activedescendant'));
|
|
2028
|
+
if (!isSearchQueryInput) {
|
|
2029
|
+
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2030
|
+
}
|
|
2031
|
+
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
2032
|
+
if (target instanceof HTMLInputElement &&
|
|
2033
|
+
(target.type === 'tel' ||
|
|
2034
|
+
target.closest('.iti, .intl-tel-input, [data-intl-tel-input-id], [class*="phone"], [class*="Phone"]'))) {
|
|
2035
|
+
target.dispatchEvent(new Event('countrychange', { bubbles: true }));
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
function commitRoot(start) {
|
|
2039
|
+
let best = start.parentElement ?? start;
|
|
2040
|
+
let current = start.parentElement;
|
|
2041
|
+
let depth = 0;
|
|
2042
|
+
while (current && depth < 6) {
|
|
2043
|
+
if (current.tagName.toLowerCase() === 'form')
|
|
2044
|
+
break;
|
|
2045
|
+
const className = (current.getAttribute('class') ?? '').toLowerCase();
|
|
2046
|
+
const controlCount = current.querySelectorAll('input, textarea, select, [role="combobox"], [aria-haspopup="listbox"]').length;
|
|
2047
|
+
const looksLikeField = current.querySelector('label, legend') !== null ||
|
|
2048
|
+
className.includes('field') ||
|
|
2049
|
+
className.includes('form-group') ||
|
|
2050
|
+
className.includes('form-control') ||
|
|
2051
|
+
className.includes('select') ||
|
|
2052
|
+
className.includes('combo') ||
|
|
2053
|
+
className.includes('phone') ||
|
|
2054
|
+
className.includes('iti') ||
|
|
2055
|
+
className.includes('input');
|
|
2056
|
+
if (looksLikeField && controlCount > 0 && controlCount <= 10)
|
|
2057
|
+
best = current;
|
|
2058
|
+
current = current.parentElement;
|
|
2059
|
+
depth++;
|
|
2060
|
+
}
|
|
2061
|
+
return best;
|
|
2062
|
+
}
|
|
2063
|
+
const targets = [];
|
|
2064
|
+
const seen = new Set();
|
|
2065
|
+
const add = (candidate) => {
|
|
2066
|
+
if (!(candidate instanceof HTMLElement))
|
|
2067
|
+
return;
|
|
2068
|
+
if (seen.has(candidate))
|
|
2069
|
+
return;
|
|
2070
|
+
seen.add(candidate);
|
|
2071
|
+
targets.push(candidate);
|
|
2072
|
+
};
|
|
2073
|
+
add(el);
|
|
2074
|
+
const root = commitRoot(el);
|
|
2075
|
+
for (const candidate of Array.from(root.querySelectorAll('input, textarea, select, [role="combobox"], [aria-haspopup="listbox"]'))) {
|
|
2076
|
+
if (candidate.closest('[role="listbox"], [role="menu"]') &&
|
|
2077
|
+
!candidate.matches('[role="combobox"], input, select, textarea')) {
|
|
2078
|
+
continue;
|
|
2079
|
+
}
|
|
2080
|
+
add(candidate);
|
|
2081
|
+
}
|
|
2082
|
+
for (const target of targets)
|
|
2083
|
+
dispatchCommit(target);
|
|
2084
|
+
return targets.length > 0;
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
catch {
|
|
2088
|
+
return false;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
1989
2091
|
/**
|
|
1990
2092
|
* Read form-level invalid state for a combobox trigger.
|
|
1991
2093
|
*
|
|
@@ -3310,6 +3412,22 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3310
3412
|
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
3311
3413
|
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
3312
3414
|
}
|
|
3415
|
+
function clearReactTracker(target, nextChecked) {
|
|
3416
|
+
const tracker = target._valueTracker;
|
|
3417
|
+
if (!tracker || typeof tracker.setValue !== 'function')
|
|
3418
|
+
return false;
|
|
3419
|
+
try {
|
|
3420
|
+
if (target instanceof HTMLInputElement && (target.type === 'checkbox' || target.type === 'radio')) {
|
|
3421
|
+
tracker.setValue(String(!(nextChecked ?? target.checked)));
|
|
3422
|
+
}
|
|
3423
|
+
else {
|
|
3424
|
+
tracker.setValue('');
|
|
3425
|
+
}
|
|
3426
|
+
return true;
|
|
3427
|
+
}
|
|
3428
|
+
catch { /* ignore */ }
|
|
3429
|
+
return false;
|
|
3430
|
+
}
|
|
3313
3431
|
function setInputLikeValue(target, next) {
|
|
3314
3432
|
const proto = target instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype;
|
|
3315
3433
|
const descriptor = Object.getOwnPropertyDescriptor(proto, 'value');
|
|
@@ -3318,6 +3436,18 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3318
3436
|
else
|
|
3319
3437
|
target.value = next;
|
|
3320
3438
|
}
|
|
3439
|
+
function setInputCheckedReactAware(target, next) {
|
|
3440
|
+
const hadReactTracker = clearReactTracker(target, next);
|
|
3441
|
+
if (!hadReactTracker && target.checked === next)
|
|
3442
|
+
return true;
|
|
3443
|
+
const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'checked');
|
|
3444
|
+
if (descriptor?.set)
|
|
3445
|
+
descriptor.set.call(target, next);
|
|
3446
|
+
else
|
|
3447
|
+
target.checked = next;
|
|
3448
|
+
dispatch(target);
|
|
3449
|
+
return target.checked === next;
|
|
3450
|
+
}
|
|
3321
3451
|
function currentValue(el) {
|
|
3322
3452
|
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)
|
|
3323
3453
|
return el.value;
|
|
@@ -3470,6 +3600,7 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3470
3600
|
const inputType = control instanceof HTMLInputElement ? control.type : 'textarea';
|
|
3471
3601
|
const v = canonicalizeHtmlInputValueInPage(inputType, value);
|
|
3472
3602
|
control.focus();
|
|
3603
|
+
clearReactTracker(control);
|
|
3473
3604
|
setInputLikeValue(control, v);
|
|
3474
3605
|
dispatch(control);
|
|
3475
3606
|
return matches(currentValue(control), v, false);
|
|
@@ -3478,6 +3609,7 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3478
3609
|
if (!isPlainContentEditableBatch(control))
|
|
3479
3610
|
return false;
|
|
3480
3611
|
control.focus();
|
|
3612
|
+
clearReactTracker(control);
|
|
3481
3613
|
control.textContent = value;
|
|
3482
3614
|
dispatch(control);
|
|
3483
3615
|
return matches(currentValue(control), value, false);
|
|
@@ -3556,19 +3688,13 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3556
3688
|
if (!matches(choiceLabel(option), value, exact))
|
|
3557
3689
|
continue;
|
|
3558
3690
|
if (option instanceof HTMLInputElement) {
|
|
3559
|
-
|
|
3560
|
-
option.click();
|
|
3561
|
-
if (!option.checked) {
|
|
3562
|
-
option.checked = true;
|
|
3563
|
-
dispatch(option);
|
|
3564
|
-
}
|
|
3565
|
-
return option.checked;
|
|
3691
|
+
return setInputCheckedReactAware(option, true);
|
|
3566
3692
|
}
|
|
3567
3693
|
if (option instanceof HTMLLabelElement) {
|
|
3568
|
-
option.click();
|
|
3569
3694
|
const control = option.control;
|
|
3570
3695
|
if (control instanceof HTMLInputElement)
|
|
3571
|
-
return control
|
|
3696
|
+
return setInputCheckedReactAware(control, true);
|
|
3697
|
+
option.click();
|
|
3572
3698
|
return true;
|
|
3573
3699
|
}
|
|
3574
3700
|
// role=radio / role=checkbox: click and verify aria-checked
|
|
@@ -3609,13 +3735,8 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3609
3735
|
continue;
|
|
3610
3736
|
if (!matches(explicitLabelText(input), label, exact))
|
|
3611
3737
|
continue;
|
|
3612
|
-
if (input
|
|
3613
|
-
|
|
3614
|
-
if (input.checked !== checked) {
|
|
3615
|
-
input.checked = checked;
|
|
3616
|
-
dispatch(input);
|
|
3617
|
-
}
|
|
3618
|
-
}
|
|
3738
|
+
if (!setInputCheckedReactAware(input, checked))
|
|
3739
|
+
return false;
|
|
3619
3740
|
return input.checked === checked;
|
|
3620
3741
|
}
|
|
3621
3742
|
const labels = Array.from(document.querySelectorAll('label'));
|
|
@@ -3629,12 +3750,8 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3629
3750
|
continue;
|
|
3630
3751
|
if (controlType && control.type !== controlType)
|
|
3631
3752
|
continue;
|
|
3632
|
-
if (control
|
|
3633
|
-
|
|
3634
|
-
if (control.checked !== checked) {
|
|
3635
|
-
control.checked = checked;
|
|
3636
|
-
dispatch(control);
|
|
3637
|
-
}
|
|
3753
|
+
if (!setInputCheckedReactAware(control, checked))
|
|
3754
|
+
return false;
|
|
3638
3755
|
return control.checked === checked;
|
|
3639
3756
|
}
|
|
3640
3757
|
return false;
|
|
@@ -4336,6 +4453,33 @@ async function chooseValueFromLabeledGroup(page, fieldLabel, value, exact) {
|
|
|
4336
4453
|
return `${ariaPressed}|${ariaChecked}|${ariaSelected}|${dataState}|${dataSelected}|${className}|${checked}`;
|
|
4337
4454
|
}).join('||');
|
|
4338
4455
|
}
|
|
4456
|
+
function dispatch(target) {
|
|
4457
|
+
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
4458
|
+
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
4459
|
+
}
|
|
4460
|
+
function clearReactTracker(target, next) {
|
|
4461
|
+
const tracker = target._valueTracker;
|
|
4462
|
+
if (tracker && typeof tracker.setValue === 'function') {
|
|
4463
|
+
try {
|
|
4464
|
+
tracker.setValue(String(!next));
|
|
4465
|
+
return true;
|
|
4466
|
+
}
|
|
4467
|
+
catch { /* ignore */ }
|
|
4468
|
+
}
|
|
4469
|
+
return false;
|
|
4470
|
+
}
|
|
4471
|
+
function setInputCheckedReactAware(target, next) {
|
|
4472
|
+
const hadReactTracker = clearReactTracker(target, next);
|
|
4473
|
+
if (!hadReactTracker && target.checked === next)
|
|
4474
|
+
return true;
|
|
4475
|
+
const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'checked');
|
|
4476
|
+
if (descriptor?.set)
|
|
4477
|
+
descriptor.set.call(target, next);
|
|
4478
|
+
else
|
|
4479
|
+
target.checked = next;
|
|
4480
|
+
dispatch(target);
|
|
4481
|
+
return target.checked === next;
|
|
4482
|
+
}
|
|
4339
4483
|
for (const candidate of candidates) {
|
|
4340
4484
|
const options = Array.from(candidate.root.querySelectorAll('input[type="radio"], input[type="checkbox"], [role="radio"], [role="checkbox"], label, button'));
|
|
4341
4485
|
for (const option of options) {
|
|
@@ -4344,15 +4488,14 @@ async function chooseValueFromLabeledGroup(page, fieldLabel, value, exact) {
|
|
|
4344
4488
|
if (!matchesChoice(choiceLabel(option)))
|
|
4345
4489
|
continue;
|
|
4346
4490
|
if (option instanceof HTMLInputElement) {
|
|
4347
|
-
option
|
|
4348
|
-
return option.checked;
|
|
4491
|
+
return setInputCheckedReactAware(option, true);
|
|
4349
4492
|
}
|
|
4350
4493
|
if (option instanceof HTMLLabelElement) {
|
|
4351
4494
|
const labelBeforeSig = selectionSignature(options);
|
|
4352
|
-
option.click();
|
|
4353
4495
|
const control = option.control;
|
|
4354
4496
|
if (control instanceof HTMLInputElement)
|
|
4355
|
-
return control
|
|
4497
|
+
return setInputCheckedReactAware(control, true);
|
|
4498
|
+
option.click();
|
|
4356
4499
|
// No backing input — verify via group signature change so we don't
|
|
4357
4500
|
// silently no-op on label wrappers whose target is unparented.
|
|
4358
4501
|
const labelAfterSig = selectionSignature(options);
|
|
@@ -4771,6 +4914,7 @@ export async function pickListboxOption(page, label, opts) {
|
|
|
4771
4914
|
// commit path, which ALL tested libraries honor. No-op for native
|
|
4772
4915
|
// <select> / plain ARIA listboxes — see isAutocompleteCombobox.
|
|
4773
4916
|
await pressEnterToCommitListbox(page, openedHandle);
|
|
4917
|
+
await dispatchListboxCommitEvents(openedHandle);
|
|
4774
4918
|
if (!opts?.fieldLabel ||
|
|
4775
4919
|
await confirmListboxSelection(page, opts.fieldLabel, label, exact, anchor, openedHandle, selectedOptionText, {
|
|
4776
4920
|
editable: openedEditable,
|
|
@@ -4879,6 +5023,7 @@ export async function pickListboxOption(page, label, opts) {
|
|
|
4879
5023
|
if (keyboardSelection) {
|
|
4880
5024
|
selectedOptionText = keyboardSelection;
|
|
4881
5025
|
attemptedSelection = true;
|
|
5026
|
+
await dispatchListboxCommitEvents(openedHandle);
|
|
4882
5027
|
if (!opts?.fieldLabel ||
|
|
4883
5028
|
await confirmListboxSelection(page, opts.fieldLabel, label, exact, anchor, openedHandle, selectedOptionText, {
|
|
4884
5029
|
editable: openedEditable,
|
|
@@ -5014,6 +5159,33 @@ export async function setCheckedControl(page, label, opts) {
|
|
|
5014
5159
|
}
|
|
5015
5160
|
return el instanceof HTMLElement ? el : null;
|
|
5016
5161
|
}
|
|
5162
|
+
function dispatch(target) {
|
|
5163
|
+
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
5164
|
+
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
5165
|
+
}
|
|
5166
|
+
function clearReactTracker(target, next) {
|
|
5167
|
+
const tracker = target._valueTracker;
|
|
5168
|
+
if (tracker && typeof tracker.setValue === 'function') {
|
|
5169
|
+
try {
|
|
5170
|
+
tracker.setValue(String(!next));
|
|
5171
|
+
return true;
|
|
5172
|
+
}
|
|
5173
|
+
catch { /* ignore */ }
|
|
5174
|
+
}
|
|
5175
|
+
return false;
|
|
5176
|
+
}
|
|
5177
|
+
function setInputCheckedReactAware(target, next) {
|
|
5178
|
+
const hadReactTracker = clearReactTracker(target, next);
|
|
5179
|
+
if (!hadReactTracker && target.checked === next)
|
|
5180
|
+
return true;
|
|
5181
|
+
const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'checked');
|
|
5182
|
+
if (descriptor?.set)
|
|
5183
|
+
descriptor.set.call(target, next);
|
|
5184
|
+
else
|
|
5185
|
+
target.checked = next;
|
|
5186
|
+
dispatch(target);
|
|
5187
|
+
return target.checked === next;
|
|
5188
|
+
}
|
|
5017
5189
|
const selector = 'input[type="checkbox"], input[type="radio"], [role="checkbox"], [role="radio"], [role="switch"]';
|
|
5018
5190
|
const candidates = Array.from(document.querySelectorAll(selector)).filter((el) => el instanceof HTMLElement && visible(el));
|
|
5019
5191
|
const target = candidates.find((el) => {
|
|
@@ -5033,14 +5205,12 @@ export async function setCheckedControl(page, label, opts) {
|
|
|
5033
5205
|
if (kind === 'radio' && payload.checked === false) {
|
|
5034
5206
|
return { matched: true, success: before === false, reason: 'radio-uncheck', kind, name };
|
|
5035
5207
|
}
|
|
5036
|
-
if (before !== payload.checked) {
|
|
5208
|
+
if (before !== payload.checked && !(target instanceof HTMLInputElement)) {
|
|
5037
5209
|
clickTarget(target)?.click();
|
|
5038
5210
|
}
|
|
5039
5211
|
let after = readChecked(target);
|
|
5040
|
-
if (
|
|
5041
|
-
target
|
|
5042
|
-
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
5043
|
-
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
5212
|
+
if (target instanceof HTMLInputElement) {
|
|
5213
|
+
setInputCheckedReactAware(target, payload.checked);
|
|
5044
5214
|
after = target.checked;
|
|
5045
5215
|
}
|
|
5046
5216
|
return {
|