kelt-ui-kit-react 1.6.7 → 1.6.8
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/package.json +1 -1
- package/src/button/Button.view.tsx +24 -0
- package/src/button/buttonActions/ButtonActions.tsx +1 -1
- package/src/button/buttonFilters/ButtonFilters.tsx +102 -0
- package/src/button/buttonFilters/buttonFilters.css +22 -0
- package/src/modal/Modal.tsx +9 -3
- package/src/modal/Modal.view.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
+
import { TypeInputEnum } from "../form/form.enum";
|
|
3
|
+
import { FormInterface } from "../form/form.interface";
|
|
2
4
|
import { Button } from "./Button";
|
|
3
5
|
import { ButtonInterface } from "./button.interface";
|
|
4
6
|
import {
|
|
5
7
|
ButtonActions,
|
|
6
8
|
ButtonActionsProps,
|
|
7
9
|
} from "./buttonActions/ButtonActions";
|
|
10
|
+
import { ButtonFilters } from "./buttonFilters/ButtonFilters";
|
|
8
11
|
|
|
9
12
|
export const ButtonView = (): JSX.Element => {
|
|
13
|
+
const initialValues: FormInterface[] = [
|
|
14
|
+
{
|
|
15
|
+
value: false,
|
|
16
|
+
name: "test1",
|
|
17
|
+
label: "test 1",
|
|
18
|
+
type: TypeInputEnum.CHECKBOX,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: false,
|
|
22
|
+
name: "test2",
|
|
23
|
+
label: "test 2",
|
|
24
|
+
type: TypeInputEnum.CHECKBOX,
|
|
25
|
+
},
|
|
26
|
+
];
|
|
10
27
|
const mockButtonItems: ButtonInterface[] = [
|
|
11
28
|
{
|
|
12
29
|
title: "Envoyer",
|
|
@@ -56,6 +73,13 @@ export const ButtonView = (): JSX.Element => {
|
|
|
56
73
|
</div>
|
|
57
74
|
))}
|
|
58
75
|
<ButtonActions {...mockButtonAction} />
|
|
76
|
+
<div className="ml-2">
|
|
77
|
+
<ButtonFilters
|
|
78
|
+
classIcon="bi-send"
|
|
79
|
+
{...mockButtonAction}
|
|
80
|
+
dataForm={initialValues}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
59
83
|
</div>
|
|
60
84
|
);
|
|
61
85
|
};
|
|
@@ -39,7 +39,7 @@ export const ButtonActions = ({
|
|
|
39
39
|
e.stopPropagation();
|
|
40
40
|
if (actions) setOpenOverlay(!openOverlay);
|
|
41
41
|
},
|
|
42
|
-
[openOverlay, setOpenOverlay]
|
|
42
|
+
[openOverlay, setOpenOverlay],
|
|
43
43
|
);
|
|
44
44
|
const overlayMenu: MenuInterface[] = useMemo(() => {
|
|
45
45
|
if (!actions) return [];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { DynamicForm } from "../../form/Form";
|
|
3
|
+
import { FormInterface, FormValuesInterface } from "../../form/form.interface";
|
|
4
|
+
import { Icon } from "../../icon/Icon";
|
|
5
|
+
import { IconSizeEnum } from "../../icon/iconSize.enum";
|
|
6
|
+
import "./buttonFilters.css";
|
|
7
|
+
export type ButtonActionsProps<
|
|
8
|
+
T extends { [key: string]: string | number | boolean | Date | string[] },
|
|
9
|
+
> = {
|
|
10
|
+
className?: string;
|
|
11
|
+
onClick?: (e: React.MouseEvent) => void;
|
|
12
|
+
title: string;
|
|
13
|
+
classIcon?: string;
|
|
14
|
+
sizeIcon?: IconSizeEnum;
|
|
15
|
+
dataForm: FormInterface[];
|
|
16
|
+
onChange?: (values: FormValuesInterface<T>) => void;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
id?: string;
|
|
19
|
+
};
|
|
20
|
+
export const ButtonFilters = <
|
|
21
|
+
T extends { [key: string]: string | number | boolean | Date | string[] },
|
|
22
|
+
>({
|
|
23
|
+
className,
|
|
24
|
+
onClick,
|
|
25
|
+
title,
|
|
26
|
+
classIcon,
|
|
27
|
+
sizeIcon,
|
|
28
|
+
disabled = false,
|
|
29
|
+
id,
|
|
30
|
+
dataForm,
|
|
31
|
+
onChange,
|
|
32
|
+
}: ButtonActionsProps<T>) => {
|
|
33
|
+
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
|
34
|
+
const [openFilters, setOpenFilters] = useState(false);
|
|
35
|
+
const handleClick = (e: React.MouseEvent) => {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
setOpenFilters(!openFilters);
|
|
38
|
+
if (onClick) {
|
|
39
|
+
onClick(e);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const handleClickOutside = useCallback(
|
|
43
|
+
(event: MouseEvent) => {
|
|
44
|
+
if (
|
|
45
|
+
buttonRef.current &&
|
|
46
|
+
!buttonRef.current.contains(event.target as Node)
|
|
47
|
+
) {
|
|
48
|
+
setOpenFilters(false);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
[setOpenFilters],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (openFilters) {
|
|
56
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
57
|
+
} else {
|
|
58
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return () => {
|
|
62
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
63
|
+
};
|
|
64
|
+
}, [openFilters, handleClickOutside]);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
<button
|
|
69
|
+
ref={buttonRef}
|
|
70
|
+
id={id ?? ""}
|
|
71
|
+
disabled={disabled}
|
|
72
|
+
type="button"
|
|
73
|
+
onClick={(e) => handleClick(e)}
|
|
74
|
+
className={` ${className} button--filters button--transparent `}
|
|
75
|
+
>
|
|
76
|
+
{classIcon && (
|
|
77
|
+
<span>
|
|
78
|
+
<Icon
|
|
79
|
+
classIcon={classIcon}
|
|
80
|
+
size={sizeIcon || IconSizeEnum.EXTRA_SMALL}
|
|
81
|
+
/>
|
|
82
|
+
</span>
|
|
83
|
+
)}
|
|
84
|
+
<span className=" flex-1">{title}</span>
|
|
85
|
+
{openFilters && (
|
|
86
|
+
<div
|
|
87
|
+
className="button--filters-overlay"
|
|
88
|
+
onClick={(e) => e.stopPropagation()}
|
|
89
|
+
>
|
|
90
|
+
<div className="button--filters-overlay-content">
|
|
91
|
+
<DynamicForm
|
|
92
|
+
onChange={onChange as any}
|
|
93
|
+
initialForm={dataForm}
|
|
94
|
+
hideSubmit
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
)}
|
|
99
|
+
</button>
|
|
100
|
+
</>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.button--filters {
|
|
2
|
+
position: relative;
|
|
3
|
+
.button--filters-overlay {
|
|
4
|
+
position: absolute;
|
|
5
|
+
margin-top: 0.25rem;
|
|
6
|
+
top: 100%;
|
|
7
|
+
left: 0;
|
|
8
|
+
background-color: white;
|
|
9
|
+
border: 1px solid #ccc;
|
|
10
|
+
padding: 10px;
|
|
11
|
+
z-index: 1000;
|
|
12
|
+
border-radius: 4px;
|
|
13
|
+
width: 100%;
|
|
14
|
+
.button--filters-overlay-content {
|
|
15
|
+
display: flex;
|
|
16
|
+
gap: 0.5rem;
|
|
17
|
+
label {
|
|
18
|
+
color: #333;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/modal/Modal.tsx
CHANGED
|
@@ -13,6 +13,7 @@ interface ModalProps {
|
|
|
13
13
|
title?: string;
|
|
14
14
|
styleContainer?: React.CSSProperties;
|
|
15
15
|
classNameContainer?: string;
|
|
16
|
+
closeOnOverlayClick?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const Modal: React.FC<ModalProps> = ({
|
|
@@ -24,11 +25,16 @@ export const Modal: React.FC<ModalProps> = ({
|
|
|
24
25
|
title,
|
|
25
26
|
styleContainer = {},
|
|
26
27
|
classNameContainer = "",
|
|
28
|
+
closeOnOverlayClick = true,
|
|
27
29
|
}) => {
|
|
28
30
|
if (!isOpen) return null;
|
|
29
|
-
|
|
31
|
+
const handleOverlayMouseDown = () => {
|
|
32
|
+
if (closeOnOverlayClick) {
|
|
33
|
+
onClose();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
30
36
|
return createPortal(
|
|
31
|
-
<div className="modal-overlay" onMouseDown={
|
|
37
|
+
<div className="modal-overlay" onMouseDown={handleOverlayMouseDown}>
|
|
32
38
|
<div
|
|
33
39
|
className={`modal-container ${classNameContainer}`}
|
|
34
40
|
style={styleContainer}
|
|
@@ -48,6 +54,6 @@ export const Modal: React.FC<ModalProps> = ({
|
|
|
48
54
|
)}
|
|
49
55
|
</div>
|
|
50
56
|
</div>,
|
|
51
|
-
document.body
|
|
57
|
+
document.body,
|
|
52
58
|
);
|
|
53
59
|
};
|