@astral/ui 4.52.0 → 4.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/DashboardContext/DashboardContext.d.ts +2 -3
- package/components/DashboardContext/DashboardContext.js +1 -0
- package/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.d.ts +2 -2
- package/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.js +2 -1
- package/components/DashboardLayout/Container/Container.d.ts +6 -0
- package/components/DashboardLayout/Container/Container.js +24 -0
- package/components/DashboardLayout/Container/constants.d.ts +6 -0
- package/components/DashboardLayout/Container/constants.js +7 -0
- package/components/DashboardLayout/Container/index.d.ts +1 -0
- package/components/DashboardLayout/Container/index.js +1 -0
- package/components/DashboardLayout/Container/styles.d.ts +5 -0
- package/components/DashboardLayout/Container/styles.js +55 -0
- package/components/DashboardLayout/DashboardLayout.d.ts +1 -1
- package/components/DashboardLayout/DashboardLayout.js +2 -2
- package/components/DashboardLayout/DashboardWrapper/DashboardWrapper.js +3 -2
- package/components/DashboardLayout/DashboardWrapper/constants.d.ts +6 -0
- package/components/DashboardLayout/DashboardWrapper/constants.js +7 -0
- package/components/DashboardLayout/DashboardWrapper/styles.d.ts +0 -6
- package/components/DashboardLayout/DashboardWrapper/styles.js +0 -45
- package/components/DashboardLayout/Header/useLogic/useLogic.d.ts +1 -1
- package/components/DashboardLayout/types.d.ts +5 -0
- package/components/DashboardLayoutSkeleton/DashboardLayoutSkeleton.js +3 -2
- package/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.d.ts +2 -0
- package/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.js +2 -1
- package/components/DatePicker/hooks/useMaskedValue/useMaskedValue.d.ts +4 -0
- package/components/DatePicker/hooks/useMaskedValue/useMaskedValue.js +37 -8
- package/components/DatePicker/useLogic/useLogic.d.ts +1 -0
- package/components/DatePicker/useLogic/useLogic.js +19 -13
- package/components/DateRangePicker/useLogic/useLogic.d.ts +2 -0
- package/components/DateRangePicker/useLogic/useLogic.js +27 -3
- package/components/DateRangePicker/useLogic/utils/index.d.ts +0 -1
- package/components/DateRangePicker/useLogic/utils/index.js +0 -1
- package/components/utils/date/format/index.d.ts +1 -0
- package/components/utils/date/format/index.js +1 -0
- package/{node/components/DateRangePicker/useLogic/utils → components/utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.d.ts +1 -1
- package/components/utils/date/format/parseDate/parseDate.d.ts +1 -0
- package/components/utils/date/format/parseDate/parseDate.js +42 -13
- package/node/components/DashboardContext/DashboardContext.d.ts +2 -3
- package/node/components/DashboardContext/DashboardContext.js +1 -0
- package/node/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.d.ts +2 -2
- package/node/components/DashboardContext/DashboardContextProvider/DashboardContextProvider.js +2 -1
- package/node/components/DashboardLayout/Container/Container.d.ts +6 -0
- package/node/components/DashboardLayout/Container/Container.js +28 -0
- package/node/components/DashboardLayout/Container/constants.d.ts +6 -0
- package/node/components/DashboardLayout/Container/constants.js +10 -0
- package/node/components/DashboardLayout/Container/index.d.ts +1 -0
- package/node/components/DashboardLayout/Container/index.js +17 -0
- package/node/components/DashboardLayout/Container/styles.d.ts +5 -0
- package/node/components/DashboardLayout/Container/styles.js +58 -0
- package/node/components/DashboardLayout/DashboardLayout.d.ts +1 -1
- package/node/components/DashboardLayout/DashboardLayout.js +2 -2
- package/node/components/DashboardLayout/DashboardWrapper/DashboardWrapper.js +2 -1
- package/node/components/DashboardLayout/DashboardWrapper/constants.d.ts +6 -0
- package/node/components/DashboardLayout/DashboardWrapper/constants.js +10 -0
- package/node/components/DashboardLayout/DashboardWrapper/styles.d.ts +0 -6
- package/node/components/DashboardLayout/DashboardWrapper/styles.js +4 -49
- package/node/components/DashboardLayout/Header/useLogic/useLogic.d.ts +1 -1
- package/node/components/DashboardLayout/types.d.ts +5 -0
- package/node/components/DashboardLayoutSkeleton/DashboardLayoutSkeleton.js +2 -1
- package/node/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.d.ts +2 -0
- package/node/components/DatePicker/hooks/useDatePickerOptions/useDatePickerOptions.js +2 -1
- package/node/components/DatePicker/hooks/useMaskedValue/useMaskedValue.d.ts +4 -0
- package/node/components/DatePicker/hooks/useMaskedValue/useMaskedValue.js +35 -6
- package/node/components/DatePicker/useLogic/useLogic.d.ts +1 -0
- package/node/components/DatePicker/useLogic/useLogic.js +19 -13
- package/node/components/DateRangePicker/useLogic/useLogic.d.ts +2 -0
- package/node/components/DateRangePicker/useLogic/useLogic.js +28 -4
- package/node/components/DateRangePicker/useLogic/utils/index.d.ts +0 -1
- package/node/components/DateRangePicker/useLogic/utils/index.js +0 -1
- package/node/components/utils/date/format/index.d.ts +1 -0
- package/node/components/utils/date/format/index.js +1 -0
- package/{components/DateRangePicker/useLogic/utils → node/components/utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.d.ts +1 -1
- package/node/components/utils/date/format/parseDate/parseDate.d.ts +1 -0
- package/node/components/utils/date/format/parseDate/parseDate.js +45 -13
- package/package.json +1 -1
- /package/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.d.ts +0 -0
- /package/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.js +0 -0
- /package/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.js +0 -0
- /package/node/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.d.ts +0 -0
- /package/node/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/index.js +0 -0
- /package/node/components/{DateRangePicker/useLogic/utils → utils/date/format}/isMaskedDateSyntacticallyComplete/isMaskedDateSyntacticallyComplete.js +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type RefObject } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
mobileHeaderPriorityFeature: 'profile' | 'menuOrg';
|
|
2
|
+
import { type DashboardLayoutProps } from '../DashboardLayout';
|
|
3
|
+
export type DashboardContextProps = Required<Pick<DashboardLayoutProps, 'isFocusedMode' | 'mobileHeaderPriorityFeature' | 'desktopViewMode'>> & {
|
|
5
4
|
setAlertElement?: (element: HTMLElement | null) => void;
|
|
6
5
|
alertHeight: number;
|
|
7
6
|
isLoading: boolean;
|
|
@@ -2,6 +2,7 @@ import { createContext, createRef } from 'react';
|
|
|
2
2
|
export const DashboardContext = createContext({
|
|
3
3
|
isFocusedMode: false,
|
|
4
4
|
mobileHeaderPriorityFeature: 'menuOrg',
|
|
5
|
+
desktopViewMode: 'compact',
|
|
5
6
|
alertHeight: 0,
|
|
6
7
|
isLoading: false,
|
|
7
8
|
hasMenuOrganizationRef: createRef(),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import { type DashboardContextProps } from '../DashboardContext';
|
|
3
|
-
type Props = Pick<DashboardContextProps, 'isFocusedMode' | 'mobileHeaderPriorityFeature'> & {
|
|
3
|
+
type Props = Pick<DashboardContextProps, 'isFocusedMode' | 'mobileHeaderPriorityFeature' | 'desktopViewMode'> & {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
isLoading: boolean;
|
|
6
6
|
};
|
|
7
|
-
export declare const DashboardContextProvider: ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const DashboardContextProvider: ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, desktopViewMode, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { DashboardContext, } from '../DashboardContext';
|
|
4
|
-
export const DashboardContextProvider = ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, }) => {
|
|
4
|
+
export const DashboardContextProvider = ({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, desktopViewMode, }) => {
|
|
5
5
|
const [alertElement, setAlertElement] = useState(null);
|
|
6
6
|
const [alertHeight, setAlertHeight] = useState(0);
|
|
7
7
|
const [isFocusedModeInternal, setFocusedMode] = useState(isFocusedMode);
|
|
@@ -29,6 +29,7 @@ export const DashboardContextProvider = ({ children, isFocusedMode, isLoading, m
|
|
|
29
29
|
return (_jsx(DashboardContext.Provider, { value: {
|
|
30
30
|
isFocusedMode: isFocusedModeInternal,
|
|
31
31
|
mobileHeaderPriorityFeature,
|
|
32
|
+
desktopViewMode,
|
|
32
33
|
setAlertElement,
|
|
33
34
|
alertHeight,
|
|
34
35
|
isLoading,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { DashboardContext } from '../../DashboardContext';
|
|
4
|
+
import { cva } from '../../utils/cva';
|
|
5
|
+
import { containerClassnames } from './constants';
|
|
6
|
+
import { Root } from './styles';
|
|
7
|
+
const containerCva = cva(containerClassnames.root, {
|
|
8
|
+
variants: {
|
|
9
|
+
desktopViewMode: {
|
|
10
|
+
compact: containerClassnames.compact,
|
|
11
|
+
wide: containerClassnames.wide,
|
|
12
|
+
},
|
|
13
|
+
isFocusedMode: {
|
|
14
|
+
true: containerClassnames.focusedMode,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
export const Container = ({ children }) => {
|
|
19
|
+
const { isFocusedMode, desktopViewMode } = useContext(DashboardContext);
|
|
20
|
+
return (_jsx(Root, { className: containerCva({
|
|
21
|
+
desktopViewMode,
|
|
22
|
+
isFocusedMode,
|
|
23
|
+
}), children: children }));
|
|
24
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createUIKitClassname } from '../../utils/createUIKitClassname';
|
|
2
|
+
export const containerClassnames = {
|
|
3
|
+
root: createUIKitClassname('dashboard-layout__container'),
|
|
4
|
+
compact: createUIKitClassname('dashboard-layout__container_compact'),
|
|
5
|
+
wide: createUIKitClassname('dashboard-layout__container_wide'),
|
|
6
|
+
focusedMode: createUIKitClassname('dashboard-layout__container_focused-mode'),
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Container';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Container';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const Root: import("../../styled").StyledComponent<{
|
|
3
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
4
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
5
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { dashboardSidebarClassnames } from '../../DashboardSidebar/constants';
|
|
2
|
+
import { styled } from '../../styled';
|
|
3
|
+
import { containerClassnames } from './constants';
|
|
4
|
+
export const Root = styled.div `
|
|
5
|
+
display: grid;
|
|
6
|
+
grid-template-columns: auto 1fr;
|
|
7
|
+
grid-template-rows: auto auto 1fr;
|
|
8
|
+
flex-grow: 1;
|
|
9
|
+
|
|
10
|
+
height: 100vh;
|
|
11
|
+
padding: ${({ theme }) => theme.spacing(0, 4, 4)};
|
|
12
|
+
|
|
13
|
+
transition: ${({ theme }) => {
|
|
14
|
+
return theme.transitions.create(['max-width'], {
|
|
15
|
+
duration: theme.transitions.duration.complex,
|
|
16
|
+
});
|
|
17
|
+
}};
|
|
18
|
+
|
|
19
|
+
/* Причина игнора: Не критично для отображения */
|
|
20
|
+
/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
|
|
21
|
+
&:has(.${dashboardSidebarClassnames.root}) {
|
|
22
|
+
column-gap: ${({ theme }) => theme.spacing(4)};
|
|
23
|
+
|
|
24
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
25
|
+
column-gap: 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Причина игнора: Прогрессивное улучшение */
|
|
30
|
+
/* stylelint-disable plugin/no-unsupported-browser-features */
|
|
31
|
+
@supports (height: 100dvh) {
|
|
32
|
+
height: 100dvh;
|
|
33
|
+
}
|
|
34
|
+
/* stylelint-enable plugin/no-unsupported-browser-features */
|
|
35
|
+
|
|
36
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
37
|
+
column-gap: 0;
|
|
38
|
+
|
|
39
|
+
min-width: unset;
|
|
40
|
+
max-width: unset;
|
|
41
|
+
padding: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.${containerClassnames.compact} {
|
|
45
|
+
max-width: 1572px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.${containerClassnames.wide} {
|
|
49
|
+
max-width: 1920px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&.${containerClassnames.focusedMode} {
|
|
53
|
+
max-width: 100%;
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
@@ -4,7 +4,7 @@ import { type DashboardLayoutProps } from './types';
|
|
|
4
4
|
* Общий Layout приложения
|
|
5
5
|
*/
|
|
6
6
|
export declare const DashboardLayout: {
|
|
7
|
-
({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
({ children, isFocusedMode, isLoading, mobileHeaderPriorityFeature, desktopViewMode, }: 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>>;
|
|
@@ -7,8 +7,8 @@ import { Main } from './Main';
|
|
|
7
7
|
/**
|
|
8
8
|
* Общий Layout приложения
|
|
9
9
|
*/
|
|
10
|
-
export const DashboardLayout = ({ children, isFocusedMode = false, isLoading = false, mobileHeaderPriorityFeature = 'menuOrg', }) => {
|
|
11
|
-
return (_jsx(DashboardContextProvider, { isFocusedMode: isFocusedMode, isLoading: isLoading, mobileHeaderPriorityFeature: mobileHeaderPriorityFeature, children: _jsx(DashboardWrapper, { children: children }) }));
|
|
10
|
+
export const DashboardLayout = ({ children, isFocusedMode = false, isLoading = false, mobileHeaderPriorityFeature = 'menuOrg', desktopViewMode = 'compact', }) => {
|
|
11
|
+
return (_jsx(DashboardContextProvider, { isFocusedMode: isFocusedMode, isLoading: isLoading, desktopViewMode: desktopViewMode, mobileHeaderPriorityFeature: mobileHeaderPriorityFeature, children: _jsx(DashboardWrapper, { children: children }) }));
|
|
12
12
|
};
|
|
13
13
|
DashboardLayout.Header = Header;
|
|
14
14
|
DashboardLayout.Sidebar = DashboardSidebar;
|
|
@@ -2,9 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useContext } from 'react';
|
|
3
3
|
import { DashboardContext } from '../../DashboardContext';
|
|
4
4
|
import { DashboardSidebarProvider } from '../../DashboardSidebarProvider';
|
|
5
|
+
import { Container } from '../Container';
|
|
5
6
|
import { dashboardLayoutClassnames } from '../constants';
|
|
6
|
-
import { DecorativeHeaderBackground,
|
|
7
|
+
import { DecorativeHeaderBackground, Wrapper } from './styles';
|
|
7
8
|
export const DashboardWrapper = ({ children }) => {
|
|
8
9
|
const { isFocusedMode } = useContext(DashboardContext);
|
|
9
|
-
return (_jsx(DashboardSidebarProvider, { isFocusedMode: isFocusedMode, children: _jsxs(Wrapper, { className: dashboardLayoutClassnames.root, children: [_jsx(DecorativeHeaderBackground, { role: "presentation", "$isFocusedMode": isFocusedMode }), _jsx(
|
|
10
|
+
return (_jsx(DashboardSidebarProvider, { isFocusedMode: isFocusedMode, children: _jsxs(Wrapper, { className: dashboardLayoutClassnames.root, children: [_jsx(DecorativeHeaderBackground, { role: "presentation", "$isFocusedMode": isFocusedMode }), _jsx(Container, { children: children })] }) }));
|
|
10
11
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createUIKitClassname } from '../../utils/createUIKitClassname';
|
|
2
|
+
export const dashboardLayoutContainerClassnames = {
|
|
3
|
+
root: createUIKitClassname('dashboard-layout__container'),
|
|
4
|
+
compact: createUIKitClassname('dashboard-layout__container_compact'),
|
|
5
|
+
wide: createUIKitClassname('dashboard-layout__container_wide'),
|
|
6
|
+
focusedMode: createUIKitClassname('dashboard-layout__container_focused-mode'),
|
|
7
|
+
};
|
|
@@ -9,9 +9,3 @@ export declare const DecorativeHeaderBackground: import("../../styled").StyledCo
|
|
|
9
9
|
} & {
|
|
10
10
|
$isFocusedMode: boolean;
|
|
11
11
|
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
12
|
-
export declare const LayoutContent: import("../../styled").StyledComponent<{
|
|
13
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
14
|
-
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
15
|
-
} & {
|
|
16
|
-
$isFocusedMode: boolean;
|
|
17
|
-
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { dashboardSidebarClassnames } from '../../DashboardSidebar/constants';
|
|
2
1
|
import { styled } from '../../styled';
|
|
3
2
|
import { HEADER_HEIGHT_DESKTOP, HEADER_HEIGHT_LAPTOP } from '../constants';
|
|
4
3
|
export const Wrapper = styled('div') `
|
|
@@ -36,47 +35,3 @@ export const DecorativeHeaderBackground = styled.div `
|
|
|
36
35
|
display: none;
|
|
37
36
|
}
|
|
38
37
|
`;
|
|
39
|
-
export const LayoutContent = styled('div', {
|
|
40
|
-
shouldForwardProp: (prop) => !['$isFocusedMode'].includes(prop),
|
|
41
|
-
}) `
|
|
42
|
-
display: grid;
|
|
43
|
-
grid-template-columns: auto 1fr;
|
|
44
|
-
grid-template-rows: auto auto 1fr;
|
|
45
|
-
flex-grow: 1;
|
|
46
|
-
|
|
47
|
-
/* Максимальная ширина с отступами */
|
|
48
|
-
max-width: ${({ $isFocusedMode }) => ($isFocusedMode ? '100%' : '1572px')};
|
|
49
|
-
height: 100vh;
|
|
50
|
-
padding: ${({ theme }) => theme.spacing(0, 4, 4)};
|
|
51
|
-
|
|
52
|
-
transition: ${({ theme }) => {
|
|
53
|
-
return theme.transitions.create(['max-width'], {
|
|
54
|
-
duration: theme.transitions.duration.complex,
|
|
55
|
-
});
|
|
56
|
-
}};
|
|
57
|
-
|
|
58
|
-
/* Причина игнора: Не критично для отображения */
|
|
59
|
-
/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
|
|
60
|
-
&:has(.${dashboardSidebarClassnames.root}) {
|
|
61
|
-
column-gap: ${({ theme }) => theme.spacing(4)};
|
|
62
|
-
|
|
63
|
-
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
64
|
-
column-gap: 0;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/* Причина игнора: Прогрессивное улучшение */
|
|
69
|
-
/* stylelint-disable plugin/no-unsupported-browser-features */
|
|
70
|
-
@supports (height: 100dvh) {
|
|
71
|
-
height: 100dvh;
|
|
72
|
-
}
|
|
73
|
-
/* stylelint-enable plugin/no-unsupported-browser-features */
|
|
74
|
-
|
|
75
|
-
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
76
|
-
column-gap: 0;
|
|
77
|
-
|
|
78
|
-
min-width: unset;
|
|
79
|
-
max-width: unset;
|
|
80
|
-
padding: 0;
|
|
81
|
-
}
|
|
82
|
-
`;
|
|
@@ -5,7 +5,7 @@ export declare const useLogic: ({ profile, menuOrganization }: HeaderProps) => {
|
|
|
5
5
|
isShowProfile: boolean;
|
|
6
6
|
isMobile: boolean;
|
|
7
7
|
isFocusedMode: boolean;
|
|
8
|
-
mobileHeaderPriorityFeature: "
|
|
8
|
+
mobileHeaderPriorityFeature: "menuOrg" | "profile";
|
|
9
9
|
isLoading: boolean;
|
|
10
10
|
collapsedIn: boolean;
|
|
11
11
|
onToggleSidebar: (newValue?: boolean | undefined) => void;
|
|
@@ -15,4 +15,9 @@ export type DashboardLayoutProps = {
|
|
|
15
15
|
* Второстепенный будет помещен в sidebar.
|
|
16
16
|
*/
|
|
17
17
|
mobileHeaderPriorityFeature?: 'profile' | 'menuOrg';
|
|
18
|
+
/**
|
|
19
|
+
* Compact - ширина layout ограничена 1572px. Необходимо для удобного чтения контента, без лишнего растягивания
|
|
20
|
+
* Wide - ширина layout ограничена 1920px. Применяйте, когда в вашем приложении отображается много табличных данных с большим количеством колонок. Пример - админки
|
|
21
|
+
*/
|
|
22
|
+
desktopViewMode?: 'wide' | 'compact';
|
|
18
23
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Container } from '../DashboardLayout/Container';
|
|
2
3
|
import { dashboardLayoutClassnames } from '../DashboardLayout/constants';
|
|
3
4
|
import { DashboardLayout } from '../DashboardLayout/DashboardLayout';
|
|
4
|
-
import { DecorativeHeaderBackground,
|
|
5
|
+
import { DecorativeHeaderBackground, Wrapper, } from '../DashboardLayout/DashboardWrapper/styles';
|
|
5
6
|
import { Header } from '../DashboardLayout/Header';
|
|
6
7
|
import { DashboardSidebarSkeleton } from '../DashboardSidebarSkeleton';
|
|
7
8
|
import { MenuOrganizationSkeleton } from '../MenuOrganization';
|
|
@@ -11,7 +12,7 @@ import { Content } from './styles';
|
|
|
11
12
|
* Компонент можно использовать для отображения состояния загрузки дашборда
|
|
12
13
|
*/
|
|
13
14
|
export const DashboardLayoutSkeleton = ({ product, productSwitcher, hasSidebar = true, hasProfile = true, hasMenuOrganization = true, }) => {
|
|
14
|
-
return (_jsxs(Wrapper, { className: dashboardLayoutClassnames.root, children: [_jsx(DecorativeHeaderBackground, { role: "presentation", "$isFocusedMode": false }), _jsxs(
|
|
15
|
+
return (_jsxs(Wrapper, { className: dashboardLayoutClassnames.root, children: [_jsx(DecorativeHeaderBackground, { role: "presentation", "$isFocusedMode": false }), _jsxs(Container, { children: [hasSidebar && _jsx(DashboardSidebarSkeleton, {}), _jsx(Header, { productSwitcher: productSwitcher, product: product, menuOrganization: hasMenuOrganization ? () => _jsx(MenuOrganizationSkeleton, {}) : undefined, profile: hasProfile
|
|
15
16
|
? { displayName: '', isLoading: true, menuList: [] }
|
|
16
17
|
: undefined }), _jsx(DashboardLayout.Main, { children: _jsx(Content, { children: _jsx(LoadingPlaceholder, { title: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0434\u0430\u043D\u043D\u044B\u0445" }) }) })] })] }));
|
|
17
18
|
};
|
|
@@ -30,6 +30,8 @@ type UseMaskedValueAndSelectedBaseDateReturn = {
|
|
|
30
30
|
*/
|
|
31
31
|
value: string;
|
|
32
32
|
};
|
|
33
|
+
/** При blur неполной даты - в onChange уходит Invalid Date (тот же стейт, что у маски). */
|
|
34
|
+
onMaskedValueBlur: () => void;
|
|
33
35
|
};
|
|
34
36
|
/**
|
|
35
37
|
* хук объединяющий повторяющуюся логику в работе DatePicker и RangeDatePicker:
|
|
@@ -12,7 +12,7 @@ import { useSelectedBaseDate } from '../useSelectedBaseDate';
|
|
|
12
12
|
*/
|
|
13
13
|
export const useDatePickerOptions = ({ onChange, mask, currentValue, minDate, maxDate, monthOffset, onDatePick, }) => {
|
|
14
14
|
const baseDate = useBaseDateInRange({ minDate, maxDate, monthOffset });
|
|
15
|
-
const { maskedValue, onMaskedValueChange, onMaskedDateChange } = useMaskedValue({
|
|
15
|
+
const { maskedValue, onMaskedValueChange, onMaskedValueBlur, onMaskedDateChange, } = useMaskedValue({
|
|
16
16
|
currentValue,
|
|
17
17
|
mask,
|
|
18
18
|
onChangeValue: onChange,
|
|
@@ -39,5 +39,6 @@ export const useDatePickerOptions = ({ onChange, mask, currentValue, minDate, ma
|
|
|
39
39
|
onChange: handleDatePick,
|
|
40
40
|
date: selectedBaseDate || baseDate,
|
|
41
41
|
},
|
|
42
|
+
onMaskedValueBlur,
|
|
42
43
|
};
|
|
43
44
|
};
|
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
import { isDate } from '@astral/utils/date/isDate';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import { formatDate, parseDate } from '../../../utils/date';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { formatDate, isMaskedDateSyntacticallyComplete, parseDate, } from '../../../utils/date';
|
|
4
4
|
/**
|
|
5
5
|
* Хук для управления значением для MaskField
|
|
6
6
|
*/
|
|
7
7
|
export const useMaskedValue = ({ currentValue, mask, onChangeValue, }) => {
|
|
8
8
|
const [maskedValue, setMaskedValue] = useState(() => currentValue ? formatDate(currentValue, mask) : '');
|
|
9
|
+
const maskedValueRef = useRef(maskedValue);
|
|
10
|
+
/**
|
|
11
|
+
* Ввод в маску: синхронизируем локальное значение и ref (ref нужен на blur и после выбора даты из календаря,
|
|
12
|
+
* чтобы не читать устаревший state).
|
|
13
|
+
* `onChangeValue` вызываем только при пустой строке (`null`) или когда маска синтаксически полная —
|
|
14
|
+
* иначе partial не уходит наружу до завершения ввода или до blur (см. `handleMaskedValueBlur`).
|
|
15
|
+
*/
|
|
9
16
|
const handleMaskedValueChange = (value) => {
|
|
10
17
|
setMaskedValue(value);
|
|
11
|
-
|
|
18
|
+
maskedValueRef.current = value;
|
|
12
19
|
if (!value) {
|
|
13
20
|
onChangeValue?.(null, value);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!isMaskedDateSyntacticallyComplete(value, mask)) {
|
|
24
|
+
return;
|
|
14
25
|
}
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
onChangeValue?.(parseDate(value, mask), value);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Blur поля: если осталась непустая неполная маска — один раз отдаём `Invalid Date` в `onChangeValue`,
|
|
30
|
+
* чтобы формы могли показать ошибку. Пустая строка и полная маска не дублируют уже отправленный `onChange`.
|
|
31
|
+
*/
|
|
32
|
+
const handleMaskedValueBlur = () => {
|
|
33
|
+
const currentMaskedValue = maskedValueRef.current;
|
|
34
|
+
if (!currentMaskedValue) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (isMaskedDateSyntacticallyComplete(currentMaskedValue, mask)) {
|
|
38
|
+
return;
|
|
17
39
|
}
|
|
40
|
+
onChangeValue?.(new Date(Number.NaN), currentMaskedValue);
|
|
18
41
|
};
|
|
19
42
|
const handleChangeMaskedDate = (date) => {
|
|
20
43
|
const formatted = formatDate(date, mask);
|
|
21
44
|
setMaskedValue(formatted);
|
|
45
|
+
maskedValueRef.current = formatted;
|
|
22
46
|
onChangeValue?.(date, formatted);
|
|
23
47
|
};
|
|
24
48
|
// здесь происходит реакция на изменение value из вне (управляемый компонент)
|
|
@@ -26,6 +50,7 @@ export const useMaskedValue = ({ currentValue, mask, onChangeValue, }) => {
|
|
|
26
50
|
// если новое значение пустое, то сбрасываем значение MaskField
|
|
27
51
|
if (!currentValue) {
|
|
28
52
|
setMaskedValue('');
|
|
53
|
+
maskedValueRef.current = '';
|
|
29
54
|
return;
|
|
30
55
|
}
|
|
31
56
|
// здесь обрабатывается сценарий, когда в инпут вводится невалидная дата и при этом currentValue становится Invalid Date
|
|
@@ -33,16 +58,20 @@ export const useMaskedValue = ({ currentValue, mask, onChangeValue, }) => {
|
|
|
33
58
|
if (!isDate(currentValue) && maskedValue) {
|
|
34
59
|
return;
|
|
35
60
|
}
|
|
36
|
-
//
|
|
37
|
-
const isEqualValueAndMaskedDate =
|
|
61
|
+
// сравнение только при полной маске, иначе getTime() от parseDate может быть NaN
|
|
62
|
+
const isEqualValueAndMaskedDate = isMaskedDateSyntacticallyComplete(maskedValue, mask) &&
|
|
63
|
+
currentValue.getTime() === parseDate(maskedValue, mask).getTime();
|
|
38
64
|
// если даты не равны, то значит изменился currentValue из вне и надо синхронизировать maskedValue
|
|
39
65
|
if (!isEqualValueAndMaskedDate) {
|
|
40
|
-
|
|
66
|
+
const formatted = formatDate(currentValue, mask);
|
|
67
|
+
setMaskedValue(formatted);
|
|
68
|
+
maskedValueRef.current = formatted;
|
|
41
69
|
}
|
|
42
70
|
}, [currentValue]);
|
|
43
71
|
return {
|
|
44
72
|
maskedValue,
|
|
45
73
|
onMaskedValueChange: handleMaskedValueChange,
|
|
74
|
+
onMaskedValueBlur: handleMaskedValueBlur,
|
|
46
75
|
onMaskedDateChange: handleChangeMaskedDate,
|
|
47
76
|
};
|
|
48
77
|
};
|
|
@@ -13,6 +13,7 @@ export declare const useLogic: ({ label, value, maxDate, minDate, mask, onOpen,
|
|
|
13
13
|
};
|
|
14
14
|
DatePickerInputProps: {
|
|
15
15
|
value: string;
|
|
16
|
+
onBlur: () => void;
|
|
16
17
|
};
|
|
17
18
|
onAccept: ((value: string, maskRef: import("imask").default.InputMask<import("imask").default.AnyMaskedOptions>, e?: InputEvent | undefined, onChange?: ((changeValue: string) => void) | undefined) => void) | undefined;
|
|
18
19
|
pickerProps: import("../types").PickerProps;
|
|
@@ -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:
|
|
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
|
|
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: {
|