Jesus sucks
This commit is contained in:
195
backend/frontend/node_modules/@restart/ui/esm/Dropdown.js
generated
vendored
Normal file
195
backend/frontend/node_modules/@restart/ui/esm/Dropdown.js
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
import qsa from 'dom-helpers/querySelectorAll';
|
||||
import addEventListener from 'dom-helpers/addEventListener';
|
||||
import { useCallback, useRef, useEffect, useMemo, useContext } from 'react';
|
||||
import * as React from 'react';
|
||||
import { useUncontrolledProp } from 'uncontrollable';
|
||||
import usePrevious from '@restart/hooks/usePrevious';
|
||||
import useForceUpdate from '@restart/hooks/useForceUpdate';
|
||||
import useEventListener from '@restart/hooks/useEventListener';
|
||||
import useEventCallback from '@restart/hooks/useEventCallback';
|
||||
import DropdownContext from './DropdownContext';
|
||||
import DropdownMenu from './DropdownMenu';
|
||||
import DropdownToggle, { isRoleMenu } from './DropdownToggle';
|
||||
import DropdownItem from './DropdownItem';
|
||||
import SelectableContext from './SelectableContext';
|
||||
import { dataAttr } from './DataKey';
|
||||
import useWindow from './useWindow';
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
function useRefWithUpdate() {
|
||||
const forceUpdate = useForceUpdate();
|
||||
const ref = useRef(null);
|
||||
const attachRef = useCallback(element => {
|
||||
ref.current = element;
|
||||
// ensure that a menu set triggers an update for consumers
|
||||
forceUpdate();
|
||||
}, [forceUpdate]);
|
||||
return [ref, attachRef];
|
||||
}
|
||||
|
||||
/**
|
||||
* @displayName Dropdown
|
||||
* @public
|
||||
*/
|
||||
function Dropdown({
|
||||
defaultShow,
|
||||
show: rawShow,
|
||||
onSelect,
|
||||
onToggle: rawOnToggle,
|
||||
itemSelector = `* [${dataAttr('dropdown-item')}]`,
|
||||
focusFirstItemOnShow,
|
||||
placement = 'bottom-start',
|
||||
children
|
||||
}) {
|
||||
const window = useWindow();
|
||||
const [show, onToggle] = useUncontrolledProp(rawShow, defaultShow, rawOnToggle);
|
||||
|
||||
// We use normal refs instead of useCallbackRef in order to populate the
|
||||
// the value as quickly as possible, otherwise the effect to focus the element
|
||||
// may run before the state value is set
|
||||
const [menuRef, setMenu] = useRefWithUpdate();
|
||||
const menuElement = menuRef.current;
|
||||
const [toggleRef, setToggle] = useRefWithUpdate();
|
||||
const toggleElement = toggleRef.current;
|
||||
const lastShow = usePrevious(show);
|
||||
const lastSourceEvent = useRef(null);
|
||||
const focusInDropdown = useRef(false);
|
||||
const onSelectCtx = useContext(SelectableContext);
|
||||
const toggle = useCallback((nextShow, event, source = event == null ? void 0 : event.type) => {
|
||||
onToggle(nextShow, {
|
||||
originalEvent: event,
|
||||
source
|
||||
});
|
||||
}, [onToggle]);
|
||||
const handleSelect = useEventCallback((key, event) => {
|
||||
onSelect == null ? void 0 : onSelect(key, event);
|
||||
toggle(false, event, 'select');
|
||||
if (!event.isPropagationStopped()) {
|
||||
onSelectCtx == null ? void 0 : onSelectCtx(key, event);
|
||||
}
|
||||
});
|
||||
const context = useMemo(() => ({
|
||||
toggle,
|
||||
placement,
|
||||
show,
|
||||
menuElement,
|
||||
toggleElement,
|
||||
setMenu,
|
||||
setToggle
|
||||
}), [toggle, placement, show, menuElement, toggleElement, setMenu, setToggle]);
|
||||
if (menuElement && lastShow && !show) {
|
||||
focusInDropdown.current = menuElement.contains(menuElement.ownerDocument.activeElement);
|
||||
}
|
||||
const focusToggle = useEventCallback(() => {
|
||||
if (toggleElement && toggleElement.focus) {
|
||||
toggleElement.focus();
|
||||
}
|
||||
});
|
||||
const maybeFocusFirst = useEventCallback(() => {
|
||||
const type = lastSourceEvent.current;
|
||||
let focusType = focusFirstItemOnShow;
|
||||
if (focusType == null) {
|
||||
focusType = menuRef.current && isRoleMenu(menuRef.current) ? 'keyboard' : false;
|
||||
}
|
||||
if (focusType === false || focusType === 'keyboard' && !/^key.+$/.test(type)) {
|
||||
return;
|
||||
}
|
||||
const first = qsa(menuRef.current, itemSelector)[0];
|
||||
if (first && first.focus) first.focus();
|
||||
});
|
||||
useEffect(() => {
|
||||
if (show) maybeFocusFirst();else if (focusInDropdown.current) {
|
||||
focusInDropdown.current = false;
|
||||
focusToggle();
|
||||
}
|
||||
// only `show` should be changing
|
||||
}, [show, focusInDropdown, focusToggle, maybeFocusFirst]);
|
||||
useEffect(() => {
|
||||
lastSourceEvent.current = null;
|
||||
});
|
||||
const getNextFocusedChild = (current, offset) => {
|
||||
if (!menuRef.current) return null;
|
||||
const items = qsa(menuRef.current, itemSelector);
|
||||
let index = items.indexOf(current) + offset;
|
||||
index = Math.max(0, Math.min(index, items.length));
|
||||
return items[index];
|
||||
};
|
||||
useEventListener(useCallback(() => window.document, [window]), 'keydown', event => {
|
||||
var _menuRef$current, _toggleRef$current;
|
||||
const {
|
||||
key
|
||||
} = event;
|
||||
const target = event.target;
|
||||
const fromMenu = (_menuRef$current = menuRef.current) == null ? void 0 : _menuRef$current.contains(target);
|
||||
const fromToggle = (_toggleRef$current = toggleRef.current) == null ? void 0 : _toggleRef$current.contains(target);
|
||||
|
||||
// Second only to https://github.com/twbs/bootstrap/blob/8cfbf6933b8a0146ac3fbc369f19e520bd1ebdac/js/src/dropdown.js#L400
|
||||
// in inscrutability
|
||||
const isInput = /input|textarea/i.test(target.tagName);
|
||||
if (isInput && (key === ' ' || key !== 'Escape' && fromMenu || key === 'Escape' && target.type === 'search')) {
|
||||
return;
|
||||
}
|
||||
if (!fromMenu && !fromToggle) {
|
||||
return;
|
||||
}
|
||||
if (key === 'Tab' && (!menuRef.current || !show)) {
|
||||
return;
|
||||
}
|
||||
lastSourceEvent.current = event.type;
|
||||
const meta = {
|
||||
originalEvent: event,
|
||||
source: event.type
|
||||
};
|
||||
switch (key) {
|
||||
case 'ArrowUp':
|
||||
{
|
||||
const next = getNextFocusedChild(target, -1);
|
||||
if (next && next.focus) next.focus();
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
case 'ArrowDown':
|
||||
event.preventDefault();
|
||||
if (!show) {
|
||||
onToggle(true, meta);
|
||||
} else {
|
||||
const next = getNextFocusedChild(target, 1);
|
||||
if (next && next.focus) next.focus();
|
||||
}
|
||||
return;
|
||||
case 'Tab':
|
||||
// on keydown the target is the element being tabbed FROM, we need that
|
||||
// to know if this event is relevant to this dropdown (e.g. in this menu).
|
||||
// On `keyup` the target is the element being tagged TO which we use to check
|
||||
// if focus has left the menu
|
||||
addEventListener(target.ownerDocument, 'keyup', e => {
|
||||
var _menuRef$current2;
|
||||
if (e.key === 'Tab' && !e.target || !((_menuRef$current2 = menuRef.current) != null && _menuRef$current2.contains(e.target))) {
|
||||
onToggle(false, meta);
|
||||
}
|
||||
}, {
|
||||
once: true
|
||||
});
|
||||
break;
|
||||
case 'Escape':
|
||||
if (key === 'Escape') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
onToggle(false, meta);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
return /*#__PURE__*/_jsx(SelectableContext.Provider, {
|
||||
value: handleSelect,
|
||||
children: /*#__PURE__*/_jsx(DropdownContext.Provider, {
|
||||
value: context,
|
||||
children: children
|
||||
})
|
||||
});
|
||||
}
|
||||
Dropdown.displayName = 'Dropdown';
|
||||
Dropdown.Menu = DropdownMenu;
|
||||
Dropdown.Toggle = DropdownToggle;
|
||||
Dropdown.Item = DropdownItem;
|
||||
export default Dropdown;
|
||||
Reference in New Issue
Block a user