Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@n3/react-autocomplete

Package Overview
Dependencies
Maintainers
5
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@n3/react-autocomplete - npm Package Compare versions

Comparing version
1.0.0
to
2.0.0
+86
dist/index.d.mts
import { ComponentType, PropsWithChildren, HTMLProps, Ref, ReactNode, ChangeEventHandler, ReactElement } from 'react';
type WrapperComponent = ComponentType<PropsWithChildren>;
type InputComponentProps = HTMLProps<HTMLInputElement> & {
$hasError: boolean;
$hasWarning: boolean;
};
type InputComponent = ComponentType<InputComponentProps>;
type MenuComponent = ComponentType<PropsWithChildren<{
ref: Ref<HTMLElement>;
}>>;
type MenuItemProps = HTMLProps<HTMLDivElement> & {
$isHighlighted: boolean;
};
type MenuItemComponent = ComponentType<MenuItemProps>;
type Components = {
Wrapper: WrapperComponent;
Input: InputComponent;
Menu: MenuComponent;
MenuItem: MenuItemComponent;
};
type LoadOptionsResponse<Option> = {
options: Option[];
};
type LoadOptions<Option> = (inputValue: string) => LoadOptionsResponse<Option> | Promise<LoadOptionsResponse<Option>>;
type GetOptionLabel<Option> = (option: Option) => string;
type FormatOptionLabel<Option> = (Option: Option) => ReactNode;
type OnSelect<Option> = (value: string, option: Option) => void;
type AutocompleteProps<Option> = {
/**
* Функция загрузки опций
* @param {String} search - текущее значение поля ввода
* @returns {Object[]} response.options - опции
*/
loadOptions: LoadOptions<Option>;
/**
* Значение элемента input
*/
value: string;
/**
* Обработчик изменения значения поля при ручном вводе
*/
onChange?: ChangeEventHandler<HTMLInputElement>;
/**
* Обработчик изменения значения поля при выборе из меню
* @param {String} value - текст выбранной опции
* @param {Object} option - выбранная опция
*/
onSelect?: OnSelect<Option>;
/**
* Выключено ли поле
*/
disabled?: boolean;
/**
* Есть ли у поля ошибка
*/
hasError?: boolean;
/**
* Есть ли у поля предупреждение
*/
hasWarning?: boolean;
/**
* Дополнительные props элемента input
*/
inputProps?: Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange' | 'disabled'>;
/**
* Ключ, по которому хранится текст опции
*/
labelKey?: string;
/**
* Функция получения текста опции, который будет подставлен при выборе
*/
getOptionLabel?: GetOptionLabel<Option>;
/**
* Функция отображения опции
*/
formatOptionLabel?: FormatOptionLabel<Option>;
/**
* Переиспользуемые компоненты
*/
components?: Partial<Components>;
};
declare function Autocomplete<Option>({ loadOptions, value, onChange: onChangeProp, onSelect: onSelectProp, disabled, hasError, hasWarning, inputProps, labelKey, getOptionLabel: getOptionLabelProp, formatOptionLabel: formatOptionLabelProp, components: componentsProp, }: AutocompleteProps<Option>): ReactElement;
export { Autocomplete, AutocompleteProps, Components, FormatOptionLabel, GetOptionLabel, InputComponent, InputComponentProps, LoadOptions, LoadOptionsResponse, MenuComponent, MenuItemComponent, MenuItemProps, OnSelect, WrapperComponent };
+4
-4

@@ -44,6 +44,6 @@ // src/Autocomplete.tsx

zIndex: 1,
marginTop: 4,
maxHeight: 200,
marginTop: "4px",
maxHeight: "200px",
overflowY: "auto",
borderRadius: 4,
borderRadius: "4px",
backgroundColor: "#fff",

@@ -61,3 +61,3 @@ border: "1px solid #d9e1e8",

boxSizing: "border-box",
padding: 10,
padding: "10px",
color: "#666",

@@ -64,0 +64,0 @@ backgroundColor: $isHighlighted ? "#f9f9f9" : "#fff",

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/Autocomplete.tsx","../../src/components/Wrapper.tsx","../../src/components/Input.tsx","../../src/components/Menu.tsx","../../src/components/MenuItem.tsx","../../src/components/index.ts","../../src/Dropdown.tsx","../../src/DropdownItem.tsx"],"sourcesContent":["import {\n useCallback,\n useState,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport type {\n ChangeEventHandler,\n HTMLProps,\n ReactElement,\n} from 'react';\n\nimport { components as defaultComponents } from './components';\nimport { Dropdown } from './Dropdown';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n LoadOptions,\n OnSelect,\n} from './types';\n\nexport type AutocompleteProps<Option> = {\n /**\n * Функция загрузки опций\n * @param {String} search - текущее значение поля ввода\n * @returns {Object[]} response.options - опции\n */\n loadOptions: LoadOptions<Option>;\n /**\n * Значение элемента input\n */\n value: string;\n /**\n * Обработчик изменения значения поля при ручном вводе\n */\n onChange?: ChangeEventHandler<HTMLInputElement>;\n /**\n * Обработчик изменения значения поля при выборе из меню\n * @param {String} value - текст выбранной опции\n * @param {Object} option - выбранная опция\n */\n onSelect?: OnSelect<Option>;\n /**\n * Выключено ли поле\n */\n disabled?: boolean;\n /**\n * Есть ли у поля ошибка\n */\n hasError?: boolean;\n /**\n * Есть ли у поля предупреждение\n */\n hasWarning?: boolean;\n\n /**\n * Дополнительные props элемента input\n */\n inputProps?: Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange' | 'disabled'>;\n\n /**\n * Ключ, по которому хранится текст опции\n */\n labelKey?: string;\n /**\n * Функция получения текста опции, который будет подставлен при выборе\n */\n getOptionLabel?: GetOptionLabel<Option>;\n /**\n * Функция отображения опции\n */\n formatOptionLabel?: FormatOptionLabel<Option>;\n /**\n * Переиспользуемые компоненты\n */\n components?: Partial<Components>;\n};\n\nconst emptyObj = {};\n\nexport function Autocomplete<Option>({\n loadOptions,\n value,\n onChange: onChangeProp = undefined,\n onSelect: onSelectProp = undefined,\n disabled = false,\n hasError = false,\n hasWarning = false,\n inputProps = emptyObj,\n labelKey = 'label',\n getOptionLabel: getOptionLabelProp = undefined,\n formatOptionLabel: formatOptionLabelProp = undefined,\n components: componentsProp = emptyObj,\n}: AutocompleteProps<Option>): ReactElement {\n const components = useMemo<Components>(() => ({\n ...defaultComponents,\n ...componentsProp,\n }), [componentsProp]);\n\n const valueRef = useRef<string>(value);\n valueRef.current = value;\n\n const [options, setOptions] = useState<Option[]>([]);\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const getOptionLabel = useCallback<GetOptionLabel<Option>>((option) => {\n if (getOptionLabelProp) {\n return getOptionLabelProp(option);\n }\n\n if (typeof option === 'string') {\n return option;\n }\n\n if (typeof option === 'number') {\n return String(option);\n }\n\n if (!option || typeof option !== 'object') {\n return '';\n }\n\n const label = (option as Record<string, unknown>)[labelKey];\n\n if (typeof label === 'string') {\n return label;\n }\n\n if (typeof label === 'number') {\n return String(label);\n }\n\n return '';\n }, [getOptionLabelProp, labelKey]);\n\n const formatOptionLabel = useCallback<FormatOptionLabel<Option>>((option) => {\n if (formatOptionLabelProp) {\n return formatOptionLabelProp(option);\n }\n\n return getOptionLabel(option);\n }, [formatOptionLabelProp, getOptionLabel]);\n\n const onInputFocus = useCallback(() => {\n setIsOpen(true);\n }, []);\n\n const closeMenu = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n const onSelect = useCallback<OnSelect<Option>>((label, option) => {\n setIsOpen(false);\n\n if (onSelectProp) {\n onSelectProp(label, option);\n }\n }, [onSelectProp]);\n\n const onChange = useCallback<ChangeEventHandler<HTMLInputElement>>((event) => {\n if (onChangeProp) {\n onChangeProp(event);\n }\n\n if (!isOpen) {\n setIsOpen(true);\n }\n }, [onChangeProp, isOpen]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n const response = await loadOptions(value);\n\n if (valueRef.current === value) {\n setOptions(response.options);\n }\n })().catch((e) => {\n throw e;\n });\n }, [\n loadOptions,\n value,\n ]);\n\n const {\n Wrapper,\n Input,\n } = components;\n\n return (\n <Wrapper>\n <Input\n {...inputProps}\n disabled={disabled}\n $hasError={hasError}\n $hasWarning={hasWarning}\n value={value}\n onChange={onChange}\n onFocus={onInputFocus}\n />\n\n {\n isOpen && options.length > 0 && (\n <Dropdown\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n options={options}\n onSelect={onSelect}\n closeMenu={closeMenu}\n />\n )\n }\n </Wrapper>\n );\n}\n","import styled from 'styled-components';\n\nimport type {\n WrapperComponent,\n} from '../types';\n\nexport const Wrapper: WrapperComponent = styled.div({\n position: 'relative',\n});\n","import styled from 'styled-components';\nimport type {\n CSSObject,\n} from 'styled-components';\n\nimport type {\n InputComponentProps,\n InputComponent,\n} from '../types';\n\nexport const Input: InputComponent = styled.input<InputComponentProps>(({\n $hasError,\n $hasWarning,\n}) => {\n const res: CSSObject = {\n width: '100%',\n boxSizing: 'border-box',\n };\n\n if ($hasError) {\n res.borderColor = '#d64c4c';\n res.backgroundColor = '#fdf6f6';\n } else if ($hasWarning) {\n res.borderColor = '#eea505';\n res.backgroundColor = '#fdf6e6';\n }\n\n return res;\n});\n","import styled from 'styled-components';\n\nimport type {\n MenuComponent,\n} from '../types';\n\nexport const Menu: MenuComponent = styled.div({\n boxSizing: 'border-box',\n position: 'absolute',\n top: '100%',\n width: '100%',\n zIndex: 1,\n marginTop: 4,\n maxHeight: 200,\n overflowY: 'auto',\n borderRadius: 4,\n backgroundColor: '#fff',\n border: '1px solid #d9e1e8',\n boxShadow: '0 1px 0 rgba(0, 0, 0, 0.06)',\n});\n","import styled from 'styled-components';\n\nimport type {\n MenuItemProps,\n MenuItemComponent,\n} from '../types';\n\nexport const MenuItem: MenuItemComponent = styled.div<MenuItemProps>(({\n $isHighlighted,\n}) => ({\n display: 'block',\n boxSizing: 'border-box',\n padding: 10,\n color: '#666',\n backgroundColor: $isHighlighted ? '#f9f9f9' : '#fff',\n cursor: 'pointer',\n}));\n","import { Wrapper } from './Wrapper';\nimport { Input } from './Input';\nimport { Menu } from './Menu';\nimport { MenuItem } from './MenuItem';\n\nimport type {\n Components,\n} from '../types';\n\nexport const components: Components = {\n Wrapper,\n Input,\n Menu,\n MenuItem,\n};\n","import {\n useRef,\n useState,\n useEffect,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport useOnClickOutside from 'use-onclickoutside';\n\nimport { DropdownItem } from './DropdownItem';\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n options: Option[];\n onSelect: OnSelect<Option>;\n closeMenu: () => void;\n};\n\nexport function Dropdown<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n options,\n onSelect,\n closeMenu,\n}: DropdownProps<Option>): ReactElement {\n const rootRef = useRef<HTMLElement>(null);\n useOnClickOutside(rootRef, closeMenu);\n\n const isInitRef = useRef<boolean>(true);\n\n const [highlightedIndex, setHighlightedIndex] = useState<number>(0);\n\n const highlightedIndexRef = useRef<number>(highlightedIndex);\n highlightedIndexRef.current = highlightedIndex;\n\n useEffect(() => {\n if (isInitRef.current) {\n isInitRef.current = false;\n } else {\n setHighlightedIndex(0);\n }\n\n const onKeyDown = (event: KeyboardEvent): void => {\n switch (event.key) {\n case 'ArrowDown':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === options.length - 1) {\n return 0;\n }\n\n return prevIndex + 1;\n });\n break;\n\n case 'ArrowUp':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === 0) {\n return options.length - 1;\n }\n\n return prevIndex - 1;\n });\n break;\n\n case 'Enter':\n {\n const option = options[highlightedIndexRef.current];\n onSelect(getOptionLabel(option), option);\n\n break;\n }\n\n default:\n break;\n }\n };\n\n document.addEventListener('keydown', onKeyDown);\n\n return (): void => {\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [\n options,\n getOptionLabel,\n onSelect,\n ]);\n\n const {\n Menu,\n } = components;\n\n return (\n <Menu\n ref={rootRef}\n >\n {\n options.map((option, index) => (\n <DropdownItem\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n option={option}\n isHighlighted={highlightedIndex === index}\n onSelect={onSelect}\n setHighlightedIndex={setHighlightedIndex}\n index={index}\n key={index}\n />\n ))\n }\n </Menu>\n );\n}\n","import {\n useCallback,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownItemProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n option: Option;\n isHighlighted: boolean;\n onSelect: OnSelect<Option>;\n setHighlightedIndex: (index: number) => void;\n index: number;\n};\n\nexport function DropdownItem<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n isHighlighted,\n option,\n onSelect,\n setHighlightedIndex,\n index,\n}: DropdownItemProps<Option>): ReactElement {\n const onClick = useCallback(() => {\n onSelect(getOptionLabel(option), option);\n }, [onSelect, option, getOptionLabel]);\n\n const onMouseEnter = useCallback(() => {\n setHighlightedIndex(index);\n }, [setHighlightedIndex, index]);\n\n const {\n MenuItem,\n } = components;\n\n return (\n <MenuItem\n $isHighlighted={isHighlighted}\n onMouseEnter={onMouseEnter}\n onClick={onClick}\n >\n {formatOptionLabel(option)}\n </MenuItem>\n );\n}\n"],"mappings":"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","names":["useCallback","useState","useRef","useEffect","styled","styled","styled","components","MenuItem","jsx","components","Menu","jsx","components","useRef","useState","useCallback","useEffect","Wrapper","Input"]}
{"version":3,"sources":["../../src/Autocomplete.tsx","../../src/components/Wrapper.tsx","../../src/components/Input.tsx","../../src/components/Menu.tsx","../../src/components/MenuItem.tsx","../../src/components/index.ts","../../src/Dropdown.tsx","../../src/DropdownItem.tsx"],"sourcesContent":["import {\n useCallback,\n useState,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport type {\n ChangeEventHandler,\n HTMLProps,\n ReactElement,\n} from 'react';\n\nimport { components as defaultComponents } from './components';\nimport { Dropdown } from './Dropdown';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n LoadOptions,\n OnSelect,\n} from './types';\n\nexport type AutocompleteProps<Option> = {\n /**\n * Функция загрузки опций\n * @param {String} search - текущее значение поля ввода\n * @returns {Object[]} response.options - опции\n */\n loadOptions: LoadOptions<Option>;\n /**\n * Значение элемента input\n */\n value: string;\n /**\n * Обработчик изменения значения поля при ручном вводе\n */\n onChange?: ChangeEventHandler<HTMLInputElement>;\n /**\n * Обработчик изменения значения поля при выборе из меню\n * @param {String} value - текст выбранной опции\n * @param {Object} option - выбранная опция\n */\n onSelect?: OnSelect<Option>;\n /**\n * Выключено ли поле\n */\n disabled?: boolean;\n /**\n * Есть ли у поля ошибка\n */\n hasError?: boolean;\n /**\n * Есть ли у поля предупреждение\n */\n hasWarning?: boolean;\n\n /**\n * Дополнительные props элемента input\n */\n inputProps?: Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange' | 'disabled'>;\n\n /**\n * Ключ, по которому хранится текст опции\n */\n labelKey?: string;\n /**\n * Функция получения текста опции, который будет подставлен при выборе\n */\n getOptionLabel?: GetOptionLabel<Option>;\n /**\n * Функция отображения опции\n */\n formatOptionLabel?: FormatOptionLabel<Option>;\n /**\n * Переиспользуемые компоненты\n */\n components?: Partial<Components>;\n};\n\nconst emptyObj = {};\n\nexport function Autocomplete<Option>({\n loadOptions,\n value,\n onChange: onChangeProp = undefined,\n onSelect: onSelectProp = undefined,\n disabled = false,\n hasError = false,\n hasWarning = false,\n inputProps = emptyObj,\n labelKey = 'label',\n getOptionLabel: getOptionLabelProp = undefined,\n formatOptionLabel: formatOptionLabelProp = undefined,\n components: componentsProp = emptyObj,\n}: AutocompleteProps<Option>): ReactElement {\n const components = useMemo<Components>(() => ({\n ...defaultComponents,\n ...componentsProp,\n }), [componentsProp]);\n\n const valueRef = useRef<string>(value);\n valueRef.current = value;\n\n const [options, setOptions] = useState<Option[]>([]);\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const getOptionLabel = useCallback<GetOptionLabel<Option>>((option) => {\n if (getOptionLabelProp) {\n return getOptionLabelProp(option);\n }\n\n if (typeof option === 'string') {\n return option;\n }\n\n if (typeof option === 'number') {\n return String(option);\n }\n\n if (!option || typeof option !== 'object') {\n return '';\n }\n\n const label = (option as Record<string, unknown>)[labelKey];\n\n if (typeof label === 'string') {\n return label;\n }\n\n if (typeof label === 'number') {\n return String(label);\n }\n\n return '';\n }, [getOptionLabelProp, labelKey]);\n\n const formatOptionLabel = useCallback<FormatOptionLabel<Option>>((option) => {\n if (formatOptionLabelProp) {\n return formatOptionLabelProp(option);\n }\n\n return getOptionLabel(option);\n }, [formatOptionLabelProp, getOptionLabel]);\n\n const onInputFocus = useCallback(() => {\n setIsOpen(true);\n }, []);\n\n const closeMenu = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n const onSelect = useCallback<OnSelect<Option>>((label, option) => {\n setIsOpen(false);\n\n if (onSelectProp) {\n onSelectProp(label, option);\n }\n }, [onSelectProp]);\n\n const onChange = useCallback<ChangeEventHandler<HTMLInputElement>>((event) => {\n if (onChangeProp) {\n onChangeProp(event);\n }\n\n if (!isOpen) {\n setIsOpen(true);\n }\n }, [onChangeProp, isOpen]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n const response = await loadOptions(value);\n\n if (valueRef.current === value) {\n setOptions(response.options);\n }\n })().catch((e) => {\n throw e;\n });\n }, [\n loadOptions,\n value,\n ]);\n\n const {\n Wrapper,\n Input,\n } = components;\n\n return (\n <Wrapper>\n <Input\n {...inputProps}\n disabled={disabled}\n $hasError={hasError}\n $hasWarning={hasWarning}\n value={value}\n onChange={onChange}\n onFocus={onInputFocus}\n />\n\n {\n isOpen && options.length > 0 && (\n <Dropdown\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n options={options}\n onSelect={onSelect}\n closeMenu={closeMenu}\n />\n )\n }\n </Wrapper>\n );\n}\n","import styled from 'styled-components';\n\nimport type {\n WrapperComponent,\n} from '../types';\n\nexport const Wrapper: WrapperComponent = styled.div({\n position: 'relative',\n});\n","import styled from 'styled-components';\nimport type {\n StyledObject,\n} from 'styled-components';\n\nimport type {\n InputComponentProps,\n InputComponent,\n} from '../types';\n\nexport const Input: InputComponent = styled.input<InputComponentProps>(({\n $hasError,\n $hasWarning,\n}) => {\n const res: StyledObject<object> = {\n width: '100%',\n boxSizing: 'border-box',\n };\n\n if ($hasError) {\n res.borderColor = '#d64c4c';\n res.backgroundColor = '#fdf6f6';\n } else if ($hasWarning) {\n res.borderColor = '#eea505';\n res.backgroundColor = '#fdf6e6';\n }\n\n return res;\n});\n","import styled from 'styled-components';\n\nimport type {\n MenuComponent,\n} from '../types';\n\nexport const Menu = styled.div({\n boxSizing: 'border-box',\n position: 'absolute',\n top: '100%',\n width: '100%',\n zIndex: 1,\n marginTop: '4px',\n maxHeight: '200px',\n overflowY: 'auto',\n borderRadius: '4px',\n backgroundColor: '#fff',\n border: '1px solid #d9e1e8',\n boxShadow: '0 1px 0 rgba(0, 0, 0, 0.06)',\n}) as unknown as MenuComponent;\n","import styled from 'styled-components';\n\nimport type {\n MenuItemProps,\n MenuItemComponent,\n} from '../types';\n\nexport const MenuItem: MenuItemComponent = styled.div<MenuItemProps>(({\n $isHighlighted,\n}) => ({\n display: 'block',\n boxSizing: 'border-box',\n padding: '10px',\n color: '#666',\n backgroundColor: $isHighlighted ? '#f9f9f9' : '#fff',\n cursor: 'pointer',\n}));\n","import { Wrapper } from './Wrapper';\nimport { Input } from './Input';\nimport { Menu } from './Menu';\nimport { MenuItem } from './MenuItem';\n\nimport type {\n Components,\n} from '../types';\n\nexport const components: Components = {\n Wrapper,\n Input,\n Menu,\n MenuItem,\n};\n","import {\n useRef,\n useState,\n useEffect,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport useOnClickOutside from 'use-onclickoutside';\n\nimport { DropdownItem } from './DropdownItem';\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n options: Option[];\n onSelect: OnSelect<Option>;\n closeMenu: () => void;\n};\n\nexport function Dropdown<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n options,\n onSelect,\n closeMenu,\n}: DropdownProps<Option>): ReactElement {\n const rootRef = useRef<HTMLElement>(null);\n useOnClickOutside(rootRef, closeMenu);\n\n const isInitRef = useRef<boolean>(true);\n\n const [highlightedIndex, setHighlightedIndex] = useState<number>(0);\n\n const highlightedIndexRef = useRef<number>(highlightedIndex);\n highlightedIndexRef.current = highlightedIndex;\n\n useEffect(() => {\n if (isInitRef.current) {\n isInitRef.current = false;\n } else {\n setHighlightedIndex(0);\n }\n\n const onKeyDown = (event: KeyboardEvent): void => {\n switch (event.key) {\n case 'ArrowDown':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === options.length - 1) {\n return 0;\n }\n\n return prevIndex + 1;\n });\n break;\n\n case 'ArrowUp':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === 0) {\n return options.length - 1;\n }\n\n return prevIndex - 1;\n });\n break;\n\n case 'Enter':\n {\n const option = options[highlightedIndexRef.current];\n onSelect(getOptionLabel(option), option);\n\n break;\n }\n\n default:\n break;\n }\n };\n\n document.addEventListener('keydown', onKeyDown);\n\n return (): void => {\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [\n options,\n getOptionLabel,\n onSelect,\n ]);\n\n const {\n Menu,\n } = components;\n\n return (\n <Menu\n ref={rootRef}\n >\n {\n options.map((option, index) => (\n <DropdownItem\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n option={option}\n isHighlighted={highlightedIndex === index}\n onSelect={onSelect}\n setHighlightedIndex={setHighlightedIndex}\n index={index}\n key={index}\n />\n ))\n }\n </Menu>\n );\n}\n","import {\n useCallback,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownItemProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n option: Option;\n isHighlighted: boolean;\n onSelect: OnSelect<Option>;\n setHighlightedIndex: (index: number) => void;\n index: number;\n};\n\nexport function DropdownItem<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n isHighlighted,\n option,\n onSelect,\n setHighlightedIndex,\n index,\n}: DropdownItemProps<Option>): ReactElement {\n const onClick = useCallback(() => {\n onSelect(getOptionLabel(option), option);\n }, [onSelect, option, getOptionLabel]);\n\n const onMouseEnter = useCallback(() => {\n setHighlightedIndex(index);\n }, [setHighlightedIndex, index]);\n\n const {\n MenuItem,\n } = components;\n\n return (\n <MenuItem\n $isHighlighted={isHighlighted}\n onMouseEnter={onMouseEnter}\n onClick={onClick}\n >\n {formatOptionLabel(option)}\n </MenuItem>\n );\n}\n"],"mappings":"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","names":["useCallback","useState","useRef","useEffect","styled","styled","styled","components","MenuItem","jsx","components","Menu","jsx","components","useRef","useState","useCallback","useEffect","Wrapper","Input"]}

@@ -74,6 +74,6 @@ "use strict";

zIndex: 1,
marginTop: 4,
maxHeight: 200,
marginTop: "4px",
maxHeight: "200px",
overflowY: "auto",
borderRadius: 4,
borderRadius: "4px",
backgroundColor: "#fff",

@@ -91,3 +91,3 @@ border: "1px solid #d9e1e8",

boxSizing: "border-box",
padding: 10,
padding: "10px",
color: "#666",

@@ -94,0 +94,0 @@ backgroundColor: $isHighlighted ? "#f9f9f9" : "#fff",

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/Autocomplete.tsx","../src/components/Wrapper.tsx","../src/components/Input.tsx","../src/components/Menu.tsx","../src/components/MenuItem.tsx","../src/components/index.ts","../src/Dropdown.tsx","../src/DropdownItem.tsx"],"sourcesContent":["export { Autocomplete } from './Autocomplete';\nexport type {\n AutocompleteProps,\n} from './Autocomplete';\n\nexport * from './types';\n","import {\n useCallback,\n useState,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport type {\n ChangeEventHandler,\n HTMLProps,\n ReactElement,\n} from 'react';\n\nimport { components as defaultComponents } from './components';\nimport { Dropdown } from './Dropdown';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n LoadOptions,\n OnSelect,\n} from './types';\n\nexport type AutocompleteProps<Option> = {\n /**\n * Функция загрузки опций\n * @param {String} search - текущее значение поля ввода\n * @returns {Object[]} response.options - опции\n */\n loadOptions: LoadOptions<Option>;\n /**\n * Значение элемента input\n */\n value: string;\n /**\n * Обработчик изменения значения поля при ручном вводе\n */\n onChange?: ChangeEventHandler<HTMLInputElement>;\n /**\n * Обработчик изменения значения поля при выборе из меню\n * @param {String} value - текст выбранной опции\n * @param {Object} option - выбранная опция\n */\n onSelect?: OnSelect<Option>;\n /**\n * Выключено ли поле\n */\n disabled?: boolean;\n /**\n * Есть ли у поля ошибка\n */\n hasError?: boolean;\n /**\n * Есть ли у поля предупреждение\n */\n hasWarning?: boolean;\n\n /**\n * Дополнительные props элемента input\n */\n inputProps?: Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange' | 'disabled'>;\n\n /**\n * Ключ, по которому хранится текст опции\n */\n labelKey?: string;\n /**\n * Функция получения текста опции, который будет подставлен при выборе\n */\n getOptionLabel?: GetOptionLabel<Option>;\n /**\n * Функция отображения опции\n */\n formatOptionLabel?: FormatOptionLabel<Option>;\n /**\n * Переиспользуемые компоненты\n */\n components?: Partial<Components>;\n};\n\nconst emptyObj = {};\n\nexport function Autocomplete<Option>({\n loadOptions,\n value,\n onChange: onChangeProp = undefined,\n onSelect: onSelectProp = undefined,\n disabled = false,\n hasError = false,\n hasWarning = false,\n inputProps = emptyObj,\n labelKey = 'label',\n getOptionLabel: getOptionLabelProp = undefined,\n formatOptionLabel: formatOptionLabelProp = undefined,\n components: componentsProp = emptyObj,\n}: AutocompleteProps<Option>): ReactElement {\n const components = useMemo<Components>(() => ({\n ...defaultComponents,\n ...componentsProp,\n }), [componentsProp]);\n\n const valueRef = useRef<string>(value);\n valueRef.current = value;\n\n const [options, setOptions] = useState<Option[]>([]);\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const getOptionLabel = useCallback<GetOptionLabel<Option>>((option) => {\n if (getOptionLabelProp) {\n return getOptionLabelProp(option);\n }\n\n if (typeof option === 'string') {\n return option;\n }\n\n if (typeof option === 'number') {\n return String(option);\n }\n\n if (!option || typeof option !== 'object') {\n return '';\n }\n\n const label = (option as Record<string, unknown>)[labelKey];\n\n if (typeof label === 'string') {\n return label;\n }\n\n if (typeof label === 'number') {\n return String(label);\n }\n\n return '';\n }, [getOptionLabelProp, labelKey]);\n\n const formatOptionLabel = useCallback<FormatOptionLabel<Option>>((option) => {\n if (formatOptionLabelProp) {\n return formatOptionLabelProp(option);\n }\n\n return getOptionLabel(option);\n }, [formatOptionLabelProp, getOptionLabel]);\n\n const onInputFocus = useCallback(() => {\n setIsOpen(true);\n }, []);\n\n const closeMenu = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n const onSelect = useCallback<OnSelect<Option>>((label, option) => {\n setIsOpen(false);\n\n if (onSelectProp) {\n onSelectProp(label, option);\n }\n }, [onSelectProp]);\n\n const onChange = useCallback<ChangeEventHandler<HTMLInputElement>>((event) => {\n if (onChangeProp) {\n onChangeProp(event);\n }\n\n if (!isOpen) {\n setIsOpen(true);\n }\n }, [onChangeProp, isOpen]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n const response = await loadOptions(value);\n\n if (valueRef.current === value) {\n setOptions(response.options);\n }\n })().catch((e) => {\n throw e;\n });\n }, [\n loadOptions,\n value,\n ]);\n\n const {\n Wrapper,\n Input,\n } = components;\n\n return (\n <Wrapper>\n <Input\n {...inputProps}\n disabled={disabled}\n $hasError={hasError}\n $hasWarning={hasWarning}\n value={value}\n onChange={onChange}\n onFocus={onInputFocus}\n />\n\n {\n isOpen && options.length > 0 && (\n <Dropdown\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n options={options}\n onSelect={onSelect}\n closeMenu={closeMenu}\n />\n )\n }\n </Wrapper>\n );\n}\n","import styled from 'styled-components';\n\nimport type {\n WrapperComponent,\n} from '../types';\n\nexport const Wrapper: WrapperComponent = styled.div({\n position: 'relative',\n});\n","import styled from 'styled-components';\nimport type {\n CSSObject,\n} from 'styled-components';\n\nimport type {\n InputComponentProps,\n InputComponent,\n} from '../types';\n\nexport const Input: InputComponent = styled.input<InputComponentProps>(({\n $hasError,\n $hasWarning,\n}) => {\n const res: CSSObject = {\n width: '100%',\n boxSizing: 'border-box',\n };\n\n if ($hasError) {\n res.borderColor = '#d64c4c';\n res.backgroundColor = '#fdf6f6';\n } else if ($hasWarning) {\n res.borderColor = '#eea505';\n res.backgroundColor = '#fdf6e6';\n }\n\n return res;\n});\n","import styled from 'styled-components';\n\nimport type {\n MenuComponent,\n} from '../types';\n\nexport const Menu: MenuComponent = styled.div({\n boxSizing: 'border-box',\n position: 'absolute',\n top: '100%',\n width: '100%',\n zIndex: 1,\n marginTop: 4,\n maxHeight: 200,\n overflowY: 'auto',\n borderRadius: 4,\n backgroundColor: '#fff',\n border: '1px solid #d9e1e8',\n boxShadow: '0 1px 0 rgba(0, 0, 0, 0.06)',\n});\n","import styled from 'styled-components';\n\nimport type {\n MenuItemProps,\n MenuItemComponent,\n} from '../types';\n\nexport const MenuItem: MenuItemComponent = styled.div<MenuItemProps>(({\n $isHighlighted,\n}) => ({\n display: 'block',\n boxSizing: 'border-box',\n padding: 10,\n color: '#666',\n backgroundColor: $isHighlighted ? '#f9f9f9' : '#fff',\n cursor: 'pointer',\n}));\n","import { Wrapper } from './Wrapper';\nimport { Input } from './Input';\nimport { Menu } from './Menu';\nimport { MenuItem } from './MenuItem';\n\nimport type {\n Components,\n} from '../types';\n\nexport const components: Components = {\n Wrapper,\n Input,\n Menu,\n MenuItem,\n};\n","import {\n useRef,\n useState,\n useEffect,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport useOnClickOutside from 'use-onclickoutside';\n\nimport { DropdownItem } from './DropdownItem';\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n options: Option[];\n onSelect: OnSelect<Option>;\n closeMenu: () => void;\n};\n\nexport function Dropdown<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n options,\n onSelect,\n closeMenu,\n}: DropdownProps<Option>): ReactElement {\n const rootRef = useRef<HTMLElement>(null);\n useOnClickOutside(rootRef, closeMenu);\n\n const isInitRef = useRef<boolean>(true);\n\n const [highlightedIndex, setHighlightedIndex] = useState<number>(0);\n\n const highlightedIndexRef = useRef<number>(highlightedIndex);\n highlightedIndexRef.current = highlightedIndex;\n\n useEffect(() => {\n if (isInitRef.current) {\n isInitRef.current = false;\n } else {\n setHighlightedIndex(0);\n }\n\n const onKeyDown = (event: KeyboardEvent): void => {\n switch (event.key) {\n case 'ArrowDown':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === options.length - 1) {\n return 0;\n }\n\n return prevIndex + 1;\n });\n break;\n\n case 'ArrowUp':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === 0) {\n return options.length - 1;\n }\n\n return prevIndex - 1;\n });\n break;\n\n case 'Enter':\n {\n const option = options[highlightedIndexRef.current];\n onSelect(getOptionLabel(option), option);\n\n break;\n }\n\n default:\n break;\n }\n };\n\n document.addEventListener('keydown', onKeyDown);\n\n return (): void => {\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [\n options,\n getOptionLabel,\n onSelect,\n ]);\n\n const {\n Menu,\n } = components;\n\n return (\n <Menu\n ref={rootRef}\n >\n {\n options.map((option, index) => (\n <DropdownItem\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n option={option}\n isHighlighted={highlightedIndex === index}\n onSelect={onSelect}\n setHighlightedIndex={setHighlightedIndex}\n index={index}\n key={index}\n />\n ))\n }\n </Menu>\n );\n}\n","import {\n useCallback,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownItemProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n option: Option;\n isHighlighted: boolean;\n onSelect: OnSelect<Option>;\n setHighlightedIndex: (index: number) => void;\n index: number;\n};\n\nexport function DropdownItem<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n isHighlighted,\n option,\n onSelect,\n setHighlightedIndex,\n index,\n}: DropdownItemProps<Option>): ReactElement {\n const onClick = useCallback(() => {\n onSelect(getOptionLabel(option), option);\n }, [onSelect, option, getOptionLabel]);\n\n const onMouseEnter = useCallback(() => {\n setHighlightedIndex(index);\n }, [setHighlightedIndex, index]);\n\n const {\n MenuItem,\n } = components;\n\n return (\n <MenuItem\n $isHighlighted={isHighlighted}\n onMouseEnter={onMouseEnter}\n onClick={onClick}\n >\n {formatOptionLabel(option)}\n </MenuItem>\n );\n}\n"],"mappings":"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","names":["import_react","styled","import_styled_components","styled","import_styled_components","styled","import_styled_components","styled","import_react","components","MenuItem","import_jsx_runtime","components","useOnClickOutside","Menu","import_jsx_runtime","components","Wrapper","Input"]}
{"version":3,"sources":["../src/index.ts","../src/Autocomplete.tsx","../src/components/Wrapper.tsx","../src/components/Input.tsx","../src/components/Menu.tsx","../src/components/MenuItem.tsx","../src/components/index.ts","../src/Dropdown.tsx","../src/DropdownItem.tsx"],"sourcesContent":["export { Autocomplete } from './Autocomplete';\nexport type {\n AutocompleteProps,\n} from './Autocomplete';\n\nexport * from './types';\n","import {\n useCallback,\n useState,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport type {\n ChangeEventHandler,\n HTMLProps,\n ReactElement,\n} from 'react';\n\nimport { components as defaultComponents } from './components';\nimport { Dropdown } from './Dropdown';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n LoadOptions,\n OnSelect,\n} from './types';\n\nexport type AutocompleteProps<Option> = {\n /**\n * Функция загрузки опций\n * @param {String} search - текущее значение поля ввода\n * @returns {Object[]} response.options - опции\n */\n loadOptions: LoadOptions<Option>;\n /**\n * Значение элемента input\n */\n value: string;\n /**\n * Обработчик изменения значения поля при ручном вводе\n */\n onChange?: ChangeEventHandler<HTMLInputElement>;\n /**\n * Обработчик изменения значения поля при выборе из меню\n * @param {String} value - текст выбранной опции\n * @param {Object} option - выбранная опция\n */\n onSelect?: OnSelect<Option>;\n /**\n * Выключено ли поле\n */\n disabled?: boolean;\n /**\n * Есть ли у поля ошибка\n */\n hasError?: boolean;\n /**\n * Есть ли у поля предупреждение\n */\n hasWarning?: boolean;\n\n /**\n * Дополнительные props элемента input\n */\n inputProps?: Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange' | 'disabled'>;\n\n /**\n * Ключ, по которому хранится текст опции\n */\n labelKey?: string;\n /**\n * Функция получения текста опции, который будет подставлен при выборе\n */\n getOptionLabel?: GetOptionLabel<Option>;\n /**\n * Функция отображения опции\n */\n formatOptionLabel?: FormatOptionLabel<Option>;\n /**\n * Переиспользуемые компоненты\n */\n components?: Partial<Components>;\n};\n\nconst emptyObj = {};\n\nexport function Autocomplete<Option>({\n loadOptions,\n value,\n onChange: onChangeProp = undefined,\n onSelect: onSelectProp = undefined,\n disabled = false,\n hasError = false,\n hasWarning = false,\n inputProps = emptyObj,\n labelKey = 'label',\n getOptionLabel: getOptionLabelProp = undefined,\n formatOptionLabel: formatOptionLabelProp = undefined,\n components: componentsProp = emptyObj,\n}: AutocompleteProps<Option>): ReactElement {\n const components = useMemo<Components>(() => ({\n ...defaultComponents,\n ...componentsProp,\n }), [componentsProp]);\n\n const valueRef = useRef<string>(value);\n valueRef.current = value;\n\n const [options, setOptions] = useState<Option[]>([]);\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const getOptionLabel = useCallback<GetOptionLabel<Option>>((option) => {\n if (getOptionLabelProp) {\n return getOptionLabelProp(option);\n }\n\n if (typeof option === 'string') {\n return option;\n }\n\n if (typeof option === 'number') {\n return String(option);\n }\n\n if (!option || typeof option !== 'object') {\n return '';\n }\n\n const label = (option as Record<string, unknown>)[labelKey];\n\n if (typeof label === 'string') {\n return label;\n }\n\n if (typeof label === 'number') {\n return String(label);\n }\n\n return '';\n }, [getOptionLabelProp, labelKey]);\n\n const formatOptionLabel = useCallback<FormatOptionLabel<Option>>((option) => {\n if (formatOptionLabelProp) {\n return formatOptionLabelProp(option);\n }\n\n return getOptionLabel(option);\n }, [formatOptionLabelProp, getOptionLabel]);\n\n const onInputFocus = useCallback(() => {\n setIsOpen(true);\n }, []);\n\n const closeMenu = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n const onSelect = useCallback<OnSelect<Option>>((label, option) => {\n setIsOpen(false);\n\n if (onSelectProp) {\n onSelectProp(label, option);\n }\n }, [onSelectProp]);\n\n const onChange = useCallback<ChangeEventHandler<HTMLInputElement>>((event) => {\n if (onChangeProp) {\n onChangeProp(event);\n }\n\n if (!isOpen) {\n setIsOpen(true);\n }\n }, [onChangeProp, isOpen]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n const response = await loadOptions(value);\n\n if (valueRef.current === value) {\n setOptions(response.options);\n }\n })().catch((e) => {\n throw e;\n });\n }, [\n loadOptions,\n value,\n ]);\n\n const {\n Wrapper,\n Input,\n } = components;\n\n return (\n <Wrapper>\n <Input\n {...inputProps}\n disabled={disabled}\n $hasError={hasError}\n $hasWarning={hasWarning}\n value={value}\n onChange={onChange}\n onFocus={onInputFocus}\n />\n\n {\n isOpen && options.length > 0 && (\n <Dropdown\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n options={options}\n onSelect={onSelect}\n closeMenu={closeMenu}\n />\n )\n }\n </Wrapper>\n );\n}\n","import styled from 'styled-components';\n\nimport type {\n WrapperComponent,\n} from '../types';\n\nexport const Wrapper: WrapperComponent = styled.div({\n position: 'relative',\n});\n","import styled from 'styled-components';\nimport type {\n StyledObject,\n} from 'styled-components';\n\nimport type {\n InputComponentProps,\n InputComponent,\n} from '../types';\n\nexport const Input: InputComponent = styled.input<InputComponentProps>(({\n $hasError,\n $hasWarning,\n}) => {\n const res: StyledObject<object> = {\n width: '100%',\n boxSizing: 'border-box',\n };\n\n if ($hasError) {\n res.borderColor = '#d64c4c';\n res.backgroundColor = '#fdf6f6';\n } else if ($hasWarning) {\n res.borderColor = '#eea505';\n res.backgroundColor = '#fdf6e6';\n }\n\n return res;\n});\n","import styled from 'styled-components';\n\nimport type {\n MenuComponent,\n} from '../types';\n\nexport const Menu = styled.div({\n boxSizing: 'border-box',\n position: 'absolute',\n top: '100%',\n width: '100%',\n zIndex: 1,\n marginTop: '4px',\n maxHeight: '200px',\n overflowY: 'auto',\n borderRadius: '4px',\n backgroundColor: '#fff',\n border: '1px solid #d9e1e8',\n boxShadow: '0 1px 0 rgba(0, 0, 0, 0.06)',\n}) as unknown as MenuComponent;\n","import styled from 'styled-components';\n\nimport type {\n MenuItemProps,\n MenuItemComponent,\n} from '../types';\n\nexport const MenuItem: MenuItemComponent = styled.div<MenuItemProps>(({\n $isHighlighted,\n}) => ({\n display: 'block',\n boxSizing: 'border-box',\n padding: '10px',\n color: '#666',\n backgroundColor: $isHighlighted ? '#f9f9f9' : '#fff',\n cursor: 'pointer',\n}));\n","import { Wrapper } from './Wrapper';\nimport { Input } from './Input';\nimport { Menu } from './Menu';\nimport { MenuItem } from './MenuItem';\n\nimport type {\n Components,\n} from '../types';\n\nexport const components: Components = {\n Wrapper,\n Input,\n Menu,\n MenuItem,\n};\n","import {\n useRef,\n useState,\n useEffect,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport useOnClickOutside from 'use-onclickoutside';\n\nimport { DropdownItem } from './DropdownItem';\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n options: Option[];\n onSelect: OnSelect<Option>;\n closeMenu: () => void;\n};\n\nexport function Dropdown<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n options,\n onSelect,\n closeMenu,\n}: DropdownProps<Option>): ReactElement {\n const rootRef = useRef<HTMLElement>(null);\n useOnClickOutside(rootRef, closeMenu);\n\n const isInitRef = useRef<boolean>(true);\n\n const [highlightedIndex, setHighlightedIndex] = useState<number>(0);\n\n const highlightedIndexRef = useRef<number>(highlightedIndex);\n highlightedIndexRef.current = highlightedIndex;\n\n useEffect(() => {\n if (isInitRef.current) {\n isInitRef.current = false;\n } else {\n setHighlightedIndex(0);\n }\n\n const onKeyDown = (event: KeyboardEvent): void => {\n switch (event.key) {\n case 'ArrowDown':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === options.length - 1) {\n return 0;\n }\n\n return prevIndex + 1;\n });\n break;\n\n case 'ArrowUp':\n setHighlightedIndex((prevIndex) => {\n if (prevIndex === 0) {\n return options.length - 1;\n }\n\n return prevIndex - 1;\n });\n break;\n\n case 'Enter':\n {\n const option = options[highlightedIndexRef.current];\n onSelect(getOptionLabel(option), option);\n\n break;\n }\n\n default:\n break;\n }\n };\n\n document.addEventListener('keydown', onKeyDown);\n\n return (): void => {\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [\n options,\n getOptionLabel,\n onSelect,\n ]);\n\n const {\n Menu,\n } = components;\n\n return (\n <Menu\n ref={rootRef}\n >\n {\n options.map((option, index) => (\n <DropdownItem\n components={components}\n getOptionLabel={getOptionLabel}\n formatOptionLabel={formatOptionLabel}\n option={option}\n isHighlighted={highlightedIndex === index}\n onSelect={onSelect}\n setHighlightedIndex={setHighlightedIndex}\n index={index}\n key={index}\n />\n ))\n }\n </Menu>\n );\n}\n","import {\n useCallback,\n} from 'react';\nimport type {\n ReactElement,\n} from 'react';\n\nimport type {\n Components,\n FormatOptionLabel,\n GetOptionLabel,\n OnSelect,\n} from './types';\n\nexport type DropdownItemProps<Option> = {\n components: Components;\n getOptionLabel: GetOptionLabel<Option>;\n formatOptionLabel: FormatOptionLabel<Option>;\n option: Option;\n isHighlighted: boolean;\n onSelect: OnSelect<Option>;\n setHighlightedIndex: (index: number) => void;\n index: number;\n};\n\nexport function DropdownItem<Option>({\n components,\n getOptionLabel,\n formatOptionLabel,\n isHighlighted,\n option,\n onSelect,\n setHighlightedIndex,\n index,\n}: DropdownItemProps<Option>): ReactElement {\n const onClick = useCallback(() => {\n onSelect(getOptionLabel(option), option);\n }, [onSelect, option, getOptionLabel]);\n\n const onMouseEnter = useCallback(() => {\n setHighlightedIndex(index);\n }, [setHighlightedIndex, index]);\n\n const {\n MenuItem,\n } = components;\n\n return (\n <MenuItem\n $isHighlighted={isHighlighted}\n onMouseEnter={onMouseEnter}\n onClick={onClick}\n >\n {formatOptionLabel(option)}\n </MenuItem>\n );\n}\n"],"mappings":"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","names":["import_react","styled","import_styled_components","styled","import_styled_components","styled","import_styled_components","styled","import_react","components","MenuItem","import_jsx_runtime","components","useOnClickOutside","Menu","import_jsx_runtime","components","Wrapper","Input"]}
{
"name": "@n3/react-autocomplete",
"version": "1.0.0",
"version": "2.0.0",
"description": "Autocomplete component for react applications",

@@ -29,3 +29,3 @@ "main": "./dist/index.js",

"clean": "rimraf dist",
"start": "start-storybook",
"start": "storybook dev -p 6006",
"build": "tsup src/index.ts --sourcemap --format esm,cjs --dts --legacy-output",

@@ -38,35 +38,33 @@ "test:ts": "tsc -p ./tsconfig.validate.json --noEmit",

"peerDependencies": {
"react": "^17.0.0 || ^18.0.0"
"react": "^17.0.0 || ^18.0.0",
"styled-components": "^5.0.0 || ^6.0.0"
},
"devDependencies": {
"@babel/types": "^7.21.2",
"@babel/types": "^7.22.5",
"@mdx-js/react": "^2.3.0",
"@n3/eslint-config": "^0.13.3",
"@storybook/addon-controls": "^6.5.16",
"@storybook/addon-docs": "^6.5.16",
"@storybook/addons": "^6.5.16",
"@storybook/builder-vite": "^0.4.2",
"@storybook/channel-postmessage": "^6.5.16",
"@storybook/channel-websocket": "^6.5.16",
"@storybook/client-api": "^6.5.16",
"@storybook/mdx2-csf": "^0.0.4",
"@storybook/node-logger": "^6.5.16",
"@storybook/preset-create-react-app": "^4.1.2",
"@storybook/preview-web": "^6.5.16",
"@storybook/react": "^6.5.16",
"@types/react": "^18.0.28",
"@storybook/addon-essentials": "^7.0.26",
"@storybook/addon-interactions": "^7.0.26",
"@storybook/addon-links": "^7.0.26",
"@storybook/blocks": "^7.0.26",
"@storybook/builder-vite": "^7.0.26",
"@storybook/react": "^7.0.26",
"@storybook/react-vite": "^7.0.26",
"@storybook/testing-library": "^0.2.0",
"@types/react": "^18.2.14",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0",
"@vitejs/plugin-react-swc": "^3.2.0",
"eslint": "^8.35.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"eslint": "^8.44.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.6.12",
"react": "^18.2.0",

@@ -76,11 +74,12 @@ "react-dom": "^18.2.0",

"react-refresh": "^0.14.0",
"rimraf": "^4.1.2",
"tsup": "^6.6.3",
"typescript": "^4.9.5",
"vite": "^4.1.4"
"rimraf": "^5.0.1",
"storybook": "^7.0.26",
"styled-components": "^6.0.3",
"tsup": "^7.1.0",
"typescript": "^5.1.6",
"vite": "^4.4.3"
},
"dependencies": {
"styled-components": "^5.3.6",
"use-onclickoutside": "^0.4.1"
}
}

@@ -5,5 +5,5 @@ # @n3/react-autocomplete

```sh
yarn add @n3/react-autocomplete styled-components
```
yarn add @n3/react-autocomplete
```

@@ -15,3 +15,3 @@ ## API

```javascript
import Autocomplete from '@n3/react-autocomplete';
import { Autocomplete } from '@n3/react-autocomplete';

@@ -18,0 +18,0 @@ <Autocomplete