UNPKG

@wordpress/commands

Version:
289 lines (284 loc) 9.14 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.CommandMenu = CommandMenu; exports.CommandMenuGroup = CommandMenuGroup; exports.CommandMenuLoaderWrapper = CommandMenuLoaderWrapper; var _cmdk = require("cmdk"); var _clsx = _interopRequireDefault(require("clsx")); var _data = require("@wordpress/data"); var _element = require("@wordpress/element"); var _i18n = require("@wordpress/i18n"); var _components = require("@wordpress/components"); var _keyboardShortcuts = require("@wordpress/keyboard-shortcuts"); var _icons = require("@wordpress/icons"); var _store = require("../store"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const inputLabel = (0, _i18n.__)('Search commands and settings'); function CommandMenuLoader({ name, search, hook, setLoader, close }) { var _hook; const { isLoading, commands = [] } = (_hook = hook({ search })) !== null && _hook !== void 0 ? _hook : {}; (0, _element.useEffect)(() => { setLoader(name, isLoading); }, [setLoader, name, isLoading]); if (!commands.length) { return null; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { children: commands.map(command => { var _command$searchLabel; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_cmdk.Command.Item, { value: (_command$searchLabel = command.searchLabel) !== null && _command$searchLabel !== void 0 ? _command$searchLabel : command.label, onSelect: () => command.callback({ close }), id: command.name, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalHStack, { alignment: "left", className: (0, _clsx.default)('commands-command-menu__item', { 'has-icon': command.icon }), children: [command.icon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.Icon, { icon: command.icon }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextHighlight, { text: command.label, highlight: search }) })] }) }, command.name); }) }); } function CommandMenuLoaderWrapper({ hook, search, setLoader, close }) { // The "hook" prop is actually a custom React hook // so to avoid breaking the rules of hooks // the CommandMenuLoaderWrapper component need to be // remounted on each hook prop change // We use the key state to make sure we do that properly. const currentLoaderRef = (0, _element.useRef)(hook); const [key, setKey] = (0, _element.useState)(0); (0, _element.useEffect)(() => { if (currentLoaderRef.current !== hook) { currentLoaderRef.current = hook; setKey(prevKey => prevKey + 1); } }, [hook]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(CommandMenuLoader, { hook: currentLoaderRef.current, search: search, setLoader: setLoader, close: close }, key); } function CommandMenuGroup({ isContextual, search, setLoader, close }) { const { commands, loaders } = (0, _data.useSelect)(select => { const { getCommands, getCommandLoaders } = select(_store.store); return { commands: getCommands(isContextual), loaders: getCommandLoaders(isContextual) }; }, [isContextual]); if (!commands.length && !loaders.length) { return null; } return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_cmdk.Command.Group, { children: [commands.map(command => { var _command$searchLabel2; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_cmdk.Command.Item, { value: (_command$searchLabel2 = command.searchLabel) !== null && _command$searchLabel2 !== void 0 ? _command$searchLabel2 : command.label, onSelect: () => command.callback({ close }), id: command.name, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalHStack, { alignment: "left", className: (0, _clsx.default)('commands-command-menu__item', { 'has-icon': command.icon }), children: [command.icon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.Icon, { icon: command.icon }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextHighlight, { text: command.label, highlight: search }) })] }) }, command.name); }), loaders.map(loader => /*#__PURE__*/(0, _jsxRuntime.jsx)(CommandMenuLoaderWrapper, { hook: loader.hook, search: search, setLoader: setLoader, close: close }, loader.name))] }); } function CommandInput({ isOpen, search, setSearch }) { const commandMenuInput = (0, _element.useRef)(); const _value = (0, _cmdk.useCommandState)(state => state.value); const selectedItemId = (0, _element.useMemo)(() => { const item = document.querySelector(`[cmdk-item=""][data-value="${_value}"]`); return item?.getAttribute('id'); }, [_value]); (0, _element.useEffect)(() => { // Focus the command palette input when mounting the modal. if (isOpen) { commandMenuInput.current.focus(); } }, [isOpen]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_cmdk.Command.Input, { ref: commandMenuInput, value: search, onValueChange: setSearch, placeholder: inputLabel, "aria-activedescendant": selectedItemId, icon: search }); } /** * @ignore */ function CommandMenu() { const { registerShortcut } = (0, _data.useDispatch)(_keyboardShortcuts.store); const [search, setSearch] = (0, _element.useState)(''); const isOpen = (0, _data.useSelect)(select => select(_store.store).isOpen(), []); const { open, close } = (0, _data.useDispatch)(_store.store); const [loaders, setLoaders] = (0, _element.useState)({}); (0, _element.useEffect)(() => { registerShortcut({ name: 'core/commands', category: 'global', description: (0, _i18n.__)('Open the command palette.'), keyCombination: { modifier: 'primary', character: 'k' } }); }, [registerShortcut]); (0, _keyboardShortcuts.useShortcut)('core/commands', /** @type {import('react').KeyboardEventHandler} */ event => { // Bails to avoid obscuring the effect of the preceding handler(s). if (event.defaultPrevented) { return; } event.preventDefault(); if (isOpen) { close(); } else { open(); } }, { bindGlobal: true }); const setLoader = (0, _element.useCallback)((name, value) => setLoaders(current => ({ ...current, [name]: value })), []); const closeAndReset = () => { setSearch(''); close(); }; if (!isOpen) { return false; } const onKeyDown = event => { if ( // Ignore keydowns from IMEs event.nativeEvent.isComposing || // Workaround for Mac Safari where the final Enter/Backspace of an IME composition // is `isComposing=false`, even though it's technically still part of the composition. // These can only be detected by keyCode. event.keyCode === 229) { event.preventDefault(); } }; const isLoading = Object.values(loaders).some(Boolean); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Modal, { className: "commands-command-menu", overlayClassName: "commands-command-menu__overlay", onRequestClose: closeAndReset, __experimentalHideHeader: true, contentLabel: (0, _i18n.__)('Command palette'), children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: "commands-command-menu__container", children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_cmdk.Command, { label: inputLabel, onKeyDown: onKeyDown, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: "commands-command-menu__header", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(CommandInput, { search: search, setSearch: setSearch, isOpen: isOpen }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.Icon, { icon: _icons.search })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_cmdk.Command.List, { label: (0, _i18n.__)('Command suggestions'), children: [search && !isLoading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_cmdk.Command.Empty, { children: (0, _i18n.__)('No results found.') }), /*#__PURE__*/(0, _jsxRuntime.jsx)(CommandMenuGroup, { search: search, setLoader: setLoader, close: closeAndReset, isContextual: true }), search && /*#__PURE__*/(0, _jsxRuntime.jsx)(CommandMenuGroup, { search: search, setLoader: setLoader, close: closeAndReset })] })] }) }) }); } //# sourceMappingURL=command-menu.js.map