@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,103 @@
1
+ export var SlotKey;
2
+ (function (SlotKey) {
3
+ SlotKey["Day"] = "D";
4
+ SlotKey["Month"] = "M";
5
+ SlotKey["Year"] = "Y";
6
+ SlotKey["Hours"] = "h";
7
+ SlotKey["Minutes"] = "m";
8
+ SlotKey["Seconds"] = "s";
9
+ })(SlotKey || (SlotKey = {}));
10
+ export const MODES = {
11
+ Date: 'date',
12
+ DateTime: 'date-time',
13
+ };
14
+ export const TIME_MODES = {
15
+ FullTime: 'full-time',
16
+ NoSeconds: 'no-seconds',
17
+ };
18
+ export const NO_SECONDS_MODE = 'date-time-no-sec';
19
+ export const MASK = {
20
+ [MODES.Date]: {
21
+ 'ru-RU': 'ДД.ММ.ГГГГ',
22
+ 'en-US': 'DD.MM.YYYY',
23
+ },
24
+ [MODES.DateTime]: {
25
+ 'ru-RU': 'ДД.ММ.ГГГГ, чч:мм:сс',
26
+ 'en-US': 'DD.MM.YYYY, hh:mm:ss',
27
+ },
28
+ [NO_SECONDS_MODE]: {
29
+ 'ru-RU': 'ДД.ММ.ГГГГ, чч:мм',
30
+ 'en-US': 'DD.MM.YYYY, hh:mm',
31
+ },
32
+ [TIME_MODES.FullTime]: {
33
+ 'ru-RU': 'чч:мм:сс',
34
+ 'en-US': 'hh:mm:ss',
35
+ },
36
+ [TIME_MODES.NoSeconds]: {
37
+ 'ru-RU': 'чч:мм',
38
+ 'en-US': 'hh:mm',
39
+ },
40
+ };
41
+ export const DEFAULT_LOCALE = new Intl.Locale('ru-RU');
42
+ const DATE_SLOTS = {
43
+ [SlotKey.Day]: { start: 0, end: 2, max: 31, min: 1 },
44
+ [SlotKey.Month]: { start: 3, end: 5, max: 12, min: 1 },
45
+ [SlotKey.Year]: { start: 6, end: 10, max: 2100, min: 1900 },
46
+ };
47
+ const TIME_SLOTS = (shift, showSeconds) => (Object.assign({ [SlotKey.Hours]: { start: shift, end: shift + 2, max: 23, min: 0 }, [SlotKey.Minutes]: { start: shift + 3, end: shift + 5, max: 59, min: 0 } }, (showSeconds ? { [SlotKey.Seconds]: { start: shift + 6, end: shift + 8, max: 59, min: 0 } } : {})));
48
+ export const SLOTS = {
49
+ [MODES.Date]: DATE_SLOTS,
50
+ [MODES.DateTime]: Object.assign(Object.assign({}, DATE_SLOTS), TIME_SLOTS(12, true)),
51
+ [NO_SECONDS_MODE]: Object.assign(Object.assign({}, DATE_SLOTS), TIME_SLOTS(12, false)),
52
+ [TIME_MODES.FullTime]: TIME_SLOTS(0, true),
53
+ [TIME_MODES.NoSeconds]: TIME_SLOTS(0, false),
54
+ };
55
+ export const SLOT_ORDER = {
56
+ [MODES.Date]: [SlotKey.Day, SlotKey.Month, SlotKey.Year],
57
+ [MODES.DateTime]: [SlotKey.Day, SlotKey.Month, SlotKey.Year, SlotKey.Hours, SlotKey.Minutes, SlotKey.Seconds],
58
+ [NO_SECONDS_MODE]: [SlotKey.Day, SlotKey.Month, SlotKey.Year, SlotKey.Hours, SlotKey.Minutes],
59
+ [TIME_MODES.FullTime]: [SlotKey.Hours, SlotKey.Minutes, SlotKey.Seconds],
60
+ [TIME_MODES.NoSeconds]: [SlotKey.Hours, SlotKey.Minutes],
61
+ };
62
+ const RU_DATE_SLOTS_PLACEHOLDER = {
63
+ [SlotKey.Day]: 'ДД',
64
+ [SlotKey.Month]: 'ММ',
65
+ [SlotKey.Year]: 'ГГГГ',
66
+ };
67
+ const RU_TIME_SLOTS_PLACEHOLDER = {
68
+ [SlotKey.Hours]: 'чч',
69
+ [SlotKey.Minutes]: 'мм',
70
+ [SlotKey.Seconds]: 'сс',
71
+ };
72
+ const EN_DATE_SLOTS_PLACEHOLDER = {
73
+ [SlotKey.Day]: 'DD',
74
+ [SlotKey.Month]: 'MM',
75
+ [SlotKey.Year]: 'YYYY',
76
+ };
77
+ const EN_TIME_SLOTS_PLACEHOLDER = {
78
+ [SlotKey.Hours]: 'hh',
79
+ [SlotKey.Minutes]: 'mm',
80
+ [SlotKey.Seconds]: 'ss',
81
+ };
82
+ export const SLOTS_PLACEHOLDER = {
83
+ [MODES.Date]: {
84
+ 'ru-RU': RU_DATE_SLOTS_PLACEHOLDER,
85
+ 'en-US': EN_DATE_SLOTS_PLACEHOLDER,
86
+ },
87
+ [MODES.DateTime]: {
88
+ 'ru-RU': Object.assign(Object.assign({}, RU_DATE_SLOTS_PLACEHOLDER), RU_TIME_SLOTS_PLACEHOLDER),
89
+ 'en-US': Object.assign(Object.assign({}, EN_DATE_SLOTS_PLACEHOLDER), EN_TIME_SLOTS_PLACEHOLDER),
90
+ },
91
+ [NO_SECONDS_MODE]: {
92
+ 'ru-RU': Object.assign(Object.assign(Object.assign({}, RU_DATE_SLOTS_PLACEHOLDER), RU_TIME_SLOTS_PLACEHOLDER), { [SlotKey.Seconds]: undefined }),
93
+ 'en-US': Object.assign(Object.assign(Object.assign({}, EN_DATE_SLOTS_PLACEHOLDER), EN_TIME_SLOTS_PLACEHOLDER), { [SlotKey.Seconds]: undefined }),
94
+ },
95
+ [TIME_MODES.FullTime]: {
96
+ 'ru-RU': RU_TIME_SLOTS_PLACEHOLDER,
97
+ 'en-US': EN_TIME_SLOTS_PLACEHOLDER,
98
+ },
99
+ [TIME_MODES.NoSeconds]: {
100
+ 'ru-RU': Object.assign(Object.assign({}, RU_TIME_SLOTS_PLACEHOLDER), { [SlotKey.Seconds]: undefined }),
101
+ 'en-US': Object.assign(Object.assign({}, EN_TIME_SLOTS_PLACEHOLDER), { [SlotKey.Seconds]: undefined }),
102
+ },
103
+ };
@@ -0,0 +1,2 @@
1
+ export * from './allFields';
2
+ export * from './dateFields';
@@ -0,0 +1,2 @@
1
+ export * from './allFields';
2
+ export * from './dateFields';
@@ -0,0 +1,3 @@
1
+ export * from './useDateField';
2
+ export * from './useFocusHandlers';
3
+ export * from './useHandlers';
@@ -0,0 +1,3 @@
1
+ export * from './useDateField';
2
+ export * from './useFocusHandlers';
3
+ export * from './useHandlers';
@@ -1,14 +1,22 @@
1
1
  import { ChangeEvent, FocusEventHandler, KeyboardEvent, RefObject } from 'react';
2
- import { SlotKey } from '../constants';
3
- type UseDateFieldProps = {
2
+ import { TimePickerProps } from '@snack-uikit/calendar';
3
+ import { FocusSlot } from '../../constants';
4
+ import { Mode, TimeMode } from '../../types';
5
+ type BaseProps = {
4
6
  inputRef: RefObject<HTMLInputElement>;
5
- onChange?(value: string): void;
6
7
  readonly?: boolean;
7
8
  locale?: Intl.Locale;
8
9
  setIsOpen(v: boolean): void;
10
+ showSeconds?: boolean;
9
11
  };
10
- type FocusSlot = SlotKey.Day | SlotKey.Year | 'auto';
11
- export declare function useDateField({ inputRef, onChange, readonly, locale, setIsOpen }: UseDateFieldProps): {
12
+ type UseDateFieldProps = ({
13
+ mode: Mode;
14
+ onChange?(value: Date | undefined): void;
15
+ } & BaseProps) | ({
16
+ mode: TimeMode;
17
+ onChange?: TimePickerProps['onChangeValue'];
18
+ } & BaseProps);
19
+ export declare function useDateField({ inputRef, onChange, readonly, locale, setIsOpen, mode, showSeconds, }: UseDateFieldProps): {
12
20
  handleKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void;
13
21
  handleChange: (value: string, e?: ChangeEvent<HTMLInputElement> | undefined) => void;
14
22
  handleClick: () => void;
@@ -1,51 +1,56 @@
1
1
  import { useCallback, useMemo, useRef } from 'react';
2
2
  import { isBrowser } from '@snack-uikit/utils';
3
- import { DEFAULT_LOCALE, MASK, SlotKey, SLOTS, SLOTS_PLACEHOLDER } from '../constants';
4
- import { getNextSlotKey, getPrevSlotKey, getSlotKey } from '../utils';
5
- import { useDateFieldHelpers } from './useDateFieldHelpers';
6
- export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LOCALE, setIsOpen }) {
3
+ import { DEFAULT_LOCALE, MASK, MODES, NO_SECONDS_MODE, SLOT_ORDER, SlotKey, SLOTS, SLOTS_PLACEHOLDER, } from '../../constants';
4
+ import { parseDate } from '../../utils/dateFields';
5
+ import { useDateFieldHelpersForMode } from './useDateFieldHelpersForMode';
6
+ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LOCALE, setIsOpen, mode, showSeconds, }) {
7
7
  var _a;
8
- const { setFocus, updateSlot, getSlot, isLikeDate, isAllSelected, isValidInput, tryToCompleteInput } = useDateFieldHelpers(inputRef);
9
- const focusSlotRef = useRef(SlotKey.Day);
10
- const mask = useMemo(() => MASK[locale.baseName] || MASK[DEFAULT_LOCALE.baseName], [locale]);
11
- const slotsPlaceHolder = useMemo(() => SLOTS_PLACEHOLDER[locale.baseName] || SLOTS_PLACEHOLDER[DEFAULT_LOCALE.baseName], [locale.baseName]);
8
+ const dateTimeMode = mode === MODES.DateTime && !showSeconds ? NO_SECONDS_MODE : mode;
9
+ const slotsInfo = SLOTS[dateTimeMode];
10
+ const mask = MASK[dateTimeMode][locale.baseName] || MASK[dateTimeMode][DEFAULT_LOCALE.baseName];
11
+ const slotsPlaceholder = SLOTS_PLACEHOLDER[dateTimeMode][locale.baseName] || SLOTS_PLACEHOLDER[dateTimeMode][DEFAULT_LOCALE.baseName];
12
+ const slotOrder = SLOT_ORDER[dateTimeMode];
13
+ const { getNextSlotKey, getPrevSlotKey, getSlotKeyFromIndex, setFocus, updateSlot, getSlot, isLikeDate, isAllSelected, tryToCompleteInput, isValidInput, } = useDateFieldHelpersForMode({ inputRef, mode: dateTimeMode });
14
+ const focusSlotKey = useMemo(() => slotOrder[0], [slotOrder]);
15
+ const focusSlotRef = useRef(focusSlotKey);
12
16
  const setInputFocus = useCallback((focusSlot) => {
13
17
  if (!inputRef.current || readonly) {
14
18
  return;
15
19
  }
16
20
  if (isBrowser() && document.activeElement !== inputRef.current) {
17
- focusSlotRef.current = focusSlot || SlotKey.Day;
21
+ focusSlotRef.current = focusSlot || focusSlotKey;
18
22
  inputRef.current.focus();
19
23
  return;
20
24
  }
21
25
  const focusSlotValue = focusSlot || focusSlotRef.current;
22
- if (isLikeDate() && focusSlotValue === SlotKey.Day) {
26
+ if (isLikeDate() && focusSlotValue === focusSlotKey) {
23
27
  return;
24
28
  }
25
29
  if (!inputRef.current.value) {
26
30
  inputRef.current.value = mask;
27
- setFocus(SlotKey.Day);
31
+ setFocus(focusSlotKey);
28
32
  return;
29
33
  }
30
34
  if (focusSlot !== 'auto') {
31
35
  setFocus(focusSlotValue);
32
36
  return;
33
37
  }
34
- const slotKey = getSlotKey(inputRef.current.selectionStart);
38
+ const slotKey = getSlotKeyFromIndex(inputRef.current.selectionStart);
35
39
  if (slotKey) {
36
- const { start, end } = SLOTS[slotKey];
40
+ const { start, end } = slotsInfo[slotKey];
37
41
  inputRef.current.setSelectionRange(start, end);
38
42
  }
39
- }, [inputRef, isLikeDate, mask, readonly, setFocus]);
43
+ }, [inputRef, readonly, isLikeDate, focusSlotKey, getSlotKeyFromIndex, mask, setFocus, slotsInfo]);
40
44
  const handleClick = useCallback(() => {
41
45
  setInputFocus('auto');
42
46
  }, [setInputFocus]);
43
47
  const handleChange = () => {
44
48
  var _a;
45
- onChange && isLikeDate() && onChange(((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value) || '');
49
+ onChange && isLikeDate() && onChange(parseDate(((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value) || ''));
46
50
  };
47
51
  const checkInputAndGoNext = useCallback((slotKey) => {
48
- if (slotKey === SlotKey.Year && tryToCompleteInput()) {
52
+ var _a, _b;
53
+ if (slotKey === slotOrder[slotOrder.length - 1] && tryToCompleteInput()) {
49
54
  return;
50
55
  }
51
56
  if (isValidInput()) {
@@ -54,19 +59,20 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
54
59
  }
55
60
  switch (slotKey) {
56
61
  case SlotKey.Day:
57
- updateSlot(SlotKey.Month, slotsPlaceHolder[SlotKey.Month]);
62
+ updateSlot(SlotKey.Month, (_a = slotsPlaceholder === null || slotsPlaceholder === void 0 ? void 0 : slotsPlaceholder[SlotKey.Month]) !== null && _a !== void 0 ? _a : '');
58
63
  setFocus(SlotKey.Month);
59
64
  return;
60
65
  case SlotKey.Year:
61
66
  case SlotKey.Month:
62
- updateSlot(SlotKey.Day, slotsPlaceHolder[SlotKey.Day]);
67
+ updateSlot(SlotKey.Day, (_b = slotsPlaceholder === null || slotsPlaceholder === void 0 ? void 0 : slotsPlaceholder[SlotKey.Day]) !== null && _b !== void 0 ? _b : '');
63
68
  setFocus(SlotKey.Day);
64
69
  return;
65
70
  default:
66
71
  setFocus(getNextSlotKey(slotKey));
67
72
  }
68
- }, [tryToCompleteInput, isValidInput, setFocus, slotsPlaceHolder, updateSlot]);
73
+ }, [slotOrder, tryToCompleteInput, isValidInput, setFocus, getNextSlotKey, updateSlot, slotsPlaceholder]);
69
74
  const handleKeyDown = useCallback((e) => {
75
+ var _a;
70
76
  if (inputRef.current && !readonly) {
71
77
  if (e.key !== 'Tab') {
72
78
  e.preventDefault();
@@ -83,13 +89,13 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
83
89
  tryToCompleteInput();
84
90
  }
85
91
  const clickIndex = inputRef.current.selectionStart;
86
- const slotKey = getSlotKey(clickIndex);
92
+ const slotKey = getSlotKeyFromIndex(clickIndex);
87
93
  if (slotKey) {
88
94
  const value = getSlot(slotKey);
89
- const { max } = SLOTS[slotKey];
95
+ const { max } = slotsInfo[slotKey];
90
96
  const numberValue = Number(value) || 0;
91
97
  if (e.key === 'ArrowRight') {
92
- if (isAllSelected() || slotKey === SlotKey.Year) {
98
+ if (isAllSelected() || slotKey === slotOrder[slotOrder.length - 1]) {
93
99
  inputRef.current.selectionStart = inputRef.current.value.length;
94
100
  return;
95
101
  }
@@ -103,10 +109,10 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
103
109
  if (e.key === 'Backspace') {
104
110
  if (isAllSelected()) {
105
111
  inputRef.current.value = mask;
106
- setFocus(SlotKey.Day);
112
+ setFocus(focusSlotKey);
107
113
  }
108
114
  else {
109
- updateSlot(slotKey, slotsPlaceHolder[slotKey]);
115
+ updateSlot(slotKey, (_a = slotsPlaceholder[slotKey]) !== null && _a !== void 0 ? _a : '');
110
116
  }
111
117
  }
112
118
  if (/^\d+$/.test(e.key)) {
@@ -144,31 +150,38 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
144
150
  }
145
151
  }
146
152
  }
147
- onChange === null || onChange === void 0 ? void 0 : onChange(isLikeDate() ? inputRef.current.value : '');
153
+ const newDate = parseDate(isLikeDate() ? inputRef.current.value : '');
154
+ onChange === null || onChange === void 0 ? void 0 : onChange(newDate);
148
155
  }
149
156
  }
150
157
  }, [
151
- checkInputAndGoNext,
152
- getSlot,
153
158
  inputRef,
154
- isAllSelected,
155
- isLikeDate,
156
- mask,
157
- onChange,
158
159
  readonly,
159
- setFocus,
160
+ getSlotKeyFromIndex,
160
161
  setIsOpen,
161
- slotsPlaceHolder,
162
162
  tryToCompleteInput,
163
+ getSlot,
164
+ slotsInfo,
165
+ isLikeDate,
166
+ onChange,
167
+ isAllSelected,
168
+ slotOrder,
169
+ setFocus,
170
+ getNextSlotKey,
171
+ getPrevSlotKey,
172
+ mask,
173
+ focusSlotKey,
163
174
  updateSlot,
175
+ slotsPlaceholder,
176
+ checkInputAndGoNext,
164
177
  ]);
165
178
  const handleBlur = useCallback(() => {
166
179
  var _a;
167
180
  if (!readonly && ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value) === mask) {
168
181
  inputRef.current.value = '';
169
182
  }
170
- focusSlotRef.current = SlotKey.Day;
171
- }, [inputRef, mask, readonly]);
183
+ focusSlotRef.current = focusSlotKey;
184
+ }, [inputRef, mask, readonly, focusSlotKey]);
172
185
  return {
173
186
  handleKeyDown,
174
187
  handleChange,
@@ -0,0 +1,18 @@
1
+ import { RefObject } from 'react';
2
+ import { SlotKey } from '../../constants';
3
+ import { Mode, NoSecondsMode, TimeMode } from '../../types';
4
+ export declare function useDateFieldHelpersForMode({ inputRef, mode, }: {
5
+ inputRef: RefObject<HTMLInputElement>;
6
+ mode: Mode | TimeMode | NoSecondsMode;
7
+ }): {
8
+ isAllSelected: () => boolean;
9
+ isValidInput: () => boolean;
10
+ tryToCompleteInput: () => boolean;
11
+ getSlot: (slotKey: string) => string;
12
+ updateSlot: (slotKey: string, slotValue: number | string) => void;
13
+ setFocus: (slotKey: string) => void;
14
+ isLikeDate: () => boolean;
15
+ getNextSlotKey: (slotKey: SlotKey | undefined) => SlotKey;
16
+ getPrevSlotKey: (slotKey: SlotKey | undefined) => SlotKey;
17
+ getSlotKeyFromIndex: (index: number | null) => SlotKey | undefined;
18
+ };
@@ -0,0 +1,95 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ import { MODES, NO_SECONDS_MODE, SlotKey, SLOTS, TIME_MODES } from '../../constants';
3
+ import { getNextSlotKeyHandler, getPrevSlotKeyHandler, getSlotKeyFromIndexHandler } from '../../utils/dateFields';
4
+ export function useDateFieldHelpersForMode({ inputRef, mode, }) {
5
+ const setFocus = useCallback((slotKey) => {
6
+ if (inputRef.current) {
7
+ const { start, end } = SLOTS[mode][slotKey];
8
+ inputRef.current.setSelectionRange(start, end);
9
+ }
10
+ }, [mode, inputRef]);
11
+ const isAllSelected = useCallback(() => { var _a, _b, _c; return ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value.length) === ((_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.selectionEnd) && ((_c = inputRef.current) === null || _c === void 0 ? void 0 : _c.selectionStart) === 0; }, [inputRef]);
12
+ const getSlot = useCallback((slotKey) => {
13
+ if (inputRef.current) {
14
+ return inputRef.current.value.slice(SLOTS[mode][slotKey].start, SLOTS[mode][slotKey].end);
15
+ }
16
+ return '';
17
+ }, [mode, inputRef]);
18
+ const isLikeDate = useCallback(() => {
19
+ if (inputRef.current) {
20
+ return Object.keys(SLOTS[mode]).every(slotKey => getSlot(slotKey) && Number.isInteger(Number(getSlot(slotKey))));
21
+ }
22
+ return false;
23
+ }, [mode, getSlot, inputRef]);
24
+ const isValidInput = useCallback(() => {
25
+ const isTimeMode = Object.values(TIME_MODES).includes(mode);
26
+ if (isTimeMode) {
27
+ return true;
28
+ }
29
+ const day = parseInt(getSlot(SlotKey.Day), 10);
30
+ const month = parseInt(getSlot(SlotKey.Month), 10);
31
+ const year = parseInt(getSlot(SlotKey.Year), 10);
32
+ if (!month || !day) {
33
+ return true;
34
+ }
35
+ const date = new Date(year || /* високосный год = */ 2020, month - 1, day);
36
+ return date.getDate() === day;
37
+ }, [getSlot, mode]);
38
+ const tryToCompleteInput = useCallback(() => {
39
+ var _a;
40
+ let isCompleted;
41
+ const parsedSlotsData = Object.keys(SLOTS[mode]).reduce((res, key) => {
42
+ const slotKey = key;
43
+ res[slotKey] = parseInt(getSlot(slotKey), 10);
44
+ return res;
45
+ }, {});
46
+ const { [SlotKey.Day]: day, [SlotKey.Month]: month, [SlotKey.Year]: year, [SlotKey.Hours]: hours, [SlotKey.Minutes]: minutes, [SlotKey.Seconds]: seconds, } = parsedSlotsData;
47
+ const yearSlotMeta = SLOTS[mode][SlotKey.Year];
48
+ const isDateCompleted = Boolean(day && month && year >= (yearSlotMeta === null || yearSlotMeta === void 0 ? void 0 : yearSlotMeta.min) && year <= (yearSlotMeta === null || yearSlotMeta === void 0 ? void 0 : yearSlotMeta.max));
49
+ const isTimeCompleted = [
50
+ hours,
51
+ minutes,
52
+ ...(mode === MODES.DateTime || mode === TIME_MODES.FullTime ? [seconds] : []),
53
+ ].every(value => value !== undefined);
54
+ if (mode === MODES.DateTime || mode === NO_SECONDS_MODE) {
55
+ isCompleted = isDateCompleted && isTimeCompleted;
56
+ }
57
+ else if (mode === TIME_MODES.FullTime || mode === TIME_MODES.NoSeconds) {
58
+ isCompleted = isTimeCompleted;
59
+ }
60
+ else {
61
+ isCompleted = isDateCompleted;
62
+ }
63
+ if (isCompleted && inputRef.current) {
64
+ const lastPosition = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value.length;
65
+ inputRef.current.selectionStart = lastPosition;
66
+ inputRef.current.selectionEnd = lastPosition;
67
+ }
68
+ return isCompleted;
69
+ }, [getSlot, inputRef, mode]);
70
+ const updateSlot = useCallback((slotKey, slotValue) => {
71
+ if (inputRef.current) {
72
+ const { start, end, max } = SLOTS[mode][slotKey];
73
+ inputRef.current.value =
74
+ inputRef.current.value.slice(0, start) +
75
+ slotValue.toString().padStart(max.toString().length, '0') +
76
+ inputRef.current.value.slice(end);
77
+ setFocus(slotKey);
78
+ }
79
+ }, [inputRef, setFocus, mode]);
80
+ const getNextSlotKey = useMemo(() => getNextSlotKeyHandler(mode), [mode]);
81
+ const getPrevSlotKey = useMemo(() => getPrevSlotKeyHandler(mode), [mode]);
82
+ const getSlotKeyFromIndex = useMemo(() => getSlotKeyFromIndexHandler(mode), [mode]);
83
+ return {
84
+ isAllSelected,
85
+ isValidInput,
86
+ tryToCompleteInput,
87
+ getSlot,
88
+ updateSlot,
89
+ setFocus,
90
+ isLikeDate,
91
+ getNextSlotKey,
92
+ getPrevSlotKey,
93
+ getSlotKeyFromIndex,
94
+ };
95
+ }
@@ -1,3 +1,4 @@
1
+ export * from './dateHandlers';
1
2
  export * from './useCopyButton';
2
3
  export * from './useHideButton';
3
4
  export * from './usePostfix';
@@ -1,3 +1,4 @@
1
+ export * from './dateHandlers';
1
2
  export * from './useCopyButton';
2
3
  export * from './useHideButton';
3
4
  export * from './usePostfix';
@@ -8,6 +8,6 @@ export function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy
8
8
  active: true,
9
9
  ref: copyButtonRef,
10
10
  show: showCopyButton,
11
- render: props => (_jsx(ButtonCopyValue, Object.assign({}, props, { size: BUTTON_SIZE_MAP[size], valueToCopy: prefix + valueToCopy + postfix, onValueRequest: onValueRequest, disabled: disabled }))),
11
+ render: props => (_jsx(ButtonCopyValue, Object.assign({}, props, { size: BUTTON_SIZE_MAP[size], valueToCopy: (prefix !== null && prefix !== void 0 ? prefix : '') + valueToCopy + (postfix !== null && postfix !== void 0 ? postfix : ''), onValueRequest: onValueRequest, disabled: disabled }))),
12
12
  }), [copyButtonRef, disabled, onValueRequest, showCopyButton, size, valueToCopy, prefix, postfix]);
13
13
  }
@@ -1,7 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { DroplistProps, SelectionSingleState } from '@snack-uikit/list';
3
3
  import { ValueOf } from '@snack-uikit/utils';
4
- import { BUTTON_VARIANT, CONTAINER_VARIANT, VALIDATION_STATE } from './constants';
4
+ import { BUTTON_VARIANT, CONTAINER_VARIANT, VALIDATION_STATE } from '../constants';
5
5
  export type ValidationState = ValueOf<typeof VALIDATION_STATE>;
6
6
  export type ContainerVariant = ValueOf<typeof CONTAINER_VARIANT>;
7
7
  export type ButtonVariant = ValueOf<typeof BUTTON_VARIANT>;
@@ -0,0 +1,11 @@
1
+ import { ValueOf } from '@snack-uikit/utils';
2
+ import { MODES, NO_SECONDS_MODE, TIME_MODES } from '../constants';
3
+ export type Slot = {
4
+ start: number;
5
+ end: number;
6
+ max: number;
7
+ min: number;
8
+ };
9
+ export type Mode = ValueOf<typeof MODES>;
10
+ export type TimeMode = ValueOf<typeof TIME_MODES>;
11
+ export type NoSecondsMode = typeof NO_SECONDS_MODE;
@@ -0,0 +1,2 @@
1
+ export * from './allFields';
2
+ export * from './dateFields';
@@ -0,0 +1,2 @@
1
+ export * from './allFields';
2
+ export * from './dateFields';
@@ -0,0 +1,10 @@
1
+ import { SlotKey } from '../constants';
2
+ import { Mode, NoSecondsMode, TimeMode } from '../types';
3
+ export declare function getSlotKeyFromIndexHandler(mode: Mode | TimeMode | NoSecondsMode): (index: number | null) => SlotKey | undefined;
4
+ export declare function getNextSlotKeyHandler(mode: Mode | TimeMode | NoSecondsMode): (slotKey: SlotKey | undefined) => SlotKey;
5
+ export declare function getPrevSlotKeyHandler(mode: Mode | TimeMode | NoSecondsMode): (slotKey: SlotKey | undefined) => SlotKey;
6
+ /**
7
+ * Преобразует строковое значение поля FieldDate в тип Date
8
+ * @function helper
9
+ */
10
+ export declare function parseDate(value: string): Date | undefined;
@@ -0,0 +1,59 @@
1
+ import { SLOT_ORDER, SLOTS } from '../constants';
2
+ export function getSlotKeyFromIndexHandler(mode) {
3
+ return (index) => {
4
+ if (index !== null) {
5
+ for (const key in SLOTS[mode]) {
6
+ if (index >= SLOTS[mode][key].start && index <= SLOTS[mode][key].end) {
7
+ return key;
8
+ }
9
+ }
10
+ }
11
+ return undefined;
12
+ };
13
+ }
14
+ export function getNextSlotKeyHandler(mode) {
15
+ const order = SLOT_ORDER[mode];
16
+ return (slotKey) => {
17
+ const defaultIndex = order.length - 1;
18
+ const defaultSLot = order[defaultIndex];
19
+ const currentIndex = order.indexOf(slotKey);
20
+ return currentIndex === -1 || currentIndex === defaultIndex ? defaultSLot : order[currentIndex + 1];
21
+ };
22
+ }
23
+ export function getPrevSlotKeyHandler(mode) {
24
+ const order = SLOT_ORDER[mode];
25
+ return (slotKey) => {
26
+ const defaultIndex = 0;
27
+ const defaultSLot = order[defaultIndex];
28
+ const currentIndex = order.indexOf(slotKey);
29
+ return currentIndex === -1 || currentIndex === defaultIndex ? defaultSLot : order[currentIndex - 1];
30
+ };
31
+ }
32
+ const DATE_STUB = new Date();
33
+ /**
34
+ * Преобразует строковое значение поля FieldDate в тип Date
35
+ * @function helper
36
+ */
37
+ export function parseDate(value) {
38
+ if (!value) {
39
+ return undefined;
40
+ }
41
+ const splittedValue = value.split(', ');
42
+ const date = splittedValue[0];
43
+ let time = splittedValue[1];
44
+ let [day, month, year] = date.split('.').map(Number);
45
+ month -= 1;
46
+ if (date.includes(':')) {
47
+ time = date;
48
+ }
49
+ if (time) {
50
+ if (isNaN(year) || isNaN(month) || isNaN(day)) {
51
+ year = DATE_STUB.getFullYear();
52
+ month = DATE_STUB.getMonth();
53
+ day = DATE_STUB.getDay();
54
+ }
55
+ const [hours = 0, minutes = 0, seconds = 0] = time.split(':').map(str => { var _a; return (_a = Number(str)) !== null && _a !== void 0 ? _a : 0; });
56
+ return new Date(year, month, day, hours, minutes, seconds);
57
+ }
58
+ return new Date(year, month, day);
59
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Fields",
7
- "version": "0.30.0",
7
+ "version": "0.32.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -36,20 +36,20 @@
36
36
  "license": "Apache-2.0",
37
37
  "scripts": {},
38
38
  "dependencies": {
39
- "@snack-uikit/button": "0.18.0",
40
- "@snack-uikit/calendar": "0.9.0",
41
- "@snack-uikit/color-picker": "0.2.0",
42
- "@snack-uikit/divider": "3.1.0",
43
- "@snack-uikit/dropdown": "0.3.0",
44
- "@snack-uikit/icons": "0.23.0",
45
- "@snack-uikit/input-private": "4.1.0",
46
- "@snack-uikit/list": "0.19.0",
47
- "@snack-uikit/scroll": "0.7.0",
48
- "@snack-uikit/skeleton": "0.4.0",
49
- "@snack-uikit/slider": "0.2.0",
50
- "@snack-uikit/tag": "0.10.0",
51
- "@snack-uikit/tooltip": "0.14.0",
52
- "@snack-uikit/truncate-string": "0.5.0",
39
+ "@snack-uikit/button": "0.19.1",
40
+ "@snack-uikit/calendar": "0.11.0",
41
+ "@snack-uikit/color-picker": "0.3.1",
42
+ "@snack-uikit/divider": "3.2.0",
43
+ "@snack-uikit/dropdown": "0.4.0",
44
+ "@snack-uikit/icons": "0.24.0",
45
+ "@snack-uikit/input-private": "4.2.1",
46
+ "@snack-uikit/list": "0.21.0",
47
+ "@snack-uikit/scroll": "0.9.0",
48
+ "@snack-uikit/skeleton": "0.5.0",
49
+ "@snack-uikit/slider": "0.3.1",
50
+ "@snack-uikit/tag": "0.11.1",
51
+ "@snack-uikit/tooltip": "0.15.0",
52
+ "@snack-uikit/truncate-string": "0.6.0",
53
53
  "@snack-uikit/utils": "3.5.0",
54
54
  "classnames": "2.3.2",
55
55
  "copy-to-clipboard": "3.3.3",
@@ -65,5 +65,5 @@
65
65
  "peerDependencies": {
66
66
  "@snack-uikit/locale": "*"
67
67
  },
68
- "gitHead": "62cc21d8606a61a78f80e3a7455b20d6f38474fa"
68
+ "gitHead": "b7163c6f939105eb34cabec64c9e983ac7958c26"
69
69
  }