Fix `tabbable` performance issues in Chrome / Edge (#1614)

* fix: improve tabbable performance

* add note about composed-offset-position

* update package.json

* prettier

* prettier

* prettier
pull/1655/head
Konnor Rogers 2023-10-16 12:30:34 -04:00 zatwierdzone przez GitHub
rodzic ff94ea2e0c
commit 2643e4ff9e
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 26 dodań i 10 usunięć

Wyświetl plik

@ -25,8 +25,15 @@
"./dist/react/*": "./dist/react/*",
"./dist/translations/*": "./dist/translations/*"
},
"files": ["dist", "cdn"],
"keywords": ["web components", "custom elements", "components"],
"files": [
"dist",
"cdn"
],
"keywords": [
"web components",
"custom elements",
"components"
],
"repository": {
"type": "git",
"url": "git+https://github.com/shoelace-style/shoelace.git"
@ -43,8 +50,8 @@
"build": "node scripts/build.js",
"verify": "npm run prettier:check && npm run lint && npm run build && npm run test",
"prepublishOnly": "npm run verify",
"prettier": "prettier --write --loglevel warn .",
"prettier:check": "prettier --check --loglevel warn .",
"prettier": "prettier --write --log-level=warn .",
"prettier:check": "prettier --check --log-level=warn .",
"lint": "eslint src --max-warnings 0",
"lint:fix": "eslint src --max-warnings 0 --fix",
"ts-check": "tsc --noEmit --project ./tsconfig.json",
@ -133,6 +140,9 @@
"user-agent-data-types": "^0.3.1"
},
"lint-staged": {
"*.{ts,js}": ["eslint --max-warnings 0 --cache --fix", "prettier --write"]
"*.{ts,js}": [
"eslint --max-warnings 0 --cache --fix",
"prettier --write"
]
}
}

Wyświetl plik

@ -87,7 +87,7 @@ export default class Modal {
if (currentFocusIndex === -1) {
this.currentFocus = tabbableElements[0];
this.currentFocus.focus({ preventScroll: true });
this.currentFocus?.focus({ preventScroll: true });
return;
}

Wyświetl plik

@ -1,5 +1,11 @@
import { offsetParent } from 'composed-offset-position';
// It doesn't technically check visibility, it checks if the element has been rendered and can maybe possibly be tabbed to.
// This is a workaround for shadowroots not having an `offsetParent`
// https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
// Previously, we used https://www.npmjs.com/package/composed-offset-position, but recursing up an entire
// node tree took up a lot of CPU cycles and made focus traps unusable in Chrome / Edge.
function isTakingUpSpace(elem: HTMLElement): boolean {
return Boolean(elem.offsetParent || elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
}
/** Determines if the specified element is tabbable using heuristics inspired by https://github.com/focus-trap/tabbable */
function isTabbable(el: HTMLElement) {
const tag = el.tagName.toLowerCase();
@ -20,8 +26,8 @@ function isTabbable(el: HTMLElement) {
}
// Elements that are hidden have no offsetParent and are not tabbable
// offsetParent() is added because otherwise it misses elements in Safari
if (el.offsetParent === null && offsetParent(el) === null) {
// !isRendered is added because otherwise it misses elements in Safari
if (!isTakingUpSpace(el)) {
return false;
}