@snack-uikit/fields 0.8.3-preview-85c5f47b.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.
Files changed (172) hide show
  1. package/CHANGELOG.md +655 -0
  2. package/LICENSE +201 -0
  3. package/README.md +329 -0
  4. package/dist/components/FieldDate/FieldDate.d.ts +29 -0
  5. package/dist/components/FieldDate/FieldDate.js +152 -0
  6. package/dist/components/FieldDate/constants.d.ts +10 -0
  7. package/dist/components/FieldDate/constants.js +28 -0
  8. package/dist/components/FieldDate/hooks/index.d.ts +1 -0
  9. package/dist/components/FieldDate/hooks/index.js +1 -0
  10. package/dist/components/FieldDate/hooks/useDateField.d.ts +20 -0
  11. package/dist/components/FieldDate/hooks/useDateField.js +180 -0
  12. package/dist/components/FieldDate/hooks/useDateFieldHelpers.d.ts +10 -0
  13. package/dist/components/FieldDate/hooks/useDateFieldHelpers.js +66 -0
  14. package/dist/components/FieldDate/hooks/useFocusHandlers.d.ts +15 -0
  15. package/dist/components/FieldDate/hooks/useFocusHandlers.js +33 -0
  16. package/dist/components/FieldDate/hooks/useHandlers.d.ts +6 -0
  17. package/dist/components/FieldDate/hooks/useHandlers.js +9 -0
  18. package/dist/components/FieldDate/index.d.ts +1 -0
  19. package/dist/components/FieldDate/index.js +1 -0
  20. package/dist/components/FieldDate/styles.module.css +44 -0
  21. package/dist/components/FieldDate/types.d.ts +6 -0
  22. package/dist/components/FieldDate/types.js +1 -0
  23. package/dist/components/FieldDate/utils.d.ts +5 -0
  24. package/dist/components/FieldDate/utils.js +39 -0
  25. package/dist/components/FieldDecorator/FieldDecorator.d.ts +20 -0
  26. package/dist/components/FieldDecorator/FieldDecorator.js +26 -0
  27. package/dist/components/FieldDecorator/Footer.d.ts +24 -0
  28. package/dist/components/FieldDecorator/Footer.js +39 -0
  29. package/dist/components/FieldDecorator/Header.d.ts +20 -0
  30. package/dist/components/FieldDecorator/Header.js +8 -0
  31. package/dist/components/FieldDecorator/index.d.ts +1 -0
  32. package/dist/components/FieldDecorator/index.js +1 -0
  33. package/dist/components/FieldDecorator/styles.module.css +177 -0
  34. package/dist/components/FieldSecure/FieldSecure.d.ts +29 -0
  35. package/dist/components/FieldSecure/FieldSecure.js +55 -0
  36. package/dist/components/FieldSecure/index.d.ts +1 -0
  37. package/dist/components/FieldSecure/index.js +1 -0
  38. package/dist/components/FieldSelect/FieldSelect.d.ts +16 -0
  39. package/dist/components/FieldSelect/FieldSelect.js +34 -0
  40. package/dist/components/FieldSelect/FieldSelectBase.d.ts +30 -0
  41. package/dist/components/FieldSelect/FieldSelectBase.js +51 -0
  42. package/dist/components/FieldSelect/FieldSelectMulti.d.ts +36 -0
  43. package/dist/components/FieldSelect/FieldSelectMulti.js +89 -0
  44. package/dist/components/FieldSelect/FieldSelectSingle.d.ts +35 -0
  45. package/dist/components/FieldSelect/FieldSelectSingle.js +76 -0
  46. package/dist/components/FieldSelect/constants.d.ts +3 -0
  47. package/dist/components/FieldSelect/constants.js +2 -0
  48. package/dist/components/FieldSelect/helpers/getArrowIcon.d.ts +8 -0
  49. package/dist/components/FieldSelect/helpers/getArrowIcon.js +5 -0
  50. package/dist/components/FieldSelect/helpers/getDisplayedValue.d.ts +9 -0
  51. package/dist/components/FieldSelect/helpers/getDisplayedValue.js +12 -0
  52. package/dist/components/FieldSelect/helpers/index.d.ts +2 -0
  53. package/dist/components/FieldSelect/helpers/index.js +2 -0
  54. package/dist/components/FieldSelect/hooks/index.d.ts +3 -0
  55. package/dist/components/FieldSelect/hooks/index.js +3 -0
  56. package/dist/components/FieldSelect/hooks/useFilteredOptions.d.ts +7 -0
  57. package/dist/components/FieldSelect/hooks/useFilteredOptions.js +6 -0
  58. package/dist/components/FieldSelect/hooks/useList.d.ts +36 -0
  59. package/dist/components/FieldSelect/hooks/useList.js +52 -0
  60. package/dist/components/FieldSelect/hooks/useListNavigation.d.ts +26 -0
  61. package/dist/components/FieldSelect/hooks/useListNavigation.js +48 -0
  62. package/dist/components/FieldSelect/index.d.ts +1 -0
  63. package/dist/components/FieldSelect/index.js +1 -0
  64. package/dist/components/FieldSelect/styles.module.css +74 -0
  65. package/dist/components/FieldSelect/types.d.ts +53 -0
  66. package/dist/components/FieldSelect/types.js +5 -0
  67. package/dist/components/FieldText/FieldText.d.ts +25 -0
  68. package/dist/components/FieldText/FieldText.js +52 -0
  69. package/dist/components/FieldText/index.d.ts +1 -0
  70. package/dist/components/FieldText/index.js +1 -0
  71. package/dist/components/FieldTextArea/FieldTextArea.d.ts +30 -0
  72. package/dist/components/FieldTextArea/FieldTextArea.js +54 -0
  73. package/dist/components/FieldTextArea/index.d.ts +1 -0
  74. package/dist/components/FieldTextArea/index.js +1 -0
  75. package/dist/components/FieldTextArea/styles.module.css +48 -0
  76. package/dist/components/index.d.ts +6 -0
  77. package/dist/components/index.js +6 -0
  78. package/dist/constants.d.ts +10 -0
  79. package/dist/constants.js +12 -0
  80. package/dist/helperComponents/ButtonCopyValue/ButtonCopyValue.d.ts +11 -0
  81. package/dist/helperComponents/ButtonCopyValue/ButtonCopyValue.js +24 -0
  82. package/dist/helperComponents/ButtonCopyValue/helpers.d.ts +7 -0
  83. package/dist/helperComponents/ButtonCopyValue/helpers.js +14 -0
  84. package/dist/helperComponents/ButtonCopyValue/index.d.ts +1 -0
  85. package/dist/helperComponents/ButtonCopyValue/index.js +1 -0
  86. package/dist/helperComponents/ButtonCopyValue/styles.module.css +47 -0
  87. package/dist/helperComponents/ButtonHideValue/ButtonHideValue.d.ts +12 -0
  88. package/dist/helperComponents/ButtonHideValue/ButtonHideValue.js +15 -0
  89. package/dist/helperComponents/ButtonHideValue/index.d.ts +1 -0
  90. package/dist/helperComponents/ButtonHideValue/index.js +1 -0
  91. package/dist/helperComponents/ButtonHideValue/styles.module.css +47 -0
  92. package/dist/helperComponents/FieldContainerPrivate/FieldContainerPrivate.d.ts +21 -0
  93. package/dist/helperComponents/FieldContainerPrivate/FieldContainerPrivate.js +27 -0
  94. package/dist/helperComponents/FieldContainerPrivate/index.d.ts +1 -0
  95. package/dist/helperComponents/FieldContainerPrivate/index.js +1 -0
  96. package/dist/helperComponents/FieldContainerPrivate/styles.module.css +197 -0
  97. package/dist/helperComponents/TextArea/TextArea.d.ts +32 -0
  98. package/dist/helperComponents/TextArea/TextArea.js +27 -0
  99. package/dist/helperComponents/TextArea/index.d.ts +1 -0
  100. package/dist/helperComponents/TextArea/index.js +1 -0
  101. package/dist/helperComponents/TextArea/styles.module.css +32 -0
  102. package/dist/helperComponents/index.d.ts +4 -0
  103. package/dist/helperComponents/index.js +4 -0
  104. package/dist/hooks/index.d.ts +2 -0
  105. package/dist/hooks/index.js +2 -0
  106. package/dist/hooks/useCopyButton.d.ts +10 -0
  107. package/dist/hooks/useCopyButton.js +12 -0
  108. package/dist/hooks/useHideButton.d.ts +12 -0
  109. package/dist/hooks/useHideButton.js +20 -0
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.js +1 -0
  112. package/dist/styles.module.css +0 -0
  113. package/package.json +53 -0
  114. package/src/components/FieldDate/FieldDate.tsx +339 -0
  115. package/src/components/FieldDate/constants.ts +33 -0
  116. package/src/components/FieldDate/hooks/index.ts +1 -0
  117. package/src/components/FieldDate/hooks/useDateField.ts +227 -0
  118. package/src/components/FieldDate/hooks/useDateFieldHelpers.ts +96 -0
  119. package/src/components/FieldDate/hooks/useFocusHandlers.ts +46 -0
  120. package/src/components/FieldDate/hooks/useHandlers.ts +15 -0
  121. package/src/components/FieldDate/index.ts +1 -0
  122. package/src/components/FieldDate/styles.module.scss +58 -0
  123. package/src/components/FieldDate/types.ts +6 -0
  124. package/src/components/FieldDate/utils.ts +44 -0
  125. package/src/components/FieldDecorator/FieldDecorator.tsx +69 -0
  126. package/src/components/FieldDecorator/Footer.tsx +105 -0
  127. package/src/components/FieldDecorator/Header.tsx +52 -0
  128. package/src/components/FieldDecorator/index.ts +1 -0
  129. package/src/components/FieldDecorator/styles.module.scss +176 -0
  130. package/src/components/FieldSecure/FieldSecure.tsx +170 -0
  131. package/src/components/FieldSecure/index.ts +1 -0
  132. package/src/components/FieldSelect/FieldSelect.tsx +41 -0
  133. package/src/components/FieldSelect/FieldSelectBase.tsx +221 -0
  134. package/src/components/FieldSelect/FieldSelectMulti.tsx +161 -0
  135. package/src/components/FieldSelect/FieldSelectSingle.tsx +131 -0
  136. package/src/components/FieldSelect/constants.ts +4 -0
  137. package/src/components/FieldSelect/helpers/getArrowIcon.ts +6 -0
  138. package/src/components/FieldSelect/helpers/getDisplayedValue.ts +24 -0
  139. package/src/components/FieldSelect/helpers/index.ts +2 -0
  140. package/src/components/FieldSelect/hooks/index.ts +3 -0
  141. package/src/components/FieldSelect/hooks/useFilteredOptions.ts +23 -0
  142. package/src/components/FieldSelect/hooks/useList.ts +85 -0
  143. package/src/components/FieldSelect/hooks/useListNavigation.ts +81 -0
  144. package/src/components/FieldSelect/index.ts +1 -0
  145. package/src/components/FieldSelect/styles.module.scss +87 -0
  146. package/src/components/FieldSelect/types.ts +78 -0
  147. package/src/components/FieldText/FieldText.tsx +154 -0
  148. package/src/components/FieldText/index.ts +1 -0
  149. package/src/components/FieldTextArea/FieldTextArea.tsx +171 -0
  150. package/src/components/FieldTextArea/index.ts +1 -0
  151. package/src/components/FieldTextArea/styles.module.scss +41 -0
  152. package/src/components/index.ts +6 -0
  153. package/src/constants.ts +11 -0
  154. package/src/helperComponents/ButtonCopyValue/ButtonCopyValue.tsx +55 -0
  155. package/src/helperComponents/ButtonCopyValue/helpers.tsx +19 -0
  156. package/src/helperComponents/ButtonCopyValue/index.ts +1 -0
  157. package/src/helperComponents/ButtonCopyValue/styles.module.scss +5 -0
  158. package/src/helperComponents/ButtonHideValue/ButtonHideValue.tsx +55 -0
  159. package/src/helperComponents/ButtonHideValue/index.ts +1 -0
  160. package/src/helperComponents/ButtonHideValue/styles.module.scss +5 -0
  161. package/src/helperComponents/FieldContainerPrivate/FieldContainerPrivate.tsx +78 -0
  162. package/src/helperComponents/FieldContainerPrivate/index.ts +1 -0
  163. package/src/helperComponents/FieldContainerPrivate/styles.module.scss +162 -0
  164. package/src/helperComponents/TextArea/TextArea.tsx +102 -0
  165. package/src/helperComponents/TextArea/index.ts +1 -0
  166. package/src/helperComponents/TextArea/styles.module.scss +35 -0
  167. package/src/helperComponents/index.ts +4 -0
  168. package/src/hooks/index.ts +2 -0
  169. package/src/hooks/useCopyButton.tsx +24 -0
  170. package/src/hooks/useHideButton.tsx +50 -0
  171. package/src/index.ts +1 -0
  172. package/src/styles.module.scss +55 -0
@@ -0,0 +1,171 @@
1
+ import mergeRefs from 'merge-refs';
2
+ import { ChangeEvent, forwardRef, useMemo, useRef } from 'react';
3
+ import { useUncontrolledProp } from 'uncontrollable';
4
+
5
+ import { Size, useButtonNavigation, useClearButton } from '@snack-uikit/input-private';
6
+ import { Scroll } from '@snack-uikit/scroll';
7
+ import { Tooltip } from '@snack-uikit/tooltip';
8
+ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
9
+
10
+ import { ContainerVariant, ValidationState } from '../../constants';
11
+ import { FieldContainerPrivate, TextArea, TextAreaProps } from '../../helperComponents';
12
+ import { useCopyButton } from '../../hooks';
13
+ import { FieldDecorator, FieldDecoratorProps } from '../FieldDecorator';
14
+ import styles from './styles.module.scss';
15
+
16
+ type InputProps = Pick<Partial<TextAreaProps>, 'value'> &
17
+ Pick<TextAreaProps, 'id' | 'name' | 'placeholder' | 'maxLength' | 'disabled' | 'readonly' | 'onFocus' | 'onBlur'>;
18
+
19
+ type WrapperProps = Pick<
20
+ FieldDecoratorProps,
21
+ | 'className'
22
+ | 'label'
23
+ | 'labelTooltip'
24
+ | 'required'
25
+ | 'hint'
26
+ | 'size'
27
+ | 'validationState'
28
+ | 'showHintIcon'
29
+ | 'labelTooltipPlacement'
30
+ >;
31
+
32
+ type FieldTextAreaOwnProps = {
33
+ /** Максимальное кол-во строк, до которого размер поля может быть увеличен */
34
+ maxRows?: number;
35
+ /** Может ли ли пользователь изменять размеры поля (если св-во не включено, поле автоматически меняет свой размер) */
36
+ resizable?: boolean;
37
+ /** Колбек смены значения */
38
+ onChange?(value: string, e?: ChangeEvent<HTMLTextAreaElement>): void;
39
+ /** Показывать ли кнопку Копировать для поля (актуально только для `readonly = true`) */
40
+ showCopyButton?: boolean;
41
+ /** Можно ли вводить больше разрешённого кол-ва символов */
42
+ allowMoreThanMaxLength?: boolean;
43
+ };
44
+
45
+ export type FieldTextAreaProps = WithSupportProps<FieldTextAreaOwnProps & InputProps & WrapperProps>;
46
+
47
+ const ForwardedFieldTextArea = forwardRef<HTMLTextAreaElement, FieldTextAreaProps>(
48
+ (
49
+ {
50
+ id,
51
+ name,
52
+ value: valueProp,
53
+ placeholder,
54
+ maxLength,
55
+ maxRows,
56
+ disabled = false,
57
+ resizable = false,
58
+ readonly = false,
59
+ showCopyButton: showCopyButtonProp = true,
60
+ allowMoreThanMaxLength = true,
61
+ showHintIcon,
62
+ onChange: onChangeProp,
63
+ onFocus,
64
+ onBlur,
65
+ className,
66
+ label,
67
+ labelTooltip,
68
+ labelTooltipPlacement,
69
+ required = false,
70
+ hint,
71
+ size = Size.S,
72
+ validationState = ValidationState.Default,
73
+ ...rest
74
+ },
75
+ ref,
76
+ ) => {
77
+ const localRef = useRef<HTMLTextAreaElement>(null);
78
+ const clearButtonRef = useRef<HTMLButtonElement>(null);
79
+ const copyButtonRef = useRef<HTMLButtonElement>(null);
80
+ const isResizable = !readonly && !disabled && resizable;
81
+ const [value, onChange] = useUncontrolledProp(valueProp, '', onChangeProp);
82
+ const showCopyButton = showCopyButtonProp && Boolean(value) && !disabled && readonly;
83
+ const showClearButton = Boolean(value) && !disabled && !readonly;
84
+
85
+ const onClear = () => {
86
+ onChange('');
87
+
88
+ if (required) {
89
+ localRef.current?.focus();
90
+ }
91
+ };
92
+
93
+ const clearButtonSettings = useClearButton({ clearButtonRef, showClearButton, size, onClear });
94
+ const copyButtonSettings = useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy: value });
95
+ const { buttons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
96
+ inputRef: localRef,
97
+ buttons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
98
+ readonly,
99
+ submitKeys: ['Enter', 'Space', 'Tab'],
100
+ });
101
+
102
+ return (
103
+ <FieldDecorator
104
+ className={className}
105
+ label={label}
106
+ labelTooltip={labelTooltip}
107
+ labelTooltipPlacement={labelTooltipPlacement}
108
+ labelFor={id}
109
+ required={required}
110
+ length={maxLength ? { max: maxLength, current: value.length } : undefined}
111
+ hint={hint}
112
+ disabled={disabled}
113
+ readonly={readonly}
114
+ showHintIcon={showHintIcon}
115
+ size={size}
116
+ validationState={validationState}
117
+ {...extractSupportProps(rest)}
118
+ >
119
+ <FieldContainerPrivate
120
+ className={styles.container}
121
+ size={size}
122
+ validationState={validationState}
123
+ disabled={disabled}
124
+ readonly={readonly}
125
+ data-resizable={isResizable || undefined}
126
+ variant={ContainerVariant.MultiLine}
127
+ style={{ '--max-rows': maxRows }}
128
+ inputRef={localRef}
129
+ postfix={<span className={styles.postfix}>{buttons}</span>}
130
+ >
131
+ <Scroll
132
+ className={styles.scrollContainer}
133
+ size={Scroll.sizes.S}
134
+ barHideStrategy={Scroll.barHideStrategies.Never}
135
+ resize={isResizable ? Scroll.resizes.Vertical : Scroll.resizes.None}
136
+ data-test-id='field-textarea__scroll-area'
137
+ >
138
+ <TextArea
139
+ className={styles.textarea}
140
+ data-size={size}
141
+ value={value}
142
+ onChange={onChange}
143
+ placeholder={placeholder}
144
+ disabled={disabled}
145
+ readonly={readonly}
146
+ id={id}
147
+ name={name}
148
+ ref={mergeRefs(ref, localRef)}
149
+ onFocus={onFocus}
150
+ onBlur={onBlur}
151
+ onKeyDown={onInputKeyDown}
152
+ tabIndex={inputTabIndex}
153
+ maxLength={allowMoreThanMaxLength ? undefined : maxLength || undefined}
154
+ data-test-id='field-textarea__input'
155
+ />
156
+ </Scroll>
157
+ </FieldContainerPrivate>
158
+ </FieldDecorator>
159
+ );
160
+ },
161
+ );
162
+
163
+ export const FieldTextArea = ForwardedFieldTextArea as typeof ForwardedFieldTextArea & {
164
+ sizes: typeof Size;
165
+ validationStates: typeof ValidationState;
166
+ labelTooltipPlacements: typeof Tooltip.placements;
167
+ };
168
+
169
+ FieldTextArea.sizes = Size;
170
+ FieldTextArea.validationStates = ValidationState;
171
+ FieldTextArea.labelTooltipPlacements = Tooltip.placements;
@@ -0,0 +1 @@
1
+ export * from './FieldTextArea';
@@ -0,0 +1,41 @@
1
+ @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields';
2
+
3
+ $sizes: 's', 'm', 'l';
4
+ $padding-right: (
5
+ 's': $fields-buttons-s,
6
+ 'm': $fields-buttons-m,
7
+ 'l': $fields-buttons-m,
8
+ );
9
+
10
+ .container {
11
+ --max-rows: 1000;
12
+ --min-rows: 3;
13
+ --horizontal-scroll-bar-height: 4px;
14
+
15
+ .scrollContainer {
16
+ min-height: calc(var(--min-rows) * var(--row-height) + var(--horizontal-scroll-bar-height));
17
+ max-height: calc(var(--max-rows) * var(--row-height) + var(--horizontal-scroll-bar-height));
18
+ }
19
+
20
+ &[data-resizable] .scrollContainer {
21
+ height: calc(var(--min-rows) * var(--row-height) + var(--horizontal-scroll-bar-height));
22
+ }
23
+
24
+ @each $size in $sizes {
25
+ &[data-size='#{$size}'] {
26
+ --row-height: #{simple-var($theme-variables, 'sans', 'body', $size, 'line-height')};
27
+
28
+ .textarea {
29
+ overflow: hidden;
30
+ padding-right: calc(simple-var($padding-right, $size, 'width') + simple-var($fields-scroll-bar-width, 'width'));
31
+ }
32
+
33
+ .postfix {
34
+ position: absolute;
35
+ top: simple-var($fields, 'multi-line-container', $size, 'padding-top');
36
+ right: calc(simple-var($fields, 'multi-line-container', $size, 'padding-right') + simple-var($fields-scroll-bar-width, 'width'));
37
+ }
38
+ }
39
+ }
40
+ }
41
+
@@ -0,0 +1,6 @@
1
+ export * from './FieldDecorator';
2
+ export * from './FieldText';
3
+ export * from './FieldTextArea';
4
+ export * from './FieldSecure';
5
+ export * from './FieldDate';
6
+ export * from './FieldSelect';
@@ -0,0 +1,11 @@
1
+ export enum ValidationState {
2
+ Default = 'default',
3
+ Error = 'error',
4
+ Warning = 'warning',
5
+ Success = 'success',
6
+ }
7
+
8
+ export enum ContainerVariant {
9
+ SingleLine = 'single-line-container',
10
+ MultiLine = 'multi-line-container',
11
+ }
@@ -0,0 +1,55 @@
1
+ import copyToClipboard from 'copy-to-clipboard';
2
+ import { forwardRef, KeyboardEventHandler, MouseEventHandler, useEffect, useRef, useState } from 'react';
3
+
4
+ import { ButtonSize } from '@snack-uikit/input-private';
5
+
6
+ import { getIcon } from './helpers';
7
+ import styles from './styles.module.scss';
8
+
9
+ type ButtonCopyValueProps = {
10
+ size: ButtonSize;
11
+ valueToCopy?: string;
12
+ onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
13
+ onClick?: MouseEventHandler<HTMLButtonElement>;
14
+ tabIndex?: number;
15
+ };
16
+ export const ButtonCopyValue = forwardRef<HTMLButtonElement, ButtonCopyValueProps>(
17
+ ({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick }, ref) => {
18
+ const [isChecked, setIsChecked] = useState(false);
19
+ const timerId = useRef<ReturnType<typeof setTimeout>>();
20
+ const openTooltip = () => setIsChecked(true);
21
+ const closeTooltip = () => setIsChecked(false);
22
+
23
+ const handleClick: MouseEventHandler<HTMLButtonElement> = event => {
24
+ event.stopPropagation();
25
+ valueToCopy && copyToClipboard(valueToCopy, { format: 'text/plain' });
26
+ openTooltip();
27
+ clearTimeout(timerId.current);
28
+ timerId.current = setTimeout(closeTooltip, 2000);
29
+ onClick?.(event);
30
+ };
31
+
32
+ useEffect(
33
+ () => () => {
34
+ closeTooltip();
35
+ clearTimeout(timerId.current);
36
+ },
37
+ [],
38
+ );
39
+
40
+ return (
41
+ <button
42
+ className={styles.buttonCopyValue}
43
+ data-size={size}
44
+ onClick={handleClick}
45
+ data-test-id='button-copy-value'
46
+ ref={ref}
47
+ onKeyDown={onKeyDown}
48
+ tabIndex={tabIndex}
49
+ type='button'
50
+ >
51
+ {getIcon({ size, isChecked })}
52
+ </button>
53
+ );
54
+ },
55
+ );
@@ -0,0 +1,19 @@
1
+ import { CheckSVG, CopySVG } from '@snack-uikit/icons';
2
+ import { ButtonSize } from '@snack-uikit/input-private';
3
+
4
+ type GetIconProps = {
5
+ size: ButtonSize;
6
+ isChecked: boolean;
7
+ };
8
+
9
+ export function getIcon({ size, isChecked }: GetIconProps) {
10
+ switch (size) {
11
+ case ButtonSize.S: {
12
+ return isChecked ? <CheckSVG size={16} /> : <CopySVG size={16} />;
13
+ }
14
+ case ButtonSize.M:
15
+ default: {
16
+ return isChecked ? <CheckSVG size={24} /> : <CopySVG size={24} />;
17
+ }
18
+ }
19
+ }
@@ -0,0 +1 @@
1
+ export * from './ButtonCopyValue';
@@ -0,0 +1,5 @@
1
+ @import "../../styles.module";
2
+
3
+ .buttonCopyValue {
4
+ @include button-styles();
5
+ }
@@ -0,0 +1,55 @@
1
+ import { forwardRef, KeyboardEventHandler, MouseEventHandler } from 'react';
2
+
3
+ import { EyeClosedSVG, EyeSVG } from '@snack-uikit/icons';
4
+ import { ButtonSize } from '@snack-uikit/input-private';
5
+
6
+ import styles from './styles.module.scss';
7
+
8
+ type ButtonHideValueProps = {
9
+ size: ButtonSize;
10
+ hidden?: boolean;
11
+ disabled?: boolean;
12
+ onClick: MouseEventHandler<HTMLButtonElement>;
13
+ onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
14
+ tabIndex?: number;
15
+ };
16
+
17
+ export const ButtonHideValue = forwardRef<HTMLButtonElement, ButtonHideValueProps>(
18
+ ({ size, onClick, hidden, disabled, tabIndex = -1, onKeyDown }, ref) => {
19
+ const handleClick: MouseEventHandler<HTMLButtonElement> = event => {
20
+ if (disabled) {
21
+ return;
22
+ }
23
+
24
+ event.stopPropagation();
25
+ onClick(event);
26
+ };
27
+
28
+ return (
29
+ <button
30
+ className={styles.buttonHideValue}
31
+ data-size={size}
32
+ data-disabled={disabled || undefined}
33
+ disabled={disabled}
34
+ onClick={handleClick}
35
+ data-test-id='button-hide-value'
36
+ ref={ref}
37
+ onKeyDown={onKeyDown}
38
+ type='button'
39
+ tabIndex={disabled ? -1 : tabIndex}
40
+ >
41
+ {hidden ? (
42
+ <>
43
+ {size === ButtonSize.S && <EyeClosedSVG size={16} />}
44
+ {size === ButtonSize.M && <EyeClosedSVG />}
45
+ </>
46
+ ) : (
47
+ <>
48
+ {size === ButtonSize.S && <EyeSVG size={16} />}
49
+ {size === ButtonSize.M && <EyeSVG />}
50
+ </>
51
+ )}
52
+ </button>
53
+ );
54
+ },
55
+ );
@@ -0,0 +1 @@
1
+ export * from './ButtonHideValue';
@@ -0,0 +1,5 @@
1
+ @import "../../styles.module";
2
+
3
+ .buttonHideValue {
4
+ @include button-styles();
5
+ }
@@ -0,0 +1,78 @@
1
+ import cn from 'classnames';
2
+ import { CSSProperties, MouseEventHandler, ReactElement, ReactNode, RefObject } from 'react';
3
+
4
+ import { Size } from '@snack-uikit/input-private';
5
+ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
6
+
7
+ import { ContainerVariant, ValidationState } from '../../constants';
8
+ import styles from './styles.module.scss';
9
+
10
+ export type FieldContainerPrivateProps = WithSupportProps<{
11
+ className?: string;
12
+ children: ReactNode;
13
+ size: Size;
14
+ validationState: ValidationState;
15
+ variant: ContainerVariant;
16
+ disabled: boolean;
17
+ readonly: boolean;
18
+ focused?: boolean;
19
+ selectable?: boolean;
20
+ style?: CSSProperties;
21
+ prefix?: ReactElement;
22
+ postfix?: ReactElement;
23
+ inputRef: RefObject<HTMLElement>;
24
+ onMouseDown?: MouseEventHandler<HTMLElement>;
25
+ }>;
26
+
27
+ export function FieldContainerPrivate({
28
+ className,
29
+ children,
30
+ size,
31
+ validationState,
32
+ variant,
33
+ disabled,
34
+ readonly,
35
+ focused,
36
+ selectable,
37
+ style,
38
+ prefix,
39
+ postfix,
40
+ inputRef,
41
+ onMouseDown,
42
+ ...rest
43
+ }: FieldContainerPrivateProps) {
44
+ const handleContainerClick: MouseEventHandler<HTMLDivElement> = () => {
45
+ if (disabled) {
46
+ return;
47
+ }
48
+ inputRef.current?.focus();
49
+ };
50
+
51
+ return (
52
+ <div
53
+ className={cn(className, styles.container)}
54
+ style={style}
55
+ data-size={size}
56
+ data-validation={disabled || readonly ? ValidationState.Default : validationState}
57
+ data-variant={variant}
58
+ data-disabled={disabled || undefined}
59
+ data-readonly={readonly || undefined}
60
+ data-focused={focused || undefined}
61
+ data-selectable={selectable || undefined}
62
+ data-test-id='field-container-private'
63
+ onClick={handleContainerClick}
64
+ onMouseDown={onMouseDown}
65
+ role='textbox'
66
+ tabIndex={-1}
67
+ {...extractSupportProps(rest)}
68
+ >
69
+ {prefix && (
70
+ <span className={styles.prefix} data-test-id='field-container-private__prefix-icon'>
71
+ {prefix}
72
+ </span>
73
+ )}
74
+ {children}
75
+ {postfix && <span className={styles.postfix}>{postfix}</span>}
76
+ </div>
77
+ );
78
+ }
@@ -0,0 +1 @@
1
+ export * from './FieldContainerPrivate';
@@ -0,0 +1,162 @@
1
+ @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields';
2
+ @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
3
+
4
+ /* stylelint-disable no-descending-specificity */
5
+
6
+ $sizes: 's', 'm', 'l';
7
+ $variants: 'single-line-container', 'multi-line-container';
8
+
9
+ .container {
10
+ position: relative;
11
+
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: space-between;
15
+
16
+ box-sizing: border-box;
17
+
18
+ border-style: solid;
19
+
20
+ @each $size in $sizes {
21
+ &[data-size='#{$size}'] {
22
+ @include composite-var($fields, 'container', $size);
23
+
24
+ &, input, select, textarea, span {
25
+ @include composite-var($theme-variables, 'sans', 'body', $size);
26
+
27
+ cursor: text;
28
+ }
29
+
30
+ @each $variant in $variants {
31
+ &[data-variant='#{$variant}'] {
32
+ @include composite-var($fields, $variant, $size);
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ &[data-validation="default"] {
39
+ background-color: simple-var($sys-neutral-background1-level);
40
+ border-color: simple-var($sys-neutral-decor-default);
41
+
42
+ &:hover {
43
+ background-color: simple-var($sys-neutral-background2-level);
44
+ border-color: simple-var($sys-primary-decor-hovered);
45
+ }
46
+
47
+ &:focus-within,
48
+ &[data-focused] {
49
+ @include outline-var($container-focused-m);
50
+
51
+ background-color: simple-var($sys-neutral-background2-level);
52
+ border-color: simple-var($sys-primary-accent-default);
53
+ outline-color: simple-var($sys-primary-decor-activated);
54
+ }
55
+ }
56
+
57
+ &[data-validation="error"] {
58
+ background-color: simple-var($sys-red-background1-level);
59
+ border-color: simple-var($sys-red-decor-default);
60
+
61
+ &:hover {
62
+ background-color: simple-var($sys-neutral-background2-level);
63
+ border-color: simple-var($sys-red-decor-hovered);
64
+ }
65
+
66
+ &:focus-within,
67
+ &[data-focused] {
68
+ @include outline-var($container-focused-m);
69
+
70
+ background-color: simple-var($sys-neutral-background2-level);
71
+ border-color: simple-var($sys-red-accent-default);
72
+ outline-color: simple-var($sys-red-decor-activated);
73
+ }
74
+ }
75
+
76
+ &[data-validation="warning"] {
77
+ background-color: simple-var($sys-yellow-background1-level);
78
+ border-color: simple-var($sys-yellow-decor-default);
79
+
80
+ &:hover {
81
+ background-color: simple-var($sys-neutral-background2-level);
82
+ border-color: simple-var($sys-yellow-decor-hovered);
83
+ }
84
+
85
+ &:focus-within,
86
+ &[data-focused] {
87
+ @include outline-var($container-focused-m);
88
+
89
+ background-color: simple-var($sys-neutral-background2-level);
90
+ border-color: simple-var($sys-yellow-accent-default);
91
+ outline-color: simple-var($sys-yellow-decor-activated);
92
+ }
93
+ }
94
+
95
+ &[data-validation="success"] {
96
+ background-color: simple-var($sys-green-background1-level);
97
+ border-color: simple-var($sys-green-decor-default);
98
+
99
+ &:hover {
100
+ background-color: simple-var($sys-neutral-background2-level);
101
+ border-color: simple-var($sys-green-decor-hovered);
102
+ }
103
+
104
+ &:focus-within,
105
+ &[data-focused] {
106
+ @include outline-var($container-focused-m);
107
+
108
+ background-color: simple-var($sys-neutral-background2-level);
109
+ border-color: simple-var($sys-green-accent-default);
110
+ outline-color: simple-var($sys-green-decor-activated);
111
+ }
112
+ }
113
+
114
+ &[data-selectable] {
115
+ &, input, select, textarea, span {
116
+ cursor: pointer;
117
+ }
118
+ }
119
+
120
+ &[data-readonly] {
121
+ &, input, select, textarea, span {
122
+ cursor: default;
123
+ }
124
+
125
+ &, &:hover {
126
+ background-color: simple-var($sys-neutral-decor-disabled);
127
+ border-color: simple-var($sys-neutral-decor-disabled);
128
+ }
129
+
130
+ &:focus-within, &[data-focused] {
131
+ @include outline-var($container-focused-m);
132
+
133
+ background-color: simple-var($sys-neutral-decor-disabled);
134
+ border-color: simple-var($sys-neutral-decor-disabled);
135
+ outline-color: simple-var($sys-primary-decor-activated);
136
+ }
137
+ }
138
+
139
+ &[data-disabled] {
140
+ &, input, select, textarea, span {
141
+ cursor: not-allowed;
142
+ }
143
+
144
+ &, &:focus-within, &[data-focused], &:hover {
145
+ background-color: simple-var($sys-neutral-background);
146
+ border-color: simple-var($sys-neutral-decor-disabled);
147
+ outline: none;
148
+ }
149
+ }
150
+ }
151
+
152
+ .prefix {
153
+ display: inline-flex;
154
+ flex-shrink: 0;
155
+ color: $sys-neutral-text-disabled;
156
+ }
157
+
158
+ .postfix {
159
+ display: inline-flex;
160
+ flex-shrink: 0;
161
+ gap: $space-fields-postfix-gap;
162
+ }