@n3/react-autocomplete
Advanced tools
| 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 }; |
@@ -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"]} |
+4
-4
@@ -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"]} |
+27
-28
| { | ||
| "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" | ||
| } | ||
| } |
+3
-3
@@ -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 |
AI-detected possible typosquat
Supply chain riskAI has identified this package as a potential typosquat of a more popular package. This suggests that the package may be intentionally mimicking another package's name, description, or other metadata.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
63280
5.91%37
-2.63%8
14.29%0
-100%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed