@snack-uikit/fields 0.13.4-preview-bd4095bc.0 → 0.14.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 +22 -0
- package/README.md +31 -0
- package/dist/components/FieldDate/styles.module.css +9 -9
- package/dist/components/FieldDecorator/styles.module.css +20 -20
- package/dist/components/FieldSelect/styles.module.css +17 -17
- package/dist/components/FieldSlider/FieldSlider.d.ts +21 -0
- package/dist/components/FieldSlider/FieldSlider.js +93 -0
- package/dist/components/FieldSlider/helpers/generateAllowedValues.d.ts +1 -0
- package/dist/components/FieldSlider/helpers/generateAllowedValues.js +9 -0
- package/dist/components/FieldSlider/helpers/getClosestMark.d.ts +4 -0
- package/dist/components/FieldSlider/helpers/getClosestMark.js +14 -0
- package/dist/components/FieldSlider/helpers/getTextFieldValue.d.ts +2 -0
- package/dist/components/FieldSlider/helpers/getTextFieldValue.js +6 -0
- package/dist/components/FieldSlider/helpers/index.d.ts +3 -0
- package/dist/components/FieldSlider/helpers/index.js +3 -0
- package/dist/components/FieldSlider/index.d.ts +1 -0
- package/dist/components/FieldSlider/index.js +1 -0
- package/dist/components/FieldSlider/styles.module.css +31 -0
- package/dist/components/FieldSlider/types.d.ts +1 -0
- package/dist/components/FieldSlider/types.js +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/helperComponents/ButtonCopyValue/styles.module.css +10 -10
- package/dist/helperComponents/ButtonHideValue/styles.module.css +10 -10
- package/dist/helperComponents/FieldContainerPrivate/styles.module.css +32 -32
- package/dist/helperComponents/TextArea/styles.module.css +6 -6
- package/package.json +4 -3
- package/src/components/FieldSlider/FieldSlider.tsx +215 -0
- package/src/components/FieldSlider/helpers/generateAllowedValues.ts +12 -0
- package/src/components/FieldSlider/helpers/getClosestMark.ts +20 -0
- package/src/components/FieldSlider/helpers/getTextFieldValue.ts +9 -0
- package/src/components/FieldSlider/helpers/index.ts +3 -0
- package/src/components/FieldSlider/index.ts +1 -0
- package/src/components/FieldSlider/styles.module.scss +29 -0
- package/src/components/FieldSlider/types.ts +1 -0
- package/src/components/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 0.14.0 (2024-02-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **FF-4218:** Field slider ([7a853bf](https://github.com/cloud-ru-tech/snack-uikit/commit/7a853bf8807ae595b2a8a635d754825305c07d6a))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## 0.13.4 (2024-02-12)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **FF-4205:** update locale usage ([bd4095b](https://github.com/cloud-ru-tech/snack-uikit/commit/bd4095bc875c2efc95a0549a366d5b40dd424741))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## 0.13.3 (2024-02-09)
|
|
7
29
|
|
|
8
30
|
### Only dependencies have been changed
|
package/README.md
CHANGED
|
@@ -360,6 +360,37 @@ const [isOpen, setIsOpen] = useState(false);
|
|
|
360
360
|
| showHintIcon | `boolean` | - | Отображать иконку подсказки |
|
|
361
361
|
| ref | `Ref<HTMLInputElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom |
|
|
362
362
|
| key | `Key` | - | |
|
|
363
|
+
## FieldSlider
|
|
364
|
+
### Props
|
|
365
|
+
| name | type | default value | description |
|
|
366
|
+
|------|------|---------------|-------------|
|
|
367
|
+
| postfixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-постфикс для поля |
|
|
368
|
+
| showScaleBar | `boolean` | true | Отображение линейки |
|
|
369
|
+
| textInputFormatter | `TextInputFormatter` | - | Функция для форматирования значений в текстовом поле |
|
|
370
|
+
| disabled | `boolean` | - | Является ли поле деактивированным |
|
|
371
|
+
| readonly | `boolean` | - | Является ли поле доступным только для чтения |
|
|
372
|
+
| id | `string` | - | Значение html-атрибута id |
|
|
373
|
+
| name | `string` | - | Значение html-атрибута name |
|
|
374
|
+
| onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
|
|
375
|
+
| onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
|
|
376
|
+
| value | `number \| number[]` | - | |
|
|
377
|
+
| onChange | `(value: number \| number[]) => void` | - | |
|
|
378
|
+
| range | `boolean` | - | |
|
|
379
|
+
| tipFormatter | `(value: string \| number) => ReactNode` | - | |
|
|
380
|
+
| step | `number` | - | |
|
|
381
|
+
| min | `number` | - | |
|
|
382
|
+
| max | `number` | - | |
|
|
383
|
+
| marks | `Record<string \| number, ReactNode \| MarkObj>` | - | |
|
|
384
|
+
| className | `string` | - | CSS-класс |
|
|
385
|
+
| label | `string` | - | Лейбл |
|
|
386
|
+
| labelTooltip | `string` | - | Всплывающая подсказка лейбла |
|
|
387
|
+
| required | `boolean` | - | Является ли поле обязательным |
|
|
388
|
+
| size | enum Size: `"s"`, `"m"`, `"l"` | SIZE.S | Размер |
|
|
389
|
+
| labelTooltipPlacement | enum Placement: `"left"`, `"left-start"`, `"left-end"`, `"right"`, `"right-start"`, `"right-end"`, `"top"`, `"top-start"`, `"top-end"`, `"bottom"`, `"bottom-start"`, `"bottom-end"` | top | Расположение подсказки лейбла |
|
|
390
|
+
| hint | `string` | - | Подсказка внизу |
|
|
391
|
+
| showHintIcon | `boolean` | - | Отображать иконку подсказки |
|
|
392
|
+
| ref | `Ref<HTMLInputElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom |
|
|
393
|
+
| key | `Key` | - | |
|
|
363
394
|
|
|
364
395
|
|
|
365
396
|
[//]: DOCUMENTATION_SECTION_END
|
|
@@ -22,23 +22,23 @@
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.container .calendarIcon{
|
|
25
|
-
color:var(--sys-neutral-text-light, #
|
|
25
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
26
26
|
}
|
|
27
27
|
.container .calendarIcon[data-size=s]{
|
|
28
|
-
width:var(--
|
|
29
|
-
height:var(--
|
|
28
|
+
width:var(--size-icon-container-xs, 16px) !important;
|
|
29
|
+
height:var(--size-icon-container-xs, 16px) !important;
|
|
30
30
|
}
|
|
31
31
|
.container .calendarIcon[data-size=m]{
|
|
32
|
-
width:var(--
|
|
33
|
-
height:var(--
|
|
32
|
+
width:var(--size-icon-container-s, 24px) !important;
|
|
33
|
+
height:var(--size-icon-container-s, 24px) !important;
|
|
34
34
|
}
|
|
35
35
|
.container .calendarIcon[data-size=l]{
|
|
36
|
-
width:var(--
|
|
37
|
-
height:var(--
|
|
36
|
+
width:var(--size-icon-container-s, 24px) !important;
|
|
37
|
+
height:var(--size-icon-container-s, 24px) !important;
|
|
38
38
|
}
|
|
39
39
|
.container:hover .calendarIcon, .container:focus-within .calendarIcon, .container[data-focused] .calendarIcon{
|
|
40
|
-
color:var(--sys-neutral-text-support, #
|
|
40
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
41
41
|
}
|
|
42
42
|
.container[data-disabled] .calendarIcon, .container[data-readonly] .calendarIcon{
|
|
43
|
-
color:var(--sys-neutral-text-disabled, #
|
|
43
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
44
44
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
.header{
|
|
19
19
|
display:flex;
|
|
20
20
|
box-sizing:border-box;
|
|
21
|
-
color:var(--sys-neutral-text-support, #
|
|
21
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
22
22
|
}
|
|
23
23
|
.header[data-size=s]{
|
|
24
24
|
font-family:var(--sans-label-m-font-family, SB Sans Interface);
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
.labelLayout{
|
|
49
|
-
gap:var(--
|
|
49
|
+
gap:var(--space-fields-label-gap, 2px);
|
|
50
50
|
display:inline-flex;
|
|
51
51
|
align-items:center;
|
|
52
52
|
}
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
.hintLayout{
|
|
92
|
-
gap:var(--
|
|
92
|
+
gap:var(--space-fields-hint-gap, 2px);
|
|
93
93
|
display:inline-flex;
|
|
94
94
|
align-items:flex-start;
|
|
95
95
|
}
|
|
@@ -118,22 +118,22 @@
|
|
|
118
118
|
flex-grow:1;
|
|
119
119
|
}
|
|
120
120
|
.hint[data-validation=default]{
|
|
121
|
-
color:var(--sys-neutral-text-light, #
|
|
121
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
122
122
|
}
|
|
123
123
|
.hint[data-validation=error]{
|
|
124
|
-
color:var(--sys-red-text-main, #
|
|
124
|
+
color:var(--sys-red-text-main, #621c1b);
|
|
125
125
|
}
|
|
126
126
|
.hint[data-validation=warning]{
|
|
127
|
-
color:var(--sys-yellow-text-main, #
|
|
127
|
+
color:var(--sys-yellow-text-main, #5e3d06);
|
|
128
128
|
}
|
|
129
129
|
.hint[data-validation=success]{
|
|
130
|
-
color:var(--sys-green-text-main, #
|
|
130
|
+
color:var(--sys-green-text-main, #323f27);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
.icon{
|
|
134
134
|
flex-shrink:0;
|
|
135
135
|
box-sizing:content-box;
|
|
136
|
-
color:var(--sys-neutral-text-light, #
|
|
136
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
.hintIcon{
|
|
@@ -141,40 +141,40 @@
|
|
|
141
141
|
box-sizing:content-box;
|
|
142
142
|
}
|
|
143
143
|
.hintIcon[data-validation=default]{
|
|
144
|
-
color:var(--sys-neutral-text-light, #
|
|
144
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
145
145
|
}
|
|
146
146
|
.hintIcon[data-validation=error]{
|
|
147
|
-
color:var(--sys-red-accent-default, #
|
|
147
|
+
color:var(--sys-red-accent-default, #cd3c3c);
|
|
148
148
|
}
|
|
149
149
|
.hintIcon[data-validation=warning]{
|
|
150
|
-
color:var(--sys-yellow-accent-default, #
|
|
150
|
+
color:var(--sys-yellow-accent-default, #fdca46);
|
|
151
151
|
}
|
|
152
152
|
.hintIcon[data-validation=success]{
|
|
153
|
-
color:var(--sys-green-accent-default, #
|
|
153
|
+
color:var(--sys-green-accent-default, #57b762);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
.counterLimit > span[data-validation=default]{
|
|
157
|
-
color:var(--sys-neutral-text-light, #
|
|
157
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
158
158
|
}
|
|
159
159
|
.counterLimit > span[data-limit-exceeded], .counterLimit > span[data-validation=error]{
|
|
160
|
-
color:var(--sys-red-text-light, #
|
|
160
|
+
color:var(--sys-red-text-light, #ea6658);
|
|
161
161
|
}
|
|
162
162
|
.counterLimit > span[data-validation=warning]{
|
|
163
|
-
color:var(--sys-yellow-text-light, #
|
|
163
|
+
color:var(--sys-yellow-text-light, #ddb035);
|
|
164
164
|
}
|
|
165
165
|
.counterLimit > span[data-validation=success]{
|
|
166
|
-
color:var(--sys-green-text-light, #
|
|
166
|
+
color:var(--sys-green-text-light, #67ba6e);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
.counterCurrentValue[data-limit-exceeded][data-validation=default]{
|
|
170
|
-
color:var(--sys-neutral-text-main, #
|
|
170
|
+
color:var(--sys-neutral-text-main, #33333b);
|
|
171
171
|
}
|
|
172
172
|
.counterCurrentValue[data-limit-exceeded][data-validation=error]{
|
|
173
|
-
color:var(--sys-red-text-main, #
|
|
173
|
+
color:var(--sys-red-text-main, #621c1b);
|
|
174
174
|
}
|
|
175
175
|
.counterCurrentValue[data-limit-exceeded][data-validation=warning]{
|
|
176
|
-
color:var(--sys-yellow-text-main, #
|
|
176
|
+
color:var(--sys-yellow-text-main, #5e3d06);
|
|
177
177
|
}
|
|
178
178
|
.counterCurrentValue[data-limit-exceeded][data-validation=success]{
|
|
179
|
-
color:var(--sys-green-text-light, #
|
|
179
|
+
color:var(--sys-green-text-light, #67ba6e);
|
|
180
180
|
}
|
|
@@ -34,41 +34,41 @@
|
|
|
34
34
|
flex:1 1 0;
|
|
35
35
|
}
|
|
36
36
|
.container[data-size=s] .arrowIcon{
|
|
37
|
-
width:var(--
|
|
38
|
-
height:var(--
|
|
39
|
-
color:var(--sys-neutral-text-light, #
|
|
37
|
+
width:var(--size-icon-container-xs, 16px) !important;
|
|
38
|
+
height:var(--size-icon-container-xs, 16px) !important;
|
|
39
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
40
40
|
}
|
|
41
41
|
.container[data-size=s][data-variant=single-line-container] .displayValue{
|
|
42
|
-
width:calc(100% - (var(--space-fields-single-line-container-s-right, 6px) + var(--space-fields-single-line-container-s-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--
|
|
43
|
-
margin-right:calc(var(--space-fields-single-line-container-s-right, 6px) + var(--space-fields-single-line-container-s-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--
|
|
42
|
+
width:calc(100% - (var(--space-fields-single-line-container-s-right, 6px) + var(--space-fields-single-line-container-s-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--size-icon-container-xs, 16px) * 2)));
|
|
43
|
+
margin-right:calc(var(--space-fields-single-line-container-s-right, 6px) + var(--space-fields-single-line-container-s-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--size-icon-container-xs, 16px) * 2));
|
|
44
44
|
padding-left:var(--space-fields-single-line-container-s-left, 6px);
|
|
45
45
|
border-radius:var(--radius-fields-s, 12px);
|
|
46
46
|
}
|
|
47
47
|
.container[data-size=m] .arrowIcon{
|
|
48
|
-
width:var(--
|
|
49
|
-
height:var(--
|
|
50
|
-
color:var(--sys-neutral-text-light, #
|
|
48
|
+
width:var(--size-icon-container-s, 24px) !important;
|
|
49
|
+
height:var(--size-icon-container-s, 24px) !important;
|
|
50
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
51
51
|
}
|
|
52
52
|
.container[data-size=m][data-variant=single-line-container] .displayValue{
|
|
53
|
-
width:calc(100% - (var(--space-fields-single-line-container-m-right, 8px) + var(--space-fields-single-line-container-m-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--
|
|
54
|
-
margin-right:calc(var(--space-fields-single-line-container-m-right, 8px) + var(--space-fields-single-line-container-m-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--
|
|
53
|
+
width:calc(100% - (var(--space-fields-single-line-container-m-right, 8px) + var(--space-fields-single-line-container-m-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--size-icon-container-s, 24px) * 2)));
|
|
54
|
+
margin-right:calc(var(--space-fields-single-line-container-m-right, 8px) + var(--space-fields-single-line-container-m-gap, 4px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--size-icon-container-s, 24px) * 2));
|
|
55
55
|
padding-left:var(--space-fields-single-line-container-m-left, 8px);
|
|
56
56
|
border-radius:var(--radius-fields-m, 14px);
|
|
57
57
|
}
|
|
58
58
|
.container[data-size=l] .arrowIcon{
|
|
59
|
-
width:var(--
|
|
60
|
-
height:var(--
|
|
61
|
-
color:var(--sys-neutral-text-light, #
|
|
59
|
+
width:var(--size-icon-container-s, 24px) !important;
|
|
60
|
+
height:var(--size-icon-container-s, 24px) !important;
|
|
61
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
62
62
|
}
|
|
63
63
|
.container[data-size=l][data-variant=single-line-container] .displayValue{
|
|
64
|
-
width:calc(100% - (var(--space-fields-single-line-container-l-right, 10px) + var(--space-fields-single-line-container-l-gap, 8px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--
|
|
65
|
-
margin-right:calc(var(--space-fields-single-line-container-l-right, 10px) + var(--space-fields-single-line-container-l-gap, 8px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--
|
|
64
|
+
width:calc(100% - (var(--space-fields-single-line-container-l-right, 10px) + var(--space-fields-single-line-container-l-gap, 8px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--size-icon-container-s, 24px) * 2)));
|
|
65
|
+
margin-right:calc(var(--space-fields-single-line-container-l-right, 10px) + var(--space-fields-single-line-container-l-gap, 8px) + calc(var(var(--space-fields-postfix-gap, 4px)) + var(--size-icon-container-s, 24px) * 2));
|
|
66
66
|
padding-left:var(--space-fields-single-line-container-l-left, 10px);
|
|
67
67
|
border-radius:var(--radius-fields-l, 16px);
|
|
68
68
|
}
|
|
69
69
|
.container:hover .arrowIcon, .container:focus-within .arrowIcon, .container[data-focused] .arrowIcon{
|
|
70
|
-
color:var(--sys-neutral-text-support, #
|
|
70
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
71
71
|
}
|
|
72
72
|
.container[data-disabled] .arrowIcon, .container[data-readonly] .arrowIcon{
|
|
73
|
-
color:var(--sys-neutral-text-disabled, #
|
|
73
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
74
74
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { InputPrivateProps } from '@snack-uikit/input-private';
|
|
3
|
+
import { SliderProps as SliderComponentProps } from '@snack-uikit/slider';
|
|
4
|
+
import { WithSupportProps } from '@snack-uikit/utils';
|
|
5
|
+
import { FieldDecoratorProps } from '../FieldDecorator';
|
|
6
|
+
import { TextInputFormatter } from './types';
|
|
7
|
+
type SliderProps = Pick<InputPrivateProps, 'id' | 'name' | 'disabled' | 'readonly' | 'onFocus' | 'onBlur'> & Pick<SliderComponentProps, 'range' | 'value' | 'onChange' | 'tipFormatter'> & Required<Pick<SliderComponentProps, 'min' | 'max' | 'step' | 'marks'>>;
|
|
8
|
+
type WrapperProps = Pick<FieldDecoratorProps, 'className' | 'label' | 'labelTooltip' | 'required' | 'hint' | 'showHintIcon' | 'size' | 'labelTooltipPlacement'>;
|
|
9
|
+
type FieldSliderOwnProps = {
|
|
10
|
+
/** Иконка-постфикс для поля */
|
|
11
|
+
postfixIcon?: ReactElement;
|
|
12
|
+
/** Отображение линейки */
|
|
13
|
+
showScaleBar?: boolean;
|
|
14
|
+
/** Функция для форматирования значений в текстовом поле */
|
|
15
|
+
textInputFormatter?: TextInputFormatter;
|
|
16
|
+
};
|
|
17
|
+
export type FieldSliderProps = WithSupportProps<FieldSliderOwnProps & SliderProps & WrapperProps>;
|
|
18
|
+
export declare const FieldSlider: import("react").ForwardRefExoticComponent<{
|
|
19
|
+
'data-test-id'?: string | undefined;
|
|
20
|
+
} & import("react").AriaAttributes & FieldSliderOwnProps & Pick<InputPrivateProps, "disabled" | "readonly" | "name" | "id" | "onFocus" | "onBlur"> & Pick<SliderComponentProps, "value" | "onChange" | "range" | "tipFormatter"> & Required<Pick<SliderComponentProps, "max" | "step" | "min" | "marks">> & WrapperProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import mergeRefs from 'merge-refs';
|
|
14
|
+
import { forwardRef, useEffect, useRef, useState } from 'react';
|
|
15
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
16
|
+
import { InputPrivate, SIZE } from '@snack-uikit/input-private';
|
|
17
|
+
import { Slider } from '@snack-uikit/slider';
|
|
18
|
+
import { extractSupportProps } from '@snack-uikit/utils';
|
|
19
|
+
import { CONTAINER_VARIANT, VALIDATION_STATE } from '../../constants';
|
|
20
|
+
import { FieldContainerPrivate } from '../../helperComponents';
|
|
21
|
+
import { FieldDecorator } from '../FieldDecorator';
|
|
22
|
+
import { generateAllowedValues, getClosestMark, getTextFieldValue } from './helpers';
|
|
23
|
+
import styles from './styles.module.css';
|
|
24
|
+
const getDefaultValue = (range, min, max, value) => {
|
|
25
|
+
if (range) {
|
|
26
|
+
if (value) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
return [min, max];
|
|
30
|
+
}
|
|
31
|
+
return value !== null && value !== void 0 ? value : min;
|
|
32
|
+
};
|
|
33
|
+
export const FieldSlider = forwardRef((_a, ref) => {
|
|
34
|
+
var { id, name, min, max, step, marks, showScaleBar = true, value: valueProp, range = false, disabled = false, readonly = false, onChange: onChangeProp, onFocus, onBlur, className, label, labelTooltip, labelTooltipPlacement, required, hint, showHintIcon, size = SIZE.S, postfixIcon, textInputFormatter } = _a, rest = __rest(_a, ["id", "name", "min", "max", "step", "marks", "showScaleBar", "value", "range", "disabled", "readonly", "onChange", "onFocus", "onBlur", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "hint", "showHintIcon", "size", "postfixIcon", "textInputFormatter"]);
|
|
35
|
+
const [value, onChange] = useUncontrolledProp(valueProp, getDefaultValue(range, min, max, valueProp), onChangeProp);
|
|
36
|
+
const [textFieldInputValue, setTextFieldInputValue] = useState(getTextFieldValue(value, textInputFormatter));
|
|
37
|
+
const localRef = useRef(null);
|
|
38
|
+
const onTextFieldChange = (textFieldValue) => {
|
|
39
|
+
const numValue = Number(textFieldValue);
|
|
40
|
+
if (Number.isNaN(numValue)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setTextFieldInputValue(textFieldValue);
|
|
44
|
+
};
|
|
45
|
+
const handleTextValueChange = () => {
|
|
46
|
+
const textFieldNumValue = Number(textFieldInputValue);
|
|
47
|
+
if (Number.isNaN(textFieldNumValue)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (textFieldNumValue < min) {
|
|
51
|
+
setTextFieldInputValue(String(min));
|
|
52
|
+
onChange(min);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (textFieldNumValue > max) {
|
|
56
|
+
setTextFieldInputValue(String(max));
|
|
57
|
+
onChange(max);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (step === null) {
|
|
61
|
+
const allowedValues = Object.keys(marks).map(Number);
|
|
62
|
+
if (allowedValues.includes(textFieldNumValue)) {
|
|
63
|
+
onChange(textFieldNumValue);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const { mark } = getClosestMark(textFieldNumValue, allowedValues);
|
|
67
|
+
setTextFieldInputValue(String(mark));
|
|
68
|
+
onChange(mark);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const allowedValues = generateAllowedValues(min, max, step);
|
|
72
|
+
if (allowedValues.includes(textFieldNumValue)) {
|
|
73
|
+
onChange(textFieldNumValue);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const { mark } = getClosestMark(textFieldNumValue, allowedValues);
|
|
77
|
+
setTextFieldInputValue(String(mark));
|
|
78
|
+
onChange(mark);
|
|
79
|
+
};
|
|
80
|
+
const onTextFieldBlur = (e) => {
|
|
81
|
+
onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
|
|
82
|
+
handleTextValueChange();
|
|
83
|
+
};
|
|
84
|
+
const handleTextFieldKeyChange = (e) => {
|
|
85
|
+
if (e.key === 'Enter') {
|
|
86
|
+
handleTextValueChange();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
setTextFieldInputValue(getTextFieldValue(value, textInputFormatter));
|
|
91
|
+
}, [value, textInputFormatter]);
|
|
92
|
+
return (_jsxs(FieldDecorator, Object.assign({ className: className, label: label, labelTooltip: labelTooltip, labelTooltipPlacement: labelTooltipPlacement, labelFor: id, disabled: disabled, required: required, hint: hint, showHintIcon: showHintIcon, readonly: readonly, size: size }, extractSupportProps(rest), { children: [_jsx(FieldContainerPrivate, { className: styles.fieldContainer, size: size, validationState: VALIDATION_STATE.Default, disabled: disabled, readonly: readonly, variant: CONTAINER_VARIANT.SingleLine, inputRef: localRef, postfix: postfixIcon, children: _jsx(InputPrivate, { ref: mergeRefs(ref, localRef), "data-size": size, value: textFieldInputValue, onChange: range ? undefined : onTextFieldChange, onFocus: onFocus, onBlur: range ? onBlur : onTextFieldBlur, onKeyDown: handleTextFieldKeyChange, disabled: disabled, readonly: range ? true : readonly, type: 'text', id: id, name: name, "data-test-id": 'field-slider__input' }) }), _jsx("div", { className: styles.sliderWrapper, children: _jsx("div", { className: styles.slider, "data-size": size, children: _jsx(Slider, { range: range, min: min, max: max, step: step, value: value, onChange: onChange, marks: showScaleBar ? marks : undefined, disabled: readonly || disabled, "data-test-id": 'field-slider__slider' }) }) })] })));
|
|
93
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const generateAllowedValues: (min: number, max: number, step: number) => number[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const getDiff = (value, mark) => Math.abs(mark - value);
|
|
2
|
+
export const getClosestMark = (value, marks) => marks.reduce((accResult, mark) => {
|
|
3
|
+
const diff = getDiff(value, mark);
|
|
4
|
+
if (diff < accResult.lowestDiff) {
|
|
5
|
+
return {
|
|
6
|
+
lowestDiff: diff,
|
|
7
|
+
mark,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return accResult;
|
|
11
|
+
}, {
|
|
12
|
+
lowestDiff: getDiff(value, marks[0]),
|
|
13
|
+
mark: marks[0],
|
|
14
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const getTextFieldValue = (value, textInputFormatter) => {
|
|
2
|
+
if (!textInputFormatter) {
|
|
3
|
+
return typeof value === 'number' ? String(value) : value.join(' – ');
|
|
4
|
+
}
|
|
5
|
+
return typeof value === 'number' ? textInputFormatter(value) : value.map(textInputFormatter).join(' – ');
|
|
6
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FieldSlider';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FieldSlider';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
.sliderWrapper{
|
|
2
|
+
display:flex;
|
|
3
|
+
justify-content:center;
|
|
4
|
+
width:100%;
|
|
5
|
+
margin-top:-13px;
|
|
6
|
+
}
|
|
7
|
+
.sliderWrapper .slider{
|
|
8
|
+
flex:1;
|
|
9
|
+
}
|
|
10
|
+
.sliderWrapper .slider[data-size=s]{
|
|
11
|
+
height:var(--size-slider-track-line, 2px);
|
|
12
|
+
padding-left:var(--space-fields-slider-padding-s, 8px);
|
|
13
|
+
padding-right:var(--space-fields-slider-padding-s, 8px);
|
|
14
|
+
height:inherit;
|
|
15
|
+
}
|
|
16
|
+
.sliderWrapper .slider[data-size=m]{
|
|
17
|
+
height:var(--size-slider-track-line, 2px);
|
|
18
|
+
padding-left:var(--space-fields-slider-padding-m, 10px);
|
|
19
|
+
padding-right:var(--space-fields-slider-padding-m, 10px);
|
|
20
|
+
height:inherit;
|
|
21
|
+
}
|
|
22
|
+
.sliderWrapper .slider[data-size=l]{
|
|
23
|
+
height:var(--size-slider-track-line, 2px);
|
|
24
|
+
padding-left:var(--space-fields-slider-padding-l, 12px);
|
|
25
|
+
padding-right:var(--space-fields-slider-padding-l, 12px);
|
|
26
|
+
height:inherit;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.fieldContainer svg{
|
|
30
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type TextInputFormatter = (value: number) => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/components/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
justify-content:center;
|
|
5
5
|
margin:0;
|
|
6
6
|
padding:0;
|
|
7
|
-
color:var(--sys-neutral-text-light, #
|
|
7
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
8
8
|
background-color:transparent;
|
|
9
9
|
border:none;
|
|
10
10
|
}
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
border-radius:var(--radius-fields-buttons-s, 8px);
|
|
15
15
|
}
|
|
16
16
|
.buttonCopyValue[data-size=s] svg{
|
|
17
|
-
width:var(--
|
|
18
|
-
height:var(--
|
|
17
|
+
width:var(--size-icon-container-xs, 16px) !important;
|
|
18
|
+
height:var(--size-icon-container-xs, 16px) !important;
|
|
19
19
|
}
|
|
20
20
|
.buttonCopyValue[data-size=m]{
|
|
21
21
|
width:var(--size-fields-buttons-m, 24px);
|
|
@@ -23,25 +23,25 @@
|
|
|
23
23
|
border-radius:var(--radius-fields-buttons-m, 12px);
|
|
24
24
|
}
|
|
25
25
|
.buttonCopyValue[data-size=m] svg{
|
|
26
|
-
width:var(--
|
|
27
|
-
height:var(--
|
|
26
|
+
width:var(--size-icon-container-s, 24px) !important;
|
|
27
|
+
height:var(--size-icon-container-s, 24px) !important;
|
|
28
28
|
}
|
|
29
29
|
.buttonCopyValue:hover{
|
|
30
30
|
cursor:pointer;
|
|
31
|
-
color:var(--sys-neutral-text-support, #
|
|
31
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
32
32
|
}
|
|
33
33
|
.buttonCopyValue:focus-visible{
|
|
34
34
|
outline-width:var(--border-state-focus-s-border-width, 2px);
|
|
35
35
|
outline-style:var(--border-state-focus-s-border-style, solid);
|
|
36
36
|
outline-color:var(--border-state-focus-s-border-color, );
|
|
37
|
-
color:var(--sys-neutral-text-support, #
|
|
38
|
-
outline-color:var(--sys-available-complementary, #
|
|
37
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
38
|
+
outline-color:var(--sys-available-complementary, #141415);
|
|
39
39
|
outline-offset:var(--spacing-state-focus-offset, 2px);
|
|
40
40
|
}
|
|
41
41
|
.buttonCopyValue:active{
|
|
42
|
-
color:var(--sys-neutral-text-main, #
|
|
42
|
+
color:var(--sys-neutral-text-main, #33333b);
|
|
43
43
|
}
|
|
44
44
|
.buttonCopyValue[data-disabled]{
|
|
45
45
|
cursor:not-allowed;
|
|
46
|
-
color:var(--sys-neutral-text-disabled, #
|
|
46
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
47
47
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
justify-content:center;
|
|
5
5
|
margin:0;
|
|
6
6
|
padding:0;
|
|
7
|
-
color:var(--sys-neutral-text-light, #
|
|
7
|
+
color:var(--sys-neutral-text-light, #868892);
|
|
8
8
|
background-color:transparent;
|
|
9
9
|
border:none;
|
|
10
10
|
}
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
border-radius:var(--radius-fields-buttons-s, 8px);
|
|
15
15
|
}
|
|
16
16
|
.buttonHideValue[data-size=s] svg{
|
|
17
|
-
width:var(--
|
|
18
|
-
height:var(--
|
|
17
|
+
width:var(--size-icon-container-xs, 16px) !important;
|
|
18
|
+
height:var(--size-icon-container-xs, 16px) !important;
|
|
19
19
|
}
|
|
20
20
|
.buttonHideValue[data-size=m]{
|
|
21
21
|
width:var(--size-fields-buttons-m, 24px);
|
|
@@ -23,25 +23,25 @@
|
|
|
23
23
|
border-radius:var(--radius-fields-buttons-m, 12px);
|
|
24
24
|
}
|
|
25
25
|
.buttonHideValue[data-size=m] svg{
|
|
26
|
-
width:var(--
|
|
27
|
-
height:var(--
|
|
26
|
+
width:var(--size-icon-container-s, 24px) !important;
|
|
27
|
+
height:var(--size-icon-container-s, 24px) !important;
|
|
28
28
|
}
|
|
29
29
|
.buttonHideValue:hover{
|
|
30
30
|
cursor:pointer;
|
|
31
|
-
color:var(--sys-neutral-text-support, #
|
|
31
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
32
32
|
}
|
|
33
33
|
.buttonHideValue:focus-visible{
|
|
34
34
|
outline-width:var(--border-state-focus-s-border-width, 2px);
|
|
35
35
|
outline-style:var(--border-state-focus-s-border-style, solid);
|
|
36
36
|
outline-color:var(--border-state-focus-s-border-color, );
|
|
37
|
-
color:var(--sys-neutral-text-support, #
|
|
38
|
-
outline-color:var(--sys-available-complementary, #
|
|
37
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
38
|
+
outline-color:var(--sys-available-complementary, #141415);
|
|
39
39
|
outline-offset:var(--spacing-state-focus-offset, 2px);
|
|
40
40
|
}
|
|
41
41
|
.buttonHideValue:active{
|
|
42
|
-
color:var(--sys-neutral-text-main, #
|
|
42
|
+
color:var(--sys-neutral-text-main, #33333b);
|
|
43
43
|
}
|
|
44
44
|
.buttonHideValue[data-disabled]{
|
|
45
45
|
cursor:not-allowed;
|
|
46
|
-
color:var(--sys-neutral-text-disabled, #
|
|
46
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
47
47
|
}
|
|
@@ -94,68 +94,68 @@
|
|
|
94
94
|
padding-right:var(--space-fields-multi-line-container-l-right, 2px);
|
|
95
95
|
}
|
|
96
96
|
.container[data-validation=default]{
|
|
97
|
-
background-color:var(--sys-neutral-background1-level, #
|
|
98
|
-
border-color:var(--sys-neutral-decor-default, #
|
|
97
|
+
background-color:var(--sys-neutral-background1-level, #fafafc);
|
|
98
|
+
border-color:var(--sys-neutral-decor-default, #dfe2ec);
|
|
99
99
|
}
|
|
100
100
|
.container[data-validation=default]:hover{
|
|
101
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
101
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
102
102
|
border-color:var(--sys-primary-decor-hovered, #decdfb);
|
|
103
103
|
}
|
|
104
104
|
.container[data-validation=default]:focus-within, .container[data-validation=default][data-focused]{
|
|
105
105
|
outline-width:var(--border-state-focus-m-border-width, 3px);
|
|
106
106
|
outline-style:var(--border-state-focus-m-border-style, solid);
|
|
107
107
|
outline-color:var(--border-state-focus-m-border-color, );
|
|
108
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
108
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
109
109
|
border-color:var(--sys-primary-accent-default, #794ed3);
|
|
110
110
|
outline-color:var(--sys-primary-decor-activated, #c5b2f1);
|
|
111
111
|
}
|
|
112
112
|
.container[data-validation=error]{
|
|
113
|
-
background-color:var(--sys-red-background1-level, #
|
|
114
|
-
border-color:var(--sys-red-decor-default, #
|
|
113
|
+
background-color:var(--sys-red-background1-level, #fcf6f5);
|
|
114
|
+
border-color:var(--sys-red-decor-default, #fdd6cd);
|
|
115
115
|
}
|
|
116
116
|
.container[data-validation=error]:hover{
|
|
117
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
118
|
-
border-color:var(--sys-red-decor-hovered, #
|
|
117
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
118
|
+
border-color:var(--sys-red-decor-hovered, #fac1b3);
|
|
119
119
|
}
|
|
120
120
|
.container[data-validation=error]:focus-within, .container[data-validation=error][data-focused]{
|
|
121
121
|
outline-width:var(--border-state-focus-m-border-width, 3px);
|
|
122
122
|
outline-style:var(--border-state-focus-m-border-style, solid);
|
|
123
123
|
outline-color:var(--border-state-focus-m-border-color, );
|
|
124
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
125
|
-
border-color:var(--sys-red-accent-default, #
|
|
126
|
-
outline-color:var(--sys-red-decor-activated, #
|
|
124
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
125
|
+
border-color:var(--sys-red-accent-default, #cd3c3c);
|
|
126
|
+
outline-color:var(--sys-red-decor-activated, #fbab99);
|
|
127
127
|
}
|
|
128
128
|
.container[data-validation=warning]{
|
|
129
|
-
background-color:var(--sys-yellow-background1-level, #
|
|
130
|
-
border-color:var(--sys-yellow-decor-default, #
|
|
129
|
+
background-color:var(--sys-yellow-background1-level, #fefae6);
|
|
130
|
+
border-color:var(--sys-yellow-decor-default, #f0dfb1);
|
|
131
131
|
}
|
|
132
132
|
.container[data-validation=warning]:hover{
|
|
133
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
134
|
-
border-color:var(--sys-yellow-decor-hovered, #
|
|
133
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
134
|
+
border-color:var(--sys-yellow-decor-hovered, #ead49a);
|
|
135
135
|
}
|
|
136
136
|
.container[data-validation=warning]:focus-within, .container[data-validation=warning][data-focused]{
|
|
137
137
|
outline-width:var(--border-state-focus-m-border-width, 3px);
|
|
138
138
|
outline-style:var(--border-state-focus-m-border-style, solid);
|
|
139
139
|
outline-color:var(--border-state-focus-m-border-color, );
|
|
140
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
141
|
-
border-color:var(--sys-yellow-accent-default, #
|
|
142
|
-
outline-color:var(--sys-yellow-decor-activated, #
|
|
140
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
141
|
+
border-color:var(--sys-yellow-accent-default, #fdca46);
|
|
142
|
+
outline-color:var(--sys-yellow-decor-activated, #e5c878);
|
|
143
143
|
}
|
|
144
144
|
.container[data-validation=success]{
|
|
145
|
-
background-color:var(--sys-green-background1-level, #
|
|
146
|
-
border-color:var(--sys-green-decor-default, #
|
|
145
|
+
background-color:var(--sys-green-background1-level, #f6faf3);
|
|
146
|
+
border-color:var(--sys-green-decor-default, #d2ead0);
|
|
147
147
|
}
|
|
148
148
|
.container[data-validation=success]:hover{
|
|
149
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
150
|
-
border-color:var(--sys-green-decor-hovered, #
|
|
149
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
150
|
+
border-color:var(--sys-green-decor-hovered, #c0e1ba);
|
|
151
151
|
}
|
|
152
152
|
.container[data-validation=success]:focus-within, .container[data-validation=success][data-focused]{
|
|
153
153
|
outline-width:var(--border-state-focus-m-border-width, 3px);
|
|
154
154
|
outline-style:var(--border-state-focus-m-border-style, solid);
|
|
155
155
|
outline-color:var(--border-state-focus-m-border-color, );
|
|
156
|
-
background-color:var(--sys-neutral-background2-level, #
|
|
157
|
-
border-color:var(--sys-green-accent-default, #
|
|
158
|
-
outline-color:var(--sys-green-decor-activated, #
|
|
156
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
157
|
+
border-color:var(--sys-green-accent-default, #57b762);
|
|
158
|
+
outline-color:var(--sys-green-decor-activated, #a8d1a2);
|
|
159
159
|
}
|
|
160
160
|
.container[data-selectable], .container[data-selectable] input, .container[data-selectable] select, .container[data-selectable] textarea, .container[data-selectable] span{
|
|
161
161
|
cursor:pointer;
|
|
@@ -164,30 +164,30 @@
|
|
|
164
164
|
cursor:default;
|
|
165
165
|
}
|
|
166
166
|
.container[data-readonly], .container[data-readonly]:hover{
|
|
167
|
-
background-color:var(--sys-neutral-decor-disabled, #
|
|
168
|
-
border-color:var(--sys-neutral-decor-disabled, #
|
|
167
|
+
background-color:var(--sys-neutral-decor-disabled, #e8eaf1);
|
|
168
|
+
border-color:var(--sys-neutral-decor-disabled, #e8eaf1);
|
|
169
169
|
}
|
|
170
170
|
.container[data-readonly]:focus-within, .container[data-readonly][data-focused]{
|
|
171
171
|
outline-width:var(--border-state-focus-m-border-width, 3px);
|
|
172
172
|
outline-style:var(--border-state-focus-m-border-style, solid);
|
|
173
173
|
outline-color:var(--border-state-focus-m-border-color, );
|
|
174
|
-
background-color:var(--sys-neutral-decor-disabled, #
|
|
175
|
-
border-color:var(--sys-neutral-decor-disabled, #
|
|
174
|
+
background-color:var(--sys-neutral-decor-disabled, #e8eaf1);
|
|
175
|
+
border-color:var(--sys-neutral-decor-disabled, #e8eaf1);
|
|
176
176
|
outline-color:var(--sys-primary-decor-activated, #c5b2f1);
|
|
177
177
|
}
|
|
178
178
|
.container[data-disabled], .container[data-disabled] input, .container[data-disabled] select, .container[data-disabled] textarea, .container[data-disabled] span{
|
|
179
179
|
cursor:not-allowed;
|
|
180
180
|
}
|
|
181
181
|
.container[data-disabled], .container[data-disabled]:focus-within, .container[data-disabled][data-focused], .container[data-disabled]:hover{
|
|
182
|
-
background-color:var(--sys-neutral-background, #
|
|
183
|
-
border-color:var(--sys-neutral-decor-disabled, #
|
|
182
|
+
background-color:var(--sys-neutral-background, #f1f2f6);
|
|
183
|
+
border-color:var(--sys-neutral-decor-disabled, #e8eaf1);
|
|
184
184
|
outline:none;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
.prefix{
|
|
188
188
|
display:inline-flex;
|
|
189
189
|
flex-shrink:0;
|
|
190
|
-
color:var(--sys-neutral-text-disabled, #
|
|
190
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
.postfix{
|
|
@@ -5,28 +5,28 @@
|
|
|
5
5
|
max-width:100%;
|
|
6
6
|
margin:0;
|
|
7
7
|
padding:0;
|
|
8
|
-
color:var(--sys-neutral-text-main, #
|
|
8
|
+
color:var(--sys-neutral-text-main, #33333b);
|
|
9
9
|
background-color:transparent;
|
|
10
10
|
border:none;
|
|
11
11
|
border-radius:0;
|
|
12
12
|
outline:0;
|
|
13
13
|
}
|
|
14
14
|
.textarea::-moz-placeholder{
|
|
15
|
-
color:var(--sys-neutral-text-disabled, #
|
|
15
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
16
16
|
}
|
|
17
17
|
.textarea::placeholder{
|
|
18
|
-
color:var(--sys-neutral-text-disabled, #
|
|
18
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
19
19
|
}
|
|
20
20
|
.textarea::-webkit-scrollbar{
|
|
21
21
|
width:0;
|
|
22
22
|
max-width:0;
|
|
23
23
|
}
|
|
24
24
|
.textarea:-moz-read-only{
|
|
25
|
-
color:var(--sys-neutral-text-support, #
|
|
25
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
26
26
|
}
|
|
27
27
|
.textarea:read-only{
|
|
28
|
-
color:var(--sys-neutral-text-support, #
|
|
28
|
+
color:var(--sys-neutral-text-support, #656771);
|
|
29
29
|
}
|
|
30
30
|
.textarea[disabled]{
|
|
31
|
-
color:var(--sys-neutral-text-disabled, #
|
|
31
|
+
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
32
32
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Fields",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.14.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -33,11 +33,12 @@
|
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@snack-uikit/button": "0.16.0",
|
|
36
|
-
"@snack-uikit/calendar": "0.7.5
|
|
36
|
+
"@snack-uikit/calendar": "0.7.5",
|
|
37
37
|
"@snack-uikit/droplist": "0.13.4",
|
|
38
38
|
"@snack-uikit/icons": "0.20.1",
|
|
39
39
|
"@snack-uikit/input-private": "3.1.0",
|
|
40
40
|
"@snack-uikit/scroll": "0.5.1",
|
|
41
|
+
"@snack-uikit/slider": "0.1.1",
|
|
41
42
|
"@snack-uikit/tooltip": "0.11.1",
|
|
42
43
|
"@snack-uikit/truncate-string": "0.4.7",
|
|
43
44
|
"@snack-uikit/utils": "3.2.0",
|
|
@@ -53,5 +54,5 @@
|
|
|
53
54
|
"peerDependencies": {
|
|
54
55
|
"@snack-uikit/locale": "*"
|
|
55
56
|
},
|
|
56
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "a1d688a1f1f70b6807cd05e2514cd1636c3e925a"
|
|
57
58
|
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import mergeRefs from 'merge-refs';
|
|
2
|
+
import { FocusEvent, forwardRef, KeyboardEvent, ReactElement, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
4
|
+
|
|
5
|
+
import { InputPrivate, InputPrivateProps, SIZE } from '@snack-uikit/input-private';
|
|
6
|
+
import { Slider, SliderProps as SliderComponentProps } from '@snack-uikit/slider';
|
|
7
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
8
|
+
|
|
9
|
+
import { CONTAINER_VARIANT, VALIDATION_STATE } from '../../constants';
|
|
10
|
+
import { FieldContainerPrivate } from '../../helperComponents';
|
|
11
|
+
import { FieldDecorator, FieldDecoratorProps } from '../FieldDecorator';
|
|
12
|
+
import { generateAllowedValues, getClosestMark, getTextFieldValue } from './helpers';
|
|
13
|
+
import styles from './styles.module.scss';
|
|
14
|
+
import { TextInputFormatter } from './types';
|
|
15
|
+
|
|
16
|
+
type SliderProps = Pick<InputPrivateProps, 'id' | 'name' | 'disabled' | 'readonly' | 'onFocus' | 'onBlur'> &
|
|
17
|
+
Pick<SliderComponentProps, 'range' | 'value' | 'onChange' | 'tipFormatter'> &
|
|
18
|
+
Required<Pick<SliderComponentProps, 'min' | 'max' | 'step' | 'marks'>>;
|
|
19
|
+
|
|
20
|
+
type WrapperProps = Pick<
|
|
21
|
+
FieldDecoratorProps,
|
|
22
|
+
'className' | 'label' | 'labelTooltip' | 'required' | 'hint' | 'showHintIcon' | 'size' | 'labelTooltipPlacement'
|
|
23
|
+
>;
|
|
24
|
+
|
|
25
|
+
type FieldSliderOwnProps = {
|
|
26
|
+
/** Иконка-постфикс для поля */
|
|
27
|
+
postfixIcon?: ReactElement;
|
|
28
|
+
/** Отображение линейки */
|
|
29
|
+
showScaleBar?: boolean;
|
|
30
|
+
/** Функция для форматирования значений в текстовом поле */
|
|
31
|
+
textInputFormatter?: TextInputFormatter;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type FieldSliderProps = WithSupportProps<FieldSliderOwnProps & SliderProps & WrapperProps>;
|
|
35
|
+
|
|
36
|
+
const getDefaultValue = (
|
|
37
|
+
range: boolean,
|
|
38
|
+
min: FieldSliderProps['min'],
|
|
39
|
+
max: FieldSliderProps['max'],
|
|
40
|
+
value: FieldSliderProps['value'],
|
|
41
|
+
): number | number[] => {
|
|
42
|
+
if (range) {
|
|
43
|
+
if (value) {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return [min, max];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return value ?? min;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const FieldSlider = forwardRef<HTMLInputElement, FieldSliderProps>(
|
|
54
|
+
(
|
|
55
|
+
{
|
|
56
|
+
id,
|
|
57
|
+
name,
|
|
58
|
+
min,
|
|
59
|
+
max,
|
|
60
|
+
step,
|
|
61
|
+
marks,
|
|
62
|
+
showScaleBar = true,
|
|
63
|
+
value: valueProp,
|
|
64
|
+
range = false,
|
|
65
|
+
disabled = false,
|
|
66
|
+
readonly = false,
|
|
67
|
+
onChange: onChangeProp,
|
|
68
|
+
onFocus,
|
|
69
|
+
onBlur,
|
|
70
|
+
className,
|
|
71
|
+
label,
|
|
72
|
+
labelTooltip,
|
|
73
|
+
labelTooltipPlacement,
|
|
74
|
+
required,
|
|
75
|
+
hint,
|
|
76
|
+
showHintIcon,
|
|
77
|
+
size = SIZE.S,
|
|
78
|
+
postfixIcon,
|
|
79
|
+
textInputFormatter,
|
|
80
|
+
...rest
|
|
81
|
+
},
|
|
82
|
+
ref,
|
|
83
|
+
) => {
|
|
84
|
+
const [value, onChange] = useUncontrolledProp(valueProp, getDefaultValue(range, min, max, valueProp), onChangeProp);
|
|
85
|
+
const [textFieldInputValue, setTextFieldInputValue] = useState<string>(
|
|
86
|
+
getTextFieldValue(value, textInputFormatter),
|
|
87
|
+
);
|
|
88
|
+
const localRef = useRef<HTMLInputElement>(null);
|
|
89
|
+
|
|
90
|
+
const onTextFieldChange = (textFieldValue: string) => {
|
|
91
|
+
const numValue = Number(textFieldValue);
|
|
92
|
+
if (Number.isNaN(numValue)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
setTextFieldInputValue(textFieldValue);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const handleTextValueChange = () => {
|
|
100
|
+
const textFieldNumValue = Number(textFieldInputValue);
|
|
101
|
+
if (Number.isNaN(textFieldNumValue)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (textFieldNumValue < min) {
|
|
106
|
+
setTextFieldInputValue(String(min));
|
|
107
|
+
onChange(min);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (textFieldNumValue > max) {
|
|
112
|
+
setTextFieldInputValue(String(max));
|
|
113
|
+
onChange(max);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (step === null) {
|
|
118
|
+
const allowedValues = Object.keys(marks).map(Number);
|
|
119
|
+
if (allowedValues.includes(textFieldNumValue)) {
|
|
120
|
+
onChange(textFieldNumValue);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const { mark } = getClosestMark(textFieldNumValue, allowedValues);
|
|
125
|
+
setTextFieldInputValue(String(mark));
|
|
126
|
+
onChange(mark);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const allowedValues = generateAllowedValues(min, max, step);
|
|
131
|
+
if (allowedValues.includes(textFieldNumValue)) {
|
|
132
|
+
onChange(textFieldNumValue);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const { mark } = getClosestMark(textFieldNumValue, allowedValues);
|
|
137
|
+
setTextFieldInputValue(String(mark));
|
|
138
|
+
onChange(mark);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const onTextFieldBlur = (e: FocusEvent<HTMLInputElement, Element>) => {
|
|
142
|
+
onBlur?.(e);
|
|
143
|
+
handleTextValueChange();
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const handleTextFieldKeyChange = (e: KeyboardEvent<HTMLInputElement>) => {
|
|
147
|
+
if (e.key === 'Enter') {
|
|
148
|
+
handleTextValueChange();
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
setTextFieldInputValue(getTextFieldValue(value, textInputFormatter));
|
|
154
|
+
}, [value, textInputFormatter]);
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<FieldDecorator
|
|
158
|
+
className={className}
|
|
159
|
+
label={label}
|
|
160
|
+
labelTooltip={labelTooltip}
|
|
161
|
+
labelTooltipPlacement={labelTooltipPlacement}
|
|
162
|
+
labelFor={id}
|
|
163
|
+
disabled={disabled}
|
|
164
|
+
required={required}
|
|
165
|
+
hint={hint}
|
|
166
|
+
showHintIcon={showHintIcon}
|
|
167
|
+
readonly={readonly}
|
|
168
|
+
size={size}
|
|
169
|
+
{...extractSupportProps(rest)}
|
|
170
|
+
>
|
|
171
|
+
<FieldContainerPrivate
|
|
172
|
+
className={styles.fieldContainer}
|
|
173
|
+
size={size}
|
|
174
|
+
validationState={VALIDATION_STATE.Default}
|
|
175
|
+
disabled={disabled}
|
|
176
|
+
readonly={readonly}
|
|
177
|
+
variant={CONTAINER_VARIANT.SingleLine}
|
|
178
|
+
inputRef={localRef}
|
|
179
|
+
postfix={postfixIcon}
|
|
180
|
+
>
|
|
181
|
+
<InputPrivate
|
|
182
|
+
ref={mergeRefs(ref, localRef)}
|
|
183
|
+
data-size={size}
|
|
184
|
+
value={textFieldInputValue}
|
|
185
|
+
onChange={range ? undefined : onTextFieldChange}
|
|
186
|
+
onFocus={onFocus}
|
|
187
|
+
onBlur={range ? onBlur : onTextFieldBlur}
|
|
188
|
+
onKeyDown={handleTextFieldKeyChange}
|
|
189
|
+
disabled={disabled}
|
|
190
|
+
readonly={range ? true : readonly}
|
|
191
|
+
type='text'
|
|
192
|
+
id={id}
|
|
193
|
+
name={name}
|
|
194
|
+
data-test-id='field-slider__input'
|
|
195
|
+
/>
|
|
196
|
+
</FieldContainerPrivate>
|
|
197
|
+
<div className={styles.sliderWrapper}>
|
|
198
|
+
<div className={styles.slider} data-size={size}>
|
|
199
|
+
<Slider
|
|
200
|
+
range={range}
|
|
201
|
+
min={min}
|
|
202
|
+
max={max}
|
|
203
|
+
step={step}
|
|
204
|
+
value={value}
|
|
205
|
+
onChange={onChange}
|
|
206
|
+
marks={showScaleBar ? marks : undefined}
|
|
207
|
+
disabled={readonly || disabled}
|
|
208
|
+
data-test-id='field-slider__slider'
|
|
209
|
+
/>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</FieldDecorator>
|
|
213
|
+
);
|
|
214
|
+
},
|
|
215
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const getDiff = (value: number, mark: number): number => Math.abs(mark - value);
|
|
2
|
+
|
|
3
|
+
export const getClosestMark = (value: number, marks: number[]): { lowestDiff: number; mark: number } =>
|
|
4
|
+
marks.reduce(
|
|
5
|
+
(accResult, mark) => {
|
|
6
|
+
const diff = getDiff(value, mark);
|
|
7
|
+
if (diff < accResult.lowestDiff) {
|
|
8
|
+
return {
|
|
9
|
+
lowestDiff: diff,
|
|
10
|
+
mark,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return accResult;
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
lowestDiff: getDiff(value, marks[0]),
|
|
18
|
+
mark: marks[0],
|
|
19
|
+
},
|
|
20
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TextInputFormatter } from '../types';
|
|
2
|
+
|
|
3
|
+
export const getTextFieldValue = (value: number | number[], textInputFormatter?: TextInputFormatter): string => {
|
|
4
|
+
if (!textInputFormatter) {
|
|
5
|
+
return typeof value === 'number' ? String(value) : value.join(' – ');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return typeof value === 'number' ? textInputFormatter(value) : value.map(textInputFormatter).join(' – ');
|
|
9
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FieldSlider';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields';
|
|
2
|
+
@import '@snack-uikit/figma-tokens/build/scss/styles-theme-variables';
|
|
3
|
+
|
|
4
|
+
$sizes: 's', 'm', 'l';
|
|
5
|
+
|
|
6
|
+
.sliderWrapper {
|
|
7
|
+
display: flex;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
width: 100%;
|
|
10
|
+
margin-top: -13px;
|
|
11
|
+
|
|
12
|
+
.slider {
|
|
13
|
+
flex: 1;
|
|
14
|
+
|
|
15
|
+
@each $size in $sizes {
|
|
16
|
+
&[data-size='#{$size}'] {
|
|
17
|
+
@include composite-var($fields, 'slider-wrap', $size);
|
|
18
|
+
|
|
19
|
+
height: inherit;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.fieldContainer {
|
|
26
|
+
svg {
|
|
27
|
+
color: simple-var($theme-variables, 'sys', 'neutral', 'text-disabled');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type TextInputFormatter = (value: number) => string;
|
package/src/components/index.ts
CHANGED