kelt-ui-kit-react 0.1.9 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/card/Card.d.ts +0 -8
  2. package/dist/card/cardAction/CardAction.d.ts +8 -0
  3. package/dist/card/cardAction.interface.d.ts +1 -0
  4. package/dist/card/hook/useCardInteractions.d.ts +8 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +1201 -1146
  7. package/dist/menus/menu/menu.interface.d.ts +1 -0
  8. package/dist/modal/Modal.d.ts +10 -0
  9. package/dist/modal/Modal.view.d.ts +1 -0
  10. package/dist/overlayPanel/overlay.context.d.ts +11 -0
  11. package/dist/sidebar/Sidebar.d.ts +4 -3
  12. package/dist/sidebarData/SidebarData.d.ts +3 -7
  13. package/dist/style.css +1 -1
  14. package/package.json +1 -1
  15. package/src/App.menu.tsx +8 -0
  16. package/src/App.tsx +12 -9
  17. package/src/card/Card.tsx +22 -53
  18. package/src/card/Card.view.tsx +3 -4
  19. package/src/card/card.css +56 -12
  20. package/src/card/cardAction/CardAction.tsx +72 -0
  21. package/src/card/cardAction/cardAction.css +7 -0
  22. package/src/card/cardAction.interface.tsx +1 -0
  23. package/src/card/hook/useCardInteractions.tsx +30 -0
  24. package/src/index.css +15 -1
  25. package/src/index.ts +2 -0
  26. package/src/menus/menu/menu.interface.tsx +1 -0
  27. package/src/modal/Modal.tsx +34 -0
  28. package/src/modal/Modal.view.tsx +19 -0
  29. package/src/modal/modal.css +63 -0
  30. package/src/overlayPanel/OverlayPanel.tsx +52 -48
  31. package/src/overlayPanel/OverlayPanel.view.tsx +3 -2
  32. package/src/overlayPanel/overlay.context.tsx +28 -0
  33. package/src/quantity/Quantity.tsx +3 -0
  34. package/src/quantity/quantity.css +5 -0
  35. package/src/sidebar/Sidebar.tsx +7 -2
  36. package/src/sidebarData/SidebarData.tsx +7 -23
@@ -1,8 +1,11 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
1
+ import React, { useCallback, useEffect, useId, useRef, useState } from "react";
2
2
  import ReactDOM from "react-dom";
3
+
3
4
  import { Icon } from "../icon/Icon";
5
+ import { useOverlayContext } from "./overlay.context";
4
6
  import "./overlayPanel.css";
5
7
  import { OverlayPanelStyled } from "./overlayPanelStyled/overlayPanelStyled";
8
+
6
9
  type Position =
7
10
  | "left"
8
11
  | "right"
@@ -12,8 +15,8 @@ type Position =
12
15
  | "bottomRight";
13
16
 
14
17
  interface OverlayPanelProps {
15
- referenceElement: HTMLElement; // Élément de référence
16
- position?: Position; // Position souhaitée par rapport à l'élément
18
+ referenceElement: HTMLElement;
19
+ position?: Position;
17
20
  children: React.ReactNode;
18
21
  show?: boolean;
19
22
  closeOverlay?: (close: boolean) => void;
@@ -26,57 +29,44 @@ export const OverlayPanel = ({
26
29
  show,
27
30
  closeOverlay,
28
31
  }: OverlayPanelProps) => {
32
+ const { activeOverlayId, setActiveOverlay } = useOverlayContext();
29
33
  const [isShow, setIsShow] = useState(show || false);
30
34
  const [coords, setCoords] = useState({ top: 0, left: 0 });
31
35
  const boxRef = useRef<HTMLDivElement>(null);
32
- const getCoordTopRight = (rect: DOMRect, boxRect: DOMRect) => {
33
- return {
34
- top: rect.top - boxRect.height,
35
- left: rect.right - boxRect.width,
36
- };
37
- };
38
- const getCoordTopLeft = (rect: DOMRect, boxRect: DOMRect) => {
39
- return {
40
- top: rect.top - boxRect.height,
41
- left: rect.left,
42
- };
43
- };
44
- const getCoordBottomRight = (rect: DOMRect, panelRect: DOMRect) => {
45
- return {
46
- top: rect.bottom,
47
- left: rect.right - panelRect.width,
48
- };
49
- };
50
- const getCoordBottomLeft = (rect: DOMRect) => {
51
- return {
52
- top: rect.bottom,
53
- left: rect.left,
54
- };
55
- };
56
- const getCoordLeft = (rect: DOMRect, boxRect: DOMRect) => {
57
- return {
58
- top: rect.top + rect.height / 2 - boxRect.height / 2,
59
- left: rect.left - boxRect.width,
60
- };
61
- };
62
- const getCoordRight = (rect: DOMRect, boxRect: DOMRect) => {
63
- return {
64
- top: rect.top + rect.height / 2 - boxRect.height / 2,
65
- left: rect.right,
66
- };
67
- };
36
+ const overlayId = useId();
37
+ useEffect(() => {
38
+ if (activeOverlayId !== overlayId) {
39
+ setIsShow(false);
40
+ }
41
+ }, [activeOverlayId, overlayId]);
42
+
68
43
  useEffect(() => {
69
44
  const updatePosition = () => {
70
45
  const rect = referenceElement.getBoundingClientRect();
71
46
  const boxRect = boxRef.current?.getBoundingClientRect();
72
47
  if (boxRect) {
73
48
  const coords = {
74
- topRight: getCoordTopRight,
75
- topLeft: getCoordTopLeft,
76
- bottomRight: getCoordBottomRight,
77
- bottomLeft: getCoordBottomLeft,
78
- left: getCoordLeft,
79
- right: getCoordRight,
49
+ topRight: (r: DOMRect, b: DOMRect) => ({
50
+ top: r.top - b.height,
51
+ left: r.right - b.width,
52
+ }),
53
+ topLeft: (r: DOMRect, b: DOMRect) => ({
54
+ top: r.top - b.height,
55
+ left: r.left,
56
+ }),
57
+ bottomRight: (r: DOMRect, b: DOMRect) => ({
58
+ top: r.bottom,
59
+ left: r.right - b.width,
60
+ }),
61
+ bottomLeft: (r: DOMRect) => ({ top: r.bottom, left: r.left }),
62
+ left: (r: DOMRect, b: DOMRect) => ({
63
+ top: r.top + r.height / 2 - b.height / 2,
64
+ left: r.left - b.width,
65
+ }),
66
+ right: (r: DOMRect, b: DOMRect) => ({
67
+ top: r.top + r.height / 2 - b.height / 2,
68
+ left: r.right,
69
+ }),
80
70
  };
81
71
  const { top, left } = coords[position ?? "topLeft"](rect, boxRect);
82
72
  setCoords({ top, left });
@@ -87,18 +77,32 @@ export const OverlayPanel = ({
87
77
  window.addEventListener("resize", updatePosition);
88
78
  return () => window.removeEventListener("resize", updatePosition);
89
79
  }, [referenceElement, position]);
90
- const toggleSidebar = useCallback(() => {
80
+
81
+ const openOverlay = () => {
82
+ setIsShow(true);
83
+ setActiveOverlay(overlayId);
84
+ };
85
+
86
+ const closeOverlayHandler = useCallback(() => {
91
87
  setIsShow(false);
88
+ setActiveOverlay(null);
92
89
  if (closeOverlay) {
93
90
  closeOverlay(false);
94
91
  }
95
- }, [isShow]);
92
+ }, [closeOverlay, setActiveOverlay]);
93
+
94
+ useEffect(() => {
95
+ if (show) {
96
+ openOverlay();
97
+ }
98
+ }, [show]);
96
99
 
97
100
  if (!isShow) return null;
101
+
98
102
  return ReactDOM.createPortal(
99
103
  <OverlayPanelStyled ref={boxRef} $top={coords.top} $left={coords.left}>
100
104
  <div className="overlayPanel">
101
- <button className="toggle-btn" onClick={toggleSidebar}>
105
+ <button className="toggle-btn" onClick={closeOverlayHandler}>
102
106
  <Icon classIcon="bi-x-lg" />
103
107
  </button>
104
108
  {children}
@@ -1,16 +1,17 @@
1
1
  import { useRef, useState } from "react";
2
- import { OverlayPanel } from "./OverlayPanel";
3
2
  import { Icon } from "../icon/Icon";
3
+ import { OverlayPanel } from "./OverlayPanel";
4
4
 
5
5
  export const OverlayPanelView = () => {
6
6
  const refButton = useRef<HTMLDivElement>(null);
7
7
  const [openOverlay, setOpenOverlay] = useState(false);
8
+
8
9
  return (
9
10
  <>
10
11
  <div ref={refButton} onClick={() => setOpenOverlay(!openOverlay)}>
11
12
  <Icon classIcon="bi-list" />
12
13
  </div>
13
- {openOverlay && refButton.current && (
14
+ {refButton.current && (
14
15
  <OverlayPanel
15
16
  position="bottomRight"
16
17
  show={openOverlay}
@@ -0,0 +1,28 @@
1
+ import React, { createContext, useContext, useState } from "react";
2
+
3
+ interface OverlayContextType {
4
+ activeOverlayId: string | null;
5
+ setActiveOverlay: (id: string | null) => void;
6
+ }
7
+
8
+ const OverlayContext = createContext<OverlayContextType | undefined>(undefined);
9
+
10
+ export const OverlayProvider: React.FC<{ children: React.ReactNode }> = ({
11
+ children,
12
+ }) => {
13
+ const [activeOverlayId, setActiveOverlay] = useState<string | null>(null);
14
+
15
+ return (
16
+ <OverlayContext.Provider value={{ activeOverlayId, setActiveOverlay }}>
17
+ {children}
18
+ </OverlayContext.Provider>
19
+ );
20
+ };
21
+
22
+ export const useOverlayContext = () => {
23
+ const context = useContext(OverlayContext);
24
+ if (!context) {
25
+ throw new Error("useOverlayContext must be used within an OverlayProvider");
26
+ }
27
+ return context;
28
+ };
@@ -29,6 +29,9 @@ export const Quantity = ({ setQuantity, item }: QuantityProps) => {
29
29
  const decrementQte = useCallback(
30
30
  (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
31
31
  e.stopPropagation();
32
+ if (qte === 0) {
33
+ return qte;
34
+ }
32
35
  changeQuantity(qte - 1);
33
36
  },
34
37
  [changeQuantity, qte]
@@ -1,9 +1,14 @@
1
1
  .qte {
2
2
  display: flex;
3
3
  align-items: center;
4
+ .qte-label {
5
+ width: 20px;
6
+ text-align: center;
7
+ }
4
8
  .qte-action {
5
9
  cursor: pointer;
6
10
  margin-right: 1.5rem;
11
+
7
12
  &.qte-action--plus {
8
13
  margin-left: 0.5rem;
9
14
  }
@@ -3,13 +3,15 @@ import ReactDOM from "react-dom";
3
3
  import { Icon } from "../icon/Icon";
4
4
  import "./sidebar.css";
5
5
 
6
- interface SidebarProps {
6
+ export interface SidebarProps {
7
7
  id?: string;
8
8
  open?: boolean;
9
9
  title?: string;
10
10
  children?: React.ReactNode;
11
11
  className?: string;
12
12
  width?: string;
13
+ displayOverlay?: boolean;
14
+ closeOnClickOutside?: boolean;
13
15
  onClose?: (close: boolean) => void;
14
16
  }
15
17
 
@@ -21,6 +23,8 @@ export const Sidebar = ({
21
23
  className,
22
24
  id,
23
25
  width,
26
+ closeOnClickOutside = true,
27
+ displayOverlay = true,
24
28
  }: SidebarProps): JSX.Element => {
25
29
  const [isOpen, setIsOpen] = useState(open || false);
26
30
  const sidebarRef = useRef<HTMLDivElement | null>(null);
@@ -57,6 +61,7 @@ export const Sidebar = ({
57
61
 
58
62
  const handleClickOutside = useCallback(
59
63
  (event: MouseEvent) => {
64
+ if (!closeOnClickOutside) return;
60
65
  if (
61
66
  sidebarRef.current &&
62
67
  !sidebarRef.current.contains(event.target as Node)
@@ -80,7 +85,7 @@ export const Sidebar = ({
80
85
 
81
86
  return ReactDOM.createPortal(
82
87
  <>
83
- {isOpen && <div className="overlay"></div>}
88
+ {isOpen && displayOverlay && <div className="overlay"></div>}
84
89
  <div
85
90
  ref={sidebarRef}
86
91
  style={width ? { width: width } : {}}
@@ -1,33 +1,17 @@
1
- import { Sidebar } from "../sidebar/Sidebar";
1
+ import { Sidebar, SidebarProps } from "../sidebar/Sidebar";
2
2
  import "./sidebarData.css";
3
3
 
4
- interface SidebarDataProps {
5
- open?: boolean;
6
- title?: string;
7
- width?: string;
8
- className?: string;
4
+ interface SidebarDataProps extends SidebarProps {
9
5
  children?: React.ReactNode;
10
- onClose?: (close: boolean) => void;
11
6
  }
12
7
 
13
- export const SidebarData = ({
14
- open,
15
- children,
16
- title,
17
- onClose,
18
- width,
19
- className,
20
- }: SidebarDataProps) => {
8
+ export const SidebarData = (props: SidebarDataProps) => {
21
9
  return (
22
10
  <>
23
- <Sidebar
24
- onClose={onClose}
25
- title={title}
26
- open={open}
27
- width={width}
28
- className={`full sidebar-data ${className}`}
29
- >
30
- {children && <div className="sidebar-data-content">{children}</div>}
11
+ <Sidebar {...props} className={`full sidebar-data ${props.className}`}>
12
+ {props.children && (
13
+ <div className="sidebar-data-content">{props.children}</div>
14
+ )}
31
15
  </Sidebar>
32
16
  </>
33
17
  );