Upload folder using huggingface_hub (part 12)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- node_modules/@tanstack/virtual-core/LICENSE +21 -0
- node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js +34 -0
- node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js.map +1 -0
- node_modules/@tanstack/virtual-core/dist/esm/utils.d.ts +15 -0
- node_modules/@tanstack/virtual-core/dist/esm/utils.js +74 -0
- node_modules/@tanstack/virtual-core/dist/esm/utils.js.map +1 -0
- node_modules/@tanstack/virtual-core/package.json +56 -0
- node_modules/@tanstack/virtual-core/src/index.ts +2093 -0
- node_modules/@tanstack/virtual-core/src/lazy-measurements.ts +44 -0
- node_modules/@tanstack/virtual-core/src/utils.ts +109 -0
- node_modules/@testing-library/dom/LICENSE +20 -0
- node_modules/@testing-library/dom/README.md +402 -0
- node_modules/@testing-library/dom/dist/@testing-library/dom.cjs.js +0 -0
- node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js +2848 -0
- node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js +0 -0
- node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js.map +0 -0
- node_modules/@testing-library/dom/dist/@testing-library/dom.umd.min.js +0 -0
- node_modules/@testing-library/dom/dist/@testing-library/dom.umd.min.js.map +0 -0
- node_modules/@testing-library/dom/dist/DOMElementFilter.js +116 -0
- node_modules/@testing-library/dom/dist/config.js +67 -0
- node_modules/@testing-library/dom/dist/event-map.js +711 -0
- node_modules/@testing-library/dom/dist/events.js +140 -0
- node_modules/@testing-library/dom/dist/get-node-text.js +13 -0
- node_modules/@testing-library/dom/dist/get-queries-for-element.js +25 -0
- node_modules/@testing-library/dom/dist/get-user-code-frame.js +55 -0
- node_modules/@testing-library/dom/dist/helpers.js +69 -0
- node_modules/@testing-library/dom/dist/index.js +185 -0
- node_modules/@testing-library/dom/dist/label-helpers.js +64 -0
- node_modules/@testing-library/dom/dist/matches.js +92 -0
- node_modules/@testing-library/dom/dist/pretty-dom.js +96 -0
- node_modules/@testing-library/dom/dist/queries/all-utils.js +49 -0
- node_modules/@testing-library/dom/dist/queries/alt-text.js +24 -0
- node_modules/@testing-library/dom/dist/queries/display-value.js +40 -0
- node_modules/@testing-library/dom/dist/queries/index.js +93 -0
- node_modules/@testing-library/dom/dist/queries/label-text.js +133 -0
- node_modules/@testing-library/dom/dist/queries/placeholder-text.js +22 -0
- node_modules/@testing-library/dom/dist/queries/role.js +274 -0
- node_modules/@testing-library/dom/dist/queries/test-id.js +23 -0
- node_modules/@testing-library/dom/dist/queries/text.js +57 -0
- node_modules/@testing-library/dom/dist/queries/title.js +34 -0
- node_modules/@testing-library/dom/dist/query-helpers.js +141 -0
- node_modules/@testing-library/dom/dist/role-helpers.js +355 -0
- node_modules/@testing-library/dom/dist/screen.js +57 -0
- node_modules/@testing-library/dom/dist/suggestions.js +118 -0
- node_modules/@testing-library/dom/dist/wait-for-element-to-be-removed.js +52 -0
- node_modules/@testing-library/dom/dist/wait-for.js +173 -0
- node_modules/@testing-library/dom/package.json +120 -0
- node_modules/@testing-library/dom/types/config.d.ts +27 -0
- node_modules/@testing-library/dom/types/events.d.ts +118 -0
- node_modules/@testing-library/dom/types/get-node-text.d.ts +1 -0
node_modules/@tanstack/virtual-core/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2021-present Tanner Linsley
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function createLazyMeasurementsView(count, flat, getItemKey) {
|
| 2 |
+
const cache = new Array(count);
|
| 3 |
+
return new Proxy(cache, {
|
| 4 |
+
get(target, prop, receiver) {
|
| 5 |
+
if (typeof prop === "string") {
|
| 6 |
+
const c = prop.charCodeAt(0);
|
| 7 |
+
if (c >= 48 && c <= 57) {
|
| 8 |
+
const i = +prop;
|
| 9 |
+
if (Number.isInteger(i) && i >= 0 && i < count) {
|
| 10 |
+
let v = target[i];
|
| 11 |
+
if (!v) {
|
| 12 |
+
const s = flat[i * 2];
|
| 13 |
+
v = target[i] = {
|
| 14 |
+
index: i,
|
| 15 |
+
key: getItemKey(i),
|
| 16 |
+
start: s,
|
| 17 |
+
size: flat[i * 2 + 1],
|
| 18 |
+
end: s + flat[i * 2 + 1],
|
| 19 |
+
lane: 0
|
| 20 |
+
};
|
| 21 |
+
}
|
| 22 |
+
return v;
|
| 23 |
+
}
|
| 24 |
+
}
|
| 25 |
+
if (prop === "length") return count;
|
| 26 |
+
}
|
| 27 |
+
return Reflect.get(target, prop, receiver);
|
| 28 |
+
}
|
| 29 |
+
});
|
| 30 |
+
}
|
| 31 |
+
export {
|
| 32 |
+
createLazyMeasurementsView
|
| 33 |
+
};
|
| 34 |
+
//# sourceMappingURL=lazy-measurements.js.map
|
node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"version":3,"file":"lazy-measurements.js","sources":["../../src/lazy-measurements.ts"],"sourcesContent":["// Lazy materialization for the lanes===1 fast path. Backed by a\n// Float64Array (stride 2: start, size, …); VirtualItems are constructed on\n// first indexed read and cached. Saves the per-item object allocation at\n// large list counts where most items are never visible.\n\nimport type { VirtualItem } from './index'\n\ntype Key = number | string | bigint\n\nexport function createLazyMeasurementsView(\n count: number,\n flat: Float64Array,\n getItemKey: (i: number) => Key,\n): Array<VirtualItem> {\n const cache: Array<VirtualItem | undefined> = new Array(count)\n return new Proxy(cache as any, {\n get(target, prop, receiver) {\n if (typeof prop === 'string') {\n // Cheap digit-prefix sniff before number coerce.\n const c = prop.charCodeAt(0)\n if (c >= 48 && c <= 57) {\n const i = +prop\n if (Number.isInteger(i) && i >= 0 && i < count) {\n let v = target[i]\n if (!v) {\n const s = flat[i * 2]!\n v = target[i] = {\n index: i,\n key: getItemKey(i),\n start: s,\n size: flat[i * 2 + 1]!,\n end: s + flat[i * 2 + 1]!,\n lane: 0,\n }\n }\n return v\n }\n }\n if (prop === 'length') return count\n }\n return Reflect.get(target, prop, receiver)\n },\n }) as Array<VirtualItem>\n}\n"],"names":[],"mappings":"AASO,SAAS,2BACd,OACA,MACA,YACoB;AACpB,QAAM,QAAwC,IAAI,MAAM,KAAK;AAC7D,SAAO,IAAI,MAAM,OAAc;AAAA,IAC7B,IAAI,QAAQ,MAAM,UAAU;AAC1B,UAAI,OAAO,SAAS,UAAU;AAE5B,cAAM,IAAI,KAAK,WAAW,CAAC;AAC3B,YAAI,KAAK,MAAM,KAAK,IAAI;AACtB,gBAAM,IAAI,CAAC;AACX,cAAI,OAAO,UAAU,CAAC,KAAK,KAAK,KAAK,IAAI,OAAO;AAC9C,gBAAI,IAAI,OAAO,CAAC;AAChB,gBAAI,CAAC,GAAG;AACN,oBAAM,IAAI,KAAK,IAAI,CAAC;AACpB,kBAAI,OAAO,CAAC,IAAI;AAAA,gBACd,OAAO;AAAA,gBACP,KAAK,WAAW,CAAC;AAAA,gBACjB,OAAO;AAAA,gBACP,MAAM,KAAK,IAAI,IAAI,CAAC;AAAA,gBACpB,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC;AAAA,gBACvB,MAAM;AAAA,cAAA;AAAA,YAEV;AACA,mBAAO;AAAA,UACT;AAAA,QACF;AACA,YAAI,SAAS,SAAU,QAAO;AAAA,MAChC;AACA,aAAO,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAAA,IAC3C;AAAA,EAAA,CACD;AACH;"}
|
node_modules/@tanstack/virtual-core/dist/esm/utils.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export type NoInfer<A extends any> = [A][A extends any ? 0 : never];
|
| 2 |
+
export type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
| 3 |
+
export declare function memo<TDeps extends ReadonlyArray<any>, TResult>(getDeps: () => [...TDeps], fn: (...args: NoInfer<[...TDeps]>) => TResult, opts: {
|
| 4 |
+
key: false | string;
|
| 5 |
+
debug?: () => boolean;
|
| 6 |
+
onChange?: (result: TResult) => void;
|
| 7 |
+
initialDeps?: TDeps;
|
| 8 |
+
skipInitialOnChange?: boolean;
|
| 9 |
+
}): {
|
| 10 |
+
(): TResult;
|
| 11 |
+
updateDeps(newDeps: [...TDeps]): void;
|
| 12 |
+
};
|
| 13 |
+
export declare function notUndefined<T>(value: T | undefined, msg?: string): T;
|
| 14 |
+
export declare const approxEqual: (a: number, b: number) => boolean;
|
| 15 |
+
export declare const debounce: (targetWindow: Window & typeof globalThis, fn: Function, ms: number) => (this: any, ...args: Array<any>) => void;
|
node_modules/@tanstack/virtual-core/dist/esm/utils.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function memo(getDeps, fn, opts) {
|
| 2 |
+
let deps = opts.initialDeps ?? [];
|
| 3 |
+
let result;
|
| 4 |
+
let isInitial = true;
|
| 5 |
+
function memoizedFunction() {
|
| 6 |
+
var _a;
|
| 7 |
+
const debugEnabled = process.env.NODE_ENV !== "production" && !!opts.key && !!((_a = opts.debug) == null ? void 0 : _a.call(opts));
|
| 8 |
+
let depTime = 0;
|
| 9 |
+
if (debugEnabled) depTime = Date.now();
|
| 10 |
+
const newDeps = getDeps();
|
| 11 |
+
const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
|
| 12 |
+
if (!depsChanged) {
|
| 13 |
+
return result;
|
| 14 |
+
}
|
| 15 |
+
deps = newDeps;
|
| 16 |
+
let resultTime = 0;
|
| 17 |
+
if (debugEnabled) resultTime = Date.now();
|
| 18 |
+
result = fn(...newDeps);
|
| 19 |
+
if (debugEnabled) {
|
| 20 |
+
const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
|
| 21 |
+
const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
|
| 22 |
+
const resultFpsPercentage = resultEndTime / 16;
|
| 23 |
+
const pad = (str, num) => {
|
| 24 |
+
str = String(str);
|
| 25 |
+
while (str.length < num) {
|
| 26 |
+
str = " " + str;
|
| 27 |
+
}
|
| 28 |
+
return str;
|
| 29 |
+
};
|
| 30 |
+
console.info(
|
| 31 |
+
`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,
|
| 32 |
+
`
|
| 33 |
+
font-size: .6rem;
|
| 34 |
+
font-weight: bold;
|
| 35 |
+
color: hsl(${Math.max(
|
| 36 |
+
0,
|
| 37 |
+
Math.min(120 - 120 * resultFpsPercentage, 120)
|
| 38 |
+
)}deg 100% 31%);`,
|
| 39 |
+
opts == null ? void 0 : opts.key
|
| 40 |
+
);
|
| 41 |
+
}
|
| 42 |
+
if ((opts == null ? void 0 : opts.onChange) && !(isInitial && opts.skipInitialOnChange)) {
|
| 43 |
+
opts.onChange(result);
|
| 44 |
+
}
|
| 45 |
+
isInitial = false;
|
| 46 |
+
return result;
|
| 47 |
+
}
|
| 48 |
+
memoizedFunction.updateDeps = (newDeps) => {
|
| 49 |
+
deps = newDeps;
|
| 50 |
+
};
|
| 51 |
+
return memoizedFunction;
|
| 52 |
+
}
|
| 53 |
+
function notUndefined(value, msg) {
|
| 54 |
+
if (value === void 0) {
|
| 55 |
+
throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ""}`);
|
| 56 |
+
} else {
|
| 57 |
+
return value;
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
const approxEqual = (a, b) => Math.abs(a - b) < 1.01;
|
| 61 |
+
const debounce = (targetWindow, fn, ms) => {
|
| 62 |
+
let timeoutId;
|
| 63 |
+
return function(...args) {
|
| 64 |
+
targetWindow.clearTimeout(timeoutId);
|
| 65 |
+
timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);
|
| 66 |
+
};
|
| 67 |
+
};
|
| 68 |
+
export {
|
| 69 |
+
approxEqual,
|
| 70 |
+
debounce,
|
| 71 |
+
memo,
|
| 72 |
+
notUndefined
|
| 73 |
+
};
|
| 74 |
+
//# sourceMappingURL=utils.js.map
|
node_modules/@tanstack/virtual-core/dist/esm/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends ReadonlyArray<any>, TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: false | string\n debug?: () => boolean\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n skipInitialOnChange?: boolean\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n let isInitial = true\n\n function memoizedFunction(): TResult {\n // Debug-only timing. In production builds, `process.env.NODE_ENV !==\n // 'production'` is constant-folded to `false` by downstream minifiers\n // (Terser/esbuild/swc with `define`), which DCEs the entire block.\n const debugEnabled =\n process.env.NODE_ENV !== 'production' && !!opts.key && !!opts.debug?.()\n let depTime = 0\n if (debugEnabled) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime = 0\n if (debugEnabled) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (debugEnabled) {\n const depEndTime = Math.round((Date.now() - depTime) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n if (opts?.onChange && !(isInitial && opts.skipInitialOnChange)) {\n opts.onChange(result)\n }\n\n isInitial = false\n\n return result\n }\n\n // Attach updateDeps to the function itself\n memoizedFunction.updateDeps = (newDeps: [...TDeps]) => {\n deps = newDeps\n }\n\n return memoizedFunction\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1.01\n\nexport const debounce = (\n targetWindow: Window & typeof globalThis,\n fn: Function,\n ms: number,\n) => {\n let timeoutId: number\n return function (this: any, ...args: Array<any>) {\n targetWindow.clearTimeout(timeoutId)\n timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms)\n }\n}\n"],"names":[],"mappings":"AAIO,SAAS,KACd,SACA,IACA,MAOA;AACA,MAAI,OAAO,KAAK,eAAe,CAAA;AAC/B,MAAI;AACJ,MAAI,YAAY;AAEhB,WAAS,mBAA4B;AAfhC;AAmBH,UAAM,eACJ,QAAQ,IAAI,aAAa,gBAAgB,CAAC,CAAC,KAAK,OAAO,CAAC,GAAC,UAAK,UAAL;AAC3D,QAAI,UAAU;AACd,QAAI,aAAc,WAAU,KAAK,IAAA;AAEjC,UAAM,UAAU,QAAA;AAEhB,UAAM,cACJ,QAAQ,WAAW,KAAK,UACxB,QAAQ,KAAK,CAAC,KAAU,UAAkB,KAAK,KAAK,MAAM,GAAG;AAE/D,QAAI,CAAC,aAAa;AAChB,aAAO;AAAA,IACT;AAEA,WAAO;AAEP,QAAI,aAAa;AACjB,QAAI,aAAc,cAAa,KAAK,IAAA;AAEpC,aAAS,GAAG,GAAG,OAAO;AAEtB,QAAI,cAAc;AAChB,YAAM,aAAa,KAAK,OAAO,KAAK,QAAQ,WAAW,GAAG,IAAI;AAC9D,YAAM,gBAAgB,KAAK,OAAO,KAAK,QAAQ,cAAc,GAAG,IAAI;AACpE,YAAM,sBAAsB,gBAAgB;AAE5C,YAAM,MAAM,CAAC,KAAsB,QAAgB;AACjD,cAAM,OAAO,GAAG;AAChB,eAAO,IAAI,SAAS,KAAK;AACvB,gBAAM,MAAM;AAAA,QACd;AACA,eAAO;AAAA,MACT;AAEA,cAAQ;AAAA,QACN,OAAO,IAAI,eAAe,CAAC,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;AAAA,QACnD;AAAA;AAAA;AAAA,yBAGiB,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,IAAI,MAAM,MAAM,qBAAqB,GAAG;AAAA,QAAA,CAC9C;AAAA,QACL,6BAAM;AAAA,MAAA;AAAA,IAEV;AAEA,SAAI,6BAAM,aAAY,EAAE,aAAa,KAAK,sBAAsB;AAC9D,WAAK,SAAS,MAAM;AAAA,IACtB;AAEA,gBAAY;AAEZ,WAAO;AAAA,EACT;AAGA,mBAAiB,aAAa,CAAC,YAAwB;AACrD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,aAAgB,OAAsB,KAAiB;AACrE,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI,MAAM,uBAAuB,MAAM,KAAK,GAAG,KAAK,EAAE,EAAE;AAAA,EAChE,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEO,MAAM,cAAc,CAAC,GAAW,MAAc,KAAK,IAAI,IAAI,CAAC,IAAI;AAEhE,MAAM,WAAW,CACtB,cACA,IACA,OACG;AACH,MAAI;AACJ,SAAO,YAAwB,MAAkB;AAC/C,iBAAa,aAAa,SAAS;AACnC,gBAAY,aAAa,WAAW,MAAM,GAAG,MAAM,MAAM,IAAI,GAAG,EAAE;AAAA,EACpE;AACF;"}
|
node_modules/@tanstack/virtual-core/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "@tanstack/virtual-core",
|
| 3 |
+
"version": "3.17.7",
|
| 4 |
+
"description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
|
| 5 |
+
"author": "Tanner Linsley",
|
| 6 |
+
"license": "MIT",
|
| 7 |
+
"repository": {
|
| 8 |
+
"type": "git",
|
| 9 |
+
"url": "git+https://github.com/TanStack/virtual.git",
|
| 10 |
+
"directory": "packages/virtual-core"
|
| 11 |
+
},
|
| 12 |
+
"homepage": "https://tanstack.com/virtual",
|
| 13 |
+
"funding": {
|
| 14 |
+
"type": "github",
|
| 15 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
| 16 |
+
},
|
| 17 |
+
"keywords": [
|
| 18 |
+
"react",
|
| 19 |
+
"vue",
|
| 20 |
+
"solid",
|
| 21 |
+
"virtual",
|
| 22 |
+
"virtual-core",
|
| 23 |
+
"datagrid"
|
| 24 |
+
],
|
| 25 |
+
"type": "module",
|
| 26 |
+
"types": "dist/esm/index.d.ts",
|
| 27 |
+
"main": "dist/cjs/index.cjs",
|
| 28 |
+
"module": "dist/esm/index.js",
|
| 29 |
+
"exports": {
|
| 30 |
+
".": {
|
| 31 |
+
"import": {
|
| 32 |
+
"types": "./dist/esm/index.d.ts",
|
| 33 |
+
"default": "./dist/esm/index.js"
|
| 34 |
+
},
|
| 35 |
+
"require": {
|
| 36 |
+
"types": "./dist/cjs/index.d.cts",
|
| 37 |
+
"default": "./dist/cjs/index.cjs"
|
| 38 |
+
}
|
| 39 |
+
},
|
| 40 |
+
"./package.json": "./package.json"
|
| 41 |
+
},
|
| 42 |
+
"sideEffects": false,
|
| 43 |
+
"files": [
|
| 44 |
+
"dist",
|
| 45 |
+
"src"
|
| 46 |
+
],
|
| 47 |
+
"scripts": {
|
| 48 |
+
"clean": "premove ./dist ./coverage",
|
| 49 |
+
"test:eslint": "eslint ./src",
|
| 50 |
+
"test:types": "tsc",
|
| 51 |
+
"test:lib": "vitest",
|
| 52 |
+
"test:lib:dev": "pnpm run test:lib --watch",
|
| 53 |
+
"test:build": "publint --strict",
|
| 54 |
+
"build": "vite build"
|
| 55 |
+
}
|
| 56 |
+
}
|
node_modules/@tanstack/virtual-core/src/index.ts
ADDED
|
@@ -0,0 +1,2093 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { createLazyMeasurementsView } from './lazy-measurements'
|
| 2 |
+
import { approxEqual, debounce, memo, notUndefined } from './utils'
|
| 3 |
+
|
| 4 |
+
// Browser-aware iOS detection. Programmatic `scrollTo`/`scrollTop` writes
|
| 5 |
+
// during a momentum-scroll cancel the momentum on iOS WebKit, so we defer
|
| 6 |
+
// scroll-position adjustments triggered by mid-scroll resizes until the
|
| 7 |
+
// scroll settles. SSR-safe (returns false when navigator is unavailable).
|
| 8 |
+
let _isIOSResult: boolean | undefined
|
| 9 |
+
const isIOSWebKit = (): boolean => {
|
| 10 |
+
if (_isIOSResult !== undefined) return _isIOSResult
|
| 11 |
+
if (typeof navigator === 'undefined') return (_isIOSResult = false)
|
| 12 |
+
if (/iP(hone|od|ad)/.test(navigator.userAgent)) return (_isIOSResult = true)
|
| 13 |
+
// iPadOS 13+ reports as MacIntel; touch-points distinguishes it from desktop.
|
| 14 |
+
const mtp = (navigator as Navigator & { maxTouchPoints?: number })
|
| 15 |
+
.maxTouchPoints
|
| 16 |
+
return (_isIOSResult =
|
| 17 |
+
navigator.platform === 'MacIntel' && mtp !== undefined && mtp > 0)
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
// Test hook: reset the iOS detection cache. Not exported.
|
| 21 |
+
export const _resetIOSDetectionForTests = () => {
|
| 22 |
+
_isIOSResult = undefined
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
export { approxEqual, debounce, memo, notUndefined } from './utils'
|
| 26 |
+
export type { NoInfer, PartialKeys } from './utils'
|
| 27 |
+
|
| 28 |
+
//
|
| 29 |
+
|
| 30 |
+
type ScrollDirection = 'forward' | 'backward'
|
| 31 |
+
|
| 32 |
+
type ScrollAlignment = 'start' | 'center' | 'end' | 'auto'
|
| 33 |
+
|
| 34 |
+
type ScrollBehavior = 'auto' | 'smooth' | 'instant'
|
| 35 |
+
|
| 36 |
+
type ScrollAnchor = 'start' | 'end'
|
| 37 |
+
|
| 38 |
+
type FollowOnAppend = boolean | ScrollBehavior
|
| 39 |
+
|
| 40 |
+
export interface ScrollToOptions {
|
| 41 |
+
align?: ScrollAlignment
|
| 42 |
+
behavior?: ScrollBehavior
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
type ScrollToOffsetOptions = ScrollToOptions
|
| 46 |
+
|
| 47 |
+
type ScrollToIndexOptions = ScrollToOptions
|
| 48 |
+
|
| 49 |
+
type ScrollToEndOptions = Pick<ScrollToOptions, 'behavior'>
|
| 50 |
+
|
| 51 |
+
export interface Range {
|
| 52 |
+
startIndex: number
|
| 53 |
+
endIndex: number
|
| 54 |
+
overscan: number
|
| 55 |
+
count: number
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
type Key = number | string | bigint
|
| 59 |
+
|
| 60 |
+
export interface VirtualItem {
|
| 61 |
+
key: Key
|
| 62 |
+
index: number
|
| 63 |
+
start: number
|
| 64 |
+
end: number
|
| 65 |
+
size: number
|
| 66 |
+
lane: number
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
export interface Rect {
|
| 70 |
+
width: number
|
| 71 |
+
height: number
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
//
|
| 75 |
+
|
| 76 |
+
const getRect = (element: HTMLElement): Rect => {
|
| 77 |
+
const { offsetWidth, offsetHeight } = element
|
| 78 |
+
return { width: offsetWidth, height: offsetHeight }
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
export const defaultKeyExtractor = (index: number) => index
|
| 82 |
+
|
| 83 |
+
export const defaultRangeExtractor = (range: Range) => {
|
| 84 |
+
const start = Math.max(range.startIndex - range.overscan, 0)
|
| 85 |
+
const end = Math.min(range.endIndex + range.overscan, range.count - 1)
|
| 86 |
+
const len = end - start + 1
|
| 87 |
+
|
| 88 |
+
const arr = new Array<number>(len)
|
| 89 |
+
for (let i = 0; i < len; i++) {
|
| 90 |
+
arr[i] = start + i
|
| 91 |
+
}
|
| 92 |
+
return arr
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
export const observeElementRect = <T extends Element>(
|
| 96 |
+
instance: Virtualizer<T, any>,
|
| 97 |
+
cb: (rect: Rect) => void,
|
| 98 |
+
) => {
|
| 99 |
+
const element = instance.scrollElement
|
| 100 |
+
if (!element) {
|
| 101 |
+
return
|
| 102 |
+
}
|
| 103 |
+
const targetWindow = instance.targetWindow
|
| 104 |
+
if (!targetWindow) {
|
| 105 |
+
return
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
const handler = (rect: Rect) => {
|
| 109 |
+
const { width, height } = rect
|
| 110 |
+
cb({ width: Math.round(width), height: Math.round(height) })
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
handler(getRect(element as unknown as HTMLElement))
|
| 114 |
+
|
| 115 |
+
if (!targetWindow.ResizeObserver) {
|
| 116 |
+
return () => {}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
const observer = new targetWindow.ResizeObserver((entries) => {
|
| 120 |
+
const run = () => {
|
| 121 |
+
const entry = entries[0]
|
| 122 |
+
if (entry?.borderBoxSize) {
|
| 123 |
+
const box = entry.borderBoxSize[0]
|
| 124 |
+
if (box) {
|
| 125 |
+
handler({ width: box.inlineSize, height: box.blockSize })
|
| 126 |
+
return
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
handler(getRect(element as unknown as HTMLElement))
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
instance.options.useAnimationFrameWithResizeObserver
|
| 133 |
+
? requestAnimationFrame(run)
|
| 134 |
+
: run()
|
| 135 |
+
})
|
| 136 |
+
|
| 137 |
+
observer.observe(element, { box: 'border-box' })
|
| 138 |
+
|
| 139 |
+
return () => {
|
| 140 |
+
observer.unobserve(element)
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
const addEventListenerOptions = {
|
| 145 |
+
passive: true,
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
export const observeWindowRect = (
|
| 149 |
+
instance: Virtualizer<Window, any>,
|
| 150 |
+
cb: (rect: Rect) => void,
|
| 151 |
+
) => {
|
| 152 |
+
const element = instance.scrollElement
|
| 153 |
+
if (!element) {
|
| 154 |
+
return
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
const handler = () => {
|
| 158 |
+
cb({ width: element.innerWidth, height: element.innerHeight })
|
| 159 |
+
}
|
| 160 |
+
handler()
|
| 161 |
+
|
| 162 |
+
element.addEventListener('resize', handler, addEventListenerOptions)
|
| 163 |
+
|
| 164 |
+
return () => {
|
| 165 |
+
element.removeEventListener('resize', handler)
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
const supportsScrollend =
|
| 170 |
+
typeof window == 'undefined' ? true : 'onscrollend' in window
|
| 171 |
+
|
| 172 |
+
type ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void
|
| 173 |
+
|
| 174 |
+
// Shared core: both element and window variants attach scroll/scrollend
|
| 175 |
+
// listeners with the same lifecycle; they only differ in how to read the
|
| 176 |
+
// current offset from the scroll target.
|
| 177 |
+
const observeOffset = <T extends Element | Window>(
|
| 178 |
+
instance: Virtualizer<T, any>,
|
| 179 |
+
cb: ObserveOffsetCallBack,
|
| 180 |
+
readOffset: (target: T) => number,
|
| 181 |
+
) => {
|
| 182 |
+
const element = instance.scrollElement
|
| 183 |
+
if (!element) {
|
| 184 |
+
return
|
| 185 |
+
}
|
| 186 |
+
const targetWindow = instance.targetWindow
|
| 187 |
+
if (!targetWindow) {
|
| 188 |
+
return
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
const registerScrollendEvent =
|
| 192 |
+
instance.options.useScrollendEvent && supportsScrollend
|
| 193 |
+
|
| 194 |
+
let offset = 0
|
| 195 |
+
const fallback = registerScrollendEvent
|
| 196 |
+
? null
|
| 197 |
+
: debounce(
|
| 198 |
+
targetWindow,
|
| 199 |
+
() => cb(offset, false),
|
| 200 |
+
instance.options.isScrollingResetDelay,
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
const createHandler = (isScrolling: boolean) => () => {
|
| 204 |
+
offset = readOffset(element)
|
| 205 |
+
fallback?.()
|
| 206 |
+
cb(offset, isScrolling)
|
| 207 |
+
}
|
| 208 |
+
const handler = createHandler(true)
|
| 209 |
+
const endHandler = createHandler(false)
|
| 210 |
+
|
| 211 |
+
element.addEventListener('scroll', handler, addEventListenerOptions)
|
| 212 |
+
if (registerScrollendEvent) {
|
| 213 |
+
element.addEventListener('scrollend', endHandler, addEventListenerOptions)
|
| 214 |
+
}
|
| 215 |
+
return () => {
|
| 216 |
+
element.removeEventListener('scroll', handler)
|
| 217 |
+
if (registerScrollendEvent) {
|
| 218 |
+
element.removeEventListener('scrollend', endHandler)
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
export const observeElementOffset = <T extends Element>(
|
| 224 |
+
instance: Virtualizer<T, any>,
|
| 225 |
+
cb: ObserveOffsetCallBack,
|
| 226 |
+
) =>
|
| 227 |
+
observeOffset(instance, cb, (el) => {
|
| 228 |
+
const { horizontal, isRtl } = instance.options
|
| 229 |
+
return horizontal ? el.scrollLeft * ((isRtl && -1) || 1) : el.scrollTop
|
| 230 |
+
})
|
| 231 |
+
|
| 232 |
+
export const observeWindowOffset = (
|
| 233 |
+
instance: Virtualizer<Window, any>,
|
| 234 |
+
cb: ObserveOffsetCallBack,
|
| 235 |
+
) =>
|
| 236 |
+
observeOffset(instance, cb, (win) =>
|
| 237 |
+
instance.options.horizontal ? win.scrollX : win.scrollY,
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
export const measureElement = <TItemElement extends Element>(
|
| 241 |
+
element: TItemElement,
|
| 242 |
+
entry: ResizeObserverEntry | undefined,
|
| 243 |
+
instance: Virtualizer<any, TItemElement>,
|
| 244 |
+
) => {
|
| 245 |
+
// When useCachedMeasurements is enabled, return the cached size
|
| 246 |
+
// (or estimateSize as fallback) instead of measuring the DOM.
|
| 247 |
+
if (instance.options.useCachedMeasurements) {
|
| 248 |
+
const index = instance.indexFromElement(element)
|
| 249 |
+
const key = instance.options.getItemKey(index)
|
| 250 |
+
return (
|
| 251 |
+
instance.itemSizeCache.get(key) ?? instance.options.estimateSize(index)
|
| 252 |
+
)
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
if (entry?.borderBoxSize) {
|
| 256 |
+
const box = entry.borderBoxSize[0]
|
| 257 |
+
if (box) {
|
| 258 |
+
const size = Math.round(
|
| 259 |
+
box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],
|
| 260 |
+
)
|
| 261 |
+
return size
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
// When called without a ResizeObserverEntry (sync measurement path),
|
| 266 |
+
// return the previously measured size if available. This avoids a
|
| 267 |
+
// synchronous layout read (offsetWidth/offsetHeight) on re-renders.
|
| 268 |
+
// The ResizeObserver is already observing the element and will deliver
|
| 269 |
+
// the accurate size asynchronously if it changed.
|
| 270 |
+
// Users who need synchronous DOM reads can provide a custom measureElement.
|
| 271 |
+
if (!entry) {
|
| 272 |
+
const index = instance.indexFromElement(element)
|
| 273 |
+
const key = instance.options.getItemKey(index)
|
| 274 |
+
const cachedSize = instance.itemSizeCache.get(key)
|
| 275 |
+
if (cachedSize !== undefined) {
|
| 276 |
+
return cachedSize
|
| 277 |
+
}
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
return (element as unknown as HTMLElement)[
|
| 281 |
+
instance.options.horizontal ? 'offsetWidth' : 'offsetHeight'
|
| 282 |
+
]
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
const scrollWithAdjustments = (
|
| 286 |
+
offset: number,
|
| 287 |
+
{
|
| 288 |
+
adjustments = 0,
|
| 289 |
+
behavior,
|
| 290 |
+
}: { adjustments?: number; behavior?: ScrollBehavior },
|
| 291 |
+
instance: Virtualizer<any, any>,
|
| 292 |
+
) => {
|
| 293 |
+
instance.scrollElement?.scrollTo?.({
|
| 294 |
+
[instance.options.horizontal ? 'left' : 'top']: offset + adjustments,
|
| 295 |
+
behavior,
|
| 296 |
+
})
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
export const windowScroll: <T extends Window>(
|
| 300 |
+
offset: number,
|
| 301 |
+
options: { adjustments?: number; behavior?: ScrollBehavior },
|
| 302 |
+
instance: Virtualizer<T, any>,
|
| 303 |
+
) => void = scrollWithAdjustments
|
| 304 |
+
|
| 305 |
+
export const elementScroll: <T extends Element>(
|
| 306 |
+
offset: number,
|
| 307 |
+
options: { adjustments?: number; behavior?: ScrollBehavior },
|
| 308 |
+
instance: Virtualizer<T, any>,
|
| 309 |
+
) => void = scrollWithAdjustments
|
| 310 |
+
|
| 311 |
+
type LaneAssignmentMode = 'estimate' | 'measured'
|
| 312 |
+
|
| 313 |
+
export interface VirtualizerOptions<
|
| 314 |
+
TScrollElement extends Element | Window,
|
| 315 |
+
TItemElement extends Element,
|
| 316 |
+
> {
|
| 317 |
+
// Required from the user
|
| 318 |
+
count: number
|
| 319 |
+
getScrollElement: () => TScrollElement | null
|
| 320 |
+
estimateSize: (index: number) => number
|
| 321 |
+
|
| 322 |
+
// Required from the framework adapter (but can be overridden)
|
| 323 |
+
scrollToFn: (
|
| 324 |
+
offset: number,
|
| 325 |
+
options: { adjustments?: number; behavior?: ScrollBehavior },
|
| 326 |
+
instance: Virtualizer<TScrollElement, TItemElement>,
|
| 327 |
+
) => void
|
| 328 |
+
observeElementRect: (
|
| 329 |
+
instance: Virtualizer<TScrollElement, TItemElement>,
|
| 330 |
+
cb: (rect: Rect) => void,
|
| 331 |
+
) => void | (() => void)
|
| 332 |
+
observeElementOffset: (
|
| 333 |
+
instance: Virtualizer<TScrollElement, TItemElement>,
|
| 334 |
+
cb: ObserveOffsetCallBack,
|
| 335 |
+
) => void | (() => void)
|
| 336 |
+
// Optional
|
| 337 |
+
debug?: boolean
|
| 338 |
+
initialRect?: Rect
|
| 339 |
+
onChange?: (
|
| 340 |
+
instance: Virtualizer<TScrollElement, TItemElement>,
|
| 341 |
+
sync: boolean,
|
| 342 |
+
) => void
|
| 343 |
+
measureElement?: (
|
| 344 |
+
element: TItemElement,
|
| 345 |
+
entry: ResizeObserverEntry | undefined,
|
| 346 |
+
instance: Virtualizer<TScrollElement, TItemElement>,
|
| 347 |
+
) => number
|
| 348 |
+
overscan?: number
|
| 349 |
+
horizontal?: boolean
|
| 350 |
+
paddingStart?: number
|
| 351 |
+
paddingEnd?: number
|
| 352 |
+
scrollPaddingStart?: number
|
| 353 |
+
scrollPaddingEnd?: number
|
| 354 |
+
initialOffset?: number | (() => number)
|
| 355 |
+
getItemKey?: (index: number) => Key
|
| 356 |
+
rangeExtractor?: (range: Range) => Array<number>
|
| 357 |
+
scrollMargin?: number
|
| 358 |
+
gap?: number
|
| 359 |
+
indexAttribute?: string
|
| 360 |
+
initialMeasurementsCache?: Array<VirtualItem>
|
| 361 |
+
lanes?: number
|
| 362 |
+
anchorTo?: ScrollAnchor
|
| 363 |
+
followOnAppend?: FollowOnAppend
|
| 364 |
+
scrollEndThreshold?: number
|
| 365 |
+
isScrollingResetDelay?: number
|
| 366 |
+
useScrollendEvent?: boolean
|
| 367 |
+
enabled?: boolean
|
| 368 |
+
isRtl?: boolean
|
| 369 |
+
useAnimationFrameWithResizeObserver?: boolean
|
| 370 |
+
laneAssignmentMode?: LaneAssignmentMode
|
| 371 |
+
useCachedMeasurements?: boolean
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
type ScrollState = {
|
| 375 |
+
// what we want
|
| 376 |
+
index: number | null
|
| 377 |
+
align: ScrollAlignment
|
| 378 |
+
behavior: ScrollBehavior
|
| 379 |
+
|
| 380 |
+
// lifecycle
|
| 381 |
+
startedAt: number
|
| 382 |
+
|
| 383 |
+
// target tracking
|
| 384 |
+
lastTargetOffset: number
|
| 385 |
+
|
| 386 |
+
// settling
|
| 387 |
+
stableFrames: number
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
type PendingScrollAnchor = [
|
| 391 |
+
key: Key | null,
|
| 392 |
+
offset: number,
|
| 393 |
+
followOnAppend: ScrollBehavior | null,
|
| 394 |
+
anchorDelta: number,
|
| 395 |
+
]
|
| 396 |
+
|
| 397 |
+
export class Virtualizer<
|
| 398 |
+
TScrollElement extends Element | Window,
|
| 399 |
+
TItemElement extends Element,
|
| 400 |
+
> {
|
| 401 |
+
private unsubs: Array<void | (() => void)> = []
|
| 402 |
+
options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>
|
| 403 |
+
scrollElement: TScrollElement | null = null
|
| 404 |
+
targetWindow: (Window & typeof globalThis) | null = null
|
| 405 |
+
isScrolling = false
|
| 406 |
+
private scrollState: ScrollState | null = null
|
| 407 |
+
measurementsCache: Array<VirtualItem> = []
|
| 408 |
+
// Flat backing store for the lanes===1 fast path: [start_0, size_0, start_1, size_1, ...].
|
| 409 |
+
// null until the first single-lane build; reused (and grown) across rebuilds.
|
| 410 |
+
private _flatMeasurements: Float64Array | null = null
|
| 411 |
+
itemSizeCache = new Map<Key, number>()
|
| 412 |
+
private itemSizeCacheVersion = 0
|
| 413 |
+
private laneAssignments = new Map<number, number>() // index → lane cache
|
| 414 |
+
// Earliest index dirtied since last getMeasurements() rebuild, or null.
|
| 415 |
+
private pendingMin: number | null = null
|
| 416 |
+
private prevLanes: number | undefined = undefined
|
| 417 |
+
private lanesChangedFlag = false
|
| 418 |
+
private lanesSettling = false
|
| 419 |
+
private pendingScrollAnchor: PendingScrollAnchor | null = null
|
| 420 |
+
scrollRect: Rect | null = null
|
| 421 |
+
scrollOffset: number | null = null
|
| 422 |
+
scrollDirection: ScrollDirection | null = null
|
| 423 |
+
scrollAdjustments = 0
|
| 424 |
+
// Sum of size-change deltas above-viewport that were skipped during
|
| 425 |
+
// iOS momentum scroll (writing scrollTop mid-momentum cancels it).
|
| 426 |
+
// Flushed in a single scrollTo when iOS is fully settled.
|
| 427 |
+
private _iosDeferredAdjustment = 0
|
| 428 |
+
// Touch state. iOS WebKit cancels momentum when scrollTop is written, so
|
| 429 |
+
// we defer adjustments not only during `isScrolling` but also through the
|
| 430 |
+
// touchstart→touchend window (active drag) and a short tail after
|
| 431 |
+
// touchend (early-momentum window — iOS only fires touch events once at
|
| 432 |
+
// the start of momentum, so we use a timer rather than another event).
|
| 433 |
+
private _iosTouching = false
|
| 434 |
+
private _iosJustTouchEnded = false
|
| 435 |
+
private _iosTouchEndTimerId: number | null = null
|
| 436 |
+
// Subpixel reconciliation. Safari (and Chrome/Firefox under certain DPRs)
|
| 437 |
+
// round scrollTop/scrollLeft writes to integer pixels. If we wrote 12345.5
|
| 438 |
+
// but the browser reports back 12346, the next reconcileScroll sees a
|
| 439 |
+
// "target changed" and re-fires scrollTo — a feedback loop that the
|
| 440 |
+
// approxEqual(<1.01) tolerance otherwise absorbs as a workaround.
|
| 441 |
+
// By remembering the intended value of our most-recent self-driven
|
| 442 |
+
// scrollTo, we can match the browser's rounded read back to the intended
|
| 443 |
+
// value when the diff is < 1.5 px, distinguishing it from a real user
|
| 444 |
+
// scroll. The +0.5 over Math.abs lets us also absorb the +1 / -1 cases.
|
| 445 |
+
private _intendedScrollOffset: number | null = null
|
| 446 |
+
shouldAdjustScrollPositionOnItemSizeChange:
|
| 447 |
+
| undefined
|
| 448 |
+
| ((
|
| 449 |
+
item: VirtualItem,
|
| 450 |
+
delta: number,
|
| 451 |
+
instance: Virtualizer<TScrollElement, TItemElement>,
|
| 452 |
+
) => boolean)
|
| 453 |
+
elementsCache = new Map<Key, TItemElement>()
|
| 454 |
+
private now = () => this.targetWindow?.performance?.now?.() ?? Date.now()
|
| 455 |
+
private observer = (() => {
|
| 456 |
+
let _ro: ResizeObserver | null = null
|
| 457 |
+
|
| 458 |
+
const get = () => {
|
| 459 |
+
if (_ro) {
|
| 460 |
+
return _ro
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
if (!this.targetWindow || !this.targetWindow.ResizeObserver) {
|
| 464 |
+
return null
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
return (_ro = new this.targetWindow.ResizeObserver((entries) => {
|
| 468 |
+
entries.forEach((entry) => {
|
| 469 |
+
const run = () => {
|
| 470 |
+
const node = entry.target as TItemElement
|
| 471 |
+
const index = this.indexFromElement(node)
|
| 472 |
+
|
| 473 |
+
if (!node.isConnected) {
|
| 474 |
+
this.observer.unobserve(node)
|
| 475 |
+
// Find the cache entry pointing to this exact node and remove
|
| 476 |
+
// it. We can't call getItemKey(index) here because items may
|
| 477 |
+
// have been removed since this node was rendered — the index
|
| 478 |
+
// could be stale and out-of-bounds in the user's data array
|
| 479 |
+
// (regression test in e2e/.../stale-index.spec.ts, fix #1148).
|
| 480 |
+
// The === comparison naturally handles the React-replaced-
|
| 481 |
+
// a-node-for-the-same-key case: that entry now points to a
|
| 482 |
+
// different node, so this loop won't match.
|
| 483 |
+
for (const [cacheKey, cachedNode] of this.elementsCache) {
|
| 484 |
+
if (cachedNode === node) {
|
| 485 |
+
this.elementsCache.delete(cacheKey)
|
| 486 |
+
break
|
| 487 |
+
}
|
| 488 |
+
}
|
| 489 |
+
return
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
if (this.shouldMeasureDuringScroll(index)) {
|
| 493 |
+
this.resizeItem(
|
| 494 |
+
index,
|
| 495 |
+
this.options.measureElement(node, entry, this),
|
| 496 |
+
)
|
| 497 |
+
}
|
| 498 |
+
}
|
| 499 |
+
this.options.useAnimationFrameWithResizeObserver
|
| 500 |
+
? requestAnimationFrame(run)
|
| 501 |
+
: run()
|
| 502 |
+
})
|
| 503 |
+
}))
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
return {
|
| 507 |
+
disconnect: () => {
|
| 508 |
+
get()?.disconnect()
|
| 509 |
+
_ro = null
|
| 510 |
+
},
|
| 511 |
+
observe: (target: Element) =>
|
| 512 |
+
get()?.observe(target, { box: 'border-box' }),
|
| 513 |
+
unobserve: (target: Element) => get()?.unobserve(target),
|
| 514 |
+
}
|
| 515 |
+
})()
|
| 516 |
+
range: { startIndex: number; endIndex: number } | null = null
|
| 517 |
+
|
| 518 |
+
constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {
|
| 519 |
+
this.setOptions(opts)
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {
|
| 523 |
+
// Skip `{...defaults, ...opts}` because explicit `undefined` values in
|
| 524 |
+
// opts would override defaults with `undefined`.
|
| 525 |
+
const merged = {
|
| 526 |
+
debug: false,
|
| 527 |
+
initialOffset: 0,
|
| 528 |
+
overscan: 1,
|
| 529 |
+
paddingStart: 0,
|
| 530 |
+
paddingEnd: 0,
|
| 531 |
+
scrollPaddingStart: 0,
|
| 532 |
+
scrollPaddingEnd: 0,
|
| 533 |
+
horizontal: false,
|
| 534 |
+
getItemKey: defaultKeyExtractor,
|
| 535 |
+
rangeExtractor: defaultRangeExtractor,
|
| 536 |
+
onChange: () => {},
|
| 537 |
+
measureElement,
|
| 538 |
+
initialRect: { width: 0, height: 0 },
|
| 539 |
+
scrollMargin: 0,
|
| 540 |
+
gap: 0,
|
| 541 |
+
indexAttribute: 'data-index',
|
| 542 |
+
initialMeasurementsCache: [],
|
| 543 |
+
lanes: 1,
|
| 544 |
+
anchorTo: 'start',
|
| 545 |
+
followOnAppend: false,
|
| 546 |
+
scrollEndThreshold: 1,
|
| 547 |
+
isScrollingResetDelay: 150,
|
| 548 |
+
enabled: true,
|
| 549 |
+
isRtl: false,
|
| 550 |
+
useScrollendEvent: false,
|
| 551 |
+
useAnimationFrameWithResizeObserver: false,
|
| 552 |
+
laneAssignmentMode: 'estimate',
|
| 553 |
+
useCachedMeasurements: false,
|
| 554 |
+
} as unknown as Required<VirtualizerOptions<TScrollElement, TItemElement>>
|
| 555 |
+
|
| 556 |
+
for (const key in opts) {
|
| 557 |
+
const v = (opts as any)[key]
|
| 558 |
+
if (v !== undefined) (merged as any)[key] = v
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
const prevOptions = this.options as
|
| 562 |
+
| Required<VirtualizerOptions<TScrollElement, TItemElement>>
|
| 563 |
+
| undefined
|
| 564 |
+
let anchor: [Key, number] | null = null
|
| 565 |
+
let followOnAppend: ScrollBehavior | null = null
|
| 566 |
+
let edgeKeysChanged = false
|
| 567 |
+
|
| 568 |
+
if (
|
| 569 |
+
prevOptions !== undefined &&
|
| 570 |
+
prevOptions.enabled &&
|
| 571 |
+
merged.enabled &&
|
| 572 |
+
merged.anchorTo === 'end' &&
|
| 573 |
+
this.scrollElement !== null
|
| 574 |
+
) {
|
| 575 |
+
const prevCount = prevOptions.count
|
| 576 |
+
const nextCount = merged.count
|
| 577 |
+
const measurements = this.getMeasurements()
|
| 578 |
+
const prevFirstKey =
|
| 579 |
+
prevCount > 0
|
| 580 |
+
? (measurements[0]?.key ?? prevOptions.getItemKey(0))
|
| 581 |
+
: null
|
| 582 |
+
const prevLastKey =
|
| 583 |
+
prevCount > 0
|
| 584 |
+
? (measurements[prevCount - 1]?.key ??
|
| 585 |
+
prevOptions.getItemKey(prevCount - 1))
|
| 586 |
+
: null
|
| 587 |
+
const didCountChange = nextCount !== prevCount
|
| 588 |
+
const didEdgeKeysChange =
|
| 589 |
+
didCountChange ||
|
| 590 |
+
(prevCount > 0 &&
|
| 591 |
+
nextCount > 0 &&
|
| 592 |
+
(merged.getItemKey(0) !== prevFirstKey ||
|
| 593 |
+
merged.getItemKey(nextCount - 1) !== prevLastKey))
|
| 594 |
+
|
| 595 |
+
if (didEdgeKeysChange) {
|
| 596 |
+
edgeKeysChanged = true
|
| 597 |
+
const item =
|
| 598 |
+
prevCount > 0
|
| 599 |
+
? (this.getVirtualItemForOffset(this.getScrollOffset()) ??
|
| 600 |
+
measurements[0])
|
| 601 |
+
: null
|
| 602 |
+
|
| 603 |
+
if (item) {
|
| 604 |
+
anchor = [item.key, this.getScrollOffset() - item.start]
|
| 605 |
+
}
|
| 606 |
+
|
| 607 |
+
const behavior =
|
| 608 |
+
merged.followOnAppend === true
|
| 609 |
+
? 'auto'
|
| 610 |
+
: merged.followOnAppend || null
|
| 611 |
+
|
| 612 |
+
if (
|
| 613 |
+
behavior &&
|
| 614 |
+
nextCount > prevCount &&
|
| 615 |
+
this.isAtEnd(prevOptions.scrollEndThreshold) &&
|
| 616 |
+
(prevCount === 0 || merged.getItemKey(nextCount - 1) !== prevLastKey)
|
| 617 |
+
) {
|
| 618 |
+
followOnAppend = behavior
|
| 619 |
+
}
|
| 620 |
+
}
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
this.options = merged
|
| 624 |
+
|
| 625 |
+
// When edge keys changed (prepend, trim, reorder, etc.) the key→index
|
| 626 |
+
// mapping has shifted. Force a full measurement rebuild so the anchor
|
| 627 |
+
// resolution below reads positions from the new layout, not the stale
|
| 628 |
+
// memoised cache. Without this, a stable `getItemKey` reference +
|
| 629 |
+
// unchanged `count` would let getMeasurements() return the old layout.
|
| 630 |
+
if (edgeKeysChanged) {
|
| 631 |
+
this.pendingMin = 0
|
| 632 |
+
this.itemSizeCacheVersion++
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
// Eagerly adjust scrollOffset so the virtualizer computes the correct
|
| 636 |
+
// visible range during the current render pass — before _willUpdate
|
| 637 |
+
// syncs the DOM scroll position in a layout effect. Without this,
|
| 638 |
+
// the virtualizer would render the wrong items for one frame (the
|
| 639 |
+
// estimate-based positions are stale) and then correct in the next
|
| 640 |
+
// frame, producing a visible "jump" on prepend with dynamic sizes.
|
| 641 |
+
let anchorResolved = false
|
| 642 |
+
let anchorDelta = 0
|
| 643 |
+
if (anchor && this.scrollOffset !== null) {
|
| 644 |
+
const [anchorKey, anchorOffset] = anchor
|
| 645 |
+
const newMeasurements = this.getMeasurements()
|
| 646 |
+
const { count, getItemKey } = this.options
|
| 647 |
+
let idx = 0
|
| 648 |
+
while (idx < count && getItemKey(idx) !== anchorKey) {
|
| 649 |
+
idx++
|
| 650 |
+
}
|
| 651 |
+
if (idx < count) {
|
| 652 |
+
const anchorItem = newMeasurements[idx]
|
| 653 |
+
if (anchorItem) {
|
| 654 |
+
// Clamp to the reachable range's lower bound — anchorOffset may
|
| 655 |
+
// have been derived from a transiently negative scrollOffset
|
| 656 |
+
// (rubber-band), and a negative tracked offset never self-heals
|
| 657 |
+
// when the element cannot scroll (#1229).
|
| 658 |
+
const newOffset = Math.max(0, anchorItem.start + anchorOffset)
|
| 659 |
+
if (newOffset !== this.scrollOffset) {
|
| 660 |
+
anchorDelta = newOffset - this.scrollOffset
|
| 661 |
+
this.scrollOffset = newOffset
|
| 662 |
+
anchorResolved = true
|
| 663 |
+
}
|
| 664 |
+
}
|
| 665 |
+
}
|
| 666 |
+
}
|
| 667 |
+
|
| 668 |
+
if (anchorResolved || followOnAppend) {
|
| 669 |
+
this.pendingScrollAnchor = [
|
| 670 |
+
anchorResolved ? anchor![0] : null,
|
| 671 |
+
anchorResolved ? anchor![1] : 0,
|
| 672 |
+
followOnAppend,
|
| 673 |
+
anchorDelta,
|
| 674 |
+
]
|
| 675 |
+
}
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
private notify = (sync: boolean) => {
|
| 679 |
+
this.options.onChange?.(this, sync)
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
// Returns `true` when it performed a synchronous `scrollTop` write this
|
| 683 |
+
// tick, `false` when the delta was zero or the write was deferred (iOS).
|
| 684 |
+
// `resizeItem` uses that to decide whether the follow-up `notify` must be
|
| 685 |
+
// synchronous so the grown transforms commit in the same paint (#1227).
|
| 686 |
+
private applyScrollAdjustment(
|
| 687 |
+
delta: number,
|
| 688 |
+
behavior?: ScrollBehavior,
|
| 689 |
+
): boolean {
|
| 690 |
+
if (delta === 0) return false
|
| 691 |
+
|
| 692 |
+
if (process.env.NODE_ENV !== 'production' && this.options.debug) {
|
| 693 |
+
console.info('correction', delta)
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
if (
|
| 697 |
+
isIOSWebKit() &&
|
| 698 |
+
(this.isScrolling || this._iosTouching || this._iosJustTouchEnded)
|
| 699 |
+
) {
|
| 700 |
+
this._iosDeferredAdjustment += delta
|
| 701 |
+
return false
|
| 702 |
+
} else {
|
| 703 |
+
this._scrollToOffset(this.getScrollOffset(), {
|
| 704 |
+
adjustments: (this.scrollAdjustments += delta),
|
| 705 |
+
behavior,
|
| 706 |
+
})
|
| 707 |
+
// Eagerly carry the intended target in `scrollOffset` so callers that
|
| 708 |
+
// read it before the next scroll event — notably the next `resizeItem`
|
| 709 |
+
// tick's `getVirtualDistanceFromEnd()` / `wasAtEnd` check — see the
|
| 710 |
+
// post-adjustment position even when the DOM `scrollTop` write was
|
| 711 |
+
// clamped because the consumer hasn't grown the sizer yet (`notify()`
|
| 712 |
+
// runs after this in `resizeItem`). Same idea as the eager
|
| 713 |
+
// `scrollOffset` adjustment for prepend in `setOptions` (#1176). The
|
| 714 |
+
// adjustment is now baked into `scrollOffset`, so zero
|
| 715 |
+
// `scrollAdjustments` to keep their sum invariant.
|
| 716 |
+
if (this.scrollOffset !== null) {
|
| 717 |
+
this.scrollOffset += this.scrollAdjustments
|
| 718 |
+
// Clamp only the lower bound: a negative offset is unreachable, and
|
| 719 |
+
// on an unscrollable element (content fits the viewport) no scroll
|
| 720 |
+
// event ever fires to correct it, permanently skewing
|
| 721 |
+
// getDistanceFromEnd() and wedging _flushIosDeferredIfReady (#1229).
|
| 722 |
+
// Upper-bound overflow stays untouched — it is transiently
|
| 723 |
+
// legitimate mid-prepend while the consumer's sizer catches up.
|
| 724 |
+
if (this.scrollOffset < 0) this.scrollOffset = 0
|
| 725 |
+
this.scrollAdjustments = 0
|
| 726 |
+
}
|
| 727 |
+
return true
|
| 728 |
+
}
|
| 729 |
+
}
|
| 730 |
+
|
| 731 |
+
private maybeNotify = memo(
|
| 732 |
+
() => {
|
| 733 |
+
this.calculateRange()
|
| 734 |
+
|
| 735 |
+
return [
|
| 736 |
+
this.isScrolling,
|
| 737 |
+
this.range ? this.range.startIndex : null,
|
| 738 |
+
this.range ? this.range.endIndex : null,
|
| 739 |
+
]
|
| 740 |
+
},
|
| 741 |
+
(isScrolling) => {
|
| 742 |
+
this.notify(isScrolling)
|
| 743 |
+
},
|
| 744 |
+
{
|
| 745 |
+
key: process.env.NODE_ENV !== 'production' && 'maybeNotify',
|
| 746 |
+
debug: () => this.options.debug,
|
| 747 |
+
initialDeps: [
|
| 748 |
+
this.isScrolling,
|
| 749 |
+
this.range ? this.range.startIndex : null,
|
| 750 |
+
this.range ? this.range.endIndex : null,
|
| 751 |
+
] as [boolean, number | null, number | null],
|
| 752 |
+
},
|
| 753 |
+
)
|
| 754 |
+
|
| 755 |
+
private cleanup = () => {
|
| 756 |
+
this.unsubs.filter(Boolean).forEach((d) => d!())
|
| 757 |
+
this.unsubs = []
|
| 758 |
+
this.observer.disconnect()
|
| 759 |
+
if (this.rafId != null && this.targetWindow) {
|
| 760 |
+
this.targetWindow.cancelAnimationFrame(this.rafId)
|
| 761 |
+
this.rafId = null
|
| 762 |
+
}
|
| 763 |
+
this.scrollState = null
|
| 764 |
+
// The iOS gesture/deferral state is scoped to the current scroll
|
| 765 |
+
// element: the touch listeners that maintain it were just removed, and
|
| 766 |
+
// an in-flight touch keeps targeting the old element (implicit touch
|
| 767 |
+
// capture), so the new element never reports it. Carrying the state
|
| 768 |
+
// over would replay a stale deferred delta on the new element's first
|
| 769 |
+
// flush, and a cleanup that lands mid-touch or inside the post-touchend
|
| 770 |
+
// grace window would strand _iosTouching / _iosJustTouchEnded as true
|
| 771 |
+
// (the listener unsub clears the grace timer, and with it the only
|
| 772 |
+
// pending reset of the flag), deferring every adjustment on the new
|
| 773 |
+
// element until its next touch cycle.
|
| 774 |
+
this._iosDeferredAdjustment = 0
|
| 775 |
+
this._iosTouching = false
|
| 776 |
+
this._iosJustTouchEnded = false
|
| 777 |
+
this.scrollElement = null
|
| 778 |
+
this.targetWindow = null
|
| 779 |
+
}
|
| 780 |
+
|
| 781 |
+
_didMount = () => {
|
| 782 |
+
return () => {
|
| 783 |
+
this.cleanup()
|
| 784 |
+
}
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
_willUpdate = () => {
|
| 788 |
+
const scrollElement = this.options.enabled
|
| 789 |
+
? this.options.getScrollElement()
|
| 790 |
+
: null
|
| 791 |
+
|
| 792 |
+
if (this.scrollElement !== scrollElement) {
|
| 793 |
+
this.cleanup()
|
| 794 |
+
|
| 795 |
+
if (!scrollElement) {
|
| 796 |
+
this.maybeNotify()
|
| 797 |
+
return
|
| 798 |
+
}
|
| 799 |
+
|
| 800 |
+
this.scrollElement = scrollElement
|
| 801 |
+
|
| 802 |
+
if (this.scrollElement && 'ownerDocument' in this.scrollElement) {
|
| 803 |
+
this.targetWindow = this.scrollElement.ownerDocument.defaultView
|
| 804 |
+
} else {
|
| 805 |
+
this.targetWindow = this.scrollElement?.window ?? null
|
| 806 |
+
}
|
| 807 |
+
|
| 808 |
+
this.elementsCache.forEach((cached) => {
|
| 809 |
+
this.observer.observe(cached)
|
| 810 |
+
})
|
| 811 |
+
|
| 812 |
+
this.unsubs.push(
|
| 813 |
+
this.options.observeElementRect(this, (rect) => {
|
| 814 |
+
this.scrollRect = rect
|
| 815 |
+
this.maybeNotify()
|
| 816 |
+
}),
|
| 817 |
+
)
|
| 818 |
+
|
| 819 |
+
this.unsubs.push(
|
| 820 |
+
this.options.observeElementOffset(this, (offset, isScrolling) => {
|
| 821 |
+
// A scroll event that reports movement but lands on the offset we
|
| 822 |
+
// already hold — and isn't a self-write read-back — is a spurious
|
| 823 |
+
// no-op re-emit that Safari/Firefox fire after a re-render's layout
|
| 824 |
+
// (Chrome doesn't). Treating it as scrolling re-arms `isScrolling`,
|
| 825 |
+
// which forces a render that triggers another such event: an
|
| 826 |
+
// infinite re-render loop. Ignore it. (Self-writes are handled by
|
| 827 |
+
// the `_intendedScrollOffset` reconciliation just below.)
|
| 828 |
+
if (
|
| 829 |
+
isScrolling &&
|
| 830 |
+
this._intendedScrollOffset === null &&
|
| 831 |
+
offset === this.scrollOffset
|
| 832 |
+
) {
|
| 833 |
+
return
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
// If this scroll event looks like the browser's read-back of a
|
| 837 |
+
// value we just wrote, prefer our intended (sub-pixel-accurate)
|
| 838 |
+
// value over the browser's rounded one. The 1.5 px tolerance is
|
| 839 |
+
// tight enough to avoid mistaking a real user scroll for a
|
| 840 |
+
// self-write — by the time the user has moved 1.5 px, the
|
| 841 |
+
// intended value will already have been consumed by a prior
|
| 842 |
+
// scroll event and cleared.
|
| 843 |
+
if (
|
| 844 |
+
this._intendedScrollOffset !== null &&
|
| 845 |
+
Math.abs(offset - this._intendedScrollOffset) < 1.5
|
| 846 |
+
) {
|
| 847 |
+
offset = this._intendedScrollOffset
|
| 848 |
+
}
|
| 849 |
+
this._intendedScrollOffset = null
|
| 850 |
+
|
| 851 |
+
this.scrollAdjustments = 0
|
| 852 |
+
// If the offset hasn't moved, this is the echo of our own
|
| 853 |
+
// adjustment write — `applyScrollAdjustment` already folded it
|
| 854 |
+
// into `scrollOffset`. There's no direction to infer, so leave
|
| 855 |
+
// it alone; a real gesture always moves the offset.
|
| 856 |
+
const prevOffset = this.getScrollOffset()
|
| 857 |
+
this.scrollDirection = isScrolling
|
| 858 |
+
? prevOffset === offset
|
| 859 |
+
? this.scrollDirection
|
| 860 |
+
: prevOffset < offset
|
| 861 |
+
? 'forward'
|
| 862 |
+
: 'backward'
|
| 863 |
+
: null
|
| 864 |
+
this.scrollOffset = offset
|
| 865 |
+
this.isScrolling = isScrolling
|
| 866 |
+
|
| 867 |
+
// Flush deferred iOS adjustments if we're now fully settled.
|
| 868 |
+
// "Fully settled" means: not actively scrolling, no finger on
|
| 869 |
+
// screen, and the post-touchend grace window has expired.
|
| 870 |
+
this._flushIosDeferredIfReady()
|
| 871 |
+
|
| 872 |
+
if (this.scrollState) {
|
| 873 |
+
this.scheduleScrollReconcile()
|
| 874 |
+
}
|
| 875 |
+
this.maybeNotify()
|
| 876 |
+
}),
|
| 877 |
+
)
|
| 878 |
+
|
| 879 |
+
// Touch event listeners (iOS-aware deferral). We attach unconditionally
|
| 880 |
+
// — the listeners are passive and cheap; on non-touch devices they
|
| 881 |
+
// simply never fire. The gating by isIOSWebKit() lives in resizeItem
|
| 882 |
+
// and _flushIosDeferredIfReady so we only burn the path on iOS.
|
| 883 |
+
if ('addEventListener' in this.scrollElement) {
|
| 884 |
+
const scrollEl = this.scrollElement as unknown as EventTarget
|
| 885 |
+
const onTouchStart = () => {
|
| 886 |
+
this._iosTouching = true
|
| 887 |
+
this._iosJustTouchEnded = false
|
| 888 |
+
if (this._iosTouchEndTimerId !== null && this.targetWindow != null) {
|
| 889 |
+
this.targetWindow.clearTimeout(this._iosTouchEndTimerId)
|
| 890 |
+
this._iosTouchEndTimerId = null
|
| 891 |
+
}
|
| 892 |
+
}
|
| 893 |
+
const onTouchEnd = () => {
|
| 894 |
+
this._iosTouching = false
|
| 895 |
+
if (!isIOSWebKit() || this.targetWindow == null) {
|
| 896 |
+
// Non-iOS: nothing more to track. Just clear the touching flag.
|
| 897 |
+
return
|
| 898 |
+
}
|
| 899 |
+
this._iosJustTouchEnded = true
|
| 900 |
+
// After ~150 ms with no scroll/touch events, momentum is done.
|
| 901 |
+
this._iosTouchEndTimerId = this.targetWindow.setTimeout(() => {
|
| 902 |
+
this._iosJustTouchEnded = false
|
| 903 |
+
this._iosTouchEndTimerId = null
|
| 904 |
+
// After the grace window, attempt to flush. The scroll event
|
| 905 |
+
// for momentum decay may have already fired before our timer.
|
| 906 |
+
this._flushIosDeferredIfReady()
|
| 907 |
+
}, 150)
|
| 908 |
+
}
|
| 909 |
+
scrollEl.addEventListener(
|
| 910 |
+
'touchstart',
|
| 911 |
+
onTouchStart,
|
| 912 |
+
addEventListenerOptions,
|
| 913 |
+
)
|
| 914 |
+
scrollEl.addEventListener(
|
| 915 |
+
'touchend',
|
| 916 |
+
onTouchEnd,
|
| 917 |
+
addEventListenerOptions,
|
| 918 |
+
)
|
| 919 |
+
this.unsubs.push(() => {
|
| 920 |
+
scrollEl.removeEventListener('touchstart', onTouchStart)
|
| 921 |
+
scrollEl.removeEventListener('touchend', onTouchEnd)
|
| 922 |
+
if (this._iosTouchEndTimerId !== null && this.targetWindow != null) {
|
| 923 |
+
this.targetWindow.clearTimeout(this._iosTouchEndTimerId)
|
| 924 |
+
this._iosTouchEndTimerId = null
|
| 925 |
+
}
|
| 926 |
+
})
|
| 927 |
+
}
|
| 928 |
+
|
| 929 |
+
this._scrollToOffset(this.getScrollOffset(), {
|
| 930 |
+
adjustments: undefined,
|
| 931 |
+
behavior: undefined,
|
| 932 |
+
})
|
| 933 |
+
}
|
| 934 |
+
|
| 935 |
+
const anchor = this.pendingScrollAnchor
|
| 936 |
+
this.pendingScrollAnchor = null
|
| 937 |
+
|
| 938 |
+
if (anchor && this.scrollElement && this.options.enabled) {
|
| 939 |
+
const [key, _offset, followOnAppend, anchorDelta] = anchor
|
| 940 |
+
|
| 941 |
+
if (key !== null && !followOnAppend) {
|
| 942 |
+
// scrollOffset was eagerly adjusted in setOptions so the
|
| 943 |
+
// virtualizer already computed the correct range during render.
|
| 944 |
+
// Now sync the browser's actual scroll position to match.
|
| 945 |
+
// Skip when followOnAppend is set — scrollToEnd will handle it.
|
| 946 |
+
//
|
| 947 |
+
// On iOS WebKit, writing scrollTop during touch/momentum cancels
|
| 948 |
+
// the in-flight scroll. Defer the DOM sync the same way
|
| 949 |
+
// applyScrollAdjustment does — accumulate the delta and let
|
| 950 |
+
// _flushIosDeferredIfReady handle it once the scroll settles.
|
| 951 |
+
if (
|
| 952 |
+
isIOSWebKit() &&
|
| 953 |
+
(this.isScrolling || this._iosTouching || this._iosJustTouchEnded)
|
| 954 |
+
) {
|
| 955 |
+
if (anchorDelta !== 0) {
|
| 956 |
+
this._iosDeferredAdjustment += anchorDelta
|
| 957 |
+
}
|
| 958 |
+
} else {
|
| 959 |
+
this._scrollToOffset(this.getScrollOffset(), {
|
| 960 |
+
adjustments: undefined,
|
| 961 |
+
behavior: undefined,
|
| 962 |
+
})
|
| 963 |
+
}
|
| 964 |
+
}
|
| 965 |
+
|
| 966 |
+
if (followOnAppend) {
|
| 967 |
+
this.scrollToEnd({ behavior: followOnAppend })
|
| 968 |
+
}
|
| 969 |
+
}
|
| 970 |
+
}
|
| 971 |
+
|
| 972 |
+
// Apply any accumulated iOS-deferred scroll adjustment, but only when we're
|
| 973 |
+
// truly settled — not actively scrolling, not under an active touch, and
|
| 974 |
+
// past the post-touchend grace window. Called from the scroll callback
|
| 975 |
+
// and the touchend grace-timer.
|
| 976 |
+
private _flushIosDeferredIfReady = () => {
|
| 977 |
+
if (this._iosDeferredAdjustment === 0) return
|
| 978 |
+
if (this.isScrolling) return
|
| 979 |
+
if (this._iosTouching) return
|
| 980 |
+
if (this._iosJustTouchEnded) return
|
| 981 |
+
// Phase 2b: Safari elastic-overscroll (rubber-band) lets scrollTop go
|
| 982 |
+
// negative or beyond scrollHeight - clientHeight. Writing scrollTop
|
| 983 |
+
// while in that zone snaps the page back to the clamped value at the
|
| 984 |
+
// end of the bounce, often discarding the user's intent. Skip the
|
| 985 |
+
// flush; the next in-bounds scroll event will retry.
|
| 986 |
+
const cur = this.getScrollOffset()
|
| 987 |
+
const max = this.getMaxScrollOffset()
|
| 988 |
+
if (cur < 0 || cur > max) return
|
| 989 |
+
// At the end clamp the browser already absorbed a shrink above the
|
| 990 |
+
// viewport (it clamped scrollTop onto the new bottom), so replaying our
|
| 991 |
+
// deferred negative delta would lift the view off the bottom — drop it.
|
| 992 |
+
// Positive deltas still replay: growth above doesn't clamp. (#1233)
|
| 993 |
+
if (this._iosDeferredAdjustment < 0 && cur >= max - 1) {
|
| 994 |
+
this._iosDeferredAdjustment = 0
|
| 995 |
+
return
|
| 996 |
+
}
|
| 997 |
+
const delta = this._iosDeferredAdjustment
|
| 998 |
+
this._iosDeferredAdjustment = 0
|
| 999 |
+
// Roll the deferred delta into the running accumulator so any resize
|
| 1000 |
+
// landing between now and the resulting scroll event computes from the
|
| 1001 |
+
// post-flush offset rather than the stale one.
|
| 1002 |
+
this._scrollToOffset(cur, {
|
| 1003 |
+
adjustments: (this.scrollAdjustments += delta),
|
| 1004 |
+
behavior: undefined,
|
| 1005 |
+
})
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
private rafId: number | null = null
|
| 1009 |
+
private scheduleScrollReconcile() {
|
| 1010 |
+
if (!this.targetWindow) {
|
| 1011 |
+
this.scrollState = null
|
| 1012 |
+
return
|
| 1013 |
+
}
|
| 1014 |
+
if (this.rafId != null) return
|
| 1015 |
+
this.rafId = this.targetWindow.requestAnimationFrame(() => {
|
| 1016 |
+
this.rafId = null
|
| 1017 |
+
this.reconcileScroll()
|
| 1018 |
+
})
|
| 1019 |
+
}
|
| 1020 |
+
private reconcileScroll() {
|
| 1021 |
+
if (!this.scrollState) return
|
| 1022 |
+
|
| 1023 |
+
const el = this.scrollElement
|
| 1024 |
+
if (!el) return
|
| 1025 |
+
|
| 1026 |
+
// Safety valve: bail out if reconciliation has been running too long
|
| 1027 |
+
const MAX_RECONCILE_MS = 5000
|
| 1028 |
+
if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {
|
| 1029 |
+
this.scrollState = null
|
| 1030 |
+
return
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
const offsetInfo =
|
| 1034 |
+
this.scrollState.index != null
|
| 1035 |
+
? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align)
|
| 1036 |
+
: undefined
|
| 1037 |
+
const targetOffset = offsetInfo
|
| 1038 |
+
? offsetInfo[0]
|
| 1039 |
+
: this.scrollState.lastTargetOffset
|
| 1040 |
+
|
| 1041 |
+
// Require one stable frame where target matches scroll offset.
|
| 1042 |
+
// approxEqual() already tolerates minor fluctuations, so one frame is sufficient
|
| 1043 |
+
// to confirm scroll has reached its target without premature cleanup.
|
| 1044 |
+
const STABLE_FRAMES = 1
|
| 1045 |
+
|
| 1046 |
+
const targetChanged = targetOffset !== this.scrollState.lastTargetOffset
|
| 1047 |
+
|
| 1048 |
+
if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {
|
| 1049 |
+
this.scrollState.stableFrames++
|
| 1050 |
+
if (this.scrollState.stableFrames >= STABLE_FRAMES) {
|
| 1051 |
+
// Final-pass exact landing. The reconcile-stable check uses a 1.01px
|
| 1052 |
+
// tolerance (approxEqual) so we don't fight subpixel browser rounding
|
| 1053 |
+
// during the converging phase. Once we're definitively settled,
|
| 1054 |
+
// commit the exact target so consumers calling scrollToIndex(N)
|
| 1055 |
+
// end up at the EXACT computed position of item N — matching
|
| 1056 |
+
// virtuoso's 0px landing accuracy rather than our prior 0.5-1px.
|
| 1057 |
+
if (this.getScrollOffset() !== targetOffset) {
|
| 1058 |
+
this._scrollToOffset(targetOffset, {
|
| 1059 |
+
adjustments: undefined,
|
| 1060 |
+
behavior: 'auto',
|
| 1061 |
+
})
|
| 1062 |
+
}
|
| 1063 |
+
this.scrollState = null
|
| 1064 |
+
return
|
| 1065 |
+
}
|
| 1066 |
+
} else {
|
| 1067 |
+
this.scrollState.stableFrames = 0
|
| 1068 |
+
|
| 1069 |
+
if (targetChanged) {
|
| 1070 |
+
// When the target moves during smooth scroll (because items came into
|
| 1071 |
+
// view and got measured, shifting positions), the original logic was
|
| 1072 |
+
// to immediately snap to 'auto' — visibly jarring on long
|
| 1073 |
+
// scroll-to-index calls. Now: keep smooth while we're still far
|
| 1074 |
+
// (more than a viewport) from the new target. Only fall back to
|
| 1075 |
+
// 'auto' for the final approach, so the user sees one continuous
|
| 1076 |
+
// motion that smoothly adjusts its endpoint as measurements arrive.
|
| 1077 |
+
const viewport = this.getSize() || 600
|
| 1078 |
+
const distance = Math.abs(targetOffset - this.getScrollOffset())
|
| 1079 |
+
const keepSmooth =
|
| 1080 |
+
this.scrollState.behavior === 'smooth' && distance > viewport
|
| 1081 |
+
|
| 1082 |
+
this.scrollState.lastTargetOffset = targetOffset
|
| 1083 |
+
if (!keepSmooth) {
|
| 1084 |
+
this.scrollState.behavior = 'auto'
|
| 1085 |
+
}
|
| 1086 |
+
|
| 1087 |
+
this._scrollToOffset(targetOffset, {
|
| 1088 |
+
adjustments: undefined,
|
| 1089 |
+
behavior: keepSmooth ? 'smooth' : 'auto',
|
| 1090 |
+
})
|
| 1091 |
+
}
|
| 1092 |
+
}
|
| 1093 |
+
|
| 1094 |
+
// Always reschedule while scrollState is active to guarantee
|
| 1095 |
+
// the safety valve timeout runs even if no scroll events fire
|
| 1096 |
+
// (e.g. no-op scrollToFn, detached element)
|
| 1097 |
+
this.scheduleScrollReconcile()
|
| 1098 |
+
}
|
| 1099 |
+
|
| 1100 |
+
private getSize = () => {
|
| 1101 |
+
if (!this.options.enabled) {
|
| 1102 |
+
this.scrollRect = null
|
| 1103 |
+
return 0
|
| 1104 |
+
}
|
| 1105 |
+
|
| 1106 |
+
this.scrollRect = this.scrollRect ?? this.options.initialRect
|
| 1107 |
+
|
| 1108 |
+
return this.scrollRect[this.options.horizontal ? 'width' : 'height']
|
| 1109 |
+
}
|
| 1110 |
+
|
| 1111 |
+
private getScrollOffset = () => {
|
| 1112 |
+
if (!this.options.enabled) {
|
| 1113 |
+
this.scrollOffset = null
|
| 1114 |
+
return 0
|
| 1115 |
+
}
|
| 1116 |
+
|
| 1117 |
+
this.scrollOffset =
|
| 1118 |
+
this.scrollOffset ??
|
| 1119 |
+
(typeof this.options.initialOffset === 'function'
|
| 1120 |
+
? this.options.initialOffset()
|
| 1121 |
+
: this.options.initialOffset)
|
| 1122 |
+
|
| 1123 |
+
return this.scrollOffset
|
| 1124 |
+
}
|
| 1125 |
+
|
| 1126 |
+
private getMeasurementOptions = memo(
|
| 1127 |
+
() => [
|
| 1128 |
+
this.options.count,
|
| 1129 |
+
this.options.paddingStart,
|
| 1130 |
+
this.options.scrollMargin,
|
| 1131 |
+
this.options.getItemKey,
|
| 1132 |
+
this.options.enabled,
|
| 1133 |
+
this.options.lanes,
|
| 1134 |
+
this.options.laneAssignmentMode,
|
| 1135 |
+
this.options.gap,
|
| 1136 |
+
],
|
| 1137 |
+
(
|
| 1138 |
+
count,
|
| 1139 |
+
paddingStart,
|
| 1140 |
+
scrollMargin,
|
| 1141 |
+
getItemKey,
|
| 1142 |
+
enabled,
|
| 1143 |
+
lanes,
|
| 1144 |
+
laneAssignmentMode,
|
| 1145 |
+
gap,
|
| 1146 |
+
) => {
|
| 1147 |
+
const lanesChanged =
|
| 1148 |
+
this.prevLanes !== undefined && this.prevLanes !== lanes
|
| 1149 |
+
|
| 1150 |
+
if (lanesChanged) {
|
| 1151 |
+
// Set flag for getMeasurements to handle
|
| 1152 |
+
this.lanesChangedFlag = true
|
| 1153 |
+
}
|
| 1154 |
+
|
| 1155 |
+
this.prevLanes = lanes
|
| 1156 |
+
this.pendingMin = null
|
| 1157 |
+
|
| 1158 |
+
return {
|
| 1159 |
+
count,
|
| 1160 |
+
paddingStart,
|
| 1161 |
+
scrollMargin,
|
| 1162 |
+
getItemKey,
|
| 1163 |
+
enabled,
|
| 1164 |
+
lanes,
|
| 1165 |
+
laneAssignmentMode,
|
| 1166 |
+
gap,
|
| 1167 |
+
}
|
| 1168 |
+
},
|
| 1169 |
+
{
|
| 1170 |
+
key: false,
|
| 1171 |
+
},
|
| 1172 |
+
)
|
| 1173 |
+
|
| 1174 |
+
private getMeasurements = memo(
|
| 1175 |
+
() => [this.getMeasurementOptions(), this.itemSizeCacheVersion],
|
| 1176 |
+
(
|
| 1177 |
+
{
|
| 1178 |
+
count,
|
| 1179 |
+
paddingStart,
|
| 1180 |
+
scrollMargin,
|
| 1181 |
+
getItemKey,
|
| 1182 |
+
enabled,
|
| 1183 |
+
lanes,
|
| 1184 |
+
laneAssignmentMode,
|
| 1185 |
+
gap,
|
| 1186 |
+
},
|
| 1187 |
+
_itemSizeCacheVersion,
|
| 1188 |
+
) => {
|
| 1189 |
+
const itemSizeCache = this.itemSizeCache
|
| 1190 |
+
if (!enabled) {
|
| 1191 |
+
this.measurementsCache = []
|
| 1192 |
+
this.itemSizeCache.clear()
|
| 1193 |
+
this.laneAssignments.clear()
|
| 1194 |
+
return []
|
| 1195 |
+
}
|
| 1196 |
+
|
| 1197 |
+
// Clean up stale lane cache entries when count decreases
|
| 1198 |
+
if (this.laneAssignments.size > count) {
|
| 1199 |
+
for (const index of this.laneAssignments.keys()) {
|
| 1200 |
+
if (index >= count) {
|
| 1201 |
+
this.laneAssignments.delete(index)
|
| 1202 |
+
}
|
| 1203 |
+
}
|
| 1204 |
+
}
|
| 1205 |
+
|
| 1206 |
+
// ✅ Force complete recalculation when lanes change
|
| 1207 |
+
if (this.lanesChangedFlag) {
|
| 1208 |
+
this.lanesChangedFlag = false // Reset immediately
|
| 1209 |
+
this.lanesSettling = true // Start settling period
|
| 1210 |
+
this.measurementsCache = []
|
| 1211 |
+
this.itemSizeCache.clear()
|
| 1212 |
+
this.laneAssignments.clear() // Clear lane cache for new lane count
|
| 1213 |
+
// Force min = 0 on the rebuild
|
| 1214 |
+
this.pendingMin = null
|
| 1215 |
+
}
|
| 1216 |
+
|
| 1217 |
+
// Don't restore from initialMeasurementsCache during lane changes
|
| 1218 |
+
// as it contains stale lane assignments from the previous lane count
|
| 1219 |
+
if (this.measurementsCache.length === 0 && !this.lanesSettling) {
|
| 1220 |
+
this.measurementsCache = this.options.initialMeasurementsCache
|
| 1221 |
+
this.measurementsCache.forEach((item) => {
|
| 1222 |
+
this.itemSizeCache.set(item.key, item.size)
|
| 1223 |
+
})
|
| 1224 |
+
}
|
| 1225 |
+
|
| 1226 |
+
// During lanes settling, ignore pendingMin to prevent repositioning
|
| 1227 |
+
const min = this.lanesSettling ? 0 : (this.pendingMin ?? 0)
|
| 1228 |
+
this.pendingMin = null
|
| 1229 |
+
|
| 1230 |
+
// ✅ End settling period when cache is fully built
|
| 1231 |
+
if (this.lanesSettling && this.measurementsCache.length === count) {
|
| 1232 |
+
this.lanesSettling = false
|
| 1233 |
+
}
|
| 1234 |
+
|
| 1235 |
+
// ─── Fast path: single-lane lazy materialization ────────────────────
|
| 1236 |
+
// For lanes === 1 (the default and most common case), skip the
|
| 1237 |
+
// per-item VirtualItem object allocation. We write start/size pairs
|
| 1238 |
+
// into a Float64Array and return a Proxy that builds VirtualItem
|
| 1239 |
+
// objects on demand (only the indices a consumer actually reads).
|
| 1240 |
+
//
|
| 1241 |
+
// At n=100k this drops cold-mount cost from ~2.5ms (eager object
|
| 1242 |
+
// allocation) to roughly the cost of a single typed-array fill.
|
| 1243 |
+
if (lanes === 1) {
|
| 1244 |
+
// Reuse flat backing if large enough; else grow (preserving data
|
| 1245 |
+
// before `min` to mirror the slice-and-rebuild contract).
|
| 1246 |
+
const need = count * 2
|
| 1247 |
+
let flat = this._flatMeasurements
|
| 1248 |
+
if (!flat || flat.length < need) {
|
| 1249 |
+
const next = new Float64Array(need)
|
| 1250 |
+
if (flat && min > 0) next.set(flat.subarray(0, min * 2))
|
| 1251 |
+
flat = next
|
| 1252 |
+
this._flatMeasurements = flat
|
| 1253 |
+
}
|
| 1254 |
+
|
| 1255 |
+
let runningStart: number
|
| 1256 |
+
if (min === 0) {
|
| 1257 |
+
runningStart = paddingStart + scrollMargin
|
| 1258 |
+
} else {
|
| 1259 |
+
// Continue from where we left off
|
| 1260 |
+
const prevIdx = min - 1
|
| 1261 |
+
runningStart = flat[prevIdx * 2]! + flat[prevIdx * 2 + 1]! + gap
|
| 1262 |
+
}
|
| 1263 |
+
|
| 1264 |
+
for (let i = min; i < count; i++) {
|
| 1265 |
+
const key = getItemKey(i)
|
| 1266 |
+
const measuredSize = itemSizeCache.get(key)
|
| 1267 |
+
const size =
|
| 1268 |
+
typeof measuredSize === 'number'
|
| 1269 |
+
? measuredSize
|
| 1270 |
+
: this.options.estimateSize(i)
|
| 1271 |
+
flat[i * 2] = runningStart
|
| 1272 |
+
flat[i * 2 + 1] = size
|
| 1273 |
+
runningStart += size + gap
|
| 1274 |
+
}
|
| 1275 |
+
|
| 1276 |
+
const view = createLazyMeasurementsView(count, flat, getItemKey)
|
| 1277 |
+
this.measurementsCache = view
|
| 1278 |
+
return view
|
| 1279 |
+
}
|
| 1280 |
+
|
| 1281 |
+
const measurements = this.measurementsCache.slice(0, min)
|
| 1282 |
+
|
| 1283 |
+
// ✅ Performance: Track last item index per lane for O(1) lookup
|
| 1284 |
+
const laneLastIndex: Array<number | undefined> = new Array(lanes).fill(
|
| 1285 |
+
undefined,
|
| 1286 |
+
)
|
| 1287 |
+
// Running end position of each lane's last item, so the shortest lane
|
| 1288 |
+
// can be found with an O(lanes) argmin instead of the old backward walk
|
| 1289 |
+
// through `measurements` (getFurthestMeasurement). `filledLanes` tracks
|
| 1290 |
+
// how many lanes have at least one item, mirroring the previous
|
| 1291 |
+
// "all lanes seen → shortest lane, else i % lanes" branch.
|
| 1292 |
+
const laneEnds = new Float64Array(lanes)
|
| 1293 |
+
let filledLanes = 0
|
| 1294 |
+
|
| 1295 |
+
// Initialize from existing measurements (before min)
|
| 1296 |
+
for (let m = 0; m < min; m++) {
|
| 1297 |
+
const item = measurements[m]
|
| 1298 |
+
if (item) {
|
| 1299 |
+
if (laneLastIndex[item.lane] === undefined) filledLanes++
|
| 1300 |
+
laneLastIndex[item.lane] = m
|
| 1301 |
+
laneEnds[item.lane] = item.end
|
| 1302 |
+
}
|
| 1303 |
+
}
|
| 1304 |
+
|
| 1305 |
+
for (let i = min; i < count; i++) {
|
| 1306 |
+
const key = getItemKey(i)
|
| 1307 |
+
|
| 1308 |
+
// Check for cached lane assignment
|
| 1309 |
+
const cachedLane = this.laneAssignments.get(i)
|
| 1310 |
+
let lane: number
|
| 1311 |
+
let start: number
|
| 1312 |
+
|
| 1313 |
+
const shouldCacheLane =
|
| 1314 |
+
laneAssignmentMode === 'estimate' || itemSizeCache.has(key)
|
| 1315 |
+
|
| 1316 |
+
if (cachedLane !== undefined && this.options.lanes > 1) {
|
| 1317 |
+
// Use cached lane - O(1) lookup for previous item in same lane
|
| 1318 |
+
lane = cachedLane
|
| 1319 |
+
const prevIndex = laneLastIndex[lane]
|
| 1320 |
+
const prevInLane =
|
| 1321 |
+
prevIndex !== undefined ? measurements[prevIndex] : undefined
|
| 1322 |
+
start = prevInLane
|
| 1323 |
+
? prevInLane.end + gap
|
| 1324 |
+
: paddingStart + scrollMargin
|
| 1325 |
+
} else if (filledLanes === lanes) {
|
| 1326 |
+
// No cache, every lane seeded: place in the shortest lane.
|
| 1327 |
+
// Read the running per-lane ends (O(lanes) argmin) instead of the
|
| 1328 |
+
// old backward scan. Tie-break on the lane's last-item index to
|
| 1329 |
+
// preserve the previous sort-by-(end, index) placement exactly.
|
| 1330 |
+
let bestLane = 0
|
| 1331 |
+
let bestEnd = laneEnds[0]!
|
| 1332 |
+
let bestIdx = laneLastIndex[0]!
|
| 1333 |
+
for (let l = 1; l < lanes; l++) {
|
| 1334 |
+
const e = laneEnds[l]!
|
| 1335 |
+
if (e < bestEnd || (e === bestEnd && laneLastIndex[l]! < bestIdx)) {
|
| 1336 |
+
bestLane = l
|
| 1337 |
+
bestEnd = e
|
| 1338 |
+
bestIdx = laneLastIndex[l]!
|
| 1339 |
+
}
|
| 1340 |
+
}
|
| 1341 |
+
lane = bestLane
|
| 1342 |
+
start = bestEnd + gap
|
| 1343 |
+
|
| 1344 |
+
if (shouldCacheLane) {
|
| 1345 |
+
this.laneAssignments.set(i, lane)
|
| 1346 |
+
}
|
| 1347 |
+
} else {
|
| 1348 |
+
// No cache and not every lane seeded yet — seed lanes in order,
|
| 1349 |
+
// matching the previous `i % lanes` fallback for the first row.
|
| 1350 |
+
lane = i % this.options.lanes
|
| 1351 |
+
start = paddingStart + scrollMargin
|
| 1352 |
+
|
| 1353 |
+
if (shouldCacheLane) {
|
| 1354 |
+
this.laneAssignments.set(i, lane)
|
| 1355 |
+
}
|
| 1356 |
+
}
|
| 1357 |
+
|
| 1358 |
+
const measuredSize = itemSizeCache.get(key)
|
| 1359 |
+
const size =
|
| 1360 |
+
typeof measuredSize === 'number'
|
| 1361 |
+
? measuredSize
|
| 1362 |
+
: this.options.estimateSize(i)
|
| 1363 |
+
|
| 1364 |
+
const end = start + size
|
| 1365 |
+
|
| 1366 |
+
measurements[i] = {
|
| 1367 |
+
index: i,
|
| 1368 |
+
start,
|
| 1369 |
+
size,
|
| 1370 |
+
end,
|
| 1371 |
+
key,
|
| 1372 |
+
lane,
|
| 1373 |
+
}
|
| 1374 |
+
|
| 1375 |
+
// ✅ Performance: Update lane's last item index + running end
|
| 1376 |
+
if (laneLastIndex[lane] === undefined) filledLanes++
|
| 1377 |
+
laneLastIndex[lane] = i
|
| 1378 |
+
laneEnds[lane] = end
|
| 1379 |
+
}
|
| 1380 |
+
|
| 1381 |
+
this.measurementsCache = measurements
|
| 1382 |
+
|
| 1383 |
+
return measurements
|
| 1384 |
+
},
|
| 1385 |
+
{
|
| 1386 |
+
key: process.env.NODE_ENV !== 'production' && 'getMeasurements',
|
| 1387 |
+
debug: () => this.options.debug,
|
| 1388 |
+
},
|
| 1389 |
+
)
|
| 1390 |
+
|
| 1391 |
+
calculateRange = memo(
|
| 1392 |
+
() => [
|
| 1393 |
+
this.getMeasurements(),
|
| 1394 |
+
this.getSize(),
|
| 1395 |
+
this.getScrollOffset(),
|
| 1396 |
+
this.options.lanes,
|
| 1397 |
+
],
|
| 1398 |
+
(measurements, outerSize, scrollOffset, lanes) => {
|
| 1399 |
+
if (measurements.length === 0 || outerSize === 0) {
|
| 1400 |
+
this.range = null
|
| 1401 |
+
return null
|
| 1402 |
+
}
|
| 1403 |
+
this.range = calculateRangeImpl(
|
| 1404 |
+
measurements,
|
| 1405 |
+
outerSize,
|
| 1406 |
+
scrollOffset,
|
| 1407 |
+
lanes,
|
| 1408 |
+
// Pass the typed array so binary search + forward-walk can read
|
| 1409 |
+
// start/end directly from Float64Array, skipping the Proxy traps.
|
| 1410 |
+
lanes === 1 && this._flatMeasurements != null
|
| 1411 |
+
? this._flatMeasurements
|
| 1412 |
+
: null,
|
| 1413 |
+
)
|
| 1414 |
+
return this.range
|
| 1415 |
+
},
|
| 1416 |
+
{
|
| 1417 |
+
key: process.env.NODE_ENV !== 'production' && 'calculateRange',
|
| 1418 |
+
debug: () => this.options.debug,
|
| 1419 |
+
},
|
| 1420 |
+
)
|
| 1421 |
+
|
| 1422 |
+
getVirtualIndexes = memo(
|
| 1423 |
+
() => {
|
| 1424 |
+
let startIndex: number | null = null
|
| 1425 |
+
let endIndex: number | null = null
|
| 1426 |
+
const range = this.calculateRange()
|
| 1427 |
+
if (range) {
|
| 1428 |
+
startIndex = range.startIndex
|
| 1429 |
+
endIndex = range.endIndex
|
| 1430 |
+
}
|
| 1431 |
+
this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex])
|
| 1432 |
+
return [
|
| 1433 |
+
this.options.rangeExtractor,
|
| 1434 |
+
this.options.overscan,
|
| 1435 |
+
this.options.count,
|
| 1436 |
+
startIndex,
|
| 1437 |
+
endIndex,
|
| 1438 |
+
]
|
| 1439 |
+
},
|
| 1440 |
+
(rangeExtractor, overscan, count, startIndex, endIndex) => {
|
| 1441 |
+
return startIndex === null || endIndex === null
|
| 1442 |
+
? []
|
| 1443 |
+
: rangeExtractor({
|
| 1444 |
+
startIndex,
|
| 1445 |
+
endIndex,
|
| 1446 |
+
overscan,
|
| 1447 |
+
count,
|
| 1448 |
+
})
|
| 1449 |
+
},
|
| 1450 |
+
{
|
| 1451 |
+
key: process.env.NODE_ENV !== 'production' && 'getVirtualIndexes',
|
| 1452 |
+
debug: () => this.options.debug,
|
| 1453 |
+
},
|
| 1454 |
+
)
|
| 1455 |
+
|
| 1456 |
+
indexFromElement = (node: TItemElement) => {
|
| 1457 |
+
const attributeName = this.options.indexAttribute
|
| 1458 |
+
const indexStr = node.getAttribute(attributeName)
|
| 1459 |
+
|
| 1460 |
+
if (!indexStr) {
|
| 1461 |
+
console.warn(
|
| 1462 |
+
`Missing attribute name '${attributeName}={index}' on measured element.`,
|
| 1463 |
+
)
|
| 1464 |
+
return -1
|
| 1465 |
+
}
|
| 1466 |
+
|
| 1467 |
+
return parseInt(indexStr, 10)
|
| 1468 |
+
}
|
| 1469 |
+
|
| 1470 |
+
/**
|
| 1471 |
+
* Determines if an item at the given index should be measured during smooth scroll.
|
| 1472 |
+
* During smooth scroll, only items within a buffer range around the target are measured
|
| 1473 |
+
* to prevent items far from the target from pushing it away.
|
| 1474 |
+
*/
|
| 1475 |
+
private shouldMeasureDuringScroll = (index: number): boolean => {
|
| 1476 |
+
// No scroll state or not smooth scroll - always allow measurements
|
| 1477 |
+
if (!this.scrollState || this.scrollState.behavior !== 'smooth') {
|
| 1478 |
+
return true
|
| 1479 |
+
}
|
| 1480 |
+
|
| 1481 |
+
const scrollIndex =
|
| 1482 |
+
this.scrollState.index ??
|
| 1483 |
+
this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)?.index
|
| 1484 |
+
|
| 1485 |
+
if (scrollIndex !== undefined && this.range) {
|
| 1486 |
+
// Allow measurements within a buffer range around the scroll target
|
| 1487 |
+
const bufferSize = Math.max(
|
| 1488 |
+
this.options.overscan,
|
| 1489 |
+
Math.ceil((this.range.endIndex - this.range.startIndex) / 2),
|
| 1490 |
+
)
|
| 1491 |
+
const minIndex = Math.max(0, scrollIndex - bufferSize)
|
| 1492 |
+
const maxIndex = Math.min(
|
| 1493 |
+
this.options.count - 1,
|
| 1494 |
+
scrollIndex + bufferSize,
|
| 1495 |
+
)
|
| 1496 |
+
return index >= minIndex && index <= maxIndex
|
| 1497 |
+
}
|
| 1498 |
+
|
| 1499 |
+
return true
|
| 1500 |
+
}
|
| 1501 |
+
|
| 1502 |
+
measureElement = (node: TItemElement | null) => {
|
| 1503 |
+
if (!node) {
|
| 1504 |
+
this.elementsCache.forEach((cached, key) => {
|
| 1505 |
+
if (!cached.isConnected) {
|
| 1506 |
+
this.observer.unobserve(cached)
|
| 1507 |
+
this.elementsCache.delete(key)
|
| 1508 |
+
}
|
| 1509 |
+
})
|
| 1510 |
+
return
|
| 1511 |
+
}
|
| 1512 |
+
|
| 1513 |
+
const index = this.indexFromElement(node)
|
| 1514 |
+
const key = this.options.getItemKey(index)
|
| 1515 |
+
const prevNode = this.elementsCache.get(key)
|
| 1516 |
+
|
| 1517 |
+
if (prevNode !== node) {
|
| 1518 |
+
if (prevNode) {
|
| 1519 |
+
this.observer.unobserve(prevNode)
|
| 1520 |
+
}
|
| 1521 |
+
this.observer.observe(node)
|
| 1522 |
+
this.elementsCache.set(key, node)
|
| 1523 |
+
}
|
| 1524 |
+
|
| 1525 |
+
// Sync-measure when idle (initial render) or during programmatic scrolling
|
| 1526 |
+
// (scrollToIndex/scrollToOffset) where reconcileScroll needs sizes in the same frame.
|
| 1527 |
+
// During normal user scrolling, skip sync measurement — the RO callback handles it async.
|
| 1528 |
+
if (
|
| 1529 |
+
(!this.isScrolling || this.scrollState) &&
|
| 1530 |
+
this.shouldMeasureDuringScroll(index)
|
| 1531 |
+
) {
|
| 1532 |
+
this.resizeItem(index, this.options.measureElement(node, undefined, this))
|
| 1533 |
+
}
|
| 1534 |
+
}
|
| 1535 |
+
|
| 1536 |
+
resizeItem = (index: number, size: number) => {
|
| 1537 |
+
if (index < 0 || index >= this.options.count) return
|
| 1538 |
+
|
| 1539 |
+
// Fast field reads. For lanes===1 we read raw start/size from the flat
|
| 1540 |
+
// typed array, avoiding a Proxy.get + VirtualItem allocation per call.
|
| 1541 |
+
// For lanes>1 we fall back to the cached VirtualItem array.
|
| 1542 |
+
let cachedSize: number
|
| 1543 |
+
let itemStart: number
|
| 1544 |
+
let key: Key
|
| 1545 |
+
const flat = this._flatMeasurements
|
| 1546 |
+
if (this.options.lanes === 1 && flat !== null) {
|
| 1547 |
+
key = this.options.getItemKey(index)
|
| 1548 |
+
itemStart = flat[index * 2]!
|
| 1549 |
+
cachedSize = flat[index * 2 + 1]!
|
| 1550 |
+
} else {
|
| 1551 |
+
const item = this.measurementsCache[index]
|
| 1552 |
+
if (!item) return
|
| 1553 |
+
key = item.key
|
| 1554 |
+
itemStart = item.start
|
| 1555 |
+
cachedSize = item.size
|
| 1556 |
+
}
|
| 1557 |
+
|
| 1558 |
+
const itemSize = this.itemSizeCache.get(key) ?? cachedSize
|
| 1559 |
+
const delta = size - itemSize
|
| 1560 |
+
|
| 1561 |
+
if (delta !== 0) {
|
| 1562 |
+
const wasAtEnd =
|
| 1563 |
+
this.options.anchorTo === 'end' &&
|
| 1564 |
+
this.scrollState?.behavior !== 'smooth' &&
|
| 1565 |
+
this.getVirtualDistanceFromEnd() <= this.options.scrollEndThreshold
|
| 1566 |
+
const prevTotalSize = wasAtEnd ? this.getTotalSize() : 0
|
| 1567 |
+
// Default anchoring predicate (used unless the consumer supplies a
|
| 1568 |
+
// custom shouldAdjustScrollPositionOnItemSizeChange).
|
| 1569 |
+
const scrollOffsetWithAdj =
|
| 1570 |
+
this.getScrollOffset() + this.scrollAdjustments
|
| 1571 |
+
const isFirstMeasure = !this.itemSizeCache.has(key)
|
| 1572 |
+
const defaultShouldAdjust = isFirstMeasure
|
| 1573 |
+
? // First measurement: compensate any item whose top sits above the
|
| 1574 |
+
// fold — the estimate→actual delta must be corrected regardless of
|
| 1575 |
+
// scroll direction, since the whole estimated block was above it.
|
| 1576 |
+
itemStart < scrollOffsetWithAdj
|
| 1577 |
+
: // Re-measurement: only compensate an item that is ENTIRELY above the
|
| 1578 |
+
// fold. An item that merely *spans* the fold (top above, bottom
|
| 1579 |
+
// below — e.g. a streaming chat message growing at its bottom)
|
| 1580 |
+
// changes size *below* the anchor point, so shifting scrollTop by the
|
| 1581 |
+
// delta would drag the viewport downward on every growth (#1218).
|
| 1582 |
+
// Also skip during backward scroll to avoid the "items jump while
|
| 1583 |
+
// scrolling up" cascade.
|
| 1584 |
+
itemStart + itemSize <= scrollOffsetWithAdj &&
|
| 1585 |
+
this.scrollDirection !== 'backward'
|
| 1586 |
+
const shouldAdjustScroll =
|
| 1587 |
+
this.scrollState?.behavior !== 'smooth' &&
|
| 1588 |
+
(this.shouldAdjustScrollPositionOnItemSizeChange !== undefined
|
| 1589 |
+
? this.shouldAdjustScrollPositionOnItemSizeChange(
|
| 1590 |
+
// The callback expects a VirtualItem; build one lazily only
|
| 1591 |
+
// when the consumer actually supplied a custom predicate.
|
| 1592 |
+
this.measurementsCache[index] ?? {
|
| 1593 |
+
index,
|
| 1594 |
+
key,
|
| 1595 |
+
start: itemStart,
|
| 1596 |
+
size: cachedSize,
|
| 1597 |
+
end: itemStart + cachedSize,
|
| 1598 |
+
lane: 0,
|
| 1599 |
+
},
|
| 1600 |
+
delta,
|
| 1601 |
+
this,
|
| 1602 |
+
)
|
| 1603 |
+
: defaultShouldAdjust)
|
| 1604 |
+
|
| 1605 |
+
if (this.pendingMin === null || index < this.pendingMin) {
|
| 1606 |
+
this.pendingMin = index
|
| 1607 |
+
}
|
| 1608 |
+
this.itemSizeCache.set(key, size)
|
| 1609 |
+
this.itemSizeCacheVersion++
|
| 1610 |
+
|
| 1611 |
+
let adjustedSync = false
|
| 1612 |
+
if (wasAtEnd) {
|
| 1613 |
+
adjustedSync = this.applyScrollAdjustment(
|
| 1614 |
+
this.getTotalSize() - prevTotalSize,
|
| 1615 |
+
)
|
| 1616 |
+
} else if (shouldAdjustScroll) {
|
| 1617 |
+
adjustedSync = this.applyScrollAdjustment(delta)
|
| 1618 |
+
}
|
| 1619 |
+
|
| 1620 |
+
// When we just moved `scrollTop` to compensate for an above-viewport
|
| 1621 |
+
// resize, the grown item transforms must commit in the SAME frame as
|
| 1622 |
+
// that write. `applyScrollAdjustment` writes `scrollTop` synchronously
|
| 1623 |
+
// inside this ResizeObserver callback, but an async `notify` schedules
|
| 1624 |
+
// the transform render for a later commit — so the browser can paint
|
| 1625 |
+
// one frame with the new `scrollTop` and the old positions, and the
|
| 1626 |
+
// viewport visibly jumps by `delta` before snapping back (#1227). A
|
| 1627 |
+
// synchronous notify flushes the render in this same callback, so both
|
| 1628 |
+
// land in one paint. When nothing moved (or the write was deferred on
|
| 1629 |
+
// iOS), keep the cheaper async notify.
|
| 1630 |
+
this.notify(adjustedSync)
|
| 1631 |
+
}
|
| 1632 |
+
}
|
| 1633 |
+
|
| 1634 |
+
getVirtualItems = memo(
|
| 1635 |
+
() => [this.getVirtualIndexes(), this.getMeasurements()],
|
| 1636 |
+
(indexes, measurements) => {
|
| 1637 |
+
const virtualItems: Array<VirtualItem> = []
|
| 1638 |
+
|
| 1639 |
+
for (let k = 0, len = indexes.length; k < len; k++) {
|
| 1640 |
+
const i = indexes[k]!
|
| 1641 |
+
const measurement = measurements[i]!
|
| 1642 |
+
|
| 1643 |
+
virtualItems.push(measurement)
|
| 1644 |
+
}
|
| 1645 |
+
|
| 1646 |
+
return virtualItems
|
| 1647 |
+
},
|
| 1648 |
+
{
|
| 1649 |
+
key: process.env.NODE_ENV !== 'production' && 'getVirtualItems',
|
| 1650 |
+
debug: () => this.options.debug,
|
| 1651 |
+
},
|
| 1652 |
+
)
|
| 1653 |
+
|
| 1654 |
+
getVirtualItemForOffset = (offset: number) => {
|
| 1655 |
+
const measurements = this.getMeasurements()
|
| 1656 |
+
if (measurements.length === 0) {
|
| 1657 |
+
return undefined
|
| 1658 |
+
}
|
| 1659 |
+
// Same fast-path as calculateRange: read start values directly from the
|
| 1660 |
+
// typed array during binary search to skip the Proxy.get materialization
|
| 1661 |
+
// per probe.
|
| 1662 |
+
const flat = this._flatMeasurements
|
| 1663 |
+
const useFlat = this.options.lanes === 1 && flat != null
|
| 1664 |
+
const idx = findNearestBinarySearch(
|
| 1665 |
+
0,
|
| 1666 |
+
measurements.length - 1,
|
| 1667 |
+
useFlat
|
| 1668 |
+
? (i: number) => flat[i * 2]!
|
| 1669 |
+
: (i: number) => notUndefined(measurements[i]).start,
|
| 1670 |
+
offset,
|
| 1671 |
+
)
|
| 1672 |
+
return notUndefined(measurements[idx])
|
| 1673 |
+
}
|
| 1674 |
+
|
| 1675 |
+
private getMaxScrollOffset = () => {
|
| 1676 |
+
if (!this.scrollElement) return 0
|
| 1677 |
+
|
| 1678 |
+
if ('scrollHeight' in this.scrollElement) {
|
| 1679 |
+
// Element
|
| 1680 |
+
return this.options.horizontal
|
| 1681 |
+
? this.scrollElement.scrollWidth - this.scrollElement.clientWidth
|
| 1682 |
+
: this.scrollElement.scrollHeight - this.scrollElement.clientHeight
|
| 1683 |
+
} else {
|
| 1684 |
+
// Window
|
| 1685 |
+
const doc = this.scrollElement.document.documentElement
|
| 1686 |
+
return this.options.horizontal
|
| 1687 |
+
? doc.scrollWidth - this.scrollElement.innerWidth
|
| 1688 |
+
: doc.scrollHeight - this.scrollElement.innerHeight
|
| 1689 |
+
}
|
| 1690 |
+
}
|
| 1691 |
+
|
| 1692 |
+
private getVirtualDistanceFromEnd = () => {
|
| 1693 |
+
return Math.max(
|
| 1694 |
+
this.getTotalSize() - this.getSize() - this.getScrollOffset(),
|
| 1695 |
+
0,
|
| 1696 |
+
)
|
| 1697 |
+
}
|
| 1698 |
+
|
| 1699 |
+
getDistanceFromEnd = () => {
|
| 1700 |
+
return Math.max(this.getMaxScrollOffset() - this.getScrollOffset(), 0)
|
| 1701 |
+
}
|
| 1702 |
+
|
| 1703 |
+
isAtEnd = (threshold = this.options.scrollEndThreshold) => {
|
| 1704 |
+
return this.getDistanceFromEnd() <= threshold
|
| 1705 |
+
}
|
| 1706 |
+
|
| 1707 |
+
getOffsetForAlignment = (
|
| 1708 |
+
toOffset: number,
|
| 1709 |
+
align: ScrollAlignment,
|
| 1710 |
+
itemSize = 0,
|
| 1711 |
+
) => {
|
| 1712 |
+
if (!this.scrollElement) return 0
|
| 1713 |
+
|
| 1714 |
+
const size = this.getSize()
|
| 1715 |
+
const scrollOffset = this.getScrollOffset()
|
| 1716 |
+
|
| 1717 |
+
if (align === 'auto') {
|
| 1718 |
+
align = toOffset >= scrollOffset + size ? 'end' : 'start'
|
| 1719 |
+
}
|
| 1720 |
+
|
| 1721 |
+
if (align === 'center') {
|
| 1722 |
+
// When aligning to a particular item (e.g. with scrollToIndex),
|
| 1723 |
+
// adjust offset by the size of the item to center on the item
|
| 1724 |
+
toOffset += (itemSize - size) / 2
|
| 1725 |
+
} else if (align === 'end') {
|
| 1726 |
+
toOffset -= size
|
| 1727 |
+
}
|
| 1728 |
+
|
| 1729 |
+
const maxOffset = this.getMaxScrollOffset()
|
| 1730 |
+
|
| 1731 |
+
return Math.max(Math.min(maxOffset, toOffset), 0)
|
| 1732 |
+
}
|
| 1733 |
+
|
| 1734 |
+
getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {
|
| 1735 |
+
index = Math.max(0, Math.min(index, this.options.count - 1))
|
| 1736 |
+
|
| 1737 |
+
const size = this.getSize()
|
| 1738 |
+
const scrollOffset = this.getScrollOffset()
|
| 1739 |
+
|
| 1740 |
+
const item = this.measurementsCache[index]
|
| 1741 |
+
if (!item) return
|
| 1742 |
+
|
| 1743 |
+
if (align === 'auto') {
|
| 1744 |
+
if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {
|
| 1745 |
+
align = 'end'
|
| 1746 |
+
} else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {
|
| 1747 |
+
align = 'start'
|
| 1748 |
+
} else {
|
| 1749 |
+
return [scrollOffset, align] as const
|
| 1750 |
+
}
|
| 1751 |
+
}
|
| 1752 |
+
|
| 1753 |
+
// For the last item with 'end' alignment, use browser's actual max scroll
|
| 1754 |
+
// to account for borders/padding that aren't in our measurements
|
| 1755 |
+
if (align === 'end' && index === this.options.count - 1) {
|
| 1756 |
+
return [this.getMaxScrollOffset(), align] as const
|
| 1757 |
+
}
|
| 1758 |
+
|
| 1759 |
+
const toOffset =
|
| 1760 |
+
align === 'end'
|
| 1761 |
+
? item.end + this.options.scrollPaddingEnd
|
| 1762 |
+
: item.start - this.options.scrollPaddingStart
|
| 1763 |
+
|
| 1764 |
+
return [
|
| 1765 |
+
this.getOffsetForAlignment(toOffset, align, item.size),
|
| 1766 |
+
align,
|
| 1767 |
+
] as const
|
| 1768 |
+
}
|
| 1769 |
+
|
| 1770 |
+
scrollToOffset = (
|
| 1771 |
+
toOffset: number,
|
| 1772 |
+
{ align = 'start', behavior = 'auto' }: ScrollToOffsetOptions = {},
|
| 1773 |
+
) => {
|
| 1774 |
+
// An absolute scroll command derives its target from current
|
| 1775 |
+
// measurements, so any iOS-deferred compensation still pending is stale by
|
| 1776 |
+
// definition — the command already accounts for the measurements the delta
|
| 1777 |
+
// was compensating for. Drop it so _flushIosDeferredIfReady doesn't replay
|
| 1778 |
+
// it onto the just-established position (relative commands like scrollBy
|
| 1779 |
+
// intentionally keep the deferral, since they build on the current offset).
|
| 1780 |
+
this._iosDeferredAdjustment = 0
|
| 1781 |
+
|
| 1782 |
+
const offset = this.getOffsetForAlignment(toOffset, align)
|
| 1783 |
+
|
| 1784 |
+
const now = this.now()
|
| 1785 |
+
this.scrollState = {
|
| 1786 |
+
index: null,
|
| 1787 |
+
align,
|
| 1788 |
+
behavior,
|
| 1789 |
+
startedAt: now,
|
| 1790 |
+
lastTargetOffset: offset,
|
| 1791 |
+
stableFrames: 0,
|
| 1792 |
+
}
|
| 1793 |
+
|
| 1794 |
+
this._scrollToOffset(offset, { adjustments: undefined, behavior })
|
| 1795 |
+
|
| 1796 |
+
this.scheduleScrollReconcile()
|
| 1797 |
+
}
|
| 1798 |
+
|
| 1799 |
+
scrollToIndex = (
|
| 1800 |
+
index: number,
|
| 1801 |
+
{
|
| 1802 |
+
align: initialAlign = 'auto',
|
| 1803 |
+
behavior = 'auto',
|
| 1804 |
+
}: ScrollToIndexOptions = {},
|
| 1805 |
+
) => {
|
| 1806 |
+
// See scrollToOffset: an absolute target invalidates any pending
|
| 1807 |
+
// iOS-deferred compensation.
|
| 1808 |
+
this._iosDeferredAdjustment = 0
|
| 1809 |
+
|
| 1810 |
+
index = Math.max(0, Math.min(index, this.options.count - 1))
|
| 1811 |
+
|
| 1812 |
+
const offsetInfo = this.getOffsetForIndex(index, initialAlign)
|
| 1813 |
+
if (!offsetInfo) {
|
| 1814 |
+
return
|
| 1815 |
+
}
|
| 1816 |
+
const [offset, align] = offsetInfo
|
| 1817 |
+
|
| 1818 |
+
const now = this.now()
|
| 1819 |
+
this.scrollState = {
|
| 1820 |
+
index,
|
| 1821 |
+
align,
|
| 1822 |
+
behavior,
|
| 1823 |
+
startedAt: now,
|
| 1824 |
+
lastTargetOffset: offset,
|
| 1825 |
+
stableFrames: 0,
|
| 1826 |
+
}
|
| 1827 |
+
|
| 1828 |
+
this._scrollToOffset(offset, { adjustments: undefined, behavior })
|
| 1829 |
+
|
| 1830 |
+
this.scheduleScrollReconcile()
|
| 1831 |
+
}
|
| 1832 |
+
|
| 1833 |
+
scrollBy = (
|
| 1834 |
+
delta: number,
|
| 1835 |
+
{ behavior = 'auto' }: ScrollToOffsetOptions = {},
|
| 1836 |
+
) => {
|
| 1837 |
+
const offset = this.getScrollOffset() + delta
|
| 1838 |
+
const now = this.now()
|
| 1839 |
+
|
| 1840 |
+
this.scrollState = {
|
| 1841 |
+
index: null,
|
| 1842 |
+
align: 'start',
|
| 1843 |
+
behavior,
|
| 1844 |
+
startedAt: now,
|
| 1845 |
+
lastTargetOffset: offset,
|
| 1846 |
+
stableFrames: 0,
|
| 1847 |
+
}
|
| 1848 |
+
|
| 1849 |
+
this._scrollToOffset(offset, { adjustments: undefined, behavior })
|
| 1850 |
+
|
| 1851 |
+
this.scheduleScrollReconcile()
|
| 1852 |
+
}
|
| 1853 |
+
|
| 1854 |
+
scrollToEnd = ({ behavior = 'auto' }: ScrollToEndOptions = {}) => {
|
| 1855 |
+
if (this.options.count > 0) {
|
| 1856 |
+
this.scrollToIndex(this.options.count - 1, {
|
| 1857 |
+
align: 'end',
|
| 1858 |
+
behavior,
|
| 1859 |
+
})
|
| 1860 |
+
return
|
| 1861 |
+
}
|
| 1862 |
+
|
| 1863 |
+
this.scrollToOffset(Math.max(this.getTotalSize() - this.getSize(), 0), {
|
| 1864 |
+
behavior,
|
| 1865 |
+
})
|
| 1866 |
+
}
|
| 1867 |
+
|
| 1868 |
+
getTotalSize = () => {
|
| 1869 |
+
const measurements = this.getMeasurements()
|
| 1870 |
+
|
| 1871 |
+
let end: number
|
| 1872 |
+
// If there are no measurements, set the end to paddingStart
|
| 1873 |
+
// If there is only one lane, use the last measurement's end
|
| 1874 |
+
// Otherwise find the maximum end value among all measurements
|
| 1875 |
+
if (measurements.length === 0) {
|
| 1876 |
+
end = this.options.paddingStart
|
| 1877 |
+
} else if (this.options.lanes === 1) {
|
| 1878 |
+
// Fast path: read last item's end directly from the flat typed array
|
| 1879 |
+
// when available; avoids a Proxy.get + VirtualItem materialization
|
| 1880 |
+
// just to call getTotalSize (which React renders trigger every commit).
|
| 1881 |
+
const lastIdx = measurements.length - 1
|
| 1882 |
+
const flat = this._flatMeasurements
|
| 1883 |
+
if (flat != null) {
|
| 1884 |
+
end = flat[lastIdx * 2]! + flat[lastIdx * 2 + 1]!
|
| 1885 |
+
} else {
|
| 1886 |
+
end = measurements[lastIdx]?.end ?? 0
|
| 1887 |
+
}
|
| 1888 |
+
} else {
|
| 1889 |
+
const endByLane = Array<number | null>(this.options.lanes).fill(null)
|
| 1890 |
+
let endIndex = measurements.length - 1
|
| 1891 |
+
while (endIndex >= 0 && endByLane.some((val) => val === null)) {
|
| 1892 |
+
const item = measurements[endIndex]!
|
| 1893 |
+
if (endByLane[item.lane] === null) {
|
| 1894 |
+
endByLane[item.lane] = item.end
|
| 1895 |
+
}
|
| 1896 |
+
|
| 1897 |
+
endIndex--
|
| 1898 |
+
}
|
| 1899 |
+
|
| 1900 |
+
end = Math.max(...endByLane.filter((val): val is number => val !== null))
|
| 1901 |
+
}
|
| 1902 |
+
|
| 1903 |
+
return Math.max(
|
| 1904 |
+
end - this.options.scrollMargin + this.options.paddingEnd,
|
| 1905 |
+
0,
|
| 1906 |
+
)
|
| 1907 |
+
}
|
| 1908 |
+
|
| 1909 |
+
/**
|
| 1910 |
+
* Returns a snapshot of currently-measured items suitable for round-
|
| 1911 |
+
* tripping through state storage (sessionStorage, history, etc.) and
|
| 1912 |
+
* passing back as `initialMeasurementsCache` on remount. Pair with the
|
| 1913 |
+
* current `scrollOffset` to restore exact scroll position after navigation.
|
| 1914 |
+
*
|
| 1915 |
+
* Only items the consumer has actually rendered (and thus measured) appear
|
| 1916 |
+
* in the snapshot; unmeasured items will fall back to `estimateSize` on
|
| 1917 |
+
* restore. Returns an empty array if no items have been measured.
|
| 1918 |
+
*/
|
| 1919 |
+
takeSnapshot = (): Array<VirtualItem> => {
|
| 1920 |
+
const snapshot: Array<VirtualItem> = []
|
| 1921 |
+
if (this.itemSizeCache.size === 0) return snapshot
|
| 1922 |
+
// Iterate measurementsCache only for indices whose key is in itemSizeCache
|
| 1923 |
+
// (i.e., have been measured). We build VirtualItem objects with the
|
| 1924 |
+
// current start/size/end so they can be persisted as plain data.
|
| 1925 |
+
const m = this.getMeasurements()
|
| 1926 |
+
for (const item of m) {
|
| 1927 |
+
if (item && this.itemSizeCache.has(item.key)) {
|
| 1928 |
+
// Force materialization (lazy path) and copy plain fields.
|
| 1929 |
+
snapshot.push({
|
| 1930 |
+
index: item.index,
|
| 1931 |
+
key: item.key,
|
| 1932 |
+
start: item.start,
|
| 1933 |
+
size: item.size,
|
| 1934 |
+
end: item.end,
|
| 1935 |
+
lane: item.lane,
|
| 1936 |
+
})
|
| 1937 |
+
}
|
| 1938 |
+
}
|
| 1939 |
+
return snapshot
|
| 1940 |
+
}
|
| 1941 |
+
|
| 1942 |
+
private _scrollToOffset = (
|
| 1943 |
+
offset: number,
|
| 1944 |
+
{
|
| 1945 |
+
adjustments,
|
| 1946 |
+
behavior,
|
| 1947 |
+
}: {
|
| 1948 |
+
adjustments: number | undefined
|
| 1949 |
+
behavior: ScrollBehavior | undefined
|
| 1950 |
+
},
|
| 1951 |
+
) => {
|
| 1952 |
+
// Record the intended logical scroll target so the next scroll event
|
| 1953 |
+
// can reconcile against subpixel rounding by the browser.
|
| 1954 |
+
this._intendedScrollOffset = offset + (adjustments ?? 0)
|
| 1955 |
+
this.options.scrollToFn(offset, { behavior, adjustments }, this)
|
| 1956 |
+
}
|
| 1957 |
+
|
| 1958 |
+
measure = () => {
|
| 1959 |
+
// Reset pendingMin so the next getMeasurements rebuilds from index 0.
|
| 1960 |
+
// Without this, a prior resizeItem() that left pendingMin > 0 would
|
| 1961 |
+
// cause the rebuild to preserve stale items before that index.
|
| 1962 |
+
this.pendingMin = null
|
| 1963 |
+
this.itemSizeCache.clear()
|
| 1964 |
+
this.laneAssignments.clear() // Clear lane cache for full re-layout
|
| 1965 |
+
this.itemSizeCacheVersion++
|
| 1966 |
+
this.notify(false)
|
| 1967 |
+
}
|
| 1968 |
+
}
|
| 1969 |
+
|
| 1970 |
+
const findNearestBinarySearch = (
|
| 1971 |
+
low: number,
|
| 1972 |
+
high: number,
|
| 1973 |
+
getCurrentValue: (i: number) => number,
|
| 1974 |
+
value: number,
|
| 1975 |
+
) => {
|
| 1976 |
+
while (low <= high) {
|
| 1977 |
+
const middle = ((low + high) / 2) | 0
|
| 1978 |
+
const currentValue = getCurrentValue(middle)
|
| 1979 |
+
|
| 1980 |
+
if (currentValue < value) {
|
| 1981 |
+
low = middle + 1
|
| 1982 |
+
} else if (currentValue > value) {
|
| 1983 |
+
high = middle - 1
|
| 1984 |
+
} else {
|
| 1985 |
+
return middle
|
| 1986 |
+
}
|
| 1987 |
+
}
|
| 1988 |
+
|
| 1989 |
+
if (low > 0) {
|
| 1990 |
+
return low - 1
|
| 1991 |
+
} else {
|
| 1992 |
+
return 0
|
| 1993 |
+
}
|
| 1994 |
+
}
|
| 1995 |
+
|
| 1996 |
+
// Monomorphic Float64Array variant — reads start values directly at stride
|
| 1997 |
+
// 2 instead of through a getter closure. JITs the inner load to a typed-
|
| 1998 |
+
// array bounds-check + load with no indirect call.
|
| 1999 |
+
function findNearestBinarySearchFlat(
|
| 2000 |
+
flat: Float64Array,
|
| 2001 |
+
high: number,
|
| 2002 |
+
value: number,
|
| 2003 |
+
) {
|
| 2004 |
+
let low = 0
|
| 2005 |
+
while (low <= high) {
|
| 2006 |
+
const middle = ((low + high) / 2) | 0
|
| 2007 |
+
const currentValue = flat[middle * 2]!
|
| 2008 |
+
|
| 2009 |
+
if (currentValue < value) {
|
| 2010 |
+
low = middle + 1
|
| 2011 |
+
} else if (currentValue > value) {
|
| 2012 |
+
high = middle - 1
|
| 2013 |
+
} else {
|
| 2014 |
+
return middle
|
| 2015 |
+
}
|
| 2016 |
+
}
|
| 2017 |
+
return low > 0 ? low - 1 : 0
|
| 2018 |
+
}
|
| 2019 |
+
|
| 2020 |
+
function calculateRangeImpl(
|
| 2021 |
+
measurements: Array<VirtualItem>,
|
| 2022 |
+
outerSize: number,
|
| 2023 |
+
scrollOffset: number,
|
| 2024 |
+
lanes: number,
|
| 2025 |
+
flat: Float64Array | null,
|
| 2026 |
+
) {
|
| 2027 |
+
const lastIndex = measurements.length - 1
|
| 2028 |
+
|
| 2029 |
+
// handle case when item count is less than or equal to lanes
|
| 2030 |
+
if (measurements.length <= lanes) {
|
| 2031 |
+
return { startIndex: 0, endIndex: lastIndex }
|
| 2032 |
+
}
|
| 2033 |
+
|
| 2034 |
+
if (lanes === 1 && flat !== null) {
|
| 2035 |
+
// Hot single-lane path: typed-array reads, no closures, no Proxy traps.
|
| 2036 |
+
const startIndex = findNearestBinarySearchFlat(
|
| 2037 |
+
flat,
|
| 2038 |
+
lastIndex,
|
| 2039 |
+
scrollOffset,
|
| 2040 |
+
)
|
| 2041 |
+
let endIndex = startIndex
|
| 2042 |
+
const limit = scrollOffset + outerSize
|
| 2043 |
+
while (
|
| 2044 |
+
endIndex < lastIndex &&
|
| 2045 |
+
flat[endIndex * 2]! + flat[endIndex * 2 + 1]! < limit
|
| 2046 |
+
) {
|
| 2047 |
+
endIndex++
|
| 2048 |
+
}
|
| 2049 |
+
return { startIndex, endIndex }
|
| 2050 |
+
}
|
| 2051 |
+
|
| 2052 |
+
// Fallback (lanes > 1 or no flat array): closure-based reads.
|
| 2053 |
+
const getStart = (index: number) => measurements[index]!.start
|
| 2054 |
+
let startIndex = findNearestBinarySearch(0, lastIndex, getStart, scrollOffset)
|
| 2055 |
+
let endIndex = startIndex
|
| 2056 |
+
|
| 2057 |
+
if (lanes === 1) {
|
| 2058 |
+
while (
|
| 2059 |
+
endIndex < lastIndex &&
|
| 2060 |
+
measurements[endIndex]!.end < scrollOffset + outerSize
|
| 2061 |
+
) {
|
| 2062 |
+
endIndex++
|
| 2063 |
+
}
|
| 2064 |
+
} else if (lanes > 1) {
|
| 2065 |
+
// Expand forward until we include the visible items from all lanes
|
| 2066 |
+
// which are closer to the end of the virtualizer window
|
| 2067 |
+
const endPerLane = Array(lanes).fill(0)
|
| 2068 |
+
while (
|
| 2069 |
+
endIndex < lastIndex &&
|
| 2070 |
+
endPerLane.some((pos) => pos < scrollOffset + outerSize)
|
| 2071 |
+
) {
|
| 2072 |
+
const item = measurements[endIndex]!
|
| 2073 |
+
endPerLane[item.lane] = item.end
|
| 2074 |
+
endIndex++
|
| 2075 |
+
}
|
| 2076 |
+
|
| 2077 |
+
// Expand backward until we include all lanes' visible items
|
| 2078 |
+
// closer to the top
|
| 2079 |
+
const startPerLane = Array(lanes).fill(scrollOffset + outerSize)
|
| 2080 |
+
while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
|
| 2081 |
+
const item = measurements[startIndex]!
|
| 2082 |
+
startPerLane[item.lane] = item.start
|
| 2083 |
+
startIndex--
|
| 2084 |
+
}
|
| 2085 |
+
|
| 2086 |
+
// Align startIndex to the beginning of its lane
|
| 2087 |
+
startIndex = Math.max(0, startIndex - (startIndex % lanes))
|
| 2088 |
+
// Align endIndex to the end of its lane
|
| 2089 |
+
endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - (endIndex % lanes)))
|
| 2090 |
+
}
|
| 2091 |
+
|
| 2092 |
+
return { startIndex, endIndex }
|
| 2093 |
+
}
|
node_modules/@tanstack/virtual-core/src/lazy-measurements.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Lazy materialization for the lanes===1 fast path. Backed by a
|
| 2 |
+
// Float64Array (stride 2: start, size, …); VirtualItems are constructed on
|
| 3 |
+
// first indexed read and cached. Saves the per-item object allocation at
|
| 4 |
+
// large list counts where most items are never visible.
|
| 5 |
+
|
| 6 |
+
import type { VirtualItem } from './index'
|
| 7 |
+
|
| 8 |
+
type Key = number | string | bigint
|
| 9 |
+
|
| 10 |
+
export function createLazyMeasurementsView(
|
| 11 |
+
count: number,
|
| 12 |
+
flat: Float64Array,
|
| 13 |
+
getItemKey: (i: number) => Key,
|
| 14 |
+
): Array<VirtualItem> {
|
| 15 |
+
const cache: Array<VirtualItem | undefined> = new Array(count)
|
| 16 |
+
return new Proxy(cache as any, {
|
| 17 |
+
get(target, prop, receiver) {
|
| 18 |
+
if (typeof prop === 'string') {
|
| 19 |
+
// Cheap digit-prefix sniff before number coerce.
|
| 20 |
+
const c = prop.charCodeAt(0)
|
| 21 |
+
if (c >= 48 && c <= 57) {
|
| 22 |
+
const i = +prop
|
| 23 |
+
if (Number.isInteger(i) && i >= 0 && i < count) {
|
| 24 |
+
let v = target[i]
|
| 25 |
+
if (!v) {
|
| 26 |
+
const s = flat[i * 2]!
|
| 27 |
+
v = target[i] = {
|
| 28 |
+
index: i,
|
| 29 |
+
key: getItemKey(i),
|
| 30 |
+
start: s,
|
| 31 |
+
size: flat[i * 2 + 1]!,
|
| 32 |
+
end: s + flat[i * 2 + 1]!,
|
| 33 |
+
lane: 0,
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
return v
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
if (prop === 'length') return count
|
| 40 |
+
}
|
| 41 |
+
return Reflect.get(target, prop, receiver)
|
| 42 |
+
},
|
| 43 |
+
}) as Array<VirtualItem>
|
| 44 |
+
}
|
node_modules/@tanstack/virtual-core/src/utils.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export type NoInfer<A extends any> = [A][A extends any ? 0 : never]
|
| 2 |
+
|
| 3 |
+
export type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
| 4 |
+
|
| 5 |
+
export function memo<TDeps extends ReadonlyArray<any>, TResult>(
|
| 6 |
+
getDeps: () => [...TDeps],
|
| 7 |
+
fn: (...args: NoInfer<[...TDeps]>) => TResult,
|
| 8 |
+
opts: {
|
| 9 |
+
key: false | string
|
| 10 |
+
debug?: () => boolean
|
| 11 |
+
onChange?: (result: TResult) => void
|
| 12 |
+
initialDeps?: TDeps
|
| 13 |
+
skipInitialOnChange?: boolean
|
| 14 |
+
},
|
| 15 |
+
) {
|
| 16 |
+
let deps = opts.initialDeps ?? []
|
| 17 |
+
let result: TResult | undefined
|
| 18 |
+
let isInitial = true
|
| 19 |
+
|
| 20 |
+
function memoizedFunction(): TResult {
|
| 21 |
+
// Debug-only timing. In production builds, `process.env.NODE_ENV !==
|
| 22 |
+
// 'production'` is constant-folded to `false` by downstream minifiers
|
| 23 |
+
// (Terser/esbuild/swc with `define`), which DCEs the entire block.
|
| 24 |
+
const debugEnabled =
|
| 25 |
+
process.env.NODE_ENV !== 'production' && !!opts.key && !!opts.debug?.()
|
| 26 |
+
let depTime = 0
|
| 27 |
+
if (debugEnabled) depTime = Date.now()
|
| 28 |
+
|
| 29 |
+
const newDeps = getDeps()
|
| 30 |
+
|
| 31 |
+
const depsChanged =
|
| 32 |
+
newDeps.length !== deps.length ||
|
| 33 |
+
newDeps.some((dep: any, index: number) => deps[index] !== dep)
|
| 34 |
+
|
| 35 |
+
if (!depsChanged) {
|
| 36 |
+
return result!
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
deps = newDeps
|
| 40 |
+
|
| 41 |
+
let resultTime = 0
|
| 42 |
+
if (debugEnabled) resultTime = Date.now()
|
| 43 |
+
|
| 44 |
+
result = fn(...newDeps)
|
| 45 |
+
|
| 46 |
+
if (debugEnabled) {
|
| 47 |
+
const depEndTime = Math.round((Date.now() - depTime) * 100) / 100
|
| 48 |
+
const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100
|
| 49 |
+
const resultFpsPercentage = resultEndTime / 16
|
| 50 |
+
|
| 51 |
+
const pad = (str: number | string, num: number) => {
|
| 52 |
+
str = String(str)
|
| 53 |
+
while (str.length < num) {
|
| 54 |
+
str = ' ' + str
|
| 55 |
+
}
|
| 56 |
+
return str
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
console.info(
|
| 60 |
+
`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,
|
| 61 |
+
`
|
| 62 |
+
font-size: .6rem;
|
| 63 |
+
font-weight: bold;
|
| 64 |
+
color: hsl(${Math.max(
|
| 65 |
+
0,
|
| 66 |
+
Math.min(120 - 120 * resultFpsPercentage, 120),
|
| 67 |
+
)}deg 100% 31%);`,
|
| 68 |
+
opts?.key,
|
| 69 |
+
)
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
if (opts?.onChange && !(isInitial && opts.skipInitialOnChange)) {
|
| 73 |
+
opts.onChange(result)
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
isInitial = false
|
| 77 |
+
|
| 78 |
+
return result
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
// Attach updateDeps to the function itself
|
| 82 |
+
memoizedFunction.updateDeps = (newDeps: [...TDeps]) => {
|
| 83 |
+
deps = newDeps
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
return memoizedFunction
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
export function notUndefined<T>(value: T | undefined, msg?: string): T {
|
| 90 |
+
if (value === undefined) {
|
| 91 |
+
throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)
|
| 92 |
+
} else {
|
| 93 |
+
return value
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
export const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1.01
|
| 98 |
+
|
| 99 |
+
export const debounce = (
|
| 100 |
+
targetWindow: Window & typeof globalThis,
|
| 101 |
+
fn: Function,
|
| 102 |
+
ms: number,
|
| 103 |
+
) => {
|
| 104 |
+
let timeoutId: number
|
| 105 |
+
return function (this: any, ...args: Array<any>) {
|
| 106 |
+
targetWindow.clearTimeout(timeoutId)
|
| 107 |
+
timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms)
|
| 108 |
+
}
|
| 109 |
+
}
|
node_modules/@testing-library/dom/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The MIT License (MIT)
|
| 2 |
+
Copyright (c) 2017 Kent C. Dodds
|
| 3 |
+
|
| 4 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 5 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 6 |
+
in the Software without restriction, including without limitation the rights
|
| 7 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 8 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 9 |
+
furnished to do so, subject to the following conditions:
|
| 10 |
+
|
| 11 |
+
The above copyright notice and this permission notice shall be included in all
|
| 12 |
+
copies or substantial portions of the Software.
|
| 13 |
+
|
| 14 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 15 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 16 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 17 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 18 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 19 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 20 |
+
SOFTWARE.
|
node_modules/@testing-library/dom/README.md
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div align="center">
|
| 2 |
+
<h1>DOM Testing Library</h1>
|
| 3 |
+
|
| 4 |
+
<a href="https://www.emojione.com/emoji/1f419">
|
| 5 |
+
<img
|
| 6 |
+
height="80"
|
| 7 |
+
width="80"
|
| 8 |
+
alt="octopus"
|
| 9 |
+
src="https://raw.githubusercontent.com/testing-library/dom-testing-library/main/other/octopus.png"
|
| 10 |
+
/>
|
| 11 |
+
</a>
|
| 12 |
+
|
| 13 |
+
<p>Simple and complete DOM testing utilities that encourage good testing
|
| 14 |
+
practices.</p>
|
| 15 |
+
|
| 16 |
+
[**Read the docs**](https://testing-library.com/dom) |
|
| 17 |
+
[Edit the docs](https://github.com/testing-library/testing-library-docs)
|
| 18 |
+
|
| 19 |
+
</div>
|
| 20 |
+
|
| 21 |
+
<hr />
|
| 22 |
+
|
| 23 |
+
<!-- prettier-ignore-start -->
|
| 24 |
+
[![Build Status][build-badge]][build]
|
| 25 |
+
[![Code Coverage][coverage-badge]][coverage]
|
| 26 |
+
[![version][version-badge]][package]
|
| 27 |
+
[![downloads][downloads-badge]][npmtrends]
|
| 28 |
+
[![MIT License][license-badge]][license]
|
| 29 |
+
[![All Contributors][all-contributors-badge]](#contributors)
|
| 30 |
+
[![PRs Welcome][prs-badge]][prs]
|
| 31 |
+
[![Code of Conduct][coc-badge]][coc]
|
| 32 |
+
[![Discord][discord-badge]][discord]
|
| 33 |
+
|
| 34 |
+
[![Watch on GitHub][github-watch-badge]][github-watch]
|
| 35 |
+
[![Star on GitHub][github-star-badge]][github-star]
|
| 36 |
+
[![Tweet][twitter-badge]][twitter]
|
| 37 |
+
<!-- prettier-ignore-end -->
|
| 38 |
+
|
| 39 |
+
<div align="center">
|
| 40 |
+
<a href="https://testingjavascript.com">
|
| 41 |
+
<img
|
| 42 |
+
width="500"
|
| 43 |
+
alt="TestingJavaScript.com Learn the smart, efficient way to test any JavaScript application."
|
| 44 |
+
src="https://raw.githubusercontent.com/testing-library/dom-testing-library/main/other/testingjavascript.jpg"
|
| 45 |
+
/>
|
| 46 |
+
</a>
|
| 47 |
+
</div>
|
| 48 |
+
|
| 49 |
+
## Table of Contents
|
| 50 |
+
|
| 51 |
+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
| 52 |
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
| 53 |
+
|
| 54 |
+
- [The Problem](#the-problem)
|
| 55 |
+
- [This Solution](#this-solution)
|
| 56 |
+
- [Installation](#installation)
|
| 57 |
+
- [Documentation](#documentation)
|
| 58 |
+
- [Guiding Principles](#guiding-principles)
|
| 59 |
+
- [Contributors](#contributors)
|
| 60 |
+
- [LICENSE](#license)
|
| 61 |
+
|
| 62 |
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
| 63 |
+
|
| 64 |
+
## The Problem
|
| 65 |
+
|
| 66 |
+
You want to write maintainable tests for your Web UI. As a part of this goal,
|
| 67 |
+
you want your tests to avoid including implementation details of your components
|
| 68 |
+
and rather focus on making your tests give you the confidence for which they are
|
| 69 |
+
intended. As part of this, you want your testbase to be maintainable in the long
|
| 70 |
+
run so refactors of your components (changes to implementation but not
|
| 71 |
+
functionality) don't break your tests and slow you and your team down.
|
| 72 |
+
|
| 73 |
+
## This Solution
|
| 74 |
+
|
| 75 |
+
The `DOM Testing Library` is a very light-weight solution for testing DOM nodes
|
| 76 |
+
(whether simulated with [`JSDOM`](https://github.com/jsdom/jsdom) as provided by
|
| 77 |
+
default with [Jest][] or in the browser). The main utilities it provides involve
|
| 78 |
+
querying the DOM for nodes in a way that's similar to how the user finds
|
| 79 |
+
elements on the page. In this way, the library helps ensure your tests give you
|
| 80 |
+
confidence in your UI code. The `DOM Testing Library`'s primary guiding
|
| 81 |
+
principle is:
|
| 82 |
+
|
| 83 |
+
> [The more your tests resemble the way your software is used, the more
|
| 84 |
+
> confidence they can give you.][guiding-principle]
|
| 85 |
+
|
| 86 |
+
## Installation
|
| 87 |
+
|
| 88 |
+
This module is distributed via [npm][npm] which is bundled with [node][node] and
|
| 89 |
+
should be installed as one of your project's `devDependencies`:
|
| 90 |
+
|
| 91 |
+
```
|
| 92 |
+
npm install --save-dev @testing-library/dom
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
> [**Docs**](https://testing-library.com/docs/install)
|
| 96 |
+
|
| 97 |
+
## Documentation
|
| 98 |
+
|
| 99 |
+
Read the docs (and discover framework and tool-specific implementations) at
|
| 100 |
+
[testing-library.com](https://testing-library.com/dom)
|
| 101 |
+
|
| 102 |
+
## Guiding Principles
|
| 103 |
+
|
| 104 |
+
> [The more your tests resemble the way your software is used, the more
|
| 105 |
+
> confidence they can give you.][guiding-principle]
|
| 106 |
+
|
| 107 |
+
We try to only expose methods and utilities that encourage you to write tests
|
| 108 |
+
that closely resemble how your web pages are used.
|
| 109 |
+
|
| 110 |
+
Utilities are included in this project based on the following guiding
|
| 111 |
+
principles:
|
| 112 |
+
|
| 113 |
+
1. If it relates to rendering components, it deals with DOM nodes rather than
|
| 114 |
+
component instances, nor should it encourage dealing with component
|
| 115 |
+
instances.
|
| 116 |
+
2. It should be generally useful for testing the application components in the
|
| 117 |
+
way the user would use it. We _are_ making some trade-offs here because
|
| 118 |
+
we're using a computer and often a simulated browser environment, but in
|
| 119 |
+
general, utilities should encourage tests that use the components the way
|
| 120 |
+
they're intended to be used.
|
| 121 |
+
3. Utility implementations and APIs should be simple and flexible.
|
| 122 |
+
|
| 123 |
+
At the end of the day, what we want is for this library to be pretty
|
| 124 |
+
light-weight, simple, and understandable.
|
| 125 |
+
|
| 126 |
+
## Contributors
|
| 127 |
+
|
| 128 |
+
Thanks goes to these people ([emoji key][emojis]):
|
| 129 |
+
|
| 130 |
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
| 131 |
+
<!-- prettier-ignore-start -->
|
| 132 |
+
<!-- markdownlint-disable -->
|
| 133 |
+
<table>
|
| 134 |
+
<tbody>
|
| 135 |
+
<tr>
|
| 136 |
+
<td align="center" valign="top" width="14.28%"><a href="https://kentcdodds.com"><img src="https://avatars.githubusercontent.com/u/1500684?v=3?s=100" width="100px;" alt="Kent C. Dodds"/><br /><sub><b>Kent C. Dodds</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=kentcdodds" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=kentcdodds" title="Documentation">📖</a> <a href="#infra-kentcdodds" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=kentcdodds" title="Tests">⚠️</a></td>
|
| 137 |
+
<td align="center" valign="top" width="14.28%"><a href="https://argos-ci.com"><img src="https://avatars2.githubusercontent.com/u/266302?v=4?s=100" width="100px;" alt="Greg Bergé"/><br /><sub><b>Greg Bergé</b></sub></a><br /><a href="#ideas-neoziro" title="Ideas, Planning, & Feedback">🤔</a></td>
|
| 138 |
+
<td align="center" valign="top" width="14.28%"><a href="http://audiolion.github.io"><img src="https://avatars1.githubusercontent.com/u/2430381?v=4?s=100" width="100px;" alt="Ryan Castner"/><br /><sub><b>Ryan Castner</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=audiolion" title="Documentation">📖</a></td>
|
| 139 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.dnlsandiego.com"><img src="https://avatars0.githubusercontent.com/u/8008023?v=4?s=100" width="100px;" alt="Daniel Sandiego"/><br /><sub><b>Daniel Sandiego</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dnlsandiego" title="Code">💻</a></td>
|
| 140 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Miklet"><img src="https://avatars2.githubusercontent.com/u/12592677?v=4?s=100" width="100px;" alt="Paweł Mikołajczyk"/><br /><sub><b>Paweł Mikołajczyk</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Miklet" title="Code">💻</a></td>
|
| 141 |
+
<td align="center" valign="top" width="14.28%"><a href="http://co.linkedin.com/in/alejandronanez/"><img src="https://avatars3.githubusercontent.com/u/464978?v=4?s=100" width="100px;" alt="Alejandro Ñáñez Ortiz"/><br /><sub><b>Alejandro Ñáñez Ortiz</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=alejandronanez" title="Documentation">📖</a></td>
|
| 142 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pbomb"><img src="https://avatars0.githubusercontent.com/u/1402095?v=4?s=100" width="100px;" alt="Matt Parrish"/><br /><sub><b>Matt Parrish</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Apbomb" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=pbomb" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=pbomb" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=pbomb" title="Tests">⚠️</a></td>
|
| 143 |
+
</tr>
|
| 144 |
+
<tr>
|
| 145 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wKovacs64"><img src="https://avatars1.githubusercontent.com/u/1288694?v=4?s=100" width="100px;" alt="Justin Hall"/><br /><sub><b>Justin Hall</b></sub></a><br /><a href="#platform-wKovacs64" title="Packaging/porting to new platform">📦</a></td>
|
| 146 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/antoaravinth"><img src="https://avatars1.githubusercontent.com/u/1241511?s=460&v=4?s=100" width="100px;" alt="Anto Aravinth"/><br /><sub><b>Anto Aravinth</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=antoaravinth" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=antoaravinth" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=antoaravinth" title="Documentation">📖</a></td>
|
| 147 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JonahMoses"><img src="https://avatars2.githubusercontent.com/u/3462296?v=4?s=100" width="100px;" alt="Jonah Moses"/><br /><sub><b>Jonah Moses</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=JonahMoses" title="Documentation">📖</a></td>
|
| 148 |
+
<td align="center" valign="top" width="14.28%"><a href="http://team.thebrain.pro"><img src="https://avatars1.githubusercontent.com/u/4002543?v=4?s=100" width="100px;" alt="Łukasz Gandecki"/><br /><sub><b>Łukasz Gandecki</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=lgandecki" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=lgandecki" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=lgandecki" title="Documentation">📖</a></td>
|
| 149 |
+
<td align="center" valign="top" width="14.28%"><a href="https://sompylasar.github.io"><img src="https://avatars2.githubusercontent.com/u/498274?v=4?s=100" width="100px;" alt="Ivan Babak"/><br /><sub><b>Ivan Babak</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Asompylasar" title="Bug reports">🐛</a> <a href="#ideas-sompylasar" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=sompylasar" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=sompylasar" title="Documentation">📖</a></td>
|
| 150 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jday3"><img src="https://avatars3.githubusercontent.com/u/4439618?v=4?s=100" width="100px;" alt="Jesse Day"/><br /><sub><b>Jesse Day</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jday3" title="Code">💻</a></td>
|
| 151 |
+
<td align="center" valign="top" width="14.28%"><a href="http://gnapse.github.io"><img src="https://avatars0.githubusercontent.com/u/15199?v=4?s=100" width="100px;" alt="Ernesto García"/><br /><sub><b>Ernesto García</b></sub></a><br /><a href="#question-gnapse" title="Answering Questions">💬</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=gnapse" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=gnapse" title="Documentation">📖</a></td>
|
| 152 |
+
</tr>
|
| 153 |
+
<tr>
|
| 154 |
+
<td align="center" valign="top" width="14.28%"><a href="http://jomaxx.com"><img src="https://avatars2.githubusercontent.com/u/2747424?v=4?s=100" width="100px;" alt="Josef Maxx Blake"/><br /><sub><b>Josef Maxx Blake</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jomaxx" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=jomaxx" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=jomaxx" title="Tests">⚠️</a></td>
|
| 155 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alecook"><img src="https://avatars3.githubusercontent.com/u/725236?v=4?s=100" width="100px;" alt="Alex Cook"/><br /><sub><b>Alex Cook</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=alecook" title="Documentation">📖</a> <a href="#example-alecook" title="Examples">💡</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Aalecook" title="Reviewed Pull Requests">👀</a></td>
|
| 156 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dfcook"><img src="https://avatars3.githubusercontent.com/u/10348212?v=4?s=100" width="100px;" alt="Daniel Cook"/><br /><sub><b>Daniel Cook</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dfcook" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=dfcook" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=dfcook" title="Tests">⚠️</a></td>
|
| 157 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/thchia"><img src="https://avatars2.githubusercontent.com/u/21194045?s=400&v=4?s=100" width="100px;" alt="Thomas Chia"/><br /><sub><b>Thomas Chia</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Athchia" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=thchia" title="Code">💻</a></td>
|
| 158 |
+
<td align="center" valign="top" width="14.28%"><a href="http://timdeschryver.dev"><img src="https://avatars.githubusercontent.com/u/28659384?v=4?s=100" width="100px;" alt="Tim Deschryver"/><br /><sub><b>Tim Deschryver</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=timdeschryver" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=timdeschryver" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Atimdeschryver" title="Reviewed Pull Requests">👀</a></td>
|
| 159 |
+
<td align="center" valign="top" width="14.28%"><a href="https://alexkrolick.com"><img src="https://avatars3.githubusercontent.com/u/1571667?v=4?s=100" width="100px;" alt="Alex Krolick"/><br /><sub><b>Alex Krolick</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=alexkrolick" title="Code">💻</a></td>
|
| 160 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.maddijoyce.com"><img src="https://avatars2.githubusercontent.com/u/2224291?v=4?s=100" width="100px;" alt="Maddi Joyce"/><br /><sub><b>Maddi Joyce</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=maddijoyce" title="Code">💻</a></td>
|
| 161 |
+
</tr>
|
| 162 |
+
<tr>
|
| 163 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/npeterkamps"><img src="https://avatars1.githubusercontent.com/u/25429764?v=4?s=100" width="100px;" alt="Peter Kamps"/><br /><sub><b>Peter Kamps</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Anpeterkamps" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=npeterkamps" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=npeterkamps" title="Tests">⚠️</a></td>
|
| 164 |
+
<td align="center" valign="top" width="14.28%"><a href="http://jonathanstoye.de"><img src="https://avatars2.githubusercontent.com/u/21689428?v=4?s=100" width="100px;" alt="Jonathan Stoye"/><br /><sub><b>Jonathan Stoye</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=JonathanStoye" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=JonathanStoye" title="Code">💻</a></td>
|
| 165 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yongdamsh"><img src="https://avatars2.githubusercontent.com/u/4126644?v=4?s=100" width="100px;" alt="Sanghyeon Lee"/><br /><sub><b>Sanghyeon Lee</b></sub></a><br /><a href="#example-yongdamsh" title="Examples">💡</a></td>
|
| 166 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Dajust"><img src="https://avatars3.githubusercontent.com/u/8015514?v=4?s=100" width="100px;" alt="Justice Mba "/><br /><sub><b>Justice Mba </b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Dajust" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=Dajust" title="Documentation">📖</a> <a href="#ideas-Dajust" title="Ideas, Planning, & Feedback">🤔</a></td>
|
| 167 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wgcrouch"><img src="https://avatars3.githubusercontent.com/u/340761?v=4?s=100" width="100px;" alt="Wayne Crouch"/><br /><sub><b>Wayne Crouch</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=wgcrouch" title="Code">💻</a></td>
|
| 168 |
+
<td align="center" valign="top" width="14.28%"><a href="http://benjaminelliott.co.uk"><img src="https://avatars1.githubusercontent.com/u/4996462?v=4?s=100" width="100px;" alt="Ben Elliott"/><br /><sub><b>Ben Elliott</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=benelliott" title="Code">💻</a></td>
|
| 169 |
+
<td align="center" valign="top" width="14.28%"><a href="http://nuances.co"><img src="https://avatars3.githubusercontent.com/u/577921?v=4?s=100" width="100px;" alt="Ruben Costa"/><br /><sub><b>Ruben Costa</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=rubencosta" title="Code">💻</a></td>
|
| 170 |
+
</tr>
|
| 171 |
+
<tr>
|
| 172 |
+
<td align="center" valign="top" width="14.28%"><a href="http://rbrtsmith.com/"><img src="https://avatars2.githubusercontent.com/u/4982001?v=4?s=100" width="100px;" alt="Robert Smith"/><br /><sub><b>Robert Smith</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Arbrtsmith" title="Bug reports">🐛</a> <a href="#ideas-rbrtsmith" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=rbrtsmith" title="Documentation">📖</a></td>
|
| 173 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dadamssg"><img src="https://avatars3.githubusercontent.com/u/881986?v=4?s=100" width="100px;" alt="dadamssg"/><br /><sub><b>dadamssg</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dadamssg" title="Code">💻</a></td>
|
| 174 |
+
<td align="center" valign="top" width="14.28%"><a href="https://neilkistner.com/"><img src="https://avatars1.githubusercontent.com/u/186971?v=4?s=100" width="100px;" alt="Neil Kistner"/><br /><sub><b>Neil Kistner</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=wyze" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=wyze" title="Tests">⚠️</a></td>
|
| 175 |
+
<td align="center" valign="top" width="14.28%"><a href="http://bdchauvette.net/"><img src="https://avatars3.githubusercontent.com/u/1448597?v=4?s=100" width="100px;" alt="Ben Chauvette"/><br /><sub><b>Ben Chauvette</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=bdchauvette" title="Code">💻</a></td>
|
| 176 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JeffBaumgardt"><img src="https://avatars2.githubusercontent.com/u/777527?v=4?s=100" width="100px;" alt="Jeff Baumgardt"/><br /><sub><b>Jeff Baumgardt</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=JeffBaumgardt" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=JeffBaumgardt" title="Documentation">📖</a></td>
|
| 177 |
+
<td align="center" valign="top" width="14.28%"><a href="http://matchai.me"><img src="https://avatars0.githubusercontent.com/u/4658208?v=4?s=100" width="100px;" alt="Matan Kushner"/><br /><sub><b>Matan Kushner</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=matchai" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=matchai" title="Documentation">📖</a> <a href="#ideas-matchai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=matchai" title="Tests">⚠️</a></td>
|
| 178 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.wendtedesigns.com/"><img src="https://avatars2.githubusercontent.com/u/5779538?v=4?s=100" width="100px;" alt="Alex Wendte"/><br /><sub><b>Alex Wendte</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=themostcolm" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=themostcolm" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=themostcolm" title="Tests">⚠️</a></td>
|
| 179 |
+
</tr>
|
| 180 |
+
<tr>
|
| 181 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ruffle1986"><img src="https://avatars0.githubusercontent.com/u/2196208?v=4?s=100" width="100px;" alt="Tamas Fodor"/><br /><sub><b>Tamas Fodor</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=ruffle1986" title="Documentation">📖</a></td>
|
| 182 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BenjaminEckardt"><img src="https://avatars3.githubusercontent.com/u/14793495?v=4?s=100" width="100px;" alt="Benjamin Eckardt"/><br /><sub><b>Benjamin Eckardt</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=BenjaminEckardt" title="Code">💻</a></td>
|
| 183 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/campbellr"><img src="https://avatars3.githubusercontent.com/u/205752?v=4?s=100" width="100px;" alt="Ryan Campbell"/><br /><sub><b>Ryan Campbell</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=campbellr" title="Documentation">📖</a></td>
|
| 184 |
+
<td align="center" valign="top" width="14.28%"><a href="https://taylor-briggs.com"><img src="https://avatars2.githubusercontent.com/u/1335519?v=4?s=100" width="100px;" alt="Taylor Briggs"/><br /><sub><b>Taylor Briggs</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=TaylorBriggs" title="Tests">⚠️</a></td>
|
| 185 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jgoz"><img src="https://avatars2.githubusercontent.com/u/132233?v=4?s=100" width="100px;" alt="John Gozde"/><br /><sub><b>John Gozde</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jgoz" title="Code">💻</a></td>
|
| 186 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chentsulin"><img src="https://avatars2.githubusercontent.com/u/3382565?v=4?s=100" width="100px;" alt="C. T. Lin"/><br /><sub><b>C. T. Lin</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=chentsulin" title="Documentation">📖</a></td>
|
| 187 |
+
<td align="center" valign="top" width="14.28%"><a href="http://terrencewwong.com"><img src="https://avatars3.githubusercontent.com/u/5312329?v=4?s=100" width="100px;" alt="Terrence Wong"/><br /><sub><b>Terrence Wong</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=terrencewwong" title="Code">💻</a></td>
|
| 188 |
+
</tr>
|
| 189 |
+
<tr>
|
| 190 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.ossfinder.com"><img src="https://avatars0.githubusercontent.com/u/12230408?v=4?s=100" width="100px;" alt="Soo Jae Hwang"/><br /><sub><b>Soo Jae Hwang</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=misoguy" title="Code">💻</a></td>
|
| 191 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RoystonS"><img src="https://avatars0.githubusercontent.com/u/19773?v=4?s=100" width="100px;" alt="Royston Shufflebotham"/><br /><sub><b>Royston Shufflebotham</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3ARoystonS" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=RoystonS" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=RoystonS" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=RoystonS" title="Tests">⚠️</a></td>
|
| 192 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.vadimbrodsky.com"><img src="https://avatars0.githubusercontent.com/u/591673?v=4?s=100" width="100px;" alt="Vadim Brodsky"/><br /><sub><b>Vadim Brodsky</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=VadimBrodsky" title="Code">💻</a></td>
|
| 193 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/eunjae_lee"><img src="https://avatars3.githubusercontent.com/u/499898?v=4?s=100" width="100px;" alt="Eunjae Lee"/><br /><sub><b>Eunjae Lee</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=eunjae-lee" title="Code">💻</a></td>
|
| 194 |
+
<td align="center" valign="top" width="14.28%"><a href="http://davidpeter.me"><img src="https://avatars2.githubusercontent.com/u/167743?v=4?s=100" width="100px;" alt="David Peter"/><br /><sub><b>David Peter</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=sarenji" title="Code">💻</a></td>
|
| 195 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/@puemos"><img src="https://avatars0.githubusercontent.com/u/13174025?v=4?s=100" width="100px;" alt="Shy Alter"/><br /><sub><b>Shy Alter</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=puemos" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=puemos" title="Documentation">📖</a></td>
|
| 196 |
+
<td align="center" valign="top" width="14.28%"><a href="https://lukaszmakuch.pl"><img src="https://avatars1.githubusercontent.com/u/11966621?v=4?s=100" width="100px;" alt="Łukasz Makuch"/><br /><sub><b>Łukasz Makuch</b></sub></a><br /><a href="#platform-lukaszmakuch" title="Packaging/porting to new platform">📦</a></td>
|
| 197 |
+
</tr>
|
| 198 |
+
<tr>
|
| 199 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tylerthehaas"><img src="https://avatars1.githubusercontent.com/u/11150235?v=4?s=100" width="100px;" alt="Tyler Haas"/><br /><sub><b>Tyler Haas</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=tylerthehaas" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=tylerthehaas" title="Tests">⚠️</a></td>
|
| 200 |
+
<td align="center" valign="top" width="14.28%"><a href="http://vesalaakso.com"><img src="https://avatars2.githubusercontent.com/u/482561?v=4?s=100" width="100px;" alt="Vesa Laakso"/><br /><sub><b>Vesa Laakso</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=valscion" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=valscion" title="Tests">⚠️</a></td>
|
| 201 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tolsee"><img src="https://avatars0.githubusercontent.com/u/16590492?v=4?s=100" width="100px;" alt="Tulsi Sapkota"/><br /><sub><b>Tulsi Sapkota</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Tolsee" title="Code">💻</a></td>
|
| 202 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tnunes"><img src="https://avatars1.githubusercontent.com/u/163187?v=4?s=100" width="100px;" alt="Tiago Nunes"/><br /><sub><b>Tiago Nunes</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=tnunes" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=tnunes" title="Tests">⚠️</a></td>
|
| 203 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JaxCavalera"><img src="https://avatars1.githubusercontent.com/u/15429762?v=4?s=100" width="100px;" alt="JaxCavalera"/><br /><sub><b>JaxCavalera</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=JaxCavalera" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3AJaxCavalera" title="Reviewed Pull Requests">👀</a></td>
|
| 204 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bopfer"><img src="https://avatars2.githubusercontent.com/u/824368?v=4?s=100" width="100px;" alt="bopfer"/><br /><sub><b>bopfer</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=bopfer" title="Tests">⚠️</a></td>
|
| 205 |
+
<td align="center" valign="top" width="14.28%"><a href="http://blog.alfrescian.com"><img src="https://avatars0.githubusercontent.com/u/1340740?v=4?s=100" width="100px;" alt="Jan Pfitzner"/><br /><sub><b>Jan Pfitzner</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=alfrescian" title="Code">💻</a></td>
|
| 206 |
+
</tr>
|
| 207 |
+
<tr>
|
| 208 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dbismut"><img src="https://avatars2.githubusercontent.com/u/5003380?v=4?s=100" width="100px;" alt="David"/><br /><sub><b>David</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dbismut" title="Code">💻</a></td>
|
| 209 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/diego_codes"><img src="https://avatars0.githubusercontent.com/u/5973294?v=4?s=100" width="100px;" alt="Diego Hernandez"/><br /><sub><b>Diego Hernandez</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=diego-codes" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=diego-codes" title="Tests">⚠️</a></td>
|
| 210 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/foray1010"><img src="https://avatars3.githubusercontent.com/u/3212221?v=4?s=100" width="100px;" alt="Alex Young"/><br /><sub><b>Alex Young</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=foray1010" title="Code">💻</a></td>
|
| 211 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/paularmstrong"><img src="https://avatars1.githubusercontent.com/u/33297?v=4?s=100" width="100px;" alt="Paul Armstrong"/><br /><sub><b>Paul Armstrong</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=paularmstrong" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=paularmstrong" title="Tests">⚠️</a></td>
|
| 212 |
+
<td align="center" valign="top" width="14.28%"><a href="https://hu.linkedin.com/pub/tamas-szabo/57/a4b/242"><img src="https://avatars0.githubusercontent.com/u/3720079?v=4?s=100" width="100px;" alt="Tamás Szabó"/><br /><sub><b>Tamás Szabó</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=szabototo89" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=szabototo89" title="Tests">⚠️</a></td>
|
| 213 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/dylan_piercey"><img src="https://avatars2.githubusercontent.com/u/4985201?v=4?s=100" width="100px;" alt="Dylan Piercey"/><br /><sub><b>Dylan Piercey</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=DylanPiercey" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=DylanPiercey" title="Tests">⚠️</a></td>
|
| 214 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/michaellasky"><img src="https://avatars2.githubusercontent.com/u/6646599?v=4?s=100" width="100px;" alt="Michael Lasky"/><br /><sub><b>Michael Lasky</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=michaellasky" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=michaellasky" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=michaellasky" title="Documentation">📖</a></td>
|
| 215 |
+
</tr>
|
| 216 |
+
<tr>
|
| 217 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/sebsilbermann"><img src="https://avatars3.githubusercontent.com/u/12292047?v=4?s=100" width="100px;" alt="Sebastian Silbermann"/><br /><sub><b>Sebastian Silbermann</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=eps1lon" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=eps1lon" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=eps1lon" title="Documentation">📖</a> <a href="#infra-eps1lon" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Aeps1lon" title="Reviewed Pull Requests">👀</a></td>
|
| 218 |
+
<td align="center" valign="top" width="14.28%"><a href="https://dylanvann.com/"><img src="https://avatars0.githubusercontent.com/u/1537615?v=4?s=100" width="100px;" alt="Dylan Vann"/><br /><sub><b>Dylan Vann</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=DylanVann" title="Code">💻</a></td>
|
| 219 |
+
<td align="center" valign="top" width="14.28%"><a href="https://afontcu.dev"><img src="https://avatars0.githubusercontent.com/u/9197791?v=4?s=100" width="100px;" alt="Adrià Fontcuberta"/><br /><sub><b>Adrià Fontcuberta</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=afontcu" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=afontcu" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=afontcu" title="Documentation">📖</a></td>
|
| 220 |
+
<td align="center" valign="top" width="14.28%"><a href="http://thomlom.dev"><img src="https://avatars3.githubusercontent.com/u/16003285?v=4?s=100" width="100px;" alt="Thomas Lombart"/><br /><sub><b>Thomas Lombart</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=thomlom" title="Code">💻</a></td>
|
| 221 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/SavePointSam"><img src="https://avatars0.githubusercontent.com/u/8203211?v=4?s=100" width="100px;" alt="Sam Horton"/><br /><sub><b>Sam Horton</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=SavePointSam" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=SavePointSam" title="Tests">⚠️</a></td>
|
| 222 |
+
<td align="center" valign="top" width="14.28%"><a href="http://andrewhillcode.com"><img src="https://avatars1.githubusercontent.com/u/12396191?v=4?s=100" width="100px;" alt="Andrew Hill"/><br /><sub><b>Andrew Hill</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=andrewhillcode" title="Code">💻</a></td>
|
| 223 |
+
<td align="center" valign="top" width="14.28%"><a href="https://amann.me"><img src="https://avatars1.githubusercontent.com/u/4038316?v=4?s=100" width="100px;" alt="Jan Amann"/><br /><sub><b>Jan Amann</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=amannn" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=amannn" title="Tests">⚠️</a></td>
|
| 224 |
+
</tr>
|
| 225 |
+
<tr>
|
| 226 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/brapifra"><img src="https://avatars3.githubusercontent.com/u/17855450?v=4?s=100" width="100px;" alt="Brais Piñeiro"/><br /><sub><b>Brais Piñeiro</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=brapifra" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=brapifra" title="Tests">⚠️</a></td>
|
| 227 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.dominykas.com/"><img src="https://avatars1.githubusercontent.com/u/505619?v=4?s=100" width="100px;" alt="Dominykas Blyžė"/><br /><sub><b>Dominykas Blyžė</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dominykas" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=dominykas" title="Tests">⚠️</a></td>
|
| 228 |
+
<td align="center" valign="top" width="14.28%"><a href="http://olzhas.de"><img src="https://avatars3.githubusercontent.com/u/15848876?v=4?s=100" width="100px;" alt="Olzhas Askar"/><br /><sub><b>Olzhas Askar</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=pheeria" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=pheeria" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=pheeria" title="Documentation">📖</a></td>
|
| 229 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/mbelsky_"><img src="https://avatars1.githubusercontent.com/u/3923527?v=4?s=100" width="100px;" alt="Max Belsky"/><br /><sub><b>Max Belsky</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=mbelsky" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=mbelsky" title="Tests">⚠️</a></td>
|
| 230 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mmantel"><img src="https://avatars2.githubusercontent.com/u/1326403?v=4?s=100" width="100px;" alt="Michael Mantel"/><br /><sub><b>Michael Mantel</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=mmantel" title="Tests">⚠️</a></td>
|
| 231 |
+
<td align="center" valign="top" width="14.28%"><a href="https://tomdoes.tech/"><img src="https://avatars1.githubusercontent.com/u/8683577?v=4?s=100" width="100px;" alt="Tom Nagle"/><br /><sub><b>Tom Nagle</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=tomanagle" title="Code">💻</a></td>
|
| 232 |
+
<td align="center" valign="top" width="14.28%"><a href="http://westbrookjohnson.com"><img src="https://avatars0.githubusercontent.com/u/1156657?v=4?s=100" width="100px;" alt="Westbrook Johnson"/><br /><sub><b>Westbrook Johnson</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Westbrook" title="Code">💻</a></td>
|
| 233 |
+
</tr>
|
| 234 |
+
<tr>
|
| 235 |
+
<td align="center" valign="top" width="14.28%"><a href="https://aziz.js.org"><img src="https://avatars3.githubusercontent.com/u/17024120?v=4?s=100" width="100px;" alt="Mohammad Aziz"/><br /><sub><b>Mohammad Aziz</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=iAziz786" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=iAziz786" title="Tests">⚠️</a></td>
|
| 236 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/seetdev/"><img src="https://avatars2.githubusercontent.com/u/35116035?v=4?s=100" width="100px;" alt="seetdev"/><br /><sub><b>seetdev</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=seetdev" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=seetdev" title="Code">💻</a></td>
|
| 237 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/xgbuils"><img src="https://avatars2.githubusercontent.com/u/6483614?v=4?s=100" width="100px;" alt="Xavier Garcia Buils"/><br /><sub><b>Xavier Garcia Buils</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=xgbuils" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=xgbuils" title="Tests">⚠️</a></td>
|
| 238 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aw-davidson"><img src="https://avatars2.githubusercontent.com/u/32170938?v=4?s=100" width="100px;" alt="aw-davidson"/><br /><sub><b>aw-davidson</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=aw-davidson" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=aw-davidson" title="Tests">⚠️</a></td>
|
| 239 |
+
<td align="center" valign="top" width="14.28%"><a href="https://michaeldeboey.be"><img src="https://avatars3.githubusercontent.com/u/6643991?v=4?s=100" width="100px;" alt="Michaël De Boey"/><br /><sub><b>Michaël De Boey</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=MichaelDeBoey" title="Code">💻</a></td>
|
| 240 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/minh_ngvyen"><img src="https://avatars3.githubusercontent.com/u/2852660?v=4?s=100" width="100px;" alt="Minh Nguyen"/><br /><sub><b>Minh Nguyen</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=NMinhNguyen" title="Code">💻</a></td>
|
| 241 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/egilsster"><img src="https://avatars0.githubusercontent.com/u/5672257?v=4?s=100" width="100px;" alt="Egill Sveinbjörnsson"/><br /><sub><b>Egill Sveinbjörnsson</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=egilsster" title="Code">💻</a></td>
|
| 242 |
+
</tr>
|
| 243 |
+
<tr>
|
| 244 |
+
<td align="center" valign="top" width="14.28%"><a href="http://pustovalov.dev"><img src="https://avatars2.githubusercontent.com/u/1568885?v=4?s=100" width="100px;" alt="Pavel Pustovalov"/><br /><sub><b>Pavel Pustovalov</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=pustovalov" title="Documentation">📖</a></td>
|
| 245 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/apalaniuk"><img src="https://avatars1.githubusercontent.com/u/17710124?v=4?s=100" width="100px;" alt="Adam Palaniuk"/><br /><sub><b>Adam Palaniuk</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=apalaniuk" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=apalaniuk" title="Tests">⚠️</a></td>
|
| 246 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Yama-Tomo"><img src="https://avatars0.githubusercontent.com/u/4970917?v=4?s=100" width="100px;" alt="Yama-Tomo"/><br /><sub><b>Yama-Tomo</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Yama-Tomo" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=Yama-Tomo" title="Tests">⚠️</a></td>
|
| 247 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/airjp73"><img src="https://avatars2.githubusercontent.com/u/25882770?v=4?s=100" width="100px;" alt="Aaron Pettengill"/><br /><sub><b>Aaron Pettengill</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=airjp73" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=airjp73" title="Tests">⚠️</a></td>
|
| 248 |
+
<td align="center" valign="top" width="14.28%"><a href="http://kwboyd.com"><img src="https://avatars0.githubusercontent.com/u/13855750?v=4?s=100" width="100px;" alt="Kate W. Boyd"/><br /><sub><b>Kate W. Boyd</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=kwboyd" title="Code">💻</a></td>
|
| 249 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rahulchavan30"><img src="https://avatars2.githubusercontent.com/u/5296464?v=4?s=100" width="100px;" alt="Rahul Suryakanth"/><br /><sub><b>Rahul Suryakanth</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=rahulchavan30" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=rahulchavan30" title="Tests">⚠️</a></td>
|
| 250 |
+
<td align="center" valign="top" width="14.28%"><a href="https://jamie.tokyo"><img src="https://avatars0.githubusercontent.com/u/5964236?v=4?s=100" width="100px;" alt="Jamie"/><br /><sub><b>Jamie</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jamsinclair" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=jamsinclair" title="Tests">⚠️</a></td>
|
| 251 |
+
</tr>
|
| 252 |
+
<tr>
|
| 253 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nstepien"><img src="https://avatars0.githubusercontent.com/u/567105?v=4?s=100" width="100px;" alt="Nicolas Stepien"/><br /><sub><b>Nicolas Stepien</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=nstepien" title="Code">💻</a></td>
|
| 254 |
+
<td align="center" valign="top" width="14.28%"><a href="https://knpw.rs"><img src="https://avatars0.githubusercontent.com/u/174864?v=4?s=100" width="100px;" alt="Ken Powers"/><br /><sub><b>Ken Powers</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=knpwrs" title="Code">💻</a></td>
|
| 255 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mzdunek93"><img src="https://avatars0.githubusercontent.com/u/10826511?v=4?s=100" width="100px;" alt="Michał Zdunek"/><br /><sub><b>Michał Zdunek</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=mzdunek93" title="Code">💻</a></td>
|
| 256 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Lagily"><img src="https://avatars2.githubusercontent.com/u/42535205?v=4?s=100" width="100px;" alt="Ali Nasserzadeh"/><br /><sub><b>Ali Nasserzadeh</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Lagily" title="Code">💻</a></td>
|
| 257 |
+
<td align="center" valign="top" width="14.28%"><a href="https://darekkay.com"><img src="https://avatars0.githubusercontent.com/u/3101914?v=4?s=100" width="100px;" alt="Darek Kay"/><br /><sub><b>Darek Kay</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=darekkay" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=darekkay" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=darekkay" title="Tests">⚠️</a></td>
|
| 258 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Lukas-Kullmann"><img src="https://avatars0.githubusercontent.com/u/387547?v=4?s=100" width="100px;" alt="Lukas"/><br /><sub><b>Lukas</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Lukas-Kullmann" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=Lukas-Kullmann" title="Tests">⚠️</a></td>
|
| 259 |
+
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/pelotom"><img src="https://avatars2.githubusercontent.com/u/128019?v=4?s=100" width="100px;" alt="Tom Crockett"/><br /><sub><b>Tom Crockett</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=pelotom" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=pelotom" title="Tests">⚠️</a></td>
|
| 260 |
+
</tr>
|
| 261 |
+
<tr>
|
| 262 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/appleJax"><img src="https://avatars1.githubusercontent.com/u/13618860?v=4?s=100" width="100px;" alt="Kevin Brewer"/><br /><sub><b>Kevin Brewer</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=appleJax" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=appleJax" title="Tests">⚠️</a></td>
|
| 263 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/benmonro"><img src="https://avatars3.githubusercontent.com/u/399236?v=4?s=100" width="100px;" alt="Ben Monro"/><br /><sub><b>Ben Monro</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=benmonro" title="Code">💻</a> <a href="#ideas-benmonro" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=benmonro" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=benmonro" title="Documentation">📖</a></td>
|
| 264 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/smeijer"><img src="https://avatars1.githubusercontent.com/u/1196524?v=4?s=100" width="100px;" alt="Stephan Meijer"/><br /><sub><b>Stephan Meijer</b></sub></a><br /><a href="#ideas-smeijer" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=smeijer" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=smeijer" title="Tests">⚠️</a></td>
|
| 265 |
+
<td align="center" valign="top" width="14.28%"><a href="https://joaoforja.com/"><img src="https://avatars2.githubusercontent.com/u/7002157?v=4?s=100" width="100px;" alt="João Forja"/><br /><sub><b>João Forja</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Jnforja" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=Jnforja" title="Tests">⚠️</a></td>
|
| 266 |
+
<td align="center" valign="top" width="14.28%"><a href="https://nickmccurdy.com/"><img src="https://avatars0.githubusercontent.com/u/927220?v=4?s=100" width="100px;" alt="Nick McCurdy"/><br /><sub><b>Nick McCurdy</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=nickmccurdy" title="Documentation">📖</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=nickmccurdy" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=nickmccurdy" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Anickmccurdy" title="Reviewed Pull Requests">👀</a> <a href="#infra-nickmccurdy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| 267 |
+
<td align="center" valign="top" width="14.28%"><a href="http://calebmer.com"><img src="https://avatars1.githubusercontent.com/u/8282507?v=4?s=100" width="100px;" alt="Caleb Meredith"/><br /><sub><b>Caleb Meredith</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=calebmer" title="Code">💻</a></td>
|
| 268 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marcosvega91"><img src="https://avatars2.githubusercontent.com/u/5365582?v=4?s=100" width="100px;" alt="Marco Moretti"/><br /><sub><b>Marco Moretti</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=marcosvega91" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=marcosvega91" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Amarcosvega91" title="Reviewed Pull Requests">👀</a></td>
|
| 269 |
+
</tr>
|
| 270 |
+
<tr>
|
| 271 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tjefferson08"><img src="https://avatars2.githubusercontent.com/u/3535390?v=4?s=100" width="100px;" alt="Travis Jefferson"/><br /><sub><b>Travis Jefferson</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=tjefferson08" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=tjefferson08" title="Tests">⚠️</a></td>
|
| 272 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mdjastrzebski"><img src="https://avatars2.githubusercontent.com/u/6368606?v=4?s=100" width="100px;" alt="Maciej Jastrzebski"/><br /><sub><b>Maciej Jastrzebski</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Amdjastrzebski" title="Bug reports">🐛</a></td>
|
| 273 |
+
<td align="center" valign="top" width="14.28%"><a href="https://commonlit.org"><img src="https://avatars3.githubusercontent.com/u/319471?v=4?s=100" width="100px;" alt="Geoff Harcourt"/><br /><sub><b>Geoff Harcourt</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=geoffharcourt" title="Code">💻</a></td>
|
| 274 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars1.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt="Josh Goldberg"/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=JoshuaKGoldberg" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=JoshuaKGoldberg" title="Tests">⚠️</a></td>
|
| 275 |
+
<td align="center" valign="top" width="14.28%"><a href="http://kengregory.com"><img src="https://avatars0.githubusercontent.com/u/3155127?v=4?s=100" width="100px;" alt="Ken Gregory"/><br /><sub><b>Ken Gregory</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=kgregory" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=kgregory" title="Tests">⚠️</a></td>
|
| 276 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.jacobparis.com/"><img src="https://avatars2.githubusercontent.com/u/5633704?v=4?s=100" width="100px;" alt="Jacob Paris"/><br /><sub><b>Jacob Paris</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=JacobParis" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=JacobParis" title="Tests">⚠️</a></td>
|
| 277 |
+
<td align="center" valign="top" width="14.28%"><a href="https://keiya01.github.io/portfolio"><img src="https://avatars1.githubusercontent.com/u/34934510?v=4?s=100" width="100px;" alt="keiya sasaki"/><br /><sub><b>keiya sasaki</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=keiya01" title="Documentation">📖</a></td>
|
| 278 |
+
</tr>
|
| 279 |
+
<tr>
|
| 280 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/idanen"><img src="https://avatars2.githubusercontent.com/u/1687893?v=4?s=100" width="100px;" alt="Idan Entin"/><br /><sub><b>Idan Entin</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=idanen" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=idanen" title="Tests">⚠️</a></td>
|
| 281 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/deniz-susman-92b40a145/"><img src="https://avatars1.githubusercontent.com/u/39295979?v=4?s=100" width="100px;" alt="Deniz Susman"/><br /><sub><b>Deniz Susman</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=DenrizSusam" title="Code">💻</a></td>
|
| 282 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/delca85"><img src="https://avatars1.githubusercontent.com/u/4076043?v=4?s=100" width="100px;" alt="Bianca Del Carretto"/><br /><sub><b>Bianca Del Carretto</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=delca85" title="Tests">⚠️</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=delca85" title="Code">💻</a></td>
|
| 283 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/joshlalonde3/"><img src="https://avatars3.githubusercontent.com/u/9097492?v=4?s=100" width="100px;" alt="Josh Lalonde"/><br /><sub><b>Josh Lalonde</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=ryuuji3" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=ryuuji3" title="Tests">⚠️</a></td>
|
| 284 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ipap360"><img src="https://avatars2.githubusercontent.com/u/11017666?v=4?s=100" width="100px;" alt="Ioannis Papadopoulos"/><br /><sub><b>Ioannis Papadopoulos</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=ipap360" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=ipap360" title="Tests">⚠️</a></td>
|
| 285 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/maxnewlands"><img src="https://avatars3.githubusercontent.com/u/1304166?v=4?s=100" width="100px;" alt="Maxwell Newlands"/><br /><sub><b>Maxwell Newlands</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=maxnewlands" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=maxnewlands" title="Tests">⚠️</a></td>
|
| 286 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.jaredlux.com"><img src="https://avatars0.githubusercontent.com/u/450478?v=4?s=100" width="100px;" alt="Jared Luxenberg"/><br /><sub><b>Jared Luxenberg</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jluxenberg" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=jluxenberg" title="Tests">⚠️</a></td>
|
| 287 |
+
</tr>
|
| 288 |
+
<tr>
|
| 289 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Snizhana"><img src="https://avatars3.githubusercontent.com/u/18139946?v=4?s=100" width="100px;" alt="snizhana"/><br /><sub><b>snizhana</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Snizhana" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=Snizhana" title="Tests">⚠️</a></td>
|
| 290 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/micha149"><img src="https://avatars2.githubusercontent.com/u/298880?v=4?s=100" width="100px;" alt="Michael van Engelshoven"/><br /><sub><b>Michael van Engelshoven</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Amicha149" title="Reviewed Pull Requests">👀</a></td>
|
| 291 |
+
<td align="center" valign="top" width="14.28%"><a href="https://ashertuggle.wixsite.com/portfolio"><img src="https://avatars2.githubusercontent.com/u/10679635?v=4?s=100" width="100px;" alt="Asher Tuggle"/><br /><sub><b>Asher Tuggle</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Aawesomeunleashed" title="Bug reports">🐛</a></td>
|
| 292 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/winterlamon"><img src="https://avatars0.githubusercontent.com/u/16295605?v=4?s=100" width="100px;" alt="Winter LaMon"/><br /><sub><b>Winter LaMon</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=winterlamon" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=winterlamon" title="Tests">⚠️</a></td>
|
| 293 |
+
<td align="center" valign="top" width="14.28%"><a href="http://victorandcode.com"><img src="https://avatars0.githubusercontent.com/u/18427801?v=4?s=100" width="100px;" alt="Victor Cordova"/><br /><sub><b>Victor Cordova</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=victorandcode" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=victorandcode" title="Tests">⚠️</a></td>
|
| 294 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/slowselfip"><img src="https://avatars3.githubusercontent.com/u/9762906?v=4?s=100" width="100px;" alt="slowselfip"/><br /><sub><b>slowselfip</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Aslowselfip" title="Bug reports">🐛</a></td>
|
| 295 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Semigradsky"><img src="https://avatars3.githubusercontent.com/u/1198848?v=4?s=100" width="100px;" alt="Dmitry Semigradsky"/><br /><sub><b>Dmitry Semigradsky</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Semigradsky" title="Code">💻</a></td>
|
| 296 |
+
</tr>
|
| 297 |
+
<tr>
|
| 298 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tismas"><img src="https://avatars2.githubusercontent.com/u/13601275?v=4?s=100" width="100px;" alt="Adam"/><br /><sub><b>Adam</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Tismas" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=Tismas" title="Tests">⚠️</a></td>
|
| 299 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/balavishnuvj"><img src="https://avatars3.githubusercontent.com/u/13718688?v=4?s=100" width="100px;" alt="balavishnuvj"/><br /><sub><b>balavishnuvj</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=balavishnuvj" title="Code">💻</a></td>
|
| 300 |
+
<td align="center" valign="top" width="14.28%"><a href="https://chriscolborne.com"><img src="https://avatars2.githubusercontent.com/u/101371?v=4?s=100" width="100px;" alt="Chris Colborne"/><br /><sub><b>Chris Colborne</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=zorfling" title="Code">💻</a></td>
|
| 301 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/romain-trotard"><img src="https://avatars0.githubusercontent.com/u/17161484?v=4?s=100" width="100px;" alt="Romain Trotard"/><br /><sub><b>Romain Trotard</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=romain-trotard" title="Code">💻</a></td>
|
| 302 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.thomasmarshall.com"><img src="https://avatars0.githubusercontent.com/u/770763?v=4?s=100" width="100px;" alt="Thomas Marshall"/><br /><sub><b>Thomas Marshall</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=thomasmarshall" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=thomasmarshall" title="Tests">⚠️</a></td>
|
| 303 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/johnjesse"><img src="https://avatars1.githubusercontent.com/u/6839660?v=4?s=100" width="100px;" alt="johnjessewood"/><br /><sub><b>johnjessewood</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Ajohnjesse" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=johnjesse" title="Code">💻</a></td>
|
| 304 |
+
<td align="center" valign="top" width="14.28%"><a href="https://codepen.io/ariperkkio/"><img src="https://avatars2.githubusercontent.com/u/14806298?v=4?s=100" width="100px;" alt="Ari Perkkiö"/><br /><sub><b>Ari Perkkiö</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3AAriPerkkio" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=AriPerkkio" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=AriPerkkio" title="Documentation">📖</a></td>
|
| 305 |
+
</tr>
|
| 306 |
+
<tr>
|
| 307 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nathanforce"><img src="https://avatars2.githubusercontent.com/u/6694194?v=4?s=100" width="100px;" alt="Nathan Force"/><br /><sub><b>Nathan Force</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=nathanforce" title="Code">💻</a></td>
|
| 308 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ph-fritsche"><img src="https://avatars.githubusercontent.com/u/39068198?v=4?s=100" width="100px;" alt="Philipp Fritsche"/><br /><sub><b>Philipp Fritsche</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=ph-fritsche" title="Code">💻</a></td>
|
| 309 |
+
<td align="center" valign="top" width="14.28%"><a href="https://medium.com/@renatoalencar"><img src="https://avatars.githubusercontent.com/u/6964593?v=4?s=100" width="100px;" alt="Renato Alencar"/><br /><sub><b>Renato Alencar</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=renatoalencar" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=renatoalencar" title="Tests">⚠️</a></td>
|
| 310 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SimenB"><img src="https://avatars.githubusercontent.com/u/1404810?v=4?s=100" width="100px;" alt="Simen Bekkhus"/><br /><sub><b>Simen Bekkhus</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3ASimenB" title="Bug reports">🐛</a></td>
|
| 311 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gaearon"><img src="https://avatars.githubusercontent.com/u/810438?v=4?s=100" width="100px;" alt="Dan Abramov"/><br /><sub><b>Dan Abramov</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Agaearon" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/dom-testing-library/pulls?q=is%3Apr+reviewed-by%3Agaearon" title="Reviewed Pull Requests">👀</a></td>
|
| 312 |
+
<td align="center" valign="top" width="14.28%"><a href="https://matan.io"><img src="https://avatars.githubusercontent.com/u/12711091?v=4?s=100" width="100px;" alt="Matan Borenkraout"/><br /><sub><b>Matan Borenkraout</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=MatanBobi" title="Code">💻</a></td>
|
| 313 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/simcha90"><img src="https://avatars.githubusercontent.com/u/56388545?v=4?s=100" width="100px;" alt="simcha90"/><br /><sub><b>simcha90</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=simcha90" title="Code">💻</a></td>
|
| 314 |
+
</tr>
|
| 315 |
+
<tr>
|
| 316 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amitmiran137"><img src="https://avatars.githubusercontent.com/u/47772523?v=4?s=100" width="100px;" alt="Amit Miran"/><br /><sub><b>Amit Miran</b></sub></a><br /><a href="#infra-amitmiran137" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| 317 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/leschdom"><img src="https://avatars.githubusercontent.com/u/62334278?v=4?s=100" width="100px;" alt="Dominik Lesch"/><br /><sub><b>Dominik Lesch</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=leschdom" title="Documentation">📖</a></td>
|
| 318 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/G-Rath"><img src="https://avatars.githubusercontent.com/u/3151613?v=4?s=100" width="100px;" alt="Gareth Jones"/><br /><sub><b>Gareth Jones</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=G-Rath" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=G-Rath" title="Tests">⚠️</a></td>
|
| 319 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/riotrah"><img src="https://avatars.githubusercontent.com/u/22646419?v=4?s=100" width="100px;" alt="Rayat Rahman"/><br /><sub><b>Rayat Rahman</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=riotrah" title="Code">💻</a></td>
|
| 320 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/savcni01"><img src="https://avatars.githubusercontent.com/u/18025894?v=4?s=100" width="100px;" alt="Nik Savchenko"/><br /><sub><b>Nik Savchenko</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=savcni01" title="Code">💻</a></td>
|
| 321 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.hawkeye.dog"><img src="https://avatars.githubusercontent.com/u/7245931?v=4?s=100" width="100px;" alt="Kevin Fleischman"/><br /><sub><b>Kevin Fleischman</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=istateside" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/commits?author=istateside" title="Tests">⚠️</a></td>
|
| 322 |
+
<td align="center" valign="top" width="14.28%"><a href="http://dfdx.us"><img src="https://avatars.githubusercontent.com/u/3087358?v=4?s=100" width="100px;" alt="Beth Hitch"/><br /><sub><b>Beth Hitch</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dfoverdx" title="Code">💻</a></td>
|
| 323 |
+
</tr>
|
| 324 |
+
<tr>
|
| 325 |
+
<td align="center" valign="top" width="14.28%"><a href="http://www.jacklaurence.net"><img src="https://avatars.githubusercontent.com/u/12763356?v=4?s=100" width="100px;" alt="Jack Laurence"/><br /><sub><b>Jack Laurence</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jacklaurencegaray" title="Code">💻</a></td>
|
| 326 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Lusito"><img src="https://avatars.githubusercontent.com/u/53570854?v=4?s=100" width="100px;" alt="SantoJambit"/><br /><sub><b>SantoJambit</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=SantoJambit" title="Code">💻</a></td>
|
| 327 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mittalyashu"><img src="https://avatars.githubusercontent.com/u/29014463?v=4?s=100" width="100px;" alt="Yashu Mittal"/><br /><sub><b>Yashu Mittal</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=mittalyashu" title="Documentation">📖</a></td>
|
| 328 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/IanVS"><img src="https://avatars.githubusercontent.com/u/4616705?v=4?s=100" width="100px;" alt="Ian VanSchooten"/><br /><sub><b>Ian VanSchooten</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=IanVS" title="Code">💻</a></td>
|
| 329 |
+
<td align="center" valign="top" width="14.28%"><a href="http://supervanya.com"><img src="https://avatars.githubusercontent.com/u/12336038?v=4?s=100" width="100px;" alt="Vanya Prokopovich"/><br /><sub><b>Vanya Prokopovich</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Asupervanya" title="Bug reports">🐛</a></td>
|
| 330 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jrnail23"><img src="https://avatars.githubusercontent.com/u/392612?v=4?s=100" width="100px;" alt="James Nail"/><br /><sub><b>James Nail</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Ajrnail23" title="Bug reports">🐛</a></td>
|
| 331 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/robcaldecott"><img src="https://avatars.githubusercontent.com/u/796702?v=4?s=100" width="100px;" alt="Rob Caldecott"/><br /><sub><b>Rob Caldecott</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Arobcaldecott" title="Bug reports">🐛</a></td>
|
| 332 |
+
</tr>
|
| 333 |
+
<tr>
|
| 334 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Dennis273"><img src="https://avatars.githubusercontent.com/u/19815164?v=4?s=100" width="100px;" alt="Dennis273"/><br /><sub><b>Dennis273</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Dennis273" title="Code">💻</a></td>
|
| 335 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.jacksonhardaker.dev"><img src="https://avatars.githubusercontent.com/u/7596320?v=4?s=100" width="100px;" alt="Jackson Hardaker"/><br /><sub><b>Jackson Hardaker</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jacksonhardaker" title="Tests">⚠️</a></td>
|
| 336 |
+
<td align="center" valign="top" width="14.28%"><a href="https://www.robin-drexler.com/"><img src="https://avatars.githubusercontent.com/u/474248?v=4?s=100" width="100px;" alt="Robin Drexler"/><br /><sub><b>Robin Drexler</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=robin-drexler" title="Code">💻</a></td>
|
| 337 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dolevoper"><img src="https://avatars.githubusercontent.com/u/53278705?v=4?s=100" width="100px;" alt="Omer Dolev"/><br /><sub><b>Omer Dolev</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=dolevoper" title="Code">💻</a></td>
|
| 338 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Lirlev48"><img src="https://avatars.githubusercontent.com/u/58209233?v=4?s=100" width="100px;" alt="Lirlev48"/><br /><sub><b>Lirlev48</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=Lirlev48" title="Code">💻</a></td>
|
| 339 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kalmi"><img src="https://avatars.githubusercontent.com/u/54426?v=4?s=100" width="100px;" alt="Tarnay Kálmán"/><br /><sub><b>Tarnay Kálmán</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=kalmi" title="Code">💻</a></td>
|
| 340 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MynockSpit"><img src="https://avatars.githubusercontent.com/u/5713867?v=4?s=100" width="100px;" alt="Than Hutchins"/><br /><sub><b>Than Hutchins</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=MynockSpit" title="Code">💻</a></td>
|
| 341 |
+
</tr>
|
| 342 |
+
<tr>
|
| 343 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/raplemie"><img src="https://avatars.githubusercontent.com/u/1904889?v=4?s=100" width="100px;" alt="Raphaël LEMIEUX"/><br /><sub><b>Raphaël LEMIEUX</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=raplemie" title="Code">💻</a></td>
|
| 344 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/arthurlvilasboas"><img src="https://avatars.githubusercontent.com/u/95368212?v=4?s=100" width="100px;" alt="Arthur Lauck Vilas Boas"/><br /><sub><b>Arthur Lauck Vilas Boas</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=arthurlvilasboas" title="Documentation">📖</a></td>
|
| 345 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DaniAcu"><img src="https://avatars.githubusercontent.com/u/26409015?v=4?s=100" width="100px;" alt="Daniel Acuña"/><br /><sub><b>Daniel Acuña</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=DaniAcu" title="Code">💻</a></td>
|
| 346 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jlp-craigmorten"><img src="https://avatars.githubusercontent.com/u/124147726?v=4?s=100" width="100px;" alt="Craig Morten"/><br /><sub><b>Craig Morten</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=jlp-craigmorten" title="Code">💻</a> <a href="#question-jlp-craigmorten" title="Answering Questions">💬</a></td>
|
| 347 |
+
<td align="center" valign="top" width="14.28%"><a href="https://naor.dev"><img src="https://avatars.githubusercontent.com/u/6171622?v=4?s=100" width="100px;" alt="Naor Peled"/><br /><sub><b>Naor Peled</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=naorpeled" title="Code">💻</a></td>
|
| 348 |
+
<td align="center" valign="top" width="14.28%"><a href="http://everlong.org/"><img src="https://avatars.githubusercontent.com/u/454175?v=4?s=100" width="100px;" alt="Julien Wajsberg"/><br /><sub><b>Julien Wajsberg</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=julienw" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3Ajulienw" title="Bug reports">🐛</a></td>
|
| 349 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KevinBon"><img src="https://avatars.githubusercontent.com/u/1910927?v=4?s=100" width="100px;" alt="Kevin BON"/><br /><sub><b>Kevin BON</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=KevinBon" title="Code">💻</a> <a href="https://github.com/testing-library/dom-testing-library/issues?q=author%3AKevinBon" title="Bug reports">🐛</a></td>
|
| 350 |
+
</tr>
|
| 351 |
+
<tr>
|
| 352 |
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sieem"><img src="https://avatars.githubusercontent.com/u/36861085?v=4?s=100" width="100px;" alt="sieem"/><br /><sub><b>sieem</b></sub></a><br /><a href="https://github.com/testing-library/dom-testing-library/commits?author=sieem" title="Code">💻</a></td>
|
| 353 |
+
</tr>
|
| 354 |
+
</tbody>
|
| 355 |
+
</table>
|
| 356 |
+
|
| 357 |
+
<!-- markdownlint-restore -->
|
| 358 |
+
<!-- prettier-ignore-end -->
|
| 359 |
+
|
| 360 |
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
| 361 |
+
|
| 362 |
+
This project follows the [all-contributors][all-contributors] specification.
|
| 363 |
+
Contributions of any kind welcome!
|
| 364 |
+
|
| 365 |
+
## LICENSE
|
| 366 |
+
|
| 367 |
+
[MIT](LICENSE)
|
| 368 |
+
|
| 369 |
+
<!-- prettier-ignore-start -->
|
| 370 |
+
|
| 371 |
+
[npm]: https://www.npmjs.com/
|
| 372 |
+
[node]: https://nodejs.org
|
| 373 |
+
[build-badge]: https://img.shields.io/github/workflow/status/testing-library/dom-testing-library/validate?logo=github&style=flat-square
|
| 374 |
+
[build]: https://github.com/testing-library/dom-testing-library/actions?query=workflow%3Avalidate
|
| 375 |
+
[coverage-badge]: https://img.shields.io/codecov/c/github/testing-library/dom-testing-library.svg?style=flat-square
|
| 376 |
+
[coverage]: https://codecov.io/github/testing-library/dom-testing-library
|
| 377 |
+
[version-badge]: https://img.shields.io/npm/v/@testing-library/dom.svg?style=flat-square
|
| 378 |
+
[package]: https://www.npmjs.com/package/@testing-library/dom
|
| 379 |
+
[downloads-badge]: https://img.shields.io/npm/dm/@testing-library/dom.svg?style=flat-square
|
| 380 |
+
[npmtrends]: http://www.npmtrends.com/@testing-library/dom
|
| 381 |
+
[license-badge]: https://img.shields.io/npm/l/@testing-library/dom.svg?style=flat-square
|
| 382 |
+
[license]: https://github.com/testing-library/dom-testing-library/blob/main/LICENSE
|
| 383 |
+
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
|
| 384 |
+
[prs]: http://makeapullrequest.com
|
| 385 |
+
[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
|
| 386 |
+
[coc]: https://github.com/testing-library/dom-testing-library/blob/main/CODE_OF_CONDUCT.md
|
| 387 |
+
[github-watch-badge]: https://img.shields.io/github/watchers/testing-library/dom-testing-library.svg?style=social
|
| 388 |
+
[github-watch]: https://github.com/testing-library/dom-testing-library/watchers
|
| 389 |
+
[github-star-badge]: https://img.shields.io/github/stars/testing-library/dom-testing-library.svg?style=social
|
| 390 |
+
[github-star]: https://github.com/testing-library/dom-testing-library/stargazers
|
| 391 |
+
[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20dom-testing-library%20by%20%40testing-library%20https%3A%2F%2Fgithub.com%2Ftesting-library%2Fdom-testing-library%20%F0%9F%91%8D
|
| 392 |
+
[twitter-badge]: https://img.shields.io/twitter/url/https/github.com/testing-library/dom-testing-library.svg?style=social
|
| 393 |
+
[emojis]: https://github.com/all-contributors/all-contributors#emoji-key
|
| 394 |
+
[all-contributors]: https://github.com/all-contributors/all-contributors
|
| 395 |
+
[all-contributors-badge]: https://img.shields.io/github/all-contributors/testing-library/dom-testing-library?color=orange&style=flat-square
|
| 396 |
+
[set-immediate]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate
|
| 397 |
+
[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106
|
| 398 |
+
[jest]: https://facebook.github.io/jest
|
| 399 |
+
[discord-badge]: https://img.shields.io/discord/723559267868737556.svg?color=7389D8&labelColor=6A7EC2&logo=discord&logoColor=ffffff&style=flat-square
|
| 400 |
+
[discord]: https://discord.gg/testing-library
|
| 401 |
+
|
| 402 |
+
<!-- prettier-ignore-end -->
|
node_modules/@testing-library/dom/dist/@testing-library/dom.cjs.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js
ADDED
|
@@ -0,0 +1,2848 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as prettyFormat from 'pretty-format';
|
| 2 |
+
export { prettyFormat };
|
| 3 |
+
import { computeAccessibleName, computeAccessibleDescription } from 'dom-accessibility-api';
|
| 4 |
+
import { elementRoles, roles, roleElements } from 'aria-query';
|
| 5 |
+
import lzString from 'lz-string';
|
| 6 |
+
|
| 7 |
+
/**
|
| 8 |
+
* Source: https://github.com/facebook/jest/blob/e7bb6a1e26ffab90611b2593912df15b69315611/packages/pretty-format/src/plugins/DOMElement.ts
|
| 9 |
+
*/
|
| 10 |
+
/* eslint-disable -- trying to stay as close to the original as possible */
|
| 11 |
+
/* istanbul ignore file */
|
| 12 |
+
|
| 13 |
+
function escapeHTML(str) {
|
| 14 |
+
return str.replace(/</g, '<').replace(/>/g, '>');
|
| 15 |
+
}
|
| 16 |
+
// Return empty string if keys is empty.
|
| 17 |
+
const printProps = (keys, props, config, indentation, depth, refs, printer) => {
|
| 18 |
+
const indentationNext = indentation + config.indent;
|
| 19 |
+
const colors = config.colors;
|
| 20 |
+
return keys.map(key => {
|
| 21 |
+
const value = props[key];
|
| 22 |
+
let printed = printer(value, config, indentationNext, depth, refs);
|
| 23 |
+
if (typeof value !== 'string') {
|
| 24 |
+
if (printed.indexOf('\n') !== -1) {
|
| 25 |
+
printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation;
|
| 26 |
+
}
|
| 27 |
+
printed = '{' + printed + '}';
|
| 28 |
+
}
|
| 29 |
+
return config.spacingInner + indentation + colors.prop.open + key + colors.prop.close + '=' + colors.value.open + printed + colors.value.close;
|
| 30 |
+
}).join('');
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node_type_constants
|
| 34 |
+
const NodeTypeTextNode = 3;
|
| 35 |
+
|
| 36 |
+
// Return empty string if children is empty.
|
| 37 |
+
const printChildren = (children, config, indentation, depth, refs, printer) => children.map(child => {
|
| 38 |
+
const printedChild = typeof child === 'string' ? printText(child, config) : printer(child, config, indentation, depth, refs);
|
| 39 |
+
if (printedChild === '' && typeof child === 'object' && child !== null && child.nodeType !== NodeTypeTextNode) {
|
| 40 |
+
// A plugin serialized this Node to '' meaning we should ignore it.
|
| 41 |
+
return '';
|
| 42 |
+
}
|
| 43 |
+
return config.spacingOuter + indentation + printedChild;
|
| 44 |
+
}).join('');
|
| 45 |
+
const printText = (text, config) => {
|
| 46 |
+
const contentColor = config.colors.content;
|
| 47 |
+
return contentColor.open + escapeHTML(text) + contentColor.close;
|
| 48 |
+
};
|
| 49 |
+
const printComment = (comment, config) => {
|
| 50 |
+
const commentColor = config.colors.comment;
|
| 51 |
+
return commentColor.open + '<!--' + escapeHTML(comment) + '-->' + commentColor.close;
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
// Separate the functions to format props, children, and element,
|
| 55 |
+
// so a plugin could override a particular function, if needed.
|
| 56 |
+
// Too bad, so sad: the traditional (but unnecessary) space
|
| 57 |
+
// in a self-closing tagColor requires a second test of printedProps.
|
| 58 |
+
const printElement = (type, printedProps, printedChildren, config, indentation) => {
|
| 59 |
+
const tagColor = config.colors.tag;
|
| 60 |
+
return tagColor.open + '<' + type + (printedProps && tagColor.close + printedProps + config.spacingOuter + indentation + tagColor.open) + (printedChildren ? '>' + tagColor.close + printedChildren + config.spacingOuter + indentation + tagColor.open + '</' + type : (printedProps && !config.min ? '' : ' ') + '/') + '>' + tagColor.close;
|
| 61 |
+
};
|
| 62 |
+
const printElementAsLeaf = (type, config) => {
|
| 63 |
+
const tagColor = config.colors.tag;
|
| 64 |
+
return tagColor.open + '<' + type + tagColor.close + ' …' + tagColor.open + ' />' + tagColor.close;
|
| 65 |
+
};
|
| 66 |
+
const ELEMENT_NODE$1 = 1;
|
| 67 |
+
const TEXT_NODE$1 = 3;
|
| 68 |
+
const COMMENT_NODE$1 = 8;
|
| 69 |
+
const FRAGMENT_NODE = 11;
|
| 70 |
+
const ELEMENT_REGEXP = /^((HTML|SVG)\w*)?Element$/;
|
| 71 |
+
const isCustomElement = val => {
|
| 72 |
+
const {
|
| 73 |
+
tagName
|
| 74 |
+
} = val;
|
| 75 |
+
return Boolean(typeof tagName === 'string' && tagName.includes('-') || typeof val.hasAttribute === 'function' && val.hasAttribute('is'));
|
| 76 |
+
};
|
| 77 |
+
const testNode = val => {
|
| 78 |
+
const constructorName = val.constructor.name;
|
| 79 |
+
const {
|
| 80 |
+
nodeType
|
| 81 |
+
} = val;
|
| 82 |
+
return nodeType === ELEMENT_NODE$1 && (ELEMENT_REGEXP.test(constructorName) || isCustomElement(val)) || nodeType === TEXT_NODE$1 && constructorName === 'Text' || nodeType === COMMENT_NODE$1 && constructorName === 'Comment' || nodeType === FRAGMENT_NODE && constructorName === 'DocumentFragment';
|
| 83 |
+
};
|
| 84 |
+
function nodeIsText(node) {
|
| 85 |
+
return node.nodeType === TEXT_NODE$1;
|
| 86 |
+
}
|
| 87 |
+
function nodeIsComment(node) {
|
| 88 |
+
return node.nodeType === COMMENT_NODE$1;
|
| 89 |
+
}
|
| 90 |
+
function nodeIsFragment(node) {
|
| 91 |
+
return node.nodeType === FRAGMENT_NODE;
|
| 92 |
+
}
|
| 93 |
+
function createDOMElementFilter(filterNode) {
|
| 94 |
+
return {
|
| 95 |
+
test: val => {
|
| 96 |
+
var _val$constructor2;
|
| 97 |
+
return ((val == null || (_val$constructor2 = val.constructor) == null ? void 0 : _val$constructor2.name) || isCustomElement(val)) && testNode(val);
|
| 98 |
+
},
|
| 99 |
+
serialize: (node, config, indentation, depth, refs, printer) => {
|
| 100 |
+
if (nodeIsText(node)) {
|
| 101 |
+
return printText(node.data, config);
|
| 102 |
+
}
|
| 103 |
+
if (nodeIsComment(node)) {
|
| 104 |
+
return printComment(node.data, config);
|
| 105 |
+
}
|
| 106 |
+
const type = nodeIsFragment(node) ? "DocumentFragment" : node.tagName.toLowerCase();
|
| 107 |
+
if (++depth > config.maxDepth) {
|
| 108 |
+
return printElementAsLeaf(type, config);
|
| 109 |
+
}
|
| 110 |
+
return printElement(type, printProps(nodeIsFragment(node) ? [] : Array.from(node.attributes).map(attr => attr.name).sort(), nodeIsFragment(node) ? {} : Array.from(node.attributes).reduce((props, attribute) => {
|
| 111 |
+
props[attribute.name] = attribute.value;
|
| 112 |
+
return props;
|
| 113 |
+
}, {}), config, indentation + config.indent, depth, refs, printer), printChildren(Array.prototype.slice.call(node.childNodes || node.children).filter(filterNode), config, indentation + config.indent, depth, refs, printer), config, indentation);
|
| 114 |
+
}
|
| 115 |
+
};
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
// We try to load node dependencies
|
| 119 |
+
let picocolors = null;
|
| 120 |
+
let readFileSync = null;
|
| 121 |
+
let codeFrameColumns = null;
|
| 122 |
+
try {
|
| 123 |
+
const nodeRequire = module && module.require;
|
| 124 |
+
readFileSync = nodeRequire.call(module, 'fs').readFileSync;
|
| 125 |
+
codeFrameColumns = nodeRequire.call(module, '@babel/code-frame').codeFrameColumns;
|
| 126 |
+
picocolors = nodeRequire.call(module, 'picocolors');
|
| 127 |
+
} catch {
|
| 128 |
+
// We're in a browser environment
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
// frame has the form "at myMethod (location/to/my/file.js:10:2)"
|
| 132 |
+
function getCodeFrame(frame) {
|
| 133 |
+
const locationStart = frame.indexOf('(') + 1;
|
| 134 |
+
const locationEnd = frame.indexOf(')');
|
| 135 |
+
const frameLocation = frame.slice(locationStart, locationEnd);
|
| 136 |
+
const frameLocationElements = frameLocation.split(':');
|
| 137 |
+
const [filename, line, column] = [frameLocationElements[0], parseInt(frameLocationElements[1], 10), parseInt(frameLocationElements[2], 10)];
|
| 138 |
+
let rawFileContents = '';
|
| 139 |
+
try {
|
| 140 |
+
rawFileContents = readFileSync(filename, 'utf-8');
|
| 141 |
+
} catch {
|
| 142 |
+
return '';
|
| 143 |
+
}
|
| 144 |
+
const codeFrame = codeFrameColumns(rawFileContents, {
|
| 145 |
+
start: {
|
| 146 |
+
line,
|
| 147 |
+
column
|
| 148 |
+
}
|
| 149 |
+
}, {
|
| 150 |
+
highlightCode: true,
|
| 151 |
+
linesBelow: 0
|
| 152 |
+
});
|
| 153 |
+
return picocolors.dim(frameLocation) + "\n" + codeFrame + "\n";
|
| 154 |
+
}
|
| 155 |
+
function getUserCodeFrame() {
|
| 156 |
+
// If we couldn't load dependencies, we can't generate the user trace
|
| 157 |
+
/* istanbul ignore next */
|
| 158 |
+
if (!readFileSync || !codeFrameColumns) {
|
| 159 |
+
return '';
|
| 160 |
+
}
|
| 161 |
+
const err = new Error();
|
| 162 |
+
const firstClientCodeFrame = err.stack.split('\n').slice(1) // Remove first line which has the form "Error: TypeError"
|
| 163 |
+
.find(frame => !frame.includes('node_modules/')); // Ignore frames from 3rd party libraries
|
| 164 |
+
|
| 165 |
+
return getCodeFrame(firstClientCodeFrame);
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
// Constant node.nodeType for text nodes, see:
|
| 169 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants
|
| 170 |
+
const TEXT_NODE = 3;
|
| 171 |
+
function jestFakeTimersAreEnabled() {
|
| 172 |
+
/* istanbul ignore else */
|
| 173 |
+
// eslint-disable-next-line
|
| 174 |
+
if (typeof jest !== 'undefined' && jest !== null) {
|
| 175 |
+
return (
|
| 176 |
+
// legacy timers
|
| 177 |
+
setTimeout._isMockFunction === true ||
|
| 178 |
+
// modern timers
|
| 179 |
+
// eslint-disable-next-line prefer-object-has-own -- not supported by our support matrix
|
| 180 |
+
Object.prototype.hasOwnProperty.call(setTimeout, 'clock')
|
| 181 |
+
);
|
| 182 |
+
}
|
| 183 |
+
// istanbul ignore next
|
| 184 |
+
return false;
|
| 185 |
+
}
|
| 186 |
+
function getDocument() {
|
| 187 |
+
/* istanbul ignore if */
|
| 188 |
+
if (typeof window === 'undefined') {
|
| 189 |
+
throw new Error('Could not find default container');
|
| 190 |
+
}
|
| 191 |
+
return window.document;
|
| 192 |
+
}
|
| 193 |
+
function getWindowFromNode(node) {
|
| 194 |
+
if (node.defaultView) {
|
| 195 |
+
// node is document
|
| 196 |
+
return node.defaultView;
|
| 197 |
+
} else if (node.ownerDocument && node.ownerDocument.defaultView) {
|
| 198 |
+
// node is a DOM node
|
| 199 |
+
return node.ownerDocument.defaultView;
|
| 200 |
+
} else if (node.window) {
|
| 201 |
+
// node is window
|
| 202 |
+
return node.window;
|
| 203 |
+
} else if (node.ownerDocument && node.ownerDocument.defaultView === null) {
|
| 204 |
+
throw new Error("It looks like the window object is not available for the provided node.");
|
| 205 |
+
} else if (node.then instanceof Function) {
|
| 206 |
+
throw new Error("It looks like you passed a Promise object instead of a DOM node. Did you do something like `fireEvent.click(screen.findBy...` when you meant to use a `getBy` query `fireEvent.click(screen.getBy...`, or await the findBy query `fireEvent.click(await screen.findBy...`?");
|
| 207 |
+
} else if (Array.isArray(node)) {
|
| 208 |
+
throw new Error("It looks like you passed an Array instead of a DOM node. Did you do something like `fireEvent.click(screen.getAllBy...` when you meant to use a `getBy` query `fireEvent.click(screen.getBy...`?");
|
| 209 |
+
} else if (typeof node.debug === 'function' && typeof node.logTestingPlaygroundURL === 'function') {
|
| 210 |
+
throw new Error("It looks like you passed a `screen` object. Did you do something like `fireEvent.click(screen, ...` when you meant to use a query, e.g. `fireEvent.click(screen.getBy..., `?");
|
| 211 |
+
} else {
|
| 212 |
+
// The user passed something unusual to a calling function
|
| 213 |
+
throw new Error("The given node is not an Element, the node type is: " + typeof node + ".");
|
| 214 |
+
}
|
| 215 |
+
}
|
| 216 |
+
function checkContainerType(container) {
|
| 217 |
+
if (!container || !(typeof container.querySelector === 'function') || !(typeof container.querySelectorAll === 'function')) {
|
| 218 |
+
throw new TypeError("Expected container to be an Element, a Document or a DocumentFragment but got " + getTypeName(container) + ".");
|
| 219 |
+
}
|
| 220 |
+
function getTypeName(object) {
|
| 221 |
+
if (typeof object === 'object') {
|
| 222 |
+
return object === null ? 'null' : object.constructor.name;
|
| 223 |
+
}
|
| 224 |
+
return typeof object;
|
| 225 |
+
}
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
const shouldHighlight = () => {
|
| 229 |
+
if (typeof process === 'undefined') {
|
| 230 |
+
// Don't colorize in non-node environments (e.g. Browsers)
|
| 231 |
+
return false;
|
| 232 |
+
}
|
| 233 |
+
let colors;
|
| 234 |
+
// Try to safely parse env COLORS: We will default behavior if any step fails.
|
| 235 |
+
try {
|
| 236 |
+
var _process$env;
|
| 237 |
+
const colorsJSON = (_process$env = process.env) == null ? void 0 : _process$env.COLORS;
|
| 238 |
+
if (colorsJSON) {
|
| 239 |
+
colors = JSON.parse(colorsJSON);
|
| 240 |
+
}
|
| 241 |
+
} catch {
|
| 242 |
+
// If this throws, process.env?.COLORS wasn't parsable. Since we only
|
| 243 |
+
// care about `true` or `false`, we can safely ignore the error.
|
| 244 |
+
}
|
| 245 |
+
if (typeof colors === 'boolean') {
|
| 246 |
+
// If `colors` is set explicitly (both `true` and `false`), use that value.
|
| 247 |
+
return colors;
|
| 248 |
+
} else {
|
| 249 |
+
// If `colors` is not set, colorize if we're in node.
|
| 250 |
+
return process.versions !== undefined && process.versions.node !== undefined;
|
| 251 |
+
}
|
| 252 |
+
};
|
| 253 |
+
const {
|
| 254 |
+
DOMCollection
|
| 255 |
+
} = prettyFormat.plugins;
|
| 256 |
+
|
| 257 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node_type_constants
|
| 258 |
+
const ELEMENT_NODE = 1;
|
| 259 |
+
const COMMENT_NODE = 8;
|
| 260 |
+
|
| 261 |
+
// https://github.com/facebook/jest/blob/615084195ae1ae61ddd56162c62bbdda17587569/packages/pretty-format/src/plugins/DOMElement.ts#L50
|
| 262 |
+
function filterCommentsAndDefaultIgnoreTagsTags(value) {
|
| 263 |
+
return value.nodeType !== COMMENT_NODE && (value.nodeType !== ELEMENT_NODE || !value.matches(getConfig().defaultIgnore));
|
| 264 |
+
}
|
| 265 |
+
function prettyDOM(dom, maxLength, options) {
|
| 266 |
+
if (options === void 0) {
|
| 267 |
+
options = {};
|
| 268 |
+
}
|
| 269 |
+
if (!dom) {
|
| 270 |
+
dom = getDocument().body;
|
| 271 |
+
}
|
| 272 |
+
if (typeof maxLength !== 'number') {
|
| 273 |
+
maxLength = typeof process !== 'undefined' && typeof process.env !== 'undefined' && process.env.DEBUG_PRINT_LIMIT || 7000;
|
| 274 |
+
}
|
| 275 |
+
if (maxLength === 0) {
|
| 276 |
+
return '';
|
| 277 |
+
}
|
| 278 |
+
if (dom.documentElement) {
|
| 279 |
+
dom = dom.documentElement;
|
| 280 |
+
}
|
| 281 |
+
let domTypeName = typeof dom;
|
| 282 |
+
if (domTypeName === 'object') {
|
| 283 |
+
domTypeName = dom.constructor.name;
|
| 284 |
+
} else {
|
| 285 |
+
// To don't fall with `in` operator
|
| 286 |
+
dom = {};
|
| 287 |
+
}
|
| 288 |
+
if (!('outerHTML' in dom)) {
|
| 289 |
+
throw new TypeError("Expected an element or document but got " + domTypeName);
|
| 290 |
+
}
|
| 291 |
+
const {
|
| 292 |
+
filterNode = filterCommentsAndDefaultIgnoreTagsTags,
|
| 293 |
+
...prettyFormatOptions
|
| 294 |
+
} = options;
|
| 295 |
+
const debugContent = prettyFormat.format(dom, {
|
| 296 |
+
plugins: [createDOMElementFilter(filterNode), DOMCollection],
|
| 297 |
+
printFunctionName: false,
|
| 298 |
+
highlight: shouldHighlight(),
|
| 299 |
+
...prettyFormatOptions
|
| 300 |
+
});
|
| 301 |
+
return maxLength !== undefined && dom.outerHTML.length > maxLength ? debugContent.slice(0, maxLength) + "..." : debugContent;
|
| 302 |
+
}
|
| 303 |
+
const logDOM = function () {
|
| 304 |
+
const userCodeFrame = getUserCodeFrame();
|
| 305 |
+
if (userCodeFrame) {
|
| 306 |
+
console.log(prettyDOM(...arguments) + "\n\n" + userCodeFrame);
|
| 307 |
+
} else {
|
| 308 |
+
console.log(prettyDOM(...arguments));
|
| 309 |
+
}
|
| 310 |
+
};
|
| 311 |
+
|
| 312 |
+
// It would be cleaner for this to live inside './queries', but
|
| 313 |
+
// other parts of the code assume that all exports from
|
| 314 |
+
// './queries' are query functions.
|
| 315 |
+
let config = {
|
| 316 |
+
testIdAttribute: 'data-testid',
|
| 317 |
+
asyncUtilTimeout: 1000,
|
| 318 |
+
// asyncWrapper and advanceTimersWrapper is to support React's async `act` function.
|
| 319 |
+
// forcing react-testing-library to wrap all async functions would've been
|
| 320 |
+
// a total nightmare (consider wrapping every findBy* query and then also
|
| 321 |
+
// updating `within` so those would be wrapped too. Total nightmare).
|
| 322 |
+
// so we have this config option that's really only intended for
|
| 323 |
+
// react-testing-library to use. For that reason, this feature will remain
|
| 324 |
+
// undocumented.
|
| 325 |
+
asyncWrapper: cb => cb(),
|
| 326 |
+
unstable_advanceTimersWrapper: cb => cb(),
|
| 327 |
+
eventWrapper: cb => cb(),
|
| 328 |
+
// default value for the `hidden` option in `ByRole` queries
|
| 329 |
+
defaultHidden: false,
|
| 330 |
+
// default value for the `ignore` option in `ByText` queries
|
| 331 |
+
defaultIgnore: 'script, style',
|
| 332 |
+
// showOriginalStackTrace flag to show the full error stack traces for async errors
|
| 333 |
+
showOriginalStackTrace: false,
|
| 334 |
+
// throw errors w/ suggestions for better queries. Opt in so off by default.
|
| 335 |
+
throwSuggestions: false,
|
| 336 |
+
// called when getBy* queries fail. (message, container) => Error
|
| 337 |
+
getElementError(message, container) {
|
| 338 |
+
const prettifiedDOM = prettyDOM(container);
|
| 339 |
+
const error = new Error([message, "Ignored nodes: comments, " + config.defaultIgnore + "\n" + prettifiedDOM].filter(Boolean).join('\n\n'));
|
| 340 |
+
error.name = 'TestingLibraryElementError';
|
| 341 |
+
return error;
|
| 342 |
+
},
|
| 343 |
+
_disableExpensiveErrorDiagnostics: false,
|
| 344 |
+
computedStyleSupportsPseudoElements: false
|
| 345 |
+
};
|
| 346 |
+
function runWithExpensiveErrorDiagnosticsDisabled(callback) {
|
| 347 |
+
try {
|
| 348 |
+
config._disableExpensiveErrorDiagnostics = true;
|
| 349 |
+
return callback();
|
| 350 |
+
} finally {
|
| 351 |
+
config._disableExpensiveErrorDiagnostics = false;
|
| 352 |
+
}
|
| 353 |
+
}
|
| 354 |
+
function configure(newConfig) {
|
| 355 |
+
if (typeof newConfig === 'function') {
|
| 356 |
+
// Pass the existing config out to the provided function
|
| 357 |
+
// and accept a delta in return
|
| 358 |
+
newConfig = newConfig(config);
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
// Merge the incoming config delta
|
| 362 |
+
config = {
|
| 363 |
+
...config,
|
| 364 |
+
...newConfig
|
| 365 |
+
};
|
| 366 |
+
}
|
| 367 |
+
function getConfig() {
|
| 368 |
+
return config;
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
const labelledNodeNames = ['button', 'meter', 'output', 'progress', 'select', 'textarea', 'input'];
|
| 372 |
+
function getTextContent(node) {
|
| 373 |
+
if (labelledNodeNames.includes(node.nodeName.toLowerCase())) {
|
| 374 |
+
return '';
|
| 375 |
+
}
|
| 376 |
+
if (node.nodeType === TEXT_NODE) return node.textContent;
|
| 377 |
+
return Array.from(node.childNodes).map(childNode => getTextContent(childNode)).join('');
|
| 378 |
+
}
|
| 379 |
+
function getLabelContent(element) {
|
| 380 |
+
let textContent;
|
| 381 |
+
if (element.tagName.toLowerCase() === 'label') {
|
| 382 |
+
textContent = getTextContent(element);
|
| 383 |
+
} else {
|
| 384 |
+
textContent = element.value || element.textContent;
|
| 385 |
+
}
|
| 386 |
+
return textContent;
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
// Based on https://github.com/eps1lon/dom-accessibility-api/pull/352
|
| 390 |
+
function getRealLabels(element) {
|
| 391 |
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- types are not aware of older browsers that don't implement `labels`
|
| 392 |
+
if (element.labels !== undefined) {
|
| 393 |
+
var _labels;
|
| 394 |
+
return (_labels = element.labels) != null ? _labels : [];
|
| 395 |
+
}
|
| 396 |
+
if (!isLabelable(element)) return [];
|
| 397 |
+
const labels = element.ownerDocument.querySelectorAll('label');
|
| 398 |
+
return Array.from(labels).filter(label => label.control === element);
|
| 399 |
+
}
|
| 400 |
+
function isLabelable(element) {
|
| 401 |
+
return /BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/.test(element.tagName) || element.tagName === 'INPUT' && element.getAttribute('type') !== 'hidden';
|
| 402 |
+
}
|
| 403 |
+
function getLabels(container, element, _temp) {
|
| 404 |
+
let {
|
| 405 |
+
selector = '*'
|
| 406 |
+
} = _temp === void 0 ? {} : _temp;
|
| 407 |
+
const ariaLabelledBy = element.getAttribute('aria-labelledby');
|
| 408 |
+
const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : [];
|
| 409 |
+
return labelsId.length ? labelsId.map(labelId => {
|
| 410 |
+
const labellingElement = container.querySelector("[id=\"" + labelId + "\"]");
|
| 411 |
+
return labellingElement ? {
|
| 412 |
+
content: getLabelContent(labellingElement),
|
| 413 |
+
formControl: null
|
| 414 |
+
} : {
|
| 415 |
+
content: '',
|
| 416 |
+
formControl: null
|
| 417 |
+
};
|
| 418 |
+
}) : Array.from(getRealLabels(element)).map(label => {
|
| 419 |
+
const textToMatch = getLabelContent(label);
|
| 420 |
+
const formControlSelector = 'button, input, meter, output, progress, select, textarea';
|
| 421 |
+
const labelledFormControl = Array.from(label.querySelectorAll(formControlSelector)).filter(formControlElement => formControlElement.matches(selector))[0];
|
| 422 |
+
return {
|
| 423 |
+
content: textToMatch,
|
| 424 |
+
formControl: labelledFormControl
|
| 425 |
+
};
|
| 426 |
+
});
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
function assertNotNullOrUndefined(matcher) {
|
| 430 |
+
if (matcher === null || matcher === undefined) {
|
| 431 |
+
throw new Error(// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- implicitly converting `T` to `string`
|
| 432 |
+
"It looks like " + matcher + " was passed instead of a matcher. Did you do something like getByText(" + matcher + ")?");
|
| 433 |
+
}
|
| 434 |
+
}
|
| 435 |
+
function fuzzyMatches(textToMatch, node, matcher, normalizer) {
|
| 436 |
+
if (typeof textToMatch !== 'string') {
|
| 437 |
+
return false;
|
| 438 |
+
}
|
| 439 |
+
assertNotNullOrUndefined(matcher);
|
| 440 |
+
const normalizedText = normalizer(textToMatch);
|
| 441 |
+
if (typeof matcher === 'string' || typeof matcher === 'number') {
|
| 442 |
+
return normalizedText.toLowerCase().includes(matcher.toString().toLowerCase());
|
| 443 |
+
} else if (typeof matcher === 'function') {
|
| 444 |
+
return matcher(normalizedText, node);
|
| 445 |
+
} else {
|
| 446 |
+
return matchRegExp(matcher, normalizedText);
|
| 447 |
+
}
|
| 448 |
+
}
|
| 449 |
+
function matches(textToMatch, node, matcher, normalizer) {
|
| 450 |
+
if (typeof textToMatch !== 'string') {
|
| 451 |
+
return false;
|
| 452 |
+
}
|
| 453 |
+
assertNotNullOrUndefined(matcher);
|
| 454 |
+
const normalizedText = normalizer(textToMatch);
|
| 455 |
+
if (matcher instanceof Function) {
|
| 456 |
+
return matcher(normalizedText, node);
|
| 457 |
+
} else if (matcher instanceof RegExp) {
|
| 458 |
+
return matchRegExp(matcher, normalizedText);
|
| 459 |
+
} else {
|
| 460 |
+
return normalizedText === String(matcher);
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
function getDefaultNormalizer(_temp) {
|
| 464 |
+
let {
|
| 465 |
+
trim = true,
|
| 466 |
+
collapseWhitespace = true
|
| 467 |
+
} = _temp === void 0 ? {} : _temp;
|
| 468 |
+
return text => {
|
| 469 |
+
let normalizedText = text;
|
| 470 |
+
normalizedText = trim ? normalizedText.trim() : normalizedText;
|
| 471 |
+
normalizedText = collapseWhitespace ? normalizedText.replace(/\s+/g, ' ') : normalizedText;
|
| 472 |
+
return normalizedText;
|
| 473 |
+
};
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
/**
|
| 477 |
+
* Constructs a normalizer to pass to functions in matches.js
|
| 478 |
+
* @param {boolean|undefined} trim The user-specified value for `trim`, without
|
| 479 |
+
* any defaulting having been applied
|
| 480 |
+
* @param {boolean|undefined} collapseWhitespace The user-specified value for
|
| 481 |
+
* `collapseWhitespace`, without any defaulting having been applied
|
| 482 |
+
* @param {Function|undefined} normalizer The user-specified normalizer
|
| 483 |
+
* @returns {Function} A normalizer
|
| 484 |
+
*/
|
| 485 |
+
|
| 486 |
+
function makeNormalizer(_ref) {
|
| 487 |
+
let {
|
| 488 |
+
trim,
|
| 489 |
+
collapseWhitespace,
|
| 490 |
+
normalizer
|
| 491 |
+
} = _ref;
|
| 492 |
+
if (!normalizer) {
|
| 493 |
+
// No custom normalizer specified. Just use default.
|
| 494 |
+
return getDefaultNormalizer({
|
| 495 |
+
trim,
|
| 496 |
+
collapseWhitespace
|
| 497 |
+
});
|
| 498 |
+
}
|
| 499 |
+
if (typeof trim !== 'undefined' || typeof collapseWhitespace !== 'undefined') {
|
| 500 |
+
// They've also specified a value for trim or collapseWhitespace
|
| 501 |
+
throw new Error('trim and collapseWhitespace are not supported with a normalizer. ' + 'If you want to use the default trim and collapseWhitespace logic in your normalizer, ' + 'use "getDefaultNormalizer({trim, collapseWhitespace})" and compose that into your normalizer');
|
| 502 |
+
}
|
| 503 |
+
return normalizer;
|
| 504 |
+
}
|
| 505 |
+
function matchRegExp(matcher, text) {
|
| 506 |
+
const match = matcher.test(text);
|
| 507 |
+
if (matcher.global && matcher.lastIndex !== 0) {
|
| 508 |
+
console.warn("To match all elements we had to reset the lastIndex of the RegExp because the global flag is enabled. We encourage to remove the global flag from the RegExp.");
|
| 509 |
+
matcher.lastIndex = 0;
|
| 510 |
+
}
|
| 511 |
+
return match;
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
function getNodeText(node) {
|
| 515 |
+
if (node.matches('input[type=submit], input[type=button], input[type=reset]')) {
|
| 516 |
+
return node.value;
|
| 517 |
+
}
|
| 518 |
+
return Array.from(node.childNodes).filter(child => child.nodeType === TEXT_NODE && Boolean(child.textContent)).map(c => c.textContent).join('');
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
const elementRoleList = buildElementRoleList(elementRoles);
|
| 522 |
+
|
| 523 |
+
/**
|
| 524 |
+
* @param {Element} element -
|
| 525 |
+
* @returns {boolean} - `true` if `element` and its subtree are inaccessible
|
| 526 |
+
*/
|
| 527 |
+
function isSubtreeInaccessible(element) {
|
| 528 |
+
if (element.hidden === true) {
|
| 529 |
+
return true;
|
| 530 |
+
}
|
| 531 |
+
if (element.getAttribute('aria-hidden') === 'true') {
|
| 532 |
+
return true;
|
| 533 |
+
}
|
| 534 |
+
const window = element.ownerDocument.defaultView;
|
| 535 |
+
if (window.getComputedStyle(element).display === 'none') {
|
| 536 |
+
return true;
|
| 537 |
+
}
|
| 538 |
+
return false;
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
/**
|
| 542 |
+
* Partial implementation https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion
|
| 543 |
+
* which should only be used for elements with a non-presentational role i.e.
|
| 544 |
+
* `role="none"` and `role="presentation"` will not be excluded.
|
| 545 |
+
*
|
| 546 |
+
* Implements aria-hidden semantics (i.e. parent overrides child)
|
| 547 |
+
* Ignores "Child Presentational: True" characteristics
|
| 548 |
+
*
|
| 549 |
+
* @param {Element} element -
|
| 550 |
+
* @param {object} [options] -
|
| 551 |
+
* @param {function (element: Element): boolean} options.isSubtreeInaccessible -
|
| 552 |
+
* can be used to return cached results from previous isSubtreeInaccessible calls
|
| 553 |
+
* @returns {boolean} true if excluded, otherwise false
|
| 554 |
+
*/
|
| 555 |
+
function isInaccessible(element, options) {
|
| 556 |
+
if (options === void 0) {
|
| 557 |
+
options = {};
|
| 558 |
+
}
|
| 559 |
+
const {
|
| 560 |
+
isSubtreeInaccessible: isSubtreeInaccessibleImpl = isSubtreeInaccessible
|
| 561 |
+
} = options;
|
| 562 |
+
const window = element.ownerDocument.defaultView;
|
| 563 |
+
// since visibility is inherited we can exit early
|
| 564 |
+
if (window.getComputedStyle(element).visibility === 'hidden') {
|
| 565 |
+
return true;
|
| 566 |
+
}
|
| 567 |
+
let currentElement = element;
|
| 568 |
+
while (currentElement) {
|
| 569 |
+
if (isSubtreeInaccessibleImpl(currentElement)) {
|
| 570 |
+
return true;
|
| 571 |
+
}
|
| 572 |
+
currentElement = currentElement.parentElement;
|
| 573 |
+
}
|
| 574 |
+
return false;
|
| 575 |
+
}
|
| 576 |
+
function getImplicitAriaRoles(currentNode) {
|
| 577 |
+
// eslint bug here:
|
| 578 |
+
// eslint-disable-next-line no-unused-vars
|
| 579 |
+
for (const {
|
| 580 |
+
match,
|
| 581 |
+
roles
|
| 582 |
+
} of elementRoleList) {
|
| 583 |
+
if (match(currentNode)) {
|
| 584 |
+
return [...roles];
|
| 585 |
+
}
|
| 586 |
+
}
|
| 587 |
+
return [];
|
| 588 |
+
}
|
| 589 |
+
function buildElementRoleList(elementRolesMap) {
|
| 590 |
+
function makeElementSelector(_ref) {
|
| 591 |
+
let {
|
| 592 |
+
name,
|
| 593 |
+
attributes
|
| 594 |
+
} = _ref;
|
| 595 |
+
return "" + name + attributes.map(_ref2 => {
|
| 596 |
+
let {
|
| 597 |
+
name: attributeName,
|
| 598 |
+
value,
|
| 599 |
+
constraints = []
|
| 600 |
+
} = _ref2;
|
| 601 |
+
const shouldNotExist = constraints.indexOf('undefined') !== -1;
|
| 602 |
+
const shouldBeNonEmpty = constraints.indexOf('set') !== -1;
|
| 603 |
+
const hasExplicitValue = typeof value !== 'undefined';
|
| 604 |
+
if (hasExplicitValue) {
|
| 605 |
+
return "[" + attributeName + "=\"" + value + "\"]";
|
| 606 |
+
} else if (shouldNotExist) {
|
| 607 |
+
return ":not([" + attributeName + "])";
|
| 608 |
+
} else if (shouldBeNonEmpty) {
|
| 609 |
+
return "[" + attributeName + "]:not([" + attributeName + "=\"\"])";
|
| 610 |
+
}
|
| 611 |
+
return "[" + attributeName + "]";
|
| 612 |
+
}).join('');
|
| 613 |
+
}
|
| 614 |
+
function getSelectorSpecificity(_ref3) {
|
| 615 |
+
let {
|
| 616 |
+
attributes = []
|
| 617 |
+
} = _ref3;
|
| 618 |
+
return attributes.length;
|
| 619 |
+
}
|
| 620 |
+
function bySelectorSpecificity(_ref4, _ref5) {
|
| 621 |
+
let {
|
| 622 |
+
specificity: leftSpecificity
|
| 623 |
+
} = _ref4;
|
| 624 |
+
let {
|
| 625 |
+
specificity: rightSpecificity
|
| 626 |
+
} = _ref5;
|
| 627 |
+
return rightSpecificity - leftSpecificity;
|
| 628 |
+
}
|
| 629 |
+
function match(element) {
|
| 630 |
+
let {
|
| 631 |
+
attributes = []
|
| 632 |
+
} = element;
|
| 633 |
+
|
| 634 |
+
// https://github.com/testing-library/dom-testing-library/issues/814
|
| 635 |
+
const typeTextIndex = attributes.findIndex(attribute => attribute.value && attribute.name === 'type' && attribute.value === 'text');
|
| 636 |
+
if (typeTextIndex >= 0) {
|
| 637 |
+
// not using splice to not mutate the attributes array
|
| 638 |
+
attributes = [...attributes.slice(0, typeTextIndex), ...attributes.slice(typeTextIndex + 1)];
|
| 639 |
+
}
|
| 640 |
+
const selector = makeElementSelector({
|
| 641 |
+
...element,
|
| 642 |
+
attributes
|
| 643 |
+
});
|
| 644 |
+
return node => {
|
| 645 |
+
if (typeTextIndex >= 0 && node.type !== 'text') {
|
| 646 |
+
return false;
|
| 647 |
+
}
|
| 648 |
+
return node.matches(selector);
|
| 649 |
+
};
|
| 650 |
+
}
|
| 651 |
+
let result = [];
|
| 652 |
+
|
| 653 |
+
// eslint bug here:
|
| 654 |
+
// eslint-disable-next-line no-unused-vars
|
| 655 |
+
for (const [element, roles] of elementRolesMap.entries()) {
|
| 656 |
+
result = [...result, {
|
| 657 |
+
match: match(element),
|
| 658 |
+
roles: Array.from(roles),
|
| 659 |
+
specificity: getSelectorSpecificity(element)
|
| 660 |
+
}];
|
| 661 |
+
}
|
| 662 |
+
return result.sort(bySelectorSpecificity);
|
| 663 |
+
}
|
| 664 |
+
function getRoles(container, _temp) {
|
| 665 |
+
let {
|
| 666 |
+
hidden = false
|
| 667 |
+
} = _temp === void 0 ? {} : _temp;
|
| 668 |
+
function flattenDOM(node) {
|
| 669 |
+
return [node, ...Array.from(node.children).reduce((acc, child) => [...acc, ...flattenDOM(child)], [])];
|
| 670 |
+
}
|
| 671 |
+
return flattenDOM(container).filter(element => {
|
| 672 |
+
return hidden === false ? isInaccessible(element) === false : true;
|
| 673 |
+
}).reduce((acc, node) => {
|
| 674 |
+
let roles = [];
|
| 675 |
+
// TODO: This violates html-aria which does not allow any role on every element
|
| 676 |
+
if (node.hasAttribute('role')) {
|
| 677 |
+
roles = node.getAttribute('role').split(' ').slice(0, 1);
|
| 678 |
+
} else {
|
| 679 |
+
roles = getImplicitAriaRoles(node);
|
| 680 |
+
}
|
| 681 |
+
return roles.reduce((rolesAcc, role) => Array.isArray(rolesAcc[role]) ? {
|
| 682 |
+
...rolesAcc,
|
| 683 |
+
[role]: [...rolesAcc[role], node]
|
| 684 |
+
} : {
|
| 685 |
+
...rolesAcc,
|
| 686 |
+
[role]: [node]
|
| 687 |
+
}, acc);
|
| 688 |
+
}, {});
|
| 689 |
+
}
|
| 690 |
+
function prettyRoles(dom, _ref6) {
|
| 691 |
+
let {
|
| 692 |
+
hidden,
|
| 693 |
+
includeDescription
|
| 694 |
+
} = _ref6;
|
| 695 |
+
const roles = getRoles(dom, {
|
| 696 |
+
hidden
|
| 697 |
+
});
|
| 698 |
+
// We prefer to skip generic role, we don't recommend it
|
| 699 |
+
return Object.entries(roles).filter(_ref7 => {
|
| 700 |
+
let [role] = _ref7;
|
| 701 |
+
return role !== 'generic';
|
| 702 |
+
}).map(_ref8 => {
|
| 703 |
+
let [role, elements] = _ref8;
|
| 704 |
+
const delimiterBar = '-'.repeat(50);
|
| 705 |
+
const elementsString = elements.map(el => {
|
| 706 |
+
const nameString = "Name \"" + computeAccessibleName(el, {
|
| 707 |
+
computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements
|
| 708 |
+
}) + "\":\n";
|
| 709 |
+
const domString = prettyDOM(el.cloneNode(false));
|
| 710 |
+
if (includeDescription) {
|
| 711 |
+
const descriptionString = "Description \"" + computeAccessibleDescription(el, {
|
| 712 |
+
computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements
|
| 713 |
+
}) + "\":\n";
|
| 714 |
+
return "" + nameString + descriptionString + domString;
|
| 715 |
+
}
|
| 716 |
+
return "" + nameString + domString;
|
| 717 |
+
}).join('\n\n');
|
| 718 |
+
return role + ":\n\n" + elementsString + "\n\n" + delimiterBar;
|
| 719 |
+
}).join('\n');
|
| 720 |
+
}
|
| 721 |
+
const logRoles = function (dom, _temp2) {
|
| 722 |
+
let {
|
| 723 |
+
hidden = false
|
| 724 |
+
} = _temp2 === void 0 ? {} : _temp2;
|
| 725 |
+
return console.log(prettyRoles(dom, {
|
| 726 |
+
hidden
|
| 727 |
+
}));
|
| 728 |
+
};
|
| 729 |
+
|
| 730 |
+
/**
|
| 731 |
+
* @param {Element} element -
|
| 732 |
+
* @returns {boolean | undefined} - false/true if (not)selected, undefined if not selectable
|
| 733 |
+
*/
|
| 734 |
+
function computeAriaSelected(element) {
|
| 735 |
+
// implicit value from html-aam mappings: https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
|
| 736 |
+
// https://www.w3.org/TR/html-aam-1.0/#details-id-97
|
| 737 |
+
if (element.tagName === 'OPTION') {
|
| 738 |
+
return element.selected;
|
| 739 |
+
}
|
| 740 |
+
|
| 741 |
+
// explicit value
|
| 742 |
+
return checkBooleanAttribute(element, 'aria-selected');
|
| 743 |
+
}
|
| 744 |
+
|
| 745 |
+
/**
|
| 746 |
+
* @param {Element} element -
|
| 747 |
+
* @returns {boolean} -
|
| 748 |
+
*/
|
| 749 |
+
function computeAriaBusy(element) {
|
| 750 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-busy
|
| 751 |
+
return element.getAttribute('aria-busy') === 'true';
|
| 752 |
+
}
|
| 753 |
+
|
| 754 |
+
/**
|
| 755 |
+
* @param {Element} element -
|
| 756 |
+
* @returns {boolean | undefined} - false/true if (not)checked, undefined if not checked-able
|
| 757 |
+
*/
|
| 758 |
+
function computeAriaChecked(element) {
|
| 759 |
+
// implicit value from html-aam mappings: https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
|
| 760 |
+
// https://www.w3.org/TR/html-aam-1.0/#details-id-56
|
| 761 |
+
// https://www.w3.org/TR/html-aam-1.0/#details-id-67
|
| 762 |
+
if ('indeterminate' in element && element.indeterminate) {
|
| 763 |
+
return undefined;
|
| 764 |
+
}
|
| 765 |
+
if ('checked' in element) {
|
| 766 |
+
return element.checked;
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
// explicit value
|
| 770 |
+
return checkBooleanAttribute(element, 'aria-checked');
|
| 771 |
+
}
|
| 772 |
+
|
| 773 |
+
/**
|
| 774 |
+
* @param {Element} element -
|
| 775 |
+
* @returns {boolean | undefined} - false/true if (not)pressed, undefined if not press-able
|
| 776 |
+
*/
|
| 777 |
+
function computeAriaPressed(element) {
|
| 778 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-pressed
|
| 779 |
+
return checkBooleanAttribute(element, 'aria-pressed');
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
/**
|
| 783 |
+
* @param {Element} element -
|
| 784 |
+
* @returns {boolean | string | null} -
|
| 785 |
+
*/
|
| 786 |
+
function computeAriaCurrent(element) {
|
| 787 |
+
var _ref9, _checkBooleanAttribut;
|
| 788 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-current
|
| 789 |
+
return (_ref9 = (_checkBooleanAttribut = checkBooleanAttribute(element, 'aria-current')) != null ? _checkBooleanAttribut : element.getAttribute('aria-current')) != null ? _ref9 : false;
|
| 790 |
+
}
|
| 791 |
+
|
| 792 |
+
/**
|
| 793 |
+
* @param {Element} element -
|
| 794 |
+
* @returns {boolean | undefined} - false/true if (not)expanded, undefined if not expand-able
|
| 795 |
+
*/
|
| 796 |
+
function computeAriaExpanded(element) {
|
| 797 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-expanded
|
| 798 |
+
return checkBooleanAttribute(element, 'aria-expanded');
|
| 799 |
+
}
|
| 800 |
+
function checkBooleanAttribute(element, attribute) {
|
| 801 |
+
const attributeValue = element.getAttribute(attribute);
|
| 802 |
+
if (attributeValue === 'true') {
|
| 803 |
+
return true;
|
| 804 |
+
}
|
| 805 |
+
if (attributeValue === 'false') {
|
| 806 |
+
return false;
|
| 807 |
+
}
|
| 808 |
+
return undefined;
|
| 809 |
+
}
|
| 810 |
+
|
| 811 |
+
/**
|
| 812 |
+
* @param {Element} element -
|
| 813 |
+
* @returns {number | undefined} - number if implicit heading or aria-level present, otherwise undefined
|
| 814 |
+
*/
|
| 815 |
+
function computeHeadingLevel(element) {
|
| 816 |
+
// https://w3c.github.io/html-aam/#el-h1-h6
|
| 817 |
+
// https://w3c.github.io/html-aam/#el-h1-h6
|
| 818 |
+
const implicitHeadingLevels = {
|
| 819 |
+
H1: 1,
|
| 820 |
+
H2: 2,
|
| 821 |
+
H3: 3,
|
| 822 |
+
H4: 4,
|
| 823 |
+
H5: 5,
|
| 824 |
+
H6: 6
|
| 825 |
+
};
|
| 826 |
+
// explicit aria-level value
|
| 827 |
+
// https://www.w3.org/TR/wai-aria-1.2/#aria-level
|
| 828 |
+
const ariaLevelAttribute = element.getAttribute('aria-level') && Number(element.getAttribute('aria-level'));
|
| 829 |
+
return ariaLevelAttribute || implicitHeadingLevels[element.tagName];
|
| 830 |
+
}
|
| 831 |
+
|
| 832 |
+
/**
|
| 833 |
+
* @param {Element} element -
|
| 834 |
+
* @returns {number | undefined} -
|
| 835 |
+
*/
|
| 836 |
+
function computeAriaValueNow(element) {
|
| 837 |
+
const valueNow = element.getAttribute('aria-valuenow');
|
| 838 |
+
return valueNow === null ? undefined : +valueNow;
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
/**
|
| 842 |
+
* @param {Element} element -
|
| 843 |
+
* @returns {number | undefined} -
|
| 844 |
+
*/
|
| 845 |
+
function computeAriaValueMax(element) {
|
| 846 |
+
const valueMax = element.getAttribute('aria-valuemax');
|
| 847 |
+
return valueMax === null ? undefined : +valueMax;
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
/**
|
| 851 |
+
* @param {Element} element -
|
| 852 |
+
* @returns {number | undefined} -
|
| 853 |
+
*/
|
| 854 |
+
function computeAriaValueMin(element) {
|
| 855 |
+
const valueMin = element.getAttribute('aria-valuemin');
|
| 856 |
+
return valueMin === null ? undefined : +valueMin;
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
/**
|
| 860 |
+
* @param {Element} element -
|
| 861 |
+
* @returns {string | undefined} -
|
| 862 |
+
*/
|
| 863 |
+
function computeAriaValueText(element) {
|
| 864 |
+
const valueText = element.getAttribute('aria-valuetext');
|
| 865 |
+
return valueText === null ? undefined : valueText;
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
const normalize = getDefaultNormalizer();
|
| 869 |
+
function escapeRegExp(string) {
|
| 870 |
+
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
| 871 |
+
}
|
| 872 |
+
function getRegExpMatcher(string) {
|
| 873 |
+
return new RegExp(escapeRegExp(string.toLowerCase()), 'i');
|
| 874 |
+
}
|
| 875 |
+
function makeSuggestion(queryName, element, content, _ref) {
|
| 876 |
+
let {
|
| 877 |
+
variant,
|
| 878 |
+
name
|
| 879 |
+
} = _ref;
|
| 880 |
+
let warning = '';
|
| 881 |
+
const queryOptions = {};
|
| 882 |
+
const queryArgs = [['Role', 'TestId'].includes(queryName) ? content : getRegExpMatcher(content)];
|
| 883 |
+
if (name) {
|
| 884 |
+
queryOptions.name = getRegExpMatcher(name);
|
| 885 |
+
}
|
| 886 |
+
if (queryName === 'Role' && isInaccessible(element)) {
|
| 887 |
+
queryOptions.hidden = true;
|
| 888 |
+
warning = "Element is inaccessible. This means that the element and all its children are invisible to screen readers.\n If you are using the aria-hidden prop, make sure this is the right choice for your case.\n ";
|
| 889 |
+
}
|
| 890 |
+
if (Object.keys(queryOptions).length > 0) {
|
| 891 |
+
queryArgs.push(queryOptions);
|
| 892 |
+
}
|
| 893 |
+
const queryMethod = variant + "By" + queryName;
|
| 894 |
+
return {
|
| 895 |
+
queryName,
|
| 896 |
+
queryMethod,
|
| 897 |
+
queryArgs,
|
| 898 |
+
variant,
|
| 899 |
+
warning,
|
| 900 |
+
toString() {
|
| 901 |
+
if (warning) {
|
| 902 |
+
console.warn(warning);
|
| 903 |
+
}
|
| 904 |
+
let [text, options] = queryArgs;
|
| 905 |
+
text = typeof text === 'string' ? "'" + text + "'" : text;
|
| 906 |
+
options = options ? ", { " + Object.entries(options).map(_ref2 => {
|
| 907 |
+
let [k, v] = _ref2;
|
| 908 |
+
return k + ": " + v;
|
| 909 |
+
}).join(', ') + " }" : '';
|
| 910 |
+
return queryMethod + "(" + text + options + ")";
|
| 911 |
+
}
|
| 912 |
+
};
|
| 913 |
+
}
|
| 914 |
+
function canSuggest(currentMethod, requestedMethod, data) {
|
| 915 |
+
return data && (!requestedMethod || requestedMethod.toLowerCase() === currentMethod.toLowerCase());
|
| 916 |
+
}
|
| 917 |
+
function getSuggestedQuery(element, variant, method) {
|
| 918 |
+
var _element$getAttribute, _getImplicitAriaRoles;
|
| 919 |
+
if (variant === void 0) {
|
| 920 |
+
variant = 'get';
|
| 921 |
+
}
|
| 922 |
+
// don't create suggestions for script and style elements
|
| 923 |
+
if (element.matches(getConfig().defaultIgnore)) {
|
| 924 |
+
return undefined;
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
+
//We prefer to suggest something else if the role is generic
|
| 928 |
+
const role = (_element$getAttribute = element.getAttribute('role')) != null ? _element$getAttribute : (_getImplicitAriaRoles = getImplicitAriaRoles(element)) == null ? void 0 : _getImplicitAriaRoles[0];
|
| 929 |
+
if (role !== 'generic' && canSuggest('Role', method, role)) {
|
| 930 |
+
return makeSuggestion('Role', element, role, {
|
| 931 |
+
variant,
|
| 932 |
+
name: computeAccessibleName(element, {
|
| 933 |
+
computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements
|
| 934 |
+
})
|
| 935 |
+
});
|
| 936 |
+
}
|
| 937 |
+
const labelText = getLabels(document, element).map(label => label.content).join(' ');
|
| 938 |
+
if (canSuggest('LabelText', method, labelText)) {
|
| 939 |
+
return makeSuggestion('LabelText', element, labelText, {
|
| 940 |
+
variant
|
| 941 |
+
});
|
| 942 |
+
}
|
| 943 |
+
const placeholderText = element.getAttribute('placeholder');
|
| 944 |
+
if (canSuggest('PlaceholderText', method, placeholderText)) {
|
| 945 |
+
return makeSuggestion('PlaceholderText', element, placeholderText, {
|
| 946 |
+
variant
|
| 947 |
+
});
|
| 948 |
+
}
|
| 949 |
+
const textContent = normalize(getNodeText(element));
|
| 950 |
+
if (canSuggest('Text', method, textContent)) {
|
| 951 |
+
return makeSuggestion('Text', element, textContent, {
|
| 952 |
+
variant
|
| 953 |
+
});
|
| 954 |
+
}
|
| 955 |
+
if (canSuggest('DisplayValue', method, element.value)) {
|
| 956 |
+
return makeSuggestion('DisplayValue', element, normalize(element.value), {
|
| 957 |
+
variant
|
| 958 |
+
});
|
| 959 |
+
}
|
| 960 |
+
const alt = element.getAttribute('alt');
|
| 961 |
+
if (canSuggest('AltText', method, alt)) {
|
| 962 |
+
return makeSuggestion('AltText', element, alt, {
|
| 963 |
+
variant
|
| 964 |
+
});
|
| 965 |
+
}
|
| 966 |
+
const title = element.getAttribute('title');
|
| 967 |
+
if (canSuggest('Title', method, title)) {
|
| 968 |
+
return makeSuggestion('Title', element, title, {
|
| 969 |
+
variant
|
| 970 |
+
});
|
| 971 |
+
}
|
| 972 |
+
const testId = element.getAttribute(getConfig().testIdAttribute);
|
| 973 |
+
if (canSuggest('TestId', method, testId)) {
|
| 974 |
+
return makeSuggestion('TestId', element, testId, {
|
| 975 |
+
variant
|
| 976 |
+
});
|
| 977 |
+
}
|
| 978 |
+
return undefined;
|
| 979 |
+
}
|
| 980 |
+
|
| 981 |
+
// This is so the stack trace the developer sees is one that's
|
| 982 |
+
// closer to their code (because async stack traces are hard to follow).
|
| 983 |
+
function copyStackTrace(target, source) {
|
| 984 |
+
target.stack = source.stack.replace(source.message, target.message);
|
| 985 |
+
}
|
| 986 |
+
function waitFor(callback, _ref) {
|
| 987 |
+
let {
|
| 988 |
+
container = getDocument(),
|
| 989 |
+
timeout = getConfig().asyncUtilTimeout,
|
| 990 |
+
showOriginalStackTrace = getConfig().showOriginalStackTrace,
|
| 991 |
+
stackTraceError,
|
| 992 |
+
interval = 50,
|
| 993 |
+
onTimeout = error => {
|
| 994 |
+
Object.defineProperty(error, 'message', {
|
| 995 |
+
value: getConfig().getElementError(error.message, container).message
|
| 996 |
+
});
|
| 997 |
+
return error;
|
| 998 |
+
},
|
| 999 |
+
mutationObserverOptions = {
|
| 1000 |
+
subtree: true,
|
| 1001 |
+
childList: true,
|
| 1002 |
+
attributes: true,
|
| 1003 |
+
characterData: true
|
| 1004 |
+
}
|
| 1005 |
+
} = _ref;
|
| 1006 |
+
if (typeof callback !== 'function') {
|
| 1007 |
+
throw new TypeError('Received `callback` arg must be a function');
|
| 1008 |
+
}
|
| 1009 |
+
return new Promise(async (resolve, reject) => {
|
| 1010 |
+
let lastError, intervalId, observer;
|
| 1011 |
+
let finished = false;
|
| 1012 |
+
let promiseStatus = 'idle';
|
| 1013 |
+
const overallTimeoutTimer = setTimeout(handleTimeout, timeout);
|
| 1014 |
+
const usingJestFakeTimers = jestFakeTimersAreEnabled();
|
| 1015 |
+
if (usingJestFakeTimers) {
|
| 1016 |
+
const {
|
| 1017 |
+
unstable_advanceTimersWrapper: advanceTimersWrapper
|
| 1018 |
+
} = getConfig();
|
| 1019 |
+
checkCallback();
|
| 1020 |
+
// this is a dangerous rule to disable because it could lead to an
|
| 1021 |
+
// infinite loop. However, eslint isn't smart enough to know that we're
|
| 1022 |
+
// setting finished inside `onDone` which will be called when we're done
|
| 1023 |
+
// waiting or when we've timed out.
|
| 1024 |
+
// eslint-disable-next-line no-unmodified-loop-condition
|
| 1025 |
+
while (!finished) {
|
| 1026 |
+
if (!jestFakeTimersAreEnabled()) {
|
| 1027 |
+
const error = new Error("Changed from using fake timers to real timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to real timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830");
|
| 1028 |
+
if (!showOriginalStackTrace) copyStackTrace(error, stackTraceError);
|
| 1029 |
+
reject(error);
|
| 1030 |
+
return;
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
// In this rare case, we *need* to wait for in-flight promises
|
| 1034 |
+
// to resolve before continuing. We don't need to take advantage
|
| 1035 |
+
// of parallelization so we're fine.
|
| 1036 |
+
// https://stackoverflow.com/a/59243586/971592
|
| 1037 |
+
// eslint-disable-next-line no-await-in-loop
|
| 1038 |
+
await advanceTimersWrapper(async () => {
|
| 1039 |
+
// we *could* (maybe should?) use `advanceTimersToNextTimer` but it's
|
| 1040 |
+
// possible that could make this loop go on forever if someone is using
|
| 1041 |
+
// third party code that's setting up recursive timers so rapidly that
|
| 1042 |
+
// the user's timer's don't get a chance to resolve. So we'll advance
|
| 1043 |
+
// by an interval instead. (We have a test for this case).
|
| 1044 |
+
jest.advanceTimersByTime(interval);
|
| 1045 |
+
});
|
| 1046 |
+
|
| 1047 |
+
// Could have timed-out
|
| 1048 |
+
if (finished) {
|
| 1049 |
+
break;
|
| 1050 |
+
}
|
| 1051 |
+
// It's really important that checkCallback is run *before* we flush
|
| 1052 |
+
// in-flight promises. To be honest, I'm not sure why, and I can't quite
|
| 1053 |
+
// think of a way to reproduce the problem in a test, but I spent
|
| 1054 |
+
// an entire day banging my head against a wall on this.
|
| 1055 |
+
checkCallback();
|
| 1056 |
+
}
|
| 1057 |
+
} else {
|
| 1058 |
+
try {
|
| 1059 |
+
checkContainerType(container);
|
| 1060 |
+
} catch (e) {
|
| 1061 |
+
reject(e);
|
| 1062 |
+
return;
|
| 1063 |
+
}
|
| 1064 |
+
intervalId = setInterval(checkRealTimersCallback, interval);
|
| 1065 |
+
const {
|
| 1066 |
+
MutationObserver
|
| 1067 |
+
} = getWindowFromNode(container);
|
| 1068 |
+
observer = new MutationObserver(checkRealTimersCallback);
|
| 1069 |
+
observer.observe(container, mutationObserverOptions);
|
| 1070 |
+
checkCallback();
|
| 1071 |
+
}
|
| 1072 |
+
function onDone(error, result) {
|
| 1073 |
+
finished = true;
|
| 1074 |
+
clearTimeout(overallTimeoutTimer);
|
| 1075 |
+
if (!usingJestFakeTimers) {
|
| 1076 |
+
clearInterval(intervalId);
|
| 1077 |
+
observer.disconnect();
|
| 1078 |
+
}
|
| 1079 |
+
if (error) {
|
| 1080 |
+
reject(error);
|
| 1081 |
+
} else {
|
| 1082 |
+
resolve(result);
|
| 1083 |
+
}
|
| 1084 |
+
}
|
| 1085 |
+
function checkRealTimersCallback() {
|
| 1086 |
+
if (jestFakeTimersAreEnabled()) {
|
| 1087 |
+
const error = new Error("Changed from using real timers to fake timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to fake timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830");
|
| 1088 |
+
if (!showOriginalStackTrace) copyStackTrace(error, stackTraceError);
|
| 1089 |
+
return reject(error);
|
| 1090 |
+
} else {
|
| 1091 |
+
return checkCallback();
|
| 1092 |
+
}
|
| 1093 |
+
}
|
| 1094 |
+
function checkCallback() {
|
| 1095 |
+
if (promiseStatus === 'pending') return;
|
| 1096 |
+
try {
|
| 1097 |
+
const result = runWithExpensiveErrorDiagnosticsDisabled(callback);
|
| 1098 |
+
if (typeof (result == null ? void 0 : result.then) === 'function') {
|
| 1099 |
+
promiseStatus = 'pending';
|
| 1100 |
+
result.then(resolvedValue => {
|
| 1101 |
+
promiseStatus = 'resolved';
|
| 1102 |
+
onDone(null, resolvedValue);
|
| 1103 |
+
}, rejectedValue => {
|
| 1104 |
+
promiseStatus = 'rejected';
|
| 1105 |
+
lastError = rejectedValue;
|
| 1106 |
+
});
|
| 1107 |
+
} else {
|
| 1108 |
+
onDone(null, result);
|
| 1109 |
+
}
|
| 1110 |
+
// If `callback` throws, wait for the next mutation, interval, or timeout.
|
| 1111 |
+
} catch (error) {
|
| 1112 |
+
// Save the most recent callback error to reject the promise with it in the event of a timeout
|
| 1113 |
+
lastError = error;
|
| 1114 |
+
}
|
| 1115 |
+
}
|
| 1116 |
+
function handleTimeout() {
|
| 1117 |
+
let error;
|
| 1118 |
+
if (lastError) {
|
| 1119 |
+
error = lastError;
|
| 1120 |
+
if (!showOriginalStackTrace && error.name === 'TestingLibraryElementError') {
|
| 1121 |
+
copyStackTrace(error, stackTraceError);
|
| 1122 |
+
}
|
| 1123 |
+
} else {
|
| 1124 |
+
error = new Error('Timed out in waitFor.');
|
| 1125 |
+
if (!showOriginalStackTrace) {
|
| 1126 |
+
copyStackTrace(error, stackTraceError);
|
| 1127 |
+
}
|
| 1128 |
+
}
|
| 1129 |
+
onDone(onTimeout(error), null);
|
| 1130 |
+
}
|
| 1131 |
+
});
|
| 1132 |
+
}
|
| 1133 |
+
function waitForWrapper(callback, options) {
|
| 1134 |
+
// create the error here so its stack trace is as close to the
|
| 1135 |
+
// calling code as possible
|
| 1136 |
+
const stackTraceError = new Error('STACK_TRACE_MESSAGE');
|
| 1137 |
+
return getConfig().asyncWrapper(() => waitFor(callback, {
|
| 1138 |
+
stackTraceError,
|
| 1139 |
+
...options
|
| 1140 |
+
}));
|
| 1141 |
+
}
|
| 1142 |
+
|
| 1143 |
+
/*
|
| 1144 |
+
eslint
|
| 1145 |
+
max-lines-per-function: ["error", {"max": 200}],
|
| 1146 |
+
*/
|
| 1147 |
+
|
| 1148 |
+
function getElementError(message, container) {
|
| 1149 |
+
return getConfig().getElementError(message, container);
|
| 1150 |
+
}
|
| 1151 |
+
function getMultipleElementsFoundError(message, container) {
|
| 1152 |
+
return getElementError(message + "\n\n(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).", container);
|
| 1153 |
+
}
|
| 1154 |
+
function queryAllByAttribute(attribute, container, text, _temp) {
|
| 1155 |
+
let {
|
| 1156 |
+
exact = true,
|
| 1157 |
+
collapseWhitespace,
|
| 1158 |
+
trim,
|
| 1159 |
+
normalizer
|
| 1160 |
+
} = _temp === void 0 ? {} : _temp;
|
| 1161 |
+
const matcher = exact ? matches : fuzzyMatches;
|
| 1162 |
+
const matchNormalizer = makeNormalizer({
|
| 1163 |
+
collapseWhitespace,
|
| 1164 |
+
trim,
|
| 1165 |
+
normalizer
|
| 1166 |
+
});
|
| 1167 |
+
return Array.from(container.querySelectorAll("[" + attribute + "]")).filter(node => matcher(node.getAttribute(attribute), node, text, matchNormalizer));
|
| 1168 |
+
}
|
| 1169 |
+
function queryByAttribute(attribute, container, text, options) {
|
| 1170 |
+
const els = queryAllByAttribute(attribute, container, text, options);
|
| 1171 |
+
if (els.length > 1) {
|
| 1172 |
+
throw getMultipleElementsFoundError("Found multiple elements by [" + attribute + "=" + text + "]", container);
|
| 1173 |
+
}
|
| 1174 |
+
return els[0] || null;
|
| 1175 |
+
}
|
| 1176 |
+
|
| 1177 |
+
// this accepts a query function and returns a function which throws an error
|
| 1178 |
+
// if more than one elements is returned, otherwise it returns the first
|
| 1179 |
+
// element or null
|
| 1180 |
+
function makeSingleQuery(allQuery, getMultipleError) {
|
| 1181 |
+
return function (container) {
|
| 1182 |
+
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
| 1183 |
+
args[_key - 1] = arguments[_key];
|
| 1184 |
+
}
|
| 1185 |
+
const els = allQuery(container, ...args);
|
| 1186 |
+
if (els.length > 1) {
|
| 1187 |
+
const elementStrings = els.map(element => getElementError(null, element).message).join('\n\n');
|
| 1188 |
+
throw getMultipleElementsFoundError(getMultipleError(container, ...args) + "\n\nHere are the matching elements:\n\n" + elementStrings, container);
|
| 1189 |
+
}
|
| 1190 |
+
return els[0] || null;
|
| 1191 |
+
};
|
| 1192 |
+
}
|
| 1193 |
+
function getSuggestionError(suggestion, container) {
|
| 1194 |
+
return getConfig().getElementError("A better query is available, try this:\n" + suggestion.toString() + "\n", container);
|
| 1195 |
+
}
|
| 1196 |
+
|
| 1197 |
+
// this accepts a query function and returns a function which throws an error
|
| 1198 |
+
// if an empty list of elements is returned
|
| 1199 |
+
function makeGetAllQuery(allQuery, getMissingError) {
|
| 1200 |
+
return function (container) {
|
| 1201 |
+
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
| 1202 |
+
args[_key2 - 1] = arguments[_key2];
|
| 1203 |
+
}
|
| 1204 |
+
const els = allQuery(container, ...args);
|
| 1205 |
+
if (!els.length) {
|
| 1206 |
+
throw getConfig().getElementError(getMissingError(container, ...args), container);
|
| 1207 |
+
}
|
| 1208 |
+
return els;
|
| 1209 |
+
};
|
| 1210 |
+
}
|
| 1211 |
+
|
| 1212 |
+
// this accepts a getter query function and returns a function which calls
|
| 1213 |
+
// waitFor and passing a function which invokes the getter.
|
| 1214 |
+
function makeFindQuery(getter) {
|
| 1215 |
+
return (container, text, options, waitForOptions) => {
|
| 1216 |
+
return waitForWrapper(() => {
|
| 1217 |
+
return getter(container, text, options);
|
| 1218 |
+
}, {
|
| 1219 |
+
container,
|
| 1220 |
+
...waitForOptions
|
| 1221 |
+
});
|
| 1222 |
+
};
|
| 1223 |
+
}
|
| 1224 |
+
const wrapSingleQueryWithSuggestion = (query, queryAllByName, variant) => function (container) {
|
| 1225 |
+
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
| 1226 |
+
args[_key3 - 1] = arguments[_key3];
|
| 1227 |
+
}
|
| 1228 |
+
const element = query(container, ...args);
|
| 1229 |
+
const [{
|
| 1230 |
+
suggest = getConfig().throwSuggestions
|
| 1231 |
+
} = {}] = args.slice(-1);
|
| 1232 |
+
if (element && suggest) {
|
| 1233 |
+
const suggestion = getSuggestedQuery(element, variant);
|
| 1234 |
+
if (suggestion && !queryAllByName.endsWith(suggestion.queryName)) {
|
| 1235 |
+
throw getSuggestionError(suggestion.toString(), container);
|
| 1236 |
+
}
|
| 1237 |
+
}
|
| 1238 |
+
return element;
|
| 1239 |
+
};
|
| 1240 |
+
const wrapAllByQueryWithSuggestion = (query, queryAllByName, variant) => function (container) {
|
| 1241 |
+
for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
|
| 1242 |
+
args[_key4 - 1] = arguments[_key4];
|
| 1243 |
+
}
|
| 1244 |
+
const els = query(container, ...args);
|
| 1245 |
+
const [{
|
| 1246 |
+
suggest = getConfig().throwSuggestions
|
| 1247 |
+
} = {}] = args.slice(-1);
|
| 1248 |
+
if (els.length && suggest) {
|
| 1249 |
+
// get a unique list of all suggestion messages. We are only going to make a suggestion if
|
| 1250 |
+
// all the suggestions are the same
|
| 1251 |
+
const uniqueSuggestionMessages = [...new Set(els.map(element => {
|
| 1252 |
+
var _getSuggestedQuery;
|
| 1253 |
+
return (_getSuggestedQuery = getSuggestedQuery(element, variant)) == null ? void 0 : _getSuggestedQuery.toString();
|
| 1254 |
+
}))];
|
| 1255 |
+
if (
|
| 1256 |
+
// only want to suggest if all the els have the same suggestion.
|
| 1257 |
+
uniqueSuggestionMessages.length === 1 && !queryAllByName.endsWith(
|
| 1258 |
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: Can this be null at runtime?
|
| 1259 |
+
getSuggestedQuery(els[0], variant).queryName)) {
|
| 1260 |
+
throw getSuggestionError(uniqueSuggestionMessages[0], container);
|
| 1261 |
+
}
|
| 1262 |
+
}
|
| 1263 |
+
return els;
|
| 1264 |
+
};
|
| 1265 |
+
|
| 1266 |
+
// TODO: This deviates from the published declarations
|
| 1267 |
+
// However, the implementation always required a dyadic (after `container`) not variadic `queryAllBy` considering the implementation of `makeFindQuery`
|
| 1268 |
+
// This is at least statically true and can be verified by accepting `QueryMethod<Arguments, HTMLElement[]>`
|
| 1269 |
+
function buildQueries(queryAllBy, getMultipleError, getMissingError) {
|
| 1270 |
+
const queryBy = wrapSingleQueryWithSuggestion(makeSingleQuery(queryAllBy, getMultipleError), queryAllBy.name, 'query');
|
| 1271 |
+
const getAllBy = makeGetAllQuery(queryAllBy, getMissingError);
|
| 1272 |
+
const getBy = makeSingleQuery(getAllBy, getMultipleError);
|
| 1273 |
+
const getByWithSuggestions = wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'get');
|
| 1274 |
+
const getAllWithSuggestions = wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name.replace('query', 'get'), 'getAll');
|
| 1275 |
+
const findAllBy = makeFindQuery(wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name, 'findAll'));
|
| 1276 |
+
const findBy = makeFindQuery(wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'find'));
|
| 1277 |
+
return [queryBy, getAllWithSuggestions, getByWithSuggestions, findAllBy, findBy];
|
| 1278 |
+
}
|
| 1279 |
+
|
| 1280 |
+
var queryHelpers = /*#__PURE__*/Object.freeze({
|
| 1281 |
+
__proto__: null,
|
| 1282 |
+
getElementError: getElementError,
|
| 1283 |
+
wrapAllByQueryWithSuggestion: wrapAllByQueryWithSuggestion,
|
| 1284 |
+
wrapSingleQueryWithSuggestion: wrapSingleQueryWithSuggestion,
|
| 1285 |
+
getMultipleElementsFoundError: getMultipleElementsFoundError,
|
| 1286 |
+
queryAllByAttribute: queryAllByAttribute,
|
| 1287 |
+
queryByAttribute: queryByAttribute,
|
| 1288 |
+
makeSingleQuery: makeSingleQuery,
|
| 1289 |
+
makeGetAllQuery: makeGetAllQuery,
|
| 1290 |
+
makeFindQuery: makeFindQuery,
|
| 1291 |
+
buildQueries: buildQueries
|
| 1292 |
+
});
|
| 1293 |
+
|
| 1294 |
+
function queryAllLabels(container) {
|
| 1295 |
+
return Array.from(container.querySelectorAll('label,input')).map(node => {
|
| 1296 |
+
return {
|
| 1297 |
+
node,
|
| 1298 |
+
textToMatch: getLabelContent(node)
|
| 1299 |
+
};
|
| 1300 |
+
}).filter(_ref => {
|
| 1301 |
+
let {
|
| 1302 |
+
textToMatch
|
| 1303 |
+
} = _ref;
|
| 1304 |
+
return textToMatch !== null;
|
| 1305 |
+
});
|
| 1306 |
+
}
|
| 1307 |
+
const queryAllLabelsByText = function (container, text, _temp) {
|
| 1308 |
+
let {
|
| 1309 |
+
exact = true,
|
| 1310 |
+
trim,
|
| 1311 |
+
collapseWhitespace,
|
| 1312 |
+
normalizer
|
| 1313 |
+
} = _temp === void 0 ? {} : _temp;
|
| 1314 |
+
const matcher = exact ? matches : fuzzyMatches;
|
| 1315 |
+
const matchNormalizer = makeNormalizer({
|
| 1316 |
+
collapseWhitespace,
|
| 1317 |
+
trim,
|
| 1318 |
+
normalizer
|
| 1319 |
+
});
|
| 1320 |
+
const textToMatchByLabels = queryAllLabels(container);
|
| 1321 |
+
return textToMatchByLabels.filter(_ref2 => {
|
| 1322 |
+
let {
|
| 1323 |
+
node,
|
| 1324 |
+
textToMatch
|
| 1325 |
+
} = _ref2;
|
| 1326 |
+
return matcher(textToMatch, node, text, matchNormalizer);
|
| 1327 |
+
}).map(_ref3 => {
|
| 1328 |
+
let {
|
| 1329 |
+
node
|
| 1330 |
+
} = _ref3;
|
| 1331 |
+
return node;
|
| 1332 |
+
});
|
| 1333 |
+
};
|
| 1334 |
+
const queryAllByLabelText = function (container, text, _temp2) {
|
| 1335 |
+
let {
|
| 1336 |
+
selector = '*',
|
| 1337 |
+
exact = true,
|
| 1338 |
+
collapseWhitespace,
|
| 1339 |
+
trim,
|
| 1340 |
+
normalizer
|
| 1341 |
+
} = _temp2 === void 0 ? {} : _temp2;
|
| 1342 |
+
checkContainerType(container);
|
| 1343 |
+
const matcher = exact ? matches : fuzzyMatches;
|
| 1344 |
+
const matchNormalizer = makeNormalizer({
|
| 1345 |
+
collapseWhitespace,
|
| 1346 |
+
trim,
|
| 1347 |
+
normalizer
|
| 1348 |
+
});
|
| 1349 |
+
const matchingLabelledElements = Array.from(container.querySelectorAll('*')).filter(element => {
|
| 1350 |
+
return getRealLabels(element).length || element.hasAttribute('aria-labelledby');
|
| 1351 |
+
}).reduce((labelledElements, labelledElement) => {
|
| 1352 |
+
const labelList = getLabels(container, labelledElement, {
|
| 1353 |
+
selector
|
| 1354 |
+
});
|
| 1355 |
+
labelList.filter(label => Boolean(label.formControl)).forEach(label => {
|
| 1356 |
+
if (matcher(label.content, label.formControl, text, matchNormalizer) && label.formControl) {
|
| 1357 |
+
labelledElements.push(label.formControl);
|
| 1358 |
+
}
|
| 1359 |
+
});
|
| 1360 |
+
const labelsValue = labelList.filter(label => Boolean(label.content)).map(label => label.content);
|
| 1361 |
+
if (matcher(labelsValue.join(' '), labelledElement, text, matchNormalizer)) {
|
| 1362 |
+
labelledElements.push(labelledElement);
|
| 1363 |
+
}
|
| 1364 |
+
if (labelsValue.length > 1) {
|
| 1365 |
+
labelsValue.forEach((labelValue, index) => {
|
| 1366 |
+
if (matcher(labelValue, labelledElement, text, matchNormalizer)) {
|
| 1367 |
+
labelledElements.push(labelledElement);
|
| 1368 |
+
}
|
| 1369 |
+
const labelsFiltered = [...labelsValue];
|
| 1370 |
+
labelsFiltered.splice(index, 1);
|
| 1371 |
+
if (labelsFiltered.length > 1) {
|
| 1372 |
+
if (matcher(labelsFiltered.join(' '), labelledElement, text, matchNormalizer)) {
|
| 1373 |
+
labelledElements.push(labelledElement);
|
| 1374 |
+
}
|
| 1375 |
+
}
|
| 1376 |
+
});
|
| 1377 |
+
}
|
| 1378 |
+
return labelledElements;
|
| 1379 |
+
}, []).concat(queryAllByAttribute('aria-label', container, text, {
|
| 1380 |
+
exact,
|
| 1381 |
+
normalizer: matchNormalizer
|
| 1382 |
+
}));
|
| 1383 |
+
return Array.from(new Set(matchingLabelledElements)).filter(element => element.matches(selector));
|
| 1384 |
+
};
|
| 1385 |
+
|
| 1386 |
+
// the getAll* query would normally look like this:
|
| 1387 |
+
// const getAllByLabelText = makeGetAllQuery(
|
| 1388 |
+
// queryAllByLabelText,
|
| 1389 |
+
// (c, text) => `Unable to find a label with the text of: ${text}`,
|
| 1390 |
+
// )
|
| 1391 |
+
// however, we can give a more helpful error message than the generic one,
|
| 1392 |
+
// so we're writing this one out by hand.
|
| 1393 |
+
const getAllByLabelText = function (container, text) {
|
| 1394 |
+
for (var _len = arguments.length, rest = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
| 1395 |
+
rest[_key - 2] = arguments[_key];
|
| 1396 |
+
}
|
| 1397 |
+
const els = queryAllByLabelText(container, text, ...rest);
|
| 1398 |
+
if (!els.length) {
|
| 1399 |
+
const labels = queryAllLabelsByText(container, text, ...rest);
|
| 1400 |
+
if (labels.length) {
|
| 1401 |
+
const tagNames = labels.map(label => getTagNameOfElementAssociatedWithLabelViaFor(container, label)).filter(tagName => !!tagName);
|
| 1402 |
+
if (tagNames.length) {
|
| 1403 |
+
throw getConfig().getElementError(tagNames.map(tagName => "Found a label with the text of: " + text + ", however the element associated with this label (<" + tagName + " />) is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a <" + tagName + " />, you can use aria-label or aria-labelledby instead.").join('\n\n'), container);
|
| 1404 |
+
} else {
|
| 1405 |
+
throw getConfig().getElementError("Found a label with the text of: " + text + ", however no form control was found associated to that label. Make sure you're using the \"for\" attribute or \"aria-labelledby\" attribute correctly.", container);
|
| 1406 |
+
}
|
| 1407 |
+
} else {
|
| 1408 |
+
throw getConfig().getElementError("Unable to find a label with the text of: " + text, container);
|
| 1409 |
+
}
|
| 1410 |
+
}
|
| 1411 |
+
return els;
|
| 1412 |
+
};
|
| 1413 |
+
function getTagNameOfElementAssociatedWithLabelViaFor(container, label) {
|
| 1414 |
+
const htmlFor = label.getAttribute('for');
|
| 1415 |
+
if (!htmlFor) {
|
| 1416 |
+
return null;
|
| 1417 |
+
}
|
| 1418 |
+
const element = container.querySelector("[id=\"" + htmlFor + "\"]");
|
| 1419 |
+
return element ? element.tagName.toLowerCase() : null;
|
| 1420 |
+
}
|
| 1421 |
+
|
| 1422 |
+
// the reason mentioned above is the same reason we're not using buildQueries
|
| 1423 |
+
const getMultipleError$7 = (c, text) => "Found multiple elements with the text of: " + text;
|
| 1424 |
+
const queryByLabelText = wrapSingleQueryWithSuggestion(makeSingleQuery(queryAllByLabelText, getMultipleError$7), queryAllByLabelText.name, 'query');
|
| 1425 |
+
const getByLabelText = makeSingleQuery(getAllByLabelText, getMultipleError$7);
|
| 1426 |
+
const findAllByLabelText = makeFindQuery(wrapAllByQueryWithSuggestion(getAllByLabelText, getAllByLabelText.name, 'findAll'));
|
| 1427 |
+
const findByLabelText = makeFindQuery(wrapSingleQueryWithSuggestion(getByLabelText, getAllByLabelText.name, 'find'));
|
| 1428 |
+
const getAllByLabelTextWithSuggestions = wrapAllByQueryWithSuggestion(getAllByLabelText, getAllByLabelText.name, 'getAll');
|
| 1429 |
+
const getByLabelTextWithSuggestions = wrapSingleQueryWithSuggestion(getByLabelText, getAllByLabelText.name, 'get');
|
| 1430 |
+
const queryAllByLabelTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByLabelText, queryAllByLabelText.name, 'queryAll');
|
| 1431 |
+
|
| 1432 |
+
const queryAllByPlaceholderText = function () {
|
| 1433 |
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
| 1434 |
+
args[_key] = arguments[_key];
|
| 1435 |
+
}
|
| 1436 |
+
checkContainerType(args[0]);
|
| 1437 |
+
return queryAllByAttribute('placeholder', ...args);
|
| 1438 |
+
};
|
| 1439 |
+
const getMultipleError$6 = (c, text) => "Found multiple elements with the placeholder text of: " + text;
|
| 1440 |
+
const getMissingError$6 = (c, text) => "Unable to find an element with the placeholder text of: " + text;
|
| 1441 |
+
const queryAllByPlaceholderTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByPlaceholderText, queryAllByPlaceholderText.name, 'queryAll');
|
| 1442 |
+
const [queryByPlaceholderText, getAllByPlaceholderText, getByPlaceholderText, findAllByPlaceholderText, findByPlaceholderText] = buildQueries(queryAllByPlaceholderText, getMultipleError$6, getMissingError$6);
|
| 1443 |
+
|
| 1444 |
+
const queryAllByText = function (container, text, _temp) {
|
| 1445 |
+
let {
|
| 1446 |
+
selector = '*',
|
| 1447 |
+
exact = true,
|
| 1448 |
+
collapseWhitespace,
|
| 1449 |
+
trim,
|
| 1450 |
+
ignore = getConfig().defaultIgnore,
|
| 1451 |
+
normalizer
|
| 1452 |
+
} = _temp === void 0 ? {} : _temp;
|
| 1453 |
+
checkContainerType(container);
|
| 1454 |
+
const matcher = exact ? matches : fuzzyMatches;
|
| 1455 |
+
const matchNormalizer = makeNormalizer({
|
| 1456 |
+
collapseWhitespace,
|
| 1457 |
+
trim,
|
| 1458 |
+
normalizer
|
| 1459 |
+
});
|
| 1460 |
+
let baseArray = [];
|
| 1461 |
+
if (typeof container.matches === 'function' && container.matches(selector)) {
|
| 1462 |
+
baseArray = [container];
|
| 1463 |
+
}
|
| 1464 |
+
return [...baseArray, ...Array.from(container.querySelectorAll(selector))]
|
| 1465 |
+
// TODO: `matches` according lib.dom.d.ts can get only `string` but according our code it can handle also boolean :)
|
| 1466 |
+
.filter(node => !ignore || !node.matches(ignore)).filter(node => matcher(getNodeText(node), node, text, matchNormalizer));
|
| 1467 |
+
};
|
| 1468 |
+
const getMultipleError$5 = (c, text) => "Found multiple elements with the text: " + text;
|
| 1469 |
+
const getMissingError$5 = function (c, text, options) {
|
| 1470 |
+
if (options === void 0) {
|
| 1471 |
+
options = {};
|
| 1472 |
+
}
|
| 1473 |
+
const {
|
| 1474 |
+
collapseWhitespace,
|
| 1475 |
+
trim,
|
| 1476 |
+
normalizer,
|
| 1477 |
+
selector
|
| 1478 |
+
} = options;
|
| 1479 |
+
const matchNormalizer = makeNormalizer({
|
| 1480 |
+
collapseWhitespace,
|
| 1481 |
+
trim,
|
| 1482 |
+
normalizer
|
| 1483 |
+
});
|
| 1484 |
+
const normalizedText = matchNormalizer(text.toString());
|
| 1485 |
+
const isNormalizedDifferent = normalizedText !== text.toString();
|
| 1486 |
+
const isCustomSelector = (selector != null ? selector : '*') !== '*';
|
| 1487 |
+
return "Unable to find an element with the text: " + (isNormalizedDifferent ? normalizedText + " (normalized from '" + text + "')" : text) + (isCustomSelector ? ", which matches selector '" + selector + "'" : '') + ". This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.";
|
| 1488 |
+
};
|
| 1489 |
+
const queryAllByTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByText, queryAllByText.name, 'queryAll');
|
| 1490 |
+
const [queryByText, getAllByText, getByText, findAllByText, findByText] = buildQueries(queryAllByText, getMultipleError$5, getMissingError$5);
|
| 1491 |
+
|
| 1492 |
+
const queryAllByDisplayValue = function (container, value, _temp) {
|
| 1493 |
+
let {
|
| 1494 |
+
exact = true,
|
| 1495 |
+
collapseWhitespace,
|
| 1496 |
+
trim,
|
| 1497 |
+
normalizer
|
| 1498 |
+
} = _temp === void 0 ? {} : _temp;
|
| 1499 |
+
checkContainerType(container);
|
| 1500 |
+
const matcher = exact ? matches : fuzzyMatches;
|
| 1501 |
+
const matchNormalizer = makeNormalizer({
|
| 1502 |
+
collapseWhitespace,
|
| 1503 |
+
trim,
|
| 1504 |
+
normalizer
|
| 1505 |
+
});
|
| 1506 |
+
return Array.from(container.querySelectorAll("input,textarea,select")).filter(node => {
|
| 1507 |
+
if (node.tagName === 'SELECT') {
|
| 1508 |
+
const selectedOptions = Array.from(node.options).filter(option => option.selected);
|
| 1509 |
+
return selectedOptions.some(optionNode => matcher(getNodeText(optionNode), optionNode, value, matchNormalizer));
|
| 1510 |
+
} else {
|
| 1511 |
+
return matcher(node.value, node, value, matchNormalizer);
|
| 1512 |
+
}
|
| 1513 |
+
});
|
| 1514 |
+
};
|
| 1515 |
+
const getMultipleError$4 = (c, value) => "Found multiple elements with the display value: " + value + ".";
|
| 1516 |
+
const getMissingError$4 = (c, value) => "Unable to find an element with the display value: " + value + ".";
|
| 1517 |
+
const queryAllByDisplayValueWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByDisplayValue, queryAllByDisplayValue.name, 'queryAll');
|
| 1518 |
+
const [queryByDisplayValue, getAllByDisplayValue, getByDisplayValue, findAllByDisplayValue, findByDisplayValue] = buildQueries(queryAllByDisplayValue, getMultipleError$4, getMissingError$4);
|
| 1519 |
+
|
| 1520 |
+
// Valid tags are img, input, area and custom elements
|
| 1521 |
+
const VALID_TAG_REGEXP = /^(img|input|area|.+-.+)$/i;
|
| 1522 |
+
const queryAllByAltText = function (container, alt, options) {
|
| 1523 |
+
if (options === void 0) {
|
| 1524 |
+
options = {};
|
| 1525 |
+
}
|
| 1526 |
+
checkContainerType(container);
|
| 1527 |
+
return queryAllByAttribute('alt', container, alt, options).filter(node => VALID_TAG_REGEXP.test(node.tagName));
|
| 1528 |
+
};
|
| 1529 |
+
const getMultipleError$3 = (c, alt) => "Found multiple elements with the alt text: " + alt;
|
| 1530 |
+
const getMissingError$3 = (c, alt) => "Unable to find an element with the alt text: " + alt;
|
| 1531 |
+
const queryAllByAltTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByAltText, queryAllByAltText.name, 'queryAll');
|
| 1532 |
+
const [queryByAltText, getAllByAltText, getByAltText, findAllByAltText, findByAltText] = buildQueries(queryAllByAltText, getMultipleError$3, getMissingError$3);
|
| 1533 |
+
|
| 1534 |
+
const isSvgTitle = node => {
|
| 1535 |
+
var _node$parentElement;
|
| 1536 |
+
return node.tagName.toLowerCase() === 'title' && ((_node$parentElement = node.parentElement) == null ? void 0 : _node$parentElement.tagName.toLowerCase()) === 'svg';
|
| 1537 |
+
};
|
| 1538 |
+
const queryAllByTitle = function (container, text, _temp) {
|
| 1539 |
+
let {
|
| 1540 |
+
exact = true,
|
| 1541 |
+
collapseWhitespace,
|
| 1542 |
+
trim,
|
| 1543 |
+
normalizer
|
| 1544 |
+
} = _temp === void 0 ? {} : _temp;
|
| 1545 |
+
checkContainerType(container);
|
| 1546 |
+
const matcher = exact ? matches : fuzzyMatches;
|
| 1547 |
+
const matchNormalizer = makeNormalizer({
|
| 1548 |
+
collapseWhitespace,
|
| 1549 |
+
trim,
|
| 1550 |
+
normalizer
|
| 1551 |
+
});
|
| 1552 |
+
return Array.from(container.querySelectorAll('[title], svg > title')).filter(node => matcher(node.getAttribute('title'), node, text, matchNormalizer) || isSvgTitle(node) && matcher(getNodeText(node), node, text, matchNormalizer));
|
| 1553 |
+
};
|
| 1554 |
+
const getMultipleError$2 = (c, title) => "Found multiple elements with the title: " + title + ".";
|
| 1555 |
+
const getMissingError$2 = (c, title) => "Unable to find an element with the title: " + title + ".";
|
| 1556 |
+
const queryAllByTitleWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByTitle, queryAllByTitle.name, 'queryAll');
|
| 1557 |
+
const [queryByTitle, getAllByTitle, getByTitle, findAllByTitle, findByTitle] = buildQueries(queryAllByTitle, getMultipleError$2, getMissingError$2);
|
| 1558 |
+
|
| 1559 |
+
/* eslint-disable complexity */
|
| 1560 |
+
const queryAllByRole = function (container, role, _temp) {
|
| 1561 |
+
let {
|
| 1562 |
+
hidden = getConfig().defaultHidden,
|
| 1563 |
+
name,
|
| 1564 |
+
description,
|
| 1565 |
+
queryFallbacks = false,
|
| 1566 |
+
selected,
|
| 1567 |
+
busy,
|
| 1568 |
+
checked,
|
| 1569 |
+
pressed,
|
| 1570 |
+
current,
|
| 1571 |
+
level,
|
| 1572 |
+
expanded,
|
| 1573 |
+
value: {
|
| 1574 |
+
now: valueNow,
|
| 1575 |
+
min: valueMin,
|
| 1576 |
+
max: valueMax,
|
| 1577 |
+
text: valueText
|
| 1578 |
+
} = {}
|
| 1579 |
+
} = _temp === void 0 ? {} : _temp;
|
| 1580 |
+
checkContainerType(container);
|
| 1581 |
+
if (selected !== undefined) {
|
| 1582 |
+
var _allRoles$get;
|
| 1583 |
+
// guard against unknown roles
|
| 1584 |
+
if (((_allRoles$get = roles.get(role)) == null ? void 0 : _allRoles$get.props['aria-selected']) === undefined) {
|
| 1585 |
+
throw new Error("\"aria-selected\" is not supported on role \"" + role + "\".");
|
| 1586 |
+
}
|
| 1587 |
+
}
|
| 1588 |
+
if (busy !== undefined) {
|
| 1589 |
+
var _allRoles$get2;
|
| 1590 |
+
// guard against unknown roles
|
| 1591 |
+
if (((_allRoles$get2 = roles.get(role)) == null ? void 0 : _allRoles$get2.props['aria-busy']) === undefined) {
|
| 1592 |
+
throw new Error("\"aria-busy\" is not supported on role \"" + role + "\".");
|
| 1593 |
+
}
|
| 1594 |
+
}
|
| 1595 |
+
if (checked !== undefined) {
|
| 1596 |
+
var _allRoles$get3;
|
| 1597 |
+
// guard against unknown roles
|
| 1598 |
+
if (((_allRoles$get3 = roles.get(role)) == null ? void 0 : _allRoles$get3.props['aria-checked']) === undefined) {
|
| 1599 |
+
throw new Error("\"aria-checked\" is not supported on role \"" + role + "\".");
|
| 1600 |
+
}
|
| 1601 |
+
}
|
| 1602 |
+
if (pressed !== undefined) {
|
| 1603 |
+
var _allRoles$get4;
|
| 1604 |
+
// guard against unknown roles
|
| 1605 |
+
if (((_allRoles$get4 = roles.get(role)) == null ? void 0 : _allRoles$get4.props['aria-pressed']) === undefined) {
|
| 1606 |
+
throw new Error("\"aria-pressed\" is not supported on role \"" + role + "\".");
|
| 1607 |
+
}
|
| 1608 |
+
}
|
| 1609 |
+
if (current !== undefined) {
|
| 1610 |
+
var _allRoles$get5;
|
| 1611 |
+
/* istanbul ignore next */
|
| 1612 |
+
// guard against unknown roles
|
| 1613 |
+
// All currently released ARIA versions support `aria-current` on all roles.
|
| 1614 |
+
// Leaving this for symmetry and forward compatibility
|
| 1615 |
+
if (((_allRoles$get5 = roles.get(role)) == null ? void 0 : _allRoles$get5.props['aria-current']) === undefined) {
|
| 1616 |
+
throw new Error("\"aria-current\" is not supported on role \"" + role + "\".");
|
| 1617 |
+
}
|
| 1618 |
+
}
|
| 1619 |
+
if (level !== undefined) {
|
| 1620 |
+
// guard against using `level` option with any role other than `heading`
|
| 1621 |
+
if (role !== 'heading') {
|
| 1622 |
+
throw new Error("Role \"" + role + "\" cannot have \"level\" property.");
|
| 1623 |
+
}
|
| 1624 |
+
}
|
| 1625 |
+
if (valueNow !== undefined) {
|
| 1626 |
+
var _allRoles$get6;
|
| 1627 |
+
// guard against unknown roles
|
| 1628 |
+
if (((_allRoles$get6 = roles.get(role)) == null ? void 0 : _allRoles$get6.props['aria-valuenow']) === undefined) {
|
| 1629 |
+
throw new Error("\"aria-valuenow\" is not supported on role \"" + role + "\".");
|
| 1630 |
+
}
|
| 1631 |
+
}
|
| 1632 |
+
if (valueMax !== undefined) {
|
| 1633 |
+
var _allRoles$get7;
|
| 1634 |
+
// guard against unknown roles
|
| 1635 |
+
if (((_allRoles$get7 = roles.get(role)) == null ? void 0 : _allRoles$get7.props['aria-valuemax']) === undefined) {
|
| 1636 |
+
throw new Error("\"aria-valuemax\" is not supported on role \"" + role + "\".");
|
| 1637 |
+
}
|
| 1638 |
+
}
|
| 1639 |
+
if (valueMin !== undefined) {
|
| 1640 |
+
var _allRoles$get8;
|
| 1641 |
+
// guard against unknown roles
|
| 1642 |
+
if (((_allRoles$get8 = roles.get(role)) == null ? void 0 : _allRoles$get8.props['aria-valuemin']) === undefined) {
|
| 1643 |
+
throw new Error("\"aria-valuemin\" is not supported on role \"" + role + "\".");
|
| 1644 |
+
}
|
| 1645 |
+
}
|
| 1646 |
+
if (valueText !== undefined) {
|
| 1647 |
+
var _allRoles$get9;
|
| 1648 |
+
// guard against unknown roles
|
| 1649 |
+
if (((_allRoles$get9 = roles.get(role)) == null ? void 0 : _allRoles$get9.props['aria-valuetext']) === undefined) {
|
| 1650 |
+
throw new Error("\"aria-valuetext\" is not supported on role \"" + role + "\".");
|
| 1651 |
+
}
|
| 1652 |
+
}
|
| 1653 |
+
if (expanded !== undefined) {
|
| 1654 |
+
var _allRoles$get0;
|
| 1655 |
+
// guard against unknown roles
|
| 1656 |
+
if (((_allRoles$get0 = roles.get(role)) == null ? void 0 : _allRoles$get0.props['aria-expanded']) === undefined) {
|
| 1657 |
+
throw new Error("\"aria-expanded\" is not supported on role \"" + role + "\".");
|
| 1658 |
+
}
|
| 1659 |
+
}
|
| 1660 |
+
const subtreeIsInaccessibleCache = new WeakMap();
|
| 1661 |
+
function cachedIsSubtreeInaccessible(element) {
|
| 1662 |
+
if (!subtreeIsInaccessibleCache.has(element)) {
|
| 1663 |
+
subtreeIsInaccessibleCache.set(element, isSubtreeInaccessible(element));
|
| 1664 |
+
}
|
| 1665 |
+
return subtreeIsInaccessibleCache.get(element);
|
| 1666 |
+
}
|
| 1667 |
+
return Array.from(container.querySelectorAll(
|
| 1668 |
+
// Only query elements that can be matched by the following filters
|
| 1669 |
+
makeRoleSelector(role))).filter(node => {
|
| 1670 |
+
const isRoleSpecifiedExplicitly = node.hasAttribute('role');
|
| 1671 |
+
if (isRoleSpecifiedExplicitly) {
|
| 1672 |
+
const roleValue = node.getAttribute('role');
|
| 1673 |
+
if (queryFallbacks) {
|
| 1674 |
+
return roleValue.split(' ').filter(Boolean).some(roleAttributeToken => roleAttributeToken === role);
|
| 1675 |
+
}
|
| 1676 |
+
// other wise only send the first token to match
|
| 1677 |
+
const [firstRoleAttributeToken] = roleValue.split(' ');
|
| 1678 |
+
return firstRoleAttributeToken === role;
|
| 1679 |
+
}
|
| 1680 |
+
const implicitRoles = getImplicitAriaRoles(node);
|
| 1681 |
+
return implicitRoles.some(implicitRole => {
|
| 1682 |
+
return implicitRole === role;
|
| 1683 |
+
});
|
| 1684 |
+
}).filter(element => {
|
| 1685 |
+
if (selected !== undefined) {
|
| 1686 |
+
return selected === computeAriaSelected(element);
|
| 1687 |
+
}
|
| 1688 |
+
if (busy !== undefined) {
|
| 1689 |
+
return busy === computeAriaBusy(element);
|
| 1690 |
+
}
|
| 1691 |
+
if (checked !== undefined) {
|
| 1692 |
+
return checked === computeAriaChecked(element);
|
| 1693 |
+
}
|
| 1694 |
+
if (pressed !== undefined) {
|
| 1695 |
+
return pressed === computeAriaPressed(element);
|
| 1696 |
+
}
|
| 1697 |
+
if (current !== undefined) {
|
| 1698 |
+
return current === computeAriaCurrent(element);
|
| 1699 |
+
}
|
| 1700 |
+
if (expanded !== undefined) {
|
| 1701 |
+
return expanded === computeAriaExpanded(element);
|
| 1702 |
+
}
|
| 1703 |
+
if (level !== undefined) {
|
| 1704 |
+
return level === computeHeadingLevel(element);
|
| 1705 |
+
}
|
| 1706 |
+
if (valueNow !== undefined || valueMax !== undefined || valueMin !== undefined || valueText !== undefined) {
|
| 1707 |
+
let valueMatches = true;
|
| 1708 |
+
if (valueNow !== undefined) {
|
| 1709 |
+
valueMatches && (valueMatches = valueNow === computeAriaValueNow(element));
|
| 1710 |
+
}
|
| 1711 |
+
if (valueMax !== undefined) {
|
| 1712 |
+
valueMatches && (valueMatches = valueMax === computeAriaValueMax(element));
|
| 1713 |
+
}
|
| 1714 |
+
if (valueMin !== undefined) {
|
| 1715 |
+
valueMatches && (valueMatches = valueMin === computeAriaValueMin(element));
|
| 1716 |
+
}
|
| 1717 |
+
if (valueText !== undefined) {
|
| 1718 |
+
var _computeAriaValueText;
|
| 1719 |
+
valueMatches && (valueMatches = matches((_computeAriaValueText = computeAriaValueText(element)) != null ? _computeAriaValueText : null, element, valueText, text => text));
|
| 1720 |
+
}
|
| 1721 |
+
return valueMatches;
|
| 1722 |
+
}
|
| 1723 |
+
// don't care if aria attributes are unspecified
|
| 1724 |
+
return true;
|
| 1725 |
+
}).filter(element => {
|
| 1726 |
+
if (name === undefined) {
|
| 1727 |
+
// Don't care
|
| 1728 |
+
return true;
|
| 1729 |
+
}
|
| 1730 |
+
return matches(computeAccessibleName(element, {
|
| 1731 |
+
computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements
|
| 1732 |
+
}), element, name, text => text);
|
| 1733 |
+
}).filter(element => {
|
| 1734 |
+
if (description === undefined) {
|
| 1735 |
+
// Don't care
|
| 1736 |
+
return true;
|
| 1737 |
+
}
|
| 1738 |
+
return matches(computeAccessibleDescription(element, {
|
| 1739 |
+
computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements
|
| 1740 |
+
}), element, description, text => text);
|
| 1741 |
+
}).filter(element => {
|
| 1742 |
+
return hidden === false ? isInaccessible(element, {
|
| 1743 |
+
isSubtreeInaccessible: cachedIsSubtreeInaccessible
|
| 1744 |
+
}) === false : true;
|
| 1745 |
+
});
|
| 1746 |
+
};
|
| 1747 |
+
function makeRoleSelector(role) {
|
| 1748 |
+
var _roleElements$get;
|
| 1749 |
+
const explicitRoleSelector = "*[role~=\"" + role + "\"]";
|
| 1750 |
+
const roleRelations = (_roleElements$get = roleElements.get(role)) != null ? _roleElements$get : new Set();
|
| 1751 |
+
const implicitRoleSelectors = new Set(Array.from(roleRelations).map(_ref => {
|
| 1752 |
+
let {
|
| 1753 |
+
name
|
| 1754 |
+
} = _ref;
|
| 1755 |
+
return name;
|
| 1756 |
+
}));
|
| 1757 |
+
|
| 1758 |
+
// Current transpilation config sometimes assumes `...` is always applied to arrays.
|
| 1759 |
+
// `...` is equivalent to `Array.prototype.concat` for arrays.
|
| 1760 |
+
// If you replace this code with `[explicitRoleSelector, ...implicitRoleSelectors]`, make sure every transpilation target retains the `...` in favor of `Array.prototype.concat`.
|
| 1761 |
+
return [explicitRoleSelector].concat(Array.from(implicitRoleSelectors)).join(',');
|
| 1762 |
+
}
|
| 1763 |
+
const getNameHint = name => {
|
| 1764 |
+
let nameHint = '';
|
| 1765 |
+
if (name === undefined) {
|
| 1766 |
+
nameHint = '';
|
| 1767 |
+
} else if (typeof name === 'string') {
|
| 1768 |
+
nameHint = " and name \"" + name + "\"";
|
| 1769 |
+
} else {
|
| 1770 |
+
nameHint = " and name `" + name + "`";
|
| 1771 |
+
}
|
| 1772 |
+
return nameHint;
|
| 1773 |
+
};
|
| 1774 |
+
const getMultipleError$1 = function (c, role, _temp2) {
|
| 1775 |
+
let {
|
| 1776 |
+
name
|
| 1777 |
+
} = _temp2 === void 0 ? {} : _temp2;
|
| 1778 |
+
return "Found multiple elements with the role \"" + role + "\"" + getNameHint(name);
|
| 1779 |
+
};
|
| 1780 |
+
const getMissingError$1 = function (container, role, _temp3) {
|
| 1781 |
+
let {
|
| 1782 |
+
hidden = getConfig().defaultHidden,
|
| 1783 |
+
name,
|
| 1784 |
+
description
|
| 1785 |
+
} = _temp3 === void 0 ? {} : _temp3;
|
| 1786 |
+
if (getConfig()._disableExpensiveErrorDiagnostics) {
|
| 1787 |
+
return "Unable to find role=\"" + role + "\"" + getNameHint(name);
|
| 1788 |
+
}
|
| 1789 |
+
let roles = '';
|
| 1790 |
+
Array.from(container.children).forEach(childElement => {
|
| 1791 |
+
roles += prettyRoles(childElement, {
|
| 1792 |
+
hidden,
|
| 1793 |
+
includeDescription: description !== undefined
|
| 1794 |
+
});
|
| 1795 |
+
});
|
| 1796 |
+
let roleMessage;
|
| 1797 |
+
if (roles.length === 0) {
|
| 1798 |
+
if (hidden === false) {
|
| 1799 |
+
roleMessage = 'There are no accessible roles. But there might be some inaccessible roles. ' + 'If you wish to access them, then set the `hidden` option to `true`. ' + 'Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole';
|
| 1800 |
+
} else {
|
| 1801 |
+
roleMessage = 'There are no available roles.';
|
| 1802 |
+
}
|
| 1803 |
+
} else {
|
| 1804 |
+
roleMessage = ("\nHere are the " + (hidden === false ? 'accessible' : 'available') + " roles:\n\n " + roles.replace(/\n/g, '\n ').replace(/\n\s\s\n/g, '\n\n') + "\n").trim();
|
| 1805 |
+
}
|
| 1806 |
+
let nameHint = '';
|
| 1807 |
+
if (name === undefined) {
|
| 1808 |
+
nameHint = '';
|
| 1809 |
+
} else if (typeof name === 'string') {
|
| 1810 |
+
nameHint = " and name \"" + name + "\"";
|
| 1811 |
+
} else {
|
| 1812 |
+
nameHint = " and name `" + name + "`";
|
| 1813 |
+
}
|
| 1814 |
+
let descriptionHint = '';
|
| 1815 |
+
if (description === undefined) {
|
| 1816 |
+
descriptionHint = '';
|
| 1817 |
+
} else if (typeof description === 'string') {
|
| 1818 |
+
descriptionHint = " and description \"" + description + "\"";
|
| 1819 |
+
} else {
|
| 1820 |
+
descriptionHint = " and description `" + description + "`";
|
| 1821 |
+
}
|
| 1822 |
+
return ("\nUnable to find an " + (hidden === false ? 'accessible ' : '') + "element with the role \"" + role + "\"" + nameHint + descriptionHint + "\n\n" + roleMessage).trim();
|
| 1823 |
+
};
|
| 1824 |
+
const queryAllByRoleWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByRole, queryAllByRole.name, 'queryAll');
|
| 1825 |
+
const [queryByRole, getAllByRole, getByRole, findAllByRole, findByRole] = buildQueries(queryAllByRole, getMultipleError$1, getMissingError$1);
|
| 1826 |
+
|
| 1827 |
+
const getTestIdAttribute = () => getConfig().testIdAttribute;
|
| 1828 |
+
const queryAllByTestId = function () {
|
| 1829 |
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
| 1830 |
+
args[_key] = arguments[_key];
|
| 1831 |
+
}
|
| 1832 |
+
checkContainerType(args[0]);
|
| 1833 |
+
return queryAllByAttribute(getTestIdAttribute(), ...args);
|
| 1834 |
+
};
|
| 1835 |
+
const getMultipleError = (c, id) => "Found multiple elements by: [" + getTestIdAttribute() + "=\"" + id + "\"]";
|
| 1836 |
+
const getMissingError = (c, id) => "Unable to find an element by: [" + getTestIdAttribute() + "=\"" + id + "\"]";
|
| 1837 |
+
const queryAllByTestIdWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByTestId, queryAllByTestId.name, 'queryAll');
|
| 1838 |
+
const [queryByTestId, getAllByTestId, getByTestId, findAllByTestId, findByTestId] = buildQueries(queryAllByTestId, getMultipleError, getMissingError);
|
| 1839 |
+
|
| 1840 |
+
var queries = /*#__PURE__*/Object.freeze({
|
| 1841 |
+
__proto__: null,
|
| 1842 |
+
queryAllByLabelText: queryAllByLabelTextWithSuggestions,
|
| 1843 |
+
queryByLabelText: queryByLabelText,
|
| 1844 |
+
getAllByLabelText: getAllByLabelTextWithSuggestions,
|
| 1845 |
+
getByLabelText: getByLabelTextWithSuggestions,
|
| 1846 |
+
findAllByLabelText: findAllByLabelText,
|
| 1847 |
+
findByLabelText: findByLabelText,
|
| 1848 |
+
queryByPlaceholderText: queryByPlaceholderText,
|
| 1849 |
+
queryAllByPlaceholderText: queryAllByPlaceholderTextWithSuggestions,
|
| 1850 |
+
getByPlaceholderText: getByPlaceholderText,
|
| 1851 |
+
getAllByPlaceholderText: getAllByPlaceholderText,
|
| 1852 |
+
findAllByPlaceholderText: findAllByPlaceholderText,
|
| 1853 |
+
findByPlaceholderText: findByPlaceholderText,
|
| 1854 |
+
queryByText: queryByText,
|
| 1855 |
+
queryAllByText: queryAllByTextWithSuggestions,
|
| 1856 |
+
getByText: getByText,
|
| 1857 |
+
getAllByText: getAllByText,
|
| 1858 |
+
findAllByText: findAllByText,
|
| 1859 |
+
findByText: findByText,
|
| 1860 |
+
queryByDisplayValue: queryByDisplayValue,
|
| 1861 |
+
queryAllByDisplayValue: queryAllByDisplayValueWithSuggestions,
|
| 1862 |
+
getByDisplayValue: getByDisplayValue,
|
| 1863 |
+
getAllByDisplayValue: getAllByDisplayValue,
|
| 1864 |
+
findAllByDisplayValue: findAllByDisplayValue,
|
| 1865 |
+
findByDisplayValue: findByDisplayValue,
|
| 1866 |
+
queryByAltText: queryByAltText,
|
| 1867 |
+
queryAllByAltText: queryAllByAltTextWithSuggestions,
|
| 1868 |
+
getByAltText: getByAltText,
|
| 1869 |
+
getAllByAltText: getAllByAltText,
|
| 1870 |
+
findAllByAltText: findAllByAltText,
|
| 1871 |
+
findByAltText: findByAltText,
|
| 1872 |
+
queryByTitle: queryByTitle,
|
| 1873 |
+
queryAllByTitle: queryAllByTitleWithSuggestions,
|
| 1874 |
+
getByTitle: getByTitle,
|
| 1875 |
+
getAllByTitle: getAllByTitle,
|
| 1876 |
+
findAllByTitle: findAllByTitle,
|
| 1877 |
+
findByTitle: findByTitle,
|
| 1878 |
+
queryByRole: queryByRole,
|
| 1879 |
+
queryAllByRole: queryAllByRoleWithSuggestions,
|
| 1880 |
+
getAllByRole: getAllByRole,
|
| 1881 |
+
getByRole: getByRole,
|
| 1882 |
+
findAllByRole: findAllByRole,
|
| 1883 |
+
findByRole: findByRole,
|
| 1884 |
+
queryByTestId: queryByTestId,
|
| 1885 |
+
queryAllByTestId: queryAllByTestIdWithSuggestions,
|
| 1886 |
+
getByTestId: getByTestId,
|
| 1887 |
+
getAllByTestId: getAllByTestId,
|
| 1888 |
+
findAllByTestId: findAllByTestId,
|
| 1889 |
+
findByTestId: findByTestId
|
| 1890 |
+
});
|
| 1891 |
+
|
| 1892 |
+
/**
|
| 1893 |
+
* @typedef {{[key: string]: Function}} FuncMap
|
| 1894 |
+
*/
|
| 1895 |
+
|
| 1896 |
+
/**
|
| 1897 |
+
* @param {HTMLElement} element container
|
| 1898 |
+
* @param {FuncMap} queries object of functions
|
| 1899 |
+
* @param {Object} initialValue for reducer
|
| 1900 |
+
* @returns {FuncMap} returns object of functions bound to container
|
| 1901 |
+
*/
|
| 1902 |
+
function getQueriesForElement(element, queries$1, initialValue) {
|
| 1903 |
+
if (queries$1 === void 0) {
|
| 1904 |
+
queries$1 = queries;
|
| 1905 |
+
}
|
| 1906 |
+
if (initialValue === void 0) {
|
| 1907 |
+
initialValue = {};
|
| 1908 |
+
}
|
| 1909 |
+
return Object.keys(queries$1).reduce((helpers, key) => {
|
| 1910 |
+
const fn = queries$1[key];
|
| 1911 |
+
helpers[key] = fn.bind(null, element);
|
| 1912 |
+
return helpers;
|
| 1913 |
+
}, initialValue);
|
| 1914 |
+
}
|
| 1915 |
+
|
| 1916 |
+
const isRemoved = result => !result || Array.isArray(result) && !result.length;
|
| 1917 |
+
|
| 1918 |
+
// Check if the element is not present.
|
| 1919 |
+
// As the name implies, waitForElementToBeRemoved should check `present` --> `removed`
|
| 1920 |
+
function initialCheck(elements) {
|
| 1921 |
+
if (isRemoved(elements)) {
|
| 1922 |
+
throw new Error('The element(s) given to waitForElementToBeRemoved are already removed. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.');
|
| 1923 |
+
}
|
| 1924 |
+
}
|
| 1925 |
+
async function waitForElementToBeRemoved(callback, options) {
|
| 1926 |
+
// created here so we get a nice stacktrace
|
| 1927 |
+
const timeoutError = new Error('Timed out in waitForElementToBeRemoved.');
|
| 1928 |
+
if (typeof callback !== 'function') {
|
| 1929 |
+
initialCheck(callback);
|
| 1930 |
+
const elements = Array.isArray(callback) ? callback : [callback];
|
| 1931 |
+
const getRemainingElements = elements.map(element => {
|
| 1932 |
+
let parent = element.parentElement;
|
| 1933 |
+
if (parent === null) return () => null;
|
| 1934 |
+
while (parent.parentElement) parent = parent.parentElement;
|
| 1935 |
+
return () => parent.contains(element) ? element : null;
|
| 1936 |
+
});
|
| 1937 |
+
callback = () => getRemainingElements.map(c => c()).filter(Boolean);
|
| 1938 |
+
}
|
| 1939 |
+
initialCheck(callback());
|
| 1940 |
+
return waitForWrapper(() => {
|
| 1941 |
+
let result;
|
| 1942 |
+
try {
|
| 1943 |
+
result = callback();
|
| 1944 |
+
} catch (error) {
|
| 1945 |
+
if (error.name === 'TestingLibraryElementError') {
|
| 1946 |
+
return undefined;
|
| 1947 |
+
}
|
| 1948 |
+
throw error;
|
| 1949 |
+
}
|
| 1950 |
+
if (!isRemoved(result)) {
|
| 1951 |
+
throw timeoutError;
|
| 1952 |
+
}
|
| 1953 |
+
return undefined;
|
| 1954 |
+
}, options);
|
| 1955 |
+
}
|
| 1956 |
+
|
| 1957 |
+
/*
|
| 1958 |
+
eslint
|
| 1959 |
+
require-await: "off"
|
| 1960 |
+
*/
|
| 1961 |
+
|
| 1962 |
+
const eventMap = {
|
| 1963 |
+
// Clipboard Events
|
| 1964 |
+
copy: {
|
| 1965 |
+
EventType: 'ClipboardEvent',
|
| 1966 |
+
defaultInit: {
|
| 1967 |
+
bubbles: true,
|
| 1968 |
+
cancelable: true,
|
| 1969 |
+
composed: true
|
| 1970 |
+
}
|
| 1971 |
+
},
|
| 1972 |
+
cut: {
|
| 1973 |
+
EventType: 'ClipboardEvent',
|
| 1974 |
+
defaultInit: {
|
| 1975 |
+
bubbles: true,
|
| 1976 |
+
cancelable: true,
|
| 1977 |
+
composed: true
|
| 1978 |
+
}
|
| 1979 |
+
},
|
| 1980 |
+
paste: {
|
| 1981 |
+
EventType: 'ClipboardEvent',
|
| 1982 |
+
defaultInit: {
|
| 1983 |
+
bubbles: true,
|
| 1984 |
+
cancelable: true,
|
| 1985 |
+
composed: true
|
| 1986 |
+
}
|
| 1987 |
+
},
|
| 1988 |
+
// Composition Events
|
| 1989 |
+
compositionEnd: {
|
| 1990 |
+
EventType: 'CompositionEvent',
|
| 1991 |
+
defaultInit: {
|
| 1992 |
+
bubbles: true,
|
| 1993 |
+
cancelable: true,
|
| 1994 |
+
composed: true
|
| 1995 |
+
}
|
| 1996 |
+
},
|
| 1997 |
+
compositionStart: {
|
| 1998 |
+
EventType: 'CompositionEvent',
|
| 1999 |
+
defaultInit: {
|
| 2000 |
+
bubbles: true,
|
| 2001 |
+
cancelable: true,
|
| 2002 |
+
composed: true
|
| 2003 |
+
}
|
| 2004 |
+
},
|
| 2005 |
+
compositionUpdate: {
|
| 2006 |
+
EventType: 'CompositionEvent',
|
| 2007 |
+
defaultInit: {
|
| 2008 |
+
bubbles: true,
|
| 2009 |
+
cancelable: true,
|
| 2010 |
+
composed: true
|
| 2011 |
+
}
|
| 2012 |
+
},
|
| 2013 |
+
// Keyboard Events
|
| 2014 |
+
keyDown: {
|
| 2015 |
+
EventType: 'KeyboardEvent',
|
| 2016 |
+
defaultInit: {
|
| 2017 |
+
bubbles: true,
|
| 2018 |
+
cancelable: true,
|
| 2019 |
+
charCode: 0,
|
| 2020 |
+
composed: true
|
| 2021 |
+
}
|
| 2022 |
+
},
|
| 2023 |
+
keyPress: {
|
| 2024 |
+
EventType: 'KeyboardEvent',
|
| 2025 |
+
defaultInit: {
|
| 2026 |
+
bubbles: true,
|
| 2027 |
+
cancelable: true,
|
| 2028 |
+
charCode: 0,
|
| 2029 |
+
composed: true
|
| 2030 |
+
}
|
| 2031 |
+
},
|
| 2032 |
+
keyUp: {
|
| 2033 |
+
EventType: 'KeyboardEvent',
|
| 2034 |
+
defaultInit: {
|
| 2035 |
+
bubbles: true,
|
| 2036 |
+
cancelable: true,
|
| 2037 |
+
charCode: 0,
|
| 2038 |
+
composed: true
|
| 2039 |
+
}
|
| 2040 |
+
},
|
| 2041 |
+
// Focus Events
|
| 2042 |
+
focus: {
|
| 2043 |
+
EventType: 'FocusEvent',
|
| 2044 |
+
defaultInit: {
|
| 2045 |
+
bubbles: false,
|
| 2046 |
+
cancelable: false,
|
| 2047 |
+
composed: true
|
| 2048 |
+
}
|
| 2049 |
+
},
|
| 2050 |
+
blur: {
|
| 2051 |
+
EventType: 'FocusEvent',
|
| 2052 |
+
defaultInit: {
|
| 2053 |
+
bubbles: false,
|
| 2054 |
+
cancelable: false,
|
| 2055 |
+
composed: true
|
| 2056 |
+
}
|
| 2057 |
+
},
|
| 2058 |
+
focusIn: {
|
| 2059 |
+
EventType: 'FocusEvent',
|
| 2060 |
+
defaultInit: {
|
| 2061 |
+
bubbles: true,
|
| 2062 |
+
cancelable: false,
|
| 2063 |
+
composed: true
|
| 2064 |
+
}
|
| 2065 |
+
},
|
| 2066 |
+
focusOut: {
|
| 2067 |
+
EventType: 'FocusEvent',
|
| 2068 |
+
defaultInit: {
|
| 2069 |
+
bubbles: true,
|
| 2070 |
+
cancelable: false,
|
| 2071 |
+
composed: true
|
| 2072 |
+
}
|
| 2073 |
+
},
|
| 2074 |
+
// Form Events
|
| 2075 |
+
change: {
|
| 2076 |
+
EventType: 'Event',
|
| 2077 |
+
defaultInit: {
|
| 2078 |
+
bubbles: true,
|
| 2079 |
+
cancelable: false
|
| 2080 |
+
}
|
| 2081 |
+
},
|
| 2082 |
+
input: {
|
| 2083 |
+
EventType: 'InputEvent',
|
| 2084 |
+
defaultInit: {
|
| 2085 |
+
bubbles: true,
|
| 2086 |
+
cancelable: false,
|
| 2087 |
+
composed: true
|
| 2088 |
+
}
|
| 2089 |
+
},
|
| 2090 |
+
invalid: {
|
| 2091 |
+
EventType: 'Event',
|
| 2092 |
+
defaultInit: {
|
| 2093 |
+
bubbles: false,
|
| 2094 |
+
cancelable: true
|
| 2095 |
+
}
|
| 2096 |
+
},
|
| 2097 |
+
submit: {
|
| 2098 |
+
EventType: 'Event',
|
| 2099 |
+
defaultInit: {
|
| 2100 |
+
bubbles: true,
|
| 2101 |
+
cancelable: true
|
| 2102 |
+
}
|
| 2103 |
+
},
|
| 2104 |
+
reset: {
|
| 2105 |
+
EventType: 'Event',
|
| 2106 |
+
defaultInit: {
|
| 2107 |
+
bubbles: true,
|
| 2108 |
+
cancelable: true
|
| 2109 |
+
}
|
| 2110 |
+
},
|
| 2111 |
+
// Mouse Events
|
| 2112 |
+
click: {
|
| 2113 |
+
EventType: 'MouseEvent',
|
| 2114 |
+
defaultInit: {
|
| 2115 |
+
bubbles: true,
|
| 2116 |
+
cancelable: true,
|
| 2117 |
+
button: 0,
|
| 2118 |
+
composed: true
|
| 2119 |
+
}
|
| 2120 |
+
},
|
| 2121 |
+
contextMenu: {
|
| 2122 |
+
EventType: 'MouseEvent',
|
| 2123 |
+
defaultInit: {
|
| 2124 |
+
bubbles: true,
|
| 2125 |
+
cancelable: true,
|
| 2126 |
+
composed: true
|
| 2127 |
+
}
|
| 2128 |
+
},
|
| 2129 |
+
dblClick: {
|
| 2130 |
+
EventType: 'MouseEvent',
|
| 2131 |
+
defaultInit: {
|
| 2132 |
+
bubbles: true,
|
| 2133 |
+
cancelable: true,
|
| 2134 |
+
composed: true
|
| 2135 |
+
}
|
| 2136 |
+
},
|
| 2137 |
+
drag: {
|
| 2138 |
+
EventType: 'DragEvent',
|
| 2139 |
+
defaultInit: {
|
| 2140 |
+
bubbles: true,
|
| 2141 |
+
cancelable: true,
|
| 2142 |
+
composed: true
|
| 2143 |
+
}
|
| 2144 |
+
},
|
| 2145 |
+
dragEnd: {
|
| 2146 |
+
EventType: 'DragEvent',
|
| 2147 |
+
defaultInit: {
|
| 2148 |
+
bubbles: true,
|
| 2149 |
+
cancelable: false,
|
| 2150 |
+
composed: true
|
| 2151 |
+
}
|
| 2152 |
+
},
|
| 2153 |
+
dragEnter: {
|
| 2154 |
+
EventType: 'DragEvent',
|
| 2155 |
+
defaultInit: {
|
| 2156 |
+
bubbles: true,
|
| 2157 |
+
cancelable: true,
|
| 2158 |
+
composed: true
|
| 2159 |
+
}
|
| 2160 |
+
},
|
| 2161 |
+
dragExit: {
|
| 2162 |
+
EventType: 'DragEvent',
|
| 2163 |
+
defaultInit: {
|
| 2164 |
+
bubbles: true,
|
| 2165 |
+
cancelable: false,
|
| 2166 |
+
composed: true
|
| 2167 |
+
}
|
| 2168 |
+
},
|
| 2169 |
+
dragLeave: {
|
| 2170 |
+
EventType: 'DragEvent',
|
| 2171 |
+
defaultInit: {
|
| 2172 |
+
bubbles: true,
|
| 2173 |
+
cancelable: false,
|
| 2174 |
+
composed: true
|
| 2175 |
+
}
|
| 2176 |
+
},
|
| 2177 |
+
dragOver: {
|
| 2178 |
+
EventType: 'DragEvent',
|
| 2179 |
+
defaultInit: {
|
| 2180 |
+
bubbles: true,
|
| 2181 |
+
cancelable: true,
|
| 2182 |
+
composed: true
|
| 2183 |
+
}
|
| 2184 |
+
},
|
| 2185 |
+
dragStart: {
|
| 2186 |
+
EventType: 'DragEvent',
|
| 2187 |
+
defaultInit: {
|
| 2188 |
+
bubbles: true,
|
| 2189 |
+
cancelable: true,
|
| 2190 |
+
composed: true
|
| 2191 |
+
}
|
| 2192 |
+
},
|
| 2193 |
+
drop: {
|
| 2194 |
+
EventType: 'DragEvent',
|
| 2195 |
+
defaultInit: {
|
| 2196 |
+
bubbles: true,
|
| 2197 |
+
cancelable: true,
|
| 2198 |
+
composed: true
|
| 2199 |
+
}
|
| 2200 |
+
},
|
| 2201 |
+
mouseDown: {
|
| 2202 |
+
EventType: 'MouseEvent',
|
| 2203 |
+
defaultInit: {
|
| 2204 |
+
bubbles: true,
|
| 2205 |
+
cancelable: true,
|
| 2206 |
+
composed: true
|
| 2207 |
+
}
|
| 2208 |
+
},
|
| 2209 |
+
mouseEnter: {
|
| 2210 |
+
EventType: 'MouseEvent',
|
| 2211 |
+
defaultInit: {
|
| 2212 |
+
bubbles: false,
|
| 2213 |
+
cancelable: false,
|
| 2214 |
+
composed: true
|
| 2215 |
+
}
|
| 2216 |
+
},
|
| 2217 |
+
mouseLeave: {
|
| 2218 |
+
EventType: 'MouseEvent',
|
| 2219 |
+
defaultInit: {
|
| 2220 |
+
bubbles: false,
|
| 2221 |
+
cancelable: false,
|
| 2222 |
+
composed: true
|
| 2223 |
+
}
|
| 2224 |
+
},
|
| 2225 |
+
mouseMove: {
|
| 2226 |
+
EventType: 'MouseEvent',
|
| 2227 |
+
defaultInit: {
|
| 2228 |
+
bubbles: true,
|
| 2229 |
+
cancelable: true,
|
| 2230 |
+
composed: true
|
| 2231 |
+
}
|
| 2232 |
+
},
|
| 2233 |
+
mouseOut: {
|
| 2234 |
+
EventType: 'MouseEvent',
|
| 2235 |
+
defaultInit: {
|
| 2236 |
+
bubbles: true,
|
| 2237 |
+
cancelable: true,
|
| 2238 |
+
composed: true
|
| 2239 |
+
}
|
| 2240 |
+
},
|
| 2241 |
+
mouseOver: {
|
| 2242 |
+
EventType: 'MouseEvent',
|
| 2243 |
+
defaultInit: {
|
| 2244 |
+
bubbles: true,
|
| 2245 |
+
cancelable: true,
|
| 2246 |
+
composed: true
|
| 2247 |
+
}
|
| 2248 |
+
},
|
| 2249 |
+
mouseUp: {
|
| 2250 |
+
EventType: 'MouseEvent',
|
| 2251 |
+
defaultInit: {
|
| 2252 |
+
bubbles: true,
|
| 2253 |
+
cancelable: true,
|
| 2254 |
+
composed: true
|
| 2255 |
+
}
|
| 2256 |
+
},
|
| 2257 |
+
// Selection Events
|
| 2258 |
+
select: {
|
| 2259 |
+
EventType: 'Event',
|
| 2260 |
+
defaultInit: {
|
| 2261 |
+
bubbles: true,
|
| 2262 |
+
cancelable: false
|
| 2263 |
+
}
|
| 2264 |
+
},
|
| 2265 |
+
// Touch Events
|
| 2266 |
+
touchCancel: {
|
| 2267 |
+
EventType: 'TouchEvent',
|
| 2268 |
+
defaultInit: {
|
| 2269 |
+
bubbles: true,
|
| 2270 |
+
cancelable: false,
|
| 2271 |
+
composed: true
|
| 2272 |
+
}
|
| 2273 |
+
},
|
| 2274 |
+
touchEnd: {
|
| 2275 |
+
EventType: 'TouchEvent',
|
| 2276 |
+
defaultInit: {
|
| 2277 |
+
bubbles: true,
|
| 2278 |
+
cancelable: true,
|
| 2279 |
+
composed: true
|
| 2280 |
+
}
|
| 2281 |
+
},
|
| 2282 |
+
touchMove: {
|
| 2283 |
+
EventType: 'TouchEvent',
|
| 2284 |
+
defaultInit: {
|
| 2285 |
+
bubbles: true,
|
| 2286 |
+
cancelable: true,
|
| 2287 |
+
composed: true
|
| 2288 |
+
}
|
| 2289 |
+
},
|
| 2290 |
+
touchStart: {
|
| 2291 |
+
EventType: 'TouchEvent',
|
| 2292 |
+
defaultInit: {
|
| 2293 |
+
bubbles: true,
|
| 2294 |
+
cancelable: true,
|
| 2295 |
+
composed: true
|
| 2296 |
+
}
|
| 2297 |
+
},
|
| 2298 |
+
// UI Events
|
| 2299 |
+
resize: {
|
| 2300 |
+
EventType: 'UIEvent',
|
| 2301 |
+
defaultInit: {
|
| 2302 |
+
bubbles: false,
|
| 2303 |
+
cancelable: false
|
| 2304 |
+
}
|
| 2305 |
+
},
|
| 2306 |
+
scroll: {
|
| 2307 |
+
EventType: 'UIEvent',
|
| 2308 |
+
defaultInit: {
|
| 2309 |
+
bubbles: false,
|
| 2310 |
+
cancelable: false
|
| 2311 |
+
}
|
| 2312 |
+
},
|
| 2313 |
+
// Wheel Events
|
| 2314 |
+
wheel: {
|
| 2315 |
+
EventType: 'WheelEvent',
|
| 2316 |
+
defaultInit: {
|
| 2317 |
+
bubbles: true,
|
| 2318 |
+
cancelable: true,
|
| 2319 |
+
composed: true
|
| 2320 |
+
}
|
| 2321 |
+
},
|
| 2322 |
+
// Media Events
|
| 2323 |
+
abort: {
|
| 2324 |
+
EventType: 'Event',
|
| 2325 |
+
defaultInit: {
|
| 2326 |
+
bubbles: false,
|
| 2327 |
+
cancelable: false
|
| 2328 |
+
}
|
| 2329 |
+
},
|
| 2330 |
+
canPlay: {
|
| 2331 |
+
EventType: 'Event',
|
| 2332 |
+
defaultInit: {
|
| 2333 |
+
bubbles: false,
|
| 2334 |
+
cancelable: false
|
| 2335 |
+
}
|
| 2336 |
+
},
|
| 2337 |
+
canPlayThrough: {
|
| 2338 |
+
EventType: 'Event',
|
| 2339 |
+
defaultInit: {
|
| 2340 |
+
bubbles: false,
|
| 2341 |
+
cancelable: false
|
| 2342 |
+
}
|
| 2343 |
+
},
|
| 2344 |
+
durationChange: {
|
| 2345 |
+
EventType: 'Event',
|
| 2346 |
+
defaultInit: {
|
| 2347 |
+
bubbles: false,
|
| 2348 |
+
cancelable: false
|
| 2349 |
+
}
|
| 2350 |
+
},
|
| 2351 |
+
emptied: {
|
| 2352 |
+
EventType: 'Event',
|
| 2353 |
+
defaultInit: {
|
| 2354 |
+
bubbles: false,
|
| 2355 |
+
cancelable: false
|
| 2356 |
+
}
|
| 2357 |
+
},
|
| 2358 |
+
encrypted: {
|
| 2359 |
+
EventType: 'Event',
|
| 2360 |
+
defaultInit: {
|
| 2361 |
+
bubbles: false,
|
| 2362 |
+
cancelable: false
|
| 2363 |
+
}
|
| 2364 |
+
},
|
| 2365 |
+
ended: {
|
| 2366 |
+
EventType: 'Event',
|
| 2367 |
+
defaultInit: {
|
| 2368 |
+
bubbles: false,
|
| 2369 |
+
cancelable: false
|
| 2370 |
+
}
|
| 2371 |
+
},
|
| 2372 |
+
loadedData: {
|
| 2373 |
+
EventType: 'Event',
|
| 2374 |
+
defaultInit: {
|
| 2375 |
+
bubbles: false,
|
| 2376 |
+
cancelable: false
|
| 2377 |
+
}
|
| 2378 |
+
},
|
| 2379 |
+
loadedMetadata: {
|
| 2380 |
+
EventType: 'Event',
|
| 2381 |
+
defaultInit: {
|
| 2382 |
+
bubbles: false,
|
| 2383 |
+
cancelable: false
|
| 2384 |
+
}
|
| 2385 |
+
},
|
| 2386 |
+
loadStart: {
|
| 2387 |
+
EventType: 'ProgressEvent',
|
| 2388 |
+
defaultInit: {
|
| 2389 |
+
bubbles: false,
|
| 2390 |
+
cancelable: false
|
| 2391 |
+
}
|
| 2392 |
+
},
|
| 2393 |
+
pause: {
|
| 2394 |
+
EventType: 'Event',
|
| 2395 |
+
defaultInit: {
|
| 2396 |
+
bubbles: false,
|
| 2397 |
+
cancelable: false
|
| 2398 |
+
}
|
| 2399 |
+
},
|
| 2400 |
+
play: {
|
| 2401 |
+
EventType: 'Event',
|
| 2402 |
+
defaultInit: {
|
| 2403 |
+
bubbles: false,
|
| 2404 |
+
cancelable: false
|
| 2405 |
+
}
|
| 2406 |
+
},
|
| 2407 |
+
playing: {
|
| 2408 |
+
EventType: 'Event',
|
| 2409 |
+
defaultInit: {
|
| 2410 |
+
bubbles: false,
|
| 2411 |
+
cancelable: false
|
| 2412 |
+
}
|
| 2413 |
+
},
|
| 2414 |
+
progress: {
|
| 2415 |
+
EventType: 'ProgressEvent',
|
| 2416 |
+
defaultInit: {
|
| 2417 |
+
bubbles: false,
|
| 2418 |
+
cancelable: false
|
| 2419 |
+
}
|
| 2420 |
+
},
|
| 2421 |
+
rateChange: {
|
| 2422 |
+
EventType: 'Event',
|
| 2423 |
+
defaultInit: {
|
| 2424 |
+
bubbles: false,
|
| 2425 |
+
cancelable: false
|
| 2426 |
+
}
|
| 2427 |
+
},
|
| 2428 |
+
seeked: {
|
| 2429 |
+
EventType: 'Event',
|
| 2430 |
+
defaultInit: {
|
| 2431 |
+
bubbles: false,
|
| 2432 |
+
cancelable: false
|
| 2433 |
+
}
|
| 2434 |
+
},
|
| 2435 |
+
seeking: {
|
| 2436 |
+
EventType: 'Event',
|
| 2437 |
+
defaultInit: {
|
| 2438 |
+
bubbles: false,
|
| 2439 |
+
cancelable: false
|
| 2440 |
+
}
|
| 2441 |
+
},
|
| 2442 |
+
stalled: {
|
| 2443 |
+
EventType: 'Event',
|
| 2444 |
+
defaultInit: {
|
| 2445 |
+
bubbles: false,
|
| 2446 |
+
cancelable: false
|
| 2447 |
+
}
|
| 2448 |
+
},
|
| 2449 |
+
suspend: {
|
| 2450 |
+
EventType: 'Event',
|
| 2451 |
+
defaultInit: {
|
| 2452 |
+
bubbles: false,
|
| 2453 |
+
cancelable: false
|
| 2454 |
+
}
|
| 2455 |
+
},
|
| 2456 |
+
timeUpdate: {
|
| 2457 |
+
EventType: 'Event',
|
| 2458 |
+
defaultInit: {
|
| 2459 |
+
bubbles: false,
|
| 2460 |
+
cancelable: false
|
| 2461 |
+
}
|
| 2462 |
+
},
|
| 2463 |
+
volumeChange: {
|
| 2464 |
+
EventType: 'Event',
|
| 2465 |
+
defaultInit: {
|
| 2466 |
+
bubbles: false,
|
| 2467 |
+
cancelable: false
|
| 2468 |
+
}
|
| 2469 |
+
},
|
| 2470 |
+
waiting: {
|
| 2471 |
+
EventType: 'Event',
|
| 2472 |
+
defaultInit: {
|
| 2473 |
+
bubbles: false,
|
| 2474 |
+
cancelable: false
|
| 2475 |
+
}
|
| 2476 |
+
},
|
| 2477 |
+
// Events
|
| 2478 |
+
load: {
|
| 2479 |
+
// TODO: load events can be UIEvent or Event depending on what generated them
|
| 2480 |
+
// This is where this abstraction breaks down.
|
| 2481 |
+
// But the common targets are <img />, <script /> and window.
|
| 2482 |
+
// Neither of these targets receive a UIEvent
|
| 2483 |
+
EventType: 'Event',
|
| 2484 |
+
defaultInit: {
|
| 2485 |
+
bubbles: false,
|
| 2486 |
+
cancelable: false
|
| 2487 |
+
}
|
| 2488 |
+
},
|
| 2489 |
+
error: {
|
| 2490 |
+
EventType: 'Event',
|
| 2491 |
+
defaultInit: {
|
| 2492 |
+
bubbles: false,
|
| 2493 |
+
cancelable: false
|
| 2494 |
+
}
|
| 2495 |
+
},
|
| 2496 |
+
// Animation Events
|
| 2497 |
+
animationStart: {
|
| 2498 |
+
EventType: 'AnimationEvent',
|
| 2499 |
+
defaultInit: {
|
| 2500 |
+
bubbles: true,
|
| 2501 |
+
cancelable: false
|
| 2502 |
+
}
|
| 2503 |
+
},
|
| 2504 |
+
animationEnd: {
|
| 2505 |
+
EventType: 'AnimationEvent',
|
| 2506 |
+
defaultInit: {
|
| 2507 |
+
bubbles: true,
|
| 2508 |
+
cancelable: false
|
| 2509 |
+
}
|
| 2510 |
+
},
|
| 2511 |
+
animationIteration: {
|
| 2512 |
+
EventType: 'AnimationEvent',
|
| 2513 |
+
defaultInit: {
|
| 2514 |
+
bubbles: true,
|
| 2515 |
+
cancelable: false
|
| 2516 |
+
}
|
| 2517 |
+
},
|
| 2518 |
+
// Transition Events
|
| 2519 |
+
transitionCancel: {
|
| 2520 |
+
EventType: 'TransitionEvent',
|
| 2521 |
+
defaultInit: {
|
| 2522 |
+
bubbles: true,
|
| 2523 |
+
cancelable: false
|
| 2524 |
+
}
|
| 2525 |
+
},
|
| 2526 |
+
transitionEnd: {
|
| 2527 |
+
EventType: 'TransitionEvent',
|
| 2528 |
+
defaultInit: {
|
| 2529 |
+
bubbles: true,
|
| 2530 |
+
cancelable: true
|
| 2531 |
+
}
|
| 2532 |
+
},
|
| 2533 |
+
transitionRun: {
|
| 2534 |
+
EventType: 'TransitionEvent',
|
| 2535 |
+
defaultInit: {
|
| 2536 |
+
bubbles: true,
|
| 2537 |
+
cancelable: false
|
| 2538 |
+
}
|
| 2539 |
+
},
|
| 2540 |
+
transitionStart: {
|
| 2541 |
+
EventType: 'TransitionEvent',
|
| 2542 |
+
defaultInit: {
|
| 2543 |
+
bubbles: true,
|
| 2544 |
+
cancelable: false
|
| 2545 |
+
}
|
| 2546 |
+
},
|
| 2547 |
+
// pointer events
|
| 2548 |
+
pointerOver: {
|
| 2549 |
+
EventType: 'PointerEvent',
|
| 2550 |
+
defaultInit: {
|
| 2551 |
+
bubbles: true,
|
| 2552 |
+
cancelable: true,
|
| 2553 |
+
composed: true
|
| 2554 |
+
}
|
| 2555 |
+
},
|
| 2556 |
+
pointerEnter: {
|
| 2557 |
+
EventType: 'PointerEvent',
|
| 2558 |
+
defaultInit: {
|
| 2559 |
+
bubbles: false,
|
| 2560 |
+
cancelable: false
|
| 2561 |
+
}
|
| 2562 |
+
},
|
| 2563 |
+
pointerDown: {
|
| 2564 |
+
EventType: 'PointerEvent',
|
| 2565 |
+
defaultInit: {
|
| 2566 |
+
bubbles: true,
|
| 2567 |
+
cancelable: true,
|
| 2568 |
+
composed: true
|
| 2569 |
+
}
|
| 2570 |
+
},
|
| 2571 |
+
pointerMove: {
|
| 2572 |
+
EventType: 'PointerEvent',
|
| 2573 |
+
defaultInit: {
|
| 2574 |
+
bubbles: true,
|
| 2575 |
+
cancelable: true,
|
| 2576 |
+
composed: true
|
| 2577 |
+
}
|
| 2578 |
+
},
|
| 2579 |
+
pointerUp: {
|
| 2580 |
+
EventType: 'PointerEvent',
|
| 2581 |
+
defaultInit: {
|
| 2582 |
+
bubbles: true,
|
| 2583 |
+
cancelable: true,
|
| 2584 |
+
composed: true
|
| 2585 |
+
}
|
| 2586 |
+
},
|
| 2587 |
+
pointerCancel: {
|
| 2588 |
+
EventType: 'PointerEvent',
|
| 2589 |
+
defaultInit: {
|
| 2590 |
+
bubbles: true,
|
| 2591 |
+
cancelable: false,
|
| 2592 |
+
composed: true
|
| 2593 |
+
}
|
| 2594 |
+
},
|
| 2595 |
+
pointerOut: {
|
| 2596 |
+
EventType: 'PointerEvent',
|
| 2597 |
+
defaultInit: {
|
| 2598 |
+
bubbles: true,
|
| 2599 |
+
cancelable: true,
|
| 2600 |
+
composed: true
|
| 2601 |
+
}
|
| 2602 |
+
},
|
| 2603 |
+
pointerLeave: {
|
| 2604 |
+
EventType: 'PointerEvent',
|
| 2605 |
+
defaultInit: {
|
| 2606 |
+
bubbles: false,
|
| 2607 |
+
cancelable: false
|
| 2608 |
+
}
|
| 2609 |
+
},
|
| 2610 |
+
gotPointerCapture: {
|
| 2611 |
+
EventType: 'PointerEvent',
|
| 2612 |
+
defaultInit: {
|
| 2613 |
+
bubbles: true,
|
| 2614 |
+
cancelable: false,
|
| 2615 |
+
composed: true
|
| 2616 |
+
}
|
| 2617 |
+
},
|
| 2618 |
+
lostPointerCapture: {
|
| 2619 |
+
EventType: 'PointerEvent',
|
| 2620 |
+
defaultInit: {
|
| 2621 |
+
bubbles: true,
|
| 2622 |
+
cancelable: false,
|
| 2623 |
+
composed: true
|
| 2624 |
+
}
|
| 2625 |
+
},
|
| 2626 |
+
// history events
|
| 2627 |
+
popState: {
|
| 2628 |
+
EventType: 'PopStateEvent',
|
| 2629 |
+
defaultInit: {
|
| 2630 |
+
bubbles: true,
|
| 2631 |
+
cancelable: false
|
| 2632 |
+
}
|
| 2633 |
+
},
|
| 2634 |
+
// window events
|
| 2635 |
+
offline: {
|
| 2636 |
+
EventType: 'Event',
|
| 2637 |
+
defaultInit: {
|
| 2638 |
+
bubbles: false,
|
| 2639 |
+
cancelable: false
|
| 2640 |
+
}
|
| 2641 |
+
},
|
| 2642 |
+
online: {
|
| 2643 |
+
EventType: 'Event',
|
| 2644 |
+
defaultInit: {
|
| 2645 |
+
bubbles: false,
|
| 2646 |
+
cancelable: false
|
| 2647 |
+
}
|
| 2648 |
+
},
|
| 2649 |
+
pageHide: {
|
| 2650 |
+
EventType: 'PageTransitionEvent',
|
| 2651 |
+
defaultInit: {
|
| 2652 |
+
bubbles: true,
|
| 2653 |
+
cancelable: true
|
| 2654 |
+
}
|
| 2655 |
+
},
|
| 2656 |
+
pageShow: {
|
| 2657 |
+
EventType: 'PageTransitionEvent',
|
| 2658 |
+
defaultInit: {
|
| 2659 |
+
bubbles: true,
|
| 2660 |
+
cancelable: true
|
| 2661 |
+
}
|
| 2662 |
+
}
|
| 2663 |
+
};
|
| 2664 |
+
const eventAliasMap = {
|
| 2665 |
+
doubleClick: 'dblClick'
|
| 2666 |
+
};
|
| 2667 |
+
|
| 2668 |
+
function fireEvent(element, event) {
|
| 2669 |
+
return getConfig().eventWrapper(() => {
|
| 2670 |
+
if (!event) {
|
| 2671 |
+
throw new Error("Unable to fire an event - please provide an event object.");
|
| 2672 |
+
}
|
| 2673 |
+
if (!element) {
|
| 2674 |
+
throw new Error("Unable to fire a \"" + event.type + "\" event - please provide a DOM element.");
|
| 2675 |
+
}
|
| 2676 |
+
return element.dispatchEvent(event);
|
| 2677 |
+
});
|
| 2678 |
+
}
|
| 2679 |
+
function createEvent(eventName, node, init, _temp) {
|
| 2680 |
+
let {
|
| 2681 |
+
EventType = 'Event',
|
| 2682 |
+
defaultInit = {}
|
| 2683 |
+
} = _temp === void 0 ? {} : _temp;
|
| 2684 |
+
if (!node) {
|
| 2685 |
+
throw new Error("Unable to fire a \"" + eventName + "\" event - please provide a DOM element.");
|
| 2686 |
+
}
|
| 2687 |
+
const eventInit = {
|
| 2688 |
+
...defaultInit,
|
| 2689 |
+
...init
|
| 2690 |
+
};
|
| 2691 |
+
const {
|
| 2692 |
+
target: {
|
| 2693 |
+
value,
|
| 2694 |
+
files,
|
| 2695 |
+
...targetProperties
|
| 2696 |
+
} = {}
|
| 2697 |
+
} = eventInit;
|
| 2698 |
+
if (value !== undefined) {
|
| 2699 |
+
setNativeValue(node, value);
|
| 2700 |
+
}
|
| 2701 |
+
if (files !== undefined) {
|
| 2702 |
+
// input.files is a read-only property so this is not allowed:
|
| 2703 |
+
// input.files = [file]
|
| 2704 |
+
// so we have to use this workaround to set the property
|
| 2705 |
+
Object.defineProperty(node, 'files', {
|
| 2706 |
+
configurable: true,
|
| 2707 |
+
enumerable: true,
|
| 2708 |
+
writable: true,
|
| 2709 |
+
value: files
|
| 2710 |
+
});
|
| 2711 |
+
}
|
| 2712 |
+
Object.assign(node, targetProperties);
|
| 2713 |
+
const window = getWindowFromNode(node);
|
| 2714 |
+
const EventConstructor = window[EventType] || window.Event;
|
| 2715 |
+
let event;
|
| 2716 |
+
/* istanbul ignore else */
|
| 2717 |
+
if (typeof EventConstructor === 'function') {
|
| 2718 |
+
event = new EventConstructor(eventName, eventInit);
|
| 2719 |
+
} else {
|
| 2720 |
+
// IE11 polyfill from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
| 2721 |
+
event = window.document.createEvent(EventType);
|
| 2722 |
+
const {
|
| 2723 |
+
bubbles,
|
| 2724 |
+
cancelable,
|
| 2725 |
+
detail,
|
| 2726 |
+
...otherInit
|
| 2727 |
+
} = eventInit;
|
| 2728 |
+
event.initEvent(eventName, bubbles, cancelable, detail);
|
| 2729 |
+
Object.keys(otherInit).forEach(eventKey => {
|
| 2730 |
+
event[eventKey] = otherInit[eventKey];
|
| 2731 |
+
});
|
| 2732 |
+
}
|
| 2733 |
+
|
| 2734 |
+
// DataTransfer is not supported in jsdom: https://github.com/jsdom/jsdom/issues/1568
|
| 2735 |
+
const dataTransferProperties = ['dataTransfer', 'clipboardData'];
|
| 2736 |
+
dataTransferProperties.forEach(dataTransferKey => {
|
| 2737 |
+
const dataTransferValue = eventInit[dataTransferKey];
|
| 2738 |
+
if (typeof dataTransferValue === 'object') {
|
| 2739 |
+
/* istanbul ignore if */
|
| 2740 |
+
if (typeof window.DataTransfer === 'function') {
|
| 2741 |
+
Object.defineProperty(event, dataTransferKey, {
|
| 2742 |
+
value: Object.getOwnPropertyNames(dataTransferValue).reduce((acc, propName) => {
|
| 2743 |
+
Object.defineProperty(acc, propName, {
|
| 2744 |
+
value: dataTransferValue[propName]
|
| 2745 |
+
});
|
| 2746 |
+
return acc;
|
| 2747 |
+
}, new window.DataTransfer())
|
| 2748 |
+
});
|
| 2749 |
+
} else {
|
| 2750 |
+
Object.defineProperty(event, dataTransferKey, {
|
| 2751 |
+
value: dataTransferValue
|
| 2752 |
+
});
|
| 2753 |
+
}
|
| 2754 |
+
}
|
| 2755 |
+
});
|
| 2756 |
+
return event;
|
| 2757 |
+
}
|
| 2758 |
+
Object.keys(eventMap).forEach(key => {
|
| 2759 |
+
const {
|
| 2760 |
+
EventType,
|
| 2761 |
+
defaultInit
|
| 2762 |
+
} = eventMap[key];
|
| 2763 |
+
const eventName = key.toLowerCase();
|
| 2764 |
+
createEvent[key] = (node, init) => createEvent(eventName, node, init, {
|
| 2765 |
+
EventType,
|
| 2766 |
+
defaultInit
|
| 2767 |
+
});
|
| 2768 |
+
fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](node, init));
|
| 2769 |
+
});
|
| 2770 |
+
|
| 2771 |
+
// function written after some investigation here:
|
| 2772 |
+
// https://github.com/facebook/react/issues/10135#issuecomment-401496776
|
| 2773 |
+
function setNativeValue(element, value) {
|
| 2774 |
+
const {
|
| 2775 |
+
set: valueSetter
|
| 2776 |
+
} = Object.getOwnPropertyDescriptor(element, 'value') || {};
|
| 2777 |
+
const prototype = Object.getPrototypeOf(element);
|
| 2778 |
+
const {
|
| 2779 |
+
set: prototypeValueSetter
|
| 2780 |
+
} = Object.getOwnPropertyDescriptor(prototype, 'value') || {};
|
| 2781 |
+
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
|
| 2782 |
+
prototypeValueSetter.call(element, value);
|
| 2783 |
+
} else {
|
| 2784 |
+
/* istanbul ignore if */
|
| 2785 |
+
// eslint-disable-next-line no-lonely-if -- Can't be ignored by istanbul otherwise
|
| 2786 |
+
if (valueSetter) {
|
| 2787 |
+
valueSetter.call(element, value);
|
| 2788 |
+
} else {
|
| 2789 |
+
throw new Error('The given element does not have a value setter');
|
| 2790 |
+
}
|
| 2791 |
+
}
|
| 2792 |
+
}
|
| 2793 |
+
Object.keys(eventAliasMap).forEach(aliasKey => {
|
| 2794 |
+
const key = eventAliasMap[aliasKey];
|
| 2795 |
+
fireEvent[aliasKey] = function () {
|
| 2796 |
+
return fireEvent[key](...arguments);
|
| 2797 |
+
};
|
| 2798 |
+
});
|
| 2799 |
+
|
| 2800 |
+
/* eslint complexity:["error", 9] */
|
| 2801 |
+
|
| 2802 |
+
// WARNING: `lz-string` only has a default export but statically we assume named exports are allowed
|
| 2803 |
+
function unindent(string) {
|
| 2804 |
+
// remove white spaces first, to save a few bytes.
|
| 2805 |
+
// testing-playground will reformat on load any ways.
|
| 2806 |
+
return string.replace(/[ \t]*[\n][ \t]*/g, '\n');
|
| 2807 |
+
}
|
| 2808 |
+
function encode(value) {
|
| 2809 |
+
return lzString.compressToEncodedURIComponent(unindent(value));
|
| 2810 |
+
}
|
| 2811 |
+
function getPlaygroundUrl(markup) {
|
| 2812 |
+
return "https://testing-playground.com/#markup=" + encode(markup);
|
| 2813 |
+
}
|
| 2814 |
+
const debug = (element, maxLength, options) => Array.isArray(element) ? element.forEach(el => logDOM(el, maxLength, options)) : logDOM(element, maxLength, options);
|
| 2815 |
+
const logTestingPlaygroundURL = function (element) {
|
| 2816 |
+
if (element === void 0) {
|
| 2817 |
+
element = getDocument().body;
|
| 2818 |
+
}
|
| 2819 |
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
| 2820 |
+
if (!element || !('innerHTML' in element)) {
|
| 2821 |
+
console.log("The element you're providing isn't a valid DOM element.");
|
| 2822 |
+
return;
|
| 2823 |
+
}
|
| 2824 |
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
| 2825 |
+
if (!element.innerHTML) {
|
| 2826 |
+
console.log("The provided element doesn't have any children.");
|
| 2827 |
+
return;
|
| 2828 |
+
}
|
| 2829 |
+
const playgroundUrl = getPlaygroundUrl(element.innerHTML);
|
| 2830 |
+
console.log("Open this URL in your browser\n\n" + playgroundUrl);
|
| 2831 |
+
return playgroundUrl;
|
| 2832 |
+
};
|
| 2833 |
+
const initialValue = {
|
| 2834 |
+
debug,
|
| 2835 |
+
logTestingPlaygroundURL
|
| 2836 |
+
};
|
| 2837 |
+
const screen = typeof document !== 'undefined' && document.body // eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
| 2838 |
+
? getQueriesForElement(document.body, queries, initialValue) : Object.keys(queries).reduce((helpers, key) => {
|
| 2839 |
+
// `key` is for all intents and purposes the type of keyof `helpers`, which itself is the type of `initialValue` plus incoming properties from `queries`
|
| 2840 |
+
// if `Object.keys(something)` returned Array<keyof typeof something> this explicit type assertion would not be necessary
|
| 2841 |
+
// see https://stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript
|
| 2842 |
+
helpers[key] = () => {
|
| 2843 |
+
throw new TypeError('For queries bound to document.body a global document has to be available... Learn more: https://testing-library.com/s/screen-global-error');
|
| 2844 |
+
};
|
| 2845 |
+
return helpers;
|
| 2846 |
+
}, initialValue);
|
| 2847 |
+
|
| 2848 |
+
export { buildQueries, configure, createEvent, findAllByAltText, findAllByDisplayValue, findAllByLabelText, findAllByPlaceholderText, findAllByRole, findAllByTestId, findAllByText, findAllByTitle, findByAltText, findByDisplayValue, findByLabelText, findByPlaceholderText, findByRole, findByTestId, findByText, findByTitle, fireEvent, getAllByAltText, getAllByDisplayValue, getAllByLabelTextWithSuggestions as getAllByLabelText, getAllByPlaceholderText, getAllByRole, getAllByTestId, getAllByText, getAllByTitle, getByAltText, getByDisplayValue, getByLabelTextWithSuggestions as getByLabelText, getByPlaceholderText, getByRole, getByTestId, getByText, getByTitle, getConfig, getDefaultNormalizer, getElementError, getMultipleElementsFoundError, getNodeText, getQueriesForElement, getRoles, getSuggestedQuery, isInaccessible, logDOM, logRoles, makeFindQuery, makeGetAllQuery, makeSingleQuery, prettyDOM, queries, queryAllByAltTextWithSuggestions as queryAllByAltText, queryAllByAttribute, queryAllByDisplayValueWithSuggestions as queryAllByDisplayValue, queryAllByLabelTextWithSuggestions as queryAllByLabelText, queryAllByPlaceholderTextWithSuggestions as queryAllByPlaceholderText, queryAllByRoleWithSuggestions as queryAllByRole, queryAllByTestIdWithSuggestions as queryAllByTestId, queryAllByTextWithSuggestions as queryAllByText, queryAllByTitleWithSuggestions as queryAllByTitle, queryByAltText, queryByAttribute, queryByDisplayValue, queryByLabelText, queryByPlaceholderText, queryByRole, queryByTestId, queryByText, queryByTitle, queryHelpers, screen, waitForWrapper as waitFor, waitForElementToBeRemoved, getQueriesForElement as within, wrapAllByQueryWithSuggestion, wrapSingleQueryWithSuggestion };
|
node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js.map
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
node_modules/@testing-library/dom/dist/@testing-library/dom.umd.min.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
node_modules/@testing-library/dom/dist/@testing-library/dom.umd.min.js.map
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
node_modules/@testing-library/dom/dist/DOMElementFilter.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.default = createDOMElementFilter;
|
| 7 |
+
exports.test = void 0;
|
| 8 |
+
/**
|
| 9 |
+
* Source: https://github.com/facebook/jest/blob/e7bb6a1e26ffab90611b2593912df15b69315611/packages/pretty-format/src/plugins/DOMElement.ts
|
| 10 |
+
*/
|
| 11 |
+
/* eslint-disable -- trying to stay as close to the original as possible */
|
| 12 |
+
/* istanbul ignore file */
|
| 13 |
+
|
| 14 |
+
function escapeHTML(str) {
|
| 15 |
+
return str.replace(/</g, '<').replace(/>/g, '>');
|
| 16 |
+
}
|
| 17 |
+
// Return empty string if keys is empty.
|
| 18 |
+
const printProps = (keys, props, config, indentation, depth, refs, printer) => {
|
| 19 |
+
const indentationNext = indentation + config.indent;
|
| 20 |
+
const colors = config.colors;
|
| 21 |
+
return keys.map(key => {
|
| 22 |
+
const value = props[key];
|
| 23 |
+
let printed = printer(value, config, indentationNext, depth, refs);
|
| 24 |
+
if (typeof value !== 'string') {
|
| 25 |
+
if (printed.indexOf('\n') !== -1) {
|
| 26 |
+
printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation;
|
| 27 |
+
}
|
| 28 |
+
printed = '{' + printed + '}';
|
| 29 |
+
}
|
| 30 |
+
return config.spacingInner + indentation + colors.prop.open + key + colors.prop.close + '=' + colors.value.open + printed + colors.value.close;
|
| 31 |
+
}).join('');
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node_type_constants
|
| 35 |
+
const NodeTypeTextNode = 3;
|
| 36 |
+
|
| 37 |
+
// Return empty string if children is empty.
|
| 38 |
+
const printChildren = (children, config, indentation, depth, refs, printer) => children.map(child => {
|
| 39 |
+
const printedChild = typeof child === 'string' ? printText(child, config) : printer(child, config, indentation, depth, refs);
|
| 40 |
+
if (printedChild === '' && typeof child === 'object' && child !== null && child.nodeType !== NodeTypeTextNode) {
|
| 41 |
+
// A plugin serialized this Node to '' meaning we should ignore it.
|
| 42 |
+
return '';
|
| 43 |
+
}
|
| 44 |
+
return config.spacingOuter + indentation + printedChild;
|
| 45 |
+
}).join('');
|
| 46 |
+
const printText = (text, config) => {
|
| 47 |
+
const contentColor = config.colors.content;
|
| 48 |
+
return contentColor.open + escapeHTML(text) + contentColor.close;
|
| 49 |
+
};
|
| 50 |
+
const printComment = (comment, config) => {
|
| 51 |
+
const commentColor = config.colors.comment;
|
| 52 |
+
return commentColor.open + '<!--' + escapeHTML(comment) + '-->' + commentColor.close;
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
// Separate the functions to format props, children, and element,
|
| 56 |
+
// so a plugin could override a particular function, if needed.
|
| 57 |
+
// Too bad, so sad: the traditional (but unnecessary) space
|
| 58 |
+
// in a self-closing tagColor requires a second test of printedProps.
|
| 59 |
+
const printElement = (type, printedProps, printedChildren, config, indentation) => {
|
| 60 |
+
const tagColor = config.colors.tag;
|
| 61 |
+
return tagColor.open + '<' + type + (printedProps && tagColor.close + printedProps + config.spacingOuter + indentation + tagColor.open) + (printedChildren ? '>' + tagColor.close + printedChildren + config.spacingOuter + indentation + tagColor.open + '</' + type : (printedProps && !config.min ? '' : ' ') + '/') + '>' + tagColor.close;
|
| 62 |
+
};
|
| 63 |
+
const printElementAsLeaf = (type, config) => {
|
| 64 |
+
const tagColor = config.colors.tag;
|
| 65 |
+
return tagColor.open + '<' + type + tagColor.close + ' …' + tagColor.open + ' />' + tagColor.close;
|
| 66 |
+
};
|
| 67 |
+
const ELEMENT_NODE = 1;
|
| 68 |
+
const TEXT_NODE = 3;
|
| 69 |
+
const COMMENT_NODE = 8;
|
| 70 |
+
const FRAGMENT_NODE = 11;
|
| 71 |
+
const ELEMENT_REGEXP = /^((HTML|SVG)\w*)?Element$/;
|
| 72 |
+
const isCustomElement = val => {
|
| 73 |
+
const {
|
| 74 |
+
tagName
|
| 75 |
+
} = val;
|
| 76 |
+
return Boolean(typeof tagName === 'string' && tagName.includes('-') || typeof val.hasAttribute === 'function' && val.hasAttribute('is'));
|
| 77 |
+
};
|
| 78 |
+
const testNode = val => {
|
| 79 |
+
const constructorName = val.constructor.name;
|
| 80 |
+
const {
|
| 81 |
+
nodeType
|
| 82 |
+
} = val;
|
| 83 |
+
return nodeType === ELEMENT_NODE && (ELEMENT_REGEXP.test(constructorName) || isCustomElement(val)) || nodeType === TEXT_NODE && constructorName === 'Text' || nodeType === COMMENT_NODE && constructorName === 'Comment' || nodeType === FRAGMENT_NODE && constructorName === 'DocumentFragment';
|
| 84 |
+
};
|
| 85 |
+
const test = val => (val?.constructor?.name || isCustomElement(val)) && testNode(val);
|
| 86 |
+
exports.test = test;
|
| 87 |
+
function nodeIsText(node) {
|
| 88 |
+
return node.nodeType === TEXT_NODE;
|
| 89 |
+
}
|
| 90 |
+
function nodeIsComment(node) {
|
| 91 |
+
return node.nodeType === COMMENT_NODE;
|
| 92 |
+
}
|
| 93 |
+
function nodeIsFragment(node) {
|
| 94 |
+
return node.nodeType === FRAGMENT_NODE;
|
| 95 |
+
}
|
| 96 |
+
function createDOMElementFilter(filterNode) {
|
| 97 |
+
return {
|
| 98 |
+
test: val => (val?.constructor?.name || isCustomElement(val)) && testNode(val),
|
| 99 |
+
serialize: (node, config, indentation, depth, refs, printer) => {
|
| 100 |
+
if (nodeIsText(node)) {
|
| 101 |
+
return printText(node.data, config);
|
| 102 |
+
}
|
| 103 |
+
if (nodeIsComment(node)) {
|
| 104 |
+
return printComment(node.data, config);
|
| 105 |
+
}
|
| 106 |
+
const type = nodeIsFragment(node) ? `DocumentFragment` : node.tagName.toLowerCase();
|
| 107 |
+
if (++depth > config.maxDepth) {
|
| 108 |
+
return printElementAsLeaf(type, config);
|
| 109 |
+
}
|
| 110 |
+
return printElement(type, printProps(nodeIsFragment(node) ? [] : Array.from(node.attributes).map(attr => attr.name).sort(), nodeIsFragment(node) ? {} : Array.from(node.attributes).reduce((props, attribute) => {
|
| 111 |
+
props[attribute.name] = attribute.value;
|
| 112 |
+
return props;
|
| 113 |
+
}, {}), config, indentation + config.indent, depth, refs, printer), printChildren(Array.prototype.slice.call(node.childNodes || node.children).filter(filterNode), config, indentation + config.indent, depth, refs, printer), config, indentation);
|
| 114 |
+
}
|
| 115 |
+
};
|
| 116 |
+
}
|
node_modules/@testing-library/dom/dist/config.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.configure = configure;
|
| 7 |
+
exports.getConfig = getConfig;
|
| 8 |
+
exports.runWithExpensiveErrorDiagnosticsDisabled = runWithExpensiveErrorDiagnosticsDisabled;
|
| 9 |
+
var _prettyDom = require("./pretty-dom");
|
| 10 |
+
// It would be cleaner for this to live inside './queries', but
|
| 11 |
+
// other parts of the code assume that all exports from
|
| 12 |
+
// './queries' are query functions.
|
| 13 |
+
let config = {
|
| 14 |
+
testIdAttribute: 'data-testid',
|
| 15 |
+
asyncUtilTimeout: 1000,
|
| 16 |
+
// asyncWrapper and advanceTimersWrapper is to support React's async `act` function.
|
| 17 |
+
// forcing react-testing-library to wrap all async functions would've been
|
| 18 |
+
// a total nightmare (consider wrapping every findBy* query and then also
|
| 19 |
+
// updating `within` so those would be wrapped too. Total nightmare).
|
| 20 |
+
// so we have this config option that's really only intended for
|
| 21 |
+
// react-testing-library to use. For that reason, this feature will remain
|
| 22 |
+
// undocumented.
|
| 23 |
+
asyncWrapper: cb => cb(),
|
| 24 |
+
unstable_advanceTimersWrapper: cb => cb(),
|
| 25 |
+
eventWrapper: cb => cb(),
|
| 26 |
+
// default value for the `hidden` option in `ByRole` queries
|
| 27 |
+
defaultHidden: false,
|
| 28 |
+
// default value for the `ignore` option in `ByText` queries
|
| 29 |
+
defaultIgnore: 'script, style',
|
| 30 |
+
// showOriginalStackTrace flag to show the full error stack traces for async errors
|
| 31 |
+
showOriginalStackTrace: false,
|
| 32 |
+
// throw errors w/ suggestions for better queries. Opt in so off by default.
|
| 33 |
+
throwSuggestions: false,
|
| 34 |
+
// called when getBy* queries fail. (message, container) => Error
|
| 35 |
+
getElementError(message, container) {
|
| 36 |
+
const prettifiedDOM = (0, _prettyDom.prettyDOM)(container);
|
| 37 |
+
const error = new Error([message, `Ignored nodes: comments, ${config.defaultIgnore}\n${prettifiedDOM}`].filter(Boolean).join('\n\n'));
|
| 38 |
+
error.name = 'TestingLibraryElementError';
|
| 39 |
+
return error;
|
| 40 |
+
},
|
| 41 |
+
_disableExpensiveErrorDiagnostics: false,
|
| 42 |
+
computedStyleSupportsPseudoElements: false
|
| 43 |
+
};
|
| 44 |
+
function runWithExpensiveErrorDiagnosticsDisabled(callback) {
|
| 45 |
+
try {
|
| 46 |
+
config._disableExpensiveErrorDiagnostics = true;
|
| 47 |
+
return callback();
|
| 48 |
+
} finally {
|
| 49 |
+
config._disableExpensiveErrorDiagnostics = false;
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
function configure(newConfig) {
|
| 53 |
+
if (typeof newConfig === 'function') {
|
| 54 |
+
// Pass the existing config out to the provided function
|
| 55 |
+
// and accept a delta in return
|
| 56 |
+
newConfig = newConfig(config);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
// Merge the incoming config delta
|
| 60 |
+
config = {
|
| 61 |
+
...config,
|
| 62 |
+
...newConfig
|
| 63 |
+
};
|
| 64 |
+
}
|
| 65 |
+
function getConfig() {
|
| 66 |
+
return config;
|
| 67 |
+
}
|
node_modules/@testing-library/dom/dist/event-map.js
ADDED
|
@@ -0,0 +1,711 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.eventMap = exports.eventAliasMap = void 0;
|
| 7 |
+
const eventMap = exports.eventMap = {
|
| 8 |
+
// Clipboard Events
|
| 9 |
+
copy: {
|
| 10 |
+
EventType: 'ClipboardEvent',
|
| 11 |
+
defaultInit: {
|
| 12 |
+
bubbles: true,
|
| 13 |
+
cancelable: true,
|
| 14 |
+
composed: true
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
cut: {
|
| 18 |
+
EventType: 'ClipboardEvent',
|
| 19 |
+
defaultInit: {
|
| 20 |
+
bubbles: true,
|
| 21 |
+
cancelable: true,
|
| 22 |
+
composed: true
|
| 23 |
+
}
|
| 24 |
+
},
|
| 25 |
+
paste: {
|
| 26 |
+
EventType: 'ClipboardEvent',
|
| 27 |
+
defaultInit: {
|
| 28 |
+
bubbles: true,
|
| 29 |
+
cancelable: true,
|
| 30 |
+
composed: true
|
| 31 |
+
}
|
| 32 |
+
},
|
| 33 |
+
// Composition Events
|
| 34 |
+
compositionEnd: {
|
| 35 |
+
EventType: 'CompositionEvent',
|
| 36 |
+
defaultInit: {
|
| 37 |
+
bubbles: true,
|
| 38 |
+
cancelable: true,
|
| 39 |
+
composed: true
|
| 40 |
+
}
|
| 41 |
+
},
|
| 42 |
+
compositionStart: {
|
| 43 |
+
EventType: 'CompositionEvent',
|
| 44 |
+
defaultInit: {
|
| 45 |
+
bubbles: true,
|
| 46 |
+
cancelable: true,
|
| 47 |
+
composed: true
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
+
compositionUpdate: {
|
| 51 |
+
EventType: 'CompositionEvent',
|
| 52 |
+
defaultInit: {
|
| 53 |
+
bubbles: true,
|
| 54 |
+
cancelable: true,
|
| 55 |
+
composed: true
|
| 56 |
+
}
|
| 57 |
+
},
|
| 58 |
+
// Keyboard Events
|
| 59 |
+
keyDown: {
|
| 60 |
+
EventType: 'KeyboardEvent',
|
| 61 |
+
defaultInit: {
|
| 62 |
+
bubbles: true,
|
| 63 |
+
cancelable: true,
|
| 64 |
+
charCode: 0,
|
| 65 |
+
composed: true
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
keyPress: {
|
| 69 |
+
EventType: 'KeyboardEvent',
|
| 70 |
+
defaultInit: {
|
| 71 |
+
bubbles: true,
|
| 72 |
+
cancelable: true,
|
| 73 |
+
charCode: 0,
|
| 74 |
+
composed: true
|
| 75 |
+
}
|
| 76 |
+
},
|
| 77 |
+
keyUp: {
|
| 78 |
+
EventType: 'KeyboardEvent',
|
| 79 |
+
defaultInit: {
|
| 80 |
+
bubbles: true,
|
| 81 |
+
cancelable: true,
|
| 82 |
+
charCode: 0,
|
| 83 |
+
composed: true
|
| 84 |
+
}
|
| 85 |
+
},
|
| 86 |
+
// Focus Events
|
| 87 |
+
focus: {
|
| 88 |
+
EventType: 'FocusEvent',
|
| 89 |
+
defaultInit: {
|
| 90 |
+
bubbles: false,
|
| 91 |
+
cancelable: false,
|
| 92 |
+
composed: true
|
| 93 |
+
}
|
| 94 |
+
},
|
| 95 |
+
blur: {
|
| 96 |
+
EventType: 'FocusEvent',
|
| 97 |
+
defaultInit: {
|
| 98 |
+
bubbles: false,
|
| 99 |
+
cancelable: false,
|
| 100 |
+
composed: true
|
| 101 |
+
}
|
| 102 |
+
},
|
| 103 |
+
focusIn: {
|
| 104 |
+
EventType: 'FocusEvent',
|
| 105 |
+
defaultInit: {
|
| 106 |
+
bubbles: true,
|
| 107 |
+
cancelable: false,
|
| 108 |
+
composed: true
|
| 109 |
+
}
|
| 110 |
+
},
|
| 111 |
+
focusOut: {
|
| 112 |
+
EventType: 'FocusEvent',
|
| 113 |
+
defaultInit: {
|
| 114 |
+
bubbles: true,
|
| 115 |
+
cancelable: false,
|
| 116 |
+
composed: true
|
| 117 |
+
}
|
| 118 |
+
},
|
| 119 |
+
// Form Events
|
| 120 |
+
change: {
|
| 121 |
+
EventType: 'Event',
|
| 122 |
+
defaultInit: {
|
| 123 |
+
bubbles: true,
|
| 124 |
+
cancelable: false
|
| 125 |
+
}
|
| 126 |
+
},
|
| 127 |
+
input: {
|
| 128 |
+
EventType: 'InputEvent',
|
| 129 |
+
defaultInit: {
|
| 130 |
+
bubbles: true,
|
| 131 |
+
cancelable: false,
|
| 132 |
+
composed: true
|
| 133 |
+
}
|
| 134 |
+
},
|
| 135 |
+
invalid: {
|
| 136 |
+
EventType: 'Event',
|
| 137 |
+
defaultInit: {
|
| 138 |
+
bubbles: false,
|
| 139 |
+
cancelable: true
|
| 140 |
+
}
|
| 141 |
+
},
|
| 142 |
+
submit: {
|
| 143 |
+
EventType: 'Event',
|
| 144 |
+
defaultInit: {
|
| 145 |
+
bubbles: true,
|
| 146 |
+
cancelable: true
|
| 147 |
+
}
|
| 148 |
+
},
|
| 149 |
+
reset: {
|
| 150 |
+
EventType: 'Event',
|
| 151 |
+
defaultInit: {
|
| 152 |
+
bubbles: true,
|
| 153 |
+
cancelable: true
|
| 154 |
+
}
|
| 155 |
+
},
|
| 156 |
+
// Mouse Events
|
| 157 |
+
click: {
|
| 158 |
+
EventType: 'MouseEvent',
|
| 159 |
+
defaultInit: {
|
| 160 |
+
bubbles: true,
|
| 161 |
+
cancelable: true,
|
| 162 |
+
button: 0,
|
| 163 |
+
composed: true
|
| 164 |
+
}
|
| 165 |
+
},
|
| 166 |
+
contextMenu: {
|
| 167 |
+
EventType: 'MouseEvent',
|
| 168 |
+
defaultInit: {
|
| 169 |
+
bubbles: true,
|
| 170 |
+
cancelable: true,
|
| 171 |
+
composed: true
|
| 172 |
+
}
|
| 173 |
+
},
|
| 174 |
+
dblClick: {
|
| 175 |
+
EventType: 'MouseEvent',
|
| 176 |
+
defaultInit: {
|
| 177 |
+
bubbles: true,
|
| 178 |
+
cancelable: true,
|
| 179 |
+
composed: true
|
| 180 |
+
}
|
| 181 |
+
},
|
| 182 |
+
drag: {
|
| 183 |
+
EventType: 'DragEvent',
|
| 184 |
+
defaultInit: {
|
| 185 |
+
bubbles: true,
|
| 186 |
+
cancelable: true,
|
| 187 |
+
composed: true
|
| 188 |
+
}
|
| 189 |
+
},
|
| 190 |
+
dragEnd: {
|
| 191 |
+
EventType: 'DragEvent',
|
| 192 |
+
defaultInit: {
|
| 193 |
+
bubbles: true,
|
| 194 |
+
cancelable: false,
|
| 195 |
+
composed: true
|
| 196 |
+
}
|
| 197 |
+
},
|
| 198 |
+
dragEnter: {
|
| 199 |
+
EventType: 'DragEvent',
|
| 200 |
+
defaultInit: {
|
| 201 |
+
bubbles: true,
|
| 202 |
+
cancelable: true,
|
| 203 |
+
composed: true
|
| 204 |
+
}
|
| 205 |
+
},
|
| 206 |
+
dragExit: {
|
| 207 |
+
EventType: 'DragEvent',
|
| 208 |
+
defaultInit: {
|
| 209 |
+
bubbles: true,
|
| 210 |
+
cancelable: false,
|
| 211 |
+
composed: true
|
| 212 |
+
}
|
| 213 |
+
},
|
| 214 |
+
dragLeave: {
|
| 215 |
+
EventType: 'DragEvent',
|
| 216 |
+
defaultInit: {
|
| 217 |
+
bubbles: true,
|
| 218 |
+
cancelable: false,
|
| 219 |
+
composed: true
|
| 220 |
+
}
|
| 221 |
+
},
|
| 222 |
+
dragOver: {
|
| 223 |
+
EventType: 'DragEvent',
|
| 224 |
+
defaultInit: {
|
| 225 |
+
bubbles: true,
|
| 226 |
+
cancelable: true,
|
| 227 |
+
composed: true
|
| 228 |
+
}
|
| 229 |
+
},
|
| 230 |
+
dragStart: {
|
| 231 |
+
EventType: 'DragEvent',
|
| 232 |
+
defaultInit: {
|
| 233 |
+
bubbles: true,
|
| 234 |
+
cancelable: true,
|
| 235 |
+
composed: true
|
| 236 |
+
}
|
| 237 |
+
},
|
| 238 |
+
drop: {
|
| 239 |
+
EventType: 'DragEvent',
|
| 240 |
+
defaultInit: {
|
| 241 |
+
bubbles: true,
|
| 242 |
+
cancelable: true,
|
| 243 |
+
composed: true
|
| 244 |
+
}
|
| 245 |
+
},
|
| 246 |
+
mouseDown: {
|
| 247 |
+
EventType: 'MouseEvent',
|
| 248 |
+
defaultInit: {
|
| 249 |
+
bubbles: true,
|
| 250 |
+
cancelable: true,
|
| 251 |
+
composed: true
|
| 252 |
+
}
|
| 253 |
+
},
|
| 254 |
+
mouseEnter: {
|
| 255 |
+
EventType: 'MouseEvent',
|
| 256 |
+
defaultInit: {
|
| 257 |
+
bubbles: false,
|
| 258 |
+
cancelable: false,
|
| 259 |
+
composed: true
|
| 260 |
+
}
|
| 261 |
+
},
|
| 262 |
+
mouseLeave: {
|
| 263 |
+
EventType: 'MouseEvent',
|
| 264 |
+
defaultInit: {
|
| 265 |
+
bubbles: false,
|
| 266 |
+
cancelable: false,
|
| 267 |
+
composed: true
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
mouseMove: {
|
| 271 |
+
EventType: 'MouseEvent',
|
| 272 |
+
defaultInit: {
|
| 273 |
+
bubbles: true,
|
| 274 |
+
cancelable: true,
|
| 275 |
+
composed: true
|
| 276 |
+
}
|
| 277 |
+
},
|
| 278 |
+
mouseOut: {
|
| 279 |
+
EventType: 'MouseEvent',
|
| 280 |
+
defaultInit: {
|
| 281 |
+
bubbles: true,
|
| 282 |
+
cancelable: true,
|
| 283 |
+
composed: true
|
| 284 |
+
}
|
| 285 |
+
},
|
| 286 |
+
mouseOver: {
|
| 287 |
+
EventType: 'MouseEvent',
|
| 288 |
+
defaultInit: {
|
| 289 |
+
bubbles: true,
|
| 290 |
+
cancelable: true,
|
| 291 |
+
composed: true
|
| 292 |
+
}
|
| 293 |
+
},
|
| 294 |
+
mouseUp: {
|
| 295 |
+
EventType: 'MouseEvent',
|
| 296 |
+
defaultInit: {
|
| 297 |
+
bubbles: true,
|
| 298 |
+
cancelable: true,
|
| 299 |
+
composed: true
|
| 300 |
+
}
|
| 301 |
+
},
|
| 302 |
+
// Selection Events
|
| 303 |
+
select: {
|
| 304 |
+
EventType: 'Event',
|
| 305 |
+
defaultInit: {
|
| 306 |
+
bubbles: true,
|
| 307 |
+
cancelable: false
|
| 308 |
+
}
|
| 309 |
+
},
|
| 310 |
+
// Touch Events
|
| 311 |
+
touchCancel: {
|
| 312 |
+
EventType: 'TouchEvent',
|
| 313 |
+
defaultInit: {
|
| 314 |
+
bubbles: true,
|
| 315 |
+
cancelable: false,
|
| 316 |
+
composed: true
|
| 317 |
+
}
|
| 318 |
+
},
|
| 319 |
+
touchEnd: {
|
| 320 |
+
EventType: 'TouchEvent',
|
| 321 |
+
defaultInit: {
|
| 322 |
+
bubbles: true,
|
| 323 |
+
cancelable: true,
|
| 324 |
+
composed: true
|
| 325 |
+
}
|
| 326 |
+
},
|
| 327 |
+
touchMove: {
|
| 328 |
+
EventType: 'TouchEvent',
|
| 329 |
+
defaultInit: {
|
| 330 |
+
bubbles: true,
|
| 331 |
+
cancelable: true,
|
| 332 |
+
composed: true
|
| 333 |
+
}
|
| 334 |
+
},
|
| 335 |
+
touchStart: {
|
| 336 |
+
EventType: 'TouchEvent',
|
| 337 |
+
defaultInit: {
|
| 338 |
+
bubbles: true,
|
| 339 |
+
cancelable: true,
|
| 340 |
+
composed: true
|
| 341 |
+
}
|
| 342 |
+
},
|
| 343 |
+
// UI Events
|
| 344 |
+
resize: {
|
| 345 |
+
EventType: 'UIEvent',
|
| 346 |
+
defaultInit: {
|
| 347 |
+
bubbles: false,
|
| 348 |
+
cancelable: false
|
| 349 |
+
}
|
| 350 |
+
},
|
| 351 |
+
scroll: {
|
| 352 |
+
EventType: 'UIEvent',
|
| 353 |
+
defaultInit: {
|
| 354 |
+
bubbles: false,
|
| 355 |
+
cancelable: false
|
| 356 |
+
}
|
| 357 |
+
},
|
| 358 |
+
// Wheel Events
|
| 359 |
+
wheel: {
|
| 360 |
+
EventType: 'WheelEvent',
|
| 361 |
+
defaultInit: {
|
| 362 |
+
bubbles: true,
|
| 363 |
+
cancelable: true,
|
| 364 |
+
composed: true
|
| 365 |
+
}
|
| 366 |
+
},
|
| 367 |
+
// Media Events
|
| 368 |
+
abort: {
|
| 369 |
+
EventType: 'Event',
|
| 370 |
+
defaultInit: {
|
| 371 |
+
bubbles: false,
|
| 372 |
+
cancelable: false
|
| 373 |
+
}
|
| 374 |
+
},
|
| 375 |
+
canPlay: {
|
| 376 |
+
EventType: 'Event',
|
| 377 |
+
defaultInit: {
|
| 378 |
+
bubbles: false,
|
| 379 |
+
cancelable: false
|
| 380 |
+
}
|
| 381 |
+
},
|
| 382 |
+
canPlayThrough: {
|
| 383 |
+
EventType: 'Event',
|
| 384 |
+
defaultInit: {
|
| 385 |
+
bubbles: false,
|
| 386 |
+
cancelable: false
|
| 387 |
+
}
|
| 388 |
+
},
|
| 389 |
+
durationChange: {
|
| 390 |
+
EventType: 'Event',
|
| 391 |
+
defaultInit: {
|
| 392 |
+
bubbles: false,
|
| 393 |
+
cancelable: false
|
| 394 |
+
}
|
| 395 |
+
},
|
| 396 |
+
emptied: {
|
| 397 |
+
EventType: 'Event',
|
| 398 |
+
defaultInit: {
|
| 399 |
+
bubbles: false,
|
| 400 |
+
cancelable: false
|
| 401 |
+
}
|
| 402 |
+
},
|
| 403 |
+
encrypted: {
|
| 404 |
+
EventType: 'Event',
|
| 405 |
+
defaultInit: {
|
| 406 |
+
bubbles: false,
|
| 407 |
+
cancelable: false
|
| 408 |
+
}
|
| 409 |
+
},
|
| 410 |
+
ended: {
|
| 411 |
+
EventType: 'Event',
|
| 412 |
+
defaultInit: {
|
| 413 |
+
bubbles: false,
|
| 414 |
+
cancelable: false
|
| 415 |
+
}
|
| 416 |
+
},
|
| 417 |
+
loadedData: {
|
| 418 |
+
EventType: 'Event',
|
| 419 |
+
defaultInit: {
|
| 420 |
+
bubbles: false,
|
| 421 |
+
cancelable: false
|
| 422 |
+
}
|
| 423 |
+
},
|
| 424 |
+
loadedMetadata: {
|
| 425 |
+
EventType: 'Event',
|
| 426 |
+
defaultInit: {
|
| 427 |
+
bubbles: false,
|
| 428 |
+
cancelable: false
|
| 429 |
+
}
|
| 430 |
+
},
|
| 431 |
+
loadStart: {
|
| 432 |
+
EventType: 'ProgressEvent',
|
| 433 |
+
defaultInit: {
|
| 434 |
+
bubbles: false,
|
| 435 |
+
cancelable: false
|
| 436 |
+
}
|
| 437 |
+
},
|
| 438 |
+
pause: {
|
| 439 |
+
EventType: 'Event',
|
| 440 |
+
defaultInit: {
|
| 441 |
+
bubbles: false,
|
| 442 |
+
cancelable: false
|
| 443 |
+
}
|
| 444 |
+
},
|
| 445 |
+
play: {
|
| 446 |
+
EventType: 'Event',
|
| 447 |
+
defaultInit: {
|
| 448 |
+
bubbles: false,
|
| 449 |
+
cancelable: false
|
| 450 |
+
}
|
| 451 |
+
},
|
| 452 |
+
playing: {
|
| 453 |
+
EventType: 'Event',
|
| 454 |
+
defaultInit: {
|
| 455 |
+
bubbles: false,
|
| 456 |
+
cancelable: false
|
| 457 |
+
}
|
| 458 |
+
},
|
| 459 |
+
progress: {
|
| 460 |
+
EventType: 'ProgressEvent',
|
| 461 |
+
defaultInit: {
|
| 462 |
+
bubbles: false,
|
| 463 |
+
cancelable: false
|
| 464 |
+
}
|
| 465 |
+
},
|
| 466 |
+
rateChange: {
|
| 467 |
+
EventType: 'Event',
|
| 468 |
+
defaultInit: {
|
| 469 |
+
bubbles: false,
|
| 470 |
+
cancelable: false
|
| 471 |
+
}
|
| 472 |
+
},
|
| 473 |
+
seeked: {
|
| 474 |
+
EventType: 'Event',
|
| 475 |
+
defaultInit: {
|
| 476 |
+
bubbles: false,
|
| 477 |
+
cancelable: false
|
| 478 |
+
}
|
| 479 |
+
},
|
| 480 |
+
seeking: {
|
| 481 |
+
EventType: 'Event',
|
| 482 |
+
defaultInit: {
|
| 483 |
+
bubbles: false,
|
| 484 |
+
cancelable: false
|
| 485 |
+
}
|
| 486 |
+
},
|
| 487 |
+
stalled: {
|
| 488 |
+
EventType: 'Event',
|
| 489 |
+
defaultInit: {
|
| 490 |
+
bubbles: false,
|
| 491 |
+
cancelable: false
|
| 492 |
+
}
|
| 493 |
+
},
|
| 494 |
+
suspend: {
|
| 495 |
+
EventType: 'Event',
|
| 496 |
+
defaultInit: {
|
| 497 |
+
bubbles: false,
|
| 498 |
+
cancelable: false
|
| 499 |
+
}
|
| 500 |
+
},
|
| 501 |
+
timeUpdate: {
|
| 502 |
+
EventType: 'Event',
|
| 503 |
+
defaultInit: {
|
| 504 |
+
bubbles: false,
|
| 505 |
+
cancelable: false
|
| 506 |
+
}
|
| 507 |
+
},
|
| 508 |
+
volumeChange: {
|
| 509 |
+
EventType: 'Event',
|
| 510 |
+
defaultInit: {
|
| 511 |
+
bubbles: false,
|
| 512 |
+
cancelable: false
|
| 513 |
+
}
|
| 514 |
+
},
|
| 515 |
+
waiting: {
|
| 516 |
+
EventType: 'Event',
|
| 517 |
+
defaultInit: {
|
| 518 |
+
bubbles: false,
|
| 519 |
+
cancelable: false
|
| 520 |
+
}
|
| 521 |
+
},
|
| 522 |
+
// Events
|
| 523 |
+
load: {
|
| 524 |
+
// TODO: load events can be UIEvent or Event depending on what generated them
|
| 525 |
+
// This is where this abstraction breaks down.
|
| 526 |
+
// But the common targets are <img />, <script /> and window.
|
| 527 |
+
// Neither of these targets receive a UIEvent
|
| 528 |
+
EventType: 'Event',
|
| 529 |
+
defaultInit: {
|
| 530 |
+
bubbles: false,
|
| 531 |
+
cancelable: false
|
| 532 |
+
}
|
| 533 |
+
},
|
| 534 |
+
error: {
|
| 535 |
+
EventType: 'Event',
|
| 536 |
+
defaultInit: {
|
| 537 |
+
bubbles: false,
|
| 538 |
+
cancelable: false
|
| 539 |
+
}
|
| 540 |
+
},
|
| 541 |
+
// Animation Events
|
| 542 |
+
animationStart: {
|
| 543 |
+
EventType: 'AnimationEvent',
|
| 544 |
+
defaultInit: {
|
| 545 |
+
bubbles: true,
|
| 546 |
+
cancelable: false
|
| 547 |
+
}
|
| 548 |
+
},
|
| 549 |
+
animationEnd: {
|
| 550 |
+
EventType: 'AnimationEvent',
|
| 551 |
+
defaultInit: {
|
| 552 |
+
bubbles: true,
|
| 553 |
+
cancelable: false
|
| 554 |
+
}
|
| 555 |
+
},
|
| 556 |
+
animationIteration: {
|
| 557 |
+
EventType: 'AnimationEvent',
|
| 558 |
+
defaultInit: {
|
| 559 |
+
bubbles: true,
|
| 560 |
+
cancelable: false
|
| 561 |
+
}
|
| 562 |
+
},
|
| 563 |
+
// Transition Events
|
| 564 |
+
transitionCancel: {
|
| 565 |
+
EventType: 'TransitionEvent',
|
| 566 |
+
defaultInit: {
|
| 567 |
+
bubbles: true,
|
| 568 |
+
cancelable: false
|
| 569 |
+
}
|
| 570 |
+
},
|
| 571 |
+
transitionEnd: {
|
| 572 |
+
EventType: 'TransitionEvent',
|
| 573 |
+
defaultInit: {
|
| 574 |
+
bubbles: true,
|
| 575 |
+
cancelable: true
|
| 576 |
+
}
|
| 577 |
+
},
|
| 578 |
+
transitionRun: {
|
| 579 |
+
EventType: 'TransitionEvent',
|
| 580 |
+
defaultInit: {
|
| 581 |
+
bubbles: true,
|
| 582 |
+
cancelable: false
|
| 583 |
+
}
|
| 584 |
+
},
|
| 585 |
+
transitionStart: {
|
| 586 |
+
EventType: 'TransitionEvent',
|
| 587 |
+
defaultInit: {
|
| 588 |
+
bubbles: true,
|
| 589 |
+
cancelable: false
|
| 590 |
+
}
|
| 591 |
+
},
|
| 592 |
+
// pointer events
|
| 593 |
+
pointerOver: {
|
| 594 |
+
EventType: 'PointerEvent',
|
| 595 |
+
defaultInit: {
|
| 596 |
+
bubbles: true,
|
| 597 |
+
cancelable: true,
|
| 598 |
+
composed: true
|
| 599 |
+
}
|
| 600 |
+
},
|
| 601 |
+
pointerEnter: {
|
| 602 |
+
EventType: 'PointerEvent',
|
| 603 |
+
defaultInit: {
|
| 604 |
+
bubbles: false,
|
| 605 |
+
cancelable: false
|
| 606 |
+
}
|
| 607 |
+
},
|
| 608 |
+
pointerDown: {
|
| 609 |
+
EventType: 'PointerEvent',
|
| 610 |
+
defaultInit: {
|
| 611 |
+
bubbles: true,
|
| 612 |
+
cancelable: true,
|
| 613 |
+
composed: true
|
| 614 |
+
}
|
| 615 |
+
},
|
| 616 |
+
pointerMove: {
|
| 617 |
+
EventType: 'PointerEvent',
|
| 618 |
+
defaultInit: {
|
| 619 |
+
bubbles: true,
|
| 620 |
+
cancelable: true,
|
| 621 |
+
composed: true
|
| 622 |
+
}
|
| 623 |
+
},
|
| 624 |
+
pointerUp: {
|
| 625 |
+
EventType: 'PointerEvent',
|
| 626 |
+
defaultInit: {
|
| 627 |
+
bubbles: true,
|
| 628 |
+
cancelable: true,
|
| 629 |
+
composed: true
|
| 630 |
+
}
|
| 631 |
+
},
|
| 632 |
+
pointerCancel: {
|
| 633 |
+
EventType: 'PointerEvent',
|
| 634 |
+
defaultInit: {
|
| 635 |
+
bubbles: true,
|
| 636 |
+
cancelable: false,
|
| 637 |
+
composed: true
|
| 638 |
+
}
|
| 639 |
+
},
|
| 640 |
+
pointerOut: {
|
| 641 |
+
EventType: 'PointerEvent',
|
| 642 |
+
defaultInit: {
|
| 643 |
+
bubbles: true,
|
| 644 |
+
cancelable: true,
|
| 645 |
+
composed: true
|
| 646 |
+
}
|
| 647 |
+
},
|
| 648 |
+
pointerLeave: {
|
| 649 |
+
EventType: 'PointerEvent',
|
| 650 |
+
defaultInit: {
|
| 651 |
+
bubbles: false,
|
| 652 |
+
cancelable: false
|
| 653 |
+
}
|
| 654 |
+
},
|
| 655 |
+
gotPointerCapture: {
|
| 656 |
+
EventType: 'PointerEvent',
|
| 657 |
+
defaultInit: {
|
| 658 |
+
bubbles: true,
|
| 659 |
+
cancelable: false,
|
| 660 |
+
composed: true
|
| 661 |
+
}
|
| 662 |
+
},
|
| 663 |
+
lostPointerCapture: {
|
| 664 |
+
EventType: 'PointerEvent',
|
| 665 |
+
defaultInit: {
|
| 666 |
+
bubbles: true,
|
| 667 |
+
cancelable: false,
|
| 668 |
+
composed: true
|
| 669 |
+
}
|
| 670 |
+
},
|
| 671 |
+
// history events
|
| 672 |
+
popState: {
|
| 673 |
+
EventType: 'PopStateEvent',
|
| 674 |
+
defaultInit: {
|
| 675 |
+
bubbles: true,
|
| 676 |
+
cancelable: false
|
| 677 |
+
}
|
| 678 |
+
},
|
| 679 |
+
// window events
|
| 680 |
+
offline: {
|
| 681 |
+
EventType: 'Event',
|
| 682 |
+
defaultInit: {
|
| 683 |
+
bubbles: false,
|
| 684 |
+
cancelable: false
|
| 685 |
+
}
|
| 686 |
+
},
|
| 687 |
+
online: {
|
| 688 |
+
EventType: 'Event',
|
| 689 |
+
defaultInit: {
|
| 690 |
+
bubbles: false,
|
| 691 |
+
cancelable: false
|
| 692 |
+
}
|
| 693 |
+
},
|
| 694 |
+
pageHide: {
|
| 695 |
+
EventType: 'PageTransitionEvent',
|
| 696 |
+
defaultInit: {
|
| 697 |
+
bubbles: true,
|
| 698 |
+
cancelable: true
|
| 699 |
+
}
|
| 700 |
+
},
|
| 701 |
+
pageShow: {
|
| 702 |
+
EventType: 'PageTransitionEvent',
|
| 703 |
+
defaultInit: {
|
| 704 |
+
bubbles: true,
|
| 705 |
+
cancelable: true
|
| 706 |
+
}
|
| 707 |
+
}
|
| 708 |
+
};
|
| 709 |
+
const eventAliasMap = exports.eventAliasMap = {
|
| 710 |
+
doubleClick: 'dblClick'
|
| 711 |
+
};
|
node_modules/@testing-library/dom/dist/events.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.createEvent = createEvent;
|
| 7 |
+
exports.fireEvent = fireEvent;
|
| 8 |
+
var _config = require("./config");
|
| 9 |
+
var _helpers = require("./helpers");
|
| 10 |
+
var _eventMap = require("./event-map");
|
| 11 |
+
function fireEvent(element, event) {
|
| 12 |
+
return (0, _config.getConfig)().eventWrapper(() => {
|
| 13 |
+
if (!event) {
|
| 14 |
+
throw new Error(`Unable to fire an event - please provide an event object.`);
|
| 15 |
+
}
|
| 16 |
+
if (!element) {
|
| 17 |
+
throw new Error(`Unable to fire a "${event.type}" event - please provide a DOM element.`);
|
| 18 |
+
}
|
| 19 |
+
return element.dispatchEvent(event);
|
| 20 |
+
});
|
| 21 |
+
}
|
| 22 |
+
function createEvent(eventName, node, init, {
|
| 23 |
+
EventType = 'Event',
|
| 24 |
+
defaultInit = {}
|
| 25 |
+
} = {}) {
|
| 26 |
+
if (!node) {
|
| 27 |
+
throw new Error(`Unable to fire a "${eventName}" event - please provide a DOM element.`);
|
| 28 |
+
}
|
| 29 |
+
const eventInit = {
|
| 30 |
+
...defaultInit,
|
| 31 |
+
...init
|
| 32 |
+
};
|
| 33 |
+
const {
|
| 34 |
+
target: {
|
| 35 |
+
value,
|
| 36 |
+
files,
|
| 37 |
+
...targetProperties
|
| 38 |
+
} = {}
|
| 39 |
+
} = eventInit;
|
| 40 |
+
if (value !== undefined) {
|
| 41 |
+
setNativeValue(node, value);
|
| 42 |
+
}
|
| 43 |
+
if (files !== undefined) {
|
| 44 |
+
// input.files is a read-only property so this is not allowed:
|
| 45 |
+
// input.files = [file]
|
| 46 |
+
// so we have to use this workaround to set the property
|
| 47 |
+
Object.defineProperty(node, 'files', {
|
| 48 |
+
configurable: true,
|
| 49 |
+
enumerable: true,
|
| 50 |
+
writable: true,
|
| 51 |
+
value: files
|
| 52 |
+
});
|
| 53 |
+
}
|
| 54 |
+
Object.assign(node, targetProperties);
|
| 55 |
+
const window = (0, _helpers.getWindowFromNode)(node);
|
| 56 |
+
const EventConstructor = window[EventType] || window.Event;
|
| 57 |
+
let event;
|
| 58 |
+
/* istanbul ignore else */
|
| 59 |
+
if (typeof EventConstructor === 'function') {
|
| 60 |
+
event = new EventConstructor(eventName, eventInit);
|
| 61 |
+
} else {
|
| 62 |
+
// IE11 polyfill from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
| 63 |
+
event = window.document.createEvent(EventType);
|
| 64 |
+
const {
|
| 65 |
+
bubbles,
|
| 66 |
+
cancelable,
|
| 67 |
+
detail,
|
| 68 |
+
...otherInit
|
| 69 |
+
} = eventInit;
|
| 70 |
+
event.initEvent(eventName, bubbles, cancelable, detail);
|
| 71 |
+
Object.keys(otherInit).forEach(eventKey => {
|
| 72 |
+
event[eventKey] = otherInit[eventKey];
|
| 73 |
+
});
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
// DataTransfer is not supported in jsdom: https://github.com/jsdom/jsdom/issues/1568
|
| 77 |
+
const dataTransferProperties = ['dataTransfer', 'clipboardData'];
|
| 78 |
+
dataTransferProperties.forEach(dataTransferKey => {
|
| 79 |
+
const dataTransferValue = eventInit[dataTransferKey];
|
| 80 |
+
if (typeof dataTransferValue === 'object') {
|
| 81 |
+
/* istanbul ignore if */
|
| 82 |
+
if (typeof window.DataTransfer === 'function') {
|
| 83 |
+
Object.defineProperty(event, dataTransferKey, {
|
| 84 |
+
value: Object.getOwnPropertyNames(dataTransferValue).reduce((acc, propName) => {
|
| 85 |
+
Object.defineProperty(acc, propName, {
|
| 86 |
+
value: dataTransferValue[propName]
|
| 87 |
+
});
|
| 88 |
+
return acc;
|
| 89 |
+
}, new window.DataTransfer())
|
| 90 |
+
});
|
| 91 |
+
} else {
|
| 92 |
+
Object.defineProperty(event, dataTransferKey, {
|
| 93 |
+
value: dataTransferValue
|
| 94 |
+
});
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
});
|
| 98 |
+
return event;
|
| 99 |
+
}
|
| 100 |
+
Object.keys(_eventMap.eventMap).forEach(key => {
|
| 101 |
+
const {
|
| 102 |
+
EventType,
|
| 103 |
+
defaultInit
|
| 104 |
+
} = _eventMap.eventMap[key];
|
| 105 |
+
const eventName = key.toLowerCase();
|
| 106 |
+
createEvent[key] = (node, init) => createEvent(eventName, node, init, {
|
| 107 |
+
EventType,
|
| 108 |
+
defaultInit
|
| 109 |
+
});
|
| 110 |
+
fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](node, init));
|
| 111 |
+
});
|
| 112 |
+
|
| 113 |
+
// function written after some investigation here:
|
| 114 |
+
// https://github.com/facebook/react/issues/10135#issuecomment-401496776
|
| 115 |
+
function setNativeValue(element, value) {
|
| 116 |
+
const {
|
| 117 |
+
set: valueSetter
|
| 118 |
+
} = Object.getOwnPropertyDescriptor(element, 'value') || {};
|
| 119 |
+
const prototype = Object.getPrototypeOf(element);
|
| 120 |
+
const {
|
| 121 |
+
set: prototypeValueSetter
|
| 122 |
+
} = Object.getOwnPropertyDescriptor(prototype, 'value') || {};
|
| 123 |
+
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
|
| 124 |
+
prototypeValueSetter.call(element, value);
|
| 125 |
+
} else {
|
| 126 |
+
/* istanbul ignore if */
|
| 127 |
+
// eslint-disable-next-line no-lonely-if -- Can't be ignored by istanbul otherwise
|
| 128 |
+
if (valueSetter) {
|
| 129 |
+
valueSetter.call(element, value);
|
| 130 |
+
} else {
|
| 131 |
+
throw new Error('The given element does not have a value setter');
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
Object.keys(_eventMap.eventAliasMap).forEach(aliasKey => {
|
| 136 |
+
const key = _eventMap.eventAliasMap[aliasKey];
|
| 137 |
+
fireEvent[aliasKey] = (...args) => fireEvent[key](...args);
|
| 138 |
+
});
|
| 139 |
+
|
| 140 |
+
/* eslint complexity:["error", 9] */
|
node_modules/@testing-library/dom/dist/get-node-text.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.getNodeText = getNodeText;
|
| 7 |
+
var _helpers = require("./helpers");
|
| 8 |
+
function getNodeText(node) {
|
| 9 |
+
if (node.matches('input[type=submit], input[type=button], input[type=reset]')) {
|
| 10 |
+
return node.value;
|
| 11 |
+
}
|
| 12 |
+
return Array.from(node.childNodes).filter(child => child.nodeType === _helpers.TEXT_NODE && Boolean(child.textContent)).map(c => c.textContent).join('');
|
| 13 |
+
}
|
node_modules/@testing-library/dom/dist/get-queries-for-element.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.getQueriesForElement = getQueriesForElement;
|
| 7 |
+
var defaultQueries = _interopRequireWildcard(require("./queries"));
|
| 8 |
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
| 9 |
+
/**
|
| 10 |
+
* @typedef {{[key: string]: Function}} FuncMap
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
/**
|
| 14 |
+
* @param {HTMLElement} element container
|
| 15 |
+
* @param {FuncMap} queries object of functions
|
| 16 |
+
* @param {Object} initialValue for reducer
|
| 17 |
+
* @returns {FuncMap} returns object of functions bound to container
|
| 18 |
+
*/
|
| 19 |
+
function getQueriesForElement(element, queries = defaultQueries, initialValue = {}) {
|
| 20 |
+
return Object.keys(queries).reduce((helpers, key) => {
|
| 21 |
+
const fn = queries[key];
|
| 22 |
+
helpers[key] = fn.bind(null, element);
|
| 23 |
+
return helpers;
|
| 24 |
+
}, initialValue);
|
| 25 |
+
}
|
node_modules/@testing-library/dom/dist/get-user-code-frame.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.getUserCodeFrame = getUserCodeFrame;
|
| 7 |
+
// We try to load node dependencies
|
| 8 |
+
let picocolors = null;
|
| 9 |
+
let readFileSync = null;
|
| 10 |
+
let codeFrameColumns = null;
|
| 11 |
+
try {
|
| 12 |
+
const nodeRequire = module && module.require;
|
| 13 |
+
readFileSync = nodeRequire.call(module, 'fs').readFileSync;
|
| 14 |
+
codeFrameColumns = nodeRequire.call(module, '@babel/code-frame').codeFrameColumns;
|
| 15 |
+
picocolors = nodeRequire.call(module, 'picocolors');
|
| 16 |
+
} catch {
|
| 17 |
+
// We're in a browser environment
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
// frame has the form "at myMethod (location/to/my/file.js:10:2)"
|
| 21 |
+
function getCodeFrame(frame) {
|
| 22 |
+
const locationStart = frame.indexOf('(') + 1;
|
| 23 |
+
const locationEnd = frame.indexOf(')');
|
| 24 |
+
const frameLocation = frame.slice(locationStart, locationEnd);
|
| 25 |
+
const frameLocationElements = frameLocation.split(':');
|
| 26 |
+
const [filename, line, column] = [frameLocationElements[0], parseInt(frameLocationElements[1], 10), parseInt(frameLocationElements[2], 10)];
|
| 27 |
+
let rawFileContents = '';
|
| 28 |
+
try {
|
| 29 |
+
rawFileContents = readFileSync(filename, 'utf-8');
|
| 30 |
+
} catch {
|
| 31 |
+
return '';
|
| 32 |
+
}
|
| 33 |
+
const codeFrame = codeFrameColumns(rawFileContents, {
|
| 34 |
+
start: {
|
| 35 |
+
line,
|
| 36 |
+
column
|
| 37 |
+
}
|
| 38 |
+
}, {
|
| 39 |
+
highlightCode: true,
|
| 40 |
+
linesBelow: 0
|
| 41 |
+
});
|
| 42 |
+
return `${picocolors.dim(frameLocation)}\n${codeFrame}\n`;
|
| 43 |
+
}
|
| 44 |
+
function getUserCodeFrame() {
|
| 45 |
+
// If we couldn't load dependencies, we can't generate the user trace
|
| 46 |
+
/* istanbul ignore next */
|
| 47 |
+
if (!readFileSync || !codeFrameColumns) {
|
| 48 |
+
return '';
|
| 49 |
+
}
|
| 50 |
+
const err = new Error();
|
| 51 |
+
const firstClientCodeFrame = err.stack.split('\n').slice(1) // Remove first line which has the form "Error: TypeError"
|
| 52 |
+
.find(frame => !frame.includes('node_modules/')); // Ignore frames from 3rd party libraries
|
| 53 |
+
|
| 54 |
+
return getCodeFrame(firstClientCodeFrame);
|
| 55 |
+
}
|
node_modules/@testing-library/dom/dist/helpers.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.TEXT_NODE = void 0;
|
| 7 |
+
exports.checkContainerType = checkContainerType;
|
| 8 |
+
exports.getDocument = getDocument;
|
| 9 |
+
exports.getWindowFromNode = getWindowFromNode;
|
| 10 |
+
exports.jestFakeTimersAreEnabled = jestFakeTimersAreEnabled;
|
| 11 |
+
// Constant node.nodeType for text nodes, see:
|
| 12 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants
|
| 13 |
+
const TEXT_NODE = exports.TEXT_NODE = 3;
|
| 14 |
+
function jestFakeTimersAreEnabled() {
|
| 15 |
+
/* istanbul ignore else */
|
| 16 |
+
// eslint-disable-next-line
|
| 17 |
+
if (typeof jest !== 'undefined' && jest !== null) {
|
| 18 |
+
return (
|
| 19 |
+
// legacy timers
|
| 20 |
+
setTimeout._isMockFunction === true ||
|
| 21 |
+
// modern timers
|
| 22 |
+
// eslint-disable-next-line prefer-object-has-own -- not supported by our support matrix
|
| 23 |
+
Object.prototype.hasOwnProperty.call(setTimeout, 'clock')
|
| 24 |
+
);
|
| 25 |
+
}
|
| 26 |
+
// istanbul ignore next
|
| 27 |
+
return false;
|
| 28 |
+
}
|
| 29 |
+
function getDocument() {
|
| 30 |
+
/* istanbul ignore if */
|
| 31 |
+
if (typeof window === 'undefined') {
|
| 32 |
+
throw new Error('Could not find default container');
|
| 33 |
+
}
|
| 34 |
+
return window.document;
|
| 35 |
+
}
|
| 36 |
+
function getWindowFromNode(node) {
|
| 37 |
+
if (node.defaultView) {
|
| 38 |
+
// node is document
|
| 39 |
+
return node.defaultView;
|
| 40 |
+
} else if (node.ownerDocument && node.ownerDocument.defaultView) {
|
| 41 |
+
// node is a DOM node
|
| 42 |
+
return node.ownerDocument.defaultView;
|
| 43 |
+
} else if (node.window) {
|
| 44 |
+
// node is window
|
| 45 |
+
return node.window;
|
| 46 |
+
} else if (node.ownerDocument && node.ownerDocument.defaultView === null) {
|
| 47 |
+
throw new Error(`It looks like the window object is not available for the provided node.`);
|
| 48 |
+
} else if (node.then instanceof Function) {
|
| 49 |
+
throw new Error(`It looks like you passed a Promise object instead of a DOM node. Did you do something like \`fireEvent.click(screen.findBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`, or await the findBy query \`fireEvent.click(await screen.findBy...\`?`);
|
| 50 |
+
} else if (Array.isArray(node)) {
|
| 51 |
+
throw new Error(`It looks like you passed an Array instead of a DOM node. Did you do something like \`fireEvent.click(screen.getAllBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`?`);
|
| 52 |
+
} else if (typeof node.debug === 'function' && typeof node.logTestingPlaygroundURL === 'function') {
|
| 53 |
+
throw new Error(`It looks like you passed a \`screen\` object. Did you do something like \`fireEvent.click(screen, ...\` when you meant to use a query, e.g. \`fireEvent.click(screen.getBy..., \`?`);
|
| 54 |
+
} else {
|
| 55 |
+
// The user passed something unusual to a calling function
|
| 56 |
+
throw new Error(`The given node is not an Element, the node type is: ${typeof node}.`);
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
function checkContainerType(container) {
|
| 60 |
+
if (!container || !(typeof container.querySelector === 'function') || !(typeof container.querySelectorAll === 'function')) {
|
| 61 |
+
throw new TypeError(`Expected container to be an Element, a Document or a DocumentFragment but got ${getTypeName(container)}.`);
|
| 62 |
+
}
|
| 63 |
+
function getTypeName(object) {
|
| 64 |
+
if (typeof object === 'object') {
|
| 65 |
+
return object === null ? 'null' : object.constructor.name;
|
| 66 |
+
}
|
| 67 |
+
return typeof object;
|
| 68 |
+
}
|
| 69 |
+
}
|
node_modules/@testing-library/dom/dist/index.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
var _exportNames = {
|
| 7 |
+
within: true,
|
| 8 |
+
queries: true,
|
| 9 |
+
queryHelpers: true,
|
| 10 |
+
getDefaultNormalizer: true,
|
| 11 |
+
getRoles: true,
|
| 12 |
+
logRoles: true,
|
| 13 |
+
isInaccessible: true,
|
| 14 |
+
configure: true,
|
| 15 |
+
getConfig: true
|
| 16 |
+
};
|
| 17 |
+
Object.defineProperty(exports, "configure", {
|
| 18 |
+
enumerable: true,
|
| 19 |
+
get: function () {
|
| 20 |
+
return _config.configure;
|
| 21 |
+
}
|
| 22 |
+
});
|
| 23 |
+
Object.defineProperty(exports, "getConfig", {
|
| 24 |
+
enumerable: true,
|
| 25 |
+
get: function () {
|
| 26 |
+
return _config.getConfig;
|
| 27 |
+
}
|
| 28 |
+
});
|
| 29 |
+
Object.defineProperty(exports, "getDefaultNormalizer", {
|
| 30 |
+
enumerable: true,
|
| 31 |
+
get: function () {
|
| 32 |
+
return _matches.getDefaultNormalizer;
|
| 33 |
+
}
|
| 34 |
+
});
|
| 35 |
+
Object.defineProperty(exports, "getRoles", {
|
| 36 |
+
enumerable: true,
|
| 37 |
+
get: function () {
|
| 38 |
+
return _roleHelpers.getRoles;
|
| 39 |
+
}
|
| 40 |
+
});
|
| 41 |
+
Object.defineProperty(exports, "isInaccessible", {
|
| 42 |
+
enumerable: true,
|
| 43 |
+
get: function () {
|
| 44 |
+
return _roleHelpers.isInaccessible;
|
| 45 |
+
}
|
| 46 |
+
});
|
| 47 |
+
Object.defineProperty(exports, "logRoles", {
|
| 48 |
+
enumerable: true,
|
| 49 |
+
get: function () {
|
| 50 |
+
return _roleHelpers.logRoles;
|
| 51 |
+
}
|
| 52 |
+
});
|
| 53 |
+
exports.queryHelpers = exports.queries = void 0;
|
| 54 |
+
Object.defineProperty(exports, "within", {
|
| 55 |
+
enumerable: true,
|
| 56 |
+
get: function () {
|
| 57 |
+
return _getQueriesForElement.getQueriesForElement;
|
| 58 |
+
}
|
| 59 |
+
});
|
| 60 |
+
var _getQueriesForElement = require("./get-queries-for-element");
|
| 61 |
+
Object.keys(_getQueriesForElement).forEach(function (key) {
|
| 62 |
+
if (key === "default" || key === "__esModule") return;
|
| 63 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 64 |
+
if (key in exports && exports[key] === _getQueriesForElement[key]) return;
|
| 65 |
+
Object.defineProperty(exports, key, {
|
| 66 |
+
enumerable: true,
|
| 67 |
+
get: function () {
|
| 68 |
+
return _getQueriesForElement[key];
|
| 69 |
+
}
|
| 70 |
+
});
|
| 71 |
+
});
|
| 72 |
+
var queries = _interopRequireWildcard(require("./queries"));
|
| 73 |
+
exports.queries = queries;
|
| 74 |
+
Object.keys(queries).forEach(function (key) {
|
| 75 |
+
if (key === "default" || key === "__esModule") return;
|
| 76 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 77 |
+
if (key in exports && exports[key] === queries[key]) return;
|
| 78 |
+
Object.defineProperty(exports, key, {
|
| 79 |
+
enumerable: true,
|
| 80 |
+
get: function () {
|
| 81 |
+
return queries[key];
|
| 82 |
+
}
|
| 83 |
+
});
|
| 84 |
+
});
|
| 85 |
+
var queryHelpers = _interopRequireWildcard(require("./query-helpers"));
|
| 86 |
+
exports.queryHelpers = queryHelpers;
|
| 87 |
+
Object.keys(queryHelpers).forEach(function (key) {
|
| 88 |
+
if (key === "default" || key === "__esModule") return;
|
| 89 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 90 |
+
if (key in exports && exports[key] === queryHelpers[key]) return;
|
| 91 |
+
Object.defineProperty(exports, key, {
|
| 92 |
+
enumerable: true,
|
| 93 |
+
get: function () {
|
| 94 |
+
return queryHelpers[key];
|
| 95 |
+
}
|
| 96 |
+
});
|
| 97 |
+
});
|
| 98 |
+
var _waitFor = require("./wait-for");
|
| 99 |
+
Object.keys(_waitFor).forEach(function (key) {
|
| 100 |
+
if (key === "default" || key === "__esModule") return;
|
| 101 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 102 |
+
if (key in exports && exports[key] === _waitFor[key]) return;
|
| 103 |
+
Object.defineProperty(exports, key, {
|
| 104 |
+
enumerable: true,
|
| 105 |
+
get: function () {
|
| 106 |
+
return _waitFor[key];
|
| 107 |
+
}
|
| 108 |
+
});
|
| 109 |
+
});
|
| 110 |
+
var _waitForElementToBeRemoved = require("./wait-for-element-to-be-removed");
|
| 111 |
+
Object.keys(_waitForElementToBeRemoved).forEach(function (key) {
|
| 112 |
+
if (key === "default" || key === "__esModule") return;
|
| 113 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 114 |
+
if (key in exports && exports[key] === _waitForElementToBeRemoved[key]) return;
|
| 115 |
+
Object.defineProperty(exports, key, {
|
| 116 |
+
enumerable: true,
|
| 117 |
+
get: function () {
|
| 118 |
+
return _waitForElementToBeRemoved[key];
|
| 119 |
+
}
|
| 120 |
+
});
|
| 121 |
+
});
|
| 122 |
+
var _matches = require("./matches");
|
| 123 |
+
var _getNodeText = require("./get-node-text");
|
| 124 |
+
Object.keys(_getNodeText).forEach(function (key) {
|
| 125 |
+
if (key === "default" || key === "__esModule") return;
|
| 126 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 127 |
+
if (key in exports && exports[key] === _getNodeText[key]) return;
|
| 128 |
+
Object.defineProperty(exports, key, {
|
| 129 |
+
enumerable: true,
|
| 130 |
+
get: function () {
|
| 131 |
+
return _getNodeText[key];
|
| 132 |
+
}
|
| 133 |
+
});
|
| 134 |
+
});
|
| 135 |
+
var _events = require("./events");
|
| 136 |
+
Object.keys(_events).forEach(function (key) {
|
| 137 |
+
if (key === "default" || key === "__esModule") return;
|
| 138 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 139 |
+
if (key in exports && exports[key] === _events[key]) return;
|
| 140 |
+
Object.defineProperty(exports, key, {
|
| 141 |
+
enumerable: true,
|
| 142 |
+
get: function () {
|
| 143 |
+
return _events[key];
|
| 144 |
+
}
|
| 145 |
+
});
|
| 146 |
+
});
|
| 147 |
+
var _screen = require("./screen");
|
| 148 |
+
Object.keys(_screen).forEach(function (key) {
|
| 149 |
+
if (key === "default" || key === "__esModule") return;
|
| 150 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 151 |
+
if (key in exports && exports[key] === _screen[key]) return;
|
| 152 |
+
Object.defineProperty(exports, key, {
|
| 153 |
+
enumerable: true,
|
| 154 |
+
get: function () {
|
| 155 |
+
return _screen[key];
|
| 156 |
+
}
|
| 157 |
+
});
|
| 158 |
+
});
|
| 159 |
+
var _roleHelpers = require("./role-helpers");
|
| 160 |
+
var _prettyDom = require("./pretty-dom");
|
| 161 |
+
Object.keys(_prettyDom).forEach(function (key) {
|
| 162 |
+
if (key === "default" || key === "__esModule") return;
|
| 163 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 164 |
+
if (key in exports && exports[key] === _prettyDom[key]) return;
|
| 165 |
+
Object.defineProperty(exports, key, {
|
| 166 |
+
enumerable: true,
|
| 167 |
+
get: function () {
|
| 168 |
+
return _prettyDom[key];
|
| 169 |
+
}
|
| 170 |
+
});
|
| 171 |
+
});
|
| 172 |
+
var _config = require("./config");
|
| 173 |
+
var _suggestions = require("./suggestions");
|
| 174 |
+
Object.keys(_suggestions).forEach(function (key) {
|
| 175 |
+
if (key === "default" || key === "__esModule") return;
|
| 176 |
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
| 177 |
+
if (key in exports && exports[key] === _suggestions[key]) return;
|
| 178 |
+
Object.defineProperty(exports, key, {
|
| 179 |
+
enumerable: true,
|
| 180 |
+
get: function () {
|
| 181 |
+
return _suggestions[key];
|
| 182 |
+
}
|
| 183 |
+
});
|
| 184 |
+
});
|
| 185 |
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
node_modules/@testing-library/dom/dist/label-helpers.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.getLabelContent = getLabelContent;
|
| 7 |
+
exports.getLabels = getLabels;
|
| 8 |
+
exports.getRealLabels = getRealLabels;
|
| 9 |
+
var _helpers = require("./helpers");
|
| 10 |
+
const labelledNodeNames = ['button', 'meter', 'output', 'progress', 'select', 'textarea', 'input'];
|
| 11 |
+
function getTextContent(node) {
|
| 12 |
+
if (labelledNodeNames.includes(node.nodeName.toLowerCase())) {
|
| 13 |
+
return '';
|
| 14 |
+
}
|
| 15 |
+
if (node.nodeType === _helpers.TEXT_NODE) return node.textContent;
|
| 16 |
+
return Array.from(node.childNodes).map(childNode => getTextContent(childNode)).join('');
|
| 17 |
+
}
|
| 18 |
+
function getLabelContent(element) {
|
| 19 |
+
let textContent;
|
| 20 |
+
if (element.tagName.toLowerCase() === 'label') {
|
| 21 |
+
textContent = getTextContent(element);
|
| 22 |
+
} else {
|
| 23 |
+
textContent = element.value || element.textContent;
|
| 24 |
+
}
|
| 25 |
+
return textContent;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
// Based on https://github.com/eps1lon/dom-accessibility-api/pull/352
|
| 29 |
+
function getRealLabels(element) {
|
| 30 |
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- types are not aware of older browsers that don't implement `labels`
|
| 31 |
+
if (element.labels !== undefined) {
|
| 32 |
+
return element.labels ?? [];
|
| 33 |
+
}
|
| 34 |
+
if (!isLabelable(element)) return [];
|
| 35 |
+
const labels = element.ownerDocument.querySelectorAll('label');
|
| 36 |
+
return Array.from(labels).filter(label => label.control === element);
|
| 37 |
+
}
|
| 38 |
+
function isLabelable(element) {
|
| 39 |
+
return /BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/.test(element.tagName) || element.tagName === 'INPUT' && element.getAttribute('type') !== 'hidden';
|
| 40 |
+
}
|
| 41 |
+
function getLabels(container, element, {
|
| 42 |
+
selector = '*'
|
| 43 |
+
} = {}) {
|
| 44 |
+
const ariaLabelledBy = element.getAttribute('aria-labelledby');
|
| 45 |
+
const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : [];
|
| 46 |
+
return labelsId.length ? labelsId.map(labelId => {
|
| 47 |
+
const labellingElement = container.querySelector(`[id="${labelId}"]`);
|
| 48 |
+
return labellingElement ? {
|
| 49 |
+
content: getLabelContent(labellingElement),
|
| 50 |
+
formControl: null
|
| 51 |
+
} : {
|
| 52 |
+
content: '',
|
| 53 |
+
formControl: null
|
| 54 |
+
};
|
| 55 |
+
}) : Array.from(getRealLabels(element)).map(label => {
|
| 56 |
+
const textToMatch = getLabelContent(label);
|
| 57 |
+
const formControlSelector = 'button, input, meter, output, progress, select, textarea';
|
| 58 |
+
const labelledFormControl = Array.from(label.querySelectorAll(formControlSelector)).filter(formControlElement => formControlElement.matches(selector))[0];
|
| 59 |
+
return {
|
| 60 |
+
content: textToMatch,
|
| 61 |
+
formControl: labelledFormControl
|
| 62 |
+
};
|
| 63 |
+
});
|
| 64 |
+
}
|
node_modules/@testing-library/dom/dist/matches.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.fuzzyMatches = fuzzyMatches;
|
| 7 |
+
exports.getDefaultNormalizer = getDefaultNormalizer;
|
| 8 |
+
exports.makeNormalizer = makeNormalizer;
|
| 9 |
+
exports.matches = matches;
|
| 10 |
+
function assertNotNullOrUndefined(matcher) {
|
| 11 |
+
if (matcher === null || matcher === undefined) {
|
| 12 |
+
throw new Error(
|
| 13 |
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- implicitly converting `T` to `string`
|
| 14 |
+
`It looks like ${matcher} was passed instead of a matcher. Did you do something like getByText(${matcher})?`);
|
| 15 |
+
}
|
| 16 |
+
}
|
| 17 |
+
function fuzzyMatches(textToMatch, node, matcher, normalizer) {
|
| 18 |
+
if (typeof textToMatch !== 'string') {
|
| 19 |
+
return false;
|
| 20 |
+
}
|
| 21 |
+
assertNotNullOrUndefined(matcher);
|
| 22 |
+
const normalizedText = normalizer(textToMatch);
|
| 23 |
+
if (typeof matcher === 'string' || typeof matcher === 'number') {
|
| 24 |
+
return normalizedText.toLowerCase().includes(matcher.toString().toLowerCase());
|
| 25 |
+
} else if (typeof matcher === 'function') {
|
| 26 |
+
return matcher(normalizedText, node);
|
| 27 |
+
} else {
|
| 28 |
+
return matchRegExp(matcher, normalizedText);
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
function matches(textToMatch, node, matcher, normalizer) {
|
| 32 |
+
if (typeof textToMatch !== 'string') {
|
| 33 |
+
return false;
|
| 34 |
+
}
|
| 35 |
+
assertNotNullOrUndefined(matcher);
|
| 36 |
+
const normalizedText = normalizer(textToMatch);
|
| 37 |
+
if (matcher instanceof Function) {
|
| 38 |
+
return matcher(normalizedText, node);
|
| 39 |
+
} else if (matcher instanceof RegExp) {
|
| 40 |
+
return matchRegExp(matcher, normalizedText);
|
| 41 |
+
} else {
|
| 42 |
+
return normalizedText === String(matcher);
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
function getDefaultNormalizer({
|
| 46 |
+
trim = true,
|
| 47 |
+
collapseWhitespace = true
|
| 48 |
+
} = {}) {
|
| 49 |
+
return text => {
|
| 50 |
+
let normalizedText = text;
|
| 51 |
+
normalizedText = trim ? normalizedText.trim() : normalizedText;
|
| 52 |
+
normalizedText = collapseWhitespace ? normalizedText.replace(/\s+/g, ' ') : normalizedText;
|
| 53 |
+
return normalizedText;
|
| 54 |
+
};
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
/**
|
| 58 |
+
* Constructs a normalizer to pass to functions in matches.js
|
| 59 |
+
* @param {boolean|undefined} trim The user-specified value for `trim`, without
|
| 60 |
+
* any defaulting having been applied
|
| 61 |
+
* @param {boolean|undefined} collapseWhitespace The user-specified value for
|
| 62 |
+
* `collapseWhitespace`, without any defaulting having been applied
|
| 63 |
+
* @param {Function|undefined} normalizer The user-specified normalizer
|
| 64 |
+
* @returns {Function} A normalizer
|
| 65 |
+
*/
|
| 66 |
+
|
| 67 |
+
function makeNormalizer({
|
| 68 |
+
trim,
|
| 69 |
+
collapseWhitespace,
|
| 70 |
+
normalizer
|
| 71 |
+
}) {
|
| 72 |
+
if (!normalizer) {
|
| 73 |
+
// No custom normalizer specified. Just use default.
|
| 74 |
+
return getDefaultNormalizer({
|
| 75 |
+
trim,
|
| 76 |
+
collapseWhitespace
|
| 77 |
+
});
|
| 78 |
+
}
|
| 79 |
+
if (typeof trim !== 'undefined' || typeof collapseWhitespace !== 'undefined') {
|
| 80 |
+
// They've also specified a value for trim or collapseWhitespace
|
| 81 |
+
throw new Error('trim and collapseWhitespace are not supported with a normalizer. ' + 'If you want to use the default trim and collapseWhitespace logic in your normalizer, ' + 'use "getDefaultNormalizer({trim, collapseWhitespace})" and compose that into your normalizer');
|
| 82 |
+
}
|
| 83 |
+
return normalizer;
|
| 84 |
+
}
|
| 85 |
+
function matchRegExp(matcher, text) {
|
| 86 |
+
const match = matcher.test(text);
|
| 87 |
+
if (matcher.global && matcher.lastIndex !== 0) {
|
| 88 |
+
console.warn(`To match all elements we had to reset the lastIndex of the RegExp because the global flag is enabled. We encourage to remove the global flag from the RegExp.`);
|
| 89 |
+
matcher.lastIndex = 0;
|
| 90 |
+
}
|
| 91 |
+
return match;
|
| 92 |
+
}
|
node_modules/@testing-library/dom/dist/pretty-dom.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
| 4 |
+
Object.defineProperty(exports, "__esModule", {
|
| 5 |
+
value: true
|
| 6 |
+
});
|
| 7 |
+
exports.logDOM = void 0;
|
| 8 |
+
exports.prettyDOM = prettyDOM;
|
| 9 |
+
exports.prettyFormat = void 0;
|
| 10 |
+
var prettyFormat = _interopRequireWildcard(require("pretty-format"));
|
| 11 |
+
exports.prettyFormat = prettyFormat;
|
| 12 |
+
var _DOMElementFilter = _interopRequireDefault(require("./DOMElementFilter"));
|
| 13 |
+
var _getUserCodeFrame = require("./get-user-code-frame");
|
| 14 |
+
var _helpers = require("./helpers");
|
| 15 |
+
var _config = require("./config");
|
| 16 |
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
| 17 |
+
const shouldHighlight = () => {
|
| 18 |
+
if (typeof process === 'undefined') {
|
| 19 |
+
// Don't colorize in non-node environments (e.g. Browsers)
|
| 20 |
+
return false;
|
| 21 |
+
}
|
| 22 |
+
let colors;
|
| 23 |
+
// Try to safely parse env COLORS: We will default behavior if any step fails.
|
| 24 |
+
try {
|
| 25 |
+
const colorsJSON = process.env?.COLORS;
|
| 26 |
+
if (colorsJSON) {
|
| 27 |
+
colors = JSON.parse(colorsJSON);
|
| 28 |
+
}
|
| 29 |
+
} catch {
|
| 30 |
+
// If this throws, process.env?.COLORS wasn't parsable. Since we only
|
| 31 |
+
// care about `true` or `false`, we can safely ignore the error.
|
| 32 |
+
}
|
| 33 |
+
if (typeof colors === 'boolean') {
|
| 34 |
+
// If `colors` is set explicitly (both `true` and `false`), use that value.
|
| 35 |
+
return colors;
|
| 36 |
+
} else {
|
| 37 |
+
// If `colors` is not set, colorize if we're in node.
|
| 38 |
+
return process.versions !== undefined && process.versions.node !== undefined;
|
| 39 |
+
}
|
| 40 |
+
};
|
| 41 |
+
const {
|
| 42 |
+
DOMCollection
|
| 43 |
+
} = prettyFormat.plugins;
|
| 44 |
+
|
| 45 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node_type_constants
|
| 46 |
+
const ELEMENT_NODE = 1;
|
| 47 |
+
const COMMENT_NODE = 8;
|
| 48 |
+
|
| 49 |
+
// https://github.com/facebook/jest/blob/615084195ae1ae61ddd56162c62bbdda17587569/packages/pretty-format/src/plugins/DOMElement.ts#L50
|
| 50 |
+
function filterCommentsAndDefaultIgnoreTagsTags(value) {
|
| 51 |
+
return value.nodeType !== COMMENT_NODE && (value.nodeType !== ELEMENT_NODE || !value.matches((0, _config.getConfig)().defaultIgnore));
|
| 52 |
+
}
|
| 53 |
+
function prettyDOM(dom, maxLength, options = {}) {
|
| 54 |
+
if (!dom) {
|
| 55 |
+
dom = (0, _helpers.getDocument)().body;
|
| 56 |
+
}
|
| 57 |
+
if (typeof maxLength !== 'number') {
|
| 58 |
+
maxLength = typeof process !== 'undefined' && typeof process.env !== 'undefined' && process.env.DEBUG_PRINT_LIMIT || 7000;
|
| 59 |
+
}
|
| 60 |
+
if (maxLength === 0) {
|
| 61 |
+
return '';
|
| 62 |
+
}
|
| 63 |
+
if (dom.documentElement) {
|
| 64 |
+
dom = dom.documentElement;
|
| 65 |
+
}
|
| 66 |
+
let domTypeName = typeof dom;
|
| 67 |
+
if (domTypeName === 'object') {
|
| 68 |
+
domTypeName = dom.constructor.name;
|
| 69 |
+
} else {
|
| 70 |
+
// To don't fall with `in` operator
|
| 71 |
+
dom = {};
|
| 72 |
+
}
|
| 73 |
+
if (!('outerHTML' in dom)) {
|
| 74 |
+
throw new TypeError(`Expected an element or document but got ${domTypeName}`);
|
| 75 |
+
}
|
| 76 |
+
const {
|
| 77 |
+
filterNode = filterCommentsAndDefaultIgnoreTagsTags,
|
| 78 |
+
...prettyFormatOptions
|
| 79 |
+
} = options;
|
| 80 |
+
const debugContent = prettyFormat.format(dom, {
|
| 81 |
+
plugins: [(0, _DOMElementFilter.default)(filterNode), DOMCollection],
|
| 82 |
+
printFunctionName: false,
|
| 83 |
+
highlight: shouldHighlight(),
|
| 84 |
+
...prettyFormatOptions
|
| 85 |
+
});
|
| 86 |
+
return maxLength !== undefined && dom.outerHTML.length > maxLength ? `${debugContent.slice(0, maxLength)}...` : debugContent;
|
| 87 |
+
}
|
| 88 |
+
const logDOM = (...args) => {
|
| 89 |
+
const userCodeFrame = (0, _getUserCodeFrame.getUserCodeFrame)();
|
| 90 |
+
if (userCodeFrame) {
|
| 91 |
+
console.log(`${prettyDOM(...args)}\n\n${userCodeFrame}`);
|
| 92 |
+
} else {
|
| 93 |
+
console.log(prettyDOM(...args));
|
| 94 |
+
}
|
| 95 |
+
};
|
| 96 |
+
exports.logDOM = logDOM;
|
node_modules/@testing-library/dom/dist/queries/all-utils.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
var _matches = require("../matches");
|
| 7 |
+
Object.keys(_matches).forEach(function (key) {
|
| 8 |
+
if (key === "default" || key === "__esModule") return;
|
| 9 |
+
if (key in exports && exports[key] === _matches[key]) return;
|
| 10 |
+
Object.defineProperty(exports, key, {
|
| 11 |
+
enumerable: true,
|
| 12 |
+
get: function () {
|
| 13 |
+
return _matches[key];
|
| 14 |
+
}
|
| 15 |
+
});
|
| 16 |
+
});
|
| 17 |
+
var _getNodeText = require("../get-node-text");
|
| 18 |
+
Object.keys(_getNodeText).forEach(function (key) {
|
| 19 |
+
if (key === "default" || key === "__esModule") return;
|
| 20 |
+
if (key in exports && exports[key] === _getNodeText[key]) return;
|
| 21 |
+
Object.defineProperty(exports, key, {
|
| 22 |
+
enumerable: true,
|
| 23 |
+
get: function () {
|
| 24 |
+
return _getNodeText[key];
|
| 25 |
+
}
|
| 26 |
+
});
|
| 27 |
+
});
|
| 28 |
+
var _queryHelpers = require("../query-helpers");
|
| 29 |
+
Object.keys(_queryHelpers).forEach(function (key) {
|
| 30 |
+
if (key === "default" || key === "__esModule") return;
|
| 31 |
+
if (key in exports && exports[key] === _queryHelpers[key]) return;
|
| 32 |
+
Object.defineProperty(exports, key, {
|
| 33 |
+
enumerable: true,
|
| 34 |
+
get: function () {
|
| 35 |
+
return _queryHelpers[key];
|
| 36 |
+
}
|
| 37 |
+
});
|
| 38 |
+
});
|
| 39 |
+
var _config = require("../config");
|
| 40 |
+
Object.keys(_config).forEach(function (key) {
|
| 41 |
+
if (key === "default" || key === "__esModule") return;
|
| 42 |
+
if (key in exports && exports[key] === _config[key]) return;
|
| 43 |
+
Object.defineProperty(exports, key, {
|
| 44 |
+
enumerable: true,
|
| 45 |
+
get: function () {
|
| 46 |
+
return _config[key];
|
| 47 |
+
}
|
| 48 |
+
});
|
| 49 |
+
});
|
node_modules/@testing-library/dom/dist/queries/alt-text.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByAltText = exports.queryAllByAltText = exports.getByAltText = exports.getAllByAltText = exports.findByAltText = exports.findAllByAltText = void 0;
|
| 7 |
+
var _queryHelpers = require("../query-helpers");
|
| 8 |
+
var _helpers = require("../helpers");
|
| 9 |
+
var _allUtils = require("./all-utils");
|
| 10 |
+
// Valid tags are img, input, area and custom elements
|
| 11 |
+
const VALID_TAG_REGEXP = /^(img|input|area|.+-.+)$/i;
|
| 12 |
+
const queryAllByAltText = (container, alt, options = {}) => {
|
| 13 |
+
(0, _helpers.checkContainerType)(container);
|
| 14 |
+
return (0, _queryHelpers.queryAllByAttribute)('alt', container, alt, options).filter(node => VALID_TAG_REGEXP.test(node.tagName));
|
| 15 |
+
};
|
| 16 |
+
const getMultipleError = (c, alt) => `Found multiple elements with the alt text: ${alt}`;
|
| 17 |
+
const getMissingError = (c, alt) => `Unable to find an element with the alt text: ${alt}`;
|
| 18 |
+
const queryAllByAltTextWithSuggestions = exports.queryAllByAltText = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByAltText, queryAllByAltText.name, 'queryAll');
|
| 19 |
+
const [queryByAltText, getAllByAltText, getByAltText, findAllByAltText, findByAltText] = (0, _allUtils.buildQueries)(queryAllByAltText, getMultipleError, getMissingError);
|
| 20 |
+
exports.findByAltText = findByAltText;
|
| 21 |
+
exports.findAllByAltText = findAllByAltText;
|
| 22 |
+
exports.getByAltText = getByAltText;
|
| 23 |
+
exports.getAllByAltText = getAllByAltText;
|
| 24 |
+
exports.queryByAltText = queryByAltText;
|
node_modules/@testing-library/dom/dist/queries/display-value.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByDisplayValue = exports.queryAllByDisplayValue = exports.getByDisplayValue = exports.getAllByDisplayValue = exports.findByDisplayValue = exports.findAllByDisplayValue = void 0;
|
| 7 |
+
var _queryHelpers = require("../query-helpers");
|
| 8 |
+
var _helpers = require("../helpers");
|
| 9 |
+
var _allUtils = require("./all-utils");
|
| 10 |
+
const queryAllByDisplayValue = (container, value, {
|
| 11 |
+
exact = true,
|
| 12 |
+
collapseWhitespace,
|
| 13 |
+
trim,
|
| 14 |
+
normalizer
|
| 15 |
+
} = {}) => {
|
| 16 |
+
(0, _helpers.checkContainerType)(container);
|
| 17 |
+
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches;
|
| 18 |
+
const matchNormalizer = (0, _allUtils.makeNormalizer)({
|
| 19 |
+
collapseWhitespace,
|
| 20 |
+
trim,
|
| 21 |
+
normalizer
|
| 22 |
+
});
|
| 23 |
+
return Array.from(container.querySelectorAll(`input,textarea,select`)).filter(node => {
|
| 24 |
+
if (node.tagName === 'SELECT') {
|
| 25 |
+
const selectedOptions = Array.from(node.options).filter(option => option.selected);
|
| 26 |
+
return selectedOptions.some(optionNode => matcher((0, _allUtils.getNodeText)(optionNode), optionNode, value, matchNormalizer));
|
| 27 |
+
} else {
|
| 28 |
+
return matcher(node.value, node, value, matchNormalizer);
|
| 29 |
+
}
|
| 30 |
+
});
|
| 31 |
+
};
|
| 32 |
+
const getMultipleError = (c, value) => `Found multiple elements with the display value: ${value}.`;
|
| 33 |
+
const getMissingError = (c, value) => `Unable to find an element with the display value: ${value}.`;
|
| 34 |
+
const queryAllByDisplayValueWithSuggestions = exports.queryAllByDisplayValue = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByDisplayValue, queryAllByDisplayValue.name, 'queryAll');
|
| 35 |
+
const [queryByDisplayValue, getAllByDisplayValue, getByDisplayValue, findAllByDisplayValue, findByDisplayValue] = (0, _allUtils.buildQueries)(queryAllByDisplayValue, getMultipleError, getMissingError);
|
| 36 |
+
exports.findByDisplayValue = findByDisplayValue;
|
| 37 |
+
exports.findAllByDisplayValue = findAllByDisplayValue;
|
| 38 |
+
exports.getByDisplayValue = getByDisplayValue;
|
| 39 |
+
exports.getAllByDisplayValue = getAllByDisplayValue;
|
| 40 |
+
exports.queryByDisplayValue = queryByDisplayValue;
|
node_modules/@testing-library/dom/dist/queries/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
var _labelText = require("./label-text");
|
| 7 |
+
Object.keys(_labelText).forEach(function (key) {
|
| 8 |
+
if (key === "default" || key === "__esModule") return;
|
| 9 |
+
if (key in exports && exports[key] === _labelText[key]) return;
|
| 10 |
+
Object.defineProperty(exports, key, {
|
| 11 |
+
enumerable: true,
|
| 12 |
+
get: function () {
|
| 13 |
+
return _labelText[key];
|
| 14 |
+
}
|
| 15 |
+
});
|
| 16 |
+
});
|
| 17 |
+
var _placeholderText = require("./placeholder-text");
|
| 18 |
+
Object.keys(_placeholderText).forEach(function (key) {
|
| 19 |
+
if (key === "default" || key === "__esModule") return;
|
| 20 |
+
if (key in exports && exports[key] === _placeholderText[key]) return;
|
| 21 |
+
Object.defineProperty(exports, key, {
|
| 22 |
+
enumerable: true,
|
| 23 |
+
get: function () {
|
| 24 |
+
return _placeholderText[key];
|
| 25 |
+
}
|
| 26 |
+
});
|
| 27 |
+
});
|
| 28 |
+
var _text = require("./text");
|
| 29 |
+
Object.keys(_text).forEach(function (key) {
|
| 30 |
+
if (key === "default" || key === "__esModule") return;
|
| 31 |
+
if (key in exports && exports[key] === _text[key]) return;
|
| 32 |
+
Object.defineProperty(exports, key, {
|
| 33 |
+
enumerable: true,
|
| 34 |
+
get: function () {
|
| 35 |
+
return _text[key];
|
| 36 |
+
}
|
| 37 |
+
});
|
| 38 |
+
});
|
| 39 |
+
var _displayValue = require("./display-value");
|
| 40 |
+
Object.keys(_displayValue).forEach(function (key) {
|
| 41 |
+
if (key === "default" || key === "__esModule") return;
|
| 42 |
+
if (key in exports && exports[key] === _displayValue[key]) return;
|
| 43 |
+
Object.defineProperty(exports, key, {
|
| 44 |
+
enumerable: true,
|
| 45 |
+
get: function () {
|
| 46 |
+
return _displayValue[key];
|
| 47 |
+
}
|
| 48 |
+
});
|
| 49 |
+
});
|
| 50 |
+
var _altText = require("./alt-text");
|
| 51 |
+
Object.keys(_altText).forEach(function (key) {
|
| 52 |
+
if (key === "default" || key === "__esModule") return;
|
| 53 |
+
if (key in exports && exports[key] === _altText[key]) return;
|
| 54 |
+
Object.defineProperty(exports, key, {
|
| 55 |
+
enumerable: true,
|
| 56 |
+
get: function () {
|
| 57 |
+
return _altText[key];
|
| 58 |
+
}
|
| 59 |
+
});
|
| 60 |
+
});
|
| 61 |
+
var _title = require("./title");
|
| 62 |
+
Object.keys(_title).forEach(function (key) {
|
| 63 |
+
if (key === "default" || key === "__esModule") return;
|
| 64 |
+
if (key in exports && exports[key] === _title[key]) return;
|
| 65 |
+
Object.defineProperty(exports, key, {
|
| 66 |
+
enumerable: true,
|
| 67 |
+
get: function () {
|
| 68 |
+
return _title[key];
|
| 69 |
+
}
|
| 70 |
+
});
|
| 71 |
+
});
|
| 72 |
+
var _role = require("./role");
|
| 73 |
+
Object.keys(_role).forEach(function (key) {
|
| 74 |
+
if (key === "default" || key === "__esModule") return;
|
| 75 |
+
if (key in exports && exports[key] === _role[key]) return;
|
| 76 |
+
Object.defineProperty(exports, key, {
|
| 77 |
+
enumerable: true,
|
| 78 |
+
get: function () {
|
| 79 |
+
return _role[key];
|
| 80 |
+
}
|
| 81 |
+
});
|
| 82 |
+
});
|
| 83 |
+
var _testId = require("./test-id");
|
| 84 |
+
Object.keys(_testId).forEach(function (key) {
|
| 85 |
+
if (key === "default" || key === "__esModule") return;
|
| 86 |
+
if (key in exports && exports[key] === _testId[key]) return;
|
| 87 |
+
Object.defineProperty(exports, key, {
|
| 88 |
+
enumerable: true,
|
| 89 |
+
get: function () {
|
| 90 |
+
return _testId[key];
|
| 91 |
+
}
|
| 92 |
+
});
|
| 93 |
+
});
|
node_modules/@testing-library/dom/dist/queries/label-text.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByLabelText = exports.queryAllByLabelText = exports.getByLabelText = exports.getAllByLabelText = exports.findByLabelText = exports.findAllByLabelText = void 0;
|
| 7 |
+
var _config = require("../config");
|
| 8 |
+
var _helpers = require("../helpers");
|
| 9 |
+
var _labelHelpers = require("../label-helpers");
|
| 10 |
+
var _allUtils = require("./all-utils");
|
| 11 |
+
function queryAllLabels(container) {
|
| 12 |
+
return Array.from(container.querySelectorAll('label,input')).map(node => {
|
| 13 |
+
return {
|
| 14 |
+
node,
|
| 15 |
+
textToMatch: (0, _labelHelpers.getLabelContent)(node)
|
| 16 |
+
};
|
| 17 |
+
}).filter(({
|
| 18 |
+
textToMatch
|
| 19 |
+
}) => textToMatch !== null);
|
| 20 |
+
}
|
| 21 |
+
const queryAllLabelsByText = (container, text, {
|
| 22 |
+
exact = true,
|
| 23 |
+
trim,
|
| 24 |
+
collapseWhitespace,
|
| 25 |
+
normalizer
|
| 26 |
+
} = {}) => {
|
| 27 |
+
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches;
|
| 28 |
+
const matchNormalizer = (0, _allUtils.makeNormalizer)({
|
| 29 |
+
collapseWhitespace,
|
| 30 |
+
trim,
|
| 31 |
+
normalizer
|
| 32 |
+
});
|
| 33 |
+
const textToMatchByLabels = queryAllLabels(container);
|
| 34 |
+
return textToMatchByLabels.filter(({
|
| 35 |
+
node,
|
| 36 |
+
textToMatch
|
| 37 |
+
}) => matcher(textToMatch, node, text, matchNormalizer)).map(({
|
| 38 |
+
node
|
| 39 |
+
}) => node);
|
| 40 |
+
};
|
| 41 |
+
const queryAllByLabelText = (container, text, {
|
| 42 |
+
selector = '*',
|
| 43 |
+
exact = true,
|
| 44 |
+
collapseWhitespace,
|
| 45 |
+
trim,
|
| 46 |
+
normalizer
|
| 47 |
+
} = {}) => {
|
| 48 |
+
(0, _helpers.checkContainerType)(container);
|
| 49 |
+
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches;
|
| 50 |
+
const matchNormalizer = (0, _allUtils.makeNormalizer)({
|
| 51 |
+
collapseWhitespace,
|
| 52 |
+
trim,
|
| 53 |
+
normalizer
|
| 54 |
+
});
|
| 55 |
+
const matchingLabelledElements = Array.from(container.querySelectorAll('*')).filter(element => {
|
| 56 |
+
return (0, _labelHelpers.getRealLabels)(element).length || element.hasAttribute('aria-labelledby');
|
| 57 |
+
}).reduce((labelledElements, labelledElement) => {
|
| 58 |
+
const labelList = (0, _labelHelpers.getLabels)(container, labelledElement, {
|
| 59 |
+
selector
|
| 60 |
+
});
|
| 61 |
+
labelList.filter(label => Boolean(label.formControl)).forEach(label => {
|
| 62 |
+
if (matcher(label.content, label.formControl, text, matchNormalizer) && label.formControl) {
|
| 63 |
+
labelledElements.push(label.formControl);
|
| 64 |
+
}
|
| 65 |
+
});
|
| 66 |
+
const labelsValue = labelList.filter(label => Boolean(label.content)).map(label => label.content);
|
| 67 |
+
if (matcher(labelsValue.join(' '), labelledElement, text, matchNormalizer)) {
|
| 68 |
+
labelledElements.push(labelledElement);
|
| 69 |
+
}
|
| 70 |
+
if (labelsValue.length > 1) {
|
| 71 |
+
labelsValue.forEach((labelValue, index) => {
|
| 72 |
+
if (matcher(labelValue, labelledElement, text, matchNormalizer)) {
|
| 73 |
+
labelledElements.push(labelledElement);
|
| 74 |
+
}
|
| 75 |
+
const labelsFiltered = [...labelsValue];
|
| 76 |
+
labelsFiltered.splice(index, 1);
|
| 77 |
+
if (labelsFiltered.length > 1) {
|
| 78 |
+
if (matcher(labelsFiltered.join(' '), labelledElement, text, matchNormalizer)) {
|
| 79 |
+
labelledElements.push(labelledElement);
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
});
|
| 83 |
+
}
|
| 84 |
+
return labelledElements;
|
| 85 |
+
}, []).concat((0, _allUtils.queryAllByAttribute)('aria-label', container, text, {
|
| 86 |
+
exact,
|
| 87 |
+
normalizer: matchNormalizer
|
| 88 |
+
}));
|
| 89 |
+
return Array.from(new Set(matchingLabelledElements)).filter(element => element.matches(selector));
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
// the getAll* query would normally look like this:
|
| 93 |
+
// const getAllByLabelText = makeGetAllQuery(
|
| 94 |
+
// queryAllByLabelText,
|
| 95 |
+
// (c, text) => `Unable to find a label with the text of: ${text}`,
|
| 96 |
+
// )
|
| 97 |
+
// however, we can give a more helpful error message than the generic one,
|
| 98 |
+
// so we're writing this one out by hand.
|
| 99 |
+
const getAllByLabelText = (container, text, ...rest) => {
|
| 100 |
+
const els = queryAllByLabelText(container, text, ...rest);
|
| 101 |
+
if (!els.length) {
|
| 102 |
+
const labels = queryAllLabelsByText(container, text, ...rest);
|
| 103 |
+
if (labels.length) {
|
| 104 |
+
const tagNames = labels.map(label => getTagNameOfElementAssociatedWithLabelViaFor(container, label)).filter(tagName => !!tagName);
|
| 105 |
+
if (tagNames.length) {
|
| 106 |
+
throw (0, _config.getConfig)().getElementError(tagNames.map(tagName => `Found a label with the text of: ${text}, however the element associated with this label (<${tagName} />) is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a <${tagName} />, you can use aria-label or aria-labelledby instead.`).join('\n\n'), container);
|
| 107 |
+
} else {
|
| 108 |
+
throw (0, _config.getConfig)().getElementError(`Found a label with the text of: ${text}, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.`, container);
|
| 109 |
+
}
|
| 110 |
+
} else {
|
| 111 |
+
throw (0, _config.getConfig)().getElementError(`Unable to find a label with the text of: ${text}`, container);
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
return els;
|
| 115 |
+
};
|
| 116 |
+
function getTagNameOfElementAssociatedWithLabelViaFor(container, label) {
|
| 117 |
+
const htmlFor = label.getAttribute('for');
|
| 118 |
+
if (!htmlFor) {
|
| 119 |
+
return null;
|
| 120 |
+
}
|
| 121 |
+
const element = container.querySelector(`[id="${htmlFor}"]`);
|
| 122 |
+
return element ? element.tagName.toLowerCase() : null;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
// the reason mentioned above is the same reason we're not using buildQueries
|
| 126 |
+
const getMultipleError = (c, text) => `Found multiple elements with the text of: ${text}`;
|
| 127 |
+
const queryByLabelText = exports.queryByLabelText = (0, _allUtils.wrapSingleQueryWithSuggestion)((0, _allUtils.makeSingleQuery)(queryAllByLabelText, getMultipleError), queryAllByLabelText.name, 'query');
|
| 128 |
+
const getByLabelText = (0, _allUtils.makeSingleQuery)(getAllByLabelText, getMultipleError);
|
| 129 |
+
const findAllByLabelText = exports.findAllByLabelText = (0, _allUtils.makeFindQuery)((0, _allUtils.wrapAllByQueryWithSuggestion)(getAllByLabelText, getAllByLabelText.name, 'findAll'));
|
| 130 |
+
const findByLabelText = exports.findByLabelText = (0, _allUtils.makeFindQuery)((0, _allUtils.wrapSingleQueryWithSuggestion)(getByLabelText, getAllByLabelText.name, 'find'));
|
| 131 |
+
const getAllByLabelTextWithSuggestions = exports.getAllByLabelText = (0, _allUtils.wrapAllByQueryWithSuggestion)(getAllByLabelText, getAllByLabelText.name, 'getAll');
|
| 132 |
+
const getByLabelTextWithSuggestions = exports.getByLabelText = (0, _allUtils.wrapSingleQueryWithSuggestion)(getByLabelText, getAllByLabelText.name, 'get');
|
| 133 |
+
const queryAllByLabelTextWithSuggestions = exports.queryAllByLabelText = (0, _allUtils.wrapAllByQueryWithSuggestion)(queryAllByLabelText, queryAllByLabelText.name, 'queryAll');
|
node_modules/@testing-library/dom/dist/queries/placeholder-text.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByPlaceholderText = exports.queryAllByPlaceholderText = exports.getByPlaceholderText = exports.getAllByPlaceholderText = exports.findByPlaceholderText = exports.findAllByPlaceholderText = void 0;
|
| 7 |
+
var _queryHelpers = require("../query-helpers");
|
| 8 |
+
var _helpers = require("../helpers");
|
| 9 |
+
var _allUtils = require("./all-utils");
|
| 10 |
+
const queryAllByPlaceholderText = (...args) => {
|
| 11 |
+
(0, _helpers.checkContainerType)(args[0]);
|
| 12 |
+
return (0, _allUtils.queryAllByAttribute)('placeholder', ...args);
|
| 13 |
+
};
|
| 14 |
+
const getMultipleError = (c, text) => `Found multiple elements with the placeholder text of: ${text}`;
|
| 15 |
+
const getMissingError = (c, text) => `Unable to find an element with the placeholder text of: ${text}`;
|
| 16 |
+
const queryAllByPlaceholderTextWithSuggestions = exports.queryAllByPlaceholderText = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByPlaceholderText, queryAllByPlaceholderText.name, 'queryAll');
|
| 17 |
+
const [queryByPlaceholderText, getAllByPlaceholderText, getByPlaceholderText, findAllByPlaceholderText, findByPlaceholderText] = (0, _allUtils.buildQueries)(queryAllByPlaceholderText, getMultipleError, getMissingError);
|
| 18 |
+
exports.findByPlaceholderText = findByPlaceholderText;
|
| 19 |
+
exports.findAllByPlaceholderText = findAllByPlaceholderText;
|
| 20 |
+
exports.getByPlaceholderText = getByPlaceholderText;
|
| 21 |
+
exports.getAllByPlaceholderText = getAllByPlaceholderText;
|
| 22 |
+
exports.queryByPlaceholderText = queryByPlaceholderText;
|
node_modules/@testing-library/dom/dist/queries/role.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByRole = exports.queryAllByRole = exports.getByRole = exports.getAllByRole = exports.findByRole = exports.findAllByRole = void 0;
|
| 7 |
+
var _domAccessibilityApi = require("dom-accessibility-api");
|
| 8 |
+
var _ariaQuery = require("aria-query");
|
| 9 |
+
var _roleHelpers = require("../role-helpers");
|
| 10 |
+
var _queryHelpers = require("../query-helpers");
|
| 11 |
+
var _helpers = require("../helpers");
|
| 12 |
+
var _allUtils = require("./all-utils");
|
| 13 |
+
/* eslint-disable complexity */
|
| 14 |
+
|
| 15 |
+
const queryAllByRole = (container, role, {
|
| 16 |
+
hidden = (0, _allUtils.getConfig)().defaultHidden,
|
| 17 |
+
name,
|
| 18 |
+
description,
|
| 19 |
+
queryFallbacks = false,
|
| 20 |
+
selected,
|
| 21 |
+
busy,
|
| 22 |
+
checked,
|
| 23 |
+
pressed,
|
| 24 |
+
current,
|
| 25 |
+
level,
|
| 26 |
+
expanded,
|
| 27 |
+
value: {
|
| 28 |
+
now: valueNow,
|
| 29 |
+
min: valueMin,
|
| 30 |
+
max: valueMax,
|
| 31 |
+
text: valueText
|
| 32 |
+
} = {}
|
| 33 |
+
} = {}) => {
|
| 34 |
+
(0, _helpers.checkContainerType)(container);
|
| 35 |
+
if (selected !== undefined) {
|
| 36 |
+
// guard against unknown roles
|
| 37 |
+
if (_ariaQuery.roles.get(role)?.props['aria-selected'] === undefined) {
|
| 38 |
+
throw new Error(`"aria-selected" is not supported on role "${role}".`);
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
if (busy !== undefined) {
|
| 42 |
+
// guard against unknown roles
|
| 43 |
+
if (_ariaQuery.roles.get(role)?.props['aria-busy'] === undefined) {
|
| 44 |
+
throw new Error(`"aria-busy" is not supported on role "${role}".`);
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
+
if (checked !== undefined) {
|
| 48 |
+
// guard against unknown roles
|
| 49 |
+
if (_ariaQuery.roles.get(role)?.props['aria-checked'] === undefined) {
|
| 50 |
+
throw new Error(`"aria-checked" is not supported on role "${role}".`);
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
if (pressed !== undefined) {
|
| 54 |
+
// guard against unknown roles
|
| 55 |
+
if (_ariaQuery.roles.get(role)?.props['aria-pressed'] === undefined) {
|
| 56 |
+
throw new Error(`"aria-pressed" is not supported on role "${role}".`);
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
if (current !== undefined) {
|
| 60 |
+
/* istanbul ignore next */
|
| 61 |
+
// guard against unknown roles
|
| 62 |
+
// All currently released ARIA versions support `aria-current` on all roles.
|
| 63 |
+
// Leaving this for symmetry and forward compatibility
|
| 64 |
+
if (_ariaQuery.roles.get(role)?.props['aria-current'] === undefined) {
|
| 65 |
+
throw new Error(`"aria-current" is not supported on role "${role}".`);
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
if (level !== undefined) {
|
| 69 |
+
// guard against using `level` option with any role other than `heading`
|
| 70 |
+
if (role !== 'heading') {
|
| 71 |
+
throw new Error(`Role "${role}" cannot have "level" property.`);
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
+
if (valueNow !== undefined) {
|
| 75 |
+
// guard against unknown roles
|
| 76 |
+
if (_ariaQuery.roles.get(role)?.props['aria-valuenow'] === undefined) {
|
| 77 |
+
throw new Error(`"aria-valuenow" is not supported on role "${role}".`);
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
if (valueMax !== undefined) {
|
| 81 |
+
// guard against unknown roles
|
| 82 |
+
if (_ariaQuery.roles.get(role)?.props['aria-valuemax'] === undefined) {
|
| 83 |
+
throw new Error(`"aria-valuemax" is not supported on role "${role}".`);
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
if (valueMin !== undefined) {
|
| 87 |
+
// guard against unknown roles
|
| 88 |
+
if (_ariaQuery.roles.get(role)?.props['aria-valuemin'] === undefined) {
|
| 89 |
+
throw new Error(`"aria-valuemin" is not supported on role "${role}".`);
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
if (valueText !== undefined) {
|
| 93 |
+
// guard against unknown roles
|
| 94 |
+
if (_ariaQuery.roles.get(role)?.props['aria-valuetext'] === undefined) {
|
| 95 |
+
throw new Error(`"aria-valuetext" is not supported on role "${role}".`);
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
if (expanded !== undefined) {
|
| 99 |
+
// guard against unknown roles
|
| 100 |
+
if (_ariaQuery.roles.get(role)?.props['aria-expanded'] === undefined) {
|
| 101 |
+
throw new Error(`"aria-expanded" is not supported on role "${role}".`);
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
const subtreeIsInaccessibleCache = new WeakMap();
|
| 105 |
+
function cachedIsSubtreeInaccessible(element) {
|
| 106 |
+
if (!subtreeIsInaccessibleCache.has(element)) {
|
| 107 |
+
subtreeIsInaccessibleCache.set(element, (0, _roleHelpers.isSubtreeInaccessible)(element));
|
| 108 |
+
}
|
| 109 |
+
return subtreeIsInaccessibleCache.get(element);
|
| 110 |
+
}
|
| 111 |
+
return Array.from(container.querySelectorAll(
|
| 112 |
+
// Only query elements that can be matched by the following filters
|
| 113 |
+
makeRoleSelector(role))).filter(node => {
|
| 114 |
+
const isRoleSpecifiedExplicitly = node.hasAttribute('role');
|
| 115 |
+
if (isRoleSpecifiedExplicitly) {
|
| 116 |
+
const roleValue = node.getAttribute('role');
|
| 117 |
+
if (queryFallbacks) {
|
| 118 |
+
return roleValue.split(' ').filter(Boolean).some(roleAttributeToken => roleAttributeToken === role);
|
| 119 |
+
}
|
| 120 |
+
// other wise only send the first token to match
|
| 121 |
+
const [firstRoleAttributeToken] = roleValue.split(' ');
|
| 122 |
+
return firstRoleAttributeToken === role;
|
| 123 |
+
}
|
| 124 |
+
const implicitRoles = (0, _roleHelpers.getImplicitAriaRoles)(node);
|
| 125 |
+
return implicitRoles.some(implicitRole => {
|
| 126 |
+
return implicitRole === role;
|
| 127 |
+
});
|
| 128 |
+
}).filter(element => {
|
| 129 |
+
if (selected !== undefined) {
|
| 130 |
+
return selected === (0, _roleHelpers.computeAriaSelected)(element);
|
| 131 |
+
}
|
| 132 |
+
if (busy !== undefined) {
|
| 133 |
+
return busy === (0, _roleHelpers.computeAriaBusy)(element);
|
| 134 |
+
}
|
| 135 |
+
if (checked !== undefined) {
|
| 136 |
+
return checked === (0, _roleHelpers.computeAriaChecked)(element);
|
| 137 |
+
}
|
| 138 |
+
if (pressed !== undefined) {
|
| 139 |
+
return pressed === (0, _roleHelpers.computeAriaPressed)(element);
|
| 140 |
+
}
|
| 141 |
+
if (current !== undefined) {
|
| 142 |
+
return current === (0, _roleHelpers.computeAriaCurrent)(element);
|
| 143 |
+
}
|
| 144 |
+
if (expanded !== undefined) {
|
| 145 |
+
return expanded === (0, _roleHelpers.computeAriaExpanded)(element);
|
| 146 |
+
}
|
| 147 |
+
if (level !== undefined) {
|
| 148 |
+
return level === (0, _roleHelpers.computeHeadingLevel)(element);
|
| 149 |
+
}
|
| 150 |
+
if (valueNow !== undefined || valueMax !== undefined || valueMin !== undefined || valueText !== undefined) {
|
| 151 |
+
let valueMatches = true;
|
| 152 |
+
if (valueNow !== undefined) {
|
| 153 |
+
valueMatches &&= valueNow === (0, _roleHelpers.computeAriaValueNow)(element);
|
| 154 |
+
}
|
| 155 |
+
if (valueMax !== undefined) {
|
| 156 |
+
valueMatches &&= valueMax === (0, _roleHelpers.computeAriaValueMax)(element);
|
| 157 |
+
}
|
| 158 |
+
if (valueMin !== undefined) {
|
| 159 |
+
valueMatches &&= valueMin === (0, _roleHelpers.computeAriaValueMin)(element);
|
| 160 |
+
}
|
| 161 |
+
if (valueText !== undefined) {
|
| 162 |
+
valueMatches &&= (0, _allUtils.matches)((0, _roleHelpers.computeAriaValueText)(element) ?? null, element, valueText, text => text);
|
| 163 |
+
}
|
| 164 |
+
return valueMatches;
|
| 165 |
+
}
|
| 166 |
+
// don't care if aria attributes are unspecified
|
| 167 |
+
return true;
|
| 168 |
+
}).filter(element => {
|
| 169 |
+
if (name === undefined) {
|
| 170 |
+
// Don't care
|
| 171 |
+
return true;
|
| 172 |
+
}
|
| 173 |
+
return (0, _allUtils.matches)((0, _domAccessibilityApi.computeAccessibleName)(element, {
|
| 174 |
+
computedStyleSupportsPseudoElements: (0, _allUtils.getConfig)().computedStyleSupportsPseudoElements
|
| 175 |
+
}), element, name, text => text);
|
| 176 |
+
}).filter(element => {
|
| 177 |
+
if (description === undefined) {
|
| 178 |
+
// Don't care
|
| 179 |
+
return true;
|
| 180 |
+
}
|
| 181 |
+
return (0, _allUtils.matches)((0, _domAccessibilityApi.computeAccessibleDescription)(element, {
|
| 182 |
+
computedStyleSupportsPseudoElements: (0, _allUtils.getConfig)().computedStyleSupportsPseudoElements
|
| 183 |
+
}), element, description, text => text);
|
| 184 |
+
}).filter(element => {
|
| 185 |
+
return hidden === false ? (0, _roleHelpers.isInaccessible)(element, {
|
| 186 |
+
isSubtreeInaccessible: cachedIsSubtreeInaccessible
|
| 187 |
+
}) === false : true;
|
| 188 |
+
});
|
| 189 |
+
};
|
| 190 |
+
function makeRoleSelector(role) {
|
| 191 |
+
const explicitRoleSelector = `*[role~="${role}"]`;
|
| 192 |
+
const roleRelations = _ariaQuery.roleElements.get(role) ?? new Set();
|
| 193 |
+
const implicitRoleSelectors = new Set(Array.from(roleRelations).map(({
|
| 194 |
+
name
|
| 195 |
+
}) => name));
|
| 196 |
+
|
| 197 |
+
// Current transpilation config sometimes assumes `...` is always applied to arrays.
|
| 198 |
+
// `...` is equivalent to `Array.prototype.concat` for arrays.
|
| 199 |
+
// If you replace this code with `[explicitRoleSelector, ...implicitRoleSelectors]`, make sure every transpilation target retains the `...` in favor of `Array.prototype.concat`.
|
| 200 |
+
return [explicitRoleSelector].concat(Array.from(implicitRoleSelectors)).join(',');
|
| 201 |
+
}
|
| 202 |
+
const getNameHint = name => {
|
| 203 |
+
let nameHint = '';
|
| 204 |
+
if (name === undefined) {
|
| 205 |
+
nameHint = '';
|
| 206 |
+
} else if (typeof name === 'string') {
|
| 207 |
+
nameHint = ` and name "${name}"`;
|
| 208 |
+
} else {
|
| 209 |
+
nameHint = ` and name \`${name}\``;
|
| 210 |
+
}
|
| 211 |
+
return nameHint;
|
| 212 |
+
};
|
| 213 |
+
const getMultipleError = (c, role, {
|
| 214 |
+
name
|
| 215 |
+
} = {}) => {
|
| 216 |
+
return `Found multiple elements with the role "${role}"${getNameHint(name)}`;
|
| 217 |
+
};
|
| 218 |
+
const getMissingError = (container, role, {
|
| 219 |
+
hidden = (0, _allUtils.getConfig)().defaultHidden,
|
| 220 |
+
name,
|
| 221 |
+
description
|
| 222 |
+
} = {}) => {
|
| 223 |
+
if ((0, _allUtils.getConfig)()._disableExpensiveErrorDiagnostics) {
|
| 224 |
+
return `Unable to find role="${role}"${getNameHint(name)}`;
|
| 225 |
+
}
|
| 226 |
+
let roles = '';
|
| 227 |
+
Array.from(container.children).forEach(childElement => {
|
| 228 |
+
roles += (0, _roleHelpers.prettyRoles)(childElement, {
|
| 229 |
+
hidden,
|
| 230 |
+
includeDescription: description !== undefined
|
| 231 |
+
});
|
| 232 |
+
});
|
| 233 |
+
let roleMessage;
|
| 234 |
+
if (roles.length === 0) {
|
| 235 |
+
if (hidden === false) {
|
| 236 |
+
roleMessage = 'There are no accessible roles. But there might be some inaccessible roles. ' + 'If you wish to access them, then set the `hidden` option to `true`. ' + 'Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole';
|
| 237 |
+
} else {
|
| 238 |
+
roleMessage = 'There are no available roles.';
|
| 239 |
+
}
|
| 240 |
+
} else {
|
| 241 |
+
roleMessage = `
|
| 242 |
+
Here are the ${hidden === false ? 'accessible' : 'available'} roles:
|
| 243 |
+
|
| 244 |
+
${roles.replace(/\n/g, '\n ').replace(/\n\s\s\n/g, '\n\n')}
|
| 245 |
+
`.trim();
|
| 246 |
+
}
|
| 247 |
+
let nameHint = '';
|
| 248 |
+
if (name === undefined) {
|
| 249 |
+
nameHint = '';
|
| 250 |
+
} else if (typeof name === 'string') {
|
| 251 |
+
nameHint = ` and name "${name}"`;
|
| 252 |
+
} else {
|
| 253 |
+
nameHint = ` and name \`${name}\``;
|
| 254 |
+
}
|
| 255 |
+
let descriptionHint = '';
|
| 256 |
+
if (description === undefined) {
|
| 257 |
+
descriptionHint = '';
|
| 258 |
+
} else if (typeof description === 'string') {
|
| 259 |
+
descriptionHint = ` and description "${description}"`;
|
| 260 |
+
} else {
|
| 261 |
+
descriptionHint = ` and description \`${description}\``;
|
| 262 |
+
}
|
| 263 |
+
return `
|
| 264 |
+
Unable to find an ${hidden === false ? 'accessible ' : ''}element with the role "${role}"${nameHint}${descriptionHint}
|
| 265 |
+
|
| 266 |
+
${roleMessage}`.trim();
|
| 267 |
+
};
|
| 268 |
+
const queryAllByRoleWithSuggestions = exports.queryAllByRole = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByRole, queryAllByRole.name, 'queryAll');
|
| 269 |
+
const [queryByRole, getAllByRole, getByRole, findAllByRole, findByRole] = (0, _allUtils.buildQueries)(queryAllByRole, getMultipleError, getMissingError);
|
| 270 |
+
exports.findByRole = findByRole;
|
| 271 |
+
exports.findAllByRole = findAllByRole;
|
| 272 |
+
exports.getByRole = getByRole;
|
| 273 |
+
exports.getAllByRole = getAllByRole;
|
| 274 |
+
exports.queryByRole = queryByRole;
|
node_modules/@testing-library/dom/dist/queries/test-id.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByTestId = exports.queryAllByTestId = exports.getByTestId = exports.getAllByTestId = exports.findByTestId = exports.findAllByTestId = void 0;
|
| 7 |
+
var _helpers = require("../helpers");
|
| 8 |
+
var _queryHelpers = require("../query-helpers");
|
| 9 |
+
var _allUtils = require("./all-utils");
|
| 10 |
+
const getTestIdAttribute = () => (0, _allUtils.getConfig)().testIdAttribute;
|
| 11 |
+
const queryAllByTestId = (...args) => {
|
| 12 |
+
(0, _helpers.checkContainerType)(args[0]);
|
| 13 |
+
return (0, _allUtils.queryAllByAttribute)(getTestIdAttribute(), ...args);
|
| 14 |
+
};
|
| 15 |
+
const getMultipleError = (c, id) => `Found multiple elements by: [${getTestIdAttribute()}="${id}"]`;
|
| 16 |
+
const getMissingError = (c, id) => `Unable to find an element by: [${getTestIdAttribute()}="${id}"]`;
|
| 17 |
+
const queryAllByTestIdWithSuggestions = exports.queryAllByTestId = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByTestId, queryAllByTestId.name, 'queryAll');
|
| 18 |
+
const [queryByTestId, getAllByTestId, getByTestId, findAllByTestId, findByTestId] = (0, _allUtils.buildQueries)(queryAllByTestId, getMultipleError, getMissingError);
|
| 19 |
+
exports.findByTestId = findByTestId;
|
| 20 |
+
exports.findAllByTestId = findAllByTestId;
|
| 21 |
+
exports.getByTestId = getByTestId;
|
| 22 |
+
exports.getAllByTestId = getAllByTestId;
|
| 23 |
+
exports.queryByTestId = queryByTestId;
|
node_modules/@testing-library/dom/dist/queries/text.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByText = exports.queryAllByText = exports.getByText = exports.getAllByText = exports.findByText = exports.findAllByText = void 0;
|
| 7 |
+
var _queryHelpers = require("../query-helpers");
|
| 8 |
+
var _helpers = require("../helpers");
|
| 9 |
+
var _allUtils = require("./all-utils");
|
| 10 |
+
const queryAllByText = (container, text, {
|
| 11 |
+
selector = '*',
|
| 12 |
+
exact = true,
|
| 13 |
+
collapseWhitespace,
|
| 14 |
+
trim,
|
| 15 |
+
ignore = (0, _allUtils.getConfig)().defaultIgnore,
|
| 16 |
+
normalizer
|
| 17 |
+
} = {}) => {
|
| 18 |
+
(0, _helpers.checkContainerType)(container);
|
| 19 |
+
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches;
|
| 20 |
+
const matchNormalizer = (0, _allUtils.makeNormalizer)({
|
| 21 |
+
collapseWhitespace,
|
| 22 |
+
trim,
|
| 23 |
+
normalizer
|
| 24 |
+
});
|
| 25 |
+
let baseArray = [];
|
| 26 |
+
if (typeof container.matches === 'function' && container.matches(selector)) {
|
| 27 |
+
baseArray = [container];
|
| 28 |
+
}
|
| 29 |
+
return [...baseArray, ...Array.from(container.querySelectorAll(selector))]
|
| 30 |
+
// TODO: `matches` according lib.dom.d.ts can get only `string` but according our code it can handle also boolean :)
|
| 31 |
+
.filter(node => !ignore || !node.matches(ignore)).filter(node => matcher((0, _allUtils.getNodeText)(node), node, text, matchNormalizer));
|
| 32 |
+
};
|
| 33 |
+
const getMultipleError = (c, text) => `Found multiple elements with the text: ${text}`;
|
| 34 |
+
const getMissingError = (c, text, options = {}) => {
|
| 35 |
+
const {
|
| 36 |
+
collapseWhitespace,
|
| 37 |
+
trim,
|
| 38 |
+
normalizer,
|
| 39 |
+
selector
|
| 40 |
+
} = options;
|
| 41 |
+
const matchNormalizer = (0, _allUtils.makeNormalizer)({
|
| 42 |
+
collapseWhitespace,
|
| 43 |
+
trim,
|
| 44 |
+
normalizer
|
| 45 |
+
});
|
| 46 |
+
const normalizedText = matchNormalizer(text.toString());
|
| 47 |
+
const isNormalizedDifferent = normalizedText !== text.toString();
|
| 48 |
+
const isCustomSelector = (selector ?? '*') !== '*';
|
| 49 |
+
return `Unable to find an element with the text: ${isNormalizedDifferent ? `${normalizedText} (normalized from '${text}')` : text}${isCustomSelector ? `, which matches selector '${selector}'` : ''}. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.`;
|
| 50 |
+
};
|
| 51 |
+
const queryAllByTextWithSuggestions = exports.queryAllByText = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByText, queryAllByText.name, 'queryAll');
|
| 52 |
+
const [queryByText, getAllByText, getByText, findAllByText, findByText] = (0, _allUtils.buildQueries)(queryAllByText, getMultipleError, getMissingError);
|
| 53 |
+
exports.findByText = findByText;
|
| 54 |
+
exports.findAllByText = findAllByText;
|
| 55 |
+
exports.getByText = getByText;
|
| 56 |
+
exports.getAllByText = getAllByText;
|
| 57 |
+
exports.queryByText = queryByText;
|
node_modules/@testing-library/dom/dist/queries/title.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.queryByTitle = exports.queryAllByTitle = exports.getByTitle = exports.getAllByTitle = exports.findByTitle = exports.findAllByTitle = void 0;
|
| 7 |
+
var _queryHelpers = require("../query-helpers");
|
| 8 |
+
var _helpers = require("../helpers");
|
| 9 |
+
var _allUtils = require("./all-utils");
|
| 10 |
+
const isSvgTitle = node => node.tagName.toLowerCase() === 'title' && node.parentElement?.tagName.toLowerCase() === 'svg';
|
| 11 |
+
const queryAllByTitle = (container, text, {
|
| 12 |
+
exact = true,
|
| 13 |
+
collapseWhitespace,
|
| 14 |
+
trim,
|
| 15 |
+
normalizer
|
| 16 |
+
} = {}) => {
|
| 17 |
+
(0, _helpers.checkContainerType)(container);
|
| 18 |
+
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches;
|
| 19 |
+
const matchNormalizer = (0, _allUtils.makeNormalizer)({
|
| 20 |
+
collapseWhitespace,
|
| 21 |
+
trim,
|
| 22 |
+
normalizer
|
| 23 |
+
});
|
| 24 |
+
return Array.from(container.querySelectorAll('[title], svg > title')).filter(node => matcher(node.getAttribute('title'), node, text, matchNormalizer) || isSvgTitle(node) && matcher((0, _allUtils.getNodeText)(node), node, text, matchNormalizer));
|
| 25 |
+
};
|
| 26 |
+
const getMultipleError = (c, title) => `Found multiple elements with the title: ${title}.`;
|
| 27 |
+
const getMissingError = (c, title) => `Unable to find an element with the title: ${title}.`;
|
| 28 |
+
const queryAllByTitleWithSuggestions = exports.queryAllByTitle = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByTitle, queryAllByTitle.name, 'queryAll');
|
| 29 |
+
const [queryByTitle, getAllByTitle, getByTitle, findAllByTitle, findByTitle] = (0, _allUtils.buildQueries)(queryAllByTitle, getMultipleError, getMissingError);
|
| 30 |
+
exports.findByTitle = findByTitle;
|
| 31 |
+
exports.findAllByTitle = findAllByTitle;
|
| 32 |
+
exports.getByTitle = getByTitle;
|
| 33 |
+
exports.getAllByTitle = getAllByTitle;
|
| 34 |
+
exports.queryByTitle = queryByTitle;
|
node_modules/@testing-library/dom/dist/query-helpers.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.buildQueries = buildQueries;
|
| 7 |
+
exports.getElementError = getElementError;
|
| 8 |
+
exports.getMultipleElementsFoundError = getMultipleElementsFoundError;
|
| 9 |
+
exports.makeFindQuery = makeFindQuery;
|
| 10 |
+
exports.makeGetAllQuery = makeGetAllQuery;
|
| 11 |
+
exports.makeSingleQuery = makeSingleQuery;
|
| 12 |
+
exports.queryAllByAttribute = queryAllByAttribute;
|
| 13 |
+
exports.queryByAttribute = queryByAttribute;
|
| 14 |
+
exports.wrapSingleQueryWithSuggestion = exports.wrapAllByQueryWithSuggestion = void 0;
|
| 15 |
+
var _suggestions = require("./suggestions");
|
| 16 |
+
var _matches = require("./matches");
|
| 17 |
+
var _waitFor = require("./wait-for");
|
| 18 |
+
var _config = require("./config");
|
| 19 |
+
function getElementError(message, container) {
|
| 20 |
+
return (0, _config.getConfig)().getElementError(message, container);
|
| 21 |
+
}
|
| 22 |
+
function getMultipleElementsFoundError(message, container) {
|
| 23 |
+
return getElementError(`${message}\n\n(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).`, container);
|
| 24 |
+
}
|
| 25 |
+
function queryAllByAttribute(attribute, container, text, {
|
| 26 |
+
exact = true,
|
| 27 |
+
collapseWhitespace,
|
| 28 |
+
trim,
|
| 29 |
+
normalizer
|
| 30 |
+
} = {}) {
|
| 31 |
+
const matcher = exact ? _matches.matches : _matches.fuzzyMatches;
|
| 32 |
+
const matchNormalizer = (0, _matches.makeNormalizer)({
|
| 33 |
+
collapseWhitespace,
|
| 34 |
+
trim,
|
| 35 |
+
normalizer
|
| 36 |
+
});
|
| 37 |
+
return Array.from(container.querySelectorAll(`[${attribute}]`)).filter(node => matcher(node.getAttribute(attribute), node, text, matchNormalizer));
|
| 38 |
+
}
|
| 39 |
+
function queryByAttribute(attribute, container, text, options) {
|
| 40 |
+
const els = queryAllByAttribute(attribute, container, text, options);
|
| 41 |
+
if (els.length > 1) {
|
| 42 |
+
throw getMultipleElementsFoundError(`Found multiple elements by [${attribute}=${text}]`, container);
|
| 43 |
+
}
|
| 44 |
+
return els[0] || null;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
// this accepts a query function and returns a function which throws an error
|
| 48 |
+
// if more than one elements is returned, otherwise it returns the first
|
| 49 |
+
// element or null
|
| 50 |
+
function makeSingleQuery(allQuery, getMultipleError) {
|
| 51 |
+
return (container, ...args) => {
|
| 52 |
+
const els = allQuery(container, ...args);
|
| 53 |
+
if (els.length > 1) {
|
| 54 |
+
const elementStrings = els.map(element => getElementError(null, element).message).join('\n\n');
|
| 55 |
+
throw getMultipleElementsFoundError(`${getMultipleError(container, ...args)}
|
| 56 |
+
|
| 57 |
+
Here are the matching elements:
|
| 58 |
+
|
| 59 |
+
${elementStrings}`, container);
|
| 60 |
+
}
|
| 61 |
+
return els[0] || null;
|
| 62 |
+
};
|
| 63 |
+
}
|
| 64 |
+
function getSuggestionError(suggestion, container) {
|
| 65 |
+
return (0, _config.getConfig)().getElementError(`A better query is available, try this:
|
| 66 |
+
${suggestion.toString()}
|
| 67 |
+
`, container);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
// this accepts a query function and returns a function which throws an error
|
| 71 |
+
// if an empty list of elements is returned
|
| 72 |
+
function makeGetAllQuery(allQuery, getMissingError) {
|
| 73 |
+
return (container, ...args) => {
|
| 74 |
+
const els = allQuery(container, ...args);
|
| 75 |
+
if (!els.length) {
|
| 76 |
+
throw (0, _config.getConfig)().getElementError(getMissingError(container, ...args), container);
|
| 77 |
+
}
|
| 78 |
+
return els;
|
| 79 |
+
};
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
// this accepts a getter query function and returns a function which calls
|
| 83 |
+
// waitFor and passing a function which invokes the getter.
|
| 84 |
+
function makeFindQuery(getter) {
|
| 85 |
+
return (container, text, options, waitForOptions) => {
|
| 86 |
+
return (0, _waitFor.waitFor)(() => {
|
| 87 |
+
return getter(container, text, options);
|
| 88 |
+
}, {
|
| 89 |
+
container,
|
| 90 |
+
...waitForOptions
|
| 91 |
+
});
|
| 92 |
+
};
|
| 93 |
+
}
|
| 94 |
+
const wrapSingleQueryWithSuggestion = (query, queryAllByName, variant) => (container, ...args) => {
|
| 95 |
+
const element = query(container, ...args);
|
| 96 |
+
const [{
|
| 97 |
+
suggest = (0, _config.getConfig)().throwSuggestions
|
| 98 |
+
} = {}] = args.slice(-1);
|
| 99 |
+
if (element && suggest) {
|
| 100 |
+
const suggestion = (0, _suggestions.getSuggestedQuery)(element, variant);
|
| 101 |
+
if (suggestion && !queryAllByName.endsWith(suggestion.queryName)) {
|
| 102 |
+
throw getSuggestionError(suggestion.toString(), container);
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
return element;
|
| 106 |
+
};
|
| 107 |
+
exports.wrapSingleQueryWithSuggestion = wrapSingleQueryWithSuggestion;
|
| 108 |
+
const wrapAllByQueryWithSuggestion = (query, queryAllByName, variant) => (container, ...args) => {
|
| 109 |
+
const els = query(container, ...args);
|
| 110 |
+
const [{
|
| 111 |
+
suggest = (0, _config.getConfig)().throwSuggestions
|
| 112 |
+
} = {}] = args.slice(-1);
|
| 113 |
+
if (els.length && suggest) {
|
| 114 |
+
// get a unique list of all suggestion messages. We are only going to make a suggestion if
|
| 115 |
+
// all the suggestions are the same
|
| 116 |
+
const uniqueSuggestionMessages = [...new Set(els.map(element => (0, _suggestions.getSuggestedQuery)(element, variant)?.toString()))];
|
| 117 |
+
if (
|
| 118 |
+
// only want to suggest if all the els have the same suggestion.
|
| 119 |
+
uniqueSuggestionMessages.length === 1 && !queryAllByName.endsWith(
|
| 120 |
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: Can this be null at runtime?
|
| 121 |
+
(0, _suggestions.getSuggestedQuery)(els[0], variant).queryName)) {
|
| 122 |
+
throw getSuggestionError(uniqueSuggestionMessages[0], container);
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
return els;
|
| 126 |
+
};
|
| 127 |
+
|
| 128 |
+
// TODO: This deviates from the published declarations
|
| 129 |
+
// However, the implementation always required a dyadic (after `container`) not variadic `queryAllBy` considering the implementation of `makeFindQuery`
|
| 130 |
+
// This is at least statically true and can be verified by accepting `QueryMethod<Arguments, HTMLElement[]>`
|
| 131 |
+
exports.wrapAllByQueryWithSuggestion = wrapAllByQueryWithSuggestion;
|
| 132 |
+
function buildQueries(queryAllBy, getMultipleError, getMissingError) {
|
| 133 |
+
const queryBy = wrapSingleQueryWithSuggestion(makeSingleQuery(queryAllBy, getMultipleError), queryAllBy.name, 'query');
|
| 134 |
+
const getAllBy = makeGetAllQuery(queryAllBy, getMissingError);
|
| 135 |
+
const getBy = makeSingleQuery(getAllBy, getMultipleError);
|
| 136 |
+
const getByWithSuggestions = wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'get');
|
| 137 |
+
const getAllWithSuggestions = wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name.replace('query', 'get'), 'getAll');
|
| 138 |
+
const findAllBy = makeFindQuery(wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name, 'findAll'));
|
| 139 |
+
const findBy = makeFindQuery(wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'find'));
|
| 140 |
+
return [queryBy, getAllWithSuggestions, getByWithSuggestions, findAllBy, findBy];
|
| 141 |
+
}
|
node_modules/@testing-library/dom/dist/role-helpers.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.computeAriaBusy = computeAriaBusy;
|
| 7 |
+
exports.computeAriaChecked = computeAriaChecked;
|
| 8 |
+
exports.computeAriaCurrent = computeAriaCurrent;
|
| 9 |
+
exports.computeAriaExpanded = computeAriaExpanded;
|
| 10 |
+
exports.computeAriaPressed = computeAriaPressed;
|
| 11 |
+
exports.computeAriaSelected = computeAriaSelected;
|
| 12 |
+
exports.computeAriaValueMax = computeAriaValueMax;
|
| 13 |
+
exports.computeAriaValueMin = computeAriaValueMin;
|
| 14 |
+
exports.computeAriaValueNow = computeAriaValueNow;
|
| 15 |
+
exports.computeAriaValueText = computeAriaValueText;
|
| 16 |
+
exports.computeHeadingLevel = computeHeadingLevel;
|
| 17 |
+
exports.getImplicitAriaRoles = getImplicitAriaRoles;
|
| 18 |
+
exports.getRoles = getRoles;
|
| 19 |
+
exports.isInaccessible = isInaccessible;
|
| 20 |
+
exports.isSubtreeInaccessible = isSubtreeInaccessible;
|
| 21 |
+
exports.logRoles = void 0;
|
| 22 |
+
exports.prettyRoles = prettyRoles;
|
| 23 |
+
var _ariaQuery = require("aria-query");
|
| 24 |
+
var _domAccessibilityApi = require("dom-accessibility-api");
|
| 25 |
+
var _prettyDom = require("./pretty-dom");
|
| 26 |
+
var _config = require("./config");
|
| 27 |
+
const elementRoleList = buildElementRoleList(_ariaQuery.elementRoles);
|
| 28 |
+
|
| 29 |
+
/**
|
| 30 |
+
* @param {Element} element -
|
| 31 |
+
* @returns {boolean} - `true` if `element` and its subtree are inaccessible
|
| 32 |
+
*/
|
| 33 |
+
function isSubtreeInaccessible(element) {
|
| 34 |
+
if (element.hidden === true) {
|
| 35 |
+
return true;
|
| 36 |
+
}
|
| 37 |
+
if (element.getAttribute('aria-hidden') === 'true') {
|
| 38 |
+
return true;
|
| 39 |
+
}
|
| 40 |
+
const window = element.ownerDocument.defaultView;
|
| 41 |
+
if (window.getComputedStyle(element).display === 'none') {
|
| 42 |
+
return true;
|
| 43 |
+
}
|
| 44 |
+
return false;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/**
|
| 48 |
+
* Partial implementation https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion
|
| 49 |
+
* which should only be used for elements with a non-presentational role i.e.
|
| 50 |
+
* `role="none"` and `role="presentation"` will not be excluded.
|
| 51 |
+
*
|
| 52 |
+
* Implements aria-hidden semantics (i.e. parent overrides child)
|
| 53 |
+
* Ignores "Child Presentational: True" characteristics
|
| 54 |
+
*
|
| 55 |
+
* @param {Element} element -
|
| 56 |
+
* @param {object} [options] -
|
| 57 |
+
* @param {function (element: Element): boolean} options.isSubtreeInaccessible -
|
| 58 |
+
* can be used to return cached results from previous isSubtreeInaccessible calls
|
| 59 |
+
* @returns {boolean} true if excluded, otherwise false
|
| 60 |
+
*/
|
| 61 |
+
function isInaccessible(element, options = {}) {
|
| 62 |
+
const {
|
| 63 |
+
isSubtreeInaccessible: isSubtreeInaccessibleImpl = isSubtreeInaccessible
|
| 64 |
+
} = options;
|
| 65 |
+
const window = element.ownerDocument.defaultView;
|
| 66 |
+
// since visibility is inherited we can exit early
|
| 67 |
+
if (window.getComputedStyle(element).visibility === 'hidden') {
|
| 68 |
+
return true;
|
| 69 |
+
}
|
| 70 |
+
let currentElement = element;
|
| 71 |
+
while (currentElement) {
|
| 72 |
+
if (isSubtreeInaccessibleImpl(currentElement)) {
|
| 73 |
+
return true;
|
| 74 |
+
}
|
| 75 |
+
currentElement = currentElement.parentElement;
|
| 76 |
+
}
|
| 77 |
+
return false;
|
| 78 |
+
}
|
| 79 |
+
function getImplicitAriaRoles(currentNode) {
|
| 80 |
+
// eslint bug here:
|
| 81 |
+
// eslint-disable-next-line no-unused-vars
|
| 82 |
+
for (const {
|
| 83 |
+
match,
|
| 84 |
+
roles
|
| 85 |
+
} of elementRoleList) {
|
| 86 |
+
if (match(currentNode)) {
|
| 87 |
+
return [...roles];
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
return [];
|
| 91 |
+
}
|
| 92 |
+
function buildElementRoleList(elementRolesMap) {
|
| 93 |
+
function makeElementSelector({
|
| 94 |
+
name,
|
| 95 |
+
attributes
|
| 96 |
+
}) {
|
| 97 |
+
return `${name}${attributes.map(({
|
| 98 |
+
name: attributeName,
|
| 99 |
+
value,
|
| 100 |
+
constraints = []
|
| 101 |
+
}) => {
|
| 102 |
+
const shouldNotExist = constraints.indexOf('undefined') !== -1;
|
| 103 |
+
const shouldBeNonEmpty = constraints.indexOf('set') !== -1;
|
| 104 |
+
const hasExplicitValue = typeof value !== 'undefined';
|
| 105 |
+
if (hasExplicitValue) {
|
| 106 |
+
return `[${attributeName}="${value}"]`;
|
| 107 |
+
} else if (shouldNotExist) {
|
| 108 |
+
return `:not([${attributeName}])`;
|
| 109 |
+
} else if (shouldBeNonEmpty) {
|
| 110 |
+
return `[${attributeName}]:not([${attributeName}=""])`;
|
| 111 |
+
}
|
| 112 |
+
return `[${attributeName}]`;
|
| 113 |
+
}).join('')}`;
|
| 114 |
+
}
|
| 115 |
+
function getSelectorSpecificity({
|
| 116 |
+
attributes = []
|
| 117 |
+
}) {
|
| 118 |
+
return attributes.length;
|
| 119 |
+
}
|
| 120 |
+
function bySelectorSpecificity({
|
| 121 |
+
specificity: leftSpecificity
|
| 122 |
+
}, {
|
| 123 |
+
specificity: rightSpecificity
|
| 124 |
+
}) {
|
| 125 |
+
return rightSpecificity - leftSpecificity;
|
| 126 |
+
}
|
| 127 |
+
function match(element) {
|
| 128 |
+
let {
|
| 129 |
+
attributes = []
|
| 130 |
+
} = element;
|
| 131 |
+
|
| 132 |
+
// https://github.com/testing-library/dom-testing-library/issues/814
|
| 133 |
+
const typeTextIndex = attributes.findIndex(attribute => attribute.value && attribute.name === 'type' && attribute.value === 'text');
|
| 134 |
+
if (typeTextIndex >= 0) {
|
| 135 |
+
// not using splice to not mutate the attributes array
|
| 136 |
+
attributes = [...attributes.slice(0, typeTextIndex), ...attributes.slice(typeTextIndex + 1)];
|
| 137 |
+
}
|
| 138 |
+
const selector = makeElementSelector({
|
| 139 |
+
...element,
|
| 140 |
+
attributes
|
| 141 |
+
});
|
| 142 |
+
return node => {
|
| 143 |
+
if (typeTextIndex >= 0 && node.type !== 'text') {
|
| 144 |
+
return false;
|
| 145 |
+
}
|
| 146 |
+
return node.matches(selector);
|
| 147 |
+
};
|
| 148 |
+
}
|
| 149 |
+
let result = [];
|
| 150 |
+
|
| 151 |
+
// eslint bug here:
|
| 152 |
+
// eslint-disable-next-line no-unused-vars
|
| 153 |
+
for (const [element, roles] of elementRolesMap.entries()) {
|
| 154 |
+
result = [...result, {
|
| 155 |
+
match: match(element),
|
| 156 |
+
roles: Array.from(roles),
|
| 157 |
+
specificity: getSelectorSpecificity(element)
|
| 158 |
+
}];
|
| 159 |
+
}
|
| 160 |
+
return result.sort(bySelectorSpecificity);
|
| 161 |
+
}
|
| 162 |
+
function getRoles(container, {
|
| 163 |
+
hidden = false
|
| 164 |
+
} = {}) {
|
| 165 |
+
function flattenDOM(node) {
|
| 166 |
+
return [node, ...Array.from(node.children).reduce((acc, child) => [...acc, ...flattenDOM(child)], [])];
|
| 167 |
+
}
|
| 168 |
+
return flattenDOM(container).filter(element => {
|
| 169 |
+
return hidden === false ? isInaccessible(element) === false : true;
|
| 170 |
+
}).reduce((acc, node) => {
|
| 171 |
+
let roles = [];
|
| 172 |
+
// TODO: This violates html-aria which does not allow any role on every element
|
| 173 |
+
if (node.hasAttribute('role')) {
|
| 174 |
+
roles = node.getAttribute('role').split(' ').slice(0, 1);
|
| 175 |
+
} else {
|
| 176 |
+
roles = getImplicitAriaRoles(node);
|
| 177 |
+
}
|
| 178 |
+
return roles.reduce((rolesAcc, role) => Array.isArray(rolesAcc[role]) ? {
|
| 179 |
+
...rolesAcc,
|
| 180 |
+
[role]: [...rolesAcc[role], node]
|
| 181 |
+
} : {
|
| 182 |
+
...rolesAcc,
|
| 183 |
+
[role]: [node]
|
| 184 |
+
}, acc);
|
| 185 |
+
}, {});
|
| 186 |
+
}
|
| 187 |
+
function prettyRoles(dom, {
|
| 188 |
+
hidden,
|
| 189 |
+
includeDescription
|
| 190 |
+
}) {
|
| 191 |
+
const roles = getRoles(dom, {
|
| 192 |
+
hidden
|
| 193 |
+
});
|
| 194 |
+
// We prefer to skip generic role, we don't recommend it
|
| 195 |
+
return Object.entries(roles).filter(([role]) => role !== 'generic').map(([role, elements]) => {
|
| 196 |
+
const delimiterBar = '-'.repeat(50);
|
| 197 |
+
const elementsString = elements.map(el => {
|
| 198 |
+
const nameString = `Name "${(0, _domAccessibilityApi.computeAccessibleName)(el, {
|
| 199 |
+
computedStyleSupportsPseudoElements: (0, _config.getConfig)().computedStyleSupportsPseudoElements
|
| 200 |
+
})}":\n`;
|
| 201 |
+
const domString = (0, _prettyDom.prettyDOM)(el.cloneNode(false));
|
| 202 |
+
if (includeDescription) {
|
| 203 |
+
const descriptionString = `Description "${(0, _domAccessibilityApi.computeAccessibleDescription)(el, {
|
| 204 |
+
computedStyleSupportsPseudoElements: (0, _config.getConfig)().computedStyleSupportsPseudoElements
|
| 205 |
+
})}":\n`;
|
| 206 |
+
return `${nameString}${descriptionString}${domString}`;
|
| 207 |
+
}
|
| 208 |
+
return `${nameString}${domString}`;
|
| 209 |
+
}).join('\n\n');
|
| 210 |
+
return `${role}:\n\n${elementsString}\n\n${delimiterBar}`;
|
| 211 |
+
}).join('\n');
|
| 212 |
+
}
|
| 213 |
+
const logRoles = (dom, {
|
| 214 |
+
hidden = false
|
| 215 |
+
} = {}) => console.log(prettyRoles(dom, {
|
| 216 |
+
hidden
|
| 217 |
+
}));
|
| 218 |
+
|
| 219 |
+
/**
|
| 220 |
+
* @param {Element} element -
|
| 221 |
+
* @returns {boolean | undefined} - false/true if (not)selected, undefined if not selectable
|
| 222 |
+
*/
|
| 223 |
+
exports.logRoles = logRoles;
|
| 224 |
+
function computeAriaSelected(element) {
|
| 225 |
+
// implicit value from html-aam mappings: https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
|
| 226 |
+
// https://www.w3.org/TR/html-aam-1.0/#details-id-97
|
| 227 |
+
if (element.tagName === 'OPTION') {
|
| 228 |
+
return element.selected;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
// explicit value
|
| 232 |
+
return checkBooleanAttribute(element, 'aria-selected');
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
/**
|
| 236 |
+
* @param {Element} element -
|
| 237 |
+
* @returns {boolean} -
|
| 238 |
+
*/
|
| 239 |
+
function computeAriaBusy(element) {
|
| 240 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-busy
|
| 241 |
+
return element.getAttribute('aria-busy') === 'true';
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
/**
|
| 245 |
+
* @param {Element} element -
|
| 246 |
+
* @returns {boolean | undefined} - false/true if (not)checked, undefined if not checked-able
|
| 247 |
+
*/
|
| 248 |
+
function computeAriaChecked(element) {
|
| 249 |
+
// implicit value from html-aam mappings: https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
|
| 250 |
+
// https://www.w3.org/TR/html-aam-1.0/#details-id-56
|
| 251 |
+
// https://www.w3.org/TR/html-aam-1.0/#details-id-67
|
| 252 |
+
if ('indeterminate' in element && element.indeterminate) {
|
| 253 |
+
return undefined;
|
| 254 |
+
}
|
| 255 |
+
if ('checked' in element) {
|
| 256 |
+
return element.checked;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
// explicit value
|
| 260 |
+
return checkBooleanAttribute(element, 'aria-checked');
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
/**
|
| 264 |
+
* @param {Element} element -
|
| 265 |
+
* @returns {boolean | undefined} - false/true if (not)pressed, undefined if not press-able
|
| 266 |
+
*/
|
| 267 |
+
function computeAriaPressed(element) {
|
| 268 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-pressed
|
| 269 |
+
return checkBooleanAttribute(element, 'aria-pressed');
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
/**
|
| 273 |
+
* @param {Element} element -
|
| 274 |
+
* @returns {boolean | string | null} -
|
| 275 |
+
*/
|
| 276 |
+
function computeAriaCurrent(element) {
|
| 277 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-current
|
| 278 |
+
return checkBooleanAttribute(element, 'aria-current') ?? element.getAttribute('aria-current') ?? false;
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
/**
|
| 282 |
+
* @param {Element} element -
|
| 283 |
+
* @returns {boolean | undefined} - false/true if (not)expanded, undefined if not expand-able
|
| 284 |
+
*/
|
| 285 |
+
function computeAriaExpanded(element) {
|
| 286 |
+
// https://www.w3.org/TR/wai-aria-1.1/#aria-expanded
|
| 287 |
+
return checkBooleanAttribute(element, 'aria-expanded');
|
| 288 |
+
}
|
| 289 |
+
function checkBooleanAttribute(element, attribute) {
|
| 290 |
+
const attributeValue = element.getAttribute(attribute);
|
| 291 |
+
if (attributeValue === 'true') {
|
| 292 |
+
return true;
|
| 293 |
+
}
|
| 294 |
+
if (attributeValue === 'false') {
|
| 295 |
+
return false;
|
| 296 |
+
}
|
| 297 |
+
return undefined;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
/**
|
| 301 |
+
* @param {Element} element -
|
| 302 |
+
* @returns {number | undefined} - number if implicit heading or aria-level present, otherwise undefined
|
| 303 |
+
*/
|
| 304 |
+
function computeHeadingLevel(element) {
|
| 305 |
+
// https://w3c.github.io/html-aam/#el-h1-h6
|
| 306 |
+
// https://w3c.github.io/html-aam/#el-h1-h6
|
| 307 |
+
const implicitHeadingLevels = {
|
| 308 |
+
H1: 1,
|
| 309 |
+
H2: 2,
|
| 310 |
+
H3: 3,
|
| 311 |
+
H4: 4,
|
| 312 |
+
H5: 5,
|
| 313 |
+
H6: 6
|
| 314 |
+
};
|
| 315 |
+
// explicit aria-level value
|
| 316 |
+
// https://www.w3.org/TR/wai-aria-1.2/#aria-level
|
| 317 |
+
const ariaLevelAttribute = element.getAttribute('aria-level') && Number(element.getAttribute('aria-level'));
|
| 318 |
+
return ariaLevelAttribute || implicitHeadingLevels[element.tagName];
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
/**
|
| 322 |
+
* @param {Element} element -
|
| 323 |
+
* @returns {number | undefined} -
|
| 324 |
+
*/
|
| 325 |
+
function computeAriaValueNow(element) {
|
| 326 |
+
const valueNow = element.getAttribute('aria-valuenow');
|
| 327 |
+
return valueNow === null ? undefined : +valueNow;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
/**
|
| 331 |
+
* @param {Element} element -
|
| 332 |
+
* @returns {number | undefined} -
|
| 333 |
+
*/
|
| 334 |
+
function computeAriaValueMax(element) {
|
| 335 |
+
const valueMax = element.getAttribute('aria-valuemax');
|
| 336 |
+
return valueMax === null ? undefined : +valueMax;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
/**
|
| 340 |
+
* @param {Element} element -
|
| 341 |
+
* @returns {number | undefined} -
|
| 342 |
+
*/
|
| 343 |
+
function computeAriaValueMin(element) {
|
| 344 |
+
const valueMin = element.getAttribute('aria-valuemin');
|
| 345 |
+
return valueMin === null ? undefined : +valueMin;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
/**
|
| 349 |
+
* @param {Element} element -
|
| 350 |
+
* @returns {string | undefined} -
|
| 351 |
+
*/
|
| 352 |
+
function computeAriaValueText(element) {
|
| 353 |
+
const valueText = element.getAttribute('aria-valuetext');
|
| 354 |
+
return valueText === null ? undefined : valueText;
|
| 355 |
+
}
|
node_modules/@testing-library/dom/dist/screen.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
| 4 |
+
Object.defineProperty(exports, "__esModule", {
|
| 5 |
+
value: true
|
| 6 |
+
});
|
| 7 |
+
exports.screen = void 0;
|
| 8 |
+
var _lzString = _interopRequireDefault(require("lz-string"));
|
| 9 |
+
var _getQueriesForElement = require("./get-queries-for-element");
|
| 10 |
+
var _helpers = require("./helpers");
|
| 11 |
+
var _prettyDom = require("./pretty-dom");
|
| 12 |
+
var queries = _interopRequireWildcard(require("./queries"));
|
| 13 |
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
| 14 |
+
// WARNING: `lz-string` only has a default export but statically we assume named exports are allowed
|
| 15 |
+
// TODO: Statically verify we don't rely on NodeJS implicit named imports.
|
| 16 |
+
|
| 17 |
+
function unindent(string) {
|
| 18 |
+
// remove white spaces first, to save a few bytes.
|
| 19 |
+
// testing-playground will reformat on load any ways.
|
| 20 |
+
return string.replace(/[ \t]*[\n][ \t]*/g, '\n');
|
| 21 |
+
}
|
| 22 |
+
function encode(value) {
|
| 23 |
+
return _lzString.default.compressToEncodedURIComponent(unindent(value));
|
| 24 |
+
}
|
| 25 |
+
function getPlaygroundUrl(markup) {
|
| 26 |
+
return `https://testing-playground.com/#markup=${encode(markup)}`;
|
| 27 |
+
}
|
| 28 |
+
const debug = (element, maxLength, options) => Array.isArray(element) ? element.forEach(el => (0, _prettyDom.logDOM)(el, maxLength, options)) : (0, _prettyDom.logDOM)(element, maxLength, options);
|
| 29 |
+
const logTestingPlaygroundURL = (element = (0, _helpers.getDocument)().body) => {
|
| 30 |
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
| 31 |
+
if (!element || !('innerHTML' in element)) {
|
| 32 |
+
console.log(`The element you're providing isn't a valid DOM element.`);
|
| 33 |
+
return;
|
| 34 |
+
}
|
| 35 |
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
| 36 |
+
if (!element.innerHTML) {
|
| 37 |
+
console.log(`The provided element doesn't have any children.`);
|
| 38 |
+
return;
|
| 39 |
+
}
|
| 40 |
+
const playgroundUrl = getPlaygroundUrl(element.innerHTML);
|
| 41 |
+
console.log(`Open this URL in your browser\n\n${playgroundUrl}`);
|
| 42 |
+
return playgroundUrl;
|
| 43 |
+
};
|
| 44 |
+
const initialValue = {
|
| 45 |
+
debug,
|
| 46 |
+
logTestingPlaygroundURL
|
| 47 |
+
};
|
| 48 |
+
const screen = exports.screen = typeof document !== 'undefined' && document.body // eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
| 49 |
+
? (0, _getQueriesForElement.getQueriesForElement)(document.body, queries, initialValue) : Object.keys(queries).reduce((helpers, key) => {
|
| 50 |
+
// `key` is for all intents and purposes the type of keyof `helpers`, which itself is the type of `initialValue` plus incoming properties from `queries`
|
| 51 |
+
// if `Object.keys(something)` returned Array<keyof typeof something> this explicit type assertion would not be necessary
|
| 52 |
+
// see https://stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript
|
| 53 |
+
helpers[key] = () => {
|
| 54 |
+
throw new TypeError('For queries bound to document.body a global document has to be available... Learn more: https://testing-library.com/s/screen-global-error');
|
| 55 |
+
};
|
| 56 |
+
return helpers;
|
| 57 |
+
}, initialValue);
|
node_modules/@testing-library/dom/dist/suggestions.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.getSuggestedQuery = getSuggestedQuery;
|
| 7 |
+
var _domAccessibilityApi = require("dom-accessibility-api");
|
| 8 |
+
var _matches = require("./matches");
|
| 9 |
+
var _getNodeText = require("./get-node-text");
|
| 10 |
+
var _config = require("./config");
|
| 11 |
+
var _roleHelpers = require("./role-helpers");
|
| 12 |
+
var _labelHelpers = require("./label-helpers");
|
| 13 |
+
const normalize = (0, _matches.getDefaultNormalizer)();
|
| 14 |
+
function escapeRegExp(string) {
|
| 15 |
+
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
| 16 |
+
}
|
| 17 |
+
function getRegExpMatcher(string) {
|
| 18 |
+
return new RegExp(escapeRegExp(string.toLowerCase()), 'i');
|
| 19 |
+
}
|
| 20 |
+
function makeSuggestion(queryName, element, content, {
|
| 21 |
+
variant,
|
| 22 |
+
name
|
| 23 |
+
}) {
|
| 24 |
+
let warning = '';
|
| 25 |
+
const queryOptions = {};
|
| 26 |
+
const queryArgs = [['Role', 'TestId'].includes(queryName) ? content : getRegExpMatcher(content)];
|
| 27 |
+
if (name) {
|
| 28 |
+
queryOptions.name = getRegExpMatcher(name);
|
| 29 |
+
}
|
| 30 |
+
if (queryName === 'Role' && (0, _roleHelpers.isInaccessible)(element)) {
|
| 31 |
+
queryOptions.hidden = true;
|
| 32 |
+
warning = `Element is inaccessible. This means that the element and all its children are invisible to screen readers.
|
| 33 |
+
If you are using the aria-hidden prop, make sure this is the right choice for your case.
|
| 34 |
+
`;
|
| 35 |
+
}
|
| 36 |
+
if (Object.keys(queryOptions).length > 0) {
|
| 37 |
+
queryArgs.push(queryOptions);
|
| 38 |
+
}
|
| 39 |
+
const queryMethod = `${variant}By${queryName}`;
|
| 40 |
+
return {
|
| 41 |
+
queryName,
|
| 42 |
+
queryMethod,
|
| 43 |
+
queryArgs,
|
| 44 |
+
variant,
|
| 45 |
+
warning,
|
| 46 |
+
toString() {
|
| 47 |
+
if (warning) {
|
| 48 |
+
console.warn(warning);
|
| 49 |
+
}
|
| 50 |
+
let [text, options] = queryArgs;
|
| 51 |
+
text = typeof text === 'string' ? `'${text}'` : text;
|
| 52 |
+
options = options ? `, { ${Object.entries(options).map(([k, v]) => `${k}: ${v}`).join(', ')} }` : '';
|
| 53 |
+
return `${queryMethod}(${text}${options})`;
|
| 54 |
+
}
|
| 55 |
+
};
|
| 56 |
+
}
|
| 57 |
+
function canSuggest(currentMethod, requestedMethod, data) {
|
| 58 |
+
return data && (!requestedMethod || requestedMethod.toLowerCase() === currentMethod.toLowerCase());
|
| 59 |
+
}
|
| 60 |
+
function getSuggestedQuery(element, variant = 'get', method) {
|
| 61 |
+
// don't create suggestions for script and style elements
|
| 62 |
+
if (element.matches((0, _config.getConfig)().defaultIgnore)) {
|
| 63 |
+
return undefined;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
//We prefer to suggest something else if the role is generic
|
| 67 |
+
const role = element.getAttribute('role') ?? (0, _roleHelpers.getImplicitAriaRoles)(element)?.[0];
|
| 68 |
+
if (role !== 'generic' && canSuggest('Role', method, role)) {
|
| 69 |
+
return makeSuggestion('Role', element, role, {
|
| 70 |
+
variant,
|
| 71 |
+
name: (0, _domAccessibilityApi.computeAccessibleName)(element, {
|
| 72 |
+
computedStyleSupportsPseudoElements: (0, _config.getConfig)().computedStyleSupportsPseudoElements
|
| 73 |
+
})
|
| 74 |
+
});
|
| 75 |
+
}
|
| 76 |
+
const labelText = (0, _labelHelpers.getLabels)(document, element).map(label => label.content).join(' ');
|
| 77 |
+
if (canSuggest('LabelText', method, labelText)) {
|
| 78 |
+
return makeSuggestion('LabelText', element, labelText, {
|
| 79 |
+
variant
|
| 80 |
+
});
|
| 81 |
+
}
|
| 82 |
+
const placeholderText = element.getAttribute('placeholder');
|
| 83 |
+
if (canSuggest('PlaceholderText', method, placeholderText)) {
|
| 84 |
+
return makeSuggestion('PlaceholderText', element, placeholderText, {
|
| 85 |
+
variant
|
| 86 |
+
});
|
| 87 |
+
}
|
| 88 |
+
const textContent = normalize((0, _getNodeText.getNodeText)(element));
|
| 89 |
+
if (canSuggest('Text', method, textContent)) {
|
| 90 |
+
return makeSuggestion('Text', element, textContent, {
|
| 91 |
+
variant
|
| 92 |
+
});
|
| 93 |
+
}
|
| 94 |
+
if (canSuggest('DisplayValue', method, element.value)) {
|
| 95 |
+
return makeSuggestion('DisplayValue', element, normalize(element.value), {
|
| 96 |
+
variant
|
| 97 |
+
});
|
| 98 |
+
}
|
| 99 |
+
const alt = element.getAttribute('alt');
|
| 100 |
+
if (canSuggest('AltText', method, alt)) {
|
| 101 |
+
return makeSuggestion('AltText', element, alt, {
|
| 102 |
+
variant
|
| 103 |
+
});
|
| 104 |
+
}
|
| 105 |
+
const title = element.getAttribute('title');
|
| 106 |
+
if (canSuggest('Title', method, title)) {
|
| 107 |
+
return makeSuggestion('Title', element, title, {
|
| 108 |
+
variant
|
| 109 |
+
});
|
| 110 |
+
}
|
| 111 |
+
const testId = element.getAttribute((0, _config.getConfig)().testIdAttribute);
|
| 112 |
+
if (canSuggest('TestId', method, testId)) {
|
| 113 |
+
return makeSuggestion('TestId', element, testId, {
|
| 114 |
+
variant
|
| 115 |
+
});
|
| 116 |
+
}
|
| 117 |
+
return undefined;
|
| 118 |
+
}
|
node_modules/@testing-library/dom/dist/wait-for-element-to-be-removed.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.waitForElementToBeRemoved = waitForElementToBeRemoved;
|
| 7 |
+
var _waitFor = require("./wait-for");
|
| 8 |
+
const isRemoved = result => !result || Array.isArray(result) && !result.length;
|
| 9 |
+
|
| 10 |
+
// Check if the element is not present.
|
| 11 |
+
// As the name implies, waitForElementToBeRemoved should check `present` --> `removed`
|
| 12 |
+
function initialCheck(elements) {
|
| 13 |
+
if (isRemoved(elements)) {
|
| 14 |
+
throw new Error('The element(s) given to waitForElementToBeRemoved are already removed. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.');
|
| 15 |
+
}
|
| 16 |
+
}
|
| 17 |
+
async function waitForElementToBeRemoved(callback, options) {
|
| 18 |
+
// created here so we get a nice stacktrace
|
| 19 |
+
const timeoutError = new Error('Timed out in waitForElementToBeRemoved.');
|
| 20 |
+
if (typeof callback !== 'function') {
|
| 21 |
+
initialCheck(callback);
|
| 22 |
+
const elements = Array.isArray(callback) ? callback : [callback];
|
| 23 |
+
const getRemainingElements = elements.map(element => {
|
| 24 |
+
let parent = element.parentElement;
|
| 25 |
+
if (parent === null) return () => null;
|
| 26 |
+
while (parent.parentElement) parent = parent.parentElement;
|
| 27 |
+
return () => parent.contains(element) ? element : null;
|
| 28 |
+
});
|
| 29 |
+
callback = () => getRemainingElements.map(c => c()).filter(Boolean);
|
| 30 |
+
}
|
| 31 |
+
initialCheck(callback());
|
| 32 |
+
return (0, _waitFor.waitFor)(() => {
|
| 33 |
+
let result;
|
| 34 |
+
try {
|
| 35 |
+
result = callback();
|
| 36 |
+
} catch (error) {
|
| 37 |
+
if (error.name === 'TestingLibraryElementError') {
|
| 38 |
+
return undefined;
|
| 39 |
+
}
|
| 40 |
+
throw error;
|
| 41 |
+
}
|
| 42 |
+
if (!isRemoved(result)) {
|
| 43 |
+
throw timeoutError;
|
| 44 |
+
}
|
| 45 |
+
return undefined;
|
| 46 |
+
}, options);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/*
|
| 50 |
+
eslint
|
| 51 |
+
require-await: "off"
|
| 52 |
+
*/
|
node_modules/@testing-library/dom/dist/wait-for.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";
|
| 2 |
+
|
| 3 |
+
Object.defineProperty(exports, "__esModule", {
|
| 4 |
+
value: true
|
| 5 |
+
});
|
| 6 |
+
exports.waitFor = waitForWrapper;
|
| 7 |
+
var _helpers = require("./helpers");
|
| 8 |
+
var _config = require("./config");
|
| 9 |
+
// This is so the stack trace the developer sees is one that's
|
| 10 |
+
// closer to their code (because async stack traces are hard to follow).
|
| 11 |
+
function copyStackTrace(target, source) {
|
| 12 |
+
target.stack = source.stack.replace(source.message, target.message);
|
| 13 |
+
}
|
| 14 |
+
function waitFor(callback, {
|
| 15 |
+
container = (0, _helpers.getDocument)(),
|
| 16 |
+
timeout = (0, _config.getConfig)().asyncUtilTimeout,
|
| 17 |
+
showOriginalStackTrace = (0, _config.getConfig)().showOriginalStackTrace,
|
| 18 |
+
stackTraceError,
|
| 19 |
+
interval = 50,
|
| 20 |
+
onTimeout = error => {
|
| 21 |
+
Object.defineProperty(error, 'message', {
|
| 22 |
+
value: (0, _config.getConfig)().getElementError(error.message, container).message
|
| 23 |
+
});
|
| 24 |
+
return error;
|
| 25 |
+
},
|
| 26 |
+
mutationObserverOptions = {
|
| 27 |
+
subtree: true,
|
| 28 |
+
childList: true,
|
| 29 |
+
attributes: true,
|
| 30 |
+
characterData: true
|
| 31 |
+
}
|
| 32 |
+
}) {
|
| 33 |
+
if (typeof callback !== 'function') {
|
| 34 |
+
throw new TypeError('Received `callback` arg must be a function');
|
| 35 |
+
}
|
| 36 |
+
return new Promise(async (resolve, reject) => {
|
| 37 |
+
let lastError, intervalId, observer;
|
| 38 |
+
let finished = false;
|
| 39 |
+
let promiseStatus = 'idle';
|
| 40 |
+
const overallTimeoutTimer = setTimeout(handleTimeout, timeout);
|
| 41 |
+
const usingJestFakeTimers = (0, _helpers.jestFakeTimersAreEnabled)();
|
| 42 |
+
if (usingJestFakeTimers) {
|
| 43 |
+
const {
|
| 44 |
+
unstable_advanceTimersWrapper: advanceTimersWrapper
|
| 45 |
+
} = (0, _config.getConfig)();
|
| 46 |
+
checkCallback();
|
| 47 |
+
// this is a dangerous rule to disable because it could lead to an
|
| 48 |
+
// infinite loop. However, eslint isn't smart enough to know that we're
|
| 49 |
+
// setting finished inside `onDone` which will be called when we're done
|
| 50 |
+
// waiting or when we've timed out.
|
| 51 |
+
// eslint-disable-next-line no-unmodified-loop-condition
|
| 52 |
+
while (!finished) {
|
| 53 |
+
if (!(0, _helpers.jestFakeTimersAreEnabled)()) {
|
| 54 |
+
const error = new Error(`Changed from using fake timers to real timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to real timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830`);
|
| 55 |
+
if (!showOriginalStackTrace) copyStackTrace(error, stackTraceError);
|
| 56 |
+
reject(error);
|
| 57 |
+
return;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
// In this rare case, we *need* to wait for in-flight promises
|
| 61 |
+
// to resolve before continuing. We don't need to take advantage
|
| 62 |
+
// of parallelization so we're fine.
|
| 63 |
+
// https://stackoverflow.com/a/59243586/971592
|
| 64 |
+
// eslint-disable-next-line no-await-in-loop
|
| 65 |
+
await advanceTimersWrapper(async () => {
|
| 66 |
+
// we *could* (maybe should?) use `advanceTimersToNextTimer` but it's
|
| 67 |
+
// possible that could make this loop go on forever if someone is using
|
| 68 |
+
// third party code that's setting up recursive timers so rapidly that
|
| 69 |
+
// the user's timer's don't get a chance to resolve. So we'll advance
|
| 70 |
+
// by an interval instead. (We have a test for this case).
|
| 71 |
+
jest.advanceTimersByTime(interval);
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
// Could have timed-out
|
| 75 |
+
if (finished) {
|
| 76 |
+
break;
|
| 77 |
+
}
|
| 78 |
+
// It's really important that checkCallback is run *before* we flush
|
| 79 |
+
// in-flight promises. To be honest, I'm not sure why, and I can't quite
|
| 80 |
+
// think of a way to reproduce the problem in a test, but I spent
|
| 81 |
+
// an entire day banging my head against a wall on this.
|
| 82 |
+
checkCallback();
|
| 83 |
+
}
|
| 84 |
+
} else {
|
| 85 |
+
try {
|
| 86 |
+
(0, _helpers.checkContainerType)(container);
|
| 87 |
+
} catch (e) {
|
| 88 |
+
reject(e);
|
| 89 |
+
return;
|
| 90 |
+
}
|
| 91 |
+
intervalId = setInterval(checkRealTimersCallback, interval);
|
| 92 |
+
const {
|
| 93 |
+
MutationObserver
|
| 94 |
+
} = (0, _helpers.getWindowFromNode)(container);
|
| 95 |
+
observer = new MutationObserver(checkRealTimersCallback);
|
| 96 |
+
observer.observe(container, mutationObserverOptions);
|
| 97 |
+
checkCallback();
|
| 98 |
+
}
|
| 99 |
+
function onDone(error, result) {
|
| 100 |
+
finished = true;
|
| 101 |
+
clearTimeout(overallTimeoutTimer);
|
| 102 |
+
if (!usingJestFakeTimers) {
|
| 103 |
+
clearInterval(intervalId);
|
| 104 |
+
observer.disconnect();
|
| 105 |
+
}
|
| 106 |
+
if (error) {
|
| 107 |
+
reject(error);
|
| 108 |
+
} else {
|
| 109 |
+
resolve(result);
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
function checkRealTimersCallback() {
|
| 113 |
+
if ((0, _helpers.jestFakeTimersAreEnabled)()) {
|
| 114 |
+
const error = new Error(`Changed from using real timers to fake timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to fake timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830`);
|
| 115 |
+
if (!showOriginalStackTrace) copyStackTrace(error, stackTraceError);
|
| 116 |
+
return reject(error);
|
| 117 |
+
} else {
|
| 118 |
+
return checkCallback();
|
| 119 |
+
}
|
| 120 |
+
}
|
| 121 |
+
function checkCallback() {
|
| 122 |
+
if (promiseStatus === 'pending') return;
|
| 123 |
+
try {
|
| 124 |
+
const result = (0, _config.runWithExpensiveErrorDiagnosticsDisabled)(callback);
|
| 125 |
+
if (typeof result?.then === 'function') {
|
| 126 |
+
promiseStatus = 'pending';
|
| 127 |
+
result.then(resolvedValue => {
|
| 128 |
+
promiseStatus = 'resolved';
|
| 129 |
+
onDone(null, resolvedValue);
|
| 130 |
+
}, rejectedValue => {
|
| 131 |
+
promiseStatus = 'rejected';
|
| 132 |
+
lastError = rejectedValue;
|
| 133 |
+
});
|
| 134 |
+
} else {
|
| 135 |
+
onDone(null, result);
|
| 136 |
+
}
|
| 137 |
+
// If `callback` throws, wait for the next mutation, interval, or timeout.
|
| 138 |
+
} catch (error) {
|
| 139 |
+
// Save the most recent callback error to reject the promise with it in the event of a timeout
|
| 140 |
+
lastError = error;
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
function handleTimeout() {
|
| 144 |
+
let error;
|
| 145 |
+
if (lastError) {
|
| 146 |
+
error = lastError;
|
| 147 |
+
if (!showOriginalStackTrace && error.name === 'TestingLibraryElementError') {
|
| 148 |
+
copyStackTrace(error, stackTraceError);
|
| 149 |
+
}
|
| 150 |
+
} else {
|
| 151 |
+
error = new Error('Timed out in waitFor.');
|
| 152 |
+
if (!showOriginalStackTrace) {
|
| 153 |
+
copyStackTrace(error, stackTraceError);
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
onDone(onTimeout(error), null);
|
| 157 |
+
}
|
| 158 |
+
});
|
| 159 |
+
}
|
| 160 |
+
function waitForWrapper(callback, options) {
|
| 161 |
+
// create the error here so its stack trace is as close to the
|
| 162 |
+
// calling code as possible
|
| 163 |
+
const stackTraceError = new Error('STACK_TRACE_MESSAGE');
|
| 164 |
+
return (0, _config.getConfig)().asyncWrapper(() => waitFor(callback, {
|
| 165 |
+
stackTraceError,
|
| 166 |
+
...options
|
| 167 |
+
}));
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
/*
|
| 171 |
+
eslint
|
| 172 |
+
max-lines-per-function: ["error", {"max": 200}],
|
| 173 |
+
*/
|
node_modules/@testing-library/dom/package.json
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "@testing-library/dom",
|
| 3 |
+
"version": "10.4.1",
|
| 4 |
+
"description": "Simple and complete DOM testing utilities that encourage good testing practices.",
|
| 5 |
+
"main": "dist/index.js",
|
| 6 |
+
"types": "types/index.d.ts",
|
| 7 |
+
"module": "dist/@testing-library/dom.esm.js",
|
| 8 |
+
"umd:main": "dist/@testing-library/dom.umd.js",
|
| 9 |
+
"source": "src/index.js",
|
| 10 |
+
"keywords": [
|
| 11 |
+
"testing",
|
| 12 |
+
"ui",
|
| 13 |
+
"dom",
|
| 14 |
+
"jsdom",
|
| 15 |
+
"unit",
|
| 16 |
+
"integration",
|
| 17 |
+
"functional",
|
| 18 |
+
"end-to-end",
|
| 19 |
+
"e2e"
|
| 20 |
+
],
|
| 21 |
+
"author": "Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)",
|
| 22 |
+
"license": "MIT",
|
| 23 |
+
"engines": {
|
| 24 |
+
"node": ">=18"
|
| 25 |
+
},
|
| 26 |
+
"browserslist": [
|
| 27 |
+
"and_chr 103",
|
| 28 |
+
"and_ff 101",
|
| 29 |
+
"and_qq 10.4",
|
| 30 |
+
"and_uc 12.12",
|
| 31 |
+
"android 103",
|
| 32 |
+
"chrome 102",
|
| 33 |
+
"edge 102",
|
| 34 |
+
"firefox 91",
|
| 35 |
+
"ios_saf 12.2-12.5",
|
| 36 |
+
"kaios 2.5",
|
| 37 |
+
"op_mini all",
|
| 38 |
+
"op_mob 64",
|
| 39 |
+
"opera 88",
|
| 40 |
+
"safari 15.5",
|
| 41 |
+
"samsung 17.0",
|
| 42 |
+
"samsung 16.0",
|
| 43 |
+
"node 18.0"
|
| 44 |
+
],
|
| 45 |
+
"scripts": {
|
| 46 |
+
"build": "kcd-scripts build --no-ts-defs --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --no-ts-defs --bundle --no-clean",
|
| 47 |
+
"format": "kcd-scripts format",
|
| 48 |
+
"install:csb": "npm install",
|
| 49 |
+
"lint": "kcd-scripts lint",
|
| 50 |
+
"setup": "npm install && npm run validate -s",
|
| 51 |
+
"test": "kcd-scripts test",
|
| 52 |
+
"test:debug": "node --inspect-brk ./node_modules/.bin/jest --watch --runInBand",
|
| 53 |
+
"test:update": "npm test -- --updateSnapshot --coverage",
|
| 54 |
+
"validate": "kcd-scripts validate",
|
| 55 |
+
"typecheck": "kcd-scripts typecheck --build types"
|
| 56 |
+
},
|
| 57 |
+
"files": [
|
| 58 |
+
"dist",
|
| 59 |
+
"types/*.d.ts"
|
| 60 |
+
],
|
| 61 |
+
"dependencies": {
|
| 62 |
+
"@babel/code-frame": "^7.10.4",
|
| 63 |
+
"@babel/runtime": "^7.12.5",
|
| 64 |
+
"@types/aria-query": "^5.0.1",
|
| 65 |
+
"aria-query": "5.3.0",
|
| 66 |
+
"dom-accessibility-api": "^0.5.9",
|
| 67 |
+
"lz-string": "^1.5.0",
|
| 68 |
+
"picocolors": "1.1.1",
|
| 69 |
+
"pretty-format": "^27.0.2"
|
| 70 |
+
},
|
| 71 |
+
"devDependencies": {
|
| 72 |
+
"@testing-library/jest-dom": "^5.11.6",
|
| 73 |
+
"browserslist": "4.21.8",
|
| 74 |
+
"caniuse-lite": "1.0.30001502",
|
| 75 |
+
"jest-in-case": "^1.0.2",
|
| 76 |
+
"jest-snapshot-serializer-ansi": "^1.0.0",
|
| 77 |
+
"jest-watch-select-projects": "^2.0.0",
|
| 78 |
+
"jsdom": "20.0.0",
|
| 79 |
+
"kcd-scripts": "^13.0.0",
|
| 80 |
+
"typescript": "^4.1.2"
|
| 81 |
+
},
|
| 82 |
+
"overrides": {
|
| 83 |
+
"@babel/helper-compilation-targets": "7.24.7",
|
| 84 |
+
"browserslist": "4.21.8",
|
| 85 |
+
"caniuse-lite": "1.0.30001502"
|
| 86 |
+
},
|
| 87 |
+
"eslintConfig": {
|
| 88 |
+
"extends": [
|
| 89 |
+
"./node_modules/kcd-scripts/eslint.js",
|
| 90 |
+
"plugin:import/typescript"
|
| 91 |
+
],
|
| 92 |
+
"parserOptions": {
|
| 93 |
+
"ecmaVersion": 2020
|
| 94 |
+
},
|
| 95 |
+
"rules": {
|
| 96 |
+
"@typescript-eslint/prefer-optional-chain": "off",
|
| 97 |
+
"@typescript-eslint/no-explicit-any": "off",
|
| 98 |
+
"@typescript-eslint/no-unsafe-member-access": "off",
|
| 99 |
+
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "off",
|
| 100 |
+
"@typescript-eslint/prefer-includes": "off",
|
| 101 |
+
"import/prefer-default-export": "off",
|
| 102 |
+
"import/no-unassigned-import": "off",
|
| 103 |
+
"import/no-useless-path-segments": "off",
|
| 104 |
+
"no-console": "off"
|
| 105 |
+
}
|
| 106 |
+
},
|
| 107 |
+
"eslintIgnore": [
|
| 108 |
+
"node_modules",
|
| 109 |
+
"coverage",
|
| 110 |
+
"dist"
|
| 111 |
+
],
|
| 112 |
+
"repository": {
|
| 113 |
+
"type": "git",
|
| 114 |
+
"url": "https://github.com/testing-library/dom-testing-library"
|
| 115 |
+
},
|
| 116 |
+
"bugs": {
|
| 117 |
+
"url": "https://github.com/testing-library/dom-testing-library/issues"
|
| 118 |
+
},
|
| 119 |
+
"homepage": "https://github.com/testing-library/dom-testing-library#readme"
|
| 120 |
+
}
|
node_modules/@testing-library/dom/types/config.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export interface Config {
|
| 2 |
+
testIdAttribute: string
|
| 3 |
+
/**
|
| 4 |
+
* WARNING: `unstable` prefix means this API may change in patch and minor releases.
|
| 5 |
+
* @param cb
|
| 6 |
+
*/
|
| 7 |
+
unstable_advanceTimersWrapper(cb: (...args: unknown[]) => unknown): unknown
|
| 8 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 9 |
+
asyncWrapper(cb: (...args: any[]) => any): Promise<any>
|
| 10 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 11 |
+
eventWrapper(cb: (...args: any[]) => any): void
|
| 12 |
+
asyncUtilTimeout: number
|
| 13 |
+
computedStyleSupportsPseudoElements: boolean
|
| 14 |
+
defaultHidden: boolean
|
| 15 |
+
/** default value for the `ignore` option in `ByText` queries */
|
| 16 |
+
defaultIgnore: string
|
| 17 |
+
showOriginalStackTrace: boolean
|
| 18 |
+
throwSuggestions: boolean
|
| 19 |
+
getElementError: (message: string | null, container: Element) => Error
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
export interface ConfigFn {
|
| 23 |
+
(existingConfig: Config): Partial<Config>
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
export function configure(configDelta: ConfigFn | Partial<Config>): void
|
| 27 |
+
export function getConfig(): Config
|
node_modules/@testing-library/dom/types/events.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export type EventType =
|
| 2 |
+
| 'copy'
|
| 3 |
+
| 'cut'
|
| 4 |
+
| 'paste'
|
| 5 |
+
| 'compositionEnd'
|
| 6 |
+
| 'compositionStart'
|
| 7 |
+
| 'compositionUpdate'
|
| 8 |
+
| 'keyDown'
|
| 9 |
+
| 'keyPress'
|
| 10 |
+
| 'keyUp'
|
| 11 |
+
| 'focus'
|
| 12 |
+
| 'blur'
|
| 13 |
+
| 'focusIn'
|
| 14 |
+
| 'focusOut'
|
| 15 |
+
| 'change'
|
| 16 |
+
| 'input'
|
| 17 |
+
| 'invalid'
|
| 18 |
+
| 'submit'
|
| 19 |
+
| 'reset'
|
| 20 |
+
| 'click'
|
| 21 |
+
| 'contextMenu'
|
| 22 |
+
| 'dblClick'
|
| 23 |
+
| 'drag'
|
| 24 |
+
| 'dragEnd'
|
| 25 |
+
| 'dragEnter'
|
| 26 |
+
| 'dragExit'
|
| 27 |
+
| 'dragLeave'
|
| 28 |
+
| 'dragOver'
|
| 29 |
+
| 'dragStart'
|
| 30 |
+
| 'drop'
|
| 31 |
+
| 'mouseDown'
|
| 32 |
+
| 'mouseEnter'
|
| 33 |
+
| 'mouseLeave'
|
| 34 |
+
| 'mouseMove'
|
| 35 |
+
| 'mouseOut'
|
| 36 |
+
| 'mouseOver'
|
| 37 |
+
| 'mouseUp'
|
| 38 |
+
| 'popState'
|
| 39 |
+
| 'select'
|
| 40 |
+
| 'touchCancel'
|
| 41 |
+
| 'touchEnd'
|
| 42 |
+
| 'touchMove'
|
| 43 |
+
| 'touchStart'
|
| 44 |
+
| 'resize'
|
| 45 |
+
| 'scroll'
|
| 46 |
+
| 'wheel'
|
| 47 |
+
| 'abort'
|
| 48 |
+
| 'canPlay'
|
| 49 |
+
| 'canPlayThrough'
|
| 50 |
+
| 'durationChange'
|
| 51 |
+
| 'emptied'
|
| 52 |
+
| 'encrypted'
|
| 53 |
+
| 'ended'
|
| 54 |
+
| 'loadedData'
|
| 55 |
+
| 'loadedMetadata'
|
| 56 |
+
| 'loadStart'
|
| 57 |
+
| 'pause'
|
| 58 |
+
| 'play'
|
| 59 |
+
| 'playing'
|
| 60 |
+
| 'progress'
|
| 61 |
+
| 'rateChange'
|
| 62 |
+
| 'seeked'
|
| 63 |
+
| 'seeking'
|
| 64 |
+
| 'stalled'
|
| 65 |
+
| 'suspend'
|
| 66 |
+
| 'timeUpdate'
|
| 67 |
+
| 'volumeChange'
|
| 68 |
+
| 'waiting'
|
| 69 |
+
| 'load'
|
| 70 |
+
| 'error'
|
| 71 |
+
| 'animationStart'
|
| 72 |
+
| 'animationEnd'
|
| 73 |
+
| 'animationIteration'
|
| 74 |
+
| 'transitionCancel'
|
| 75 |
+
| 'transitionEnd'
|
| 76 |
+
| 'transitionRun'
|
| 77 |
+
| 'transitionStart'
|
| 78 |
+
| 'doubleClick'
|
| 79 |
+
| 'pointerOver'
|
| 80 |
+
| 'pointerEnter'
|
| 81 |
+
| 'pointerDown'
|
| 82 |
+
| 'pointerMove'
|
| 83 |
+
| 'pointerUp'
|
| 84 |
+
| 'pointerCancel'
|
| 85 |
+
| 'pointerOut'
|
| 86 |
+
| 'pointerLeave'
|
| 87 |
+
| 'gotPointerCapture'
|
| 88 |
+
| 'lostPointerCapture'
|
| 89 |
+
| 'offline'
|
| 90 |
+
| 'online'
|
| 91 |
+
| 'pageHide'
|
| 92 |
+
| 'pageShow'
|
| 93 |
+
|
| 94 |
+
export type FireFunction = (
|
| 95 |
+
element: Document | Element | Window | Node,
|
| 96 |
+
event: Event,
|
| 97 |
+
) => boolean
|
| 98 |
+
export type FireObject = {
|
| 99 |
+
[K in EventType]: (
|
| 100 |
+
element: Document | Element | Window | Node,
|
| 101 |
+
options?: {},
|
| 102 |
+
) => boolean
|
| 103 |
+
}
|
| 104 |
+
export type CreateFunction = (
|
| 105 |
+
eventName: string,
|
| 106 |
+
node: Document | Element | Window | Node,
|
| 107 |
+
init?: {},
|
| 108 |
+
options?: {EventType?: string; defaultInit?: {}},
|
| 109 |
+
) => Event
|
| 110 |
+
export type CreateObject = {
|
| 111 |
+
[K in EventType]: (
|
| 112 |
+
element: Document | Element | Window | Node,
|
| 113 |
+
options?: {},
|
| 114 |
+
) => Event
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
export const createEvent: CreateObject & CreateFunction
|
| 118 |
+
export const fireEvent: FireFunction & FireObject
|
node_modules/@testing-library/dom/types/get-node-text.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
export function getNodeText(node: HTMLElement): string
|