mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-16 21:11:52 +00:00
0.2.0 - Mid migration
This commit is contained in:
parent
139e6a915e
commit
7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions
15
web/node_modules/@testing-library/user-event/dist/blur.js
generated
vendored
Normal file
15
web/node_modules/@testing-library/user-event/dist/blur.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.blur = blur;
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
function blur(element) {
|
||||
if (!(0, _utils.isFocusable)(element)) return;
|
||||
const wasActive = (0, _utils.getActiveElement)(element.ownerDocument) === element;
|
||||
if (!wasActive) return;
|
||||
(0, _utils.eventWrapper)(() => element.blur());
|
||||
}
|
35
web/node_modules/@testing-library/user-event/dist/clear.js
generated
vendored
Normal file
35
web/node_modules/@testing-library/user-event/dist/clear.js
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.clear = clear;
|
||||
|
||||
var _type = require("./type");
|
||||
|
||||
function clear(element) {
|
||||
if (element.tagName !== 'INPUT' && element.tagName !== 'TEXTAREA') {
|
||||
// TODO: support contenteditable
|
||||
throw new Error('clear currently only supports input and textarea elements.');
|
||||
}
|
||||
|
||||
if (element.disabled) return; // TODO: track the selection range ourselves so we don't have to do this input "type" trickery
|
||||
// just like cypress does: https://github.com/cypress-io/cypress/blob/8d7f1a0bedc3c45a2ebf1ff50324b34129fdc683/packages/driver/src/dom/selection.ts#L16-L37
|
||||
|
||||
const elementType = element.type; // type is a readonly property on textarea, so check if element is an input before trying to modify it
|
||||
|
||||
if (element.tagName === 'INPUT') {
|
||||
// setSelectionRange is not supported on certain types of inputs, e.g. "number" or "email"
|
||||
element.type = 'text';
|
||||
}
|
||||
|
||||
(0, _type.type)(element, '{selectall}{del}', {
|
||||
delay: 0,
|
||||
initialSelectionStart: element.selectionStart,
|
||||
initialSelectionEnd: element.selectionEnd
|
||||
});
|
||||
|
||||
if (element.tagName === 'INPUT') {
|
||||
element.type = elementType;
|
||||
}
|
||||
}
|
154
web/node_modules/@testing-library/user-event/dist/click.js
generated
vendored
Normal file
154
web/node_modules/@testing-library/user-event/dist/click.js
generated
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.click = click;
|
||||
exports.dblClick = dblClick;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
var _hover = require("./hover");
|
||||
|
||||
var _blur = require("./blur");
|
||||
|
||||
var _focus = require("./focus");
|
||||
|
||||
function getPreviouslyFocusedElement(element) {
|
||||
const focusedElement = element.ownerDocument.activeElement;
|
||||
const wasAnotherElementFocused = focusedElement && focusedElement !== element.ownerDocument.body && focusedElement !== element;
|
||||
return wasAnotherElementFocused ? focusedElement : null;
|
||||
}
|
||||
|
||||
function clickLabel(label, init, {
|
||||
clickCount
|
||||
}) {
|
||||
if ((0, _utils.isLabelWithInternallyDisabledControl)(label)) return;
|
||||
|
||||
_dom.fireEvent.pointerDown(label, init);
|
||||
|
||||
_dom.fireEvent.mouseDown(label, (0, _utils.getMouseEventOptions)('mousedown', init, clickCount));
|
||||
|
||||
_dom.fireEvent.pointerUp(label, init);
|
||||
|
||||
_dom.fireEvent.mouseUp(label, (0, _utils.getMouseEventOptions)('mouseup', init, clickCount));
|
||||
|
||||
_dom.fireEvent.click(label, (0, _utils.getMouseEventOptions)('click', init, clickCount)); // clicking the label will trigger a click of the label.control
|
||||
// however, it will not focus the label.control so we have to do it
|
||||
// ourselves.
|
||||
|
||||
|
||||
if (label.control) (0, _focus.focus)(label.control);
|
||||
}
|
||||
|
||||
function clickBooleanElement(element, init, clickCount) {
|
||||
_dom.fireEvent.pointerDown(element, init);
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseDown(element, (0, _utils.getMouseEventOptions)('mousedown', init, clickCount));
|
||||
}
|
||||
|
||||
(0, _focus.focus)(element, init);
|
||||
|
||||
_dom.fireEvent.pointerUp(element, init);
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseUp(element, (0, _utils.getMouseEventOptions)('mouseup', init, clickCount));
|
||||
|
||||
_dom.fireEvent.click(element, (0, _utils.getMouseEventOptions)('click', init, clickCount));
|
||||
}
|
||||
}
|
||||
|
||||
function clickElement(element, init, {
|
||||
clickCount
|
||||
}) {
|
||||
const previousElement = getPreviouslyFocusedElement(element);
|
||||
|
||||
_dom.fireEvent.pointerDown(element, init);
|
||||
|
||||
if (!element.disabled) {
|
||||
const continueDefaultHandling = _dom.fireEvent.mouseDown(element, (0, _utils.getMouseEventOptions)('mousedown', init, clickCount));
|
||||
|
||||
if (continueDefaultHandling) {
|
||||
const closestFocusable = findClosest(element, _utils.isFocusable);
|
||||
|
||||
if (previousElement && !closestFocusable) {
|
||||
(0, _blur.blur)(previousElement, init);
|
||||
} else if (closestFocusable) {
|
||||
(0, _focus.focus)(closestFocusable, init);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_dom.fireEvent.pointerUp(element, init);
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseUp(element, (0, _utils.getMouseEventOptions)('mouseup', init, clickCount));
|
||||
|
||||
_dom.fireEvent.click(element, (0, _utils.getMouseEventOptions)('click', init, clickCount));
|
||||
|
||||
const parentLabel = element.closest('label');
|
||||
if (parentLabel != null && parentLabel.control) (0, _focus.focus)(parentLabel.control, init);
|
||||
}
|
||||
}
|
||||
|
||||
function findClosest(el, callback) {
|
||||
do {
|
||||
if (callback(el)) {
|
||||
return el;
|
||||
}
|
||||
|
||||
el = el.parentElement;
|
||||
} while (el && el !== document.body);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function click(element, init, {
|
||||
skipHover = false,
|
||||
clickCount = 0
|
||||
} = {}) {
|
||||
if (!skipHover) (0, _hover.hover)(element, init);
|
||||
|
||||
switch (element.tagName) {
|
||||
case 'LABEL':
|
||||
clickLabel(element, init, {
|
||||
clickCount
|
||||
});
|
||||
break;
|
||||
|
||||
case 'INPUT':
|
||||
if (element.type === 'checkbox' || element.type === 'radio') {
|
||||
clickBooleanElement(element, init, {
|
||||
clickCount
|
||||
});
|
||||
} else {
|
||||
clickElement(element, init, {
|
||||
clickCount
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
clickElement(element, init, {
|
||||
clickCount
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function dblClick(element, init) {
|
||||
(0, _hover.hover)(element, init);
|
||||
click(element, init, {
|
||||
skipHover: true,
|
||||
clickCount: 0
|
||||
});
|
||||
click(element, init, {
|
||||
skipHover: true,
|
||||
clickCount: 1
|
||||
});
|
||||
|
||||
_dom.fireEvent.dblClick(element, (0, _utils.getMouseEventOptions)('dblclick', init, 2));
|
||||
}
|
15
web/node_modules/@testing-library/user-event/dist/focus.js
generated
vendored
Normal file
15
web/node_modules/@testing-library/user-event/dist/focus.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.focus = focus;
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
function focus(element) {
|
||||
if (!(0, _utils.isFocusable)(element)) return;
|
||||
const isAlreadyActive = (0, _utils.getActiveElement)(element.ownerDocument) === element;
|
||||
if (isAlreadyActive) return;
|
||||
(0, _utils.eventWrapper)(() => element.focus());
|
||||
}
|
73
web/node_modules/@testing-library/user-event/dist/hover.js
generated
vendored
Normal file
73
web/node_modules/@testing-library/user-event/dist/hover.js
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.hover = hover;
|
||||
exports.unhover = unhover;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
// includes `element`
|
||||
function getParentElements(element) {
|
||||
const parentElements = [element];
|
||||
let currentElement = element;
|
||||
|
||||
while ((currentElement = currentElement.parentElement) != null) {
|
||||
parentElements.push(currentElement);
|
||||
}
|
||||
|
||||
return parentElements;
|
||||
}
|
||||
|
||||
function hover(element, init) {
|
||||
if ((0, _utils.isLabelWithInternallyDisabledControl)(element)) return;
|
||||
const parentElements = getParentElements(element).reverse();
|
||||
|
||||
_dom.fireEvent.pointerOver(element, init);
|
||||
|
||||
for (const el of parentElements) {
|
||||
_dom.fireEvent.pointerEnter(el, init);
|
||||
}
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseOver(element, (0, _utils.getMouseEventOptions)('mouseover', init));
|
||||
|
||||
for (const el of parentElements) {
|
||||
_dom.fireEvent.mouseEnter(el, (0, _utils.getMouseEventOptions)('mouseenter', init));
|
||||
}
|
||||
}
|
||||
|
||||
_dom.fireEvent.pointerMove(element, init);
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseMove(element, (0, _utils.getMouseEventOptions)('mousemove', init));
|
||||
}
|
||||
}
|
||||
|
||||
function unhover(element, init) {
|
||||
if ((0, _utils.isLabelWithInternallyDisabledControl)(element)) return;
|
||||
const parentElements = getParentElements(element);
|
||||
|
||||
_dom.fireEvent.pointerMove(element, init);
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseMove(element, (0, _utils.getMouseEventOptions)('mousemove', init));
|
||||
}
|
||||
|
||||
_dom.fireEvent.pointerOut(element, init);
|
||||
|
||||
for (const el of parentElements) {
|
||||
_dom.fireEvent.pointerLeave(el, init);
|
||||
}
|
||||
|
||||
if (!element.disabled) {
|
||||
_dom.fireEvent.mouseOut(element, (0, _utils.getMouseEventOptions)('mouseout', init));
|
||||
|
||||
for (const el of parentElements) {
|
||||
_dom.fireEvent.mouseLeave(el, (0, _utils.getMouseEventOptions)('mouseleave', init));
|
||||
}
|
||||
}
|
||||
}
|
44
web/node_modules/@testing-library/user-event/dist/index.js
generated
vendored
Normal file
44
web/node_modules/@testing-library/user-event/dist/index.js
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "specialChars", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _type.specialCharMap;
|
||||
}
|
||||
});
|
||||
exports.default = void 0;
|
||||
|
||||
var _click = require("./click");
|
||||
|
||||
var _type = require("./type");
|
||||
|
||||
var _clear = require("./clear");
|
||||
|
||||
var _tab = require("./tab");
|
||||
|
||||
var _hover = require("./hover");
|
||||
|
||||
var _upload = require("./upload");
|
||||
|
||||
var _selectOptions = require("./select-options");
|
||||
|
||||
var _paste = require("./paste");
|
||||
|
||||
const userEvent = {
|
||||
click: _click.click,
|
||||
dblClick: _click.dblClick,
|
||||
type: _type.type,
|
||||
clear: _clear.clear,
|
||||
tab: _tab.tab,
|
||||
hover: _hover.hover,
|
||||
unhover: _hover.unhover,
|
||||
upload: _upload.upload,
|
||||
selectOptions: _selectOptions.selectOptions,
|
||||
deselectOptions: _selectOptions.deselectOptions,
|
||||
paste: _paste.paste
|
||||
};
|
||||
var _default = userEvent;
|
||||
exports.default = _default;
|
75
web/node_modules/@testing-library/user-event/dist/keys/navigation-key.js
generated
vendored
Normal file
75
web/node_modules/@testing-library/user-event/dist/keys/navigation-key.js
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.navigationKey = navigationKey;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("../utils");
|
||||
|
||||
const keys = {
|
||||
Home: {
|
||||
keyCode: 36
|
||||
},
|
||||
End: {
|
||||
keyCode: 35
|
||||
},
|
||||
ArrowLeft: {
|
||||
keyCode: 37
|
||||
},
|
||||
ArrowRight: {
|
||||
keyCode: 39
|
||||
}
|
||||
};
|
||||
|
||||
function getSelectionRange(currentElement, key) {
|
||||
const {
|
||||
selectionStart,
|
||||
selectionEnd
|
||||
} = currentElement();
|
||||
|
||||
if (key === 'Home') {
|
||||
return {
|
||||
selectionStart: 0,
|
||||
selectionEnd: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (key === 'End') {
|
||||
return {
|
||||
selectionStart: selectionEnd + 1,
|
||||
selectionEnd: selectionEnd + 1
|
||||
};
|
||||
}
|
||||
|
||||
const cursorChange = Number(key in keys) * (key === 'ArrowLeft' ? -1 : 1);
|
||||
return {
|
||||
selectionStart: selectionStart + cursorChange,
|
||||
selectionEnd: selectionEnd + cursorChange
|
||||
};
|
||||
}
|
||||
|
||||
function navigationKey(key) {
|
||||
const event = {
|
||||
key,
|
||||
keyCode: keys[key].keyCode,
|
||||
which: keys[key].keyCode
|
||||
};
|
||||
return ({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) => {
|
||||
_dom.fireEvent.keyDown(currentElement(), { ...event,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
const range = getSelectionRange(currentElement, key);
|
||||
(0, _utils.setSelectionRangeIfNecessary)(currentElement(), range.selectionStart, range.selectionEnd);
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), { ...event,
|
||||
...eventOverrides
|
||||
});
|
||||
};
|
||||
}
|
55
web/node_modules/@testing-library/user-event/dist/paste.js
generated
vendored
Normal file
55
web/node_modules/@testing-library/user-event/dist/paste.js
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.paste = paste;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
function paste(element, text, init, {
|
||||
initialSelectionStart,
|
||||
initialSelectionEnd
|
||||
} = {}) {
|
||||
if (element.disabled) return;
|
||||
|
||||
if (typeof element.value === 'undefined') {
|
||||
throw new TypeError(`the current element is of type ${element.tagName} and doesn't have a valid value`);
|
||||
}
|
||||
|
||||
(0, _utils.eventWrapper)(() => element.focus()); // by default, a new element has it's selection start and end at 0
|
||||
// but most of the time when people call "paste", they expect it to paste
|
||||
// at the end of the current input value. So, if the selection start
|
||||
// and end are both the default of 0, then we'll go ahead and change
|
||||
// them to the length of the current value.
|
||||
// the only time it would make sense to pass the initialSelectionStart or
|
||||
// initialSelectionEnd is if you have an input with a value and want to
|
||||
// explicitely start typing with the cursor at 0. Not super common.
|
||||
|
||||
if (element.selectionStart === 0 && element.selectionEnd === 0) {
|
||||
(0, _utils.setSelectionRangeIfNecessary)(element, initialSelectionStart != null ? initialSelectionStart : element.value.length, initialSelectionEnd != null ? initialSelectionEnd : element.value.length);
|
||||
}
|
||||
|
||||
_dom.fireEvent.paste(element, init);
|
||||
|
||||
if (!element.readOnly) {
|
||||
const {
|
||||
newValue,
|
||||
newSelectionStart
|
||||
} = (0, _utils.calculateNewValue)(text, element);
|
||||
|
||||
_dom.fireEvent.input(element, {
|
||||
inputType: 'insertFromPaste',
|
||||
target: {
|
||||
value: newValue
|
||||
}
|
||||
});
|
||||
|
||||
(0, _utils.setSelectionRangeIfNecessary)(element, {
|
||||
newSelectionStart,
|
||||
newSelectionEnd: newSelectionStart
|
||||
});
|
||||
}
|
||||
}
|
118
web/node_modules/@testing-library/user-event/dist/select-options.js
generated
vendored
Normal file
118
web/node_modules/@testing-library/user-event/dist/select-options.js
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.deselectOptions = exports.selectOptions = void 0;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
var _click = require("./click");
|
||||
|
||||
var _focus = require("./focus");
|
||||
|
||||
var _hover = require("./hover");
|
||||
|
||||
function selectOptionsBase(newValue, select, values, init) {
|
||||
if (!newValue && !select.multiple) {
|
||||
throw (0, _dom.getConfig)().getElementError(`Unable to deselect an option in a non-multiple select. Use selectOptions to change the selection instead.`, select);
|
||||
}
|
||||
|
||||
const valArray = Array.isArray(values) ? values : [values];
|
||||
const allOptions = Array.from(select.querySelectorAll('option, [role="option"]'));
|
||||
const selectedOptions = valArray.map(val => {
|
||||
if (allOptions.includes(val)) {
|
||||
return val;
|
||||
} else {
|
||||
const matchingOption = allOptions.find(o => o.value === val || o.innerHTML === val);
|
||||
|
||||
if (matchingOption) {
|
||||
return matchingOption;
|
||||
} else {
|
||||
throw (0, _dom.getConfig)().getElementError(`Value "${val}" not found in options`, select);
|
||||
}
|
||||
}
|
||||
}).filter(option => !option.disabled);
|
||||
if (select.disabled || !selectedOptions.length) return;
|
||||
|
||||
if ((0, _utils.isInstanceOfElement)(select, 'HTMLSelectElement')) {
|
||||
if (select.multiple) {
|
||||
for (const option of selectedOptions) {
|
||||
// events fired for multiple select are weird. Can't use hover...
|
||||
_dom.fireEvent.pointerOver(option, init);
|
||||
|
||||
_dom.fireEvent.pointerEnter(select, init);
|
||||
|
||||
_dom.fireEvent.mouseOver(option);
|
||||
|
||||
_dom.fireEvent.mouseEnter(select);
|
||||
|
||||
_dom.fireEvent.pointerMove(option, init);
|
||||
|
||||
_dom.fireEvent.mouseMove(option, init);
|
||||
|
||||
_dom.fireEvent.pointerDown(option, init);
|
||||
|
||||
_dom.fireEvent.mouseDown(option, init);
|
||||
|
||||
(0, _focus.focus)(select, init);
|
||||
|
||||
_dom.fireEvent.pointerUp(option, init);
|
||||
|
||||
_dom.fireEvent.mouseUp(option, init);
|
||||
|
||||
selectOption(option);
|
||||
|
||||
_dom.fireEvent.click(option, init);
|
||||
}
|
||||
} else if (selectedOptions.length === 1) {
|
||||
// the click to open the select options
|
||||
(0, _click.click)(select, init);
|
||||
selectOption(selectedOptions[0]); // the browser triggers another click event on the select for the click on the option
|
||||
// this second click has no 'down' phase
|
||||
|
||||
_dom.fireEvent.pointerOver(select, init);
|
||||
|
||||
_dom.fireEvent.pointerEnter(select, init);
|
||||
|
||||
_dom.fireEvent.mouseOver(select);
|
||||
|
||||
_dom.fireEvent.mouseEnter(select);
|
||||
|
||||
_dom.fireEvent.pointerUp(select, init);
|
||||
|
||||
_dom.fireEvent.mouseUp(select, init);
|
||||
|
||||
_dom.fireEvent.click(select, init);
|
||||
} else {
|
||||
throw (0, _dom.getConfig)().getElementError(`Cannot select multiple options on a non-multiple select`, select);
|
||||
}
|
||||
} else if (select.getAttribute('role') === 'listbox') {
|
||||
selectedOptions.forEach(option => {
|
||||
(0, _hover.hover)(option, init);
|
||||
(0, _click.click)(option, init);
|
||||
(0, _hover.unhover)(option, init);
|
||||
});
|
||||
} else {
|
||||
throw (0, _dom.getConfig)().getElementError(`Cannot select options on elements that are neither select nor listbox elements`, select);
|
||||
}
|
||||
|
||||
function selectOption(option) {
|
||||
option.selected = newValue;
|
||||
(0, _dom.fireEvent)(select, (0, _dom.createEvent)('input', select, {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
composed: true,
|
||||
...init
|
||||
}));
|
||||
|
||||
_dom.fireEvent.change(select, init);
|
||||
}
|
||||
}
|
||||
|
||||
const selectOptions = selectOptionsBase.bind(null, true);
|
||||
exports.selectOptions = selectOptions;
|
||||
const deselectOptions = selectOptionsBase.bind(null, false);
|
||||
exports.deselectOptions = deselectOptions;
|
138
web/node_modules/@testing-library/user-event/dist/tab.js
generated
vendored
Normal file
138
web/node_modules/@testing-library/user-event/dist/tab.js
generated
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.tab = tab;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
var _focus = require("./focus");
|
||||
|
||||
var _blur = require("./blur");
|
||||
|
||||
function getNextElement(currentIndex, shift, elements, focusTrap) {
|
||||
if (focusTrap === document && currentIndex === 0 && shift) {
|
||||
return document.body;
|
||||
} else if (focusTrap === document && currentIndex === elements.length - 1 && !shift) {
|
||||
return document.body;
|
||||
} else {
|
||||
const nextIndex = shift ? currentIndex - 1 : currentIndex + 1;
|
||||
const defaultIndex = shift ? elements.length - 1 : 0;
|
||||
return elements[nextIndex] || elements[defaultIndex];
|
||||
}
|
||||
}
|
||||
|
||||
function tab({
|
||||
shift = false,
|
||||
focusTrap
|
||||
} = {}) {
|
||||
var _focusTrap$ownerDocum, _focusTrap;
|
||||
|
||||
const previousElement = (0, _utils.getActiveElement)((_focusTrap$ownerDocum = (_focusTrap = focusTrap) == null ? void 0 : _focusTrap.ownerDocument) != null ? _focusTrap$ownerDocum : document);
|
||||
|
||||
if (!focusTrap) {
|
||||
focusTrap = document;
|
||||
}
|
||||
|
||||
const focusableElements = focusTrap.querySelectorAll(_utils.FOCUSABLE_SELECTOR);
|
||||
const enabledElements = [...focusableElements].filter(el => el === previousElement || el.getAttribute('tabindex') !== '-1' && !el.disabled && // Hidden elements are not tabable
|
||||
(0, _utils.isVisible)(el));
|
||||
if (enabledElements.length === 0) return;
|
||||
const orderedElements = enabledElements.map((el, idx) => ({
|
||||
el,
|
||||
idx
|
||||
})).sort((a, b) => {
|
||||
// tabindex has no effect if the active element has tabindex="-1"
|
||||
if (previousElement && previousElement.getAttribute('tabindex') === '-1') {
|
||||
return a.idx - b.idx;
|
||||
}
|
||||
|
||||
const tabIndexA = a.el.getAttribute('tabindex');
|
||||
const tabIndexB = b.el.getAttribute('tabindex');
|
||||
const diff = tabIndexA - tabIndexB;
|
||||
return diff === 0 ? a.idx - b.idx : diff;
|
||||
}).map(({
|
||||
el
|
||||
}) => el);
|
||||
const checkedRadio = {};
|
||||
let prunedElements = [];
|
||||
orderedElements.forEach(el => {
|
||||
// For radio groups keep only the active radio
|
||||
// If there is no active radio, keep only the checked radio
|
||||
// If there is no checked radio, treat like everything else
|
||||
if (el.type === 'radio' && el.name) {
|
||||
// If the active element is part of the group, add only that
|
||||
if (previousElement && previousElement.type === el.type && previousElement.name === el.name) {
|
||||
if (el === previousElement) {
|
||||
prunedElements.push(el);
|
||||
}
|
||||
|
||||
return;
|
||||
} // If we stumble upon a checked radio, remove the others
|
||||
|
||||
|
||||
if (el.checked) {
|
||||
prunedElements = prunedElements.filter(e => e.type !== el.type || e.name !== el.name);
|
||||
prunedElements.push(el);
|
||||
checkedRadio[el.name] = el;
|
||||
return;
|
||||
} // If we already found the checked one, skip
|
||||
|
||||
|
||||
if (checkedRadio[el.name]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
prunedElements.push(el);
|
||||
});
|
||||
const index = prunedElements.findIndex(el => el === previousElement);
|
||||
const nextElement = getNextElement(index, shift, prunedElements, focusTrap);
|
||||
const shiftKeyInit = {
|
||||
key: 'Shift',
|
||||
keyCode: 16,
|
||||
shiftKey: true
|
||||
};
|
||||
const tabKeyInit = {
|
||||
key: 'Tab',
|
||||
keyCode: 9,
|
||||
shiftKey: shift
|
||||
};
|
||||
let continueToTab = true; // not sure how to make it so there's no previous element...
|
||||
// istanbul ignore else
|
||||
|
||||
if (previousElement) {
|
||||
// preventDefault on the shift key makes no difference
|
||||
if (shift) _dom.fireEvent.keyDown(previousElement, { ...shiftKeyInit
|
||||
});
|
||||
continueToTab = _dom.fireEvent.keyDown(previousElement, { ...tabKeyInit
|
||||
});
|
||||
}
|
||||
|
||||
const keyUpTarget = !continueToTab && previousElement ? previousElement : nextElement;
|
||||
|
||||
if (continueToTab) {
|
||||
if (nextElement === document.body) {
|
||||
(0, _blur.blur)(previousElement);
|
||||
} else {
|
||||
(0, _focus.focus)(nextElement);
|
||||
}
|
||||
}
|
||||
|
||||
_dom.fireEvent.keyUp(keyUpTarget, { ...tabKeyInit
|
||||
});
|
||||
|
||||
if (shift) {
|
||||
_dom.fireEvent.keyUp(keyUpTarget, { ...shiftKeyInit,
|
||||
shiftKey: false
|
||||
});
|
||||
}
|
||||
}
|
||||
/*
|
||||
eslint
|
||||
complexity: "off",
|
||||
max-statements: "off",
|
||||
*/
|
867
web/node_modules/@testing-library/user-event/dist/type.js
generated
vendored
Normal file
867
web/node_modules/@testing-library/user-event/dist/type.js
generated
vendored
Normal file
|
@ -0,0 +1,867 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.type = type;
|
||||
exports.specialCharMap = void 0;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _utils = require("./utils");
|
||||
|
||||
var _click = require("./click");
|
||||
|
||||
var _navigationKey = require("./keys/navigation-key");
|
||||
|
||||
// TODO: wrap in asyncWrapper
|
||||
const modifierCallbackMap = { ...createModifierCallbackEntries({
|
||||
name: 'shift',
|
||||
key: 'Shift',
|
||||
keyCode: 16,
|
||||
modifierProperty: 'shiftKey'
|
||||
}),
|
||||
...createModifierCallbackEntries({
|
||||
name: 'ctrl',
|
||||
key: 'Control',
|
||||
keyCode: 17,
|
||||
modifierProperty: 'ctrlKey'
|
||||
}),
|
||||
...createModifierCallbackEntries({
|
||||
name: 'alt',
|
||||
key: 'Alt',
|
||||
keyCode: 18,
|
||||
modifierProperty: 'altKey'
|
||||
}),
|
||||
...createModifierCallbackEntries({
|
||||
name: 'meta',
|
||||
key: 'Meta',
|
||||
keyCode: 93,
|
||||
modifierProperty: 'metaKey'
|
||||
}),
|
||||
// capslock is inline because of the need to fire both keydown and keyup on use, while preserving the modifier state.
|
||||
'{capslock}': function capslockOn({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const newEventOverrides = {
|
||||
modifierCapsLock: true
|
||||
};
|
||||
|
||||
_dom.fireEvent.keyDown(currentElement(), {
|
||||
key: 'CapsLock',
|
||||
keyCode: 20,
|
||||
which: 20,
|
||||
...eventOverrides,
|
||||
...newEventOverrides
|
||||
});
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key: 'CapsLock',
|
||||
keyCode: 20,
|
||||
which: 20,
|
||||
...eventOverrides,
|
||||
...newEventOverrides
|
||||
});
|
||||
|
||||
return {
|
||||
eventOverrides: newEventOverrides
|
||||
};
|
||||
},
|
||||
'{/capslock}': function capslockOff({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const newEventOverrides = {
|
||||
modifierCapsLock: false
|
||||
};
|
||||
|
||||
_dom.fireEvent.keyDown(currentElement(), {
|
||||
key: 'CapsLock',
|
||||
keyCode: 20,
|
||||
which: 20,
|
||||
...eventOverrides,
|
||||
...newEventOverrides
|
||||
});
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key: 'CapsLock',
|
||||
keyCode: 20,
|
||||
which: 20,
|
||||
...eventOverrides,
|
||||
...newEventOverrides
|
||||
});
|
||||
|
||||
return {
|
||||
eventOverrides: newEventOverrides
|
||||
};
|
||||
}
|
||||
};
|
||||
const specialCharMap = {
|
||||
arrowLeft: '{arrowleft}',
|
||||
arrowRight: '{arrowright}',
|
||||
arrowDown: '{arrowdown}',
|
||||
arrowUp: '{arrowup}',
|
||||
enter: '{enter}',
|
||||
escape: '{esc}',
|
||||
delete: '{del}',
|
||||
backspace: '{backspace}',
|
||||
home: '{home}',
|
||||
end: '{end}',
|
||||
selectAll: '{selectall}',
|
||||
space: '{space}',
|
||||
whitespace: ' '
|
||||
};
|
||||
exports.specialCharMap = specialCharMap;
|
||||
const specialCharCallbackMap = {
|
||||
[specialCharMap.arrowLeft]: (0, _navigationKey.navigationKey)('ArrowLeft'),
|
||||
[specialCharMap.arrowRight]: (0, _navigationKey.navigationKey)('ArrowRight'),
|
||||
[specialCharMap.arrowDown]: handleArrowDown,
|
||||
[specialCharMap.arrowUp]: handleArrowUp,
|
||||
[specialCharMap.home]: (0, _navigationKey.navigationKey)('Home'),
|
||||
[specialCharMap.end]: (0, _navigationKey.navigationKey)('End'),
|
||||
[specialCharMap.enter]: handleEnter,
|
||||
[specialCharMap.escape]: handleEsc,
|
||||
[specialCharMap.delete]: handleDel,
|
||||
[specialCharMap.backspace]: handleBackspace,
|
||||
[specialCharMap.selectAll]: handleSelectall,
|
||||
[specialCharMap.space]: handleSpace,
|
||||
[specialCharMap.whitespace]: handleSpace
|
||||
};
|
||||
|
||||
function wait(time) {
|
||||
return new Promise(resolve => setTimeout(() => resolve(), time));
|
||||
} // this needs to be wrapped in the event/asyncWrapper for React's act and angular's change detection
|
||||
// depending on whether it will be async.
|
||||
|
||||
|
||||
async function type(element, text, {
|
||||
delay = 0,
|
||||
...options
|
||||
} = {}) {
|
||||
// we do not want to wrap in the asyncWrapper if we're not
|
||||
// going to actually be doing anything async, so we only wrap
|
||||
// if the delay is greater than 0
|
||||
let result;
|
||||
|
||||
if (delay > 0) {
|
||||
await (0, _dom.getConfig)().asyncWrapper(async () => {
|
||||
result = await typeImpl(element, text, {
|
||||
delay,
|
||||
...options
|
||||
});
|
||||
});
|
||||
} else {
|
||||
result = typeImpl(element, text, {
|
||||
delay,
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function typeImpl(element, text, {
|
||||
delay,
|
||||
skipClick = false,
|
||||
skipAutoClose = false,
|
||||
initialSelectionStart,
|
||||
initialSelectionEnd
|
||||
}) {
|
||||
if (element.disabled) return;
|
||||
if (!skipClick) (0, _click.click)(element);
|
||||
|
||||
if ((0, _utils.isContentEditable)(element) && document.getSelection().rangeCount === 0) {
|
||||
const range = document.createRange();
|
||||
range.setStart(element, 0);
|
||||
range.setEnd(element, 0);
|
||||
document.getSelection().addRange(range);
|
||||
} // The focused element could change between each event, so get the currently active element each time
|
||||
|
||||
|
||||
const currentElement = () => (0, _utils.getActiveElement)(element.ownerDocument); // by default, a new element has it's selection start and end at 0
|
||||
// but most of the time when people call "type", they expect it to type
|
||||
// at the end of the current input value. So, if the selection start
|
||||
// and end are both the default of 0, then we'll go ahead and change
|
||||
// them to the length of the current value.
|
||||
// the only time it would make sense to pass the initialSelectionStart or
|
||||
// initialSelectionEnd is if you have an input with a value and want to
|
||||
// explicitely start typing with the cursor at 0. Not super common.
|
||||
|
||||
|
||||
const value = (0, _utils.getValue)(currentElement());
|
||||
const {
|
||||
selectionStart,
|
||||
selectionEnd
|
||||
} = (0, _utils.getSelectionRange)(element);
|
||||
|
||||
if (value != null && selectionStart === 0 && selectionEnd === 0) {
|
||||
(0, _utils.setSelectionRangeIfNecessary)(currentElement(), initialSelectionStart != null ? initialSelectionStart : value.length, initialSelectionEnd != null ? initialSelectionEnd : value.length);
|
||||
}
|
||||
|
||||
const eventCallbacks = queueCallbacks();
|
||||
await runCallbacks(eventCallbacks);
|
||||
|
||||
function queueCallbacks() {
|
||||
const callbacks = [];
|
||||
let remainingString = text;
|
||||
|
||||
while (remainingString) {
|
||||
const {
|
||||
callback,
|
||||
remainingString: newRemainingString
|
||||
} = getNextCallback(remainingString, skipAutoClose);
|
||||
callbacks.push(callback);
|
||||
remainingString = newRemainingString;
|
||||
}
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
async function runCallbacks(callbacks) {
|
||||
const eventOverrides = {};
|
||||
let prevWasMinus, prevWasPeriod, prevValue, typedValue;
|
||||
|
||||
for (const callback of callbacks) {
|
||||
if (delay > 0) await wait(delay);
|
||||
|
||||
if (!currentElement().disabled) {
|
||||
const returnValue = callback({
|
||||
currentElement,
|
||||
prevWasMinus,
|
||||
prevWasPeriod,
|
||||
prevValue,
|
||||
eventOverrides,
|
||||
typedValue
|
||||
});
|
||||
Object.assign(eventOverrides, returnValue == null ? void 0 : returnValue.eventOverrides);
|
||||
prevWasMinus = returnValue == null ? void 0 : returnValue.prevWasMinus;
|
||||
prevWasPeriod = returnValue == null ? void 0 : returnValue.prevWasPeriod;
|
||||
prevValue = returnValue == null ? void 0 : returnValue.prevValue;
|
||||
typedValue = returnValue == null ? void 0 : returnValue.typedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNextCallback(remainingString, skipAutoClose) {
|
||||
const modifierCallback = getModifierCallback(remainingString, skipAutoClose);
|
||||
|
||||
if (modifierCallback) {
|
||||
return modifierCallback;
|
||||
}
|
||||
|
||||
const specialCharCallback = getSpecialCharCallback(remainingString);
|
||||
|
||||
if (specialCharCallback) {
|
||||
return specialCharCallback;
|
||||
}
|
||||
|
||||
return getTypeCallback(remainingString);
|
||||
}
|
||||
|
||||
function getModifierCallback(remainingString, skipAutoClose) {
|
||||
const modifierKey = Object.keys(modifierCallbackMap).find(key => remainingString.startsWith(key));
|
||||
|
||||
if (!modifierKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const callback = modifierCallbackMap[modifierKey]; // if this modifier has an associated "close" callback and the developer
|
||||
// doesn't close it themselves, then we close it for them automatically
|
||||
// Effectively if they send in: '{alt}a' then we type: '{alt}a{/alt}'
|
||||
|
||||
if (!skipAutoClose && callback.closeName && !remainingString.includes(callback.closeName)) {
|
||||
remainingString += callback.closeName;
|
||||
}
|
||||
|
||||
remainingString = remainingString.slice(modifierKey.length);
|
||||
return {
|
||||
callback,
|
||||
remainingString
|
||||
};
|
||||
}
|
||||
|
||||
function getSpecialCharCallback(remainingString) {
|
||||
const specialChar = Object.keys(specialCharCallbackMap).find(key => remainingString.startsWith(key));
|
||||
|
||||
if (!specialChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
callback: specialCharCallbackMap[specialChar],
|
||||
remainingString: remainingString.slice(specialChar.length)
|
||||
};
|
||||
}
|
||||
|
||||
function getTypeCallback(remainingString) {
|
||||
const character = remainingString[0];
|
||||
|
||||
const callback = context => typeCharacter(character, context);
|
||||
|
||||
return {
|
||||
callback,
|
||||
remainingString: remainingString.slice(1)
|
||||
};
|
||||
}
|
||||
|
||||
function setSelectionRange({
|
||||
currentElement,
|
||||
newValue,
|
||||
newSelectionStart
|
||||
}) {
|
||||
// if we *can* change the selection start, then we will if the new value
|
||||
// is the same as the current value (so it wasn't programatically changed
|
||||
// when the fireEvent.input was triggered).
|
||||
// The reason we have to do this at all is because it actually *is*
|
||||
// programmatically changed by fireEvent.input, so we have to simulate the
|
||||
// browser's default behavior
|
||||
const value = (0, _utils.getValue)(currentElement());
|
||||
|
||||
if (value === newValue) {
|
||||
(0, _utils.setSelectionRangeIfNecessary)(currentElement(), newSelectionStart, newSelectionStart);
|
||||
} else {
|
||||
// If the currentValue is different than the expected newValue and we *can*
|
||||
// change the selection range, than we should set it to the length of the
|
||||
// currentValue to ensure that the browser behavior is mimicked.
|
||||
(0, _utils.setSelectionRangeIfNecessary)(currentElement(), value.length, value.length);
|
||||
}
|
||||
}
|
||||
|
||||
function fireInputEventIfNeeded({
|
||||
currentElement,
|
||||
newValue,
|
||||
newSelectionStart,
|
||||
eventOverrides
|
||||
}) {
|
||||
const prevValue = (0, _utils.getValue)(currentElement());
|
||||
|
||||
if (!currentElement().readOnly && !(0, _utils.isClickableInput)(currentElement()) && newValue !== prevValue) {
|
||||
if ((0, _utils.isContentEditable)(currentElement())) {
|
||||
_dom.fireEvent.input(currentElement(), {
|
||||
target: {
|
||||
textContent: newValue
|
||||
},
|
||||
...eventOverrides
|
||||
});
|
||||
} else {
|
||||
_dom.fireEvent.input(currentElement(), {
|
||||
target: {
|
||||
value: newValue
|
||||
},
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
setSelectionRange({
|
||||
currentElement,
|
||||
newValue,
|
||||
newSelectionStart
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
prevValue
|
||||
};
|
||||
}
|
||||
|
||||
function typeCharacter(char, {
|
||||
currentElement,
|
||||
prevWasMinus = false,
|
||||
prevWasPeriod = false,
|
||||
prevValue = '',
|
||||
typedValue = '',
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = char; // TODO: check if this also valid for characters with diacritic markers e.g. úé etc
|
||||
|
||||
const keyCode = char.charCodeAt(0);
|
||||
let nextPrevWasMinus, nextPrevWasPeriod;
|
||||
const textToBeTyped = typedValue + char;
|
||||
|
||||
const keyDownDefaultNotPrevented = _dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyDownDefaultNotPrevented) {
|
||||
const keyPressDefaultNotPrevented = _dom.fireEvent.keyPress(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
charCode: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if ((0, _utils.getValue)(currentElement()) != null && keyPressDefaultNotPrevented) {
|
||||
let newEntry = char;
|
||||
|
||||
if (prevWasMinus) {
|
||||
newEntry = `-${char}`;
|
||||
} else if (prevWasPeriod) {
|
||||
newEntry = `${prevValue}.${char}`;
|
||||
}
|
||||
|
||||
if ((0, _utils.isValidDateValue)(currentElement(), textToBeTyped)) {
|
||||
newEntry = textToBeTyped;
|
||||
}
|
||||
|
||||
const timeNewEntry = (0, _utils.buildTimeValue)(textToBeTyped);
|
||||
|
||||
if ((0, _utils.isValidInputTimeValue)(currentElement(), timeNewEntry)) {
|
||||
newEntry = timeNewEntry;
|
||||
}
|
||||
|
||||
const inputEvent = fireInputEventIfNeeded({ ...(0, _utils.calculateNewValue)(newEntry, currentElement()),
|
||||
eventOverrides: {
|
||||
data: key,
|
||||
inputType: 'insertText',
|
||||
...eventOverrides
|
||||
},
|
||||
currentElement
|
||||
});
|
||||
prevValue = inputEvent.prevValue;
|
||||
|
||||
if ((0, _utils.isValidDateValue)(currentElement(), textToBeTyped)) {
|
||||
_dom.fireEvent.change(currentElement(), {
|
||||
target: {
|
||||
value: textToBeTyped
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fireChangeForInputTimeIfValid(currentElement, prevValue, timeNewEntry); // typing "-" into a number input will not actually update the value
|
||||
// so for the next character we type, the value should be set to
|
||||
// `-${newEntry}`
|
||||
// we also preserve the prevWasMinus when the value is unchanged due
|
||||
// to typing an invalid character (typing "-a3" results in "-3")
|
||||
// same applies for the decimal character.
|
||||
|
||||
if (currentElement().type === 'number') {
|
||||
const newValue = (0, _utils.getValue)(currentElement());
|
||||
|
||||
if (newValue === prevValue && newEntry !== '-') {
|
||||
nextPrevWasMinus = prevWasMinus;
|
||||
} else {
|
||||
nextPrevWasMinus = newEntry === '-';
|
||||
}
|
||||
|
||||
if (newValue === prevValue && newEntry !== '.') {
|
||||
nextPrevWasPeriod = prevWasPeriod;
|
||||
} else {
|
||||
nextPrevWasPeriod = newEntry === '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
return {
|
||||
prevWasMinus: nextPrevWasMinus,
|
||||
prevWasPeriod: nextPrevWasPeriod,
|
||||
prevValue,
|
||||
typedValue: textToBeTyped
|
||||
};
|
||||
}
|
||||
|
||||
function fireChangeForInputTimeIfValid(currentElement, prevValue, timeNewEntry) {
|
||||
if ((0, _utils.isValidInputTimeValue)(currentElement(), timeNewEntry) && prevValue !== timeNewEntry) {
|
||||
_dom.fireEvent.change(currentElement(), {
|
||||
target: {
|
||||
value: timeNewEntry
|
||||
}
|
||||
});
|
||||
}
|
||||
} // yes, calculateNewBackspaceValue and calculateNewValue look extremely similar
|
||||
// and you may be tempted to create a shared abstraction.
|
||||
// If you, brave soul, decide to so endevor, please increment this count
|
||||
// when you inevitably fail: 1
|
||||
|
||||
|
||||
function calculateNewBackspaceValue(element) {
|
||||
const {
|
||||
selectionStart,
|
||||
selectionEnd
|
||||
} = (0, _utils.getSelectionRange)(element);
|
||||
const value = (0, _utils.getValue)(element);
|
||||
let newValue, newSelectionStart;
|
||||
|
||||
if (selectionStart === null) {
|
||||
// at the end of an input type that does not support selection ranges
|
||||
// https://github.com/testing-library/user-event/issues/316#issuecomment-639744793
|
||||
newValue = value.slice(0, value.length - 1);
|
||||
newSelectionStart = selectionStart - 1;
|
||||
} else if (selectionStart === selectionEnd) {
|
||||
if (selectionStart === 0) {
|
||||
// at the beginning of the input
|
||||
newValue = value;
|
||||
newSelectionStart = selectionStart;
|
||||
} else if (selectionStart === value.length) {
|
||||
// at the end of the input
|
||||
newValue = value.slice(0, value.length - 1);
|
||||
newSelectionStart = selectionStart - 1;
|
||||
} else {
|
||||
// in the middle of the input
|
||||
newValue = value.slice(0, selectionStart - 1) + value.slice(selectionEnd);
|
||||
newSelectionStart = selectionStart - 1;
|
||||
}
|
||||
} else {
|
||||
// we have something selected
|
||||
const firstPart = value.slice(0, selectionStart);
|
||||
newValue = firstPart + value.slice(selectionEnd);
|
||||
newSelectionStart = firstPart.length;
|
||||
}
|
||||
|
||||
return {
|
||||
newValue,
|
||||
newSelectionStart
|
||||
};
|
||||
}
|
||||
|
||||
function calculateNewDeleteValue(element) {
|
||||
const {
|
||||
selectionStart,
|
||||
selectionEnd
|
||||
} = (0, _utils.getSelectionRange)(element);
|
||||
const value = (0, _utils.getValue)(element);
|
||||
let newValue;
|
||||
|
||||
if (selectionStart === null) {
|
||||
// at the end of an input type that does not support selection ranges
|
||||
// https://github.com/testing-library/user-event/issues/316#issuecomment-639744793
|
||||
newValue = value;
|
||||
} else if (selectionStart === selectionEnd) {
|
||||
if (selectionStart === 0) {
|
||||
// at the beginning of the input
|
||||
newValue = value.slice(1);
|
||||
} else if (selectionStart === value.length) {
|
||||
// at the end of the input
|
||||
newValue = value;
|
||||
} else {
|
||||
// in the middle of the input
|
||||
newValue = value.slice(0, selectionStart) + value.slice(selectionEnd + 1);
|
||||
}
|
||||
} else {
|
||||
// we have something selected
|
||||
const firstPart = value.slice(0, selectionStart);
|
||||
newValue = firstPart + value.slice(selectionEnd);
|
||||
}
|
||||
|
||||
return {
|
||||
newValue,
|
||||
newSelectionStart: selectionStart
|
||||
};
|
||||
}
|
||||
|
||||
function createModifierCallbackEntries({
|
||||
name,
|
||||
key,
|
||||
keyCode,
|
||||
modifierProperty
|
||||
}) {
|
||||
const openName = `{${name}}`;
|
||||
const closeName = `{/${name}}`;
|
||||
|
||||
function open({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const newEventOverrides = {
|
||||
[modifierProperty]: true
|
||||
};
|
||||
|
||||
_dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides,
|
||||
...newEventOverrides
|
||||
});
|
||||
|
||||
return {
|
||||
eventOverrides: newEventOverrides
|
||||
};
|
||||
}
|
||||
|
||||
open.closeName = closeName;
|
||||
|
||||
function close({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const newEventOverrides = {
|
||||
[modifierProperty]: false
|
||||
};
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides,
|
||||
...newEventOverrides
|
||||
});
|
||||
|
||||
return {
|
||||
eventOverrides: newEventOverrides
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
[openName]: open,
|
||||
[closeName]: close
|
||||
};
|
||||
}
|
||||
|
||||
function handleEnter({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = 'Enter';
|
||||
const keyCode = 13;
|
||||
|
||||
const keyDownDefaultNotPrevented = _dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyDownDefaultNotPrevented) {
|
||||
const keyPressDefaultNotPrevented = _dom.fireEvent.keyPress(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
charCode: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyPressDefaultNotPrevented) {
|
||||
if ((0, _utils.isClickableInput)(currentElement()) || // Links with href defined should handle Enter the same as a click
|
||||
(0, _utils.isInstanceOfElement)(currentElement(), 'HTMLAnchorElement') && currentElement().href) {
|
||||
_dom.fireEvent.click(currentElement(), { ...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
if (currentElement().tagName === 'TEXTAREA') {
|
||||
const {
|
||||
newValue,
|
||||
newSelectionStart
|
||||
} = (0, _utils.calculateNewValue)('\n', currentElement());
|
||||
|
||||
_dom.fireEvent.input(currentElement(), {
|
||||
target: {
|
||||
value: newValue
|
||||
},
|
||||
inputType: 'insertLineBreak',
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
setSelectionRange({
|
||||
currentElement,
|
||||
newValue,
|
||||
newSelectionStart
|
||||
});
|
||||
}
|
||||
|
||||
if (currentElement().tagName === 'INPUT' && currentElement().form && (currentElement().form.querySelectorAll('input').length === 1 || currentElement().form.querySelector('input[type="submit"]') || currentElement().form.querySelector('button[type="submit"]'))) {
|
||||
_dom.fireEvent.submit(currentElement().form);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
function handleEsc({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = 'Escape';
|
||||
const keyCode = 27;
|
||||
|
||||
_dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
}); // NOTE: Browsers do not fire a keypress on meta key presses
|
||||
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
function handleDel({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = 'Delete';
|
||||
const keyCode = 46;
|
||||
|
||||
const keyPressDefaultNotPrevented = _dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyPressDefaultNotPrevented) {
|
||||
fireInputEventIfNeeded({ ...calculateNewDeleteValue(currentElement()),
|
||||
eventOverrides: {
|
||||
inputType: 'deleteContentForward',
|
||||
...eventOverrides
|
||||
},
|
||||
currentElement
|
||||
});
|
||||
}
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
function handleBackspace({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = 'Backspace';
|
||||
const keyCode = 8;
|
||||
|
||||
const keyPressDefaultNotPrevented = _dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyPressDefaultNotPrevented) {
|
||||
fireInputEventIfNeeded({ ...calculateNewBackspaceValue(currentElement()),
|
||||
eventOverrides: {
|
||||
inputType: 'deleteContentBackward',
|
||||
...eventOverrides
|
||||
},
|
||||
currentElement
|
||||
});
|
||||
}
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
function handleSelectall({
|
||||
currentElement
|
||||
}) {
|
||||
currentElement().setSelectionRange(0, (0, _utils.getValue)(currentElement()).length);
|
||||
}
|
||||
|
||||
function handleSpace(context) {
|
||||
if ((0, _utils.isClickableInput)(context.currentElement())) {
|
||||
handleSpaceOnClickable(context);
|
||||
return;
|
||||
}
|
||||
|
||||
typeCharacter(' ', context);
|
||||
}
|
||||
|
||||
function handleSpaceOnClickable({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = ' ';
|
||||
const keyCode = 32;
|
||||
|
||||
const keyDownDefaultNotPrevented = _dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyDownDefaultNotPrevented) {
|
||||
_dom.fireEvent.keyPress(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
charCode: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
const keyUpDefaultNotPrevented = _dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
if (keyDownDefaultNotPrevented && keyUpDefaultNotPrevented) {
|
||||
_dom.fireEvent.click(currentElement(), { ...eventOverrides
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleArrowDown({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = 'ArrowDown';
|
||||
const keyCode = 40;
|
||||
|
||||
_dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
||||
|
||||
function handleArrowUp({
|
||||
currentElement,
|
||||
eventOverrides
|
||||
}) {
|
||||
const key = 'ArrowUp';
|
||||
const keyCode = 38;
|
||||
|
||||
_dom.fireEvent.keyDown(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
|
||||
_dom.fireEvent.keyUp(currentElement(), {
|
||||
key,
|
||||
keyCode,
|
||||
which: keyCode,
|
||||
...eventOverrides
|
||||
});
|
||||
}
|
74
web/node_modules/@testing-library/user-event/dist/upload.js
generated
vendored
Normal file
74
web/node_modules/@testing-library/user-event/dist/upload.js
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.upload = upload;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _click = require("./click");
|
||||
|
||||
var _blur = require("./blur");
|
||||
|
||||
var _focus = require("./focus");
|
||||
|
||||
function upload(element, fileOrFiles, init, {
|
||||
applyAccept = false
|
||||
} = {}) {
|
||||
if (element.disabled) return;
|
||||
(0, _click.click)(element, init);
|
||||
const input = element.tagName === 'LABEL' ? element.control : element;
|
||||
const files = (Array.isArray(fileOrFiles) ? fileOrFiles : [fileOrFiles]).filter(file => !applyAccept || isAcceptableFile(file, element.accept)).slice(0, input.multiple ? undefined : 1); // blur fires when the file selector pops up
|
||||
|
||||
(0, _blur.blur)(element, init); // focus fires when they make their selection
|
||||
|
||||
(0, _focus.focus)(element, init); // do not fire an input event if the file selection does not change
|
||||
|
||||
if (files.length === input.files.length && files.every((f, i) => f === input.files.item(i))) {
|
||||
return;
|
||||
} // the event fired in the browser isn't actually an "input" or "change" event
|
||||
// but a new Event with a type set to "input" and "change"
|
||||
// Kinda odd...
|
||||
|
||||
|
||||
const inputFiles = {
|
||||
length: files.length,
|
||||
item: index => files[index],
|
||||
...files
|
||||
};
|
||||
(0, _dom.fireEvent)(input, (0, _dom.createEvent)('input', input, {
|
||||
target: {
|
||||
files: inputFiles
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
composed: true,
|
||||
...init
|
||||
}));
|
||||
|
||||
_dom.fireEvent.change(input, {
|
||||
target: {
|
||||
files: inputFiles
|
||||
},
|
||||
...init
|
||||
});
|
||||
}
|
||||
|
||||
function isAcceptableFile(file, accept) {
|
||||
if (!accept) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const wildcards = ['audio/*', 'image/*', 'video/*'];
|
||||
return accept.split(',').some(acceptToken => {
|
||||
if (acceptToken[0] === '.') {
|
||||
// tokens starting with a dot represent a file extension
|
||||
return file.name.endsWith(acceptToken);
|
||||
} else if (wildcards.includes(acceptToken)) {
|
||||
return file.type.startsWith(acceptToken.substr(0, acceptToken.length - 1));
|
||||
}
|
||||
|
||||
return file.type === acceptToken;
|
||||
});
|
||||
}
|
354
web/node_modules/@testing-library/user-event/dist/utils.js
generated
vendored
Normal file
354
web/node_modules/@testing-library/user-event/dist/utils.js
generated
vendored
Normal file
|
@ -0,0 +1,354 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.isFocusable = isFocusable;
|
||||
exports.isClickableInput = isClickableInput;
|
||||
exports.getMouseEventOptions = getMouseEventOptions;
|
||||
exports.isLabelWithInternallyDisabledControl = isLabelWithInternallyDisabledControl;
|
||||
exports.getActiveElement = getActiveElement;
|
||||
exports.calculateNewValue = calculateNewValue;
|
||||
exports.setSelectionRangeIfNecessary = setSelectionRangeIfNecessary;
|
||||
exports.eventWrapper = eventWrapper;
|
||||
exports.isValidDateValue = isValidDateValue;
|
||||
exports.isValidInputTimeValue = isValidInputTimeValue;
|
||||
exports.buildTimeValue = buildTimeValue;
|
||||
exports.getValue = getValue;
|
||||
exports.getSelectionRange = getSelectionRange;
|
||||
exports.isContentEditable = isContentEditable;
|
||||
exports.isInstanceOfElement = isInstanceOfElement;
|
||||
exports.isVisible = isVisible;
|
||||
exports.FOCUSABLE_SELECTOR = void 0;
|
||||
|
||||
var _dom = require("@testing-library/dom");
|
||||
|
||||
var _helpers = require("@testing-library/dom/dist/helpers");
|
||||
|
||||
// isInstanceOfElement can be removed once the peerDependency for @testing-library/dom is bumped to a version that includes https://github.com/testing-library/dom-testing-library/pull/885
|
||||
|
||||
/**
|
||||
* Check if an element is of a given type.
|
||||
*
|
||||
* @param {Element} element The element to test
|
||||
* @param {string} elementType Constructor name. E.g. 'HTMLSelectElement'
|
||||
*/
|
||||
function isInstanceOfElement(element, elementType) {
|
||||
try {
|
||||
const window = (0, _helpers.getWindowFromNode)(element); // Window usually has the element constructors as properties but is not required to do so per specs
|
||||
|
||||
if (typeof window[elementType] === 'function') {
|
||||
return element instanceof window[elementType];
|
||||
}
|
||||
} catch (e) {// The document might not be associated with a window
|
||||
} // Fall back to the constructor name as workaround for test environments that
|
||||
// a) not associate the document with a window
|
||||
// b) not provide the constructor as property of window
|
||||
|
||||
|
||||
if (/^HTML(\w+)Element$/.test(element.constructor.name)) {
|
||||
return element.constructor.name === elementType;
|
||||
} // The user passed some node that is not created in a browser-like environment
|
||||
|
||||
|
||||
throw new Error(`Unable to verify if element is instance of ${elementType}. Please file an issue describing your test environment: https://github.com/testing-library/dom-testing-library/issues/new`);
|
||||
}
|
||||
|
||||
function isMousePressEvent(event) {
|
||||
return event === 'mousedown' || event === 'mouseup' || event === 'click' || event === 'dblclick';
|
||||
}
|
||||
|
||||
function invert(map) {
|
||||
const res = {};
|
||||
|
||||
for (const key of Object.keys(map)) {
|
||||
res[map[key]] = key;
|
||||
}
|
||||
|
||||
return res;
|
||||
} // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
|
||||
|
||||
|
||||
const BUTTONS_TO_NAMES = {
|
||||
0: 'none',
|
||||
1: 'primary',
|
||||
2: 'secondary',
|
||||
4: 'auxiliary'
|
||||
};
|
||||
const NAMES_TO_BUTTONS = invert(BUTTONS_TO_NAMES); // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
||||
|
||||
const BUTTON_TO_NAMES = {
|
||||
0: 'primary',
|
||||
1: 'auxiliary',
|
||||
2: 'secondary'
|
||||
};
|
||||
const NAMES_TO_BUTTON = invert(BUTTON_TO_NAMES);
|
||||
|
||||
function convertMouseButtons(event, init, property, mapping) {
|
||||
if (!isMousePressEvent(event)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (init[property] != null) {
|
||||
return init[property];
|
||||
}
|
||||
|
||||
if (init.buttons != null) {
|
||||
// not sure how to test this. Feel free to try and add a test if you want.
|
||||
// istanbul ignore next
|
||||
return mapping[BUTTONS_TO_NAMES[init.buttons]] || 0;
|
||||
}
|
||||
|
||||
if (init.button != null) {
|
||||
// not sure how to test this. Feel free to try and add a test if you want.
|
||||
// istanbul ignore next
|
||||
return mapping[BUTTON_TO_NAMES[init.button]] || 0;
|
||||
}
|
||||
|
||||
return property != 'button' && isMousePressEvent(event) ? 1 : 0;
|
||||
}
|
||||
|
||||
function getMouseEventOptions(event, init, clickCount = 0) {
|
||||
init = init || {};
|
||||
return { ...init,
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
|
||||
detail: event === 'mousedown' || event === 'mouseup' || event === 'click' ? 1 + clickCount : clickCount,
|
||||
buttons: convertMouseButtons(event, init, 'buttons', NAMES_TO_BUTTONS),
|
||||
button: convertMouseButtons(event, init, 'button', NAMES_TO_BUTTON)
|
||||
};
|
||||
} // Absolutely NO events fire on label elements that contain their control
|
||||
// if that control is disabled. NUTS!
|
||||
// no joke. There are NO events for: <label><input disabled /><label>
|
||||
|
||||
|
||||
function isLabelWithInternallyDisabledControl(element) {
|
||||
var _element$control;
|
||||
|
||||
return element.tagName === 'LABEL' && ((_element$control = element.control) == null ? void 0 : _element$control.disabled) && element.contains(element.control);
|
||||
}
|
||||
|
||||
function getActiveElement(document) {
|
||||
const activeElement = document.activeElement;
|
||||
|
||||
if (activeElement != null && activeElement.shadowRoot) {
|
||||
return getActiveElement(activeElement.shadowRoot);
|
||||
} else {
|
||||
return activeElement;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsMaxLength(element) {
|
||||
if (element.tagName === 'TEXTAREA') return true;
|
||||
|
||||
if (element.tagName === 'INPUT') {
|
||||
const type = element.getAttribute('type'); // Missing value default is "text"
|
||||
|
||||
if (!type) return true; // https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
|
||||
|
||||
if (type.match(/email|password|search|telephone|text|url/)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getSelectionRange(element) {
|
||||
if (isContentEditable(element)) {
|
||||
const range = element.ownerDocument.getSelection().getRangeAt(0);
|
||||
return {
|
||||
selectionStart: range.startOffset,
|
||||
selectionEnd: range.endOffset
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
selectionStart: element.selectionStart,
|
||||
selectionEnd: element.selectionEnd
|
||||
};
|
||||
} //jsdom is not supporting isContentEditable
|
||||
|
||||
|
||||
function isContentEditable(element) {
|
||||
return element.hasAttribute('contenteditable') && (element.getAttribute('contenteditable') == 'true' || element.getAttribute('contenteditable') == '');
|
||||
}
|
||||
|
||||
function getValue(element) {
|
||||
if (isContentEditable(element)) {
|
||||
return element.textContent;
|
||||
}
|
||||
|
||||
return element.value;
|
||||
}
|
||||
|
||||
function calculateNewValue(newEntry, element) {
|
||||
var _element$getAttribute;
|
||||
|
||||
const {
|
||||
selectionStart,
|
||||
selectionEnd
|
||||
} = getSelectionRange(element);
|
||||
const value = getValue(element); // can't use .maxLength property because of a jsdom bug:
|
||||
// https://github.com/jsdom/jsdom/issues/2927
|
||||
|
||||
const maxLength = Number((_element$getAttribute = element.getAttribute('maxlength')) != null ? _element$getAttribute : -1);
|
||||
let newValue, newSelectionStart;
|
||||
|
||||
if (selectionStart === null) {
|
||||
// at the end of an input type that does not support selection ranges
|
||||
// https://github.com/testing-library/user-event/issues/316#issuecomment-639744793
|
||||
newValue = value + newEntry;
|
||||
} else if (selectionStart === selectionEnd) {
|
||||
if (selectionStart === 0) {
|
||||
// at the beginning of the input
|
||||
newValue = newEntry + value;
|
||||
} else if (selectionStart === value.length) {
|
||||
// at the end of the input
|
||||
newValue = value + newEntry;
|
||||
} else {
|
||||
// in the middle of the input
|
||||
newValue = value.slice(0, selectionStart) + newEntry + value.slice(selectionEnd);
|
||||
}
|
||||
|
||||
newSelectionStart = selectionStart + newEntry.length;
|
||||
} else {
|
||||
// we have something selected
|
||||
const firstPart = value.slice(0, selectionStart) + newEntry;
|
||||
newValue = firstPart + value.slice(selectionEnd);
|
||||
newSelectionStart = firstPart.length;
|
||||
}
|
||||
|
||||
if (element.type === 'date' && !isValidDateValue(element, newValue)) {
|
||||
newValue = value;
|
||||
}
|
||||
|
||||
if (element.type === 'time' && !isValidInputTimeValue(element, newValue)) {
|
||||
if (isValidInputTimeValue(element, newEntry)) {
|
||||
newValue = newEntry;
|
||||
} else {
|
||||
newValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!supportsMaxLength(element) || maxLength < 0) {
|
||||
return {
|
||||
newValue,
|
||||
newSelectionStart
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
newValue: newValue.slice(0, maxLength),
|
||||
newSelectionStart: newSelectionStart > maxLength ? maxLength : newSelectionStart
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function setSelectionRangeIfNecessary(element, newSelectionStart, newSelectionEnd) {
|
||||
const {
|
||||
selectionStart,
|
||||
selectionEnd
|
||||
} = getSelectionRange(element);
|
||||
|
||||
if (!isContentEditable(element) && (!element.setSelectionRange || selectionStart === null)) {
|
||||
// cannot set selection
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectionStart !== newSelectionStart || selectionEnd !== newSelectionStart) {
|
||||
if (isContentEditable(element)) {
|
||||
const range = element.ownerDocument.createRange();
|
||||
range.selectNodeContents(element);
|
||||
range.setStart(element.firstChild, newSelectionStart);
|
||||
range.setEnd(element.firstChild, newSelectionEnd);
|
||||
element.ownerDocument.getSelection().removeAllRanges();
|
||||
element.ownerDocument.getSelection().addRange(range);
|
||||
} else {
|
||||
element.setSelectionRange(newSelectionStart, newSelectionEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FOCUSABLE_SELECTOR = ['input:not([type=hidden]):not([disabled])', 'button:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', '[contenteditable=""]', '[contenteditable="true"]', 'a[href]', '[tabindex]:not([disabled])'].join(', ');
|
||||
exports.FOCUSABLE_SELECTOR = FOCUSABLE_SELECTOR;
|
||||
|
||||
function isFocusable(element) {
|
||||
return !isLabelWithInternallyDisabledControl(element) && (element == null ? void 0 : element.matches(FOCUSABLE_SELECTOR));
|
||||
}
|
||||
|
||||
const CLICKABLE_INPUT_TYPES = ['button', 'color', 'file', 'image', 'reset', 'submit'];
|
||||
|
||||
function isClickableInput(element) {
|
||||
return element.tagName === 'BUTTON' || isInstanceOfElement(element, 'HTMLInputElement') && CLICKABLE_INPUT_TYPES.includes(element.type);
|
||||
}
|
||||
|
||||
function isVisible(element) {
|
||||
const getComputedStyle = (0, _helpers.getWindowFromNode)(element).getComputedStyle;
|
||||
|
||||
for (; element && element.ownerDocument; element = element.parentNode) {
|
||||
const display = getComputedStyle(element).display;
|
||||
|
||||
if (display === 'none') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function eventWrapper(cb) {
|
||||
let result;
|
||||
(0, _dom.getConfig)().eventWrapper(() => {
|
||||
result = cb();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function isValidDateValue(element, value) {
|
||||
if (element.type !== 'date') return false;
|
||||
const clone = element.cloneNode();
|
||||
clone.value = value;
|
||||
return clone.value === value;
|
||||
}
|
||||
|
||||
function buildTimeValue(value) {
|
||||
function build(onlyDigitsValue, index) {
|
||||
const hours = onlyDigitsValue.slice(0, index);
|
||||
const validHours = Math.min(parseInt(hours, 10), 23);
|
||||
const minuteCharacters = onlyDigitsValue.slice(index);
|
||||
const parsedMinutes = parseInt(minuteCharacters, 10);
|
||||
const validMinutes = Math.min(parsedMinutes, 59);
|
||||
return `${validHours.toString().padStart(2, '0')}:${validMinutes.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
const onlyDigitsValue = value.replace(/\D/g, '');
|
||||
|
||||
if (onlyDigitsValue.length < 2) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const firstDigit = parseInt(onlyDigitsValue[0], 10);
|
||||
const secondDigit = parseInt(onlyDigitsValue[1], 10);
|
||||
|
||||
if (firstDigit >= 3 || firstDigit === 2 && secondDigit >= 4) {
|
||||
let index;
|
||||
|
||||
if (firstDigit >= 3) {
|
||||
index = 1;
|
||||
} else {
|
||||
index = 2;
|
||||
}
|
||||
|
||||
return build(onlyDigitsValue, index);
|
||||
}
|
||||
|
||||
if (value.length === 2) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return build(onlyDigitsValue, 2);
|
||||
}
|
||||
|
||||
function isValidInputTimeValue(element, timeValue) {
|
||||
if (element.type !== 'time') return false;
|
||||
const clone = element.cloneNode();
|
||||
clone.value = timeValue;
|
||||
return clone.value === timeValue;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue