UNPKG

@adyen/kyc-components

Version:

This guide assumes that you have already an account with Adyen. A legalEntity needs to be created, and you need to have a `legalEntityId` to instatiate a Component.

776 lines (775 loc) 27.4 kB
try { let e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack; n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "79ba8d2d-8832-4e6d-8966-8f64fab0f197", e._sentryDebugIdIdentifier = "sentry-dbid-79ba8d2d-8832-4e6d-8966-8f64fab0f197"); } catch (e) {} import { i as Typography, o as createLogger, r as useTranslation } from "./translation-BFxyJ1c5.js"; import { r as Loader } from "./Button-oj6H8OrC.js"; import { s as noop, t as useAnalyticsContext } from "./useAnalyticsContext-BVFDMrVE.js"; import { t as KEYBOARD_KEYS } from "./keys-fzUbt2xF.js"; import { t as useId } from "./useId-eJSYfA6i.js"; import { t as debouncedInputEvent } from "./debouncedInputEvent-Dxv4-RAv.js"; import { t as Checkbox } from "./Checkbox-BCYjFPa4.js"; import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks"; import cx from "classnames"; import { Fragment, jsx, jsxs } from "preact/jsx-runtime"; import { computed, signal, useSignal, useSignalEffect } from "@preact/signals"; //#region src/components/ui/atoms/Select/useSelectFocus.ts var createSelectFocus = ({ activeItems, filteredItems: items }) => { const numberOfItems = computed(() => items.value.length - 1); const focused = signal(); const getDefaultFocusedItem = () => { const firstActiveOption = activeItems.value.find((option) => !option.disabled); const firstEnabledOption = items.value.find((option) => !option.disabled); return firstActiveOption ?? firstEnabledOption; }; const focusedItemIndex = computed(() => { const currFocus = focused.value; const toFind = focusedIsItem(currFocus) ? currFocus : getDefaultFocusedItem(); const itemsValue = items.value; if (!toFind) { console.warn("[Select] No existing focused item, and none of the filtered items are enabled"); return 0; } return itemsValue.findIndex((i) => i.id === toFind.id); }); const findPotentialIndex = (currentIndex, direction) => { const potentialIndex = direction === "down" ? currentIndex + 1 : currentIndex - 1; const potentialItem = items.value[potentialIndex]; if (potentialIndex < 0 || potentialIndex > numberOfItems.value) return "exceedsBounds"; if (potentialItem.disabled) return findPotentialIndex(potentialIndex, direction); return potentialIndex; }; const moveFocusToNextItem = () => { const nextIndex = findPotentialIndex(focusedItemIndex.value, "down"); if (nextIndex !== "exceedsBounds") focused.value = items.value[nextIndex]; }; const moveFocusToPreviousItem = () => { const prevIndex = findPotentialIndex(focusedItemIndex.value, "up"); if (prevIndex !== "exceedsBounds") focused.value = items.value[prevIndex]; }; const moveFocusToFirstItem = () => { let currIndex = focusedItemIndex.value; while (true) { const before = findPotentialIndex(currIndex, "up"); if (before === "exceedsBounds") break; currIndex = before; } focused.value = items.value[currIndex]; }; const moveFocusToLastItem = () => { let currIndex = focusedItemIndex.value; while (true) { const after = findPotentialIndex(currIndex, "down"); if (after === "exceedsBounds") break; currIndex = after; } focused.value = items.value[currIndex]; }; const focusInput = () => { focused.value = "input"; }; const focusItem = (item) => { focused.value = item; }; const focusDefaultItem = () => { focused.value = getDefaultFocusedItem(); }; const focusNothing = () => { focused.value = void 0; }; return { focused, moveFocusToFirstItem, moveFocusToLastItem, moveFocusToNextItem, moveFocusToPreviousItem, focusInput, focusItem, focusDefaultItem, focusNothing }; }; var useSelectFocus = (options) => { const [selectFocus] = useState(createSelectFocus(options)); return selectFocus; }; var focusedIsItem = (focused) => Boolean(focused) && typeof focused === "object"; //#endregion //#region src/utils/signals/useWatchingSignal.ts /** * Returns a signal "watching" its given value. Whenever the value changes, the signal will update. * * @param value */ var useWatchingSignal = (value) => { const signal = useSignal(value); if (signal.peek() !== value) signal.value = value; return signal; }; //#endregion //#region src/utils/simulateTextChangeFromKeyboardEvent.ts /** * This is useful for when you want to figure out what effect a keyboard event would have on * some arbitrary existing text, as if it were happening on an `<input>`'s value. * * This is not a perfect simulation, real input handling is much more complex. * * @param keyDownEvent the actual event which occurred, probably on some other element * @param value the existing value of the input */ var simulateTextChangeFromKeyboardEvent = (keyDownEvent, value) => { const { key } = keyDownEvent; let newValue = value; if (key === KEYBOARD_KEYS.backspace) newValue = newValue.slice(0, newValue.length - 1); else if (key.length === 1) newValue += key; return newValue; }; //#endregion //#region src/utils/useMirrorProp.ts /** * This is a 'hacky' way to handle components which may have props either controlled or uncontrolled. * * Avoid using it if at all possible - generally it's better to write a controlled inner component * and simply make an uncontrolled version which wraps it. * * * If controlled, we mirror the prop state and propagate changes upwards via {@link propOnChange}. * * If uncontrolled, it is effectively a simple {@link useState()}. * * *Note: if mirroring, both `prop` and `propOnChange` **must** be provided.* * * @param prop the prop to be mirrored * @param propOnChange the handler to propagate changes from below back upwards * @param defaultVal the default value, only used if we aren't mirroring */ function useMirrorProp(prop, propOnChange, defaultVal) { const [isMirroring] = useState(propOnChange !== void 0); const [local, setLocal] = useState(defaultVal); if (isMirroring) return [prop, propOnChange]; else return [local, setLocal]; } var SelectButton_module_default = { "select-input-wrapper": "adyen-kyc-select-input-wrapper", selectInputWrapper: "adyen-kyc-select-input-wrapper", "select-input__icon": "adyen-kyc-select-input__icon", selectInputIcon: "adyen-kyc-select-input__icon", "select-input": "adyen-kyc-select-input", selectInput: "adyen-kyc-select-input", "select-input--active": "adyen-kyc-select-input--active", selectInputActive: "adyen-kyc-select-input--active", "select-input--readonly": "adyen-kyc-select-input--readonly", selectInputReadonly: "adyen-kyc-select-input--readonly", "select-input--invalid": "adyen-kyc-select-input--invalid", selectInputInvalid: "adyen-kyc-select-input--invalid", "select-input--minimal": "adyen-kyc-select-input--minimal", selectInputMinimal: "adyen-kyc-select-input--minimal", "select-input-search": "adyen-kyc-select-input-search", selectInputSearch: "adyen-kyc-select-input-search", "select-input-search__icon": "adyen-kyc-select-input-search__icon", selectInputSearchIcon: "adyen-kyc-select-input-search__icon", "select-input--filterable": "adyen-kyc-select-input--filterable", selectInputFilterable: "adyen-kyc-select-input--filterable", "select-input-wrapper--filterable": "adyen-kyc-select-input-wrapper--filterable", selectInputWrapperFilterable: "adyen-kyc-select-input-wrapper--filterable", "select-input-wrapper--non-filterable": "adyen-kyc-select-input-wrapper--non-filterable", selectInputWrapperNonFilterable: "adyen-kyc-select-input-wrapper--non-filterable", "select-input--list-open": "adyen-kyc-select-input--list-open", selectInputListOpen: "adyen-kyc-select-input--list-open", "select-input--non-filterable": "adyen-kyc-select-input--non-filterable", selectInputNonFilterable: "adyen-kyc-select-input--non-filterable", "select-input--placeholder": "adyen-kyc-select-input--placeholder", selectInputPlaceholder: "adyen-kyc-select-input--placeholder", "ignore-pointer-events": "adyen-kyc-ignore-pointer-events", ignorePointerEvents: "adyen-kyc-ignore-pointer-events", "handle-pointer-events": "adyen-kyc-handle-pointer-events", handlePointerEvents: "adyen-kyc-handle-pointer-events" }; //#endregion //#region src/components/ui/atoms/SelectButton/SelectButton.tsx var isAppleMobile = /iPhone|iPad/.test(navigator.platform); function SelectButton({ id, name, active, readonly, showList, isInvalid, onClick, onButtonKeyDown, filterable, isFiltering, placeholder, focusProps: { focused }, selectListId, onInput, behaviour, loading, text, enableTracking = false, onFocus, inputRef, minimal, "aria-describedby": ariaDescribedBy, "aria-labelledby": ariaLabelledBy, "aria-label": ariaLabel }) { const userEvents = useAnalyticsContext(); const wrapperRef = useRef(null); useSignalEffect(() => { if (focused.value === "input") inputRef.current?.focus(); }); const handleFocus = (e) => { if (readonly) return; if (enableTracking) userEvents.addFieldEvent("Interacted with form field", { actionType: "focus", field: name }); onFocus(e); }; const handleClick = (e) => { e.preventDefault(); e.stopPropagation(); if (readonly) return; onClick(); }; const handleKeyDown = (e) => { if (!readonly) onButtonKeyDown(e); }; const handleInput = (e) => { if (filterable && !readonly) onInput(e.currentTarget.value); }; const truncatedDisplayValue = useMemo(() => { if (active.length === 0) return void 0; const activeText = active.map(({ selectedOptionName, name }) => selectedOptionName ?? name).join(", "); return activeText.length > 50 ? activeText.substring(0, 50) + "..." : activeText; }, [active]); const title = active?.length ? active.map(({ name }) => name).join(",") : placeholder; const isFocused = focused.value === "input"; const value = useMemo(() => { if (behaviour === "textIsData" || focused.value !== void 0 && filterable && isFiltering) return text; return truncatedDisplayValue; }, [ behaviour, text, focused.value, filterable, isFiltering, truncatedDisplayValue ]); return /* @__PURE__ */ jsxs("div", { className: cx({ [SelectButton_module_default.selectInputWrapper]: true, [SelectButton_module_default.selectInputMinimal]: minimal, [SelectButton_module_default.selectInputReadonly]: readonly, [SelectButton_module_default.selectInputActive]: isFocused, [SelectButton_module_default.selectInputListOpen]: showList, [SelectButton_module_default.selectInputInvalid]: isInvalid, [SelectButton_module_default.selectInputSearch]: filterable === "prefiltered", [SelectButton_module_default.selectInputWrapperFilterable]: filterable, [SelectButton_module_default.selectInputWrapperNonFilterable]: !filterable, [SelectButton_module_default.ignorePointerEvents]: isAppleMobile }), ref: wrapperRef, onClick: handleClick, onFocusIn: handleFocus, children: [ /* @__PURE__ */ jsx("input", { id, name, title, ref: inputRef, type: filterable ? "text" : "button", role: "combobox", "aria-haspopup": "listbox", "aria-owns": selectListId, "aria-controls": selectListId, "aria-expanded": showList, "aria-describedby": ariaDescribedBy, "aria-disabled": readonly, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-autocomplete": filterable ? "list" : void 0, autoComplete: "off", className: cx({ [SelectButton_module_default.selectInput]: true, [SelectButton_module_default.selectInputFilterable]: filterable, [SelectButton_module_default.selectInputNonFilterable]: !filterable, [SelectButton_module_default.selectInputMinimal]: minimal, [SelectButton_module_default.selectInputReadonly]: readonly, [SelectButton_module_default.handlePointerEvents]: isAppleMobile }), placeholder, value, disabled: readonly, onClick: handleClick, onInput: handleInput, onKeyDown: handleKeyDown }), !filterable && !value ? /* @__PURE__ */ jsx("span", { className: SelectButton_module_default.selectInputPlaceholder, children: placeholder }) : void 0, loading && /* @__PURE__ */ jsx(Loader, { size: "small" }) ] }); } //#endregion //#region src/components/ui/atoms/SelectListItem/SelectListItem.tsx var SelectListItem = ({ id, item, selected, isMulti, isSearch, children, onSelect, onKeyDown, onFocus, className }) => /* @__PURE__ */ jsx("li", { "aria-disabled": !!item.disabled, "aria-selected": selected, className: cx([ "adyen-kyc-dropdown-element", { "adyen-kyc-dropdown-element--active": selected, "adyen-kyc-dropdown-element--disabled": !!item.disabled, "adyen-kyc-dropdown-multi-element": isMulti, "adyen-kyc-dropdown-element-description": !isMulti && !isSearch && item.description, "adyen-kyc-dropdown-search-element": isSearch }, className ]), "data-disabled": !!item.disabled, "data-value": item.id, onFocus: (event) => { if (item.disabled) return; onFocus?.(event); }, onClick: (e) => { e.preventDefault(); if (item.disabled) return; onSelect(!selected); }, onKeyDown: (e) => { if (item.disabled) return; onKeyDown(e); }, role: "option", tabIndex: -1, children: isMulti ? /* @__PURE__ */ jsx("span", { style: { pointerEvents: "none", width: "100%" }, children: /* @__PURE__ */ jsx(Checkbox, { id, onChange: noop, label: item.name, disabled: item.disabled, helper: item.description, checked: selected, name: `adyen-kyc-dropdown-element__checkbox adyen-kyc-dropdown-element__checkbox--${item.id}` }) }) : children ? [children] : /* @__PURE__ */ jsxs(Fragment, { children: [item.icon && /* @__PURE__ */ jsx("span", { className: "adyen-kyc-dropdown-element__icon", children: item.icon }), item.description ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Typography, { el: "span", variant: "body-strongest", className: "adyen-kyc-dropdown-element__label", children: item.name }), /* @__PURE__ */ jsx(Typography, { el: "span", color: "secondary", className: "adyen-kyc-dropdown-element-description__text", children: item.description })] }) : /* @__PURE__ */ jsx("span", { className: "adyen-kyc-dropdown-element__label", children: item.name })] }) }); //#endregion //#region src/components/ui/atoms/SelectList/SelectList.tsx var logger = createLogger(); var DEFAULT_ITEM_HEIGHT = 36; function SelectList({ selectListId, active, filteredItems, showList, isMulti, inputRef, isSearch, loading, getSearchItem, onKeyDown, onSelect, minimal, maxVisibleItems = 5, focusProps: { focused, focusItem, focusDefaultItem, moveFocusToNextItem, moveFocusToPreviousItem, moveFocusToFirstItem, moveFocusToLastItem } }) { const { t } = useTranslation("ui"); const [startIndex, setStartIndex] = useState(0); const [endIndex, setEndIndex] = useState(maxVisibleItems); const listRef = useRef(null); const itemHeight = (() => { if (listRef.current && showList) { const height = (listRef.current.firstElementChild?.firstElementChild)?.clientHeight; if (height !== void 0) return height; } })() || DEFAULT_ITEM_HEIGHT; const totalItems = filteredItems.length; const visibleItems = useMemo(() => filteredItems.slice(startIndex, endIndex), [ endIndex, filteredItems, startIndex ]); const findElementForItem = useCallback((item) => { const listContainer = listRef.current; if (!listContainer) return; return listContainer.querySelector(`[role="option"][data-value="${item.id}"]`); }, [listRef]); /** * When we scroll, we need to figure out which items are now in view. * This also needs to be done whenever the filtered items change. */ const recalculateScrollIndexes = useCallback(() => { if (!listRef.current) return; const { scrollTop } = listRef.current; const maxStartIndex = totalItems < maxVisibleItems ? totalItems : totalItems - maxVisibleItems; const newStartIndex = Math.min(Math.max(0, Math.floor(scrollTop / itemHeight)), maxStartIndex); const newEndIndex = Math.min(newStartIndex + maxVisibleItems, totalItems); setStartIndex(newStartIndex); setEndIndex(newEndIndex); }, [ totalItems, maxVisibleItems, itemHeight, listRef ]); useEffect(() => { recalculateScrollIndexes(); }, [recalculateScrollIndexes]); const scrollItemIntoView = useCallback((item) => { if (!listRef.current) return; const itemIndex = filteredItems.indexOf(item); if (itemIndex === -1) return; const maxScrollTop = totalItems * itemHeight; listRef.current.scrollTop = Math.min(itemHeight * (itemIndex + .5), maxScrollTop); }, [ filteredItems, itemHeight, totalItems, listRef ]); const acquireFocusForItem = useCallback((item) => { let itemEl = findElementForItem(item); if (!itemEl) scrollItemIntoView(item); setTimeout(() => { itemEl = itemEl ?? findElementForItem(item); if (itemEl) itemEl.focus(); else logger.warn("[SelectList] still cannot see the option", item.name); }, 20); }, [findElementForItem, scrollItemIntoView]); useSignalEffect(() => { const currFocused = focused.value; if (focusedIsItem(currFocused)) acquireFocusForItem(currFocused); }); const listListeners = { [KEYBOARD_KEYS.arrowUp]: moveFocusToPreviousItem, [KEYBOARD_KEYS.arrowDown]: moveFocusToNextItem, [KEYBOARD_KEYS.home]: moveFocusToFirstItem, [KEYBOARD_KEYS.end]: moveFocusToLastItem }; const onListKeydown = (event) => { const listener = listListeners[event.key]; if (listener) { event.preventDefault(); listener(); } }; const getItems = () => { if (loading) return /* @__PURE__ */ jsx("div", { className: "adyen-kyc-dropdown-element adyen-kyc-dropdown-element--no-options", children: t(($) => $["loading"]) }); if (!filteredItems.length) { if (startIndex !== 0 || endIndex !== maxVisibleItems) { setStartIndex(0); setEndIndex(maxVisibleItems); } return /* @__PURE__ */ jsx("div", { className: "adyen-kyc-dropdown-element adyen-kyc-dropdown-element--no-options", children: t(($) => $["noOptionsFound"]) }); } if (visibleItems.length) return visibleItems.map((item) => /* @__PURE__ */ jsx(SelectListItem, { item, id: item.id, onKeyDown: (event) => { onKeyDown(event, item); }, onFocus: (event) => { focusItem(item); event.stopPropagation(); }, onSelect: () => { onSelect(item); }, selected: !!active.find((activeItem) => activeItem.id === item.id), isMulti, isSearch, children: getSearchItem && getSearchItem(item) }, item.id)); return null; }; const height = useMemo(() => { if (loading) return "auto"; return totalItems > maxVisibleItems && itemHeight ? `${itemHeight * maxVisibleItems}px` : "auto"; }, [ itemHeight, totalItems, loading, maxVisibleItems ]); const allItemsVisible = totalItems <= maxVisibleItems; const [showAbove, setShowAbove] = useState(false); useEffect(() => { const list = listRef.current; const input = inputRef.current; const resizeObserver = new ResizeObserver(() => { const dropdownHeight = list.offsetHeight; const windowHeight = window.innerHeight; const position = input.getBoundingClientRect().bottom; setShowAbove(!(windowHeight - position > dropdownHeight) && position > dropdownHeight); }); resizeObserver.observe(list); return () => { resizeObserver.disconnect(); }; }, [inputRef, listRef]); return /* @__PURE__ */ jsx("div", { className: cx({ "adyen-kyc-dropdown-list": true, "adyen-kyc-dropdown-list--minimal": minimal, "adyen-kyc-dropdown-list--active": showList, "adyen-kyc-dropdown-list--above": showAbove }), id: selectListId, role: "listbox", onScroll: recalculateScrollIndexes, style: { overflowY: allItemsVisible ? "hidden" : "auto", position: "absolute", height }, onKeyDown: onListKeydown, onFocus: focusDefaultItem, tabIndex: -1, ref: listRef, children: /* @__PURE__ */ jsxs("ul", { className: "adyen-kyc-dropdown-list__transformer", style: { transform: `translateY(${startIndex * itemHeight}px)` }, children: [getItems(), /* @__PURE__ */ jsx("div", { style: { height: `${(totalItems - endIndex) * itemHeight}px` } })] }) }); } //#endregion //#region src/components/ui/atoms/Select/Select.tsx var Select = ({ id, items, filterable = true, readonly = false, onChange, onSelect, selected, name, isInvalid = false, placeholder = "", isMulti, enableTracking = false, maxVisibleItems, getSearchItem, onBlur = noop, text: filterTextProp, setText: setFilterTextProp, showList: showListProp, setShowList: setShowListProp, behaviour = "textIsFilter", loading = false, minimal = false, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, excludedValues }) => { const userEvents = useAnalyticsContext(); const selectContainerRef = useRef(null); const inputRef = useRef(null); const selectListId = useId("select"); const [textFilter, setTextFilter] = useMirrorProp(filterTextProp, setFilterTextProp, ""); const [isShowList, setIsShowList] = useMirrorProp(showListProp, setShowListProp, false); const [isFiltering, setIsFiltering] = useState(false); const active = useMemo(() => { if (selected === void 0) return []; return (Array.isArray(selected) ? selected : [selected]).map((s) => { if (typeof s === "object") return s; return items.find((i) => i.id === s); }).filter(Boolean); }, [items, selected]); const filtered = useMemo(() => { return items.filter((item) => !excludedValues?.includes(item)).filter((item) => { if (filterable === "prefiltered" || !isFiltering) return true; return item.name.toLowerCase().includes(textFilter.toLowerCase()); }); }, [ filterable, isFiltering, items, textFilter, excludedValues ]); const focusProps = useSelectFocus({ activeItems: useWatchingSignal(active), filteredItems: useWatchingSignal(filtered) }); const { focusInput, focusItem, focusDefaultItem, focusNothing, moveFocusToNextItem, moveFocusToPreviousItem } = focusProps; /** * Closes the selectList, empties the text filter and focuses the button element */ const closeList = useCallback((shiftFocusTo) => { if (behaviour === "textIsFilter") setTextFilter(""); setIsShowList(false); switch (shiftFocusTo) { case "input": focusInput(); break; case "nothing": focusNothing(); break; } }, [ behaviour, focusInput, focusNothing, setIsShowList, setTextFilter ]); const showList = useCallback(() => { if (!isShowList) setIsShowList(true); }, [isShowList, setIsShowList]); const handleSelect = useCallback((selectedItem) => { setIsFiltering(false); if (readonly) return; if (isMulti) { const newActiveItems = active.find((item) => item.id === selectedItem.id) ? active.filter((i) => i.id !== selectedItem.id) : [...active, selectedItem]; onSelect?.(newActiveItems); onChange?.({ target: { value: newActiveItems.map((i) => i.id), name: name ?? "" } }); focusItem(selectedItem); } else { const handleOnSelect = onSelect; const handleOnChange = onChange; handleOnSelect?.(selectedItem); handleOnChange?.({ target: { value: selectedItem.id, name: name ?? "" } }); closeList("input"); } if (enableTracking) userEvents.addFieldEvent("Interacted with form field", { actionType: "select", field: name, returnValue: selectedItem.id }); }, [ readonly, isMulti, enableTracking, active, onSelect, onChange, name, focusItem, closeList, userEvents ]); const handleBlur = (e) => { onBlur(e); }; /** * Handle keyDown events on the selectList button * Opens the selectList and focuses the first element if available * @param e - KeyboardEvent */ const handleInputKeyDown = async (e) => { if (e.key === KEYBOARD_KEYS.enter && isShowList) if (filtered.length === 1) handleSelect(filtered[0]); else e.preventDefault(); else if (e.key === KEYBOARD_KEYS.escape) closeList("nothing"); else if (e.key === KEYBOARD_KEYS.enter || e.key === KEYBOARD_KEYS.space && (!filterable || !isShowList)) { e.preventDefault(); e.stopPropagation(); showList(); focusDefaultItem(); } else if (e.key === KEYBOARD_KEYS.arrowUp || e.key === KEYBOARD_KEYS.arrowDown) { e.preventDefault(); e.stopPropagation(); showList(); focusDefaultItem(); switch (e.key) { case KEYBOARD_KEYS.arrowUp: moveFocusToPreviousItem(); break; case KEYBOARD_KEYS.arrowDown: moveFocusToNextItem(); break; } } else if (e.key === KEYBOARD_KEYS.tab) closeList("nothing"); }; /** * Close the select list when clicking outside the list * @param e - MouseEvent */ const handleClickOutside = (e) => { if (!selectContainerRef.current?.contains(e.target)) closeList("nothing"); }; /** * Handle keyDown events on the list elements * Navigates through the list, or select an element, or focus the filter input, or close the menu. * @param e - KeyDownEvent * @param item - the item for which the keyboard event was triggered */ const handleListItemKeyDown = (e, item) => { switch (e.key) { case KEYBOARD_KEYS.escape: e.preventDefault(); closeList("input"); break; case KEYBOARD_KEYS.space: case KEYBOARD_KEYS.enter: handleSelect(item); break; case KEYBOARD_KEYS.tab: closeList("nothing"); break; case KEYBOARD_KEYS.arrowUp: case KEYBOARD_KEYS.arrowDown: case KEYBOARD_KEYS.home: case KEYBOARD_KEYS.end: break; default: e.preventDefault(); e.stopPropagation(); handleTextFilter(simulateTextChangeFromKeyboardEvent(e, textFilter)); focusInput(); } }; /** * Updates the state with the current text filter value */ const handleTextFilter = useCallback((value) => { showList(); setIsFiltering(true); setTextFilter(value); if (enableTracking) debouncedInputEvent(userEvents, { actionType: "input", field: name }); }, [ enableTracking, name, setTextFilter, showList ]); useEffect(() => { document.addEventListener("click", handleClickOutside, true); return () => { document.removeEventListener("click", handleClickOutside, true); }; }, []); return /* @__PURE__ */ jsxs("div", { className: cx({ "adyen-kyc-dropdown": true, "adyen-kyc-dropdown--minimal": minimal }), ref: selectContainerRef, onFocusOut: handleBlur, children: [/* @__PURE__ */ jsx(SelectButton, { id, name, active, filterable, isFiltering, isInvalid, onButtonKeyDown: handleInputKeyDown, onInput: handleTextFilter, placeholder, readonly, selectListId, showList: isShowList, focusProps, "aria-describedby": ariaDescribedBy || "", "aria-label": ariaLabel || "", "aria-labelledby": ariaLabelledBy || "", isMulti: Boolean(isMulti), loading, behaviour, text: textFilter, inputRef, enableTracking, minimal, onClick: () => { if (isShowList) closeList("input"); else { showList(); focusInput(); } }, onFocus: () => { focusInput(); } }), /* @__PURE__ */ jsx(SelectList, { active, filteredItems: filtered, onKeyDown: handleListItemKeyDown, onSelect: handleSelect, selectListId, showList: isShowList, textFilter, isMulti: Boolean(isMulti), isSearch: filterable === "prefiltered", getSearchItem, loading, maxVisibleItems, focusProps, inputRef, minimal })] }); }; //#endregion export { SelectListItem as n, Select as t };