@snack-uikit/fields 0.30.0 → 0.32.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 (150) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +184 -152
  3. package/dist/cjs/components/FieldDate/FieldDate.d.ts +15 -24
  4. package/dist/cjs/components/FieldDate/FieldDate.js +53 -41
  5. package/dist/cjs/components/FieldDate/index.d.ts +0 -1
  6. package/dist/cjs/components/FieldDate/index.js +1 -9
  7. package/dist/cjs/components/FieldSecure/FieldSecure.d.ts +1 -1
  8. package/dist/cjs/components/FieldSelect/hooks.d.ts +2 -2
  9. package/dist/cjs/components/FieldSelect/hooks.js +7 -3
  10. package/dist/cjs/components/FieldSelect/styles.module.css +6 -18
  11. package/dist/cjs/components/FieldSlider/FieldSlider.d.ts +1 -1
  12. package/dist/cjs/components/FieldText/FieldText.d.ts +1 -1
  13. package/dist/cjs/components/FieldTextArea/FieldTextArea.d.ts +1 -1
  14. package/dist/cjs/components/FieldTime/FieldTime.d.ts +30 -0
  15. package/dist/cjs/components/FieldTime/FieldTime.js +298 -0
  16. package/dist/cjs/components/FieldTime/index.d.ts +1 -0
  17. package/dist/cjs/components/{FieldDate/hooks → FieldTime}/index.js +1 -1
  18. package/dist/cjs/components/FieldTime/styles.module.css +27 -0
  19. package/dist/cjs/components/index.d.ts +6 -5
  20. package/dist/cjs/components/index.js +6 -5
  21. package/dist/cjs/constants/dateFields.d.ts +24 -0
  22. package/dist/cjs/constants/dateFields.js +152 -0
  23. package/dist/cjs/constants/index.d.ts +2 -0
  24. package/dist/cjs/constants/index.js +26 -0
  25. package/dist/cjs/hooks/dateHandlers/index.d.ts +3 -0
  26. package/dist/cjs/hooks/dateHandlers/index.js +27 -0
  27. package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.d.ts +13 -5
  28. package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.js +49 -34
  29. package/dist/cjs/hooks/dateHandlers/useDateFieldHelpersForMode.d.ts +18 -0
  30. package/dist/cjs/hooks/dateHandlers/useDateFieldHelpersForMode.js +113 -0
  31. package/dist/cjs/hooks/index.d.ts +1 -0
  32. package/dist/cjs/hooks/index.js +1 -0
  33. package/dist/cjs/hooks/useCopyButton.js +1 -1
  34. package/dist/cjs/{types.d.ts → types/allFields.d.ts} +1 -1
  35. package/dist/cjs/types/dateFields.d.ts +11 -0
  36. package/dist/cjs/types/index.d.ts +2 -0
  37. package/dist/cjs/types/index.js +26 -0
  38. package/dist/cjs/utils/dateFields.d.ts +10 -0
  39. package/dist/cjs/utils/dateFields.js +71 -0
  40. package/dist/esm/components/FieldDate/FieldDate.d.ts +15 -24
  41. package/dist/esm/components/FieldDate/FieldDate.js +39 -31
  42. package/dist/esm/components/FieldDate/index.d.ts +0 -1
  43. package/dist/esm/components/FieldDate/index.js +0 -1
  44. package/dist/esm/components/FieldSecure/FieldSecure.d.ts +1 -1
  45. package/dist/esm/components/FieldSelect/hooks.d.ts +2 -2
  46. package/dist/esm/components/FieldSelect/hooks.js +9 -3
  47. package/dist/esm/components/FieldSelect/styles.module.css +6 -18
  48. package/dist/esm/components/FieldSlider/FieldSlider.d.ts +1 -1
  49. package/dist/esm/components/FieldText/FieldText.d.ts +1 -1
  50. package/dist/esm/components/FieldTextArea/FieldTextArea.d.ts +1 -1
  51. package/dist/esm/components/FieldTime/FieldTime.d.ts +30 -0
  52. package/dist/esm/components/FieldTime/FieldTime.js +161 -0
  53. package/dist/esm/components/FieldTime/index.d.ts +1 -0
  54. package/dist/esm/components/FieldTime/index.js +1 -0
  55. package/dist/esm/components/FieldTime/styles.module.css +27 -0
  56. package/dist/esm/components/index.d.ts +6 -5
  57. package/dist/esm/components/index.js +6 -5
  58. package/dist/esm/constants/dateFields.d.ts +24 -0
  59. package/dist/esm/constants/dateFields.js +103 -0
  60. package/dist/esm/constants/index.d.ts +2 -0
  61. package/dist/esm/constants/index.js +2 -0
  62. package/dist/esm/hooks/dateHandlers/index.d.ts +3 -0
  63. package/dist/esm/hooks/dateHandlers/index.js +3 -0
  64. package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.d.ts +13 -5
  65. package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.js +48 -35
  66. package/dist/esm/hooks/dateHandlers/useDateFieldHelpersForMode.d.ts +18 -0
  67. package/dist/esm/hooks/dateHandlers/useDateFieldHelpersForMode.js +95 -0
  68. package/dist/esm/hooks/index.d.ts +1 -0
  69. package/dist/esm/hooks/index.js +1 -0
  70. package/dist/esm/hooks/useCopyButton.js +1 -1
  71. package/dist/esm/{types.d.ts → types/allFields.d.ts} +1 -1
  72. package/dist/esm/types/dateFields.d.ts +11 -0
  73. package/dist/esm/types/index.d.ts +2 -0
  74. package/dist/esm/types/index.js +2 -0
  75. package/dist/esm/utils/dateFields.d.ts +10 -0
  76. package/dist/esm/utils/dateFields.js +59 -0
  77. package/package.json +16 -16
  78. package/src/components/FieldColor/styles.module.scss +9 -10
  79. package/src/components/FieldDate/FieldDate.tsx +72 -52
  80. package/src/components/FieldDate/index.ts +0 -1
  81. package/src/components/FieldDate/styles.module.scss +10 -11
  82. package/src/components/FieldDecorator/styles.module.scss +44 -45
  83. package/src/components/FieldSelect/hooks.ts +15 -3
  84. package/src/components/FieldSelect/styles.module.scss +20 -20
  85. package/src/components/FieldSlider/styles.module.scss +4 -4
  86. package/src/components/FieldTextArea/styles.module.scss +18 -18
  87. package/src/components/FieldTime/FieldTime.tsx +350 -0
  88. package/src/components/FieldTime/index.ts +1 -0
  89. package/src/components/FieldTime/styles.module.scss +41 -0
  90. package/src/components/index.ts +6 -5
  91. package/src/constants/dateFields.ts +127 -0
  92. package/src/constants/index.ts +2 -0
  93. package/src/helperComponents/ButtonCopyValue/styles.module.scss +2 -2
  94. package/src/helperComponents/ButtonField/styles.module.scss +9 -9
  95. package/src/helperComponents/ButtonFieldList/styles.module.scss +2 -2
  96. package/src/helperComponents/ButtonHideValue/styles.module.scss +2 -2
  97. package/src/helperComponents/FieldContainerPrivate/styles.module.scss +24 -26
  98. package/src/helperComponents/TextArea/styles.module.scss +5 -5
  99. package/src/hooks/dateHandlers/index.ts +3 -0
  100. package/src/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.ts +93 -47
  101. package/src/hooks/dateHandlers/useDateFieldHelpersForMode.ts +145 -0
  102. package/src/hooks/index.ts +1 -0
  103. package/src/hooks/styles.module.scss +5 -5
  104. package/src/hooks/useCopyButton.tsx +1 -1
  105. package/src/styles.module.scss +15 -15
  106. package/src/{types.ts → types/allFields.ts} +1 -1
  107. package/src/types/dateFields.ts +14 -0
  108. package/src/types/index.ts +2 -0
  109. package/src/utils/dateFields.ts +75 -0
  110. package/dist/cjs/components/FieldDate/constants.d.ts +0 -10
  111. package/dist/cjs/components/FieldDate/constants.js +0 -49
  112. package/dist/cjs/components/FieldDate/hooks/index.d.ts +0 -1
  113. package/dist/cjs/components/FieldDate/hooks/useDateFieldHelpers.d.ts +0 -10
  114. package/dist/cjs/components/FieldDate/hooks/useDateFieldHelpers.js +0 -82
  115. package/dist/cjs/components/FieldDate/types.d.ts +0 -6
  116. package/dist/cjs/components/FieldDate/utils.d.ts +0 -9
  117. package/dist/cjs/components/FieldDate/utils.js +0 -56
  118. package/dist/esm/components/FieldDate/constants.d.ts +0 -10
  119. package/dist/esm/components/FieldDate/constants.js +0 -28
  120. package/dist/esm/components/FieldDate/hooks/index.d.ts +0 -1
  121. package/dist/esm/components/FieldDate/hooks/index.js +0 -1
  122. package/dist/esm/components/FieldDate/hooks/useDateFieldHelpers.d.ts +0 -10
  123. package/dist/esm/components/FieldDate/hooks/useDateFieldHelpers.js +0 -66
  124. package/dist/esm/components/FieldDate/types.d.ts +0 -6
  125. package/dist/esm/components/FieldDate/utils.d.ts +0 -9
  126. package/dist/esm/components/FieldDate/utils.js +0 -43
  127. package/src/components/FieldDate/constants.ts +0 -33
  128. package/src/components/FieldDate/hooks/index.ts +0 -1
  129. package/src/components/FieldDate/hooks/useDateFieldHelpers.ts +0 -96
  130. package/src/components/FieldDate/types.ts +0 -6
  131. package/src/components/FieldDate/utils.ts +0 -49
  132. /package/dist/cjs/{constants.d.ts → constants/allFields.d.ts} +0 -0
  133. /package/dist/cjs/{constants.js → constants/allFields.js} +0 -0
  134. /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.d.ts +0 -0
  135. /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.js +0 -0
  136. /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.d.ts +0 -0
  137. /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.js +0 -0
  138. /package/dist/cjs/{components/FieldDate/types.js → types/allFields.js} +0 -0
  139. /package/dist/cjs/{types.js → types/dateFields.js} +0 -0
  140. /package/dist/esm/{constants.d.ts → constants/allFields.d.ts} +0 -0
  141. /package/dist/esm/{constants.js → constants/allFields.js} +0 -0
  142. /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.d.ts +0 -0
  143. /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.js +0 -0
  144. /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.d.ts +0 -0
  145. /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.js +0 -0
  146. /package/dist/esm/{components/FieldDate/types.js → types/allFields.js} +0 -0
  147. /package/dist/esm/{types.js → types/dateFields.js} +0 -0
  148. /package/src/{constants.ts → constants/allFields.ts} +0 -0
  149. /package/src/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.ts +0 -0
  150. /package/src/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.ts +0 -0
@@ -0,0 +1,127 @@
1
+ import { Mode, NoSecondsMode, Slot, TimeMode } from '../types';
2
+
3
+ export enum SlotKey {
4
+ Day = 'D',
5
+ Month = 'M',
6
+ Year = 'Y',
7
+ Hours = 'h',
8
+ Minutes = 'm',
9
+ Seconds = 's',
10
+ }
11
+
12
+ export const MODES = {
13
+ Date: 'date',
14
+ DateTime: 'date-time',
15
+ } as const;
16
+
17
+ export const TIME_MODES = {
18
+ FullTime: 'full-time',
19
+ NoSeconds: 'no-seconds',
20
+ } as const;
21
+
22
+ export const NO_SECONDS_MODE = 'date-time-no-sec';
23
+
24
+ export const MASK: Record<Mode | TimeMode | NoSecondsMode, Record<string, string>> = {
25
+ [MODES.Date]: {
26
+ 'ru-RU': 'ДД.ММ.ГГГГ',
27
+ 'en-US': 'DD.MM.YYYY',
28
+ },
29
+ [MODES.DateTime]: {
30
+ 'ru-RU': 'ДД.ММ.ГГГГ, чч:мм:сс',
31
+ 'en-US': 'DD.MM.YYYY, hh:mm:ss',
32
+ },
33
+ [NO_SECONDS_MODE]: {
34
+ 'ru-RU': 'ДД.ММ.ГГГГ, чч:мм',
35
+ 'en-US': 'DD.MM.YYYY, hh:mm',
36
+ },
37
+ [TIME_MODES.FullTime]: {
38
+ 'ru-RU': 'чч:мм:сс',
39
+ 'en-US': 'hh:mm:ss',
40
+ },
41
+ [TIME_MODES.NoSeconds]: {
42
+ 'ru-RU': 'чч:мм',
43
+ 'en-US': 'hh:mm',
44
+ },
45
+ };
46
+
47
+ export const DEFAULT_LOCALE = new Intl.Locale('ru-RU');
48
+
49
+ const DATE_SLOTS = {
50
+ [SlotKey.Day]: { start: 0, end: 2, max: 31, min: 1 },
51
+ [SlotKey.Month]: { start: 3, end: 5, max: 12, min: 1 },
52
+ [SlotKey.Year]: { start: 6, end: 10, max: 2100, min: 1900 },
53
+ };
54
+
55
+ const TIME_SLOTS = (shift: number, showSeconds: boolean) => ({
56
+ [SlotKey.Hours]: { start: shift, end: shift + 2, max: 23, min: 0 },
57
+ [SlotKey.Minutes]: { start: shift + 3, end: shift + 5, max: 59, min: 0 },
58
+ ...(showSeconds ? { [SlotKey.Seconds]: { start: shift + 6, end: shift + 8, max: 59, min: 0 } } : {}),
59
+ });
60
+
61
+ export const SLOTS: Record<Mode | TimeMode | NoSecondsMode, Record<SlotKey | string, Slot>> = {
62
+ [MODES.Date]: DATE_SLOTS,
63
+ [MODES.DateTime]: { ...DATE_SLOTS, ...TIME_SLOTS(12, true) },
64
+ [NO_SECONDS_MODE]: { ...DATE_SLOTS, ...TIME_SLOTS(12, false) },
65
+ [TIME_MODES.FullTime]: TIME_SLOTS(0, true),
66
+ [TIME_MODES.NoSeconds]: TIME_SLOTS(0, false),
67
+ };
68
+
69
+ export type FocusSlot = SlotKey | 'auto';
70
+
71
+ export const SLOT_ORDER: Record<Mode | TimeMode | NoSecondsMode, SlotKey[]> = {
72
+ [MODES.Date]: [SlotKey.Day, SlotKey.Month, SlotKey.Year],
73
+ [MODES.DateTime]: [SlotKey.Day, SlotKey.Month, SlotKey.Year, SlotKey.Hours, SlotKey.Minutes, SlotKey.Seconds],
74
+ [NO_SECONDS_MODE]: [SlotKey.Day, SlotKey.Month, SlotKey.Year, SlotKey.Hours, SlotKey.Minutes],
75
+ [TIME_MODES.FullTime]: [SlotKey.Hours, SlotKey.Minutes, SlotKey.Seconds],
76
+ [TIME_MODES.NoSeconds]: [SlotKey.Hours, SlotKey.Minutes],
77
+ };
78
+
79
+ const RU_DATE_SLOTS_PLACEHOLDER = {
80
+ [SlotKey.Day]: 'ДД',
81
+ [SlotKey.Month]: 'ММ',
82
+ [SlotKey.Year]: 'ГГГГ',
83
+ };
84
+
85
+ const RU_TIME_SLOTS_PLACEHOLDER = {
86
+ [SlotKey.Hours]: 'чч',
87
+ [SlotKey.Minutes]: 'мм',
88
+ [SlotKey.Seconds]: 'сс',
89
+ };
90
+
91
+ const EN_DATE_SLOTS_PLACEHOLDER = {
92
+ [SlotKey.Day]: 'DD',
93
+ [SlotKey.Month]: 'MM',
94
+ [SlotKey.Year]: 'YYYY',
95
+ };
96
+
97
+ const EN_TIME_SLOTS_PLACEHOLDER = {
98
+ [SlotKey.Hours]: 'hh',
99
+ [SlotKey.Minutes]: 'mm',
100
+ [SlotKey.Seconds]: 'ss',
101
+ };
102
+
103
+ export const SLOTS_PLACEHOLDER: Record<
104
+ Mode | TimeMode | NoSecondsMode,
105
+ Record<string, Partial<Record<SlotKey, string>>>
106
+ > = {
107
+ [MODES.Date]: {
108
+ 'ru-RU': RU_DATE_SLOTS_PLACEHOLDER,
109
+ 'en-US': EN_DATE_SLOTS_PLACEHOLDER,
110
+ },
111
+ [MODES.DateTime]: {
112
+ 'ru-RU': { ...RU_DATE_SLOTS_PLACEHOLDER, ...RU_TIME_SLOTS_PLACEHOLDER },
113
+ 'en-US': { ...EN_DATE_SLOTS_PLACEHOLDER, ...EN_TIME_SLOTS_PLACEHOLDER },
114
+ },
115
+ [NO_SECONDS_MODE]: {
116
+ 'ru-RU': { ...RU_DATE_SLOTS_PLACEHOLDER, ...RU_TIME_SLOTS_PLACEHOLDER, [SlotKey.Seconds]: undefined },
117
+ 'en-US': { ...EN_DATE_SLOTS_PLACEHOLDER, ...EN_TIME_SLOTS_PLACEHOLDER, [SlotKey.Seconds]: undefined },
118
+ },
119
+ [TIME_MODES.FullTime]: {
120
+ 'ru-RU': RU_TIME_SLOTS_PLACEHOLDER,
121
+ 'en-US': EN_TIME_SLOTS_PLACEHOLDER,
122
+ },
123
+ [TIME_MODES.NoSeconds]: {
124
+ 'ru-RU': { ...RU_TIME_SLOTS_PLACEHOLDER, [SlotKey.Seconds]: undefined },
125
+ 'en-US': { ...EN_TIME_SLOTS_PLACEHOLDER, [SlotKey.Seconds]: undefined },
126
+ },
127
+ };
@@ -0,0 +1,2 @@
1
+ export * from './allFields';
2
+ export * from './dateFields';
@@ -1,5 +1,5 @@
1
- @import "../../styles.module";
1
+ @use "../../styles.module";
2
2
 
3
3
  .buttonCopyValue {
4
- @include button-styles();
4
+ @include styles.button-styles();
5
5
  }
@@ -1,5 +1,5 @@
1
- @import "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element";
2
- @import "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields";
1
+ @use "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element";
2
+ @use "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields";
3
3
 
4
4
  $variants: 'before', 'after';
5
5
  $sizes: 's', 'm', 'l';
@@ -13,7 +13,7 @@ $sizes: 's', 'm', 'l';
13
13
  margin: 0;
14
14
  padding: 0;
15
15
 
16
- color: $sys-neutral-text-support;
16
+ color: styles-tokens-element.$sys-neutral-text-support;
17
17
 
18
18
  background-color: transparent;
19
19
  border: none;
@@ -22,7 +22,7 @@ $sizes: 's', 'm', 'l';
22
22
  &[data-variant='#{$variant}'] {
23
23
  @each $size in $sizes {
24
24
  &[data-size='#{$size}'] {
25
- @include composite-var($fields, 'button-field', $variant, $size);
25
+ @include styles-tokens-element.composite-var(styles-tokens-fields.$fields, 'button-field', $variant, $size);
26
26
  }
27
27
  }
28
28
  }
@@ -30,19 +30,19 @@ $sizes: 's', 'm', 'l';
30
30
 
31
31
  &:hover {
32
32
  cursor: pointer;
33
- background: color-on-background-with-opacity($sys-neutral-accent-default, $sys-neutral-background1-level, $opacity-a008);
33
+ background: styles-tokens-element.color-on-background-with-opacity(styles-tokens-element.$sys-neutral-accent-default, styles-tokens-element.$sys-neutral-background1-level, styles-tokens-element.$opacity-a008);
34
34
  }
35
35
 
36
36
  &:focus-visible, &[data-arrow-open] {
37
- @include outline-var($container-focused-s);
37
+ @include styles-tokens-element.outline-var(styles-tokens-element.$container-focused-s);
38
38
 
39
- background: color-on-background-with-opacity($sys-neutral-accent-default, $sys-neutral-background1-level, $opacity-a008);
40
- outline-color: $sys-primary-accent-default;
39
+ background: styles-tokens-element.color-on-background-with-opacity(styles-tokens-element.$sys-neutral-accent-default, styles-tokens-element.$sys-neutral-background1-level, styles-tokens-element.$opacity-a008);
40
+ outline-color: styles-tokens-element.$sys-primary-accent-default;
41
41
  }
42
42
 
43
43
  &[data-disabled] {
44
44
  cursor: not-allowed;
45
- opacity: $opacity-a056;
45
+ opacity: styles-tokens-element.$opacity-a056;
46
46
  background-color: transparent;
47
47
  }
48
48
  }
@@ -1,5 +1,5 @@
1
- @import "@snack-uikit/figma-tokens/build/scss/styles-theme-variables";
1
+ @use "@snack-uikit/figma-tokens/build/scss/styles-theme-variables";
2
2
 
3
3
  .triggerClassName {
4
- --offset: #{$space-drop-list-drop-offset};
4
+ --offset: #{styles-theme-variables.$space-drop-list-drop-offset};
5
5
  }
@@ -1,5 +1,5 @@
1
- @import "../../styles.module";
1
+ @use "../../styles.module";
2
2
 
3
3
  .buttonHideValue {
4
- @include button-styles();
4
+ @include styles.button-styles();
5
5
  }
@@ -1,30 +1,28 @@
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 */
1
+ @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields';
2
+ @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
5
3
 
6
4
  $sizes: 's', 'm', 'l';
7
5
  $variants: 'single-line-container', 'single-line-container-button-before', 'single-line-container-button-after', 'multi-line-container';
8
6
 
9
7
  @mixin validationState($state, $rainbowColor, $bgDefault) {
10
8
  &[data-validation='#{$state}'] {
11
- background-color: simple-var($theme-variables, 'sys', $bgDefault, 'background1-level');
12
- border-color: simple-var($theme-variables, 'sys', $bgDefault, 'decor-default');
9
+ background-color: styles-tokens-fields.simple-var(styles-tokens-fields.$theme-variables, 'sys', $bgDefault, 'background1-level');
10
+ border-color: styles-tokens-fields.simple-var(styles-tokens-fields.$theme-variables, 'sys', $bgDefault, 'decor-default');
13
11
 
14
12
  &:hover {
15
- background-color: $sys-neutral-background2-level;
16
- border-color: simple-var($theme-variables, 'sys', $rainbowColor, 'decor-hovered');
13
+ background-color: styles-tokens-fields.$sys-neutral-background2-level;
14
+ border-color: styles-tokens-fields.simple-var(styles-tokens-fields.$theme-variables, 'sys', $rainbowColor, 'decor-hovered');
17
15
  }
18
16
 
19
17
  &:not([data-readonly]):not([data-disable-focus]) {
20
18
  &:focus-within,
21
19
  &[data-focused] {
22
20
  &:not([data-disabled]) {
23
- @include outline-var($container-focused-m);
21
+ @include styles-tokens-fields.outline-var(styles-tokens-element.$container-focused-m);
24
22
 
25
- background-color: simple-var($sys-neutral-background2-level);
26
- border-color: simple-var($theme-variables, 'sys', $rainbowColor, 'accent-default');
27
- outline-color: simple-var($theme-variables, 'sys', $rainbowColor, 'decor-activated');
23
+ background-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-background2-level);
24
+ border-color: styles-tokens-fields.simple-var(styles-tokens-fields.$theme-variables, 'sys', $rainbowColor, 'accent-default');
25
+ outline-color: styles-tokens-fields.simple-var(styles-tokens-fields.$theme-variables, 'sys', $rainbowColor, 'decor-activated');
28
26
  }
29
27
  }
30
28
  }
@@ -49,19 +47,19 @@ $variants: 'single-line-container', 'single-line-container-button-before', 'sing
49
47
 
50
48
  @each $size in $sizes {
51
49
  &[data-size='#{$size}'] {
52
- @include composite-var($fields, 'container', $size);
50
+ @include styles-tokens-fields.composite-var(styles-tokens-fields.$fields, 'container', $size);
53
51
 
54
52
  &,
55
53
  input,
56
54
  select,
57
55
  textarea,
58
56
  span {
59
- @include composite-var($theme-variables, 'sans', 'body', $size);
57
+ @include styles-tokens-fields.composite-var(styles-tokens-fields.$theme-variables, 'sans', 'body', $size);
60
58
  }
61
59
 
62
60
  @each $variant in $variants {
63
61
  &[data-variant='#{$variant}'] {
64
- @include composite-var($fields, $variant, $size);
62
+ @include styles-tokens-fields.composite-var(styles-tokens-fields.$fields, $variant, $size);
65
63
  }
66
64
  }
67
65
  }
@@ -88,17 +86,17 @@ $variants: 'single-line-container', 'single-line-container-button-before', 'sing
88
86
 
89
87
  &,
90
88
  &:hover {
91
- background-color: simple-var($sys-neutral-decor-disabled);
92
- border-color: simple-var($sys-neutral-decor-disabled);
89
+ background-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-decor-disabled);
90
+ border-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-decor-disabled);
93
91
  }
94
92
 
95
93
  &:not([data-disable-focus]) {
96
94
  &:focus-within,
97
95
  &[data-focused] {
98
- @include outline-var($container-focused-m);
96
+ @include styles-tokens-fields.outline-var(styles-tokens-element.$container-focused-m);
99
97
 
100
- background-color: simple-var($sys-neutral-decor-disabled);
101
- border-color: simple-var($sys-neutral-decor-disabled);
98
+ background-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-decor-disabled);
99
+ border-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-decor-disabled);
102
100
  outline: none;
103
101
  }
104
102
  }
@@ -111,15 +109,15 @@ $variants: 'single-line-container', 'single-line-container-button-before', 'sing
111
109
  textarea,
112
110
  span {
113
111
  cursor: not-allowed;
114
- background-color: simple-var($sys-neutral-background);
112
+ background-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-background);
115
113
  }
116
114
 
117
115
  &,
118
116
  &:focus-within,
119
117
  &[data-focused],
120
118
  &:hover {
121
- background-color: simple-var($sys-neutral-background);
122
- border-color: simple-var($sys-neutral-decor-disabled);
119
+ background-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-background);
120
+ border-color: styles-tokens-fields.simple-var(styles-tokens-fields.$sys-neutral-decor-disabled);
123
121
  outline: none;
124
122
  }
125
123
  }
@@ -128,15 +126,15 @@ $variants: 'single-line-container', 'single-line-container-button-before', 'sing
128
126
  .prefix {
129
127
  display: inline-flex;
130
128
  flex-shrink: 0;
131
- gap: $space-fields-postfix-gap;
129
+ gap: styles-tokens-fields.$space-fields-postfix-gap;
132
130
  align-items: center;
133
131
 
134
- color: $sys-neutral-text-disabled;
132
+ color: styles-tokens-fields.$sys-neutral-text-disabled;
135
133
  }
136
134
 
137
135
  .postfix {
138
136
  display: inline-flex;
139
137
  flex-shrink: 0;
140
- gap: $space-fields-postfix-gap;
138
+ gap: styles-tokens-fields.$space-fields-postfix-gap;
141
139
  align-items: center;
142
140
  }
@@ -1,4 +1,4 @@
1
- @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
1
+ @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
2
2
 
3
3
  .textarea {
4
4
  resize: none;
@@ -9,7 +9,7 @@
9
9
  margin: 0;
10
10
  padding: 0;
11
11
 
12
- color: simple-var($sys-neutral-text-main);
12
+ color: styles-tokens-element.simple-var(styles-tokens-element.$sys-neutral-text-main);
13
13
 
14
14
  background-color: transparent;
15
15
  border: none;
@@ -17,7 +17,7 @@
17
17
  outline: 0;
18
18
 
19
19
  &::placeholder {
20
- color: simple-var($sys-neutral-text-disabled);
20
+ color: styles-tokens-element.simple-var(styles-tokens-element.$sys-neutral-text-disabled);
21
21
  }
22
22
 
23
23
  &::-webkit-scrollbar {
@@ -26,10 +26,10 @@
26
26
  }
27
27
 
28
28
  &:read-only {
29
- color: simple-var($sys-neutral-text-support);
29
+ color: styles-tokens-element.simple-var(styles-tokens-element.$sys-neutral-text-support);
30
30
  }
31
31
 
32
32
  &[disabled] {
33
- color: simple-var($sys-neutral-text-disabled);
33
+ color: styles-tokens-element.simple-var(styles-tokens-element.$sys-neutral-text-disabled);
34
34
  }
35
35
  }
@@ -0,0 +1,3 @@
1
+ export * from './useDateField';
2
+ export * from './useFocusHandlers';
3
+ export * from './useHandlers';
@@ -1,32 +1,71 @@
1
1
  import { ChangeEvent, FocusEventHandler, KeyboardEvent, RefObject, useCallback, useMemo, useRef } from 'react';
2
2
 
3
+ import { TimePickerProps } from '@snack-uikit/calendar';
3
4
  import { isBrowser } from '@snack-uikit/utils';
4
5
 
5
- import { DEFAULT_LOCALE, MASK, SlotKey, SLOTS, SLOTS_PLACEHOLDER } from '../constants';
6
- import { getNextSlotKey, getPrevSlotKey, getSlotKey } from '../utils';
7
- import { useDateFieldHelpers } from './useDateFieldHelpers';
8
-
9
- type UseDateFieldProps = {
6
+ import {
7
+ DEFAULT_LOCALE,
8
+ FocusSlot,
9
+ MASK,
10
+ MODES,
11
+ NO_SECONDS_MODE,
12
+ SLOT_ORDER,
13
+ SlotKey,
14
+ SLOTS,
15
+ SLOTS_PLACEHOLDER,
16
+ } from '../../constants';
17
+ import { Mode, TimeMode } from '../../types';
18
+ import { parseDate } from '../../utils/dateFields';
19
+ import { useDateFieldHelpersForMode } from './useDateFieldHelpersForMode';
20
+
21
+ type BaseProps = {
10
22
  inputRef: RefObject<HTMLInputElement>;
11
- onChange?(value: string): void;
12
23
  readonly?: boolean;
13
24
  locale?: Intl.Locale;
14
25
  setIsOpen(v: boolean): void;
26
+ showSeconds?: boolean;
15
27
  };
16
28
 
17
- type FocusSlot = SlotKey.Day | SlotKey.Year | 'auto';
18
-
19
- export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LOCALE, setIsOpen }: UseDateFieldProps) {
20
- const { setFocus, updateSlot, getSlot, isLikeDate, isAllSelected, isValidInput, tryToCompleteInput } =
21
- useDateFieldHelpers(inputRef);
22
- const focusSlotRef = useRef<FocusSlot>(SlotKey.Day);
23
-
24
- const mask = useMemo(() => MASK[locale.baseName] || MASK[DEFAULT_LOCALE.baseName], [locale]);
25
-
26
- const slotsPlaceHolder = useMemo(
27
- () => SLOTS_PLACEHOLDER[locale.baseName] || SLOTS_PLACEHOLDER[DEFAULT_LOCALE.baseName],
28
- [locale.baseName],
29
- );
29
+ type UseDateFieldProps =
30
+ | ({
31
+ mode: Mode;
32
+ onChange?(value: Date | undefined): void;
33
+ } & BaseProps)
34
+ | ({
35
+ mode: TimeMode;
36
+ onChange?: TimePickerProps['onChangeValue'];
37
+ } & BaseProps);
38
+
39
+ export function useDateField({
40
+ inputRef,
41
+ onChange,
42
+ readonly,
43
+ locale = DEFAULT_LOCALE,
44
+ setIsOpen,
45
+ mode,
46
+ showSeconds,
47
+ }: UseDateFieldProps) {
48
+ const dateTimeMode = mode === MODES.DateTime && !showSeconds ? NO_SECONDS_MODE : mode;
49
+ const slotsInfo = SLOTS[dateTimeMode];
50
+ const mask = MASK[dateTimeMode][locale.baseName] || MASK[dateTimeMode][DEFAULT_LOCALE.baseName];
51
+ const slotsPlaceholder =
52
+ SLOTS_PLACEHOLDER[dateTimeMode][locale.baseName] || SLOTS_PLACEHOLDER[dateTimeMode][DEFAULT_LOCALE.baseName];
53
+ const slotOrder = SLOT_ORDER[dateTimeMode];
54
+ const {
55
+ getNextSlotKey,
56
+ getPrevSlotKey,
57
+ getSlotKeyFromIndex,
58
+ setFocus,
59
+ updateSlot,
60
+ getSlot,
61
+ isLikeDate,
62
+ isAllSelected,
63
+ tryToCompleteInput,
64
+ isValidInput,
65
+ } = useDateFieldHelpersForMode({ inputRef, mode: dateTimeMode });
66
+
67
+ const focusSlotKey = useMemo(() => slotOrder[0], [slotOrder]);
68
+ const focusSlotRef = useRef<FocusSlot>(focusSlotKey);
30
69
 
31
70
  const setInputFocus = useCallback(
32
71
  (focusSlot?: FocusSlot) => {
@@ -35,20 +74,20 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
35
74
  }
36
75
 
37
76
  if (isBrowser() && document.activeElement !== inputRef.current) {
38
- focusSlotRef.current = focusSlot || SlotKey.Day;
77
+ focusSlotRef.current = focusSlot || focusSlotKey;
39
78
  inputRef.current.focus();
40
79
  return;
41
80
  }
42
81
 
43
82
  const focusSlotValue = focusSlot || focusSlotRef.current;
44
83
 
45
- if (isLikeDate() && focusSlotValue === SlotKey.Day) {
84
+ if (isLikeDate() && focusSlotValue === focusSlotKey) {
46
85
  return;
47
86
  }
48
87
 
49
88
  if (!inputRef.current.value) {
50
89
  inputRef.current.value = mask;
51
- setFocus(SlotKey.Day);
90
+ setFocus(focusSlotKey);
52
91
  return;
53
92
  }
54
93
 
@@ -57,14 +96,14 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
57
96
  return;
58
97
  }
59
98
 
60
- const slotKey = getSlotKey(inputRef.current.selectionStart);
99
+ const slotKey = getSlotKeyFromIndex(inputRef.current.selectionStart);
61
100
 
62
101
  if (slotKey) {
63
- const { start, end } = SLOTS[slotKey];
102
+ const { start, end } = slotsInfo[slotKey];
64
103
  inputRef.current.setSelectionRange(start, end);
65
104
  }
66
105
  },
67
- [inputRef, isLikeDate, mask, readonly, setFocus],
106
+ [inputRef, readonly, isLikeDate, focusSlotKey, getSlotKeyFromIndex, mask, setFocus, slotsInfo],
68
107
  );
69
108
 
70
109
  const handleClick = useCallback(() => {
@@ -72,12 +111,12 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
72
111
  }, [setInputFocus]);
73
112
 
74
113
  const handleChange: (value: string, e?: ChangeEvent<HTMLInputElement> | undefined) => void = () => {
75
- onChange && isLikeDate() && onChange(inputRef.current?.value || '');
114
+ onChange && isLikeDate() && onChange(parseDate(inputRef.current?.value || ''));
76
115
  };
77
116
 
78
117
  const checkInputAndGoNext = useCallback(
79
- (slotKey: string) => {
80
- if (slotKey === SlotKey.Year && tryToCompleteInput()) {
118
+ (slotKey: SlotKey | undefined) => {
119
+ if (slotKey === slotOrder[slotOrder.length - 1] && tryToCompleteInput()) {
81
120
  return;
82
121
  }
83
122
 
@@ -88,19 +127,19 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
88
127
 
89
128
  switch (slotKey) {
90
129
  case SlotKey.Day:
91
- updateSlot(SlotKey.Month, slotsPlaceHolder[SlotKey.Month]);
130
+ updateSlot(SlotKey.Month, slotsPlaceholder?.[SlotKey.Month] ?? '');
92
131
  setFocus(SlotKey.Month);
93
132
  return;
94
133
  case SlotKey.Year:
95
134
  case SlotKey.Month:
96
- updateSlot(SlotKey.Day, slotsPlaceHolder[SlotKey.Day]);
135
+ updateSlot(SlotKey.Day, slotsPlaceholder?.[SlotKey.Day] ?? '');
97
136
  setFocus(SlotKey.Day);
98
137
  return;
99
138
  default:
100
139
  setFocus(getNextSlotKey(slotKey));
101
140
  }
102
141
  },
103
- [tryToCompleteInput, isValidInput, setFocus, slotsPlaceHolder, updateSlot],
142
+ [slotOrder, tryToCompleteInput, isValidInput, setFocus, getNextSlotKey, updateSlot, slotsPlaceholder],
104
143
  );
105
144
 
106
145
  const handleKeyDown = useCallback(
@@ -125,16 +164,16 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
125
164
  }
126
165
 
127
166
  const clickIndex = inputRef.current.selectionStart;
128
- const slotKey = getSlotKey(clickIndex);
167
+ const slotKey = getSlotKeyFromIndex(clickIndex);
129
168
 
130
169
  if (slotKey) {
131
170
  const value = getSlot(slotKey);
132
- const { max } = SLOTS[slotKey];
171
+ const { max } = slotsInfo[slotKey];
133
172
 
134
173
  const numberValue = Number(value) || 0;
135
174
 
136
175
  if (e.key === 'ArrowRight') {
137
- if (isAllSelected() || slotKey === SlotKey.Year) {
176
+ if (isAllSelected() || slotKey === slotOrder[slotOrder.length - 1]) {
138
177
  inputRef.current.selectionStart = inputRef.current.value.length;
139
178
  return;
140
179
  }
@@ -150,9 +189,9 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
150
189
  if (e.key === 'Backspace') {
151
190
  if (isAllSelected()) {
152
191
  inputRef.current.value = mask;
153
- setFocus(SlotKey.Day);
192
+ setFocus(focusSlotKey);
154
193
  } else {
155
- updateSlot(slotKey, slotsPlaceHolder[slotKey]);
194
+ updateSlot(slotKey, slotsPlaceholder[slotKey] ?? '');
156
195
  }
157
196
  }
158
197
 
@@ -189,24 +228,31 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
189
228
  }
190
229
  }
191
230
  }
192
- onChange?.(isLikeDate() ? inputRef.current.value : '');
231
+ const newDate = parseDate(isLikeDate() ? inputRef.current.value : '');
232
+ onChange?.(newDate);
193
233
  }
194
234
  }
195
235
  },
196
236
  [
197
- checkInputAndGoNext,
198
- getSlot,
199
237
  inputRef,
200
- isAllSelected,
201
- isLikeDate,
202
- mask,
203
- onChange,
204
238
  readonly,
205
- setFocus,
239
+ getSlotKeyFromIndex,
206
240
  setIsOpen,
207
- slotsPlaceHolder,
208
241
  tryToCompleteInput,
242
+ getSlot,
243
+ slotsInfo,
244
+ isLikeDate,
245
+ onChange,
246
+ isAllSelected,
247
+ slotOrder,
248
+ setFocus,
249
+ getNextSlotKey,
250
+ getPrevSlotKey,
251
+ mask,
252
+ focusSlotKey,
209
253
  updateSlot,
254
+ slotsPlaceholder,
255
+ checkInputAndGoNext,
210
256
  ],
211
257
  );
212
258
 
@@ -214,8 +260,8 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
214
260
  if (!readonly && inputRef.current?.value === mask) {
215
261
  inputRef.current.value = '';
216
262
  }
217
- focusSlotRef.current = SlotKey.Day;
218
- }, [inputRef, mask, readonly]);
263
+ focusSlotRef.current = focusSlotKey;
264
+ }, [inputRef, mask, readonly, focusSlotKey]);
219
265
 
220
266
  return {
221
267
  handleKeyDown,