@astral/ui 4.83.0 → 4.85.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/_mocks/LoggerMock/LoggerMock.d.ts +16 -0
- package/_mocks/LoggerMock/LoggerMock.js +18 -0
- package/_mocks/LoggerMock/index.d.ts +1 -0
- package/_mocks/LoggerMock/index.js +1 -0
- package/components/ConfigProvider/ConfigProvider.d.ts +7 -1
- package/components/ConfigProvider/ConfigProvider.js +14 -8
- package/components/DashboardLayout/Header/useLogic/useLogic.d.ts +1 -1
- package/components/HintPopover/HintPopover.d.ts +6 -0
- package/components/HintPopover/HintPopover.js +23 -0
- package/components/HintPopover/constants.d.ts +4 -0
- package/components/HintPopover/constants.js +5 -0
- package/components/HintPopover/index.d.ts +2 -0
- package/components/HintPopover/index.js +1 -0
- package/components/HintPopover/public.d.ts +2 -0
- package/components/HintPopover/public.js +1 -0
- package/components/HintPopover/styles.d.ts +38 -0
- package/components/HintPopover/styles.js +69 -0
- package/components/HintPopover/types.d.ts +24 -0
- package/components/HintPopover/types.js +1 -0
- package/components/NewPopover/NewPopover.d.ts +1 -1
- package/components/NewPopover/NewPopover.js +5 -4
- package/components/NewPopover/constants.d.ts +11 -0
- package/components/NewPopover/constants.js +11 -0
- package/components/NewPopover/styles.js +35 -30
- package/components/NewPopover/types.d.ts +5 -0
- package/components/NewPopover/useLogic/useLogic.d.ts +4 -3
- package/components/NewPopover/useLogic/useLogic.js +17 -8
- package/components/NewPopover/useLogic/utils/getArrowPadding/getArrowPadding.d.ts +14 -0
- package/components/NewPopover/useLogic/utils/getArrowPadding/getArrowPadding.js +12 -0
- package/components/NewPopover/useLogic/utils/getArrowPadding/index.d.ts +1 -0
- package/components/NewPopover/useLogic/utils/getArrowPadding/index.js +1 -0
- package/components/NewPopover/useLogic/utils/getPopoverCssVars/getPopoverCssVars.d.ts +2 -0
- package/components/NewPopover/useLogic/utils/getPopoverCssVars/getPopoverCssVars.js +6 -0
- package/components/NewPopover/useLogic/utils/getPopoverCssVars/index.d.ts +1 -0
- package/components/NewPopover/useLogic/utils/getPopoverCssVars/index.js +1 -0
- package/components/NewPopover/useLogic/utils/resolveAnchorNode/resolveAnchorNode.d.ts +6 -0
- package/components/NewPopover/useLogic/utils/resolveAnchorNode/resolveAnchorNode.js +8 -0
- package/components/Onboarding/Onboarding.js +13 -3
- package/components/Onboarding/core/ExitController/ExitController.d.ts +3 -1
- package/components/Onboarding/core/ExitController/ExitController.js +4 -1
- package/components/Onboarding/core/OnboardingTour/OnboardingTour.d.ts +3 -1
- package/components/Onboarding/core/OnboardingTour/OnboardingTour.js +25 -4
- package/components/Onboarding/core/ProgressStorage/ProgressStorage.d.ts +3 -1
- package/components/Onboarding/core/ProgressStorage/ProgressStorage.js +8 -4
- package/components/Onboarding/ui/StepStrategy/steps/HighlightStep/HighlightStep.js +3 -4
- package/components/Onboarding/ui/StepStrategy/steps/HighlightStep/styles.d.ts +6 -22
- package/components/Onboarding/ui/StepStrategy/steps/HighlightStep/styles.js +2 -45
- package/node/_mocks/LoggerMock/LoggerMock.d.ts +16 -0
- package/node/_mocks/LoggerMock/LoggerMock.js +23 -0
- package/node/_mocks/LoggerMock/index.d.ts +1 -0
- package/node/_mocks/LoggerMock/index.js +17 -0
- package/node/components/ConfigProvider/ConfigProvider.d.ts +7 -1
- package/node/components/ConfigProvider/ConfigProvider.js +13 -7
- package/node/components/DashboardLayout/Header/useLogic/useLogic.d.ts +1 -1
- package/node/components/HintPopover/HintPopover.d.ts +6 -0
- package/node/components/HintPopover/HintPopover.js +27 -0
- package/node/components/HintPopover/constants.d.ts +4 -0
- package/node/components/HintPopover/constants.js +8 -0
- package/node/components/HintPopover/index.d.ts +2 -0
- package/node/components/HintPopover/index.js +5 -0
- package/node/components/HintPopover/public.d.ts +2 -0
- package/node/components/HintPopover/public.js +5 -0
- package/node/components/HintPopover/styles.d.ts +38 -0
- package/node/components/HintPopover/styles.js +72 -0
- package/node/components/HintPopover/types.d.ts +24 -0
- package/node/components/HintPopover/types.js +2 -0
- package/node/components/NewPopover/NewPopover.d.ts +1 -1
- package/node/components/NewPopover/NewPopover.js +5 -4
- package/node/components/NewPopover/constants.d.ts +11 -0
- package/node/components/NewPopover/constants.js +12 -1
- package/node/components/NewPopover/styles.js +34 -29
- package/node/components/NewPopover/types.d.ts +5 -0
- package/node/components/NewPopover/useLogic/useLogic.d.ts +4 -3
- package/node/components/NewPopover/useLogic/useLogic.js +18 -9
- package/node/components/NewPopover/useLogic/utils/getArrowPadding/getArrowPadding.d.ts +14 -0
- package/node/components/NewPopover/useLogic/utils/getArrowPadding/getArrowPadding.js +16 -0
- package/node/components/NewPopover/useLogic/utils/getArrowPadding/index.d.ts +1 -0
- package/node/components/NewPopover/useLogic/utils/getArrowPadding/index.js +17 -0
- package/node/components/NewPopover/useLogic/utils/getPopoverCssVars/getPopoverCssVars.d.ts +2 -0
- package/node/components/NewPopover/useLogic/utils/getPopoverCssVars/getPopoverCssVars.js +10 -0
- package/node/components/NewPopover/useLogic/utils/getPopoverCssVars/index.d.ts +1 -0
- package/node/components/NewPopover/useLogic/utils/getPopoverCssVars/index.js +5 -0
- package/node/components/NewPopover/useLogic/utils/resolveAnchorNode/resolveAnchorNode.d.ts +6 -0
- package/node/components/NewPopover/{utils → useLogic/utils/resolveAnchorNode}/resolveAnchorNode.js +2 -2
- package/node/components/Onboarding/Onboarding.js +13 -3
- package/node/components/Onboarding/core/ExitController/ExitController.d.ts +3 -1
- package/node/components/Onboarding/core/ExitController/ExitController.js +4 -1
- package/node/components/Onboarding/core/OnboardingTour/OnboardingTour.d.ts +3 -1
- package/node/components/Onboarding/core/OnboardingTour/OnboardingTour.js +25 -4
- package/node/components/Onboarding/core/ProgressStorage/ProgressStorage.d.ts +3 -1
- package/node/components/Onboarding/core/ProgressStorage/ProgressStorage.js +8 -4
- package/node/components/Onboarding/ui/StepStrategy/steps/HighlightStep/HighlightStep.js +1 -2
- package/node/components/Onboarding/ui/StepStrategy/steps/HighlightStep/styles.d.ts +6 -22
- package/node/components/Onboarding/ui/StepStrategy/steps/HighlightStep/styles.js +3 -46
- package/node/services/Logger/Logger.d.ts +45 -0
- package/node/services/Logger/Logger.js +72 -0
- package/node/services/Logger/index.d.ts +10 -0
- package/node/services/Logger/index.js +17 -0
- package/package.json +1 -1
- package/services/Logger/Logger.d.ts +45 -0
- package/services/Logger/Logger.js +68 -0
- package/services/Logger/index.d.ts +10 -0
- package/services/Logger/index.js +12 -0
- package/components/NewPopover/utils/resolveAnchorNode.d.ts +0 -6
- package/components/NewPopover/utils/resolveAnchorNode.js +0 -8
- package/node/components/NewPopover/utils/resolveAnchorNode.d.ts +0 -6
- /package/components/NewPopover/{utils → useLogic/utils/resolveAnchorNode}/index.d.ts +0 -0
- /package/components/NewPopover/{utils → useLogic/utils/resolveAnchorNode}/index.js +0 -0
- /package/node/components/NewPopover/{utils → useLogic/utils/resolveAnchorNode}/index.d.ts +0 -0
- /package/node/components/NewPopover/{utils → useLogic/utils/resolveAnchorNode}/index.js +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Logger } from '../../services/Logger';
|
|
2
|
+
/**
|
|
3
|
+
* Mock логгера для тестов
|
|
4
|
+
*/
|
|
5
|
+
export declare class LoggerMock {
|
|
6
|
+
configure: Logger['configure'];
|
|
7
|
+
child: Logger['child'];
|
|
8
|
+
isLevelEnabled: Logger['isLevelEnabled'];
|
|
9
|
+
success: Logger['success'];
|
|
10
|
+
info: Logger['info'];
|
|
11
|
+
warn: Logger['warn'];
|
|
12
|
+
debug: Logger['debug'];
|
|
13
|
+
error: Logger['error'];
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export declare const createLoggerMock: () => Logger;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
/**
|
|
3
|
+
* Mock логгера для тестов
|
|
4
|
+
*/
|
|
5
|
+
export class LoggerMock {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.configure = vi.fn(() => vi.fn());
|
|
8
|
+
this.child = vi.fn();
|
|
9
|
+
this.isLevelEnabled = vi.fn(() => false);
|
|
10
|
+
this.success = vi.fn();
|
|
11
|
+
this.info = vi.fn();
|
|
12
|
+
this.warn = vi.fn();
|
|
13
|
+
this.debug = vi.fn();
|
|
14
|
+
this.error = vi.fn();
|
|
15
|
+
vi.mocked(this.child).mockReturnValue(this);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const createLoggerMock = () => new LoggerMock();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LoggerMock';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LoggerMock';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ReactElement, type ReactNode } from 'react';
|
|
2
|
+
import { type LogThreshold } from '../../services/Logger';
|
|
2
3
|
import { type LanguageMap } from '../DatePicker/types';
|
|
3
4
|
import { type PlaceholderImageProps } from '../placeholders/Placeholder/Image';
|
|
4
5
|
import { type CaptureException } from '../services/ErrorService';
|
|
@@ -138,7 +139,12 @@ export type ConfigProviderProps = Partial<ConfigContextProps> & {
|
|
|
138
139
|
* Переданный в компонент флаг напрямую имеет приоритет выше
|
|
139
140
|
*/
|
|
140
141
|
nextFeatureFlags?: NextFeatureFlagsContextProps;
|
|
142
|
+
/**
|
|
143
|
+
* Порог логов ui-kit в консоли. По умолчанию: prod → `error`, dev → `warn`,
|
|
144
|
+
* test → `silent`. `silent` — выключить полностью.
|
|
145
|
+
*/
|
|
146
|
+
logLevel?: LogThreshold;
|
|
141
147
|
};
|
|
142
148
|
export declare const ConfigContext: import("react").Context<ConfigContextProps>;
|
|
143
|
-
export declare const ConfigProvider: ({ children, language, datePickerLanguageMap, captureException: captureExceptionProp, emptySymbol, imagesMap, techSup, hidePersonalData, hidePersonalDataClassname, hidePersonalInputDataClassname, components: propsComponents, nextFeatureFlags, }: Partial<ConfigProviderProps>) => import("react/jsx-runtime").JSX.Element;
|
|
149
|
+
export declare const ConfigProvider: ({ children, language, datePickerLanguageMap, captureException: captureExceptionProp, emptySymbol, imagesMap, techSup, hidePersonalData, hidePersonalDataClassname, hidePersonalInputDataClassname, components: propsComponents, nextFeatureFlags, logLevel, }: Partial<ConfigProviderProps>) => import("react/jsx-runtime").JSX.Element;
|
|
144
150
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useEffect,
|
|
2
|
+
import { createContext, useEffect, } from 'react';
|
|
3
|
+
import { configureLogger } from '../../services/Logger';
|
|
3
4
|
import { russianMap } from '../DatePicker/constants';
|
|
4
5
|
import { ErrorService } from '../services/ErrorService';
|
|
5
6
|
import { NextFeatureFlagsContext, } from './NextFeatureFlagsContext';
|
|
@@ -13,6 +14,10 @@ const techSupDefault = {
|
|
|
13
14
|
phone: '',
|
|
14
15
|
email: '',
|
|
15
16
|
};
|
|
17
|
+
const defaultCaptureException = (error) => {
|
|
18
|
+
// biome-ignore lint/suspicious/noConsole: Ошибка для интеграторов
|
|
19
|
+
console.error(error);
|
|
20
|
+
};
|
|
16
21
|
const defaultHidePersonalDataClassname = 'ym-hide-content sentry-mask';
|
|
17
22
|
const defaultHidePersonalInputDataClassname = 'ym-disable-keys sentry-mask';
|
|
18
23
|
export const ConfigContext = createContext({
|
|
@@ -27,20 +32,21 @@ export const ConfigContext = createContext({
|
|
|
27
32
|
hidePersonalInputDataClassname: defaultHidePersonalInputDataClassname,
|
|
28
33
|
hidePersonalData: true,
|
|
29
34
|
});
|
|
30
|
-
export const ConfigProvider = ({ children, language = 'ru', datePickerLanguageMap = russianMap, captureException: captureExceptionProp, emptySymbol = '—', imagesMap = imagesMapDefault, techSup = techSupDefault, hidePersonalData = true, hidePersonalDataClassname = defaultHidePersonalDataClassname, hidePersonalInputDataClassname = defaultHidePersonalInputDataClassname, components: propsComponents, nextFeatureFlags = {}, }) => {
|
|
31
|
-
const captureException =
|
|
32
|
-
|
|
33
|
-
captureExceptionProp || ((error) => console.error(error));
|
|
34
|
-
useMemo(() => {
|
|
35
|
+
export const ConfigProvider = ({ children, language = 'ru', datePickerLanguageMap = russianMap, captureException: captureExceptionProp, emptySymbol = '—', imagesMap = imagesMapDefault, techSup = techSupDefault, hidePersonalData = true, hidePersonalDataClassname = defaultHidePersonalDataClassname, hidePersonalInputDataClassname = defaultHidePersonalInputDataClassname, components: propsComponents, nextFeatureFlags = {}, logLevel, }) => {
|
|
36
|
+
const captureException = captureExceptionProp ?? defaultCaptureException;
|
|
37
|
+
useEffect(() => {
|
|
35
38
|
ErrorService.getInstance().init(captureException);
|
|
36
39
|
}, [captureException]);
|
|
37
40
|
useEffect(() => {
|
|
38
|
-
|
|
41
|
+
return configureLogger({ level: logLevel });
|
|
42
|
+
}, [logLevel]);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!captureExceptionProp) {
|
|
39
45
|
// biome-ignore lint/suspicious/noConsole: Ошибка для интеграторов
|
|
40
46
|
console.warn('ConfigProvider: Необходимо наличие captureException, связанного с сервисом мониторинга ошибок.\n' +
|
|
41
47
|
'На данный момент все ошибки, отлавливаемые в ErrorBoundary будут выводиться только в консоль');
|
|
42
48
|
}
|
|
43
|
-
}, []);
|
|
49
|
+
}, [captureExceptionProp]);
|
|
44
50
|
const components = {
|
|
45
51
|
...propsComponents,
|
|
46
52
|
layout: {
|
|
@@ -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: "profile" | "menuOrg";
|
|
9
9
|
isLoading: boolean;
|
|
10
10
|
collapsedIn: boolean;
|
|
11
11
|
onToggleSidebar: (newValue?: boolean | undefined) => void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type HintPopoverProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Поповер-подсказка, привязанная к элементу: подсвечивает возможность интерфейса.
|
|
4
|
+
* Отличие от `NewPopover`: увеличенное скругление, всегда со стрелкой и не сворачивается в BottomDrawer на mobile.
|
|
5
|
+
*/
|
|
6
|
+
export declare const HintPopover: ({ variant, title, action, onClose, contentRef, children, className, ...restProps }: HintPopoverProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CrossOutlineMd } from '../../icons/CrossOutlineMd';
|
|
3
|
+
import { useViewportType } from '../useViewportType';
|
|
4
|
+
import { classNames } from '../utils/classNames';
|
|
5
|
+
import { cva } from '../utils/cva';
|
|
6
|
+
import { hintPopoverClassnames } from './constants';
|
|
7
|
+
import { ActionRow, Body, CloseButton, StyledHintPopover, Title, } from './styles';
|
|
8
|
+
const hintPopoverCva = cva(hintPopoverClassnames.root, {
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
light: '',
|
|
12
|
+
dark: hintPopoverClassnames.dark,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Поповер-подсказка, привязанная к элементу: подсвечивает возможность интерфейса.
|
|
18
|
+
* Отличие от `NewPopover`: увеличенное скругление, всегда со стрелкой и не сворачивается в BottomDrawer на mobile.
|
|
19
|
+
*/
|
|
20
|
+
export const HintPopover = ({ variant = 'dark', title, action, onClose, contentRef, children, className, ...restProps }) => {
|
|
21
|
+
const { isMobile } = useViewportType();
|
|
22
|
+
return (_jsx(StyledHintPopover, { ...restProps, className: classNames(className, hintPopoverCva({ variant })), hasArrow: true, disableMobileDrawer: true, onClose: onClose, children: _jsxs(Body, { ref: contentRef, tabIndex: -1, children: [_jsx(CloseButton, { variant: "text", onClick: onClose, "aria-label": "\u0417\u0430\u043A\u0440\u044B\u0442\u044C", children: _jsx(CrossOutlineMd, {}) }), title && (_jsx(Title, { component: "div", variant: isMobile ? 'h5' : 'h4', children: title })), children, action && _jsx(ActionRow, { children: action })] }) }));
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { HintPopover } from './HintPopover';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { HintPopover } from './HintPopover';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
/**
|
|
3
|
+
* styled-обёртка над NewPopover: переопределяет его CSS-переменные — всегда
|
|
4
|
+
* увеличенный радиус, а для `dark` ещё тёмную подложку и текст (цвет стрелки
|
|
5
|
+
* подтянется из подложки сам).
|
|
6
|
+
*/
|
|
7
|
+
export declare const StyledHintPopover: import("../styled").StyledComponent<import("../NewPopover").NewPopoverProps & {
|
|
8
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
9
|
+
}, {}, {}>;
|
|
10
|
+
export declare const Body: import("../styled").StyledComponent<{
|
|
11
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
12
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
13
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
14
|
+
export declare const Title: import("../styled").StyledComponent<import("../Typography/types").TypographyPropsBase & {
|
|
15
|
+
color?: import("../Typography").TypographyColor | undefined;
|
|
16
|
+
variant?: import("../Typography").TypographyVariant | undefined;
|
|
17
|
+
colorIntensity?: import("../Typography").Intensity | undefined;
|
|
18
|
+
component?: import("../Typography/types").ComponentProp | undefined;
|
|
19
|
+
isUpperCase?: boolean | undefined;
|
|
20
|
+
withoutCalt?: boolean | undefined;
|
|
21
|
+
isTabularNums?: boolean | undefined;
|
|
22
|
+
} & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
|
|
23
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
24
|
+
}, {}, {}>;
|
|
25
|
+
export declare const ActionRow: import("../styled").StyledComponent<{
|
|
26
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
27
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
28
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
29
|
+
export declare const CloseButton: import("../styled").StyledComponent<Omit<import("..").WithoutEmotionSpecific<import("@mui/material").ButtonProps>, "color" | "component" | "size" | "variant" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple"> & {
|
|
30
|
+
variant?: "light" | "link" | "text" | "contained" | "outlined" | undefined;
|
|
31
|
+
loading?: boolean | undefined;
|
|
32
|
+
color?: "primary" | "success" | "warning" | "error" | "grey" | undefined;
|
|
33
|
+
component?: import("react").ElementType | undefined;
|
|
34
|
+
selected?: boolean | undefined;
|
|
35
|
+
size?: "large" | "medium" | undefined;
|
|
36
|
+
} & Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, ""> & import("react").RefAttributes<HTMLButtonElement> & {
|
|
37
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
38
|
+
}, {}, {}>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { IconButton } from '../IconButton';
|
|
2
|
+
import { NewPopover } from '../NewPopover';
|
|
3
|
+
import { styled } from '../styled';
|
|
4
|
+
import { Typography } from '../Typography';
|
|
5
|
+
import { hintPopoverClassnames } from './constants';
|
|
6
|
+
/**
|
|
7
|
+
* styled-обёртка над NewPopover: переопределяет его CSS-переменные — всегда
|
|
8
|
+
* увеличенный радиус, а для `dark` ещё тёмную подложку и текст (цвет стрелки
|
|
9
|
+
* подтянется из подложки сам).
|
|
10
|
+
*/
|
|
11
|
+
export const StyledHintPopover = styled(NewPopover) `
|
|
12
|
+
--popover-radius: calc(${({ theme }) => theme.shape.medium} * 2);
|
|
13
|
+
|
|
14
|
+
&.${hintPopoverClassnames.dark} {
|
|
15
|
+
--popover-surface-color: ${({ theme }) => theme.palette.grey[900]};
|
|
16
|
+
--popover-text-color: ${({ theme }) => theme.palette.common.white};
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
export const Body = styled.div `
|
|
20
|
+
position: relative;
|
|
21
|
+
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
|
|
25
|
+
width: min(400px, calc(100vw - ${({ theme }) => theme.spacing(8)}));
|
|
26
|
+
padding: ${({ theme }) => theme.spacing(6)};
|
|
27
|
+
|
|
28
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
29
|
+
padding: ${({ theme }) => theme.spacing(4)};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Крестик висит абсолютом в углу и идёт первым в DOM, поэтому следующий за ним
|
|
33
|
+
верхний элемент (заголовок, а без него — контент) резервирует место справа,
|
|
34
|
+
чтобы текст под крестик не залез. */
|
|
35
|
+
& > button + * {
|
|
36
|
+
padding-right: ${({ theme }) => theme.spacing(10)};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Тело — программная цель фокуса (tabIndex=-1) у потребителя; рамку убираем. */
|
|
40
|
+
&:focus {
|
|
41
|
+
outline: none;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
export const Title = styled(Typography) `
|
|
45
|
+
margin-bottom: ${({ theme }) => theme.spacing(4)};
|
|
46
|
+
|
|
47
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
48
|
+
margin-bottom: ${({ theme }) => theme.spacing(1)};
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
export const ActionRow = styled.div `
|
|
52
|
+
margin-top: ${({ theme }) => theme.spacing(6)};
|
|
53
|
+
|
|
54
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
55
|
+
margin-top: ${({ theme }) => theme.spacing(4)};
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
export const CloseButton = styled(IconButton) `
|
|
59
|
+
position: absolute;
|
|
60
|
+
top: ${({ theme }) => theme.spacing(4)};
|
|
61
|
+
right: ${({ theme }) => theme.spacing(4)};
|
|
62
|
+
|
|
63
|
+
color: inherit;
|
|
64
|
+
|
|
65
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
66
|
+
top: ${({ theme }) => theme.spacing(2)};
|
|
67
|
+
right: ${({ theme }) => theme.spacing(2)};
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
|
+
import { type NewPopoverProps } from '../NewPopover';
|
|
3
|
+
/** Цвет подложки highlight-popover. */
|
|
4
|
+
export type HintPopoverVariant = 'light' | 'dark';
|
|
5
|
+
/** Параметры HintPopover */
|
|
6
|
+
export type HintPopoverProps = Omit<NewPopoverProps, 'hasArrow' | 'disableMobileDrawer' | 'title'> & {
|
|
7
|
+
/**
|
|
8
|
+
* Цвет подложки.
|
|
9
|
+
* @default 'dark'
|
|
10
|
+
*/
|
|
11
|
+
variant?: HintPopoverVariant;
|
|
12
|
+
/**
|
|
13
|
+
* Заголовок.
|
|
14
|
+
*/
|
|
15
|
+
title?: ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* Слот действий под контентом.
|
|
18
|
+
*/
|
|
19
|
+
action?: ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Ref на узел контента — для фокус-трапа/определения кликов у потребителя.
|
|
22
|
+
*/
|
|
23
|
+
contentRef?: Ref<HTMLDivElement>;
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type NewPopoverProps } from './types';
|
|
2
|
-
export declare const NewPopover: ({ children, onClose, isOpen, title, className, style, placement, anchorEl, disablePortal, disableAutoFocus, hasArrow, }: NewPopoverProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const NewPopover: ({ children, onClose, isOpen, title, className, style, placement, anchorEl, disablePortal, disableAutoFocus, hasArrow, disableMobileDrawer, }: NewPopoverProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -15,18 +15,19 @@ const animatedWrapperCva = cva(popoverClassnames.animatedWrapper, {
|
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
17
|
});
|
|
18
|
-
export const NewPopover = ({ children, onClose, isOpen, title, className, style, placement = 'bottom', anchorEl, disablePortal, disableAutoFocus, hasArrow, }) => {
|
|
19
|
-
const {
|
|
18
|
+
export const NewPopover = ({ children, onClose, isOpen, title, className, style, placement = 'bottom', anchorEl, disablePortal, disableAutoFocus, hasArrow, disableMobileDrawer, }) => {
|
|
19
|
+
const { shouldRenderDrawer, isOpened, shouldRender, handleAnimationEnd, handleClose, setContainerRef, setArrowElement, mergedModifiers, animatedWrapperStyle, } = useLogic({
|
|
20
20
|
isOpen,
|
|
21
21
|
anchorEl,
|
|
22
22
|
onClose,
|
|
23
23
|
disableAutoFocus,
|
|
24
24
|
hasArrow,
|
|
25
|
+
disableMobileDrawer,
|
|
25
26
|
});
|
|
26
|
-
if (
|
|
27
|
+
if (shouldRenderDrawer) {
|
|
27
28
|
return (_jsx(BottomDrawer, { title: title, onClose: handleClose, open: isOpened, className: className, style: style, ModalProps: {
|
|
28
29
|
disableAutoFocus,
|
|
29
30
|
}, children: children }));
|
|
30
31
|
}
|
|
31
|
-
return (_jsx(StyledMuiPopper, { className: classNames(popoverClassnames.root, className), style: style, open: shouldRender, placement: placement, anchorEl: anchorEl, disablePortal: disablePortal, modifiers: mergedModifiers, children: _jsxs(AnimatedWrapper, { className: animatedWrapperCva({ isOpen: isOpened, hasArrow }), onAnimationEnd: handleAnimationEnd, children: [hasArrow && (_jsx(PopoverArrow, { ref: setArrowElement, className: popoverClassnames.arrow })), _jsx(InnerContainer, { ref: setContainerRef, tabIndex: -1, className: popoverClassnames.innerContainer, children: children })] }) }));
|
|
32
|
+
return (_jsx(StyledMuiPopper, { className: classNames(popoverClassnames.root, className), style: style, open: shouldRender, placement: placement, anchorEl: anchorEl, disablePortal: disablePortal, modifiers: mergedModifiers, children: _jsxs(AnimatedWrapper, { className: animatedWrapperCva({ isOpen: isOpened, hasArrow }), style: animatedWrapperStyle, onAnimationEnd: handleAnimationEnd, children: [hasArrow && (_jsx(PopoverArrow, { ref: setArrowElement, className: popoverClassnames.arrow })), _jsx(InnerContainer, { ref: setContainerRef, tabIndex: -1, className: popoverClassnames.innerContainer, children: children })] }) }));
|
|
32
33
|
};
|
|
@@ -7,6 +7,17 @@ export declare const popoverClassnames: {
|
|
|
7
7
|
animatedWrapperHasArrow: string;
|
|
8
8
|
arrow: string;
|
|
9
9
|
};
|
|
10
|
+
/** Основание и высота стрелки (px). */
|
|
11
|
+
export declare const ARROW_BASE = 23;
|
|
12
|
+
export declare const ARROW_HEIGHT = 16;
|
|
13
|
+
/** Отступ стрелки от углов (px). */
|
|
14
|
+
export declare const ARROW_PADDING = 24;
|
|
15
|
+
/**
|
|
16
|
+
* Мин. отступ стрелки от угла (px)
|
|
17
|
+
*/
|
|
18
|
+
export declare const ARROW_MIN_PADDING = 16;
|
|
19
|
+
/** Мин. «ход» стрелки вдоль кромки (px). */
|
|
20
|
+
export declare const ARROW_MIN_TRACK = 16;
|
|
10
21
|
/**
|
|
11
22
|
* Базовые модификаторы Popper.js. У MUI Popper (popper.js)
|
|
12
23
|
*/
|
|
@@ -7,6 +7,17 @@ export const popoverClassnames = {
|
|
|
7
7
|
animatedWrapperHasArrow: createUIKitClassname('popover__animated-wrapper_has-arrow'),
|
|
8
8
|
arrow: createUIKitClassname('popover__arrow'),
|
|
9
9
|
};
|
|
10
|
+
/** Основание и высота стрелки (px). */
|
|
11
|
+
export const ARROW_BASE = 23;
|
|
12
|
+
export const ARROW_HEIGHT = 16;
|
|
13
|
+
/** Отступ стрелки от углов (px). */
|
|
14
|
+
export const ARROW_PADDING = 24;
|
|
15
|
+
/**
|
|
16
|
+
* Мин. отступ стрелки от угла (px)
|
|
17
|
+
*/
|
|
18
|
+
export const ARROW_MIN_PADDING = 16;
|
|
19
|
+
/** Мин. «ход» стрелки вдоль кромки (px). */
|
|
20
|
+
export const ARROW_MIN_TRACK = 16;
|
|
10
21
|
/**
|
|
11
22
|
* Базовые модификаторы Popper.js. У MUI Popper (popper.js)
|
|
12
23
|
*/
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import MuiPopper from '@mui/material/Popper';
|
|
2
2
|
import { styled } from '../styled';
|
|
3
|
-
import { popoverClassnames } from './constants';
|
|
3
|
+
import { ARROW_BASE, ARROW_HEIGHT, popoverClassnames } from './constants';
|
|
4
4
|
export const StyledMuiPopper = styled(MuiPopper) `
|
|
5
5
|
&.${popoverClassnames.root} {
|
|
6
|
+
--arrow-base: ${ARROW_BASE}px;
|
|
7
|
+
--arrow-height: ${ARROW_HEIGHT}px;
|
|
8
|
+
|
|
6
9
|
z-index: ${({ theme }) => theme.zIndex.tooltip};
|
|
7
10
|
}
|
|
8
11
|
|
|
9
|
-
/* Anchor ушёл за скролл/вьюпорт —
|
|
10
|
-
Стрелка иначе тянется к пропавшему anchor и торчит криво — прячем её. */
|
|
12
|
+
/* Anchor ушёл за скролл/вьюпорт — прячем стрелку. */
|
|
11
13
|
&[data-popper-reference-hidden] .${popoverClassnames.arrow} {
|
|
12
14
|
visibility: hidden;
|
|
13
15
|
}
|
|
@@ -36,7 +38,6 @@ export const StyledMuiPopper = styled(MuiPopper) `
|
|
|
36
38
|
margin-left: ${({ theme }) => theme.spacing(2)};
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
/* Со стрелкой отступ больше */
|
|
40
41
|
&&[data-popper-placement*='top']
|
|
41
42
|
.${popoverClassnames.animatedWrapperHasArrow} {
|
|
42
43
|
margin-bottom: ${({ theme }) => theme.spacing(4)};
|
|
@@ -58,54 +59,52 @@ export const StyledMuiPopper = styled(MuiPopper) `
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
&&[data-popper-placement*='bottom'] .${popoverClassnames.arrow} {
|
|
61
|
-
top: -
|
|
62
|
+
top: calc(var(--arrow-height) * -1);
|
|
62
63
|
|
|
63
|
-
width:
|
|
64
|
-
height:
|
|
64
|
+
width: var(--arrow-base);
|
|
65
|
+
height: var(--arrow-height);
|
|
65
66
|
|
|
66
67
|
&::before {
|
|
67
|
-
border-color: transparent transparent
|
|
68
|
-
|
|
69
|
-
border-width: 0 11.5px 16px;
|
|
68
|
+
border-color: transparent transparent var(--popover-surface-color, ${({ theme }) => theme.palette.background.paper});
|
|
69
|
+
border-width: 0 calc(var(--arrow-base) / 2) var(--arrow-height);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
&&[data-popper-placement*='top'] .${popoverClassnames.arrow} {
|
|
74
|
-
bottom: -
|
|
74
|
+
bottom: calc(var(--arrow-height) * -1);
|
|
75
75
|
|
|
76
|
-
width:
|
|
77
|
-
height:
|
|
76
|
+
width: var(--arrow-base);
|
|
77
|
+
height: var(--arrow-height);
|
|
78
78
|
|
|
79
79
|
&::before {
|
|
80
|
-
border-color: ${({ theme }) => theme.palette.background.paper} transparent
|
|
81
|
-
|
|
82
|
-
border-width: 16px 11.5px 0;
|
|
80
|
+
border-color: var(--popover-surface-color, ${({ theme }) => theme.palette.background.paper}) transparent transparent;
|
|
81
|
+
border-width: var(--arrow-height) calc(var(--arrow-base) / 2) 0;
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
&&[data-popper-placement*='right'] .${popoverClassnames.arrow} {
|
|
87
|
-
left: -
|
|
86
|
+
left: calc(var(--arrow-height) * -1);
|
|
88
87
|
|
|
89
|
-
width:
|
|
90
|
-
height:
|
|
88
|
+
width: var(--arrow-height);
|
|
89
|
+
height: var(--arrow-base);
|
|
91
90
|
|
|
92
91
|
&::before {
|
|
93
|
-
border-color: transparent ${({ theme }) => theme.palette.background.paper}
|
|
94
|
-
transparent
|
|
95
|
-
border-width:
|
|
92
|
+
border-color: transparent var(--popover-surface-color, ${({ theme }) => theme.palette.background.paper}) transparent
|
|
93
|
+
transparent;
|
|
94
|
+
border-width: calc(var(--arrow-base) / 2) var(--arrow-height) calc(var(--arrow-base) / 2) 0;
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
&&[data-popper-placement*='left'] .${popoverClassnames.arrow} {
|
|
100
|
-
right: -
|
|
99
|
+
right: calc(var(--arrow-height) * -1);
|
|
101
100
|
|
|
102
|
-
width:
|
|
103
|
-
height:
|
|
101
|
+
width: var(--arrow-height);
|
|
102
|
+
height: var(--arrow-base);
|
|
104
103
|
|
|
105
104
|
&::before {
|
|
106
105
|
border-color: transparent transparent transparent
|
|
107
|
-
${({ theme }) => theme.palette.background.paper};
|
|
108
|
-
border-width:
|
|
106
|
+
var(--popover-surface-color, ${({ theme }) => theme.palette.background.paper});
|
|
107
|
+
border-width: calc(var(--arrow-base) / 2) 0 calc(var(--arrow-base) / 2) var(--arrow-height);
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
110
|
`;
|
|
@@ -126,6 +125,8 @@ export const PopoverArrow = styled.span `
|
|
|
126
125
|
`;
|
|
127
126
|
export const AnimatedWrapper = styled.div `
|
|
128
127
|
position: relative;
|
|
128
|
+
|
|
129
|
+
filter: var(--drop-shadow);
|
|
129
130
|
|
|
130
131
|
animation: popover-grow-out
|
|
131
132
|
${({ theme }) => theme.transitions.duration.leavingScreen}ms
|
|
@@ -169,8 +170,12 @@ export const InnerContainer = styled.div `
|
|
|
169
170
|
&.${popoverClassnames.innerContainer} {
|
|
170
171
|
overflow: hidden;
|
|
171
172
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
color: var(--popover-text-color, ${({ theme }) => theme.palette.text.primary});
|
|
174
|
+
|
|
175
|
+
background: var(
|
|
176
|
+
--popover-surface-color,
|
|
177
|
+
${({ theme }) => theme.palette.background.paper}
|
|
178
|
+
);
|
|
179
|
+
border-radius: var(--popover-radius, ${({ theme }) => theme.shape.medium});
|
|
175
180
|
}
|
|
176
181
|
`;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { type NewPopoverModifier, type NewPopoverProps } from '../types';
|
|
3
|
-
type UseLogicParams = Pick<NewPopoverProps, 'isOpen' | 'anchorEl' | 'onClose' | 'disableAutoFocus' | 'hasArrow'>;
|
|
4
|
-
export declare const useLogic: ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow, }: UseLogicParams) => {
|
|
5
|
-
|
|
3
|
+
type UseLogicParams = Pick<NewPopoverProps, 'isOpen' | 'anchorEl' | 'onClose' | 'disableAutoFocus' | 'hasArrow' | 'disableMobileDrawer'>;
|
|
4
|
+
export declare const useLogic: ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow, disableMobileDrawer, }: UseLogicParams) => {
|
|
5
|
+
shouldRenderDrawer: boolean;
|
|
6
6
|
isOpened: boolean;
|
|
7
7
|
shouldRender: boolean;
|
|
8
8
|
handleAnimationEnd: () => void;
|
|
@@ -11,5 +11,6 @@ export declare const useLogic: ({ isOpen, anchorEl, onClose, disableAutoFocus, h
|
|
|
11
11
|
arrowElement: HTMLSpanElement | null;
|
|
12
12
|
setArrowElement: import("react").Dispatch<import("react").SetStateAction<HTMLSpanElement | null>>;
|
|
13
13
|
mergedModifiers: NewPopoverModifier[];
|
|
14
|
+
animatedWrapperStyle: import("react").CSSProperties;
|
|
14
15
|
};
|
|
15
16
|
export {};
|
|
@@ -5,8 +5,10 @@ import { useFocusTrapEffect } from '../../useFocusTrapEffect';
|
|
|
5
5
|
import { usePopoverAnimation } from '../../usePopoverAnimation';
|
|
6
6
|
import { useViewportType } from '../../useViewportType';
|
|
7
7
|
import { DEFAULT_MODIFIERS } from '../constants';
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import { getArrowPadding } from './utils/getArrowPadding';
|
|
9
|
+
import { getPopoverCssVars } from './utils/getPopoverCssVars';
|
|
10
|
+
import { resolveAnchorNode } from './utils/resolveAnchorNode';
|
|
11
|
+
export const useLogic = ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow, disableMobileDrawer, }) => {
|
|
10
12
|
const containerRef = useRef(null);
|
|
11
13
|
const [isContainerMounted, setIsContainerMounted] = useState(false);
|
|
12
14
|
const [arrowElement, setArrowElement] = useState(null);
|
|
@@ -18,7 +20,9 @@ export const useLogic = ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow
|
|
|
18
20
|
const isControlled = isOpen !== undefined;
|
|
19
21
|
const { isMobile } = useViewportType();
|
|
20
22
|
const { shouldRender, handleAnimationEnd } = usePopoverAnimation(isOpened);
|
|
21
|
-
const
|
|
23
|
+
const animatedWrapperStyle = getPopoverCssVars();
|
|
24
|
+
const shouldRenderDrawer = isMobile && !disableMobileDrawer;
|
|
25
|
+
const isPopoverActive = !shouldRenderDrawer && isOpened && isContainerMounted;
|
|
22
26
|
const anchorNode = useMemo(() => resolveAnchorNode(anchorEl), [anchorEl]);
|
|
23
27
|
const excludeNodes = useMemo(() => [anchorNode], [anchorNode]);
|
|
24
28
|
const handleClose = (event) => {
|
|
@@ -27,18 +31,18 @@ export const useLogic = ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow
|
|
|
27
31
|
useClickAwayEffect({
|
|
28
32
|
ref: containerRef,
|
|
29
33
|
onClickAway: handleClose,
|
|
30
|
-
isActive:
|
|
34
|
+
isActive: isPopoverActive && !isControlled,
|
|
31
35
|
preventBubbling: true,
|
|
32
36
|
excludeNodes,
|
|
33
37
|
});
|
|
34
38
|
useEscapeClickEffect({
|
|
35
39
|
onEscape: handleClose,
|
|
36
|
-
isActive:
|
|
40
|
+
isActive: isPopoverActive,
|
|
37
41
|
preventBubbling: true,
|
|
38
42
|
});
|
|
39
43
|
useFocusTrapEffect({
|
|
40
44
|
ref: containerRef,
|
|
41
|
-
isActive:
|
|
45
|
+
isActive: isPopoverActive && !disableAutoFocus,
|
|
42
46
|
returnFocusOnDeactivate: true,
|
|
43
47
|
escapeDeactivates: false,
|
|
44
48
|
clickOutsideDeactivates: false,
|
|
@@ -51,11 +55,15 @@ export const useLogic = ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow
|
|
|
51
55
|
}
|
|
52
56
|
return [
|
|
53
57
|
...DEFAULT_MODIFIERS,
|
|
54
|
-
{
|
|
58
|
+
{
|
|
59
|
+
name: 'arrow',
|
|
60
|
+
enabled: true,
|
|
61
|
+
options: { element: arrowElement, padding: getArrowPadding },
|
|
62
|
+
},
|
|
55
63
|
];
|
|
56
64
|
}, [hasArrow, arrowElement]);
|
|
57
65
|
return {
|
|
58
|
-
|
|
66
|
+
shouldRenderDrawer,
|
|
59
67
|
isOpened,
|
|
60
68
|
shouldRender,
|
|
61
69
|
handleAnimationEnd,
|
|
@@ -64,5 +72,6 @@ export const useLogic = ({ isOpen, anchorEl, onClose, disableAutoFocus, hasArrow
|
|
|
64
72
|
arrowElement,
|
|
65
73
|
setArrowElement,
|
|
66
74
|
mergedModifiers,
|
|
75
|
+
animatedWrapperStyle,
|
|
67
76
|
};
|
|
68
77
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type NewPopoverPlacement } from '../../../types';
|
|
2
|
+
type ArrowPaddingArgs = {
|
|
3
|
+
/** Прямоугольник поповера от Popper (нужны только габариты). */
|
|
4
|
+
popper: {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
placement: NewPopoverPlacement;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Фиксированный padding отобразил бы стрелку на скруглённый угол
|
|
12
|
+
*/
|
|
13
|
+
export declare const getArrowPadding: ({ popper, placement }: ArrowPaddingArgs) => number;
|
|
14
|
+
export {};
|