import React from "react"; import { Popover } from "./Popover"; import "./IconPicker.scss"; import { isArrowKey, KEYS } from "../keys"; import { getLanguage } from "../i18n"; function Picker({ options, value, label, onChange, onClose, }: { label: string; value: T; options: { value: T; text: string; icon: JSX.Element; keyBinding: string }[]; onChange: (value: T) => void; onClose: () => void; }) { const rFirstItem = React.useRef(); const rActiveItem = React.useRef(); const rGallery = React.useRef(null); React.useEffect(() => { // After the component is first mounted focus on first input if (rActiveItem.current) { rActiveItem.current.focus(); } else if (rGallery.current) { rGallery.current.focus(); } }, []); const handleKeyDown = (event: React.KeyboardEvent) => { const pressedOption = options.find( (option) => option.keyBinding === event.key.toLowerCase(), )!; if (!(event.metaKey || event.altKey || event.ctrlKey) && pressedOption) { // Keybinding navigation const index = options.indexOf(pressedOption); (rGallery!.current!.children![index] as any).focus(); event.preventDefault(); } else if (event.key === KEYS.TAB) { // Tab navigation cycle through options. If the user tabs // away from the picker, close the picker. We need to use // a timeout here to let the stack clear before checking. setTimeout(() => { const active = rActiveItem.current; const docActive = document.activeElement; if (active !== docActive) { onClose(); } }, 0); } else if (isArrowKey(event.key)) { // Arrow navigation const { activeElement } = document; const isRTL = getLanguage().rtl; const index = Array.prototype.indexOf.call( rGallery!.current!.children, activeElement, ); if (index !== -1) { const length = options.length; let nextIndex = index; switch (event.key) { // Select the next option case isRTL ? KEYS.ARROW_LEFT : KEYS.ARROW_RIGHT: case KEYS.ARROW_DOWN: { nextIndex = (index + 1) % length; break; } // Select the previous option case isRTL ? KEYS.ARROW_RIGHT : KEYS.ARROW_LEFT: case KEYS.ARROW_UP: { nextIndex = (length + index - 1) % length; break; } } (rGallery.current!.children![nextIndex] as any).focus(); } event.preventDefault(); } else if (event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) { // Close on escape or enter event.preventDefault(); onClose(); } event.nativeEvent.stopImmediatePropagation(); }; return (
{options.map((option, i) => ( ))}
); } export function IconPicker({ value, label, options, onChange, group = "", }: { label: string; value: T; options: { value: T; text: string; icon: JSX.Element; keyBinding: string }[]; onChange: (value: T) => void; group?: string; }) { const [isActive, setActive] = React.useState(false); const rPickerButton = React.useRef(null); const isRTL = getLanguage().rtl; return (