worked on GarageApp stuff
This commit is contained in:
parent
60aaf17af3
commit
eb606572b0
51919 changed files with 2168177 additions and 18 deletions
333
node_modules/@mui/material/esm/Unstable_TrapFocus/FocusTrap.js
generated
vendored
Normal file
333
node_modules/@mui/material/esm/Unstable_TrapFocus/FocusTrap.js
generated
vendored
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
'use client';
|
||||
|
||||
/* eslint-disable consistent-return, jsx-a11y/no-noninteractive-tabindex */
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import useForkRef from '@mui/utils/useForkRef';
|
||||
import ownerDocument from '@mui/utils/ownerDocument';
|
||||
import getReactElementRef from '@mui/utils/getReactElementRef';
|
||||
import exactProp from '@mui/utils/exactProp';
|
||||
import elementAcceptingRef from '@mui/utils/elementAcceptingRef';
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
// Inspired by https://github.com/focus-trap/tabbable
|
||||
const candidatesSelector = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])'].join(',');
|
||||
function getTabIndex(node) {
|
||||
const tabindexAttr = parseInt(node.getAttribute('tabindex') || '', 10);
|
||||
if (!Number.isNaN(tabindexAttr)) {
|
||||
return tabindexAttr;
|
||||
}
|
||||
|
||||
// Browsers do not return `tabIndex` correctly for contentEditable nodes;
|
||||
// https://issues.chromium.org/issues/41283952
|
||||
// so if they don't have a tabindex attribute specifically set, assume it's 0.
|
||||
// in Chrome, <details/>, <audio controls/> and <video controls/> elements get a default
|
||||
// `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM,
|
||||
// yet they are still part of the regular tab order; in FF, they get a default
|
||||
// `tabIndex` of 0; since Chrome still puts those elements in the regular tab
|
||||
// order, consider their tab index to be 0.
|
||||
if (node.contentEditable === 'true' || (node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
|
||||
return 0;
|
||||
}
|
||||
return node.tabIndex;
|
||||
}
|
||||
function isNonTabbableRadio(node) {
|
||||
if (node.tagName !== 'INPUT' || node.type !== 'radio') {
|
||||
return false;
|
||||
}
|
||||
if (!node.name) {
|
||||
return false;
|
||||
}
|
||||
const getRadio = selector => node.ownerDocument.querySelector(`input[type="radio"]${selector}`);
|
||||
let roving = getRadio(`[name="${node.name}"]:checked`);
|
||||
if (!roving) {
|
||||
roving = getRadio(`[name="${node.name}"]`);
|
||||
}
|
||||
return roving !== node;
|
||||
}
|
||||
function isNodeMatchingSelectorFocusable(node) {
|
||||
if (node.disabled || node.tagName === 'INPUT' && node.type === 'hidden' || isNonTabbableRadio(node)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function defaultGetTabbable(root) {
|
||||
const regularTabNodes = [];
|
||||
const orderedTabNodes = [];
|
||||
Array.from(root.querySelectorAll(candidatesSelector)).forEach((node, i) => {
|
||||
const nodeTabIndex = getTabIndex(node);
|
||||
if (nodeTabIndex === -1 || !isNodeMatchingSelectorFocusable(node)) {
|
||||
return;
|
||||
}
|
||||
if (nodeTabIndex === 0) {
|
||||
regularTabNodes.push(node);
|
||||
} else {
|
||||
orderedTabNodes.push({
|
||||
documentOrder: i,
|
||||
tabIndex: nodeTabIndex,
|
||||
node: node
|
||||
});
|
||||
}
|
||||
});
|
||||
return orderedTabNodes.sort((a, b) => a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex).map(a => a.node).concat(regularTabNodes);
|
||||
}
|
||||
function defaultIsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore - internal component.
|
||||
*/
|
||||
function FocusTrap(props) {
|
||||
const {
|
||||
children,
|
||||
disableAutoFocus = false,
|
||||
disableEnforceFocus = false,
|
||||
disableRestoreFocus = false,
|
||||
getTabbable = defaultGetTabbable,
|
||||
isEnabled = defaultIsEnabled,
|
||||
open
|
||||
} = props;
|
||||
const ignoreNextEnforceFocus = React.useRef(false);
|
||||
const sentinelStart = React.useRef(null);
|
||||
const sentinelEnd = React.useRef(null);
|
||||
const nodeToRestore = React.useRef(null);
|
||||
const reactFocusEventTarget = React.useRef(null);
|
||||
// This variable is useful when disableAutoFocus is true.
|
||||
// It waits for the active element to move into the component to activate.
|
||||
const activated = React.useRef(false);
|
||||
const rootRef = React.useRef(null);
|
||||
const handleRef = useForkRef(getReactElementRef(children), rootRef);
|
||||
const lastKeydown = React.useRef(null);
|
||||
React.useEffect(() => {
|
||||
// We might render an empty child.
|
||||
if (!open || !rootRef.current) {
|
||||
return;
|
||||
}
|
||||
activated.current = !disableAutoFocus;
|
||||
}, [disableAutoFocus, open]);
|
||||
React.useEffect(() => {
|
||||
// We might render an empty child.
|
||||
if (!open || !rootRef.current) {
|
||||
return;
|
||||
}
|
||||
const doc = ownerDocument(rootRef.current);
|
||||
if (!rootRef.current.contains(doc.activeElement)) {
|
||||
if (!rootRef.current.hasAttribute('tabIndex')) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.error(['MUI: The modal content node does not accept focus.', 'For the benefit of assistive technologies, ' + 'the tabIndex of the node is being set to "-1".'].join('\n'));
|
||||
}
|
||||
rootRef.current.setAttribute('tabIndex', '-1');
|
||||
}
|
||||
if (activated.current) {
|
||||
rootRef.current.focus();
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
// restoreLastFocus()
|
||||
if (!disableRestoreFocus) {
|
||||
// In IE11 it is possible for document.activeElement to be null resulting
|
||||
// in nodeToRestore.current being null.
|
||||
// Not all elements in IE11 have a focus method.
|
||||
// Once IE11 support is dropped the focus() call can be unconditional.
|
||||
if (nodeToRestore.current && nodeToRestore.current.focus) {
|
||||
ignoreNextEnforceFocus.current = true;
|
||||
nodeToRestore.current.focus();
|
||||
}
|
||||
nodeToRestore.current = null;
|
||||
}
|
||||
};
|
||||
// Missing `disableRestoreFocus` which is fine.
|
||||
// We don't support changing that prop on an open FocusTrap
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open]);
|
||||
React.useEffect(() => {
|
||||
// We might render an empty child.
|
||||
if (!open || !rootRef.current) {
|
||||
return;
|
||||
}
|
||||
const doc = ownerDocument(rootRef.current);
|
||||
const loopFocus = nativeEvent => {
|
||||
lastKeydown.current = nativeEvent;
|
||||
if (disableEnforceFocus || !isEnabled() || nativeEvent.key !== 'Tab') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the next tab starts from the right place.
|
||||
// doc.activeElement refers to the origin.
|
||||
if (doc.activeElement === rootRef.current && nativeEvent.shiftKey) {
|
||||
// We need to ignore the next contain as
|
||||
// it will try to move the focus back to the rootRef element.
|
||||
ignoreNextEnforceFocus.current = true;
|
||||
if (sentinelEnd.current) {
|
||||
sentinelEnd.current.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
const contain = () => {
|
||||
const rootElement = rootRef.current;
|
||||
|
||||
// Cleanup functions are executed lazily in React 17.
|
||||
// Contain can be called between the component being unmounted and its cleanup function being run.
|
||||
if (rootElement === null) {
|
||||
return;
|
||||
}
|
||||
if (!doc.hasFocus() || !isEnabled() || ignoreNextEnforceFocus.current) {
|
||||
ignoreNextEnforceFocus.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// The focus is already inside
|
||||
if (rootElement.contains(doc.activeElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The disableEnforceFocus is set and the focus is outside of the focus trap (and sentinel nodes)
|
||||
if (disableEnforceFocus && doc.activeElement !== sentinelStart.current && doc.activeElement !== sentinelEnd.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the focus event is not coming from inside the children's react tree, reset the refs
|
||||
if (doc.activeElement !== reactFocusEventTarget.current) {
|
||||
reactFocusEventTarget.current = null;
|
||||
} else if (reactFocusEventTarget.current !== null) {
|
||||
return;
|
||||
}
|
||||
if (!activated.current) {
|
||||
return;
|
||||
}
|
||||
let tabbable = [];
|
||||
if (doc.activeElement === sentinelStart.current || doc.activeElement === sentinelEnd.current) {
|
||||
tabbable = getTabbable(rootRef.current);
|
||||
}
|
||||
|
||||
// one of the sentinel nodes was focused, so move the focus
|
||||
// to the first/last tabbable element inside the focus trap
|
||||
if (tabbable.length > 0) {
|
||||
const isShiftTab = Boolean(lastKeydown.current?.shiftKey && lastKeydown.current?.key === 'Tab');
|
||||
const focusNext = tabbable[0];
|
||||
const focusPrevious = tabbable[tabbable.length - 1];
|
||||
if (typeof focusNext !== 'string' && typeof focusPrevious !== 'string') {
|
||||
if (isShiftTab) {
|
||||
focusPrevious.focus();
|
||||
} else {
|
||||
focusNext.focus();
|
||||
}
|
||||
}
|
||||
// no tabbable elements in the trap focus or the focus was outside of the focus trap
|
||||
} else {
|
||||
rootElement.focus();
|
||||
}
|
||||
};
|
||||
doc.addEventListener('focusin', contain);
|
||||
doc.addEventListener('keydown', loopFocus, true);
|
||||
|
||||
// With Edge, Safari and Firefox, no focus related events are fired when the focused area stops being a focused area.
|
||||
// for example https://bugzilla.mozilla.org/show_bug.cgi?id=559561.
|
||||
// Instead, we can look if the active element was restored on the BODY element.
|
||||
//
|
||||
// The whatwg spec defines how the browser should behave but does not explicitly mention any events:
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#focus-fixup-rule.
|
||||
const interval = setInterval(() => {
|
||||
if (doc.activeElement && doc.activeElement.tagName === 'BODY') {
|
||||
contain();
|
||||
}
|
||||
}, 50);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
doc.removeEventListener('focusin', contain);
|
||||
doc.removeEventListener('keydown', loopFocus, true);
|
||||
};
|
||||
}, [disableAutoFocus, disableEnforceFocus, disableRestoreFocus, isEnabled, open, getTabbable]);
|
||||
const onFocus = event => {
|
||||
if (nodeToRestore.current === null) {
|
||||
nodeToRestore.current = event.relatedTarget;
|
||||
}
|
||||
activated.current = true;
|
||||
reactFocusEventTarget.current = event.target;
|
||||
const childrenPropsHandler = children.props.onFocus;
|
||||
if (childrenPropsHandler) {
|
||||
childrenPropsHandler(event);
|
||||
}
|
||||
};
|
||||
const handleFocusSentinel = event => {
|
||||
if (nodeToRestore.current === null) {
|
||||
nodeToRestore.current = event.relatedTarget;
|
||||
}
|
||||
activated.current = true;
|
||||
};
|
||||
return /*#__PURE__*/_jsxs(React.Fragment, {
|
||||
children: [/*#__PURE__*/_jsx("div", {
|
||||
tabIndex: open ? 0 : -1,
|
||||
onFocus: handleFocusSentinel,
|
||||
ref: sentinelStart,
|
||||
"data-testid": "sentinelStart"
|
||||
}), /*#__PURE__*/React.cloneElement(children, {
|
||||
ref: handleRef,
|
||||
onFocus
|
||||
}), /*#__PURE__*/_jsx("div", {
|
||||
tabIndex: open ? 0 : -1,
|
||||
onFocus: handleFocusSentinel,
|
||||
ref: sentinelEnd,
|
||||
"data-testid": "sentinelEnd"
|
||||
})]
|
||||
});
|
||||
}
|
||||
process.env.NODE_ENV !== "production" ? FocusTrap.propTypes /* remove-proptypes */ = {
|
||||
// ┌────────────────────────────── Warning ──────────────────────────────┐
|
||||
// │ These PropTypes are generated from the TypeScript type definitions. │
|
||||
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
|
||||
// └─────────────────────────────────────────────────────────────────────┘
|
||||
/**
|
||||
* A single child content element.
|
||||
*/
|
||||
children: elementAcceptingRef,
|
||||
/**
|
||||
* If `true`, the focus trap will not automatically shift focus to itself when it opens, and
|
||||
* replace it to the last focused element when it closes.
|
||||
* This also works correctly with any focus trap children that have the `disableAutoFocus` prop.
|
||||
*
|
||||
* Generally this should never be set to `true` as it makes the focus trap less
|
||||
* accessible to assistive technologies, like screen readers.
|
||||
* @default false
|
||||
*/
|
||||
disableAutoFocus: PropTypes.bool,
|
||||
/**
|
||||
* If `true`, the focus trap will not prevent focus from leaving the focus trap while open.
|
||||
*
|
||||
* Generally this should never be set to `true` as it makes the focus trap less
|
||||
* accessible to assistive technologies, like screen readers.
|
||||
* @default false
|
||||
*/
|
||||
disableEnforceFocus: PropTypes.bool,
|
||||
/**
|
||||
* If `true`, the focus trap will not restore focus to previously focused element once
|
||||
* focus trap is hidden or unmounted.
|
||||
* @default false
|
||||
*/
|
||||
disableRestoreFocus: PropTypes.bool,
|
||||
/**
|
||||
* Returns an array of ordered tabbable nodes (i.e. in tab order) within the root.
|
||||
* For instance, you can provide the "tabbable" npm dependency.
|
||||
* @param {HTMLElement} root
|
||||
*/
|
||||
getTabbable: PropTypes.func,
|
||||
/**
|
||||
* This prop extends the `open` prop.
|
||||
* It allows to toggle the open state without having to wait for a rerender when changing the `open` prop.
|
||||
* This prop should be memoized.
|
||||
* It can be used to support multiple focus trap mounted at the same time.
|
||||
* @default function defaultIsEnabled(): boolean {
|
||||
* return true;
|
||||
* }
|
||||
*/
|
||||
isEnabled: PropTypes.func,
|
||||
/**
|
||||
* If `true`, focus is locked.
|
||||
*/
|
||||
open: PropTypes.bool.isRequired
|
||||
} : void 0;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// eslint-disable-next-line
|
||||
FocusTrap['propTypes' + ''] = exactProp(FocusTrap.propTypes);
|
||||
}
|
||||
export default FocusTrap;
|
||||
Loading…
Add table
Add a link
Reference in a new issue