@astral/ui 4.29.0 → 4.30.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/Filename/Filename.js +2 -2
- package/components/Filename/styles.d.ts +4 -0
- package/components/Filename/styles.js +4 -1
- package/hook-form/FormFilters/AllFiltersButton/AllFiltersButton.d.ts +2 -0
- package/hook-form/FormFilters/AllFiltersButton/AllFiltersButton.js +10 -0
- package/hook-form/FormFilters/AllFiltersButton/index.d.ts +1 -0
- package/hook-form/FormFilters/AllFiltersButton/index.js +1 -0
- package/hook-form/FormFilters/AllFiltersButton/styles.d.ts +19 -0
- package/hook-form/FormFilters/AllFiltersButton/styles.js +53 -0
- package/hook-form/FormFilters/AllFiltersButton/types.d.ts +8 -0
- package/hook-form/FormFilters/AllFiltersButton/types.js +1 -0
- package/hook-form/FormFilters/AllFiltersButton/useLogic/index.d.ts +1 -0
- package/hook-form/FormFilters/AllFiltersButton/useLogic/index.js +1 -0
- package/hook-form/FormFilters/AllFiltersButton/useLogic/useLogic.d.ts +6 -0
- package/hook-form/FormFilters/AllFiltersButton/useLogic/useLogic.js +33 -0
- package/hook-form/FormFilters/FormFilters.js +5 -6
- package/hook-form/FormFilters/FormFiltersDialog/useLogic/useLogic.d.ts +1 -1
- package/hook-form/FormFilters/FormFiltersDialog/useLogic/useLogic.js +4 -7
- package/hook-form/FormFilters/constants.d.ts +0 -1
- package/hook-form/FormFilters/constants.js +0 -1
- package/hook-form/FormFilters/styles.d.ts +0 -18
- package/hook-form/FormFilters/styles.js +0 -51
- package/hook-form/FormFilters/types.d.ts +7 -16
- package/hook-form/FormFilters/useLogic/useLogic.d.ts +5 -6
- package/hook-form/FormFilters/useLogic/useLogic.js +7 -95
- package/hook-form/FormFiltersSearchField/FormFiltersSearchField.js +1 -1
- package/node/components/Filename/Filename.js +1 -1
- package/node/components/Filename/styles.d.ts +4 -0
- package/node/components/Filename/styles.js +5 -2
- package/node/hook-form/FormFilters/AllFiltersButton/AllFiltersButton.d.ts +2 -0
- package/node/hook-form/FormFilters/AllFiltersButton/AllFiltersButton.js +14 -0
- package/node/hook-form/FormFilters/AllFiltersButton/index.d.ts +1 -0
- package/node/hook-form/FormFilters/AllFiltersButton/index.js +5 -0
- package/node/hook-form/FormFilters/AllFiltersButton/styles.d.ts +19 -0
- package/node/hook-form/FormFilters/AllFiltersButton/styles.js +56 -0
- package/node/hook-form/FormFilters/AllFiltersButton/types.d.ts +8 -0
- package/node/hook-form/FormFilters/AllFiltersButton/types.js +2 -0
- package/node/hook-form/FormFilters/AllFiltersButton/useLogic/index.d.ts +1 -0
- package/node/hook-form/FormFilters/AllFiltersButton/useLogic/index.js +17 -0
- package/node/hook-form/FormFilters/AllFiltersButton/useLogic/useLogic.d.ts +6 -0
- package/node/hook-form/FormFilters/AllFiltersButton/useLogic/useLogic.js +37 -0
- package/node/hook-form/FormFilters/FormFilters.js +3 -4
- package/node/hook-form/FormFilters/FormFiltersDialog/useLogic/useLogic.d.ts +1 -1
- package/node/hook-form/FormFilters/FormFiltersDialog/useLogic/useLogic.js +4 -7
- package/node/hook-form/FormFilters/constants.d.ts +0 -1
- package/node/hook-form/FormFilters/constants.js +0 -1
- package/node/hook-form/FormFilters/styles.d.ts +0 -18
- package/node/hook-form/FormFilters/styles.js +1 -52
- package/node/hook-form/FormFilters/types.d.ts +7 -16
- package/node/hook-form/FormFilters/useLogic/useLogic.d.ts +5 -6
- package/node/hook-form/FormFilters/useLogic/useLogic.js +6 -94
- package/node/hook-form/FormFiltersSearchField/FormFiltersSearchField.js +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
import { useHidePersonalData } from '../personalDataSecurity';
|
|
4
4
|
import { Tooltip } from '../Tooltip';
|
|
5
5
|
import { classNames } from '../utils/classNames';
|
|
6
|
-
import { FileBaseName, StyledTypography } from './styles';
|
|
6
|
+
import { FileBaseName, FileSuffix, StyledTypography } from './styles';
|
|
7
7
|
import { useLogic } from './useLogic';
|
|
8
8
|
export const Filename = forwardRef((props, forwardedRef) => {
|
|
9
9
|
const { isOverflowed, suffixWithExtension, baseNameProps } = useLogic({
|
|
@@ -14,5 +14,5 @@ export const Filename = forwardRef((props, forwardedRef) => {
|
|
|
14
14
|
const hidePersonalDataClassname = useHidePersonalData({
|
|
15
15
|
isEnabled: isHidePersonalData,
|
|
16
16
|
});
|
|
17
|
-
return (_jsx(Tooltip, { title: isOverflowed && children, disableInteractive: true, ...tooltipProps, className: classNames(tooltipProps?.className, hidePersonalDataClassname), children: _jsxs(StyledTypography, { "$align": align, variant: variant, className: classNames(className, hidePersonalDataClassname), ...restProps, children: [_jsx(FileBaseName, { ...baseNameProps }), _jsx(
|
|
17
|
+
return (_jsx(Tooltip, { title: isOverflowed && children, disableInteractive: true, ...tooltipProps, className: classNames(tooltipProps?.className, hidePersonalDataClassname), children: _jsxs(StyledTypography, { "$align": align, variant: variant, className: classNames(className, hidePersonalDataClassname), ...restProps, children: [_jsx(FileBaseName, { ...baseNameProps }), _jsx(FileSuffix, { children: suffixWithExtension })] }) }));
|
|
18
18
|
});
|
|
@@ -3,6 +3,10 @@ export declare const FileBaseName: import("../styled").StyledComponent<{
|
|
|
3
3
|
theme?: import("@emotion/react").Theme | undefined;
|
|
4
4
|
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
5
5
|
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {}>;
|
|
6
|
+
export declare const FileSuffix: import("../styled").StyledComponent<{
|
|
7
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
8
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
9
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {}>;
|
|
6
10
|
export declare const StyledTypography: import("../styled").StyledComponent<import("../Typography/types").TypographyPropsBase & {
|
|
7
11
|
color?: import("../Typography").TypographyColor | undefined;
|
|
8
12
|
variant?: import("../Typography").TypographyVariant | undefined;
|
|
@@ -6,7 +6,10 @@ export const FileBaseName = styled.span `
|
|
|
6
6
|
max-width: 100%;
|
|
7
7
|
|
|
8
8
|
text-overflow: ellipsis;
|
|
9
|
-
white-space: nowrap;
|
|
9
|
+
white-space: preserve nowrap;
|
|
10
|
+
`;
|
|
11
|
+
export const FileSuffix = styled.span `
|
|
12
|
+
white-space: pre;
|
|
10
13
|
`;
|
|
11
14
|
export const StyledTypography = styled(Typography, {
|
|
12
15
|
shouldForwardProp: (prop) => !['$align'].includes(prop),
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '../../../components/Button';
|
|
3
|
+
import { Filter2OutlineMd } from '../../../icons/Filter2OutlineMd';
|
|
4
|
+
import { formFiltersClassnames } from '../constants';
|
|
5
|
+
import { AllFiltersButtonWrapper, StyledBadge, StyledCounter } from './styles';
|
|
6
|
+
import { useLogic } from './useLogic';
|
|
7
|
+
export const AllFiltersButton = (props) => {
|
|
8
|
+
const { allFiltersButtonClassName, counter, onOpenModal } = useLogic(props);
|
|
9
|
+
return (_jsx(AllFiltersButtonWrapper, { className: allFiltersButtonClassName, children: _jsx(StyledBadge, { color: "error", badgeContent: counter, variant: "dot", children: _jsx(Button, { onClick: onOpenModal, variant: "outlined", color: "grey", startIcon: _jsx(Filter2OutlineMd, {}), endIcon: counter ? _jsx(StyledCounter, { color: "error", content: counter }) : null, className: formFiltersClassnames.allFiltersButton, children: "\u0412\u0441\u0435 \u0444\u0438\u043B\u044C\u0442\u0440\u044B" }) }) }));
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AllFiltersButton } from './AllFiltersButton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AllFiltersButton } from './AllFiltersButton';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const AllFiltersButtonWrapper: import("../../../components/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>, {}>;
|
|
6
|
+
export declare const StyledBadge: import("../../../components/styled").StyledComponent<Omit<import("../../..").WithoutEmotionSpecific<import("@mui/material/Badge").BadgeProps>, "color"> & {
|
|
7
|
+
color: import("../../../components/Badge").BadgeColor;
|
|
8
|
+
withBorder?: boolean | undefined;
|
|
9
|
+
variantColor?: import("../../../components/Badge").BadgeVariantsColor | undefined;
|
|
10
|
+
} & {
|
|
11
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
12
|
+
}, {}, {}>;
|
|
13
|
+
export declare const StyledCounter: import("../../../components/styled").StyledComponent<Omit<import("../../..").WithoutEmotionSpecific<import("@mui/material/Badge").BadgeProps>, "content" | "color" | "children" | "variant" | "invisible" | "anchorOrigin" | "badgeContent" | "overlap" | "withBorder"> & {
|
|
14
|
+
color: import("../../../components/Counter/types").CounterColor;
|
|
15
|
+
variant?: import("../../../components/Counter/types").CounterVariants | undefined;
|
|
16
|
+
content?: number | undefined;
|
|
17
|
+
} & {
|
|
18
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
19
|
+
}, {}, {}>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { badgeClasses } from '@mui/material/Badge';
|
|
2
|
+
import { Badge } from '../../../components/Badge';
|
|
3
|
+
import { Counter } from '../../../components/Counter';
|
|
4
|
+
import { styled } from '../../../components/styled';
|
|
5
|
+
import { formFiltersClassnames } from '../constants';
|
|
6
|
+
export const AllFiltersButtonWrapper = styled.div `
|
|
7
|
+
display: none;
|
|
8
|
+
|
|
9
|
+
white-space: nowrap;
|
|
10
|
+
|
|
11
|
+
&.${formFiltersClassnames.showAllFiltersButtonOnDesktop} {
|
|
12
|
+
display: flex;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
16
|
+
margin-right: 0;
|
|
17
|
+
&.${formFiltersClassnames.showAllFiltersButtonOnMobile} {
|
|
18
|
+
display: flex;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&.${formFiltersClassnames.withoutSearch} {
|
|
22
|
+
width: 100%;
|
|
23
|
+
|
|
24
|
+
.${formFiltersClassnames.allFiltersButton} {
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.${formFiltersClassnames.withSearch} {
|
|
30
|
+
.${formFiltersClassnames.allFiltersButton} {
|
|
31
|
+
display: unset;
|
|
32
|
+
gap: 0;
|
|
33
|
+
|
|
34
|
+
padding: 8px;
|
|
35
|
+
|
|
36
|
+
font-size: 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
export const StyledBadge = styled(Badge) `
|
|
42
|
+
width: 100%;
|
|
43
|
+
.${badgeClasses.dot} {
|
|
44
|
+
${({ theme }) => theme.breakpoints.up('sm')} {
|
|
45
|
+
display: none;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
export const StyledCounter = styled(Counter) `
|
|
50
|
+
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
51
|
+
display: none;
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type UseFormReturn } from 'react-hook-form';
|
|
2
|
+
export type AllFiltersButtonProps<TFieldValues extends Record<string, unknown>> = {
|
|
3
|
+
form: UseFormReturn<TFieldValues>;
|
|
4
|
+
onOpenModal: () => void;
|
|
5
|
+
hasMainFilters: boolean;
|
|
6
|
+
hasSecondaryFilters: boolean;
|
|
7
|
+
hasSearch: boolean;
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useLogic';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useLogic';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type AllFiltersButtonProps } from '../types';
|
|
2
|
+
export declare const useLogic: <TFieldValues extends Record<string, unknown>>({ form, onOpenModal, hasMainFilters, hasSecondaryFilters, hasSearch, }: AllFiltersButtonProps<TFieldValues>) => {
|
|
3
|
+
allFiltersButtonClassName: string;
|
|
4
|
+
counter: number;
|
|
5
|
+
onOpenModal: () => void;
|
|
6
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useWatch } from 'react-hook-form';
|
|
3
|
+
import { classNames } from '../../../../components/utils/classNames';
|
|
4
|
+
import { FORM_FILTERS_SEARCH_FIELD_ID } from '../../../FormFiltersSearchField/constants';
|
|
5
|
+
import { formFiltersClassnames } from '../../constants';
|
|
6
|
+
export const useLogic = ({ form, onOpenModal, hasMainFilters, hasSecondaryFilters, hasSearch, }) => {
|
|
7
|
+
const formValues = useWatch({
|
|
8
|
+
control: form.control,
|
|
9
|
+
});
|
|
10
|
+
const [searchName, setSearchName] = useState('');
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const searchFieldName = document
|
|
13
|
+
.getElementById(FORM_FILTERS_SEARCH_FIELD_ID)
|
|
14
|
+
?.getAttribute('name') || '';
|
|
15
|
+
setSearchName(searchFieldName);
|
|
16
|
+
}, [hasSearch]);
|
|
17
|
+
// Исключаем поиск из счетчика фильтров
|
|
18
|
+
const counter = Object.values(formValues || {}).filter(Boolean).length -
|
|
19
|
+
(formValues?.[searchName] ? 1 : 0);
|
|
20
|
+
const allFiltersButtonClassName = useMemo(() => {
|
|
21
|
+
return classNames({
|
|
22
|
+
[formFiltersClassnames.showAllFiltersButtonOnDesktop]: hasSecondaryFilters,
|
|
23
|
+
[formFiltersClassnames.showAllFiltersButtonOnMobile]: hasMainFilters || hasSecondaryFilters,
|
|
24
|
+
[formFiltersClassnames.withSearch]: hasSearch,
|
|
25
|
+
[formFiltersClassnames.withoutSearch]: !hasSearch,
|
|
26
|
+
});
|
|
27
|
+
}, [hasMainFilters, hasSecondaryFilters, hasSearch]);
|
|
28
|
+
return {
|
|
29
|
+
allFiltersButtonClassName,
|
|
30
|
+
counter,
|
|
31
|
+
onOpenModal,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
-
import { Button } from '../../components/Button';
|
|
3
|
-
import { Filter2OutlineMd } from '../../icons/Filter2OutlineMd';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
2
|
import { Form } from '../Form';
|
|
5
3
|
import { FormControlProvider } from '../FormControlProvider';
|
|
4
|
+
import { AllFiltersButton } from './AllFiltersButton';
|
|
6
5
|
import { formFiltersClassnames } from './constants';
|
|
7
6
|
import { FormFiltersDialog } from './FormFiltersDialog';
|
|
8
7
|
import { FormFiltersSkeleton } from './FormFiltersSkeleton';
|
|
9
|
-
import {
|
|
8
|
+
import { MainFiltersWrapper, SubmitButtonWrapper, Wrapper } from './styles';
|
|
10
9
|
import { useLogic } from './useLogic';
|
|
11
10
|
/**
|
|
12
11
|
* Компонент для отображения фильтров формы
|
|
13
12
|
*/
|
|
14
13
|
export const FormFilters = (props) => {
|
|
15
|
-
const {
|
|
14
|
+
const { form, onSubmit, searchField: SearchField, mainFilters: MainFilters, submitButton: SubmitButton, secondaryFilters: SecondaryFilters, onOpenModal, dialogProps, mainFiltersColumns, isLoading, } = useLogic(props);
|
|
16
15
|
if (isLoading) {
|
|
17
16
|
return _jsx(FormFiltersSkeleton, {});
|
|
18
17
|
}
|
|
19
|
-
return (_jsxs(
|
|
18
|
+
return (_jsxs(Form, { name: "form", form: form, onSubmit: form.handleSubmit(onSubmit || (() => undefined)), children: [_jsx(FormControlProvider, { size: "small", hideHelperText: true, children: _jsxs(Wrapper, { children: [SearchField && _jsx(SearchField, { control: form.control }), _jsx(AllFiltersButton, { form: form, onOpenModal: onOpenModal, hasMainFilters: Boolean(MainFilters), hasSecondaryFilters: Boolean(SecondaryFilters), hasSearch: Boolean(SearchField) }), _jsx(MainFiltersWrapper, { columns: mainFiltersColumns, children: MainFilters && (_jsx(MainFilters, { control: form.control, isModal: false })) }), SubmitButton && (_jsx(SubmitButtonWrapper, { children: _jsx(SubmitButton, { size: "medium", className: formFiltersClassnames.submitButton }) }))] }) }), _jsx(FormFiltersDialog, { ...dialogProps })] }));
|
|
20
19
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { type FormFiltersDialogProps } from '../types';
|
|
3
|
-
export declare const useLogic: <TFieldValues extends Record<string, unknown>>({ validationSchema,
|
|
3
|
+
export declare const useLogic: <TFieldValues extends Record<string, unknown>>({ validationSchema, mainFilters, secondaryFilters, isModalOpen, setIsModalOpen, onSubmit, form, }: FormFiltersDialogProps<TFieldValues>) => {
|
|
4
4
|
modalForm: import("react-hook-form").UseFormReturn<TFieldValues, any>;
|
|
5
5
|
onCloseModal: () => void;
|
|
6
6
|
onResetModal: () => void;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { useForm } from '../../../useForm';
|
|
3
|
-
export const useLogic = ({ validationSchema,
|
|
3
|
+
export const useLogic = ({ validationSchema, mainFilters, secondaryFilters, isModalOpen, setIsModalOpen, onSubmit, form, }) => {
|
|
4
4
|
const modalForm = useForm({
|
|
5
5
|
validationSchema,
|
|
6
|
-
defaultValues:
|
|
6
|
+
defaultValues: form.getValues(),
|
|
7
7
|
});
|
|
8
8
|
const onCloseModal = () => {
|
|
9
9
|
setIsModalOpen(false);
|
|
10
10
|
modalForm.reset();
|
|
11
11
|
};
|
|
12
12
|
const onResetModal = () => {
|
|
13
|
-
modalForm.reset(
|
|
13
|
+
modalForm.reset(form.getValues());
|
|
14
14
|
};
|
|
15
15
|
const onSubmitModal = (submittedValues) => {
|
|
16
16
|
onSubmit(submittedValues);
|
|
@@ -18,13 +18,10 @@ export const useLogic = ({ validationSchema, values, mainFilters, secondaryFilte
|
|
|
18
18
|
};
|
|
19
19
|
const isResetButtonDisabled = !modalForm.formState.isDirty;
|
|
20
20
|
useEffect(() => {
|
|
21
|
-
if (isModalOpen
|
|
21
|
+
if (isModalOpen) {
|
|
22
22
|
onResetModal();
|
|
23
23
|
}
|
|
24
24
|
}, [isModalOpen]);
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
modalForm.reset(values);
|
|
27
|
-
}, [values]);
|
|
28
25
|
return {
|
|
29
26
|
modalForm,
|
|
30
27
|
onCloseModal,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createUIKitClassname } from '../../components/utils/createUIKitClassname';
|
|
2
2
|
export const formFiltersClassnames = {
|
|
3
3
|
modalFilters: createUIKitClassname('form-filters__modal-filters'),
|
|
4
|
-
pageHeaderFilters: createUIKitClassname('form-filters__page-header-filters'),
|
|
5
4
|
submitButton: createUIKitClassname('form-filters__submit-button'),
|
|
6
5
|
allFiltersButton: createUIKitClassname('form-filters__all-filters-button'),
|
|
7
6
|
showAllFiltersButtonOnDesktop: createUIKitClassname('form-filters_show-all-filters-button_desktop'),
|
|
@@ -3,30 +3,12 @@ export declare const Wrapper: import("../../components/styled").StyledComponent<
|
|
|
3
3
|
theme?: import("@emotion/react").Theme | undefined;
|
|
4
4
|
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
5
5
|
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
6
|
-
export declare const AllFiltersButtonWrapper: import("../../components/styled").StyledComponent<{
|
|
7
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
8
|
-
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
9
|
-
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
10
6
|
export declare const MainFiltersWrapper: import("../../components/styled").StyledComponent<{
|
|
11
7
|
theme?: import("@emotion/react").Theme | undefined;
|
|
12
8
|
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
13
9
|
} & {
|
|
14
10
|
columns?: string | undefined;
|
|
15
11
|
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
16
|
-
export declare const StyledBadge: import("../../components/styled").StyledComponent<Omit<import("../..").WithoutEmotionSpecific<import("@mui/material/Badge").BadgeProps>, "color"> & {
|
|
17
|
-
color: import("../../components/Badge").BadgeColor;
|
|
18
|
-
withBorder?: boolean | undefined;
|
|
19
|
-
variantColor?: import("../../components/Badge").BadgeVariantsColor | undefined;
|
|
20
|
-
} & {
|
|
21
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
22
|
-
}, {}, {}>;
|
|
23
|
-
export declare const StyledCounter: import("../../components/styled").StyledComponent<Omit<import("../..").WithoutEmotionSpecific<import("@mui/material/Badge").BadgeProps>, "content" | "color" | "children" | "variant" | "invisible" | "anchorOrigin" | "badgeContent" | "overlap" | "withBorder"> & {
|
|
24
|
-
color: import("../../components/Counter/types").CounterColor;
|
|
25
|
-
variant?: import("../../components/Counter/types").CounterVariants | undefined;
|
|
26
|
-
content?: number | undefined;
|
|
27
|
-
} & {
|
|
28
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
29
|
-
}, {}, {}>;
|
|
30
12
|
export declare const SubmitButtonWrapper: import("../../components/styled").StyledComponent<{
|
|
31
13
|
theme?: import("@emotion/react").Theme | undefined;
|
|
32
14
|
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { badgeClasses } from '@mui/material/Badge';
|
|
2
1
|
import { formLabelClasses } from '@mui/material/FormLabel';
|
|
3
2
|
import { inputBaseClasses } from '@mui/material/InputBase';
|
|
4
|
-
import { Badge } from '../../components/Badge';
|
|
5
|
-
import { Counter } from '../../components/Counter';
|
|
6
3
|
import { styled } from '../../components/styled';
|
|
7
4
|
import { formFiltersClassnames } from './constants';
|
|
8
5
|
export const Wrapper = styled.div `
|
|
@@ -32,41 +29,6 @@ export const Wrapper = styled.div `
|
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
31
|
`;
|
|
35
|
-
export const AllFiltersButtonWrapper = styled.div `
|
|
36
|
-
display: none;
|
|
37
|
-
|
|
38
|
-
white-space: nowrap;
|
|
39
|
-
|
|
40
|
-
&.${formFiltersClassnames.showAllFiltersButtonOnDesktop} {
|
|
41
|
-
display: flex;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
45
|
-
margin-right: 0;
|
|
46
|
-
&.${formFiltersClassnames.showAllFiltersButtonOnMobile} {
|
|
47
|
-
display: flex;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
&.${formFiltersClassnames.withoutSearch} {
|
|
51
|
-
width: 100%;
|
|
52
|
-
|
|
53
|
-
.${formFiltersClassnames.allFiltersButton} {
|
|
54
|
-
width: 100%;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
&.${formFiltersClassnames.withSearch} {
|
|
59
|
-
.${formFiltersClassnames.allFiltersButton} {
|
|
60
|
-
display: unset;
|
|
61
|
-
gap: 0;
|
|
62
|
-
|
|
63
|
-
padding: 8px;
|
|
64
|
-
|
|
65
|
-
font-size: 0;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
`;
|
|
70
32
|
export const MainFiltersWrapper = styled.div `
|
|
71
33
|
display: grid;
|
|
72
34
|
grid-auto-flow: column;
|
|
@@ -79,19 +41,6 @@ export const MainFiltersWrapper = styled.div `
|
|
|
79
41
|
display: none;
|
|
80
42
|
}
|
|
81
43
|
`;
|
|
82
|
-
export const StyledBadge = styled(Badge) `
|
|
83
|
-
width: 100%;
|
|
84
|
-
.${badgeClasses.dot} {
|
|
85
|
-
${({ theme }) => theme.breakpoints.up('sm')} {
|
|
86
|
-
display: none;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
`;
|
|
90
|
-
export const StyledCounter = styled(Counter) `
|
|
91
|
-
${({ theme }) => theme.breakpoints.down('sm')} {
|
|
92
|
-
display: none;
|
|
93
|
-
}
|
|
94
|
-
`;
|
|
95
44
|
export const SubmitButtonWrapper = styled.div `
|
|
96
45
|
white-space: nowrap;
|
|
97
46
|
|
|
@@ -1,45 +1,36 @@
|
|
|
1
1
|
import { type ObjectAsyncGuard, type ObjectGuard } from '@astral/validations';
|
|
2
2
|
import { type ReactNode } from 'react';
|
|
3
|
-
import { type Control } from 'react-hook-form';
|
|
3
|
+
import { type Control, type UseFormReturn } from 'react-hook-form';
|
|
4
4
|
import type { ButtonProps } from '../../components/Button';
|
|
5
5
|
type InputsProps<TFieldValues extends Record<string, unknown>> = {
|
|
6
6
|
control: Control<TFieldValues>;
|
|
7
7
|
};
|
|
8
8
|
export type FormFiltersProps<TFieldValues extends Record<string, unknown>> = {
|
|
9
|
+
form: UseFormReturn<TFieldValues>;
|
|
10
|
+
onSubmit?: (values: TFieldValues) => void;
|
|
9
11
|
/**
|
|
10
12
|
* Схема валидации из @astral/validations
|
|
11
13
|
*/
|
|
12
14
|
validationSchema?: ObjectGuard<TFieldValues> | ObjectAsyncGuard<TFieldValues>;
|
|
13
|
-
/**
|
|
14
|
-
* Значения фильтров
|
|
15
|
-
*/
|
|
16
|
-
values?: TFieldValues;
|
|
17
|
-
/**
|
|
18
|
-
* Callback вызываемый при изменении значений фильтров. Вызывается с debounce (300ms)
|
|
19
|
-
*/
|
|
20
|
-
onChange: (values: TFieldValues) => void;
|
|
21
15
|
/**
|
|
22
16
|
* Поле поиска
|
|
23
17
|
*
|
|
24
18
|
* @example
|
|
25
19
|
* ```ts
|
|
26
20
|
* <FormFilters
|
|
27
|
-
* SearchField={(
|
|
21
|
+
* SearchField={({control}) => <FormFiltersSearchField control={control} placeholder="Поиск..." />}
|
|
28
22
|
* />
|
|
29
23
|
* ```
|
|
30
24
|
*/
|
|
31
|
-
searchField?: (props: InputsProps<TFieldValues>
|
|
32
|
-
fullWidth?: boolean;
|
|
33
|
-
}) => ReactNode;
|
|
25
|
+
searchField?: (props: InputsProps<TFieldValues>) => ReactNode;
|
|
34
26
|
/**
|
|
35
27
|
* Основные фильтры
|
|
36
28
|
*
|
|
37
29
|
* @example
|
|
38
30
|
* ```ts
|
|
39
31
|
* <FormFilters
|
|
40
|
-
* MainFilters={({ control, isModal
|
|
32
|
+
* MainFilters={({ control, isModal }) =>
|
|
41
33
|
* <FormTextField
|
|
42
|
-
* {...props}
|
|
43
34
|
* control={control}
|
|
44
35
|
* name="name"
|
|
45
36
|
* label="Название"
|
|
@@ -57,7 +48,7 @@ export type FormFiltersProps<TFieldValues extends Record<string, unknown>> = {
|
|
|
57
48
|
* @example
|
|
58
49
|
* ```ts
|
|
59
50
|
* <FormFilters
|
|
60
|
-
* SecondaryFilters={({ control
|
|
51
|
+
* SecondaryFilters={({ control }) => <FormTextField control={control} name="name" label="Название" placeholder="Введите название" />}
|
|
61
52
|
* />
|
|
62
53
|
* ```
|
|
63
54
|
*/
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import { type UseFormReturn } from '
|
|
1
|
+
import { type UseFormReturn } from 'react-hook-form';
|
|
2
2
|
import { type FormFiltersDialogProps } from '../FormFiltersDialog/types';
|
|
3
3
|
import { type FormFiltersProps } from '../types';
|
|
4
4
|
type UseLogicReturn<TFieldValues extends Record<string, unknown>> = {
|
|
5
|
-
|
|
5
|
+
form: UseFormReturn<TFieldValues>;
|
|
6
|
+
onSubmit?: (values: TFieldValues) => void;
|
|
6
7
|
searchField: FormFiltersProps<TFieldValues>['searchField'];
|
|
7
8
|
mainFilters: FormFiltersProps<TFieldValues>['mainFilters'];
|
|
8
9
|
submitButton: FormFiltersProps<TFieldValues>['submitButton'];
|
|
9
|
-
|
|
10
|
-
onSubmit: (submittedValues: TFieldValues) => void;
|
|
10
|
+
secondaryFilters: FormFiltersProps<TFieldValues>['secondaryFilters'];
|
|
11
11
|
onOpenModal: () => void;
|
|
12
12
|
dialogProps: FormFiltersDialogProps<TFieldValues>;
|
|
13
13
|
mainFiltersColumns?: string;
|
|
14
14
|
isLoading?: boolean;
|
|
15
|
-
allFiltersButtonClassName: string;
|
|
16
15
|
};
|
|
17
|
-
export declare const useLogic: <TFieldValues extends Record<string, unknown>>({
|
|
16
|
+
export declare const useLogic: <TFieldValues extends Record<string, unknown>>({ form, onSubmit, validationSchema, searchField, mainFilters, secondaryFilters, submitButton, mainFiltersColumns, isLoading, }: FormFiltersProps<TFieldValues>) => UseLogicReturn<TFieldValues>;
|
|
18
17
|
export {};
|
|
@@ -1,120 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { useWatch } from 'react-hook-form';
|
|
4
|
-
import { checkIsDeepEqual } from '../../../components/utils/checkIsDeepEqual';
|
|
5
|
-
import { classNames } from '../../../components/utils/classNames';
|
|
6
|
-
import { FORM_FILTERS_SEARCH_FIELD_ID } from '../../FormFiltersSearchField/constants';
|
|
7
|
-
import { useForm } from '../../useForm';
|
|
8
|
-
import { formFiltersClassnames } from '../constants';
|
|
9
|
-
import { useFirstMountAfterLoading } from './hooks';
|
|
10
|
-
export const useLogic = ({ validationSchema, values, onChange, searchField, mainFilters, secondaryFilters, submitButton, mainFiltersColumns, isLoading, }) => {
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
export const useLogic = ({ form, onSubmit, validationSchema, searchField, mainFilters, secondaryFilters, submitButton, mainFiltersColumns, isLoading, }) => {
|
|
11
3
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
12
|
-
const isFirstMount = useFirstMountAfterLoading(isLoading);
|
|
13
4
|
const onOpenModal = () => {
|
|
14
5
|
setIsModalOpen(true);
|
|
15
6
|
};
|
|
16
|
-
const headerForm = useForm({
|
|
17
|
-
validationSchema,
|
|
18
|
-
defaultValues: values,
|
|
19
|
-
});
|
|
20
|
-
const headerFormValues = useWatch({
|
|
21
|
-
control: headerForm.control,
|
|
22
|
-
});
|
|
23
|
-
// Ref для хранения debounced функции, чтобы можно было её отменить
|
|
24
|
-
const debouncedOnChangeRef = useRef(null);
|
|
25
|
-
// Ref для отслеживания внешнего reset (чтобы не вызывать onChange при внешнем reset)
|
|
26
|
-
const isExternalResetRef = useRef(false);
|
|
27
|
-
// Ref для хранения предыдущих внешних values (для сравнения)
|
|
28
|
-
const previousValuesRef = useRef(values);
|
|
29
|
-
// Отменяет предыдущий debounced вызов onChange, если он есть
|
|
30
|
-
const clearPreviousDebouncedOnChange = () => {
|
|
31
|
-
if (debouncedOnChangeRef.current) {
|
|
32
|
-
debouncedOnChangeRef.current.clear();
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
const hasSubmitButton = Boolean(submitButton);
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
// Если есть submitButton, не вызываем onChange при изменении значений
|
|
38
|
-
if (hasSubmitButton || isLoading || isFirstMount) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
clearPreviousDebouncedOnChange();
|
|
42
|
-
// Пропускаем onChange если это внешний reset
|
|
43
|
-
if (isExternalResetRef.current) {
|
|
44
|
-
isExternalResetRef.current = false;
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// Создаем новый debounced вызов
|
|
48
|
-
const debouncedOnChange = debounce(() => {
|
|
49
|
-
onChange(headerFormValues);
|
|
50
|
-
}, 300);
|
|
51
|
-
debouncedOnChangeRef.current = debouncedOnChange;
|
|
52
|
-
debouncedOnChange();
|
|
53
|
-
return () => {
|
|
54
|
-
debouncedOnChange.clear();
|
|
55
|
-
};
|
|
56
|
-
}, [headerFormValues, onChange, hasSubmitButton, isLoading]);
|
|
57
|
-
const searchName = document
|
|
58
|
-
.getElementById(FORM_FILTERS_SEARCH_FIELD_ID)
|
|
59
|
-
?.getAttribute('name') || '';
|
|
60
|
-
// Исключаем поиск из счетчика фильтров
|
|
61
|
-
const counter = Object.values(headerFormValues).filter(Boolean).length -
|
|
62
|
-
(headerFormValues[searchName] ? 1 : 0);
|
|
63
|
-
const setFiltersValues = (newValues) => headerForm.reset(newValues);
|
|
64
|
-
// Функция отправки формы на SubmitButton. Приводит к вызову onChange без debounce.
|
|
65
|
-
const onSubmit = (submittedValues) => {
|
|
66
|
-
clearPreviousDebouncedOnChange();
|
|
67
|
-
onChange?.(submittedValues);
|
|
68
|
-
};
|
|
69
7
|
// Функция отправки формы на кнопку "Применить" в модальном окне
|
|
70
8
|
const onSubmitModal = (submittedValues) => {
|
|
71
|
-
|
|
72
|
-
onSubmit(submittedValues);
|
|
9
|
+
form.reset(submittedValues);
|
|
73
10
|
};
|
|
74
|
-
// Синхронизация внешних values с формой
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (isFirstMount) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
// Сравниваем значения, чтобы избежать лишних reset
|
|
80
|
-
const valuesChanged = !checkIsDeepEqual(previousValuesRef.current, values);
|
|
81
|
-
if (!valuesChanged) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
clearPreviousDebouncedOnChange();
|
|
85
|
-
isExternalResetRef.current = true;
|
|
86
|
-
previousValuesRef.current = values;
|
|
87
|
-
setFiltersValues(values);
|
|
88
|
-
}, [values, headerForm]);
|
|
89
|
-
const allFiltersButtonClassName = useMemo(() => {
|
|
90
|
-
return classNames({
|
|
91
|
-
[formFiltersClassnames.showAllFiltersButtonOnDesktop]: Boolean(secondaryFilters),
|
|
92
|
-
[formFiltersClassnames.showAllFiltersButtonOnMobile]: Boolean(mainFilters) || Boolean(secondaryFilters),
|
|
93
|
-
[formFiltersClassnames.withSearch]: Boolean(searchField),
|
|
94
|
-
[formFiltersClassnames.withoutSearch]: !searchField,
|
|
95
|
-
});
|
|
96
|
-
}, [mainFilters, secondaryFilters, searchField]);
|
|
97
11
|
const dialogProps = {
|
|
98
12
|
validationSchema,
|
|
99
|
-
|
|
13
|
+
form,
|
|
100
14
|
mainFilters,
|
|
101
15
|
secondaryFilters,
|
|
102
|
-
defaultValues: headerFormValues,
|
|
103
16
|
onSubmit: onSubmitModal,
|
|
104
17
|
isModalOpen,
|
|
105
18
|
setIsModalOpen,
|
|
106
19
|
};
|
|
107
20
|
return {
|
|
108
|
-
|
|
21
|
+
form,
|
|
22
|
+
onSubmit,
|
|
109
23
|
searchField,
|
|
110
24
|
mainFilters,
|
|
25
|
+
secondaryFilters,
|
|
111
26
|
submitButton,
|
|
112
|
-
counter,
|
|
113
|
-
onSubmit,
|
|
114
27
|
onOpenModal,
|
|
115
28
|
dialogProps,
|
|
116
29
|
mainFiltersColumns,
|
|
117
30
|
isLoading,
|
|
118
|
-
allFiltersButtonClassName,
|
|
119
31
|
};
|
|
120
32
|
};
|
|
@@ -12,6 +12,6 @@ function FormFiltersSearchFieldInner({ width, ...props }, ref) {
|
|
|
12
12
|
...props,
|
|
13
13
|
defaultValue: props.defaultValue || '',
|
|
14
14
|
});
|
|
15
|
-
return (_jsx(Wrapper, { "$width": width, children: _jsx(SearchField, { ...fieldProps, ref: ref, inputProps: { id: FORM_FILTERS_SEARCH_FIELD_ID } }) }));
|
|
15
|
+
return (_jsx(Wrapper, { "$width": width, children: _jsx(SearchField, { ...fieldProps, ref: ref, inputProps: { id: FORM_FILTERS_SEARCH_FIELD_ID }, fullWidth: true }) }));
|
|
16
16
|
}
|
|
17
17
|
export const FormFiltersSearchField = forwardRefWithGeneric(FormFiltersSearchFieldInner);
|
|
@@ -17,5 +17,5 @@ exports.Filename = (0, react_1.forwardRef)((props, forwardedRef) => {
|
|
|
17
17
|
const hidePersonalDataClassname = (0, personalDataSecurity_1.useHidePersonalData)({
|
|
18
18
|
isEnabled: isHidePersonalData,
|
|
19
19
|
});
|
|
20
|
-
return ((0, jsx_runtime_1.jsx)(Tooltip_1.Tooltip, { title: isOverflowed && children, disableInteractive: true, ...tooltipProps, className: (0, classNames_1.classNames)(tooltipProps?.className, hidePersonalDataClassname), children: (0, jsx_runtime_1.jsxs)(styles_1.StyledTypography, { "$align": align, variant: variant, className: (0, classNames_1.classNames)(className, hidePersonalDataClassname), ...restProps, children: [(0, jsx_runtime_1.jsx)(styles_1.FileBaseName, { ...baseNameProps }), (0, jsx_runtime_1.jsx)(
|
|
20
|
+
return ((0, jsx_runtime_1.jsx)(Tooltip_1.Tooltip, { title: isOverflowed && children, disableInteractive: true, ...tooltipProps, className: (0, classNames_1.classNames)(tooltipProps?.className, hidePersonalDataClassname), children: (0, jsx_runtime_1.jsxs)(styles_1.StyledTypography, { "$align": align, variant: variant, className: (0, classNames_1.classNames)(className, hidePersonalDataClassname), ...restProps, children: [(0, jsx_runtime_1.jsx)(styles_1.FileBaseName, { ...baseNameProps }), (0, jsx_runtime_1.jsx)(styles_1.FileSuffix, { children: suffixWithExtension })] }) }));
|
|
21
21
|
});
|