@astral/ui 4.51.0 → 4.52.1

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 (89) hide show
  1. package/components/DashboardContext/DashboardContext.d.ts +2 -0
  2. package/components/DashboardContext/DashboardContext.js +2 -0
  3. package/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.d.ts +2 -2
  4. package/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.js +4 -1
  5. package/components/DashboardLayout/DashboardLayout.d.ts +1 -1
  6. package/components/DashboardLayout/DashboardLayout.js +2 -2
  7. package/components/DashboardLayout/Header/Header.js +28 -3
  8. package/components/DashboardLayout/Header/constants.d.ts +5 -1
  9. package/components/DashboardLayout/Header/constants.js +5 -1
  10. package/components/DashboardLayout/Header/styles.d.ts +4 -3
  11. package/components/DashboardLayout/Header/styles.js +66 -24
  12. package/components/DashboardLayout/Header/useLogic/useLogic.d.ts +4 -1
  13. package/components/DashboardLayout/Header/useLogic/useLogic.js +16 -11
  14. package/components/DashboardLayout/types.d.ts +5 -0
  15. package/components/DashboardSidebar/DashboardSidebar.js +17 -2
  16. package/components/DashboardSidebar/constants.d.ts +1 -0
  17. package/components/DashboardSidebar/constants.js +1 -0
  18. package/components/DashboardSidebar/styles.js +1 -1
  19. package/components/DashboardSidebar/useLogic/useLogic.d.ts +2 -1
  20. package/components/DashboardSidebar/useLogic/useLogic.js +5 -6
  21. package/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.d.ts +2 -0
  22. package/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.js +2 -1
  23. package/components/DatePicker/hooks/useMaskedValue/useMaskedValue.d.ts +4 -0
  24. package/components/DatePicker/hooks/useMaskedValue/useMaskedValue.js +37 -8
  25. package/components/DatePicker/useLogic/useLogic.d.ts +1 -0
  26. package/components/DatePicker/useLogic/useLogic.js +19 -13
  27. package/components/DateRangePicker/useLogic/useLogic.d.ts +2 -0
  28. package/components/DateRangePicker/useLogic/useLogic.js +27 -3
  29. package/components/DateRangePicker/useLogic/utils/index.d.ts +0 -1
  30. package/components/DateRangePicker/useLogic/utils/index.js +0 -1
  31. package/components/MenuOrganization/OrganizationButton/OrganizationButton.js +1 -1
  32. package/components/MenuOrganization/constants.d.ts +1 -0
  33. package/components/MenuOrganization/constants.js +1 -0
  34. package/components/Profile/Profile.js +1 -1
  35. package/components/Profile/constants.d.ts +3 -0
  36. package/components/Profile/constants.js +3 -0
  37. package/components/utils/date/format/index.d.ts +1 -0
  38. package/components/utils/date/format/index.js +1 -0
  39. package/{node/components/DateRangePicker/useLogic/utils → components/utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.d.ts +1 -1
  40. package/components/utils/date/format/parseDate/parseDate.d.ts +1 -0
  41. package/components/utils/date/format/parseDate/parseDate.js +42 -13
  42. package/node/components/DashboardContext/DashboardContext.d.ts +2 -0
  43. package/node/components/DashboardContext/DashboardContext.js +2 -0
  44. package/node/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.d.ts +2 -2
  45. package/node/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.js +4 -1
  46. package/node/components/DashboardLayout/DashboardLayout.d.ts +1 -1
  47. package/node/components/DashboardLayout/DashboardLayout.js +2 -2
  48. package/node/components/DashboardLayout/Header/Header.js +27 -2
  49. package/node/components/DashboardLayout/Header/constants.d.ts +5 -1
  50. package/node/components/DashboardLayout/Header/constants.js +5 -1
  51. package/node/components/DashboardLayout/Header/styles.d.ts +4 -3
  52. package/node/components/DashboardLayout/Header/styles.js +74 -32
  53. package/node/components/DashboardLayout/Header/useLogic/useLogic.d.ts +4 -1
  54. package/node/components/DashboardLayout/Header/useLogic/useLogic.js +15 -10
  55. package/node/components/DashboardLayout/types.d.ts +5 -0
  56. package/node/components/DashboardSidebar/DashboardSidebar.js +17 -2
  57. package/node/components/DashboardSidebar/constants.d.ts +1 -0
  58. package/node/components/DashboardSidebar/constants.js +1 -0
  59. package/node/components/DashboardSidebar/styles.js +1 -1
  60. package/node/components/DashboardSidebar/useLogic/useLogic.d.ts +2 -1
  61. package/node/components/DashboardSidebar/useLogic/useLogic.js +4 -5
  62. package/node/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.d.ts +2 -0
  63. package/node/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.js +2 -1
  64. package/node/components/DatePicker/hooks/useMaskedValue/useMaskedValue.d.ts +4 -0
  65. package/node/components/DatePicker/hooks/useMaskedValue/useMaskedValue.js +35 -6
  66. package/node/components/DatePicker/useLogic/useLogic.d.ts +1 -0
  67. package/node/components/DatePicker/useLogic/useLogic.js +19 -13
  68. package/node/components/DateRangePicker/useLogic/useLogic.d.ts +2 -0
  69. package/node/components/DateRangePicker/useLogic/useLogic.js +28 -4
  70. package/node/components/DateRangePicker/useLogic/utils/index.d.ts +0 -1
  71. package/node/components/DateRangePicker/useLogic/utils/index.js +0 -1
  72. package/node/components/MenuOrganization/OrganizationButton/OrganizationButton.js +1 -1
  73. package/node/components/MenuOrganization/constants.d.ts +1 -0
  74. package/node/components/MenuOrganization/constants.js +1 -0
  75. package/node/components/Profile/Profile.js +1 -1
  76. package/node/components/Profile/constants.d.ts +3 -0
  77. package/node/components/Profile/constants.js +3 -0
  78. package/node/components/utils/date/format/index.d.ts +1 -0
  79. package/node/components/utils/date/format/index.js +1 -0
  80. package/{components/DateRangePicker/useLogic/utils → node/components/utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.d.ts +1 -1
  81. package/node/components/utils/date/format/parseDate/parseDate.d.ts +1 -0
  82. package/node/components/utils/date/format/parseDate/parseDate.js +45 -13
  83. package/package.json +1 -1
  84. /package/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.d.ts +0 -0
  85. /package/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.js +0 -0
  86. /package/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.js +0 -0
  87. /package/node/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.d.ts +0 -0
  88. /package/node/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.js +0 -0
  89. /package/node/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.js +0 -0
@@ -4,7 +4,6 @@ import { usePopover } from '../../usePopover';
4
4
  import { useViewportType } from '../../useViewportType';
5
5
  import { DEFAULT_DATE_MASK } from '../constants';
6
6
  import { useDatePickerOptions } from '../hooks/useDatePickerOptions';
7
- import { useMaskedValue } from '../hooks/useMaskedValue';
8
7
  import { DEFAULT_MAX_DATE, DEFAULT_MIN_DATE } from '../MinMaxDateContext';
9
8
  export const useLogic = ({ label, value, maxDate = DEFAULT_MAX_DATE, minDate = DEFAULT_MIN_DATE, mask = DEFAULT_DATE_MASK, onOpen, onClose, onBlur, onChange, forwardedRef, }) => {
10
9
  const ref = useForwardedRef(forwardedRef);
@@ -12,21 +11,11 @@ export const useLogic = ({ label, value, maxDate = DEFAULT_MAX_DATE, minDate = D
12
11
  const { isOpen, actions } = usePopover();
13
12
  const { open, close } = actions;
14
13
  const { isMobile } = useViewportType();
15
- const { maskedValue } = useMaskedValue({
16
- currentValue: value,
17
- mask,
18
- onChangeValue: onChange,
19
- });
20
14
  const isTitleShow = isMobile && typeof label === 'string';
21
15
  const handleOpen = (event) => {
22
16
  onOpen?.();
23
17
  open(event);
24
18
  };
25
- const handleClose = () => {
26
- onBlur?.();
27
- onClose?.();
28
- close();
29
- };
30
19
  const handleDayPick = (date) => {
31
20
  if (isMobile) {
32
21
  setSelectedDate(date);
@@ -39,7 +28,7 @@ export const useLogic = ({ label, value, maxDate = DEFAULT_MAX_DATE, minDate = D
39
28
  onChange?.(date);
40
29
  }
41
30
  };
42
- const { onAccept, inputProps: calculatedInputProps, pickerProps, } = useDatePickerOptions({
31
+ const { onAccept, inputProps: calculatedInputProps, pickerProps, onMaskedValueBlur, } = useDatePickerOptions({
43
32
  currentValue: value,
44
33
  maxDate,
45
34
  minDate,
@@ -47,6 +36,22 @@ export const useLogic = ({ label, value, maxDate = DEFAULT_MAX_DATE, minDate = D
47
36
  onDatePick: handleDayPick,
48
37
  onChange: handleChange,
49
38
  });
39
+ /** Blur: неполный ввод -Invalid Date в onChange (при isMobile onChange не шлём), потом внешний onBlur. */
40
+ const flushMaskedValueAndCallOnBlur = () => {
41
+ onMaskedValueBlur();
42
+ onBlur?.();
43
+ };
44
+ function handleClose() {
45
+ flushMaskedValueAndCallOnBlur();
46
+ onClose?.();
47
+ close();
48
+ }
49
+ const handleInputBlur = () => {
50
+ if (isOpen) {
51
+ return;
52
+ }
53
+ flushMaskedValueAndCallOnBlur();
54
+ };
50
55
  const handleConfirm = () => {
51
56
  onChange?.(selectedDate);
52
57
  handleClose();
@@ -58,7 +63,8 @@ export const useLogic = ({ label, value, maxDate = DEFAULT_MAX_DATE, minDate = D
58
63
  title: isTitleShow ? label : undefined,
59
64
  };
60
65
  const DatePickerInputProps = {
61
- value: isMobile ? maskedValue : calculatedInputProps.value,
66
+ value: calculatedInputProps.value,
67
+ onBlur: handleInputBlur,
62
68
  };
63
69
  const confirmButtonProps = {
64
70
  onClick: handleConfirm,
@@ -7,12 +7,14 @@ export declare const useLogic: ({ value, minDate, maxDate, mask, onChange, onOpe
7
7
  ref: import("react").RefObject<HTMLInputElement | null>;
8
8
  value: string;
9
9
  onAccept: (_: string, maskRef: IMask.InputMask<IMask.AnyMaskedOptions>) => void;
10
+ onBlur: () => void;
10
11
  onClick: (e: SyntheticEvent) => void;
11
12
  };
12
13
  endDatePickerInputProps: {
13
14
  ref: import("react").RefObject<HTMLInputElement | null>;
14
15
  value: string;
15
16
  onAccept: (_: string, maskRef: IMask.InputMask<IMask.AnyMaskedOptions>) => void;
17
+ onBlur: () => void;
16
18
  onClick: (e: SyntheticEvent) => void;
17
19
  };
18
20
  popoverHoveredContextProviderProps: {
@@ -2,8 +2,9 @@ import { useEffect, useRef, useState, } from 'react';
2
2
  import { DEFAULT_DATE_MASK, DEFAULT_MAX_DATE, DEFAULT_MIN_DATE, useMaskedValue, useSelectedBaseDate, } from '../../DatePicker';
3
3
  import { useForwardedRef } from '../../useForwardedRef';
4
4
  import { usePopover } from '../../usePopover';
5
+ import { isMaskedDateSyntacticallyComplete } from '../../utils/date';
5
6
  import { useBaseRangeDates } from './hooks';
6
- import { getBoundaryDate, isMaskedDateSyntacticallyComplete } from './utils';
7
+ import { getBoundaryDate } from './utils';
7
8
  export const useLogic = ({ value, minDate = DEFAULT_MIN_DATE, maxDate = DEFAULT_MAX_DATE, mask = DEFAULT_DATE_MASK, onChange, onOpen, onClose, onBlur, }, forwardedRef) => {
8
9
  const ref = useForwardedRef(forwardedRef);
9
10
  const startInputRef = useRef(null);
@@ -65,12 +66,12 @@ export const useLogic = ({ value, minDate = DEFAULT_MIN_DATE, maxDate = DEFAULT_
65
66
  }
66
67
  onChange?.({ ...value, end: endDateValue });
67
68
  };
68
- const { maskedValue: startMaskedValue, onMaskedValueChange: onMaskedStartValueChange, onMaskedDateChange: onMaskedStartDateChange, } = useMaskedValue({
69
+ const { maskedValue: startMaskedValue, onMaskedValueChange: onMaskedStartValueChange, onMaskedValueBlur: onMaskedStartValueBlur, onMaskedDateChange: onMaskedStartDateChange, } = useMaskedValue({
69
70
  currentValue: value?.start,
70
71
  mask,
71
72
  onChangeValue: handleChangeStartDate,
72
73
  });
73
- const { maskedValue: endMaskedValue, onMaskedValueChange: onMaskedEndValueChange, onMaskedDateChange: onMaskedEndDateChange, } = useMaskedValue({
74
+ const { maskedValue: endMaskedValue, onMaskedValueChange: onMaskedEndValueChange, onMaskedValueBlur: onMaskedEndValueBlur, onMaskedDateChange: onMaskedEndDateChange, } = useMaskedValue({
74
75
  currentValue: value?.end,
75
76
  mask,
76
77
  onChangeValue: handleChangeEndDate,
@@ -79,11 +80,32 @@ export const useLogic = ({ value, minDate = DEFAULT_MIN_DATE, maxDate = DEFAULT_
79
80
  onOpen?.();
80
81
  open(event);
81
82
  };
83
+ const flushActiveMaskedValueOnClose = () => {
84
+ if (activeInput === 'startDate') {
85
+ onMaskedStartValueBlur();
86
+ }
87
+ if (activeInput === 'endDate') {
88
+ onMaskedEndValueBlur();
89
+ }
90
+ };
82
91
  const handleClose = () => {
92
+ flushActiveMaskedValueOnClose();
83
93
  onBlur?.();
84
94
  onClose?.();
85
95
  close();
86
96
  };
97
+ const handleStartInputBlur = () => {
98
+ if (isOpen) {
99
+ return;
100
+ }
101
+ onMaskedStartValueBlur();
102
+ };
103
+ const handleEndInputBlur = () => {
104
+ if (isOpen) {
105
+ return;
106
+ }
107
+ onMaskedEndValueBlur();
108
+ };
87
109
  const handleClickStartInput = (e) => {
88
110
  setActiveInput('startDate');
89
111
  startInputRef.current?.focus();
@@ -138,12 +160,14 @@ export const useLogic = ({ value, minDate = DEFAULT_MIN_DATE, maxDate = DEFAULT_
138
160
  ref: startInputRef,
139
161
  value: startMaskedValue,
140
162
  onAccept: handleAcceptStart,
163
+ onBlur: handleStartInputBlur,
141
164
  onClick: handleClickStartInput,
142
165
  },
143
166
  endDatePickerInputProps: {
144
167
  ref: endInputRef,
145
168
  value: endMaskedValue,
146
169
  onAccept: handleAcceptEnd,
170
+ onBlur: handleEndInputBlur,
147
171
  onClick: handleClickEndInput,
148
172
  },
149
173
  popoverHoveredContextProviderProps: {
@@ -1,2 +1 @@
1
1
  export * from './getBoundaryDate';
2
- export * from './isMaskedDateSyntacticallyComplete';
@@ -1,2 +1 @@
1
1
  export * from './getBoundaryDate';
2
- export * from './isMaskedDateSyntacticallyComplete';
@@ -13,7 +13,7 @@ export const OrganizationButton = forwardRef(({ onClick, isOpen, currentOrganiza
13
13
  });
14
14
  const renderButton = () => (_jsx(StyledButton, { ref: ref, variant: "text", disabled: isDisabled, onClick: onClick, className: menuOrganizationClassnames.button, endIcon: _jsx(StyledChevron, { isActive: isOpen, width: 24, height: 24 }), children: renderPreview ? (renderPreview(currentOrganization, {
15
15
  className: hidePersonalDataClassname,
16
- })) : (_jsxs(Container, { className: hidePersonalDataClassname, children: [_jsx(OverflowTypography, { variant: "h6", component: "div", children: name }), _jsxs(OrganizationData, { children: [_jsxs(StyledTypography, { "$isDisabled": isDisabled, variant: "caption", color: "textSecondary", children: ["\u0418\u041D\u041D ", inn] }), kpp && (_jsxs(StyledTypography, { "$isDisabled": isDisabled, variant: "caption", color: "textSecondary", children: ["\u041A\u041F\u041F ", kpp] }))] })] })) }));
16
+ })) : (_jsxs(Container, { className: hidePersonalDataClassname, children: [_jsx(OverflowTypography, { variant: "h6", component: "div", children: name }), _jsxs(OrganizationData, { className: menuOrganizationClassnames.organizationData, children: [_jsxs(StyledTypography, { "$isDisabled": isDisabled, variant: "caption", color: "textSecondary", children: ["\u0418\u041D\u041D ", inn] }), kpp && (_jsxs(StyledTypography, { "$isDisabled": isDisabled, variant: "caption", color: "textSecondary", children: ["\u041A\u041F\u041F ", kpp] }))] })] })) }));
17
17
  if (isDisabled && disabledReason) {
18
18
  return (_jsx(Tooltip, { title: disabledReason, withoutContainer: false, placement: "bottom", children: renderButton() }));
19
19
  }
@@ -5,4 +5,5 @@ export declare const menuOrganizationClassnames: {
5
5
  root: string;
6
6
  errorPlaceholder: string;
7
7
  button: string;
8
+ organizationData: string;
8
9
  };
@@ -6,4 +6,5 @@ export const menuOrganizationClassnames = {
6
6
  root: createUIKitClassname('menu-organization'),
7
7
  errorPlaceholder: createUIKitClassname('menu-organization__error-placeholder'),
8
8
  button: createUIKitClassname('menu-organization__button'),
9
+ organizationData: createUIKitClassname('menu-organization__organization-data'),
9
10
  };
@@ -23,7 +23,7 @@ export const Profile = (props) => {
23
23
  if (isLoading) {
24
24
  return _jsx(ProfileSkeleton, {});
25
25
  }
26
- return (_jsxs(_Fragment, { children: [_jsx(ClickAwayListener, { onClickAway: handleCloseMenu, children: _jsxs(ProfileRoot, { ref: anchorRef, variant: "text", onClick: handleOpenMenu, children: [_jsx(StyledAvatar, { ...avatar }), _jsxs(User, { children: [_jsxs(Credentials, { className: hidePersonalDataClassname, children: [_jsx(Typography, { variant: "body1", className: profileClassnames.credentials, children: displayName }), _jsx(Typography, { variant: "caption", color: "textSecondary", className: profileClassnames.credentials, children: annotation })] }), _jsx(StyledChevron, { isActive: open })] })] }) }), Menu ? (_jsx(Menu, { open: open, anchorEl: anchorRef.current, onClose: handleCloseMenu, anchorOrigin: {
26
+ return (_jsxs(_Fragment, { children: [_jsx(ClickAwayListener, { onClickAway: handleCloseMenu, children: _jsxs(ProfileRoot, { ref: anchorRef, variant: "text", onClick: handleOpenMenu, className: profileClassnames.button, children: [_jsx(StyledAvatar, { ...avatar, className: profileClassnames.avatar }), _jsxs(User, { className: profileClassnames.user, children: [_jsxs(Credentials, { className: hidePersonalDataClassname, children: [_jsx(Typography, { variant: "body1", className: profileClassnames.credentials, children: displayName }), _jsx(Typography, { variant: "caption", color: "textSecondary", className: profileClassnames.credentials, children: annotation })] }), _jsx(StyledChevron, { isActive: open })] })] }) }), Menu ? (_jsx(Menu, { open: open, anchorEl: anchorRef.current, onClose: handleCloseMenu, anchorOrigin: {
27
27
  vertical: 'bottom',
28
28
  horizontal: 'right',
29
29
  }, transformOrigin: {
@@ -1,3 +1,6 @@
1
1
  export declare const profileClassnames: {
2
2
  credentials: string;
3
+ button: string;
4
+ avatar: string;
5
+ user: string;
3
6
  };
@@ -1,4 +1,7 @@
1
1
  import { createUIKitClassname } from '../utils/createUIKitClassname';
2
2
  export const profileClassnames = {
3
3
  credentials: createUIKitClassname('profile__credentials'),
4
+ button: createUIKitClassname('profile__button'),
5
+ avatar: createUIKitClassname('profile__avatar'),
6
+ user: createUIKitClassname('profile__user'),
4
7
  };
@@ -1,3 +1,4 @@
1
1
  export * from './formatDate';
2
+ export * from './isMaskedDateSyntacticallyComplete';
2
3
  export * from './maskDate';
3
4
  export * from './parseDate';
@@ -1,3 +1,4 @@
1
1
  export * from './formatDate';
2
+ export * from './isMaskedDateSyntacticallyComplete';
2
3
  export * from './maskDate';
3
4
  export * from './parseDate';
@@ -1,4 +1,4 @@
1
- import { type DateMask } from '../../../../utils/date/format';
1
+ import { type DateMask } from '../maskDate';
2
2
  /**
3
3
  * Все ли части строки по маске заполнены цифрами полностью (без промежуточных состояний IMask).
4
4
  */
@@ -1,5 +1,6 @@
1
1
  import { type DateMask } from '../maskDate';
2
2
  /**
3
3
  * утилита конвертации строковой даты созданной по маске обратно в Date
4
+ * Строгий разбор UTC через `dayjs` + `customParseFormat`; при невалидной строке — Invalid Date
4
5
  */
5
6
  export declare const parseDate: (date: string, mask: DateMask, separator?: string) => Date;
@@ -1,21 +1,50 @@
1
- import { buildIsoDate, } from '../../buildIsoDate';
1
+ import dayjs from 'dayjs';
2
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
3
+ import utc from 'dayjs/plugin/utc';
2
4
  import { DateMaskElements } from '../maskDate';
3
- const orderMap = {
4
- [DateMaskElements.Year]: 'year',
5
- [DateMaskElements.Month]: 'month',
6
- [DateMaskElements.Day]: 'day',
7
- [DateMaskElements.Hour]: 'hour',
8
- [DateMaskElements.Minute]: 'minute',
9
- [DateMaskElements.Second]: 'second',
5
+ dayjs.extend(customParseFormat);
6
+ dayjs.extend(utc);
7
+ /**
8
+ * Токен маски UI → литерал формата `dayjs` (strict UTC).
9
+ * В маске час — `hh`, в дате используются сутки 0–23 как в `formatDate` (UTC), поэтому `HH`.
10
+ */
11
+ const maskElementToDayjs = {
12
+ [DateMaskElements.Day]: 'DD',
13
+ [DateMaskElements.Month]: 'MM',
14
+ [DateMaskElements.Year]: 'YYYY',
15
+ [DateMaskElements.Hour]: 'HH',
16
+ [DateMaskElements.Minute]: 'mm',
17
+ [DateMaskElements.Second]: 'ss',
18
+ };
19
+ const buildDayjsFormat = (mask, separator) => {
20
+ const parts = mask.split(separator);
21
+ const tokens = [];
22
+ for (const part of parts) {
23
+ const t = maskElementToDayjs[part];
24
+ if (t == null) {
25
+ return null;
26
+ }
27
+ tokens.push(t);
28
+ }
29
+ return tokens.join(separator);
10
30
  };
11
31
  /**
12
32
  * утилита конвертации строковой даты созданной по маске обратно в Date
33
+ * Строгий разбор UTC через `dayjs` + `customParseFormat`; при невалидной строке — Invalid Date
13
34
  */
14
35
  export const parseDate = (date, mask, separator = '.') => {
15
36
  const dateArr = date.split(separator);
16
- const options = { year: 1900 };
17
- mask.split('.').forEach((element, index) => {
18
- options[orderMap[element]] = parseInt(dateArr[index]);
19
- });
20
- return buildIsoDate(options);
37
+ const maskSplit = mask.split(separator);
38
+ if (dateArr.length !== maskSplit.length) {
39
+ return new Date(Number.NaN);
40
+ }
41
+ const format = buildDayjsFormat(mask, separator);
42
+ if (format == null) {
43
+ return new Date(Number.NaN);
44
+ }
45
+ const parsed = dayjs.utc(date, format, true);
46
+ if (!parsed.isValid()) {
47
+ return new Date(Number.NaN);
48
+ }
49
+ return parsed.toDate();
21
50
  };
@@ -1,10 +1,12 @@
1
1
  import { type RefObject } from 'react';
2
2
  export type DashboardContextProps = {
3
3
  isFocusedMode: boolean;
4
+ mobileHeaderPriorityFeature: 'profile' | 'menuOrg';
4
5
  setAlertElement?: (element: HTMLElement | null) => void;
5
6
  alertHeight: number;
6
7
  isLoading: boolean;
7
8
  hasMenuOrganizationRef: RefObject<boolean | null>;
9
+ hasProfileRef: RefObject<boolean | null>;
8
10
  setFocusedMode: (isFocusedMode: boolean) => void;
9
11
  };
10
12
  export declare const DashboardContext: import("react").Context<DashboardContextProps>;
@@ -4,8 +4,10 @@ exports.DashboardContext = void 0;
4
4
  const react_1 = require("react");
5
5
  exports.DashboardContext = (0, react_1.createContext)({
6
6
  isFocusedMode: false,
7
+ mobileHeaderPriorityFeature: 'menuOrg',
7
8
  alertHeight: 0,
8
9
  isLoading: false,
9
10
  hasMenuOrganizationRef: (0, react_1.createRef)(),
11
+ hasProfileRef: (0, react_1.createRef)(),
10
12
  setFocusedMode: () => undefined,
11
13
  });
@@ -1,8 +1,8 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type DashboardContextProps } from '../DashboardContext';
3
- type Props = Pick<DashboardContextProps, 'isFocusedMode'> & {
3
+ type Props = Pick<DashboardContextProps, 'isFocusedMode' | 'mobileHeaderPriorityFeature'> & {
4
4
  children: ReactNode;
5
5
  isLoading: boolean;
6
6
  };
7
- export declare const DashboardContextProvider: ({ children, isFocusedMode, isLoading, }: Props) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const DashboardContextProvider: ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, }: Props) => import("react/jsx-runtime").JSX.Element;
8
8
  export {};
@@ -4,11 +4,12 @@ exports.DashboardContextProvider = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const DashboardContext_1 = require("../DashboardContext");
7
- const DashboardContextProvider = ({ children, isFocusedMode, isLoading, }) => {
7
+ const DashboardContextProvider = ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, }) => {
8
8
  const [alertElement, setAlertElement] = (0, react_1.useState)(null);
9
9
  const [alertHeight, setAlertHeight] = (0, react_1.useState)(0);
10
10
  const [isFocusedModeInternal, setFocusedMode] = (0, react_1.useState)(isFocusedMode);
11
11
  const hasMenuOrganizationRef = (0, react_1.useRef)(false);
12
+ const hasProfileRef = (0, react_1.useRef)(false);
12
13
  (0, react_1.useEffect)(() => {
13
14
  if (isFocusedMode !== isFocusedModeInternal) {
14
15
  setFocusedMode(isFocusedMode);
@@ -30,9 +31,11 @@ const DashboardContextProvider = ({ children, isFocusedMode, isLoading, }) => {
30
31
  }, [alertElement]);
31
32
  return ((0, jsx_runtime_1.jsx)(DashboardContext_1.DashboardContext.Provider, { value: {
32
33
  isFocusedMode: isFocusedModeInternal,
34
+ mobileHeaderPriorityFeature,
33
35
  setAlertElement,
34
36
  alertHeight,
35
37
  isLoading,
38
+ hasProfileRef,
36
39
  hasMenuOrganizationRef,
37
40
  setFocusedMode,
38
41
  }, children: children }));
@@ -4,7 +4,7 @@ import { type DashboardLayoutProps } from './types';
4
4
  * Общий Layout приложения
5
5
  */
6
6
  export declare const DashboardLayout: {
7
- ({ children, isFocusedMode, isLoading, }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
7
+ ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
8
8
  Header: import("react").ForwardRefExoticComponent<import("./Header").HeaderProps & import("react").RefAttributes<HTMLDivElement>>;
9
9
  Sidebar: import("react").ForwardRefExoticComponent<import("../DashboardSidebar").DashboardSidebarProps & import("react").RefAttributes<HTMLBaseElement>>;
10
10
  Main: import("react").ForwardRefExoticComponent<import("./Main").MainProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -10,8 +10,8 @@ const Main_1 = require("./Main");
10
10
  /**
11
11
  * Общий Layout приложения
12
12
  */
13
- const DashboardLayout = ({ children, isFocusedMode = false, isLoading = false, }) => {
14
- return ((0, jsx_runtime_1.jsx)(DashboardContext_1.DashboardContextProvider, { isFocusedMode: isFocusedMode, isLoading: isLoading, children: (0, jsx_runtime_1.jsx)(DashboardWrapper_1.DashboardWrapper, { children: children }) }));
13
+ const DashboardLayout = ({ children, isFocusedMode = false, isLoading = false, mobileHeaderPriorityFeature = 'menuOrg', }) => {
14
+ return ((0, jsx_runtime_1.jsx)(DashboardContext_1.DashboardContextProvider, { isFocusedMode: isFocusedMode, isLoading: isLoading, mobileHeaderPriorityFeature: mobileHeaderPriorityFeature, children: (0, jsx_runtime_1.jsx)(DashboardWrapper_1.DashboardWrapper, { children: children }) }));
15
15
  };
16
16
  exports.DashboardLayout = DashboardLayout;
17
17
  exports.DashboardLayout.Header = Header_1.Header;
@@ -9,15 +9,40 @@ const QuitOutlineMd_1 = require("../../../icons/QuitOutlineMd");
9
9
  const Button_1 = require("../../Button");
10
10
  const Product_1 = require("../../Product");
11
11
  const Profile_1 = require("../../Profile");
12
+ const cva_1 = require("../../utils/cva");
12
13
  const getInertProps_1 = require("../../utils/getInertProps");
13
14
  const constants_1 = require("./constants");
14
15
  const styles_1 = require("./styles");
15
16
  const useLogic_1 = require("./useLogic");
17
+ const headerPriorityFeature = (0, cva_1.cva)('', {
18
+ variants: {
19
+ feature: {
20
+ menuOrg: constants_1.dashboardLayoutHeaderClassnames.priorityFeatureMenuOrg,
21
+ profile: constants_1.dashboardLayoutHeaderClassnames.priorityFeatureProfile,
22
+ },
23
+ isPinned: {
24
+ true: constants_1.dashboardLayoutHeaderClassnames.mobileSidebarPriorityFeatureVisible,
25
+ },
26
+ featureInSidebar: {
27
+ true: constants_1.dashboardLayoutHeaderClassnames.featureInSidebar,
28
+ },
29
+ },
30
+ });
16
31
  /**
17
32
  * Основной header приложения
18
33
  */
19
34
  exports.Header = (0, react_1.forwardRef)((props, ref) => {
20
35
  const { productSwitcher: ProductSwitcher, product, profile, menuOrganization, children, } = props;
21
- const { isShowExitButton, isShowProfile, isFocusedMode, isMobile, collapsedIn, onToggleSidebar, isLoading, alertHeight, menuOrganizationClassnames, } = (0, useLogic_1.useLogic)(props);
22
- return ((0, jsx_runtime_1.jsx)(styles_1.HeaderRoot, { ref: ref, "$isFocusedMode": isFocusedMode, ...(0, getInertProps_1.getInertProps)(!isMobile && isFocusedMode), className: constants_1.dashboardLayoutHeaderClassnames.root, children: (0, jsx_runtime_1.jsxs)(styles_1.HeaderContent, { children: [(0, jsx_runtime_1.jsx)(styles_1.MobileSidebarTogglerWrapper, { className: constants_1.dashboardLayoutHeaderClassnames.mobileSidebarButton, children: (0, jsx_runtime_1.jsx)(Button_1.Button, { startIcon: collapsedIn ? (0, jsx_runtime_1.jsx)(CrossOutlineMd_1.CrossOutlineMd, {}) : (0, jsx_runtime_1.jsx)(MenuOnOutlineMd_1.MenuOnOutlineMd, {}), variant: "text", onClick: () => onToggleSidebar(), title: "\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u043E\u0435 \u043C\u0435\u043D\u044E" }) }), (0, jsx_runtime_1.jsxs)(styles_1.HeaderSection, { children: [ProductSwitcher && ((0, jsx_runtime_1.jsx)(styles_1.ProductSwitcherWrapper, { children: (0, jsx_runtime_1.jsx)(ProductSwitcher, {}) })), (0, jsx_runtime_1.jsx)(Product_1.Product, { ...product })] }), (0, jsx_runtime_1.jsxs)(styles_1.HeaderContentSection, { children: [children, menuOrganization && ((0, jsx_runtime_1.jsx)(styles_1.MenuOrganizationWrapper, { className: menuOrganizationClassnames, "$alertHeight": alertHeight, children: menuOrganization() })), profile && ((0, jsx_runtime_1.jsx)(styles_1.ProfileWrapper, { "$isShow": isShowProfile, children: (0, jsx_runtime_1.jsx)(Profile_1.Profile, { isLoading: isLoading, ...profile }) })), (0, jsx_runtime_1.jsx)(styles_1.ExitButton, { "$isShow": isShowExitButton, onClick: profile?.exitButton?.onClick, title: "\u0412\u044B\u0445\u043E\u0434", variant: "text", children: (0, jsx_runtime_1.jsx)(QuitOutlineMd_1.QuitOutlineMd, {}) })] })] }) }));
36
+ const { isShowExitButton, isShowProfile, isFocusedMode, isMobile, collapsedIn, onToggleSidebar, isLoading, mobileHeaderPriorityFeature, headerStyle, isPinned, } = (0, useLogic_1.useLogic)(props);
37
+ return ((0, jsx_runtime_1.jsx)(styles_1.HeaderRoot, { ref: ref, "$isFocusedMode": isFocusedMode, ...(0, getInertProps_1.getInertProps)(!isMobile && isFocusedMode), className: constants_1.dashboardLayoutHeaderClassnames.root, style: headerStyle, children: (0, jsx_runtime_1.jsxs)(styles_1.HeaderContent, { children: [(0, jsx_runtime_1.jsx)(styles_1.MobileSidebarTogglerWrapper, { className: constants_1.dashboardLayoutHeaderClassnames.mobileSidebarButton, children: (0, jsx_runtime_1.jsx)(Button_1.Button, { startIcon: collapsedIn ? (0, jsx_runtime_1.jsx)(CrossOutlineMd_1.CrossOutlineMd, {}) : (0, jsx_runtime_1.jsx)(MenuOnOutlineMd_1.MenuOnOutlineMd, {}), variant: "text", onClick: () => onToggleSidebar(), title: "\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u043E\u0435 \u043C\u0435\u043D\u044E" }) }), (0, jsx_runtime_1.jsxs)(styles_1.HeaderSection, { children: [ProductSwitcher && ((0, jsx_runtime_1.jsx)(styles_1.ProductSwitcherWrapper, { children: (0, jsx_runtime_1.jsx)(ProductSwitcher, {}) })), (0, jsx_runtime_1.jsx)(Product_1.Product, { ...product })] }), (0, jsx_runtime_1.jsxs)(styles_1.HeaderContentSection, { className: headerPriorityFeature({
38
+ feature: mobileHeaderPriorityFeature,
39
+ }), children: [children, menuOrganization && ((0, jsx_runtime_1.jsx)(styles_1.PriorityFeatureWrapper, { className: headerPriorityFeature({
40
+ feature: mobileHeaderPriorityFeature,
41
+ isPinned,
42
+ featureInSidebar: mobileHeaderPriorityFeature === 'profile',
43
+ }), children: menuOrganization() })), profile && ((0, jsx_runtime_1.jsx)(styles_1.PriorityFeatureWrapper, { className: headerPriorityFeature({
44
+ feature: mobileHeaderPriorityFeature,
45
+ isPinned,
46
+ featureInSidebar: mobileHeaderPriorityFeature === 'menuOrg',
47
+ }), children: (0, jsx_runtime_1.jsx)(styles_1.ProfileWrapper, { className: constants_1.dashboardLayoutHeaderClassnames.profile, "$isShow": isShowProfile, children: (0, jsx_runtime_1.jsx)(Profile_1.Profile, { isLoading: isLoading, ...profile }) }) })), (0, jsx_runtime_1.jsx)(styles_1.ExitButton, { "$isShow": isShowExitButton, onClick: profile?.exitButton?.onClick, title: "\u0412\u044B\u0445\u043E\u0434", variant: "text", children: (0, jsx_runtime_1.jsx)(QuitOutlineMd_1.QuitOutlineMd, {}) })] })] }) }));
23
48
  });
@@ -1,5 +1,9 @@
1
1
  export declare const dashboardLayoutHeaderClassnames: {
2
2
  root: string;
3
3
  mobileSidebarButton: string;
4
- mobileMenuOrganizationVisible: string;
4
+ priorityFeatureMenuOrg: string;
5
+ priorityFeatureProfile: string;
6
+ mobileSidebarPriorityFeatureVisible: string;
7
+ featureInSidebar: string;
8
+ profile: string;
5
9
  };
@@ -5,5 +5,9 @@ const createUIKitClassname_1 = require("../../utils/createUIKitClassname");
5
5
  exports.dashboardLayoutHeaderClassnames = {
6
6
  root: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header'),
7
7
  mobileSidebarButton: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__sidebar-button_mobile'),
8
- mobileMenuOrganizationVisible: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__menu-organization_visible'),
8
+ priorityFeatureMenuOrg: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__priority-feature_menu-org'),
9
+ priorityFeatureProfile: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__priority-feature_profile'),
10
+ mobileSidebarPriorityFeatureVisible: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__sidebar-priority-feature_visible'),
11
+ featureInSidebar: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__feature-in-sidebar'),
12
+ profile: (0, createUIKitClassname_1.createUIKitClassname)('dashboard-layout-header__profile'),
9
13
  };
@@ -44,9 +44,10 @@ export declare const HeaderContent: import("@emotion/styled/dist/declarations/sr
44
44
  theme?: import("@emotion/react").Theme | undefined;
45
45
  as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
46
46
  }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
47
- export declare const MenuOrganizationWrapper: import("@emotion/styled/dist/declarations/src/types").StyledComponent<{
47
+ /**
48
+ * Обертка для элементов которые должны быть в мобильном хедере или помещены в sidebar.
49
+ */
50
+ export declare const PriorityFeatureWrapper: import("@emotion/styled/dist/declarations/src/types").StyledComponent<{
48
51
  theme?: import("@emotion/react").Theme | undefined;
49
52
  as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
50
- } & {
51
- $alertHeight?: number | undefined;
52
53
  }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;