@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,144 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Controller, type FieldValues } from 'react-hook-form'
|
|
5
|
+
import { NumericFormat } from 'react-number-format'
|
|
6
|
+
import type { TAdditionalInputClassesWithAttachment, TControlledInputProps } from '../model'
|
|
7
|
+
import { FieldAttachment, FieldContainer, FieldWrapper, MessageView } from '../ui'
|
|
8
|
+
import { formatNumber, getMinMaxTextSlider, getStepByVariant } from './model/helpers'
|
|
9
|
+
import { type TSliderVariants } from './model/types'
|
|
10
|
+
import { useSlider } from './model/useSlider'
|
|
11
|
+
import { SliderControl } from './ui/SliderControl'
|
|
12
|
+
import { cn } from '$/shared/utils'
|
|
13
|
+
|
|
14
|
+
export interface IInputSliderCommonProps {
|
|
15
|
+
min: number
|
|
16
|
+
max: number
|
|
17
|
+
variant: TSliderVariants
|
|
18
|
+
step?: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface InputSliderControlProps<T extends FieldValues> extends TControlledInputProps<T>, IInputSliderCommonProps {
|
|
22
|
+
classes?: Partial<TAdditionalInputClassesWithAttachment> & {
|
|
23
|
+
spanLeft?: string
|
|
24
|
+
spanRight?: string
|
|
25
|
+
}
|
|
26
|
+
disabled?: boolean
|
|
27
|
+
onInputChange?: (value?: number) => void
|
|
28
|
+
leftText?: string
|
|
29
|
+
rightText?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const InputSliderControl = <T extends FieldValues>({
|
|
33
|
+
label,
|
|
34
|
+
size = 'full',
|
|
35
|
+
helperText,
|
|
36
|
+
control,
|
|
37
|
+
classes,
|
|
38
|
+
badge,
|
|
39
|
+
icon,
|
|
40
|
+
disabled,
|
|
41
|
+
onInputChange,
|
|
42
|
+
min,
|
|
43
|
+
max,
|
|
44
|
+
variant,
|
|
45
|
+
...props
|
|
46
|
+
}: InputSliderControlProps<T>) => {
|
|
47
|
+
const inputId = React.useId()
|
|
48
|
+
const ref = React.useRef<HTMLInputElement>(null)
|
|
49
|
+
|
|
50
|
+
const handleIconClick = () => {
|
|
51
|
+
if (ref.current) {
|
|
52
|
+
ref?.current?.focus()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const { handleBlur, handleChange, getSuffixText } = useSlider()
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Controller
|
|
60
|
+
control={control}
|
|
61
|
+
name={props.name}
|
|
62
|
+
render={({ field: { onChange, value }, fieldState: { error } }) => {
|
|
63
|
+
const [start, end] = getMinMaxTextSlider(variant, min, max)
|
|
64
|
+
return (
|
|
65
|
+
<div className='flex flex-col gap-1'>
|
|
66
|
+
<FieldContainer size={size} classes={classes}>
|
|
67
|
+
<FieldWrapper
|
|
68
|
+
fieldId={inputId}
|
|
69
|
+
label={label}
|
|
70
|
+
classes={classes}
|
|
71
|
+
disabled={disabled}
|
|
72
|
+
value={value}
|
|
73
|
+
error={!!error?.message}
|
|
74
|
+
>
|
|
75
|
+
<>
|
|
76
|
+
<NumericFormat
|
|
77
|
+
aria-invalid={error?.message ? 'true' : 'false'}
|
|
78
|
+
className={cn(
|
|
79
|
+
'group/slider desk-title-bold-s h-[56px] w-full rounded-md bg-color-transparent px-4 pt-5 text-color-dark outline-none transition-all',
|
|
80
|
+
classes?.input
|
|
81
|
+
)}
|
|
82
|
+
id={inputId}
|
|
83
|
+
onBlur={() => {
|
|
84
|
+
handleBlur(value, min, max, onChange)
|
|
85
|
+
}}
|
|
86
|
+
value={value}
|
|
87
|
+
disabled={disabled}
|
|
88
|
+
suffix={` ${getSuffixText(value, variant)}`}
|
|
89
|
+
thousandsGroupStyle='thousand'
|
|
90
|
+
onValueChange={({ floatValue }) => {
|
|
91
|
+
handleChange(onChange, floatValue)
|
|
92
|
+
if (onInputChange) {
|
|
93
|
+
onInputChange(floatValue)
|
|
94
|
+
}
|
|
95
|
+
}}
|
|
96
|
+
thousandSeparator={' '}
|
|
97
|
+
allowNegative={false}
|
|
98
|
+
getInputRef={ref}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
<SliderControl
|
|
102
|
+
onValueChange={(inputValue) => onChange(inputValue[0])}
|
|
103
|
+
value={[value]}
|
|
104
|
+
min={min}
|
|
105
|
+
max={max}
|
|
106
|
+
step={getStepByVariant(value, variant)}
|
|
107
|
+
variant={variant}
|
|
108
|
+
/>
|
|
109
|
+
|
|
110
|
+
<div aria-label='edit' onKeyDown={handleIconClick} role='button' tabIndex={0} onClick={handleIconClick}>
|
|
111
|
+
<FieldAttachment
|
|
112
|
+
onClickIcon={handleIconClick}
|
|
113
|
+
onKeyDownIcon={handleIconClick}
|
|
114
|
+
isSlider
|
|
115
|
+
badge={badge}
|
|
116
|
+
icon={icon}
|
|
117
|
+
error={!!error?.message}
|
|
118
|
+
classes={classes}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
</>
|
|
122
|
+
</FieldWrapper>
|
|
123
|
+
|
|
124
|
+
<MessageView
|
|
125
|
+
className={cn(classes?.message)}
|
|
126
|
+
intent={error?.message ? 'error' : 'simple'}
|
|
127
|
+
text={error?.message || helperText}
|
|
128
|
+
disabled={disabled}
|
|
129
|
+
/>
|
|
130
|
+
</FieldContainer>
|
|
131
|
+
<div className='flex justify-between'>
|
|
132
|
+
<span
|
|
133
|
+
className={cn('desk-body-regular-m text-color-tetriary', classes?.spanLeft)}
|
|
134
|
+
>{`${formatNumber(min)} ${start}`}</span>
|
|
135
|
+
<span
|
|
136
|
+
className={cn('desk-body-regular-m text-color-tetriary', classes?.spanRight)}
|
|
137
|
+
>{`${formatNumber(max)} ${end}`}</span>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
)
|
|
141
|
+
}}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InputSliderControl, type InputSliderControlProps } from './InputSliderControl'
|
package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/dates/getEndWordMonth.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function getEndWordMonth(months: number) {
|
|
2
|
+
const remMonthsDivByTen = months % 10
|
|
3
|
+
|
|
4
|
+
switch (true) {
|
|
5
|
+
case months > 10 && months < 20:
|
|
6
|
+
return 'месяцев'
|
|
7
|
+
case remMonthsDivByTen > 1 && remMonthsDivByTen < 5:
|
|
8
|
+
return 'месяца'
|
|
9
|
+
case remMonthsDivByTen === 1:
|
|
10
|
+
return 'месяц'
|
|
11
|
+
default:
|
|
12
|
+
return 'месяцев'
|
|
13
|
+
}
|
|
14
|
+
}
|
package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/dates/getYearEnding.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function getYearEnding(years: number) {
|
|
2
|
+
const lastDigit = Math.floor(years) % 10
|
|
3
|
+
if (years >= 5 && years <= 20) {
|
|
4
|
+
return 'лет'
|
|
5
|
+
}
|
|
6
|
+
if (lastDigit === 1) {
|
|
7
|
+
return 'год'
|
|
8
|
+
}
|
|
9
|
+
if (lastDigit >= 2 && lastDigit <= 4) {
|
|
10
|
+
return 'года'
|
|
11
|
+
}
|
|
12
|
+
return 'лет'
|
|
13
|
+
}
|
package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/getInputSliderSuffix.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type TSliderVariants } from '../types'
|
|
2
|
+
import { getYearEnding } from './dates'
|
|
3
|
+
|
|
4
|
+
export const getInputSliderSuffix = (variant: TSliderVariants, value: number) => {
|
|
5
|
+
const variants = {
|
|
6
|
+
years: getYearEnding(value),
|
|
7
|
+
credit: '₽'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return variants[variant]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const getMinMaxTextSlider = (variant: TSliderVariants, min: number, max: number) => {
|
|
14
|
+
const variants = {
|
|
15
|
+
years: [min, max].map(getYearEnding),
|
|
16
|
+
credit: ['₽', '₽']
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return variants[variant]
|
|
20
|
+
}
|
package/lib/shared/ui/formControlElements/inputSliderControl/model/helpers/getStepByVariant.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type TSliderVariants } from '../types'
|
|
2
|
+
|
|
3
|
+
const getStepCredit = (value: number) => {
|
|
4
|
+
const step = 1000
|
|
5
|
+
|
|
6
|
+
const firstStep = value < 100_000
|
|
7
|
+
const secondStep = value >= 100_000 && value < 500_000
|
|
8
|
+
const max = value >= 1_000_000
|
|
9
|
+
|
|
10
|
+
switch (true) {
|
|
11
|
+
case firstStep:
|
|
12
|
+
return 1000
|
|
13
|
+
case secondStep:
|
|
14
|
+
return 10_000
|
|
15
|
+
case max:
|
|
16
|
+
return 100_000
|
|
17
|
+
default:
|
|
18
|
+
return step
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getStepByVariant = (value: number, variant: TSliderVariants) => {
|
|
23
|
+
const variants = {
|
|
24
|
+
years: 1,
|
|
25
|
+
credit: getStepCredit(value)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return variants[variant]
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type TSliderVariants = 'years' | 'credit'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getInputSliderSuffix } from './helpers'
|
|
2
|
+
import { type TSliderVariants } from './types'
|
|
3
|
+
|
|
4
|
+
export const useSlider = () => {
|
|
5
|
+
const getSuffixText = (value: number, variant: TSliderVariants) => {
|
|
6
|
+
return getInputSliderSuffix(variant, value)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const handleBlur = (value: number, min: number, max: number, onChange: (...event: unknown[]) => void) => {
|
|
10
|
+
if (value > max) {
|
|
11
|
+
onChange(max)
|
|
12
|
+
}
|
|
13
|
+
if (value < min) {
|
|
14
|
+
onChange(min)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const handleChange = (onChange: (...event: unknown[]) => void, val?: number) => {
|
|
19
|
+
if (val === undefined) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
onChange(val)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { getSuffixText, handleBlur, handleChange }
|
|
26
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import * as SliderPrimitive from '@radix-ui/react-slider'
|
|
3
|
+
import { type IInputSliderCommonProps } from '../InputSliderControl'
|
|
4
|
+
import { cn } from '$/shared/utils'
|
|
5
|
+
|
|
6
|
+
export interface ISliderControllProps extends IInputSliderCommonProps {
|
|
7
|
+
classes?: TSliderControlClasses
|
|
8
|
+
onValueChange?: (value: number[]) => void
|
|
9
|
+
value: number[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TSliderControlClasses = {
|
|
13
|
+
sliderWrapper?: string
|
|
14
|
+
sliderRoot?: string
|
|
15
|
+
spanLeft?: string
|
|
16
|
+
spanRight?: string
|
|
17
|
+
sliderTrack?: string
|
|
18
|
+
sliderThumb?: string
|
|
19
|
+
sliderRange?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const SliderControl = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, ISliderControllProps>(
|
|
23
|
+
({ min, max, classes, ...props }, ref) => {
|
|
24
|
+
return (
|
|
25
|
+
<div className={cn('absolute bottom-[-7px] w-full px-4', classes?.sliderWrapper)}>
|
|
26
|
+
<SliderPrimitive.Root
|
|
27
|
+
ref={ref}
|
|
28
|
+
className={cn('relative flex h-4 w-full touch-none select-none items-center', classes?.sliderRoot)}
|
|
29
|
+
min={min}
|
|
30
|
+
max={max}
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
<SliderPrimitive.Track
|
|
34
|
+
className={cn(
|
|
35
|
+
'relative h-[2px] w-full grow overflow-hidden rounded-full bg-color-blue-grey-500',
|
|
36
|
+
classes?.sliderTrack
|
|
37
|
+
)}
|
|
38
|
+
>
|
|
39
|
+
<SliderPrimitive.Range className={cn('absolute h-full bg-color-primary-default', classes?.sliderRange)} />
|
|
40
|
+
</SliderPrimitive.Track>
|
|
41
|
+
<SliderPrimitive.Thumb className='ring-offset-background block h-4 w-4 cursor-pointer rounded-full bg-color-primary-default transition-colors hover:before:absolute hover:before:left-1/2 hover:before:top-1/2 hover:before:h-8 hover:before:w-8 hover:before:-translate-x-1/2 hover:before:-translate-y-1/2 hover:before:rounded-full hover:before:bg-color-primary-tr-hover hover:before:content-[""] focus:outline-none focus:before:bg-color-primary-tr-pressed disabled:pointer-events-none disabled:opacity-50' />
|
|
42
|
+
</SliderPrimitive.Root>
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
SliderPrimitive.Slider.displayName = SliderPrimitive.Root.displayName
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SliderControl } from './SliderControl'
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type TFieldWrapperClasses = {
|
|
2
|
+
field: string
|
|
3
|
+
label: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type TFieldAttachmentClasses = {
|
|
7
|
+
badge: string
|
|
8
|
+
icon: string
|
|
9
|
+
attachmentWrapper: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TFieldContainerClasses = {
|
|
13
|
+
container: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type TInputCommonClasses = {
|
|
17
|
+
input: string
|
|
18
|
+
message: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type TAdditionalInputPrimitiveClasses = TFieldWrapperClasses & TFieldContainerClasses & TInputCommonClasses
|
|
22
|
+
export type TAdditionalInputClassesWithAttachment = TAdditionalInputPrimitiveClasses & TFieldAttachmentClasses
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const animation = {
|
|
2
|
+
initial: { height: 0, opacity: 0, transformOrigin: 'center bottom' },
|
|
3
|
+
animate: { height: 'auto', opacity: 1, transformOrigin: 'center bottom' },
|
|
4
|
+
exit: { height: 0, opacity: 0, transformOrigin: 'center bottom' },
|
|
5
|
+
transition: { duration: 0.2, delay: 0.2, ease: 'easeInOut' }
|
|
6
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type * as React from 'react'
|
|
2
|
+
import type { Control, FieldValues, Path } from 'react-hook-form'
|
|
3
|
+
import type { TFieldContainerConfig } from '../ui/FieldContainer'
|
|
4
|
+
|
|
5
|
+
export type TInputCommonProps = Omit<
|
|
6
|
+
React.ComponentProps<'input'>,
|
|
7
|
+
'name' | 'placeholder' | 'size' | 'type' | 'defaultValue' | 'className'
|
|
8
|
+
>
|
|
9
|
+
export type TTextareaCommonProps = Omit<React.ComponentProps<'textarea'>, 'name' | 'size' | 'type' | 'defaultValue' | 'className'>
|
|
10
|
+
|
|
11
|
+
type TFieldControlledProps<T extends FieldValues> = {
|
|
12
|
+
name: Path<T>
|
|
13
|
+
control: Control<T>
|
|
14
|
+
label: string
|
|
15
|
+
helperText?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type TFieldContainerSize = 'sm' | 'md' | 'lg' | 'full'
|
|
19
|
+
export type TFieldAttachment = {
|
|
20
|
+
badge?: string
|
|
21
|
+
icon?: React.ReactElement
|
|
22
|
+
swapPosition?: boolean
|
|
23
|
+
onClickIcon?: (...args: unknown[]) => unknown
|
|
24
|
+
onKeyDownIcon?: (event: React.KeyboardEvent) => unknown
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// # Required props on controlled INPUTS - [maskInput, baseInput, dadata]
|
|
28
|
+
export type TControlledInputProps<T extends FieldValues> = TFieldContainerConfig & TFieldAttachment & TFieldControlledProps<T>
|
|
29
|
+
|
|
30
|
+
// # Required props on controlled INPUTS - [checkbox, radio]
|
|
31
|
+
export type TControlledInputPrimitiveProps<T extends FieldValues> = TInputCommonProps & TFieldControlledProps<T>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Badge } from '../../Badge'
|
|
5
|
+
import { Icon } from '../../icon/Icon'
|
|
6
|
+
import type { TFieldAttachmentClasses } from '../model/classes-types'
|
|
7
|
+
import type { TFieldAttachment } from '../model/props-types'
|
|
8
|
+
import { cn } from '$/shared/utils'
|
|
9
|
+
|
|
10
|
+
interface IFieldAttachmentProps extends TFieldAttachment {
|
|
11
|
+
classes?: Partial<TFieldAttachmentClasses>
|
|
12
|
+
error?: boolean
|
|
13
|
+
isTextarea?: boolean
|
|
14
|
+
swapPosition?: boolean
|
|
15
|
+
onClickIcon?: (...args: unknown[]) => unknown
|
|
16
|
+
onKeyDownIcon?: (event: React.KeyboardEvent) => unknown
|
|
17
|
+
isSlider?: boolean
|
|
18
|
+
absolute?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const FieldAttachment = ({
|
|
22
|
+
badge,
|
|
23
|
+
isSlider,
|
|
24
|
+
icon,
|
|
25
|
+
error,
|
|
26
|
+
isTextarea = false,
|
|
27
|
+
classes,
|
|
28
|
+
swapPosition,
|
|
29
|
+
onClickIcon,
|
|
30
|
+
onKeyDownIcon,
|
|
31
|
+
absolute = false
|
|
32
|
+
}: IFieldAttachmentProps) => {
|
|
33
|
+
const interactiveIconAttr = (onClickIcon || onKeyDownIcon) && {
|
|
34
|
+
role: 'button',
|
|
35
|
+
tabIndex: 0,
|
|
36
|
+
onClick: onClickIcon,
|
|
37
|
+
onKeyDown: onKeyDownIcon
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
{error ? (
|
|
43
|
+
<Icon name='info/warningCircle' className={cn('mr-4 size-6 text-icon-secondary-default', { 'm-0 size-5': isTextarea })} />
|
|
44
|
+
) : (
|
|
45
|
+
<>
|
|
46
|
+
{(badge || icon) && (
|
|
47
|
+
<div
|
|
48
|
+
className={cn(
|
|
49
|
+
'mr-4 flex items-center gap-4',
|
|
50
|
+
{ 'm-0': isTextarea },
|
|
51
|
+
{ 'flex-row-reverse': swapPosition },
|
|
52
|
+
{ 'absolute right-0 top-1/2 ml-1 -translate-y-1/2': absolute },
|
|
53
|
+
classes?.attachmentWrapper
|
|
54
|
+
)}
|
|
55
|
+
>
|
|
56
|
+
{icon && (
|
|
57
|
+
<span
|
|
58
|
+
{...interactiveIconAttr}
|
|
59
|
+
className={cn(
|
|
60
|
+
'flex size-6 items-center justify-center',
|
|
61
|
+
{ 'size-5': isTextarea },
|
|
62
|
+
{ 'group-focus-within:[&_svg]:text-icon-blue-grey-800': isSlider },
|
|
63
|
+
classes?.icon
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
{icon}
|
|
67
|
+
</span>
|
|
68
|
+
)}
|
|
69
|
+
{badge && <Badge className={cn('bg-color-positive', classes?.badge)}>{badge}</Badge>}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
</>
|
|
73
|
+
)}
|
|
74
|
+
</>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
+
import type { TFieldContainerClasses } from '../model/classes-types'
|
|
6
|
+
import { cn } from '$/shared/utils'
|
|
7
|
+
|
|
8
|
+
const fieldContainerConfig = cva('relative min-w-[360px] flex flex-col group', {
|
|
9
|
+
variants: {
|
|
10
|
+
intent: {
|
|
11
|
+
clear: '!w-full min-w-[140px]',
|
|
12
|
+
filled: ''
|
|
13
|
+
},
|
|
14
|
+
size: {
|
|
15
|
+
sm: 'w-[360px]',
|
|
16
|
+
md: 'w-[520px]',
|
|
17
|
+
lg: 'w-[720px]',
|
|
18
|
+
full: 'w-full'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
size: 'full',
|
|
23
|
+
intent: 'filled'
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export type TFieldContainerConfig = VariantProps<typeof fieldContainerConfig>
|
|
28
|
+
|
|
29
|
+
interface IFieldContainerProps extends TFieldContainerConfig {
|
|
30
|
+
classes?: Partial<TFieldContainerClasses>
|
|
31
|
+
children: React.ReactNode
|
|
32
|
+
intent?: 'clear' | 'filled' | null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const FieldContainer = ({ size, intent = 'filled', classes, children }: IFieldContainerProps) => {
|
|
36
|
+
return <div className={cn(fieldContainerConfig({ size, intent }), classes?.container)}>{children}</div>
|
|
37
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import type { TFieldWrapperClasses } from '../model'
|
|
5
|
+
import { Label } from './Label'
|
|
6
|
+
import { cn } from '$/shared/utils'
|
|
7
|
+
|
|
8
|
+
interface IFieldWrapperProps<V> {
|
|
9
|
+
children: React.ReactElement
|
|
10
|
+
label: string
|
|
11
|
+
fieldId: string
|
|
12
|
+
value: V
|
|
13
|
+
error?: boolean
|
|
14
|
+
classes?: Partial<TFieldWrapperClasses>
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
isTextarea?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const FieldWrapper = <V,>({ children, error, disabled, classes, ...props }: IFieldWrapperProps<V>) => {
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
className={cn(
|
|
23
|
+
'relative flex items-center justify-between 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',
|
|
24
|
+
{ '!border-negative': error },
|
|
25
|
+
{ '!bg-color-blue-grey-100': disabled },
|
|
26
|
+
classes?.field
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
<Label {...props} />
|
|
30
|
+
{children}
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type TFieldWrapperClasses } from '../model'
|
|
2
|
+
import { cn } from '$/shared/utils'
|
|
3
|
+
|
|
4
|
+
interface ILabelProps<V> {
|
|
5
|
+
label: string
|
|
6
|
+
fieldId: string
|
|
7
|
+
value: V
|
|
8
|
+
classes?: Partial<TFieldWrapperClasses>
|
|
9
|
+
isTextarea?: boolean
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const Label = <V,>({ disabled, fieldId, label, value, classes, isTextarea = false }: ILabelProps<V>) => {
|
|
14
|
+
return (
|
|
15
|
+
<label
|
|
16
|
+
htmlFor={fieldId}
|
|
17
|
+
className={cn(
|
|
18
|
+
'desk-body-regular-l pointer-events-none absolute left-4 top-2/4 -translate-y-1/2 text-color-tetriary transition-all duration-15',
|
|
19
|
+
{ '!top-2 !translate-y-0 !bg-color-transparent [&&]:desk-body-regular-s': value && !isTextarea },
|
|
20
|
+
{
|
|
21
|
+
'group-focus-within:desk-body-regular-s group-focus-within:top-2 group-focus-within:translate-y-0 group-focus-within:bg-color-transparent':
|
|
22
|
+
!isTextarea
|
|
23
|
+
},
|
|
24
|
+
{ 'desk-body-regular-s top-2 translate-y-0': isTextarea },
|
|
25
|
+
{ 'text-color-disabled': disabled },
|
|
26
|
+
classes?.label
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
{label}
|
|
30
|
+
</label>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type { FieldError } from 'react-hook-form'
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
+
import { motion } from 'framer-motion'
|
|
6
|
+
import { animation } from '../model/message-view-animation'
|
|
7
|
+
import { cn } from '$/shared/utils'
|
|
8
|
+
|
|
9
|
+
const messageViewConfig = cva('desk-body-regular-m mt-2', {
|
|
10
|
+
variants: {
|
|
11
|
+
intent: {
|
|
12
|
+
simple: 'text-color-tetriary',
|
|
13
|
+
error: 'text-color-negative'
|
|
14
|
+
},
|
|
15
|
+
disabled: {
|
|
16
|
+
true: 'text-color-disabled',
|
|
17
|
+
false: ''
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
intent: 'simple'
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export interface IMessageViewProps extends VariantProps<typeof messageViewConfig> {
|
|
26
|
+
as?: 'div' | 'span' | 'p'
|
|
27
|
+
text?: string | FieldError['message']
|
|
28
|
+
className?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const MessageView = ({ intent, as: Element = 'p', disabled, text, className, ...props }: IMessageViewProps) => {
|
|
32
|
+
if (!text) return null
|
|
33
|
+
|
|
34
|
+
const MotionElement = motion(Element)
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<MotionElement className={cn(messageViewConfig({ intent, disabled }), className)} {...animation} {...props}>
|
|
38
|
+
{text}
|
|
39
|
+
</MotionElement>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { SPRITES_META, type SpritesMap } from './sprite.gen'
|
|
3
|
+
import { cn } from '$/shared/utils'
|
|
4
|
+
|
|
5
|
+
export type IconName<Key extends keyof SpritesMap> = `${Key}/${SpritesMap[Key]}`
|
|
6
|
+
export type TAllowedIcons = { [Key in keyof SpritesMap]: IconName<Key> }[keyof SpritesMap]
|
|
7
|
+
|
|
8
|
+
export interface IconProps extends React.SVGProps<SVGSVGElement> {
|
|
9
|
+
name: TAllowedIcons
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const getIconMeta = <Key extends keyof SpritesMap>(name: IconName<Key>) => {
|
|
13
|
+
const [spriteName, iconName] = name.split('/') as [Key, SpritesMap[Key]]
|
|
14
|
+
const {
|
|
15
|
+
filePath,
|
|
16
|
+
items: {
|
|
17
|
+
[iconName]: { viewBox, width, height }
|
|
18
|
+
}
|
|
19
|
+
} = SPRITES_META[spriteName]
|
|
20
|
+
|
|
21
|
+
const axis = width === height ? 'xy' : width > height ? 'x' : 'y'
|
|
22
|
+
|
|
23
|
+
return { filePath, iconName, viewBox, axis }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Icon = ({ name, className, ...props }: IconProps) => {
|
|
27
|
+
const { viewBox, filePath, iconName, axis } = getIconMeta(name)
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<svg
|
|
31
|
+
className={cn('text-inherit inline-block size-6 select-none fill-current', className)}
|
|
32
|
+
focusable='false'
|
|
33
|
+
viewBox={viewBox}
|
|
34
|
+
aria-hidden
|
|
35
|
+
data-axis={axis}
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
<use href={`/sprites/${filePath}#${iconName}`} />
|
|
39
|
+
</svg>
|
|
40
|
+
)
|
|
41
|
+
}
|