@cloud-ru/ds-fields 1.0.0
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/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/README.md +888 -0
- package/dist/cjs/components/FieldColor/FieldColor.d.ts +48 -0
- package/dist/cjs/components/FieldColor/FieldColor.js +147 -0
- package/dist/cjs/components/FieldColor/index.d.ts +1 -0
- package/dist/cjs/components/FieldColor/index.js +17 -0
- package/dist/cjs/components/FieldColor/styles.module.css +79 -0
- package/dist/cjs/components/FieldColor/utils.d.ts +7 -0
- package/dist/cjs/components/FieldColor/utils.js +19 -0
- package/dist/cjs/components/FieldCombo/FieldCombo.d.ts +91 -0
- package/dist/cjs/components/FieldCombo/FieldCombo.js +200 -0
- package/dist/cjs/components/FieldCombo/index.d.ts +1 -0
- package/dist/cjs/components/FieldCombo/index.js +17 -0
- package/dist/cjs/components/FieldDate/FieldDate.d.ts +2 -0
- package/dist/cjs/components/FieldDate/FieldDate.js +369 -0
- package/dist/cjs/components/FieldDate/constants.d.ts +10 -0
- package/dist/cjs/components/FieldDate/constants.js +13 -0
- package/dist/cjs/components/FieldDate/index.d.ts +3 -0
- package/dist/cjs/components/FieldDate/index.js +19 -0
- package/dist/cjs/components/FieldDate/mask.d.ts +20 -0
- package/dist/cjs/components/FieldDate/mask.js +117 -0
- package/dist/cjs/components/FieldDate/styles.module.css +43 -0
- package/dist/cjs/components/FieldDate/types.d.ts +100 -0
- package/dist/cjs/components/FieldDate/types.js +2 -0
- package/dist/cjs/components/FieldDate/utils.d.ts +3 -0
- package/dist/cjs/components/FieldDate/utils.js +8 -0
- package/dist/cjs/components/FieldSecure/FieldSecure.d.ts +64 -0
- package/dist/cjs/components/FieldSecure/FieldSecure.js +158 -0
- package/dist/cjs/components/FieldSecure/index.d.ts +1 -0
- package/dist/cjs/components/FieldSecure/index.js +17 -0
- package/dist/cjs/components/FieldSelect/FieldSelect.d.ts +2 -0
- package/dist/cjs/components/FieldSelect/FieldSelect.js +360 -0
- package/dist/cjs/components/FieldSelect/constants.d.ts +4 -0
- package/dist/cjs/components/FieldSelect/constants.js +7 -0
- package/dist/cjs/components/FieldSelect/index.d.ts +3 -0
- package/dist/cjs/components/FieldSelect/index.js +19 -0
- package/dist/cjs/components/FieldSelect/styles.module.css +92 -0
- package/dist/cjs/components/FieldSelect/types.d.ts +197 -0
- package/dist/cjs/components/FieldSelect/types.js +2 -0
- package/dist/cjs/components/FieldSelect/utils.d.ts +19 -0
- package/dist/cjs/components/FieldSelect/utils.js +104 -0
- package/dist/cjs/components/FieldSlider/FieldSlider.d.ts +92 -0
- package/dist/cjs/components/FieldSlider/FieldSlider.js +196 -0
- package/dist/cjs/components/FieldSlider/index.d.ts +2 -0
- package/dist/cjs/components/FieldSlider/index.js +18 -0
- package/dist/cjs/components/FieldSlider/styles.module.css +44 -0
- package/dist/cjs/components/FieldSlider/types.d.ts +4 -0
- package/dist/cjs/components/FieldSlider/types.js +2 -0
- package/dist/cjs/components/FieldSlider/utils/generateAllowedValues.d.ts +1 -0
- package/dist/cjs/components/FieldSlider/utils/generateAllowedValues.js +16 -0
- package/dist/cjs/components/FieldSlider/utils/getClosestMark.d.ts +4 -0
- package/dist/cjs/components/FieldSlider/utils/getClosestMark.js +16 -0
- package/dist/cjs/components/FieldSlider/utils/getMarkLabel.d.ts +2 -0
- package/dist/cjs/components/FieldSlider/utils/getMarkLabel.js +7 -0
- package/dist/cjs/components/FieldSlider/utils/getTextFieldValue.d.ts +2 -0
- package/dist/cjs/components/FieldSlider/utils/getTextFieldValue.js +9 -0
- package/dist/cjs/components/FieldSlider/utils/index.d.ts +5 -0
- package/dist/cjs/components/FieldSlider/utils/index.js +21 -0
- package/dist/cjs/components/FieldSlider/utils/isMarkObject.d.ts +6 -0
- package/dist/cjs/components/FieldSlider/utils/isMarkObject.js +6 -0
- package/dist/cjs/components/FieldStepper/FieldStepper.d.ts +81 -0
- package/dist/cjs/components/FieldStepper/FieldStepper.js +160 -0
- package/dist/cjs/components/FieldStepper/index.d.ts +1 -0
- package/dist/cjs/components/FieldStepper/index.js +17 -0
- package/dist/cjs/components/FieldStepper/styles.module.css +78 -0
- package/dist/cjs/components/FieldStepper/utils.d.ts +14 -0
- package/dist/cjs/components/FieldStepper/utils.js +45 -0
- package/dist/cjs/components/FieldText/FieldText.d.ts +11 -0
- package/dist/cjs/components/FieldText/FieldText.js +14 -0
- package/dist/cjs/components/FieldText/index.d.ts +1 -0
- package/dist/cjs/components/FieldText/index.js +17 -0
- package/dist/cjs/components/FieldTextArea/FieldTextArea.d.ts +95 -0
- package/dist/cjs/components/FieldTextArea/FieldTextArea.js +114 -0
- package/dist/cjs/components/FieldTextArea/index.d.ts +1 -0
- package/dist/cjs/components/FieldTextArea/index.js +17 -0
- package/dist/cjs/components/FieldTextArea/styles.module.css +123 -0
- package/dist/cjs/components/FieldTime/FieldTime.d.ts +74 -0
- package/dist/cjs/components/FieldTime/FieldTime.js +167 -0
- package/dist/cjs/components/FieldTime/index.d.ts +2 -0
- package/dist/cjs/components/FieldTime/index.js +17 -0
- package/dist/cjs/components/FieldTime/mask.d.ts +3 -0
- package/dist/cjs/components/FieldTime/mask.js +24 -0
- package/dist/cjs/components/FieldTime/styles.module.css +3 -0
- package/dist/cjs/components/index.d.ts +14 -0
- package/dist/cjs/components/index.js +32 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButton.d.ts +35 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButton.js +47 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.d.ts +26 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.js +24 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/constants.d.ts +9 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/constants.js +12 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/index.d.ts +4 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/index.js +20 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/styles.module.css +204 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/types.d.ts +4 -0
- package/dist/cjs/components/shared/helperComponents/FieldElementButton/types.js +2 -0
- package/dist/cjs/components/shared/helperComponents/FieldShell/FieldShell.d.ts +43 -0
- package/dist/cjs/components/shared/helperComponents/FieldShell/FieldShell.js +22 -0
- package/dist/cjs/components/shared/helperComponents/FieldShell/index.d.ts +1 -0
- package/dist/cjs/components/shared/helperComponents/FieldShell/index.js +17 -0
- package/dist/cjs/components/shared/helperComponents/FieldShell/styles.module.css +11 -0
- package/dist/cjs/components/shared/hooks/useCopyButton.d.ts +20 -0
- package/dist/cjs/components/shared/hooks/useCopyButton.js +58 -0
- package/dist/cjs/components/shared/index.d.ts +4 -0
- package/dist/cjs/components/shared/index.js +20 -0
- package/dist/cjs/components/shared/styles.module.css +673 -0
- package/dist/cjs/components/shared/utils.d.ts +69 -0
- package/dist/cjs/components/shared/utils.js +104 -0
- package/dist/cjs/constants.d.ts +61 -0
- package/dist/cjs/constants.js +76 -0
- package/dist/cjs/hooks/index.d.ts +1 -0
- package/dist/cjs/hooks/index.js +17 -0
- package/dist/cjs/hooks/useAdaptiveAutoFocus.d.ts +7 -0
- package/dist/cjs/hooks/useAdaptiveAutoFocus.js +10 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/segments/index.d.ts +2 -0
- package/dist/cjs/segments/index.js +18 -0
- package/dist/cjs/segments/segments.d.ts +22 -0
- package/dist/cjs/segments/segments.js +46 -0
- package/dist/cjs/segments/useSegmentedMask.d.ts +43 -0
- package/dist/cjs/segments/useSegmentedMask.js +282 -0
- package/dist/cjs/style.css +1350 -0
- package/dist/esm/components/FieldColor/FieldColor.d.ts +48 -0
- package/dist/esm/components/FieldColor/FieldColor.js +141 -0
- package/dist/esm/components/FieldColor/index.d.ts +1 -0
- package/dist/esm/components/FieldColor/index.js +1 -0
- package/dist/esm/components/FieldColor/styles.module.css +79 -0
- package/dist/esm/components/FieldColor/utils.d.ts +7 -0
- package/dist/esm/components/FieldColor/utils.js +16 -0
- package/dist/esm/components/FieldCombo/FieldCombo.d.ts +91 -0
- package/dist/esm/components/FieldCombo/FieldCombo.js +194 -0
- package/dist/esm/components/FieldCombo/index.d.ts +1 -0
- package/dist/esm/components/FieldCombo/index.js +1 -0
- package/dist/esm/components/FieldDate/FieldDate.d.ts +2 -0
- package/dist/esm/components/FieldDate/FieldDate.js +363 -0
- package/dist/esm/components/FieldDate/constants.d.ts +10 -0
- package/dist/esm/components/FieldDate/constants.js +10 -0
- package/dist/esm/components/FieldDate/index.d.ts +3 -0
- package/dist/esm/components/FieldDate/index.js +3 -0
- package/dist/esm/components/FieldDate/mask.d.ts +20 -0
- package/dist/esm/components/FieldDate/mask.js +111 -0
- package/dist/esm/components/FieldDate/styles.module.css +43 -0
- package/dist/esm/components/FieldDate/types.d.ts +100 -0
- package/dist/esm/components/FieldDate/types.js +1 -0
- package/dist/esm/components/FieldDate/utils.d.ts +3 -0
- package/dist/esm/components/FieldDate/utils.js +5 -0
- package/dist/esm/components/FieldSecure/FieldSecure.d.ts +64 -0
- package/dist/esm/components/FieldSecure/FieldSecure.js +152 -0
- package/dist/esm/components/FieldSecure/index.d.ts +1 -0
- package/dist/esm/components/FieldSecure/index.js +1 -0
- package/dist/esm/components/FieldSelect/FieldSelect.d.ts +2 -0
- package/dist/esm/components/FieldSelect/FieldSelect.js +354 -0
- package/dist/esm/components/FieldSelect/constants.d.ts +4 -0
- package/dist/esm/components/FieldSelect/constants.js +4 -0
- package/dist/esm/components/FieldSelect/index.d.ts +3 -0
- package/dist/esm/components/FieldSelect/index.js +3 -0
- package/dist/esm/components/FieldSelect/styles.module.css +92 -0
- package/dist/esm/components/FieldSelect/types.d.ts +197 -0
- package/dist/esm/components/FieldSelect/types.js +1 -0
- package/dist/esm/components/FieldSelect/utils.d.ts +19 -0
- package/dist/esm/components/FieldSelect/utils.js +93 -0
- package/dist/esm/components/FieldSlider/FieldSlider.d.ts +92 -0
- package/dist/esm/components/FieldSlider/FieldSlider.js +190 -0
- package/dist/esm/components/FieldSlider/index.d.ts +2 -0
- package/dist/esm/components/FieldSlider/index.js +2 -0
- package/dist/esm/components/FieldSlider/styles.module.css +44 -0
- package/dist/esm/components/FieldSlider/types.d.ts +4 -0
- package/dist/esm/components/FieldSlider/types.js +1 -0
- package/dist/esm/components/FieldSlider/utils/generateAllowedValues.d.ts +1 -0
- package/dist/esm/components/FieldSlider/utils/generateAllowedValues.js +13 -0
- package/dist/esm/components/FieldSlider/utils/getClosestMark.d.ts +4 -0
- package/dist/esm/components/FieldSlider/utils/getClosestMark.js +13 -0
- package/dist/esm/components/FieldSlider/utils/getMarkLabel.d.ts +2 -0
- package/dist/esm/components/FieldSlider/utils/getMarkLabel.js +4 -0
- package/dist/esm/components/FieldSlider/utils/getTextFieldValue.d.ts +2 -0
- package/dist/esm/components/FieldSlider/utils/getTextFieldValue.js +6 -0
- package/dist/esm/components/FieldSlider/utils/index.d.ts +5 -0
- package/dist/esm/components/FieldSlider/utils/index.js +5 -0
- package/dist/esm/components/FieldSlider/utils/isMarkObject.d.ts +6 -0
- package/dist/esm/components/FieldSlider/utils/isMarkObject.js +3 -0
- package/dist/esm/components/FieldStepper/FieldStepper.d.ts +81 -0
- package/dist/esm/components/FieldStepper/FieldStepper.js +154 -0
- package/dist/esm/components/FieldStepper/index.d.ts +1 -0
- package/dist/esm/components/FieldStepper/index.js +1 -0
- package/dist/esm/components/FieldStepper/styles.module.css +78 -0
- package/dist/esm/components/FieldStepper/utils.d.ts +14 -0
- package/dist/esm/components/FieldStepper/utils.js +38 -0
- package/dist/esm/components/FieldText/FieldText.d.ts +11 -0
- package/dist/esm/components/FieldText/FieldText.js +11 -0
- package/dist/esm/components/FieldText/index.d.ts +1 -0
- package/dist/esm/components/FieldText/index.js +1 -0
- package/dist/esm/components/FieldTextArea/FieldTextArea.d.ts +95 -0
- package/dist/esm/components/FieldTextArea/FieldTextArea.js +108 -0
- package/dist/esm/components/FieldTextArea/index.d.ts +1 -0
- package/dist/esm/components/FieldTextArea/index.js +1 -0
- package/dist/esm/components/FieldTextArea/styles.module.css +123 -0
- package/dist/esm/components/FieldTime/FieldTime.d.ts +74 -0
- package/dist/esm/components/FieldTime/FieldTime.js +161 -0
- package/dist/esm/components/FieldTime/index.d.ts +2 -0
- package/dist/esm/components/FieldTime/index.js +1 -0
- package/dist/esm/components/FieldTime/mask.d.ts +3 -0
- package/dist/esm/components/FieldTime/mask.js +20 -0
- package/dist/esm/components/FieldTime/styles.module.css +3 -0
- package/dist/esm/components/index.d.ts +14 -0
- package/dist/esm/components/index.js +12 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButton.d.ts +35 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButton.js +41 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.d.ts +26 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.js +21 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/constants.d.ts +9 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/constants.js +9 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/index.d.ts +4 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/index.js +4 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/styles.module.css +204 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/types.d.ts +4 -0
- package/dist/esm/components/shared/helperComponents/FieldElementButton/types.js +1 -0
- package/dist/esm/components/shared/helperComponents/FieldShell/FieldShell.d.ts +43 -0
- package/dist/esm/components/shared/helperComponents/FieldShell/FieldShell.js +16 -0
- package/dist/esm/components/shared/helperComponents/FieldShell/index.d.ts +1 -0
- package/dist/esm/components/shared/helperComponents/FieldShell/index.js +1 -0
- package/dist/esm/components/shared/helperComponents/FieldShell/styles.module.css +11 -0
- package/dist/esm/components/shared/hooks/useCopyButton.d.ts +20 -0
- package/dist/esm/components/shared/hooks/useCopyButton.js +55 -0
- package/dist/esm/components/shared/index.d.ts +4 -0
- package/dist/esm/components/shared/index.js +4 -0
- package/dist/esm/components/shared/styles.module.css +673 -0
- package/dist/esm/components/shared/utils.d.ts +69 -0
- package/dist/esm/components/shared/utils.js +91 -0
- package/dist/esm/constants.d.ts +61 -0
- package/dist/esm/constants.js +73 -0
- package/dist/esm/hooks/index.d.ts +1 -0
- package/dist/esm/hooks/index.js +1 -0
- package/dist/esm/hooks/useAdaptiveAutoFocus.d.ts +7 -0
- package/dist/esm/hooks/useAdaptiveAutoFocus.js +7 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/segments/index.d.ts +2 -0
- package/dist/esm/segments/index.js +2 -0
- package/dist/esm/segments/segments.d.ts +22 -0
- package/dist/esm/segments/segments.js +43 -0
- package/dist/esm/segments/useSegmentedMask.d.ts +43 -0
- package/dist/esm/segments/useSegmentedMask.js +279 -0
- package/dist/esm/style.css +1350 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +62 -0
- package/src/components/FieldColor/FieldColor.tsx +426 -0
- package/src/components/FieldColor/index.ts +1 -0
- package/src/components/FieldColor/styles.module.scss +120 -0
- package/src/components/FieldColor/utils.ts +17 -0
- package/src/components/FieldCombo/FieldCombo.tsx +495 -0
- package/src/components/FieldCombo/index.ts +1 -0
- package/src/components/FieldDate/FieldDate.tsx +658 -0
- package/src/components/FieldDate/constants.ts +11 -0
- package/src/components/FieldDate/index.ts +3 -0
- package/src/components/FieldDate/mask.ts +123 -0
- package/src/components/FieldDate/styles.module.scss +56 -0
- package/src/components/FieldDate/types.ts +124 -0
- package/src/components/FieldDate/utils.ts +7 -0
- package/src/components/FieldSecure/FieldSecure.tsx +398 -0
- package/src/components/FieldSecure/index.ts +1 -0
- package/src/components/FieldSelect/FieldSelect.tsx +689 -0
- package/src/components/FieldSelect/constants.ts +4 -0
- package/src/components/FieldSelect/index.ts +3 -0
- package/src/components/FieldSelect/styles.module.scss +104 -0
- package/src/components/FieldSelect/types.ts +212 -0
- package/src/components/FieldSelect/utils.ts +134 -0
- package/src/components/FieldSlider/FieldSlider.tsx +502 -0
- package/src/components/FieldSlider/index.ts +2 -0
- package/src/components/FieldSlider/styles.module.scss +47 -0
- package/src/components/FieldSlider/types.ts +5 -0
- package/src/components/FieldSlider/utils/generateAllowedValues.ts +13 -0
- package/src/components/FieldSlider/utils/getClosestMark.ts +21 -0
- package/src/components/FieldSlider/utils/getMarkLabel.ts +7 -0
- package/src/components/FieldSlider/utils/getTextFieldValue.ts +8 -0
- package/src/components/FieldSlider/utils/index.ts +5 -0
- package/src/components/FieldSlider/utils/isMarkObject.ts +7 -0
- package/src/components/FieldStepper/FieldStepper.tsx +457 -0
- package/src/components/FieldStepper/index.ts +1 -0
- package/src/components/FieldStepper/styles.module.scss +98 -0
- package/src/components/FieldStepper/utils.ts +44 -0
- package/src/components/FieldText/FieldText.tsx +27 -0
- package/src/components/FieldText/index.ts +1 -0
- package/src/components/FieldTextArea/FieldTextArea.tsx +374 -0
- package/src/components/FieldTextArea/index.ts +1 -0
- package/src/components/FieldTextArea/styles.module.scss +192 -0
- package/src/components/FieldTime/FieldTime.tsx +401 -0
- package/src/components/FieldTime/index.ts +2 -0
- package/src/components/FieldTime/mask.ts +22 -0
- package/src/components/FieldTime/styles.module.scss +3 -0
- package/src/components/index.ts +14 -0
- package/src/components/shared/helperComponents/FieldElementButton/FieldElementButton.tsx +127 -0
- package/src/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.tsx +72 -0
- package/src/components/shared/helperComponents/FieldElementButton/constants.ts +10 -0
- package/src/components/shared/helperComponents/FieldElementButton/index.ts +4 -0
- package/src/components/shared/helperComponents/FieldElementButton/styles.module.scss +137 -0
- package/src/components/shared/helperComponents/FieldElementButton/types.ts +6 -0
- package/src/components/shared/helperComponents/FieldShell/FieldShell.tsx +100 -0
- package/src/components/shared/helperComponents/FieldShell/index.ts +1 -0
- package/src/components/shared/helperComponents/FieldShell/styles.module.scss +13 -0
- package/src/components/shared/hooks/useCopyButton.tsx +103 -0
- package/src/components/shared/index.ts +4 -0
- package/src/components/shared/styles.module.scss +409 -0
- package/src/components/shared/utils.ts +128 -0
- package/src/constants.ts +73 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAdaptiveAutoFocus.ts +16 -0
- package/src/index.ts +3 -0
- package/src/segments/index.ts +2 -0
- package/src/segments/segments.ts +74 -0
- package/src/segments/useSegmentedMask.ts +361 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { FieldDecorator, FieldDecoratorProps, SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
|
|
2
|
+
import { useButtonNavigation, useClearButton } from '@cloud-ru/ds-input-private';
|
|
3
|
+
import { BAR_HIDE_STRATEGY, RESIZE, Scroll, SIZE as SCROLL_SIZE } from '@cloud-ru/ds-scroll';
|
|
4
|
+
import { extractSupportProps, useValueControl } from '@cloud-ru/ds-utils';
|
|
5
|
+
import cn from 'classnames';
|
|
6
|
+
import mergeRefs from 'merge-refs';
|
|
7
|
+
import {
|
|
8
|
+
ChangeEvent,
|
|
9
|
+
CSSProperties,
|
|
10
|
+
FocusEvent,
|
|
11
|
+
forwardRef,
|
|
12
|
+
HTMLAttributes,
|
|
13
|
+
KeyboardEvent,
|
|
14
|
+
MouseEvent,
|
|
15
|
+
ReactNode,
|
|
16
|
+
useCallback,
|
|
17
|
+
useMemo,
|
|
18
|
+
useRef,
|
|
19
|
+
useState,
|
|
20
|
+
} from 'react';
|
|
21
|
+
import TextareaAutosize from 'react-textarea-autosize';
|
|
22
|
+
|
|
23
|
+
import { TEST_IDS } from '../../constants';
|
|
24
|
+
import { FieldLayoutPresets, useAdaptiveAutoFocus } from '../../hooks';
|
|
25
|
+
import { copyTextToClipboard, FieldShell, toInputSize, useCopyButton } from '../shared';
|
|
26
|
+
import fieldStyles from '../shared/styles.module.scss';
|
|
27
|
+
import styles from './styles.module.scss';
|
|
28
|
+
|
|
29
|
+
type FieldTextAreaDecoratorProps = Omit<FieldDecoratorProps, 'children'>;
|
|
30
|
+
|
|
31
|
+
type FieldTextAreaOwnProps = {
|
|
32
|
+
/** CSS-класс корня `FieldDecorator` */
|
|
33
|
+
className?: string;
|
|
34
|
+
/** CSS-класс оболочки поля */
|
|
35
|
+
fieldClassName?: string;
|
|
36
|
+
/** Значение (controlled-режим) */
|
|
37
|
+
value?: string;
|
|
38
|
+
/** Начальное значение (uncontrolled-режим) */
|
|
39
|
+
defaultValue?: string;
|
|
40
|
+
/** Колбек смены значения */
|
|
41
|
+
onChange?(value: string, event?: ChangeEvent<HTMLTextAreaElement>): void;
|
|
42
|
+
/** Плейсхолдер */
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
/** HTML id */
|
|
45
|
+
id?: string;
|
|
46
|
+
/** HTML name */
|
|
47
|
+
name?: string;
|
|
48
|
+
/** Максимальное количество символов */
|
|
49
|
+
maxLength?: number;
|
|
50
|
+
/** Поле выключено */
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
/** Только для чтения */
|
|
53
|
+
readonly?: boolean;
|
|
54
|
+
/** Автофокус. На mobile выключается адаптивно (см. `layoutPresets`) */
|
|
55
|
+
autoFocus?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Переопределение адаптивных дефолтов по раскладке. Участвует `autoFocus`: на mobile он выключен
|
|
58
|
+
* (открывает клавиатуру без действия). Вернуть на mobile — `layoutPresets={{ mobile: { autoFocus: true } }}`.
|
|
59
|
+
*/
|
|
60
|
+
layoutPresets?: FieldLayoutPresets;
|
|
61
|
+
/** Режим виртуальной клавиатуры (`inputmode` нативного `<textarea>`) */
|
|
62
|
+
inputMode?: HTMLAttributes<HTMLTextAreaElement>['inputMode'];
|
|
63
|
+
/** Проверка орфографии */
|
|
64
|
+
spellCheck?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Минимальное количество строк
|
|
67
|
+
* @default 3
|
|
68
|
+
*/
|
|
69
|
+
minRows?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Максимальное количество строк (после — появляется скролл)
|
|
72
|
+
* @default 1000
|
|
73
|
+
*/
|
|
74
|
+
maxRows?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Разрешить ввод свыше `maxLength` символов (счётчик продолжит расти).
|
|
77
|
+
* @default true
|
|
78
|
+
*/
|
|
79
|
+
allowMoreThanMaxLength?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Нода над textarea — ряд элементов до контента (Figma `elementWrapperBefore` /
|
|
82
|
+
* `slotBeforeContent`): тулбар с кнопками, чипами и т.п.
|
|
83
|
+
*/
|
|
84
|
+
header?: ReactNode;
|
|
85
|
+
/**
|
|
86
|
+
* Нода под textarea — ряд элементов после контента (Figma `elementWrapperAfter` /
|
|
87
|
+
* `slotAfterContent`): действия, счётчик-плагин и т.п.
|
|
88
|
+
*/
|
|
89
|
+
footer?: ReactNode;
|
|
90
|
+
/**
|
|
91
|
+
* Можно ли менять высоту мышкой за нижний угол. Игнорируется при `disabled` или `readonly`.
|
|
92
|
+
* @default false
|
|
93
|
+
*/
|
|
94
|
+
resizable?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Фон поля (acrylic)
|
|
97
|
+
* @default true
|
|
98
|
+
*/
|
|
99
|
+
background?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Кнопка очистки (видна при value && !readonly)
|
|
102
|
+
* @default true
|
|
103
|
+
*/
|
|
104
|
+
showClearButton?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Кнопка копирования (видна при value && !disabled, независимо от readonly)
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
109
|
+
showCopyButton?: boolean;
|
|
110
|
+
/** Колбек после копирования */
|
|
111
|
+
onCopyButtonClick?(): void;
|
|
112
|
+
/** Колбек фокуса */
|
|
113
|
+
onFocus?(event: FocusEvent<HTMLTextAreaElement>): void;
|
|
114
|
+
/** Колбек блюра */
|
|
115
|
+
onBlur?(event: FocusEvent<HTMLTextAreaElement>): void;
|
|
116
|
+
/** Колбек нажатия клавиши */
|
|
117
|
+
onKeyDown?(event: KeyboardEvent<HTMLTextAreaElement>): void;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export type FieldTextAreaProps = FieldTextAreaDecoratorProps & FieldTextAreaOwnProps;
|
|
121
|
+
|
|
122
|
+
export const FieldTextArea = forwardRef<HTMLTextAreaElement, FieldTextAreaProps>(function FieldTextArea(
|
|
123
|
+
{
|
|
124
|
+
label = '',
|
|
125
|
+
labelTooltip,
|
|
126
|
+
caption,
|
|
127
|
+
hint,
|
|
128
|
+
error,
|
|
129
|
+
validationState = VALIDATION_STATE.Default,
|
|
130
|
+
showHintIcon,
|
|
131
|
+
length,
|
|
132
|
+
required,
|
|
133
|
+
size = SIZE.M,
|
|
134
|
+
className,
|
|
135
|
+
fieldClassName,
|
|
136
|
+
background = true,
|
|
137
|
+
value: valueProp,
|
|
138
|
+
defaultValue = '',
|
|
139
|
+
onChange,
|
|
140
|
+
placeholder,
|
|
141
|
+
id,
|
|
142
|
+
name,
|
|
143
|
+
maxLength,
|
|
144
|
+
disabled,
|
|
145
|
+
readonly: readOnly,
|
|
146
|
+
autoFocus,
|
|
147
|
+
layoutPresets,
|
|
148
|
+
inputMode,
|
|
149
|
+
spellCheck,
|
|
150
|
+
minRows = 3,
|
|
151
|
+
maxRows = 1000,
|
|
152
|
+
resizable = false,
|
|
153
|
+
allowMoreThanMaxLength = true,
|
|
154
|
+
header,
|
|
155
|
+
footer,
|
|
156
|
+
showClearButton: showClearButtonProp = true,
|
|
157
|
+
showCopyButton: showCopyButtonProp = true,
|
|
158
|
+
onCopyButtonClick,
|
|
159
|
+
onFocus: onFocusProp,
|
|
160
|
+
onBlur: onBlurProp,
|
|
161
|
+
onKeyDown: onKeyDownProp,
|
|
162
|
+
'data-test-id': dataTestId,
|
|
163
|
+
...rest
|
|
164
|
+
},
|
|
165
|
+
ref,
|
|
166
|
+
) {
|
|
167
|
+
const localRef = useRef<HTMLTextAreaElement>(null);
|
|
168
|
+
const clearButtonRef = useRef<HTMLButtonElement>(null);
|
|
169
|
+
const copyButtonRef = useRef<HTMLButtonElement>(null);
|
|
170
|
+
const [focusVisible, setFocusVisible] = useState(false);
|
|
171
|
+
const [hover, setHover] = useState(false);
|
|
172
|
+
|
|
173
|
+
const resolvedAutoFocus = useAdaptiveAutoFocus(autoFocus, layoutPresets);
|
|
174
|
+
|
|
175
|
+
// controlled/uncontrolled: useValueControl держит внутреннее состояние при отсутствии `value`,
|
|
176
|
+
// событие в `onChange` пробрасываем сами (useValueControl передаёт только значение).
|
|
177
|
+
const [value = '', setValue] = useValueControl<string>({ value: valueProp, defaultValue });
|
|
178
|
+
|
|
179
|
+
const effectiveValidationState = useMemo(
|
|
180
|
+
() => (error ? VALIDATION_STATE.Error : validationState),
|
|
181
|
+
[error, validationState],
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const stringValue = String(value ?? '');
|
|
185
|
+
const isResizable = resizable && !disabled && !readOnly;
|
|
186
|
+
const showClearUi = Boolean(showClearButtonProp && stringValue && !readOnly && !disabled);
|
|
187
|
+
// Copy не завязан на readonly (паритет с snack-uikit master): виден при любом непустом значении.
|
|
188
|
+
// В editable-режиме показываются обе кнопки (clear + copy), в readonly — только copy.
|
|
189
|
+
const showCopyUi = Boolean(showCopyButtonProp && stringValue && !disabled);
|
|
190
|
+
|
|
191
|
+
const onClear = useCallback(() => {
|
|
192
|
+
setValue('');
|
|
193
|
+
onChange?.('');
|
|
194
|
+
localRef.current?.focus();
|
|
195
|
+
}, [onChange, setValue]);
|
|
196
|
+
|
|
197
|
+
const onCopy = useCallback(async () => {
|
|
198
|
+
const copied = await copyTextToClipboard(stringValue);
|
|
199
|
+
if (copied) {
|
|
200
|
+
onCopyButtonClick?.();
|
|
201
|
+
}
|
|
202
|
+
return copied;
|
|
203
|
+
}, [onCopyButtonClick, stringValue]);
|
|
204
|
+
|
|
205
|
+
const clearButtonSettings = useClearButton({
|
|
206
|
+
clearButtonRef,
|
|
207
|
+
showClearButton: showClearUi,
|
|
208
|
+
size: toInputSize(size),
|
|
209
|
+
onClear,
|
|
210
|
+
disabled: Boolean(disabled || readOnly),
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const copyButtonSettings = useCopyButton({
|
|
214
|
+
copyButtonRef,
|
|
215
|
+
showCopyButton: showCopyUi,
|
|
216
|
+
size: toInputSize(size),
|
|
217
|
+
onCopy,
|
|
218
|
+
disabled: Boolean(disabled),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const { postfixButtons, inputTabIndex, onInputKeyDown } = useButtonNavigation<HTMLTextAreaElement>({
|
|
222
|
+
inputRef: localRef,
|
|
223
|
+
postfixButtons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
|
|
224
|
+
readonly: Boolean(readOnly),
|
|
225
|
+
submitKeys: ['Tab'],
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const handleKeyDown = useCallback(
|
|
229
|
+
(event: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
230
|
+
onKeyDownProp?.(event);
|
|
231
|
+
onInputKeyDown(event);
|
|
232
|
+
},
|
|
233
|
+
[onInputKeyDown, onKeyDownProp],
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
|
237
|
+
setValue(event.target.value);
|
|
238
|
+
onChange?.(event.target.value, event);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// Клик в «пустую» зону поля (под textarea при minRows-резерве, в правый резерв под кнопки)
|
|
242
|
+
// фокусит textarea и ставит курсор в конец — паритет со снеком, где попадание в любую область
|
|
243
|
+
// поля работает как клик по textarea. Намеренно `onClick`, а не `onMouseDown`+preventDefault:
|
|
244
|
+
// resize-ручка scroll-контейнера тоже работает через mousedown-drag, и preventDefault убивал бы
|
|
245
|
+
// нативный CSS-resize. Click после resize-drag не возникает, а клики по textarea, кнопкам
|
|
246
|
+
// clear/copy и DS-скроллбару отсеиваем по target.
|
|
247
|
+
const handleContentClick = useCallback(
|
|
248
|
+
(event: MouseEvent<HTMLDivElement>) => {
|
|
249
|
+
const target = event.target as HTMLElement;
|
|
250
|
+
if (disabled || target === localRef.current || target.closest('button, [class*="os-scrollbar"]')) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const textarea = localRef.current;
|
|
254
|
+
if (textarea) {
|
|
255
|
+
textarea.focus();
|
|
256
|
+
const end = textarea.value.length;
|
|
257
|
+
textarea.setSelectionRange(end, end);
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
[disabled],
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const handleFocus = useCallback(
|
|
264
|
+
(event: FocusEvent<HTMLTextAreaElement>) => {
|
|
265
|
+
setFocusVisible(event.target.matches(':focus-visible'));
|
|
266
|
+
onFocusProp?.(event);
|
|
267
|
+
},
|
|
268
|
+
[onFocusProp],
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const handleBlur = useCallback(
|
|
272
|
+
(event: FocusEvent<HTMLTextAreaElement>) => {
|
|
273
|
+
setFocusVisible(false);
|
|
274
|
+
onBlurProp?.(event);
|
|
275
|
+
},
|
|
276
|
+
[onBlurProp],
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
const handleMouseEnter = useCallback(() => {
|
|
280
|
+
if (!readOnly) {
|
|
281
|
+
setHover(true);
|
|
282
|
+
}
|
|
283
|
+
}, [readOnly]);
|
|
284
|
+
|
|
285
|
+
const handleMouseLeave = useCallback(() => {
|
|
286
|
+
setHover(false);
|
|
287
|
+
}, []);
|
|
288
|
+
|
|
289
|
+
const shell = (
|
|
290
|
+
<FieldShell
|
|
291
|
+
data-test-id={TEST_IDS.fieldTextAreaShell}
|
|
292
|
+
className={fieldClassName}
|
|
293
|
+
size={size}
|
|
294
|
+
validationState={effectiveValidationState}
|
|
295
|
+
disabled={disabled}
|
|
296
|
+
readonly={readOnly}
|
|
297
|
+
background={background}
|
|
298
|
+
focusVisible={focusVisible}
|
|
299
|
+
hover={hover}
|
|
300
|
+
header={header}
|
|
301
|
+
footer={footer}
|
|
302
|
+
style={{ '--field-textarea-min-rows': minRows, '--field-textarea-max-rows': maxRows } as CSSProperties}
|
|
303
|
+
onMouseEnter={handleMouseEnter}
|
|
304
|
+
onMouseLeave={handleMouseLeave}
|
|
305
|
+
>
|
|
306
|
+
{/* onClick лишь форвардит фокус в textarea (реальный фокусируемый/клавиатурный элемент
|
|
307
|
+
рядом) при клике в пустую зону поля — это не самостоятельный контрол, клавиатурный
|
|
308
|
+
доступ обеспечивает сама textarea, поэтому role/tabIndex здесь не нужны. */}
|
|
309
|
+
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
|
310
|
+
<div className={cn(fieldStyles.contentWrapper, styles.contentArea)} onClick={handleContentClick}>
|
|
311
|
+
{/* Скролл при превышении maxRows — кастомный из @cloud-ru/ds-scroll (по Figma), не нативный
|
|
312
|
+
скроллбар textarea. maxRows задаёт max-height контейнера через CSS-переменные,
|
|
313
|
+
autosize-textarea растёт внутри, Scroll рисует DS-скроллбар. Resize-handle —
|
|
314
|
+
на scroll-контейнере (CSS resize), не на самой textarea. */}
|
|
315
|
+
<Scroll
|
|
316
|
+
className={cn(styles.scrollContainer, { [styles.scrollContainerResizable]: isResizable })}
|
|
317
|
+
size={SCROLL_SIZE.S}
|
|
318
|
+
barHideStrategy={BAR_HIDE_STRATEGY.Never}
|
|
319
|
+
resize={isResizable ? RESIZE.Vertical : RESIZE.None}
|
|
320
|
+
overflow={{ x: 'hidden' }}
|
|
321
|
+
data-test-id={TEST_IDS.fieldTextAreaScrollArea}
|
|
322
|
+
>
|
|
323
|
+
<div className={fieldStyles.inputLine}>
|
|
324
|
+
<TextareaAutosize
|
|
325
|
+
ref={mergeRefs(ref, localRef)}
|
|
326
|
+
className={styles.textarea}
|
|
327
|
+
value={value}
|
|
328
|
+
onChange={handleChange}
|
|
329
|
+
placeholder={placeholder}
|
|
330
|
+
disabled={disabled}
|
|
331
|
+
readOnly={readOnly}
|
|
332
|
+
id={id}
|
|
333
|
+
name={name}
|
|
334
|
+
maxLength={allowMoreThanMaxLength ? undefined : maxLength}
|
|
335
|
+
autoFocus={resolvedAutoFocus}
|
|
336
|
+
inputMode={inputMode}
|
|
337
|
+
spellCheck={spellCheck}
|
|
338
|
+
minRows={minRows}
|
|
339
|
+
tabIndex={inputTabIndex}
|
|
340
|
+
data-test-id={TEST_IDS.fieldTextAreaInput}
|
|
341
|
+
onFocus={handleFocus}
|
|
342
|
+
onBlur={handleBlur}
|
|
343
|
+
onKeyDown={handleKeyDown}
|
|
344
|
+
{...extractSupportProps(rest)}
|
|
345
|
+
/>
|
|
346
|
+
</div>
|
|
347
|
+
</Scroll>
|
|
348
|
+
{postfixButtons && <span className={styles.postfixColumn}>{postfixButtons}</span>}
|
|
349
|
+
</div>
|
|
350
|
+
</FieldShell>
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
return (
|
|
354
|
+
<FieldDecorator
|
|
355
|
+
className={className}
|
|
356
|
+
label={label}
|
|
357
|
+
labelTooltip={labelTooltip}
|
|
358
|
+
caption={caption}
|
|
359
|
+
hint={hint}
|
|
360
|
+
error={error}
|
|
361
|
+
validationState={validationState}
|
|
362
|
+
showHintIcon={showHintIcon}
|
|
363
|
+
length={length ?? (maxLength ? { current: stringValue.length, max: maxLength } : undefined)}
|
|
364
|
+
required={required}
|
|
365
|
+
labelFor={id}
|
|
366
|
+
disabled={disabled}
|
|
367
|
+
readonly={readOnly}
|
|
368
|
+
size={size}
|
|
369
|
+
data-test-id={dataTestId}
|
|
370
|
+
>
|
|
371
|
+
{shell}
|
|
372
|
+
</FieldDecorator>
|
|
373
|
+
);
|
|
374
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FieldTextArea';
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/field.module' as field;
|
|
3
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/scroll.module' as scroll;
|
|
4
|
+
|
|
5
|
+
$sizes: 's', 'm', 'l';
|
|
6
|
+
|
|
7
|
+
// Ширина вертикального скроллбара @cloud-ru/ds-scroll (в компоненте он всегда size=s).
|
|
8
|
+
$scrollbar-width: base.simple-var(scroll.$scroll, 'anatomy', 'container', 'size', 's', 'width');
|
|
9
|
+
|
|
10
|
+
// Контейнер скролла (@cloud-ru/ds-scroll) вокруг textarea: minRows/maxRows клампят его высоту
|
|
11
|
+
// через CSS-переменные (выставляются компонентом на shell), autosize-textarea растёт внутри,
|
|
12
|
+
// скроллбар — кастомный DS, не нативный. Resize-handle (CSS resize) живёт на этом контейнере.
|
|
13
|
+
.scrollContainer {
|
|
14
|
+
flex: 1 1 auto;
|
|
15
|
+
min-width: 0;
|
|
16
|
+
min-height: calc(var(--field-textarea-min-rows, 3) * var(--field-textarea-row-height));
|
|
17
|
+
max-height: calc(var(--field-textarea-max-rows, 1000) * var(--field-textarea-row-height));
|
|
18
|
+
|
|
19
|
+
// Высота строки = line-height DS-типографики body соответствующего size.
|
|
20
|
+
@each $size in $sizes {
|
|
21
|
+
[data-size='#{$size}'] & {
|
|
22
|
+
--field-textarea-row-height: #{base.simple-var(base.$sn-regular, 'body', $size, 'line-height')};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// При resizable стартовая высота фиксируется на minRows — иначе CSS resize
|
|
28
|
+
// не от чего отсчитывать (контейнер с auto-высотой схлопывается обратно).
|
|
29
|
+
.scrollContainerResizable {
|
|
30
|
+
height: calc(var(--field-textarea-min-rows, 3) * var(--field-textarea-row-height));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.textarea {
|
|
34
|
+
resize: none;
|
|
35
|
+
|
|
36
|
+
// Нативный скроллбар не показывается никогда — скролл рисует обёртка @cloud-ru/ds-scroll.
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
|
|
39
|
+
width: 100%;
|
|
40
|
+
min-width: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
border: none;
|
|
43
|
+
|
|
44
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
45
|
+
|
|
46
|
+
background: transparent;
|
|
47
|
+
outline: none;
|
|
48
|
+
|
|
49
|
+
&::placeholder {
|
|
50
|
+
color: base.$sn-theme-color-available-version-textDisabled;
|
|
51
|
+
opacity: 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// disabled-поле затемняется opacity 0.4, placeholder уже textDisabled → бледный «призрак».
|
|
55
|
+
// Прячем целиком, как в @cloud-ru/ds-search (единый паттерн disabled в DS).
|
|
56
|
+
// TODO: выяснить у дизайнера ожидаемое поведение placeholder в disabled (скрывать / приглушать).
|
|
57
|
+
&:disabled::placeholder {
|
|
58
|
+
visibility: hidden;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// readonly текст приглушается так же, как .fieldInput в FieldText
|
|
62
|
+
// (общий shell, но textarea рендерит свой класс, не .fieldInput).
|
|
63
|
+
&:read-only {
|
|
64
|
+
color: base.$sn-theme-color-available-version-textTertiary;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// DS-типографика + min-height multiLine из field-токенов per-size.
|
|
68
|
+
// Без этого textarea наследует Nunito Sans 16/24 от Storybook root и не имеет минимальной высоты.
|
|
69
|
+
@each $size in $sizes {
|
|
70
|
+
[data-size='#{$size}'] & {
|
|
71
|
+
// Резерв справа под колонку clear/copy-кнопок (квадрат centeredWrapper) + скроллбар
|
|
72
|
+
// + горизонтальный паддинг inputLine (отступ слота кнопок от скроллбара по Figma):
|
|
73
|
+
// кнопки позиционируются абсолютно поверх скролл-области (см. .postfixColumn).
|
|
74
|
+
$button-slot: base.simple-var(
|
|
75
|
+
field.$field,
|
|
76
|
+
'anatomy',
|
|
77
|
+
'size',
|
|
78
|
+
$size,
|
|
79
|
+
'fieldContainer',
|
|
80
|
+
'centeredWrapper',
|
|
81
|
+
'max-height'
|
|
82
|
+
);
|
|
83
|
+
$input-line-padding: base.simple-var(
|
|
84
|
+
field.$field,
|
|
85
|
+
'anatomy',
|
|
86
|
+
'size',
|
|
87
|
+
$size,
|
|
88
|
+
'fieldContainer',
|
|
89
|
+
'contentWrapper',
|
|
90
|
+
'inputLine',
|
|
91
|
+
'padding-right'
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
min-height: base.simple-var(field.$field, 'anatomy', 'size', $size, 'fieldContainer', 'multiLine', 'min-height');
|
|
95
|
+
padding-right: calc(#{$button-slot} + #{$scrollbar-width} + #{$input-line-padding});
|
|
96
|
+
|
|
97
|
+
@include base.composite-var(base.$sn-regular, 'body', $size);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Якорь для абсолютного позиционирования кнопок: скролл-контейнер занимает всю ширину
|
|
103
|
+
// контента (скроллбар — у правого края поля, по Figma), кнопки накладываются поверх.
|
|
104
|
+
// verticalPadding (Figma contentWrapper py) опускает первую строку текста на свой отступ —
|
|
105
|
+
// без него текст (и центрированная по нему кнопка) прижимается к верхней рамке, и 32px-кнопка
|
|
106
|
+
// выступает за верхний край поля.
|
|
107
|
+
.contentArea {
|
|
108
|
+
position: relative;
|
|
109
|
+
|
|
110
|
+
@each $size in $sizes {
|
|
111
|
+
[data-size='#{$size}'] & {
|
|
112
|
+
padding-top: base.simple-var(
|
|
113
|
+
field.$field,
|
|
114
|
+
'anatomy',
|
|
115
|
+
'size',
|
|
116
|
+
$size,
|
|
117
|
+
'fieldContainer',
|
|
118
|
+
'contentWrapper',
|
|
119
|
+
'padding-top'
|
|
120
|
+
);
|
|
121
|
+
padding-bottom: base.simple-var(
|
|
122
|
+
field.$field,
|
|
123
|
+
'anatomy',
|
|
124
|
+
'size',
|
|
125
|
+
$size,
|
|
126
|
+
'fieldContainer',
|
|
127
|
+
'contentWrapper',
|
|
128
|
+
'padding-bottom'
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Кнопки clear/copy — поверх скролл-области, левее скроллбара (паритет с Figma и легаси:
|
|
135
|
+
// порядок справа налево — край поля, скроллбар, inputLine-паддинг, кнопки). Место под них
|
|
136
|
+
// резервирует padding-right textarea выше. Grid-ячейки клампят слот каждой кнопки до
|
|
137
|
+
// centeredWrapper-квадрата: сама кнопка крупнее слота и симметрично выступает за него
|
|
138
|
+
// (тот же приём, что .postfixButtonsSlot в shared/styles для FieldText), первый слот
|
|
139
|
+
// центрируется по первой строке текста.
|
|
140
|
+
.postfixColumn {
|
|
141
|
+
position: absolute;
|
|
142
|
+
|
|
143
|
+
display: grid;
|
|
144
|
+
|
|
145
|
+
// Единственный явный column-track шириной с контейнер: без него implicit-колонка
|
|
146
|
+
// растягивается (auto) под кнопку, и кнопка перестаёт центрироваться по слоту.
|
|
147
|
+
grid-template-columns: 100%;
|
|
148
|
+
row-gap: base.$sn-primitive-dimension-2;
|
|
149
|
+
place-items: center center;
|
|
150
|
+
|
|
151
|
+
@each $size in $sizes {
|
|
152
|
+
[data-size='#{$size}'] & {
|
|
153
|
+
$square: base.simple-var(
|
|
154
|
+
field.$field,
|
|
155
|
+
'anatomy',
|
|
156
|
+
'size',
|
|
157
|
+
$size,
|
|
158
|
+
'fieldContainer',
|
|
159
|
+
'centeredWrapper',
|
|
160
|
+
'max-height'
|
|
161
|
+
);
|
|
162
|
+
$input-line-padding: base.simple-var(
|
|
163
|
+
field.$field,
|
|
164
|
+
'anatomy',
|
|
165
|
+
'size',
|
|
166
|
+
$size,
|
|
167
|
+
'fieldContainer',
|
|
168
|
+
'contentWrapper',
|
|
169
|
+
'inputLine',
|
|
170
|
+
'padding-right'
|
|
171
|
+
);
|
|
172
|
+
$line-height: base.simple-var(base.$sn-regular, 'body', $size, 'line-height');
|
|
173
|
+
$vertical-padding: base.simple-var(
|
|
174
|
+
field.$field,
|
|
175
|
+
'anatomy',
|
|
176
|
+
'size',
|
|
177
|
+
$size,
|
|
178
|
+
'fieldContainer',
|
|
179
|
+
'contentWrapper',
|
|
180
|
+
'padding-top'
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// Кнопка центрируется по первой строке текста: verticalPadding (отступ контента сверху)
|
|
184
|
+
// + центровка слота в line-height. Так 32px-кнопка верхним краем садится ровно на
|
|
185
|
+
// внутреннюю границу поля (Figma), а не выступает над ней.
|
|
186
|
+
top: calc(#{$vertical-padding} + (#{$line-height} - #{$square}) / 2);
|
|
187
|
+
right: calc(#{$scrollbar-width} + #{$input-line-padding});
|
|
188
|
+
grid-auto-rows: $square;
|
|
189
|
+
width: $square;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|