kelt-ui-kit-react 2.0.2 → 2.0.3

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 (127) hide show
  1. package/README.md +0 -26
  2. package/dist/_core/type/generiqueType.d.ts +4 -0
  3. package/dist/badge/Badge.d.ts +3 -1
  4. package/dist/button/Button.d.ts +1 -1
  5. package/dist/button/button.interface.d.ts +1 -2
  6. package/dist/dataTable/DataTable.d.ts +17 -14
  7. package/dist/dataTable/dataTable.interface.d.ts +24 -19
  8. package/dist/dataTable/dataTableActions/DataTableAction.d.ts +3 -5
  9. package/dist/dataTable/dataTableColumn/DataTableColumn.d.ts +13 -7
  10. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.d.ts +10 -0
  11. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.d.ts +9 -0
  12. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.d.ts +9 -0
  13. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.d.ts +13 -0
  14. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.d.ts +9 -0
  15. package/dist/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.d.ts +11 -0
  16. package/dist/dataTable/dataTableFilters/DataTableFilters.d.ts +7 -0
  17. package/dist/dataTable/dataTableLoading/DataTableLoading.d.ts +1 -3
  18. package/dist/dataTable/dataTableRow/DataTableRow.d.ts +5 -6
  19. package/dist/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.d.ts +12 -0
  20. package/dist/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.d.ts +11 -0
  21. package/dist/expands/expand/expand.d.ts +1 -1
  22. package/dist/form/Form.d.ts +2 -4
  23. package/dist/form/form.enum.d.ts +2 -3
  24. package/dist/form/form.interface.d.ts +2 -19
  25. package/dist/form/input/Input.d.ts +3 -0
  26. package/dist/form/inputNumber/InputNumber.d.ts +0 -2
  27. package/dist/grid/col/Col.d.ts +6 -3
  28. package/dist/grid/col/colStyled/ColStyled.d.ts +5 -7
  29. package/dist/grid/grid.interface.d.ts +5 -9
  30. package/dist/header/Header.d.ts +1 -1
  31. package/dist/header/header.interface.d.ts +1 -2
  32. package/dist/icon/Icon.d.ts +1 -1
  33. package/dist/icon/icon.interface.d.ts +1 -0
  34. package/dist/index.d.ts +1 -5
  35. package/dist/index.js +3606 -3543
  36. package/dist/menus/menu/Menu.d.ts +0 -1
  37. package/dist/overlayPanel/OverlayPanel.d.ts +4 -2
  38. package/dist/overlayPanel/overlayPanelStyled/OverlayPanelStyled.d.ts +2 -0
  39. package/dist/select/Select.d.ts +6 -2
  40. package/dist/select/selectOption.interface.d.ts +1 -0
  41. package/dist/style.css +1 -1
  42. package/dist/tabs/Tabs.d.ts +2 -1
  43. package/dist/toaster/store/useToasterStore.d.ts +0 -1
  44. package/index.html +2 -1
  45. package/package/package.json +56 -0
  46. package/package/src/sidebar/Sidebar.tsx +208 -0
  47. package/package/src/sidebar/sidebar.css +104 -0
  48. package/package.json +1 -1
  49. package/src/App.menu.tsx +0 -8
  50. package/src/_core/type/generiqueType.tsx +4 -0
  51. package/src/badge/Badge.tsx +9 -1
  52. package/src/badge/badge.css +4 -0
  53. package/src/button/Button.tsx +1 -3
  54. package/src/button/button.css +2 -2
  55. package/src/button/button.interface.tsx +1 -2
  56. package/src/card/card.css +25 -5
  57. package/src/card/cardAction/CardAction.tsx +4 -4
  58. package/src/damier/Damier.tsx +7 -16
  59. package/src/damier/damier.css +4 -11
  60. package/src/dataTable/DataTable.tsx +685 -542
  61. package/src/dataTable/DataTable.view.tsx +48 -24
  62. package/src/dataTable/dataTable.css +134 -159
  63. package/src/dataTable/dataTable.interface.ts +25 -19
  64. package/src/dataTable/dataTableActions/DataTableAction.tsx +14 -25
  65. package/src/dataTable/dataTableColumn/DataTableColumn.tsx +64 -14
  66. package/src/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.tsx +36 -0
  67. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilter.css +0 -0
  68. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.tsx +39 -0
  69. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.tsx +80 -0
  70. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.tsx +89 -0
  71. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.tsx +37 -0
  72. package/src/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.tsx +42 -0
  73. package/src/dataTable/dataTableFilters/DataTableFilters.tsx +91 -0
  74. package/src/dataTable/dataTableFilters/dataTableFilters.css +16 -0
  75. package/src/dataTable/dataTableLoading/DataTableLoading.tsx +4 -15
  76. package/src/dataTable/dataTableRow/DataTableRow.tsx +64 -180
  77. package/src/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.tsx +80 -0
  78. package/src/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.tsx +123 -0
  79. package/src/expands/Expands.tsx +2 -16
  80. package/src/expands/expand/expand.tsx +5 -122
  81. package/src/expands/expands.css +3 -8
  82. package/src/form/Form.tsx +93 -258
  83. package/src/form/Form.view.tsx +1 -9
  84. package/src/form/form.css +1 -51
  85. package/src/form/form.enum.ts +1 -2
  86. package/src/form/form.interface.tsx +2 -28
  87. package/src/form/input/Input.tsx +61 -7
  88. package/src/form/input/input.css +23 -1
  89. package/src/form/inputNumber/InputNumber.tsx +6 -11
  90. package/src/form/inputPrice/InputPrice.tsx +2 -4
  91. package/src/grid/col/Col.tsx +7 -5
  92. package/src/grid/col/colStyled/ColStyled.tsx +7 -21
  93. package/src/grid/grid.interface.tsx +5 -11
  94. package/src/grid/row/row.css +2 -2
  95. package/src/header/Header.tsx +2 -4
  96. package/src/header/header.css +0 -17
  97. package/src/header/header.interface.tsx +1 -2
  98. package/src/icon/Icon.tsx +6 -2
  99. package/src/icon/icon.interface.tsx +1 -0
  100. package/src/index.css +12 -58
  101. package/src/index.ts +2 -12
  102. package/src/menus/Menus.tsx +0 -1
  103. package/src/menus/menu/Menu.tsx +1 -2
  104. package/src/overlayPanel/OverlayPanel.tsx +71 -18
  105. package/src/overlayPanel/overlay.context.tsx +6 -4
  106. package/src/overlayPanel/overlayPanel.css +10 -1
  107. package/src/overlayPanel/overlayPanelStyled/OverlayPanelStyled.tsx +7 -2
  108. package/src/select/Select.tsx +178 -41
  109. package/src/select/select.css +94 -13
  110. package/src/select/selectOption.interface.ts +1 -0
  111. package/src/sidebar/Sidebar.tsx +5 -107
  112. package/src/sidebar/sidebar.css +1 -18
  113. package/src/tabs/Tabs.tsx +20 -1
  114. package/src/tabs/tabs.css +3 -9
  115. package/src/toaster/Toaster.tsx +2 -7
  116. package/src/toaster/Toaster.view.tsx +0 -1
  117. package/src/toaster/store/useToasterStore.tsx +0 -2
  118. package/src/toaster/toaster.css +2 -7
  119. package/dist/addressSearch/AddressSearch.d.ts +0 -20
  120. package/dist/addressSearch/AddressSearch.view.d.ts +0 -1
  121. package/dist/geocoding/GeocodingService.d.ts +0 -13
  122. package/dist/geocoding/geocoding.interface.d.ts +0 -20
  123. package/src/addressSearch/AddressSearch.tsx +0 -246
  124. package/src/addressSearch/AddressSearch.view.tsx +0 -52
  125. package/src/addressSearch/addressSearch.css +0 -133
  126. package/src/geocoding/GeocodingService.ts +0 -89
  127. package/src/geocoding/geocoding.interface.ts +0 -25
package/src/index.css CHANGED
@@ -1,9 +1,9 @@
1
1
  /* variables couleur */
2
2
  :root {
3
- --primary-color: #123852;
4
- --secondary-color: #EB5E3B;
5
- --tertiary-color: #30B8C2;
6
- --quaternary-color: #7dc2ef;
3
+ --primary-color: #004aad;
4
+ --secondary-color: #ff914d;
5
+ --tertiary-color: #00ada1;
6
+ --quaternary-color: #0082ad;
7
7
  --success-color: #28a745;
8
8
  --info-color: #17a2b8;
9
9
  --warning-color: #ec942c;
@@ -17,10 +17,7 @@
17
17
  html,
18
18
  body {
19
19
  margin: 0;
20
- font-family: "Lexend", sans-serif;
21
- font-optical-sizing: auto;
22
- font-style: normal;
23
- font-size: 18px;
20
+ font-family: "Raleway", sans-serif !important;
24
21
  -webkit-font-smoothing: antialiased;
25
22
  -moz-osx-font-smoothing: grayscale;
26
23
  height: 100%;
@@ -31,48 +28,38 @@ body {
31
28
  width: 100%;
32
29
  background-color: #fff;
33
30
  }
34
-
35
31
  .app {
36
32
  container: app-container/ inline-size;
37
33
  }
38
34
 
39
35
  input[type="number"]::-webkit-outer-spin-button,
40
36
  input[type="number"]::-webkit-inner-spin-button {
41
- -webkit-appearance: none;
42
- /* Chrome, Safari, Edge */
37
+ -webkit-appearance: none; /* Chrome, Safari, Edge */
43
38
  margin: 0;
44
39
  }
45
-
46
40
  /* flex properties */
47
41
 
48
42
  .d-flex {
49
43
  display: flex;
50
44
  }
51
-
52
45
  .justify-content-start {
53
46
  justify-content: start;
54
47
  }
55
-
56
48
  .justify-content-end {
57
49
  justify-content: end;
58
50
  }
59
-
60
51
  .justify-content-center {
61
52
  justify-content: center;
62
53
  }
63
-
64
54
  .justify-content-between {
65
55
  justify-content: space-between;
66
56
  }
67
-
68
57
  .justify-content-around {
69
58
  justify-content: space-around;
70
59
  }
71
-
72
60
  .justify-content-evenly {
73
61
  justify-content: space-evenly;
74
62
  }
75
-
76
63
  .align-items-start {
77
64
  align-items: start;
78
65
  }
@@ -323,83 +310,63 @@ a {
323
310
  .mb-3 {
324
311
  margin-bottom: 1rem;
325
312
  }
326
-
327
313
  .pb-0 {
328
314
  padding-bottom: 0;
329
315
  }
330
-
331
316
  .pb-1 {
332
317
  padding-bottom: 0.25rem;
333
318
  }
334
-
335
319
  .pb-2 {
336
320
  padding-bottom: 0.5rem;
337
321
  }
338
-
339
322
  .pb-3 {
340
323
  padding-bottom: 1rem;
341
324
  }
342
-
343
325
  .pt-0 {
344
326
  padding-top: 0;
345
327
  }
346
-
347
328
  .pt-1 {
348
329
  padding-top: 0.25rem;
349
330
  }
350
-
351
331
  .pt-2 {
352
332
  padding-top: 0.5rem;
353
333
  }
354
-
355
334
  .pt-3 {
356
335
  padding-top: 1rem;
357
336
  }
358
-
359
337
  .pl-0 {
360
338
  padding-left: 0;
361
339
  }
362
-
363
340
  .pl-1 {
364
341
  padding-left: 0.25rem;
365
342
  }
366
-
367
343
  .pl-2 {
368
344
  padding-left: 0.5rem;
369
345
  }
370
-
371
346
  .pl-3 {
372
347
  padding-left: 1rem;
373
348
  }
374
-
375
349
  .pr-0 {
376
350
  padding-right: 0;
377
351
  }
378
-
379
352
  .pr-1 {
380
353
  padding-right: 0.25rem;
381
354
  }
382
-
383
355
  .pr-2 {
384
356
  padding-right: 0.5rem;
385
357
  }
386
-
387
358
  .pr-3 {
388
359
  padding-right: 1rem;
389
360
  }
390
-
391
361
  .p-0 {
392
362
  padding: 0;
393
363
  }
394
-
395
364
  .p-1 {
396
365
  padding: 0.25rem;
397
366
  }
398
-
399
367
  .p-2 {
400
368
  padding: 0.5rem;
401
369
  }
402
-
403
370
  .p-3 {
404
371
  padding: 1rem;
405
372
  }
@@ -408,32 +375,25 @@ a {
408
375
  .border-bottom {
409
376
  border-bottom: 1px solid #cfbdbd;
410
377
  }
411
-
412
378
  .border-top {
413
379
  border-top: 1px solid #cfbdbd;
414
380
  }
415
-
416
381
  .border-left {
417
382
  border-left: 1px solid #cfbdbd;
418
383
  }
419
-
420
384
  .border-right {
421
385
  border-right: 1px solid #cfbdbd;
422
386
  }
423
-
424
387
  /* fonts */
425
388
  .font-weight-bold {
426
389
  font-weight: 600;
427
390
  }
428
-
429
391
  .font-weight-light {
430
392
  font-weight: 300;
431
393
  }
432
-
433
394
  .font-weight-normal {
434
395
  font-weight: 400;
435
396
  }
436
-
437
397
  .font-weight-italic {
438
398
  font-style: italic;
439
399
  }
@@ -442,41 +402,32 @@ a {
442
402
  .visible {
443
403
  visibility: visible;
444
404
  }
445
-
446
405
  .hidden {
447
406
  visibility: hidden;
448
407
  }
449
-
450
408
  .position-relative {
451
409
  position: relative;
452
410
  }
453
-
454
411
  .position-absolute {
455
412
  position: absolute;
456
413
  }
457
-
458
414
  .cursor-pointer {
459
415
  cursor: pointer;
460
416
  }
461
-
462
417
  .w-100 {
463
418
  width: 100%;
464
419
  }
465
-
466
420
  .min-width-auto {
467
421
  min-width: auto;
468
422
  }
469
-
470
423
  .disabled {
471
424
  opacity: 0.5;
472
425
  cursor: not-allowed;
473
426
  pointer-events: none;
474
427
  }
475
-
476
428
  .overflow-auto {
477
429
  overflow: auto;
478
430
  }
479
-
480
431
  .toggle-btn {
481
432
  display: flex;
482
433
  width: 100%;
@@ -541,8 +492,11 @@ a {
541
492
  /* Couleurs : gris pour la barre, transparent pour le fond */
542
493
  }
543
494
 
544
- @media (min-width: 576px) {}
495
+ @media (min-width: 576px) {
496
+ }
545
497
 
546
- @media (min-width: 768px) {}
498
+ @media (min-width: 768px) {
499
+ }
547
500
 
548
- @media (min-width: 992px) {}
501
+ @media (min-width: 992px) {
502
+ }
package/src/index.ts CHANGED
@@ -19,13 +19,13 @@ export { useIsMobile } from "./_core/hooks/useIsMobile";
19
19
  export { useToken } from "./_core/hooks/useToken";
20
20
  export { useValidate } from "./_core/hooks/useValidate";
21
21
  export { WidgetSupport } from "./_core/hooks/widgetSupport";
22
+
22
23
  export { ButtonAction } from "./action/ButtonAction";
23
- export { AddressSearch } from "./addressSearch/AddressSearch";
24
- export type { AddressSearchProps } from "./addressSearch/AddressSearch";
25
24
  export { Badge } from "./badge/Badge";
26
25
  export { Button } from "./button/Button";
27
26
  export { ButtonActions } from "./button/buttonActions/ButtonActions";
28
27
  export { ButtonFile } from "./button/buttonFile/ButtonFile";
28
+ export { ButtonFilters } from "./button/buttonFilters/ButtonFilters";
29
29
  export { Card } from "./card/Card";
30
30
  export { Carousel } from "./carousel/Carousel";
31
31
  export { Damier } from "./damier/Damier";
@@ -35,21 +35,11 @@ export { Expands } from "./expands/Expands";
35
35
  export { FilAriane } from "./filAriane/FilAriane";
36
36
  export { DynamicForm } from "./form/Form";
37
37
  export { TypeInputEnum } from "./form/form.enum";
38
- export type { FormMode, FormSection } from "./form/form.interface";
39
38
  export { Input } from "./form/input/Input";
40
39
  export { InputNumber } from "./form/inputNumber/InputNumber";
41
40
  export { InputPrice } from "./form/inputPrice/InputPrice";
42
41
  export { TextArea } from "./form/textArea/TextArea";
43
42
  export { Grid } from "./grid/Grid";
44
- export {
45
- GeocodingService,
46
- geocodingService,
47
- } from "./geocoding/GeocodingService";
48
- export type {
49
- GeocodedAddress,
50
- GeocodingProvider,
51
- GeocodingSearchOptions,
52
- } from "./geocoding/geocoding.interface";
53
43
  export { Header } from "./header/Header";
54
44
  export { Icon } from "./icon/Icon";
55
45
  export { IconSizeEnum } from "./icon/iconSize.enum";
@@ -22,7 +22,6 @@ export const Menus = (props: ExpandProps) => {
22
22
  <Menu
23
23
  item={item}
24
24
  onChange={onChange}
25
- className={item.subMenu && item.subMenu.length > 0 ? "has-submenu" : ""}
26
25
  active={currentItem?.id === item.id}
27
26
  />
28
27
  {item.subMenu && item.subMenu.length > 0 && (
@@ -4,13 +4,12 @@ export type MenuProps = {
4
4
  active: boolean;
5
5
  item: MenuInterface;
6
6
  onChange: (item: MenuInterface) => void;
7
- className?: string;
8
7
  };
9
8
  export const Menu = (props: MenuProps): JSX.Element => {
10
9
  return (
11
10
  <div
12
11
  onClick={() => props.onChange(props.item)}
13
- className={`expand ${props.active ? "expand--active" : ""} ${props.className || ""}`}
12
+ className={props.active ? "expand expand--active" : "expand"}
14
13
  >
15
14
  {props.item.children}
16
15
  </div>
@@ -4,6 +4,7 @@ import React, {
4
4
  useEffect,
5
5
  useId,
6
6
  useImperativeHandle,
7
+ useLayoutEffect,
7
8
  useRef,
8
9
  useState,
9
10
  } from "react";
@@ -23,14 +24,16 @@ export type PositionOverlay =
23
24
  | "bottomRight";
24
25
 
25
26
  export type OverlayPanelProps = {
26
- referenceElement?: HTMLElement;
27
+ referenceElement?: HTMLElement | HTMLTableElement;
27
28
  coordonnees?: { top: number; left: number };
28
29
  position?: PositionOverlay;
29
30
  children: React.ReactNode;
30
- className?: string;
31
31
  show?: boolean;
32
32
  id?: string;
33
+ className?: string;
33
34
  closeOverlay?: (close: boolean) => void;
35
+ usePortal?: boolean;
36
+ matchReferenceWidth?: boolean;
34
37
  };
35
38
 
36
39
  export const OverlayPanel = forwardRef(
@@ -39,11 +42,13 @@ export const OverlayPanel = forwardRef(
39
42
  referenceElement,
40
43
  position,
41
44
  coordonnees,
42
- className,
43
45
  children,
44
46
  show,
47
+ className,
45
48
  id,
46
49
  closeOverlay,
50
+ usePortal = true,
51
+ matchReferenceWidth = false,
47
52
  }: OverlayPanelProps,
48
53
  ref: React.Ref<{
49
54
  setCoords?: (coords: { top: number; left: number }) => void;
@@ -54,10 +59,16 @@ export const OverlayPanel = forwardRef(
54
59
  const [coords, setCoords] = useState<{ top: number; left: number }>(
55
60
  coordonnees ?? { top: 0, left: 0 },
56
61
  );
62
+ const [referenceWidth, setReferenceWidth] = useState<number | undefined>();
63
+ // Masque l'overlay tant que sa position n'a pas été calculée (évite le flash en 0,0)
64
+ const [isPositioned, setIsPositioned] = useState(false);
57
65
  const boxRef = useRef<HTMLDivElement>(null);
58
66
  const overlayId = useId();
59
67
  useImperativeHandle(ref, () => ({
60
- setCoords,
68
+ setCoords: (newCoords: { top: number; left: number }) => {
69
+ setCoords(newCoords);
70
+ setIsPositioned(true);
71
+ },
61
72
  }));
62
73
 
63
74
  useEffect(() => {
@@ -66,10 +77,11 @@ export const OverlayPanel = forwardRef(
66
77
  }
67
78
  }, [activeOverlayId, overlayId]);
68
79
 
69
- useEffect(() => {
80
+ useLayoutEffect(() => {
70
81
  const updatePosition = () => {
71
82
  if (!position && coordonnees) {
72
83
  setCoords(coordonnees);
84
+ setIsPositioned(true);
73
85
  } else if (referenceElement) {
74
86
  const rect = referenceElement.getBoundingClientRect();
75
87
  const boxRect = boxRef.current?.getBoundingClientRect();
@@ -108,6 +120,14 @@ export const OverlayPanel = forwardRef(
108
120
  if (position && positions[position]) {
109
121
  // Si une position est définie, on tente de l'appliquer
110
122
  ({ top, left } = positions[position]());
123
+ // Manque d'espace en bas → afficher au-dessus de l'élément
124
+ if (
125
+ (position === "bottomLeft" || position === "bottomRight") &&
126
+ top + boxRect.height > innerHeight &&
127
+ rect.top - boxRect.height >= 0
128
+ ) {
129
+ top = rect.top - boxRect.height;
130
+ }
111
131
  } else {
112
132
  // Sinon, on adapte dynamiquement
113
133
  left = rect.right;
@@ -122,18 +142,35 @@ export const OverlayPanel = forwardRef(
122
142
  }
123
143
  }
124
144
 
125
- setCoords({ top, left: left < 0 ? 0 : left });
145
+ // Coordonnées viewport → coordonnées document (position absolute dans le body)
146
+ setCoords({
147
+ top: top + window.scrollY,
148
+ left: (left < 0 ? 0 : left) + window.scrollX,
149
+ });
150
+ if (matchReferenceWidth) {
151
+ setReferenceWidth(rect.width);
152
+ }
153
+ setIsPositioned(true);
126
154
  }
127
155
  }
128
156
  };
129
157
 
158
+ if (!isShow) {
159
+ setIsPositioned(false);
160
+ }
161
+
130
162
  if (isShow) {
131
163
  updatePosition();
132
164
  window.addEventListener("resize", updatePosition);
165
+ // capture : suit aussi le scroll des conteneurs (ex. contenu d'une modale)
166
+ window.addEventListener("scroll", updatePosition, true);
133
167
  }
134
168
 
135
- return () => window.removeEventListener("resize", updatePosition);
136
- }, [referenceElement, isShow, position]);
169
+ return () => {
170
+ window.removeEventListener("resize", updatePosition);
171
+ window.removeEventListener("scroll", updatePosition, true);
172
+ };
173
+ }, [referenceElement, isShow, position, matchReferenceWidth]);
137
174
 
138
175
  const openOverlay = () => {
139
176
  setIsShow(true);
@@ -154,18 +191,24 @@ export const OverlayPanel = forwardRef(
154
191
  useEffect(() => {
155
192
  const handleClickOutside = (event: MouseEvent) => {
156
193
  if (boxRef.current && !boxRef.current.contains(event.target as Node)) {
157
- closeOverlayHandler(event);
194
+ // Pas de stopPropagation ici : le clic doit continuer vers sa cible
195
+ setIsShow(false);
196
+ setActiveOverlay(null);
197
+ if (closeOverlay) {
198
+ closeOverlay(false);
199
+ }
158
200
  }
159
201
  };
160
202
 
161
203
  if (isShow) {
162
- document.addEventListener("mousedown", handleClickOutside);
204
+ // Phase de capture : fonctionne même si un parent (ex. Modal) stoppe la propagation
205
+ document.addEventListener("mousedown", handleClickOutside, true);
163
206
  }
164
207
 
165
208
  return () => {
166
- document.removeEventListener("mousedown", handleClickOutside);
209
+ document.removeEventListener("mousedown", handleClickOutside, true);
167
210
  };
168
- }, [isShow, closeOverlayHandler]);
211
+ }, [isShow, closeOverlay, setActiveOverlay]);
169
212
  useEffect(() => {
170
213
  if (show) {
171
214
  openOverlay();
@@ -174,15 +217,16 @@ export const OverlayPanel = forwardRef(
174
217
 
175
218
  if (!isShow) return null;
176
219
 
177
- return ReactDOM.createPortal(
220
+ const overlayContent = (
178
221
  <OverlayPanelStyled
179
- className={className}
180
222
  ref={boxRef}
181
223
  $top={coords.top}
182
224
  $left={coords.left}
225
+ $minWidth={referenceWidth}
226
+ $visible={isPositioned}
183
227
  >
184
228
  <div
185
- className={`overlayPanel ${
229
+ className={`overlayPanel ${className ? className : ""} ${
186
230
  coords.top > 0 || coords.left > 0 ? "visible" : "hide"
187
231
  }`}
188
232
  >
@@ -193,10 +237,19 @@ export const OverlayPanel = forwardRef(
193
237
  >
194
238
  <Icon classIcon="bi-x-lg" />
195
239
  </button>
196
- {children}
240
+ <div onClick={(e) => e.stopPropagation()}>{children}</div>
197
241
  </div>
198
- </OverlayPanelStyled>,
199
- document.body,
242
+ </OverlayPanelStyled>
200
243
  );
244
+
245
+ if (!usePortal) {
246
+ return (
247
+ <div className={`overlayPanel overlayPanel--no-portal `} ref={boxRef}>
248
+ <div onClick={(e) => e.stopPropagation()}>{children}</div>
249
+ </div>
250
+ );
251
+ }
252
+
253
+ return ReactDOM.createPortal(overlayContent, document.body);
201
254
  },
202
255
  );
@@ -7,6 +7,11 @@ interface OverlayContextType {
7
7
 
8
8
  const OverlayContext = createContext<OverlayContextType | undefined>(undefined);
9
9
 
10
+ const defaultOverlayContext: OverlayContextType = {
11
+ activeOverlayId: null,
12
+ setActiveOverlay: () => {},
13
+ };
14
+
10
15
  export const OverlayProvider: React.FC<{ children: React.ReactNode }> = ({
11
16
  children,
12
17
  }) => {
@@ -21,8 +26,5 @@ export const OverlayProvider: React.FC<{ children: React.ReactNode }> = ({
21
26
 
22
27
  export const useOverlayContext = () => {
23
28
  const context = useContext(OverlayContext);
24
- if (!context) {
25
- throw new Error("useOverlayContext must be used within an OverlayProvider");
26
- }
27
- return context;
29
+ return context ?? defaultOverlayContext;
28
30
  };
@@ -1,17 +1,26 @@
1
1
  .overlayPanel {
2
2
  position: relative;
3
3
 
4
+ &.overlayPanel--no-portal {
5
+ position: absolute;
6
+ z-index: 14 !important;
7
+ width: 100%;
8
+ }
9
+
4
10
  &.hide {
5
11
  visibility: hidden;
6
12
  }
13
+
7
14
  &.visible {
8
15
  visibility: visible !important;
9
16
  }
17
+
10
18
  button {
11
19
  span {
12
20
  text-align: left;
13
21
  }
14
22
  }
23
+
15
24
  .toggle-btn {
16
25
  display: flex;
17
26
  justify-content: flex-end;
@@ -32,4 +41,4 @@
32
41
  font-size: 1rem;
33
42
  }
34
43
  }
35
- }
44
+ }
@@ -3,16 +3,21 @@ import styled from "styled-components";
3
3
  interface OverlayPanelStyledProps {
4
4
  $top?: number;
5
5
  $left?: number;
6
+ $minWidth?: number;
7
+ $visible?: boolean;
6
8
  }
7
9
 
8
10
  export const OverlayPanelStyled = styled.div<OverlayPanelStyledProps>`
9
11
  position: absolute;
10
- z-index: 5;
12
+ z-index: 1050;
11
13
  top: ${({ $top }) => $top}px;
12
14
  left: ${({ $left }) => $left}px;
15
+ ${({ $minWidth }) => ($minWidth ? `min-width: ${$minWidth}px;` : "")}
16
+ box-sizing: border-box;
17
+ visibility: ${({ $visible }) => ($visible ? "visible" : "hidden")};
13
18
  background-color: white;
14
19
  padding: 10px;
15
20
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
16
- border-radius: 4px;
21
+ border-radius: 2px;
17
22
  border: 1px solid #ede;
18
23
  `;