@scbt-ecom/ui 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +3 -0
- package/.github/workflows/publish.yml +61 -0
- package/.github/workflows/setup-node/action.yml +22 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +1 -0
- package/.prettierrc +20 -0
- package/.releaserc +18 -0
- package/.storybook/main.ts +44 -0
- package/.storybook/preview.tsx +37 -0
- package/chromatic.config.json +5 -0
- package/eslint.config.mjs +193 -0
- package/index.html +13 -0
- package/lib/client.ts +12 -0
- package/lib/configs/index.ts +2 -0
- package/lib/configs/tailwindConfigBase.ts +110 -0
- package/lib/configs/tailwindPresets/extendsPreset.ts +43 -0
- package/lib/configs/tailwindPresets/index.ts +2 -0
- package/lib/configs/tailwindPresets/resetPreset.ts +71 -0
- package/lib/hybrid.ts +25 -0
- package/lib/shared/constants/api.ts +2 -0
- package/lib/shared/constants/designSystem/colors.ts +121 -0
- package/lib/shared/constants/designSystem/index.ts +3 -0
- package/lib/shared/constants/designSystem/others.ts +30 -0
- package/lib/shared/constants/designSystem/typography.ts +88 -0
- package/lib/shared/constants/index.ts +2 -0
- package/lib/shared/hooks/index.ts +5 -0
- package/lib/shared/hooks/useBoolean.ts +12 -0
- package/lib/shared/hooks/useClickOutside.ts +22 -0
- package/lib/shared/hooks/useCombineRef.ts +23 -0
- package/lib/shared/hooks/useControlledForm.ts +16 -0
- package/lib/shared/hooks/useDebounce.ts +38 -0
- package/lib/shared/hooks/useMediaQuery.tsx +42 -0
- package/lib/shared/style.css +118 -0
- package/lib/shared/ui/Badge.tsx +20 -0
- package/lib/shared/ui/Breadcrumbs.tsx +57 -0
- package/lib/shared/ui/ButtonIcon.tsx +50 -0
- package/lib/shared/ui/CustomLink.tsx +76 -0
- package/lib/shared/ui/Document.tsx +51 -0
- package/lib/shared/ui/Heading.tsx +33 -0
- package/lib/shared/ui/Hint.tsx +72 -0
- package/lib/shared/ui/Loader.tsx +58 -0
- package/lib/shared/ui/PhoneView.tsx +23 -0
- package/lib/shared/ui/ProgressBar.tsx +43 -0
- package/lib/shared/ui/ResponsiveContainer.tsx +15 -0
- package/lib/shared/ui/Section.tsx +15 -0
- package/lib/shared/ui/Skeleton.tsx +9 -0
- package/lib/shared/ui/TabsSwitcher.tsx +87 -0
- package/lib/shared/ui/accordion/Accordion.tsx +36 -0
- package/lib/shared/ui/accordion/index.ts +1 -0
- package/lib/shared/ui/accordion/model/types.ts +20 -0
- package/lib/shared/ui/accordion/ui/AccordionHeader.tsx +35 -0
- package/lib/shared/ui/brandLogos.tsx +14 -0
- package/lib/shared/ui/button/Button.tsx +117 -0
- package/lib/shared/ui/button/index.ts +1 -0
- package/lib/shared/ui/button/model/helpers.ts +16 -0
- package/lib/shared/ui/formControlElements/CheckboxControl.tsx +92 -0
- package/lib/shared/ui/formControlElements/FormControl.tsx +5 -0
- package/lib/shared/ui/formControlElements/InputControlMask.tsx +90 -0
- package/lib/shared/ui/formControlElements/RadioControl.tsx +130 -0
- package/lib/shared/ui/formControlElements/SwitchControl.tsx +79 -0
- package/lib/shared/ui/formControlElements/TextareaControl.tsx +96 -0
- package/lib/shared/ui/formControlElements/calendarControl/CalendarControl.tsx +178 -0
- package/lib/shared/ui/formControlElements/calendarControl/hooks/index.ts +2 -0
- package/lib/shared/ui/formControlElements/calendarControl/hooks/useCalendar.tsx +86 -0
- package/lib/shared/ui/formControlElements/calendarControl/hooks/useCalendarDropdowns.ts +38 -0
- package/lib/shared/ui/formControlElements/calendarControl/index.ts +1 -0
- package/lib/shared/ui/formControlElements/calendarControl/model/helpers.ts +60 -0
- package/lib/shared/ui/formControlElements/calendarControl/model/types.ts +44 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/DaysOfMonth.tsx +53 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/DaysOfWeek.tsx +28 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/Dropdown.tsx +62 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/Header.tsx +51 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/Navigation.tsx +32 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/OptionsList.tsx +44 -0
- package/lib/shared/ui/formControlElements/calendarControl/ui/index.ts +4 -0
- package/lib/shared/ui/formControlElements/comboboxControl/ComboboxControl.tsx +134 -0
- package/lib/shared/ui/formControlElements/comboboxControl/index.ts +1 -0
- package/lib/shared/ui/formControlElements/comboboxControl/model/selectClassnames.ts +51 -0
- package/lib/shared/ui/formControlElements/comboboxControl/model/types.ts +42 -0
- package/lib/shared/ui/formControlElements/comboboxControl/ui/ComboboxOption.tsx +38 -0
- package/lib/shared/ui/formControlElements/comboboxControl/ui/DropdownIndicator.tsx +23 -0
- package/lib/shared/ui/formControlElements/comboboxControl/ui/MultiValueRemove.tsx +16 -0
- package/lib/shared/ui/formControlElements/comboboxControl/ui/index.ts +3 -0
- package/lib/shared/ui/formControlElements/dadata/DadataInputControl.tsx +137 -0
- package/lib/shared/ui/formControlElements/dadata/index.ts +1 -0
- package/lib/shared/ui/formControlElements/dadata/model/api.ts +25 -0
- package/lib/shared/ui/formControlElements/dadata/model/helpers.ts +76 -0
- package/lib/shared/ui/formControlElements/dadata/model/types.ts +52 -0
- package/lib/shared/ui/formControlElements/dadata/model/useDadata.ts +25 -0
- package/lib/shared/ui/formControlElements/editorControl/EditorControl.tsx +82 -0
- package/lib/shared/ui/formControlElements/editorControl/components/conrols.tsx +136 -0
- package/lib/shared/ui/formControlElements/editorControl/components/menu.tsx +107 -0
- package/lib/shared/ui/formControlElements/editorControl/index.ts +60 -0
- package/lib/shared/ui/formControlElements/editorControl/ui/RemoveBlockButton.tsx +23 -0
- package/lib/shared/ui/formControlElements/editorControl/ui/ResetBlockType.tsx +17 -0
- package/lib/shared/ui/formControlElements/index.ts +14 -0
- package/lib/shared/ui/formControlElements/inputControl/InputControl.tsx +87 -0
- package/lib/shared/ui/formControlElements/inputControl/index.ts +1 -0
- package/lib/shared/ui/formControlElements/inputControl/model/hooks.tsx +26 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/InputControlUploader.tsx +47 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/index.ts +1 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/model/helpers.ts +18 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/model/hooks/useUploader.tsx +66 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/model/index.ts +1 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/model/types.ts +22 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/ui/File.tsx +35 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/ui/Filename.tsx +40 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/ui/Files.tsx +30 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/ui/Input.tsx +48 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/ui/Uploader.tsx +58 -0
- package/lib/shared/ui/formControlElements/inputControlUploader/ui/index.ts +3 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/InputCurrencyControl.tsx +88 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/index.ts +1 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/model/helpers.ts +46 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/model/useInputCurrency.tsx +33 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/ui/MenuTrigger.tsx +20 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/ui/OptionList.tsx +29 -0
- package/lib/shared/ui/formControlElements/inputCurrencyControl/ui/index.ts +2 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/InputSliderControl.tsx +144 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/index.ts +1 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/dates/getEndWordMonth.ts +14 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/dates/getYearEnding.ts +13 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/dates/index.ts +2 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/formatNumber.ts +6 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/getInputSliderSuffix.ts +20 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/getStepByVariant.ts +29 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/index.ts +4 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/types.ts +1 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/model/useSlider.ts +26 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/ui/SliderControl.tsx +47 -0
- package/lib/shared/ui/formControlElements/inputSliderControl/ui/index.ts +1 -0
- package/lib/shared/ui/formControlElements/model/classes-types.ts +22 -0
- package/lib/shared/ui/formControlElements/model/index.ts +2 -0
- package/lib/shared/ui/formControlElements/model/message-view-animation.ts +6 -0
- package/lib/shared/ui/formControlElements/model/props-types.ts +31 -0
- package/lib/shared/ui/formControlElements/ui/FieldAttachment.tsx +76 -0
- package/lib/shared/ui/formControlElements/ui/FieldContainer.tsx +37 -0
- package/lib/shared/ui/formControlElements/ui/FieldWrapper.tsx +33 -0
- package/lib/shared/ui/formControlElements/ui/Label.tsx +32 -0
- package/lib/shared/ui/formControlElements/ui/MessageView.tsx +41 -0
- package/lib/shared/ui/formControlElements/ui/index.ts +4 -0
- package/lib/shared/ui/icon/Icon.tsx +41 -0
- package/lib/shared/ui/icon/index.ts +2 -0
- package/lib/shared/ui/icon/sprite.gen.ts +177 -0
- package/lib/shared/ui/index.ts +68 -0
- package/lib/shared/ui/modal/Modal.tsx +68 -0
- package/lib/shared/ui/modal/index.ts +1 -0
- package/lib/shared/ui/modal/model/helpers.ts +13 -0
- package/lib/shared/ui/modal/ui/ModalHeader.tsx +33 -0
- package/lib/shared/ui/notification/Notification.tsx +31 -0
- package/lib/shared/ui/notification/index.ts +1 -0
- package/lib/shared/ui/notification/ui/CustomToast.tsx +42 -0
- package/lib/shared/ui/popover/Popover.tsx +74 -0
- package/lib/shared/ui/popover/index.ts +1 -0
- package/lib/shared/ui/providers/NotificationProvider.tsx +29 -0
- package/lib/shared/ui/providers/index.ts +1 -0
- package/lib/shared/ui/table/Table.tsx +144 -0
- package/lib/shared/ui/table/index.ts +1 -0
- package/lib/shared/ui/table/type.ts +30 -0
- package/lib/shared/utils/capitalize.ts +6 -0
- package/lib/shared/utils/cn.ts +6 -0
- package/lib/shared/utils/deepCompare.ts +1 -0
- package/lib/shared/utils/formatToDate.ts +5 -0
- package/lib/shared/utils/index.ts +5 -0
- package/lib/shared/utils/isClient.ts +1 -0
- package/lib/shared/validation/index.ts +3 -0
- package/lib/shared/validation/messages.ts +12 -0
- package/lib/shared/validation/regExp.ts +5 -0
- package/lib/shared/validation/zodValidation/calendar.ts +32 -0
- package/lib/shared/validation/zodValidation/dadataFio.ts +67 -0
- package/lib/shared/validation/zodValidation/index.ts +2 -0
- package/lib/vite-env.d.ts +2 -0
- package/lib/widgets/Advantages.tsx +45 -0
- package/lib/widgets/banner/Banner.tsx +74 -0
- package/lib/widgets/banner/index.ts +1 -0
- package/lib/widgets/banner/model/helpers.ts +159 -0
- package/lib/widgets/banner/money.png +0 -0
- package/lib/widgets/banner/saif.jpg +0 -0
- package/lib/widgets/banner/saifMob.jpg +0 -0
- package/lib/widgets/banner/seif.jpg +0 -0
- package/lib/widgets/banner/shield.jpg +0 -0
- package/lib/widgets/banner/shield.png +0 -0
- package/lib/widgets/banner/ui/BannerButtonsGroup.tsx +44 -0
- package/lib/widgets/banner/ui/banners/BannerImageFull.tsx +82 -0
- package/lib/widgets/banner/ui/banners/BannerWithSeparateImg.tsx +60 -0
- package/lib/widgets/banner/ui/banners/index.ts +1 -0
- package/lib/widgets/footer/Footer.tsx +95 -0
- package/lib/widgets/footer/index.ts +1 -0
- package/lib/widgets/footer/model/defaultValues.tsx +105 -0
- package/lib/widgets/footer/model/types.ts +19 -0
- package/lib/widgets/footer/ui/Copyright.tsx +15 -0
- package/lib/widgets/footer/ui/Ligal.tsx +50 -0
- package/lib/widgets/footer/ui/NavLinks.tsx +41 -0
- package/lib/widgets/footer/ui/PhonesBlock.tsx +34 -0
- package/lib/widgets/footer/ui/SocialLinks.tsx +30 -0
- package/lib/widgets/footer/ui/index.ts +5 -0
- package/lib/widgets/index.ts +5 -0
- package/lib/widgets/pageHeader/PageHeader.tsx +54 -0
- package/lib/widgets/pageHeader/index.ts +1 -0
- package/lib/widgets/stepper/Stepper.tsx +43 -0
- package/lib/widgets/stepper/index.ts +1 -0
- package/lib/widgets/stepper/ui/SingleStep.tsx +42 -0
- package/package.json +1 -4
- package/postcss.config.mjs +8 -0
- package/public/sprites/arrows.svg +1 -0
- package/public/sprites/brandLogos.svg +1 -0
- package/public/sprites/files.svg +1 -0
- package/public/sprites/general.svg +1 -0
- package/public/sprites/info.svg +1 -0
- package/public/sprites/social.svg +1 -0
- package/src/App.tsx +9 -0
- package/src/app/providers/RootProvider.tsx +11 -0
- package/src/app/providers/index.ts +1 -0
- package/src/app/providers/model/types.ts +5 -0
- package/src/configs/setup.ts +9 -0
- package/src/configs/storybook.config.ts +23 -0
- package/src/main.tsx +10 -0
- package/src/stories/primitives/Accordion.stories.tsx +66 -0
- package/src/stories/primitives/Badge.stories.tsx +28 -0
- package/src/stories/primitives/Breadcrumbs.stories.tsx +29 -0
- package/src/stories/primitives/Button/Button.stories.tsx +149 -0
- package/src/stories/primitives/Button/Button.test.tsx +150 -0
- package/src/stories/primitives/ButtonIcon.stories.tsx +75 -0
- package/src/stories/primitives/CustomLink.stories.tsx +64 -0
- package/src/stories/primitives/Document.stories.tsx +36 -0
- package/src/stories/primitives/Heading.stories.tsx +29 -0
- package/src/stories/primitives/Hint.stories.tsx +82 -0
- package/src/stories/primitives/Icon.stories.tsx +36 -0
- package/src/stories/primitives/Loader.stories.tsx +39 -0
- package/src/stories/primitives/Modal.stories.tsx +106 -0
- package/src/stories/primitives/Notification.stories.tsx +102 -0
- package/src/stories/primitives/PhoneView.stories.tsx +22 -0
- package/src/stories/primitives/Popover.stories.tsx +41 -0
- package/src/stories/primitives/ProgressBar.stories.tsx +68 -0
- package/src/stories/primitives/Skeleton.stories.tsx +21 -0
- package/src/stories/primitives/Table.stories.tsx +44 -0
- package/src/stories/primitives/TabsSwitcher.stories.tsx +45 -0
- package/src/stories/primitives/formControl/CalendarControl.stories.tsx +45 -0
- package/src/stories/primitives/formControl/CheckboxControl.stories.tsx +64 -0
- package/src/stories/primitives/formControl/ComboboxControl.stories.tsx +67 -0
- package/src/stories/primitives/formControl/DadataInputControl.stories.tsx +79 -0
- package/src/stories/primitives/formControl/EditorControl.stories.tsx +31 -0
- package/src/stories/primitives/formControl/FormControlAllFields.stories.tsx +25 -0
- package/src/stories/primitives/formControl/InputControl.stories.tsx +84 -0
- package/src/stories/primitives/formControl/InputControlPassword.stories.tsx +38 -0
- package/src/stories/primitives/formControl/InputControlUploader.stories.tsx +44 -0
- package/src/stories/primitives/formControl/InputCurrencyControl.stories.tsx +73 -0
- package/src/stories/primitives/formControl/InputSliderControl.stories.tsx +62 -0
- package/src/stories/primitives/formControl/RadioContol.stories.tsx +61 -0
- package/src/stories/primitives/formControl/SwitchControl.stories.tsx +51 -0
- package/src/stories/primitives/formControl/TextareaControl.stories.tsx +55 -0
- package/src/stories/primitives/formControl/inputControlMask.stories.tsx +67 -0
- package/src/stories/widgets/Advantages.stories.tsx +42 -0
- package/src/stories/widgets/Banner.stories.tsx +94 -0
- package/src/stories/widgets/Footer.stories.tsx +36 -0
- package/src/stories/widgets/PageHeader.stories.tsx +33 -0
- package/src/stories/widgets/Stepper.stories.tsx +24 -0
- package/src/storybookHelpers/actions.tsx +5 -0
- package/src/storybookHelpers/index.ts +2 -0
- package/src/storybookHelpers/reactHookForm/index.ts +3 -0
- package/src/storybookHelpers/reactHookForm/model/mockData.ts +19 -0
- package/src/storybookHelpers/reactHookForm/model/mocks.tsx +105 -0
- package/src/storybookHelpers/reactHookForm/model/renderFields.tsx +58 -0
- package/src/storybookHelpers/reactHookForm/model/types.ts +86 -0
- package/src/storybookHelpers/reactHookForm/ui/StorybookFieldsMapper.tsx +32 -0
- package/src/storybookHelpers/reactHookForm/ui/StorybookFormProvider.tsx +43 -0
- package/src/storybookHelpers/reactHookForm/ui/index.ts +2 -0
- package/src/storybookHelpers/table/utils/defaultValue.ts +51 -0
- package/static/arrows/arrowCircle.svg +18 -0
- package/static/arrows/arrowLink.svg +3 -0
- package/static/arrows/arrowRight.svg +3 -0
- package/static/brandLogos/logoBlack.svg +14 -0
- package/static/brandLogos/logoBusiness.svg +80 -0
- package/static/brandLogos/logoGray.svg +56 -0
- package/static/brandLogos/logoInsurance.svg +124 -0
- package/static/brandLogos/logoMain.svg +14 -0
- package/static/brandLogos/logoWhite.svg +56 -0
- package/static/files/border.svg +6 -0
- package/static/files/borderError.svg +6 -0
- package/static/files/documentFilled.svg +4 -0
- package/static/files/documentOutline.svg +4 -0
- package/static/files/upload.svg +3 -0
- package/static/general/calendar.svg +3 -0
- package/static/general/check.svg +6 -0
- package/static/general/close.svg +12 -0
- package/static/general/edit.svg +4 -0
- package/static/general/hiddenEye.svg +4 -0
- package/static/general/plus.svg +3 -0
- package/static/general/showEye.svg +4 -0
- package/static/info/warningCircle.svg +5 -0
- package/static/social/classmates.svg +3 -0
- package/static/social/telegram.svg +3 -0
- package/static/social/vk.svg +3 -0
- package/tailwind.config.ts +10 -0
- package/tsconfig.json +33 -0
- package/tsconfig.node.json +11 -0
- package/vite.config.ts +68 -0
- package/vitest.config.mjs +12 -0
- package/dist/scbt-ecom-ui-0.4.1.tgz +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { type Control, Controller, type FieldValues, type Path } from 'react-hook-form'
|
|
5
|
+
import Select, { type DropdownIndicatorProps, type MultiValueRemoveProps, type OptionProps } from 'react-select'
|
|
6
|
+
import { FieldContainer, MessageView } from '../ui'
|
|
7
|
+
import { Label } from '../ui/Label'
|
|
8
|
+
import { selectClassNames } from './model/selectClassnames'
|
|
9
|
+
import {
|
|
10
|
+
type TComboboxControlClasses,
|
|
11
|
+
type TComboboxOptionClasses,
|
|
12
|
+
type TDropdownIndicatorClasses,
|
|
13
|
+
type TMultiValueRemoveClasses
|
|
14
|
+
} from './model/types'
|
|
15
|
+
import { ComboboxOption, DropdownIndicator, MultiValueRemove } from './ui'
|
|
16
|
+
import { cn } from '$/shared/utils'
|
|
17
|
+
|
|
18
|
+
type TSelectVariant = 'primary' | 'secondary'
|
|
19
|
+
|
|
20
|
+
export interface SelectOption<ValueType> {
|
|
21
|
+
value: ValueType
|
|
22
|
+
label: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface IComboboxControlProps<T extends FieldValues, ValueType> {
|
|
26
|
+
name: Path<T>
|
|
27
|
+
control: Control<T>
|
|
28
|
+
options: SelectOption<ValueType>[]
|
|
29
|
+
label: string
|
|
30
|
+
size?: 'sm' | 'md' | 'lg' | 'full'
|
|
31
|
+
helperText?: string
|
|
32
|
+
marker?: boolean
|
|
33
|
+
variant?: TSelectVariant
|
|
34
|
+
isClearable?: boolean
|
|
35
|
+
defaultValue?: ValueType
|
|
36
|
+
noOptionsMessage?: string
|
|
37
|
+
disabled?: boolean
|
|
38
|
+
isMulti?: boolean
|
|
39
|
+
placeholder?: string
|
|
40
|
+
onClickIcon?: (...args: unknown[]) => unknown
|
|
41
|
+
onKeyDownIcon?: (event: React.KeyboardEvent) => unknown
|
|
42
|
+
isSearchable?: boolean
|
|
43
|
+
classes?: Partial<TComboboxControlClasses>
|
|
44
|
+
customChange?: (...args: unknown[]) => void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const ComboboxControl = <T extends FieldValues, ValueType>({
|
|
48
|
+
options,
|
|
49
|
+
control,
|
|
50
|
+
defaultValue,
|
|
51
|
+
variant = 'primary',
|
|
52
|
+
isClearable = false,
|
|
53
|
+
label,
|
|
54
|
+
disabled,
|
|
55
|
+
placeholder = 'Выберите несколько значений',
|
|
56
|
+
helperText,
|
|
57
|
+
noOptionsMessage = 'Нет результатов поиска',
|
|
58
|
+
size = 'full',
|
|
59
|
+
classes,
|
|
60
|
+
isMulti = false,
|
|
61
|
+
isSearchable,
|
|
62
|
+
customChange,
|
|
63
|
+
...props
|
|
64
|
+
}: IComboboxControlProps<T, ValueType>) => {
|
|
65
|
+
const selectId = React.useId()
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Controller
|
|
69
|
+
control={control}
|
|
70
|
+
name={props.name}
|
|
71
|
+
render={({ field: { onChange, ref, name, value }, fieldState: { error } }) => {
|
|
72
|
+
return (
|
|
73
|
+
<FieldContainer classes={classes} size={size}>
|
|
74
|
+
<div
|
|
75
|
+
className={cn(
|
|
76
|
+
'relative flex rounded-sm border border-solid border-transparent bg-color-blue-grey-100 transition-colors hover:bg-color-blue-grey-200 focus:outline-blue-grey-800 active:bg-color-blue-grey-100 group-focus-within:border-blue-grey-800',
|
|
77
|
+
{ '!border-negative': error },
|
|
78
|
+
{ '!bg-color-blue-grey-100': disabled }
|
|
79
|
+
)}
|
|
80
|
+
>
|
|
81
|
+
{!isMulti && <Label disabled={disabled} classes={classes} fieldId={selectId} label={label} value={value} />}
|
|
82
|
+
<Select
|
|
83
|
+
inputId={selectId}
|
|
84
|
+
placeholder={isMulti ? placeholder : ''}
|
|
85
|
+
classNamePrefix={variant}
|
|
86
|
+
instanceId={name}
|
|
87
|
+
hideSelectedOptions={false}
|
|
88
|
+
closeMenuOnSelect={!isMulti}
|
|
89
|
+
components={{
|
|
90
|
+
Option: (props: OptionProps) => (
|
|
91
|
+
<ComboboxOption {...props} classes={classes as Partial<TComboboxOptionClasses>} />
|
|
92
|
+
),
|
|
93
|
+
MultiValueRemove: (props: MultiValueRemoveProps) => (
|
|
94
|
+
<MultiValueRemove {...props} classes={classes as Partial<TMultiValueRemoveClasses>} />
|
|
95
|
+
),
|
|
96
|
+
DropdownIndicator: (props: DropdownIndicatorProps) => (
|
|
97
|
+
<DropdownIndicator {...props} classes={classes as Partial<TDropdownIndicatorClasses>} />
|
|
98
|
+
)
|
|
99
|
+
}}
|
|
100
|
+
classNames={selectClassNames(isMulti, disabled, classes)}
|
|
101
|
+
isSearchable={isSearchable}
|
|
102
|
+
ref={ref}
|
|
103
|
+
isDisabled={disabled}
|
|
104
|
+
isMulti={isMulti}
|
|
105
|
+
defaultValue={defaultValue}
|
|
106
|
+
isClearable={isClearable}
|
|
107
|
+
noOptionsMessage={() => noOptionsMessage}
|
|
108
|
+
options={options}
|
|
109
|
+
value={options.find((option) => (option as SelectOption<ValueType>).value === value)}
|
|
110
|
+
onChange={(option) => {
|
|
111
|
+
if (customChange) {
|
|
112
|
+
customChange(option)
|
|
113
|
+
}
|
|
114
|
+
if (isMulti) {
|
|
115
|
+
onChange((option as SelectOption<ValueType>[])?.map((c) => c.value))
|
|
116
|
+
} else {
|
|
117
|
+
onChange((option as SelectOption<ValueType>)?.value)
|
|
118
|
+
}
|
|
119
|
+
}}
|
|
120
|
+
{...props}
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
<MessageView
|
|
124
|
+
className={cn(classes?.message)}
|
|
125
|
+
intent={error?.message ? 'error' : 'simple'}
|
|
126
|
+
text={error?.message || helperText}
|
|
127
|
+
disabled={disabled}
|
|
128
|
+
/>
|
|
129
|
+
</FieldContainer>
|
|
130
|
+
)
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ComboboxControl, type IComboboxControlProps } from './ComboboxControl'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type MenuProps, type OptionProps } from 'react-select'
|
|
2
|
+
import { type TComboboxControlClassesCommon } from './types'
|
|
3
|
+
import { cn } from '$/shared/utils'
|
|
4
|
+
|
|
5
|
+
export const selectClassNames = (isMulti: boolean, disabled?: boolean, classes?: Partial<TComboboxControlClassesCommon>) => ({
|
|
6
|
+
dropdownIndicator: () => cn('absolute top-1/2 right-4 !p-0 -translate-y-1/2', classes?.dropdownIndicator),
|
|
7
|
+
indicatorsContainer: () => cn('', classes?.indicatorsContainer),
|
|
8
|
+
input: () =>
|
|
9
|
+
cn(
|
|
10
|
+
'desk-body-regular-l !p-0 !m-0 z-10 rounded-md bg-color-transparent text-color-dark outline-none transition-all',
|
|
11
|
+
classes?.inputCombobox
|
|
12
|
+
),
|
|
13
|
+
valueContainer: () => cn('desk-body-regular-l mr-7 gap-2 !p-0', classes?.valueContainer),
|
|
14
|
+
control: () =>
|
|
15
|
+
cn(
|
|
16
|
+
'p-4 !min-h-[56px] !bg-color-transparent !border-transparent transition-colors !shadow-[0px_0px_0px_0px_rgba(0,0,0,0)]',
|
|
17
|
+
{
|
|
18
|
+
'p-0 pt-5 pl-4': !isMulti
|
|
19
|
+
},
|
|
20
|
+
classes?.controlCombobox
|
|
21
|
+
),
|
|
22
|
+
container: () => cn('w-full !static', classes?.containerCombobox),
|
|
23
|
+
menuList: () => {
|
|
24
|
+
return cn('scrollHidden !customScrollbar-y !max-h-[246px] flex flex-col gap-[2px] overflow-x-hidden p-2', classes?.menuList)
|
|
25
|
+
},
|
|
26
|
+
menu: (state: MenuProps) => {
|
|
27
|
+
return cn(
|
|
28
|
+
'absolute !p-0 top-14 transition-all z-10 mt-2 flex w-full flex-col rounded-md border border-solid border-blue-grey-700 bg-color-white p-2 transition-all empty:invisible !shadow-[0px_0px_0px_0px_rgba(0,0,0,0)]',
|
|
29
|
+
{ 'scale-100 visible opacity-100': state.selectProps.menuIsOpen },
|
|
30
|
+
{ 'scale-95 invisible opacity-0': !state.selectProps.menuIsOpen },
|
|
31
|
+
classes?.menuCombobox
|
|
32
|
+
)
|
|
33
|
+
},
|
|
34
|
+
group: () => cn('bg-color-positive z-10', classes?.groupCombobox),
|
|
35
|
+
option: (state: OptionProps) =>
|
|
36
|
+
cn(
|
|
37
|
+
'flex !pl-10 cursor-pointer bg-color-initial text-color-initial items-center justify-between gap-2 active:!bg-color-blue-grey-200 rounded-sm px-3 py-3 hover:!bg-color-blue-grey-200 data-[disabled]:pointer-events-none data-[disabled]:!bg-color-blue-grey-100 data-[selected=true]:!bg-color-negative data-[disabled]:!text-color-disabled focus:!bg-color-blue-grey-200 active:!bg-color-blue-grey-200 hover:text-color-primary-hover',
|
|
38
|
+
{ '!pl-2': !isMulti },
|
|
39
|
+
{ '!bg-color-primary-tr-focus !text-color-primary-hover': state.isSelected },
|
|
40
|
+
{ '!bg-color-primary-tr-focus !text-color-primary-hover': state.isFocused },
|
|
41
|
+
classes?.optionCombobox
|
|
42
|
+
),
|
|
43
|
+
noOptionsMessage: () => cn('!desk-body-regular-m !text-color-tetriary', classes?.noOptionsMessage),
|
|
44
|
+
singleValue: () => cn('!m-0', classes?.singleValue),
|
|
45
|
+
multiValue: () => cn('!bg-color-blue-grey-300 truncate max-w-[300px] !rounded-sm px-[8px] !m-0 py-[5px]', classes?.multiValue),
|
|
46
|
+
multiValueLabel: () => cn('[&&]:desk-body-regular-l !p-0 pl-[6px] !text-color-secondary', classes?.multiValueLabel),
|
|
47
|
+
multiValueRemove: () => cn('hover:!bg-color-transparent', classes?.multiValueRemove),
|
|
48
|
+
placeholder: () =>
|
|
49
|
+
cn('!text-icon-blue-grey-600 !desk-body-regular-l', { '!text-color-disabled': disabled }, classes?.placeholderCombobox),
|
|
50
|
+
indicatorSeparator: () => cn('!hidden', classes?.indicatorSeparator)
|
|
51
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type TAdditionalInputPrimitiveClasses } from '../../model'
|
|
2
|
+
|
|
3
|
+
export type TComboboxControlClasses = Partial<TComboboxControlClassesCommon> &
|
|
4
|
+
Partial<TAdditionalInputPrimitiveClasses> &
|
|
5
|
+
Partial<TComboboxChildClasses> & {}
|
|
6
|
+
|
|
7
|
+
export type TComboboxControlClassesCommon = {
|
|
8
|
+
messageCombobox: string
|
|
9
|
+
selectWrapper: string
|
|
10
|
+
dropdownIndicator: string
|
|
11
|
+
indicatorsContainer: string
|
|
12
|
+
inputCombobox: string
|
|
13
|
+
valueContainer: string
|
|
14
|
+
controlCombobox: string
|
|
15
|
+
containerCombobox: string
|
|
16
|
+
menuList: string
|
|
17
|
+
menuCombobox: string
|
|
18
|
+
groupCombobox: string
|
|
19
|
+
menuPortal: string
|
|
20
|
+
optionCombobox: string
|
|
21
|
+
noOptionsMessage: string
|
|
22
|
+
singleValue: string
|
|
23
|
+
multiValue: string
|
|
24
|
+
multiValueLabel: string
|
|
25
|
+
multiValueRemove: string
|
|
26
|
+
placeholderCombobox: string
|
|
27
|
+
indicatorSeparator?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type TComboboxChildClasses = TMultiValueRemoveClasses | TComboboxOptionClasses | TDropdownIndicatorClasses
|
|
31
|
+
|
|
32
|
+
export type TMultiValueRemoveClasses = {
|
|
33
|
+
multiRemoveIcon: string
|
|
34
|
+
}
|
|
35
|
+
export type TComboboxOptionClasses = {
|
|
36
|
+
optionCustom: string
|
|
37
|
+
checkboxIsMulti: string
|
|
38
|
+
checkboxIsMultiIcon: string
|
|
39
|
+
}
|
|
40
|
+
export type TDropdownIndicatorClasses = {
|
|
41
|
+
indicatorIcon: string
|
|
42
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { components, type OptionProps } from 'react-select'
|
|
2
|
+
import { type TComboboxOptionClasses } from '../model/types'
|
|
3
|
+
import { Icon } from '$/shared/ui'
|
|
4
|
+
import { cn } from '$/shared/utils'
|
|
5
|
+
|
|
6
|
+
interface IComboboxOptionProps<Option> extends OptionProps<Option> {
|
|
7
|
+
classes?: Partial<TComboboxOptionClasses>
|
|
8
|
+
isSelected: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ComboboxOption = <Option,>({ isSelected, classes, ...props }: IComboboxOptionProps<Option>) => {
|
|
12
|
+
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
13
|
+
if (props.innerProps.onClick) {
|
|
14
|
+
props.innerProps.onClick(event)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className={cn('relative flex cursor-pointer items-center', classes?.optionCustom)}>
|
|
20
|
+
{props.isMulti && (
|
|
21
|
+
<span
|
|
22
|
+
onClick={handleClick}
|
|
23
|
+
className={cn(
|
|
24
|
+
'absolute left-1 flex size-6 items-center justify-center rounded-sm border-2 border-blue-grey-700',
|
|
25
|
+
{ 'border-none bg-color-primary-default': isSelected },
|
|
26
|
+
classes?.checkboxIsMulti
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
<Icon
|
|
30
|
+
name='general/check'
|
|
31
|
+
className={cn('size-5 text-icon-white', { invisible: !isSelected }, classes?.checkboxIsMultiIcon)}
|
|
32
|
+
/>
|
|
33
|
+
</span>
|
|
34
|
+
)}
|
|
35
|
+
<components.Option isSelected={isSelected} {...props} />
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { components, type DropdownIndicatorProps } from 'react-select'
|
|
2
|
+
import { type TDropdownIndicatorClasses } from '../model/types'
|
|
3
|
+
import { Icon } from '$/shared/ui'
|
|
4
|
+
import { cn } from '$/shared/utils'
|
|
5
|
+
|
|
6
|
+
interface IDropdownIndicatorProps<Option> extends DropdownIndicatorProps<Option> {
|
|
7
|
+
classes?: Partial<TDropdownIndicatorClasses>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const DropdownIndicator = <Option,>({ classes, ...props }: IDropdownIndicatorProps<Option>) => {
|
|
11
|
+
return (
|
|
12
|
+
<components.DropdownIndicator {...props}>
|
|
13
|
+
<Icon
|
|
14
|
+
name='arrows/arrowRight'
|
|
15
|
+
className={cn(
|
|
16
|
+
'size-6 rotate-90 text-icon-blue-grey-600 transition-all',
|
|
17
|
+
{ '-rotate-90': props.selectProps.menuIsOpen },
|
|
18
|
+
classes?.indicatorIcon
|
|
19
|
+
)}
|
|
20
|
+
/>
|
|
21
|
+
</components.DropdownIndicator>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { components, type MultiValueRemoveProps } from 'react-select'
|
|
2
|
+
import { type TMultiValueRemoveClasses } from '../model/types'
|
|
3
|
+
import { Icon } from '$/shared/ui'
|
|
4
|
+
import { cn } from '$/shared/utils'
|
|
5
|
+
|
|
6
|
+
interface IMultiValueRemoveProps extends MultiValueRemoveProps {
|
|
7
|
+
classes?: Partial<TMultiValueRemoveClasses>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const MultiValueRemove = ({ classes, ...props }: IMultiValueRemoveProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<components.MultiValueRemove {...props}>
|
|
13
|
+
<Icon name='general/close' className={cn('size-4 text-icon-blue-grey-800', classes?.multiRemoveIcon)} />
|
|
14
|
+
</components.MultiValueRemove>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Controller, type FieldValues } from 'react-hook-form'
|
|
5
|
+
import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
|
|
6
|
+
import type { TAdditionalInputClassesWithAttachment, TControlledInputProps, TInputCommonProps } from '../model'
|
|
7
|
+
import { FieldAttachment, FieldContainer, FieldWrapper, MessageView } from '../ui'
|
|
8
|
+
import type { TDadataBaseUrl, TDadataType } from './model/types'
|
|
9
|
+
import { useDadata } from './model/useDadata'
|
|
10
|
+
import { cn } from '$/shared/utils'
|
|
11
|
+
|
|
12
|
+
type TDadataClasses = Partial<TAdditionalInputClassesWithAttachment> & {
|
|
13
|
+
options?: string
|
|
14
|
+
indentMargin?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface IDadataInputControlProps<T extends FieldValues> extends TControlledInputProps<T>, TInputCommonProps {
|
|
18
|
+
classes?: TDadataClasses
|
|
19
|
+
dadataType?: TDadataType
|
|
20
|
+
dadataBaseUrl?: TDadataBaseUrl
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const DadataInputControl = <T extends FieldValues>({
|
|
24
|
+
control,
|
|
25
|
+
helperText,
|
|
26
|
+
classes,
|
|
27
|
+
size = 'full',
|
|
28
|
+
label,
|
|
29
|
+
disabled,
|
|
30
|
+
dadataType = 'fio',
|
|
31
|
+
dadataBaseUrl = 'cache',
|
|
32
|
+
badge,
|
|
33
|
+
icon,
|
|
34
|
+
swapPosition,
|
|
35
|
+
onClickIcon,
|
|
36
|
+
onKeyDownIcon,
|
|
37
|
+
|
|
38
|
+
...props
|
|
39
|
+
}: IDadataInputControlProps<T>) => {
|
|
40
|
+
const { setQuery, suggestionsOptions } = useDadata(dadataType, dadataBaseUrl)
|
|
41
|
+
const inputId = React.useId()
|
|
42
|
+
// TODO: Пофиксить при нажатие на enter очищается инпут, если нет опшенов
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Controller
|
|
46
|
+
control={control}
|
|
47
|
+
name={props.name}
|
|
48
|
+
render={({ field: { onChange, ref, name, value }, fieldState: { error } }) => {
|
|
49
|
+
return (
|
|
50
|
+
<FieldContainer size={size} classes={classes}>
|
|
51
|
+
<Combobox value={value} onChange={onChange}>
|
|
52
|
+
<FieldWrapper
|
|
53
|
+
fieldId={inputId}
|
|
54
|
+
label={label}
|
|
55
|
+
classes={classes}
|
|
56
|
+
disabled={disabled}
|
|
57
|
+
value={value}
|
|
58
|
+
error={!!error?.message}
|
|
59
|
+
>
|
|
60
|
+
<>
|
|
61
|
+
<ComboboxInput
|
|
62
|
+
className={cn(
|
|
63
|
+
'desk-body-regular-l z-10 h-[56px] w-full rounded-md bg-color-transparent px-4 pt-5 text-color-dark outline-none transition-all',
|
|
64
|
+
classes?.input
|
|
65
|
+
)}
|
|
66
|
+
ref={ref}
|
|
67
|
+
name={name}
|
|
68
|
+
value={value} // TODO: capitalize
|
|
69
|
+
displayValue={(currentValue: string) => {
|
|
70
|
+
return currentValue
|
|
71
|
+
}}
|
|
72
|
+
onChange={(event) => {
|
|
73
|
+
onChange(event.target.value)
|
|
74
|
+
setQuery(event.target.value)
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
77
|
+
{/* //TODO: Пока проблемы с реализацией на других полях */}
|
|
78
|
+
{/* {suggestionsOptions && debounceQuery && (
|
|
79
|
+
<span className='absolute desk-body-regular-l text-color-blue-grey-600 left-[16px] top-[28px] capitalize group-focus-within:visible'>
|
|
80
|
+
{suggestionsOptions[0]?.value}
|
|
81
|
+
</span>
|
|
82
|
+
)} */}
|
|
83
|
+
<FieldAttachment
|
|
84
|
+
onClickIcon={onClickIcon}
|
|
85
|
+
onKeyDownIcon={onKeyDownIcon}
|
|
86
|
+
badge={badge}
|
|
87
|
+
icon={icon}
|
|
88
|
+
error={!!error?.message}
|
|
89
|
+
classes={classes}
|
|
90
|
+
swapPosition={swapPosition}
|
|
91
|
+
/>
|
|
92
|
+
</>
|
|
93
|
+
</FieldWrapper>
|
|
94
|
+
<MessageView
|
|
95
|
+
className={cn(classes?.message)}
|
|
96
|
+
intent={error?.message ? 'error' : 'simple'}
|
|
97
|
+
text={error?.message || helperText}
|
|
98
|
+
disabled={disabled}
|
|
99
|
+
/>
|
|
100
|
+
<ComboboxOptions
|
|
101
|
+
transition
|
|
102
|
+
className={cn(
|
|
103
|
+
'scrollHidden absolute top-14 z-10 mt-2 flex w-full flex-col rounded-md border border-solid border-blue-grey-700 bg-color-white p-2 transition-all empty:invisible data-[closed]:scale-95 data-[closed]:opacity-0'
|
|
104
|
+
)}
|
|
105
|
+
>
|
|
106
|
+
<div className='customScrollbar-y !max-h-[246px] overflow-x-hidden p-2'>
|
|
107
|
+
{suggestionsOptions && suggestionsOptions?.length > 0 ? (
|
|
108
|
+
<>
|
|
109
|
+
{suggestionsOptions?.map(({ value: suggestionValue, additionalText, isDisabled }) => (
|
|
110
|
+
<ComboboxOption
|
|
111
|
+
disabled={isDisabled}
|
|
112
|
+
key={suggestionValue}
|
|
113
|
+
value={suggestionValue ?? ''}
|
|
114
|
+
className='flex cursor-pointer items-center justify-between gap-2 rounded-sm px-3 py-3 hover:bg-color-blue-grey-200 data-[disabled]:pointer-events-none data-[disabled]:bg-color-blue-grey-100 data-[focus]:bg-color-blue-grey-200 data-[disabled]:text-color-disabled'
|
|
115
|
+
>
|
|
116
|
+
<div className='flex flex-col gap-1'>
|
|
117
|
+
<p className='desk-body-regular-l'>{suggestionValue}</p>
|
|
118
|
+
|
|
119
|
+
{additionalText && <span className='desk-body-regular-s text-color-tetriary'>{additionalText}</span>}
|
|
120
|
+
</div>
|
|
121
|
+
</ComboboxOption>
|
|
122
|
+
))}
|
|
123
|
+
</>
|
|
124
|
+
) : (
|
|
125
|
+
<ComboboxOption value='' className='desk-body-regular-m text-color-tetriary'>
|
|
126
|
+
Ничего не найдено
|
|
127
|
+
</ComboboxOption>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
</ComboboxOptions>
|
|
131
|
+
</Combobox>
|
|
132
|
+
</FieldContainer>
|
|
133
|
+
)
|
|
134
|
+
}}
|
|
135
|
+
/>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DadataInputControl, type IDadataInputControlProps } from './DadataInputControl'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getDadataBaseUrl, getDataByDadataType } from './helpers'
|
|
2
|
+
import type { TDadataBaseUrl, TDadataType } from './types'
|
|
3
|
+
|
|
4
|
+
export const fetchSuggestions = async (searchText: string, dadataType: TDadataType, dadataBaseUrl: TDadataBaseUrl) => {
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetch(`${getDadataBaseUrl(dadataBaseUrl)}/${dadataType}`, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
Accept: 'application/json'
|
|
11
|
+
},
|
|
12
|
+
body: JSON.stringify({ query: searchText })
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
if (!response.ok) throw new Error('error')
|
|
16
|
+
const data = await response.json()
|
|
17
|
+
|
|
18
|
+
const formattedData = getDataByDadataType(dadataType, data)
|
|
19
|
+
|
|
20
|
+
return formattedData
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(error)
|
|
23
|
+
return []
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IDadataAutoOption,
|
|
3
|
+
IDadataCacheOption,
|
|
4
|
+
IDadataCacheSuggestion,
|
|
5
|
+
IDadataConstantsAutoSuggestion,
|
|
6
|
+
IDadataConstantsCountrySuggestion,
|
|
7
|
+
IDadataCountryOption,
|
|
8
|
+
IDadataOrganizationOption,
|
|
9
|
+
TDadataBaseUrl,
|
|
10
|
+
TDadataReturn,
|
|
11
|
+
TDadataSuggestionType,
|
|
12
|
+
TDadataType
|
|
13
|
+
} from './types'
|
|
14
|
+
import { DADATA_BASE_CACHE_URL, DADATA_BASE_CONSTANTS_URL } from '$/shared/constants'
|
|
15
|
+
|
|
16
|
+
export const getDadataBaseUrl = (baseUrl: TDadataBaseUrl) => {
|
|
17
|
+
switch (baseUrl) {
|
|
18
|
+
case 'cache':
|
|
19
|
+
return DADATA_BASE_CACHE_URL
|
|
20
|
+
case 'constants':
|
|
21
|
+
return DADATA_BASE_CONSTANTS_URL
|
|
22
|
+
default:
|
|
23
|
+
return DADATA_BASE_CACHE_URL
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const getDataByDadataType = <T>(dadataType: TDadataType, data: TDadataReturn<T>) => {
|
|
28
|
+
switch (dadataType) {
|
|
29
|
+
case 'country':
|
|
30
|
+
return (data as IDadataConstantsCountrySuggestion).matches
|
|
31
|
+
case 'auto':
|
|
32
|
+
return (data as IDadataConstantsAutoSuggestion).matches
|
|
33
|
+
default:
|
|
34
|
+
return (data as IDadataCacheSuggestion<T>).suggestions
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const getOptionsByDadataType = <T>(dadataType: TDadataType, suggestions: TDadataSuggestionType<T>) => {
|
|
39
|
+
switch (dadataType) {
|
|
40
|
+
case 'country':
|
|
41
|
+
return (suggestions as IDadataCountryOption[])?.map((suggestion) => {
|
|
42
|
+
return {
|
|
43
|
+
value: suggestion?.country_name,
|
|
44
|
+
label: suggestion?.country_name
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
case 'auto':
|
|
49
|
+
return (suggestions as IDadataAutoOption[])?.map((suggestion) => {
|
|
50
|
+
return {
|
|
51
|
+
value: suggestion?.model_mark,
|
|
52
|
+
label: suggestion?.model_mark
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
case 'party':
|
|
57
|
+
return (suggestions as IDadataOrganizationOption[])?.map((suggestion) => {
|
|
58
|
+
return {
|
|
59
|
+
value: suggestion?.value,
|
|
60
|
+
label: suggestion?.value,
|
|
61
|
+
additionalText: `ИНН: ${suggestion?.data?.inn}`
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
case 'fio':
|
|
65
|
+
case 'address':
|
|
66
|
+
return (suggestions as IDadataCacheOption<T>[])?.map((suggestion) => {
|
|
67
|
+
return {
|
|
68
|
+
value: suggestion?.value,
|
|
69
|
+
label: suggestion?.value
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
default:
|
|
74
|
+
return []
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type TDadataType = 'address' | 'fio' | 'country' | 'auto' | 'party'
|
|
2
|
+
export type TDadataBaseUrl = 'cache' | 'constants'
|
|
3
|
+
|
|
4
|
+
export type TDadataOption = {
|
|
5
|
+
value: string
|
|
6
|
+
additionalText?: string
|
|
7
|
+
isDisabled?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// # constants suggestions COUNTRY
|
|
11
|
+
export interface IDadataCountryOption {
|
|
12
|
+
id: number
|
|
13
|
+
country_name: string
|
|
14
|
+
}
|
|
15
|
+
export interface IDadataConstantsCountrySuggestion {
|
|
16
|
+
matches: IDadataCountryOption[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// # constants suggestions AUTO
|
|
20
|
+
export interface IDadataAutoOption {
|
|
21
|
+
id: number
|
|
22
|
+
mark: string
|
|
23
|
+
model: string
|
|
24
|
+
model_mark: string
|
|
25
|
+
year_max: string
|
|
26
|
+
year_min: string
|
|
27
|
+
}
|
|
28
|
+
export interface IDadataConstantsAutoSuggestion {
|
|
29
|
+
matches: IDadataAutoOption[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// # Default dadata suggestions [FIO, ADDRESS]
|
|
33
|
+
export interface IDadataCacheOption<T> {
|
|
34
|
+
value: string
|
|
35
|
+
unrestricted_value: string
|
|
36
|
+
data: T
|
|
37
|
+
}
|
|
38
|
+
export interface IDadataCacheSuggestion<T> {
|
|
39
|
+
suggestions: IDadataCacheOption<T>[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// # dadata suggestions organization (party)
|
|
43
|
+
export interface IDadataOrganizationOption {
|
|
44
|
+
value: string
|
|
45
|
+
unrestricted_value: string
|
|
46
|
+
data: {
|
|
47
|
+
inn: 'string'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type TDadataReturn<T> = IDadataConstantsCountrySuggestion | IDadataCacheSuggestion<T> | IDadataConstantsAutoSuggestion
|
|
52
|
+
export type TDadataSuggestionType<T> = IDadataCountryOption[] | IDadataCacheOption<T>[] | IDadataAutoOption[]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { fetchSuggestions } from './api'
|
|
5
|
+
import { getOptionsByDadataType } from './helpers'
|
|
6
|
+
import type { TDadataBaseUrl, TDadataOption, TDadataType } from './types'
|
|
7
|
+
import { useDebounceValue } from '$/shared/hooks'
|
|
8
|
+
|
|
9
|
+
export const useDadata = (dadataType: TDadataType, dadataBaseUrl: TDadataBaseUrl) => {
|
|
10
|
+
const [query, setQuery] = React.useState('')
|
|
11
|
+
const [suggestionsOptions, setSuggestionsOptions] = React.useState<TDadataOption[] | null>(null)
|
|
12
|
+
const debounceQuery = useDebounceValue(query, 300)
|
|
13
|
+
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
if (debounceQuery) {
|
|
16
|
+
const handleSearch = async () => {
|
|
17
|
+
const suggestions = await fetchSuggestions(debounceQuery, dadataType, dadataBaseUrl)
|
|
18
|
+
setSuggestionsOptions(getOptionsByDadataType(dadataType, suggestions))
|
|
19
|
+
}
|
|
20
|
+
handleSearch()
|
|
21
|
+
}
|
|
22
|
+
}, [debounceQuery, dadataType, dadataBaseUrl])
|
|
23
|
+
|
|
24
|
+
return { setQuery, suggestionsOptions, debounceQuery }
|
|
25
|
+
}
|