File: //home/arjun/projects/propbase/propbase_website/node_modules/@restart/ui/cjs/Dropdown.js
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _querySelectorAll = _interopRequireDefault(require("dom-helpers/querySelectorAll"));
var _addEventListener = _interopRequireDefault(require("dom-helpers/addEventListener"));
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var _uncontrollable = require("uncontrollable");
var _usePrevious = _interopRequireDefault(require("@restart/hooks/usePrevious"));
var _useForceUpdate = _interopRequireDefault(require("@restart/hooks/useForceUpdate"));
var _useEventListener = _interopRequireDefault(require("@restart/hooks/useEventListener"));
var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback"));
var _DropdownContext = _interopRequireDefault(require("./DropdownContext"));
var _DropdownMenu = _interopRequireDefault(require("./DropdownMenu"));
var _DropdownToggle = _interopRequireWildcard(require("./DropdownToggle"));
var _DropdownItem = _interopRequireDefault(require("./DropdownItem"));
var _SelectableContext = _interopRequireDefault(require("./SelectableContext"));
var _DataKey = require("./DataKey");
var _useWindow = _interopRequireDefault(require("./useWindow"));
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function useRefWithUpdate() {
const forceUpdate = (0, _useForceUpdate.default)();
const ref = (0, _react.useRef)(null);
const attachRef = (0, _react.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 = `* [${(0, _DataKey.dataAttr)('dropdown-item')}]`,
focusFirstItemOnShow,
placement = 'bottom-start',
children
}) {
const window = (0, _useWindow.default)();
const [show, onToggle] = (0, _uncontrollable.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 = (0, _usePrevious.default)(show);
const lastSourceEvent = (0, _react.useRef)(null);
const focusInDropdown = (0, _react.useRef)(false);
const onSelectCtx = (0, _react.useContext)(_SelectableContext.default);
const toggle = (0, _react.useCallback)((nextShow, event, source = event == null ? void 0 : event.type) => {
onToggle(nextShow, {
originalEvent: event,
source
});
}, [onToggle]);
const handleSelect = (0, _useEventCallback.default)((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 = (0, _react.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 = (0, _useEventCallback.default)(() => {
if (toggleElement && toggleElement.focus) {
toggleElement.focus();
}
});
const maybeFocusFirst = (0, _useEventCallback.default)(() => {
const type = lastSourceEvent.current;
let focusType = focusFirstItemOnShow;
if (focusType == null) {
focusType = menuRef.current && (0, _DropdownToggle.isRoleMenu)(menuRef.current) ? 'keyboard' : false;
}
if (focusType === false || focusType === 'keyboard' && !/^key.+$/.test(type)) {
return;
}
const first = (0, _querySelectorAll.default)(menuRef.current, itemSelector)[0];
if (first && first.focus) first.focus();
});
(0, _react.useEffect)(() => {
if (show) maybeFocusFirst();else if (focusInDropdown.current) {
focusInDropdown.current = false;
focusToggle();
}
// only `show` should be changing
}, [show, focusInDropdown, focusToggle, maybeFocusFirst]);
(0, _react.useEffect)(() => {
lastSourceEvent.current = null;
});
const getNextFocusedChild = (current, offset) => {
if (!menuRef.current) return null;
const items = (0, _querySelectorAll.default)(menuRef.current, itemSelector);
let index = items.indexOf(current) + offset;
index = Math.max(0, Math.min(index, items.length));
return items[index];
};
(0, _useEventListener.default)((0, _react.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
(0, _addEventListener.default)(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__*/(0, _jsxRuntime.jsx)(_SelectableContext.default.Provider, {
value: handleSelect,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_DropdownContext.default.Provider, {
value: context,
children: children
})
});
}
Dropdown.displayName = 'Dropdown';
Dropdown.Menu = _DropdownMenu.default;
Dropdown.Toggle = _DropdownToggle.default;
Dropdown.Item = _DropdownItem.default;
var _default = exports.default = Dropdown;