kelt-ui-kit-react 2.0.3 → 2.0.4

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 +26 -0
  2. package/dist/addressSearch/AddressSearch.d.ts +20 -0
  3. package/dist/addressSearch/AddressSearch.view.d.ts +1 -0
  4. package/dist/badge/Badge.d.ts +1 -3
  5. package/dist/button/Button.d.ts +1 -1
  6. package/dist/button/button.interface.d.ts +2 -1
  7. package/dist/card/Card.d.ts +4 -1
  8. package/dist/dataTable/DataTable.d.ts +14 -17
  9. package/dist/dataTable/dataTable.interface.d.ts +19 -24
  10. package/dist/dataTable/dataTableActions/DataTableAction.d.ts +5 -3
  11. package/dist/dataTable/dataTableColumn/DataTableColumn.d.ts +7 -13
  12. package/dist/dataTable/dataTableLoading/DataTableLoading.d.ts +3 -1
  13. package/dist/dataTable/dataTableRow/DataTableRow.d.ts +6 -5
  14. package/dist/expands/Expands.d.ts +1 -0
  15. package/dist/expands/expand/expand.d.ts +3 -2
  16. package/dist/form/Form.d.ts +10 -2
  17. package/dist/form/form.enum.d.ts +3 -2
  18. package/dist/form/form.interface.d.ts +22 -3
  19. package/dist/form/input/Input.d.ts +0 -3
  20. package/dist/form/inputNumber/InputNumber.d.ts +2 -0
  21. package/dist/geocoding/GeocodingService.d.ts +13 -0
  22. package/dist/geocoding/geocoding.interface.d.ts +20 -0
  23. package/dist/grid/Grid.d.ts +5 -2
  24. package/dist/grid/col/Col.d.ts +3 -6
  25. package/dist/grid/col/colStyled/ColStyled.d.ts +8 -5
  26. package/dist/grid/grid.interface.d.ts +20 -5
  27. package/dist/grid/row/Row.d.ts +7 -0
  28. package/dist/header/Header.d.ts +1 -1
  29. package/dist/header/header.interface.d.ts +2 -1
  30. package/dist/icon/Icon.d.ts +1 -1
  31. package/dist/icon/icon.interface.d.ts +0 -1
  32. package/dist/index.d.ts +5 -1
  33. package/dist/index.js +3724 -3628
  34. package/dist/menus/menu/Menu.d.ts +1 -0
  35. package/dist/select/Select.d.ts +2 -1
  36. package/dist/style.css +1 -1
  37. package/dist/tabs/Tabs.d.ts +1 -2
  38. package/dist/toaster/store/useToasterStore.d.ts +1 -0
  39. package/index.html +1 -2
  40. package/package.json +1 -1
  41. package/src/App.menu.tsx +8 -0
  42. package/src/addressSearch/AddressSearch.tsx +246 -0
  43. package/src/addressSearch/AddressSearch.view.tsx +52 -0
  44. package/src/addressSearch/addressSearch.css +133 -0
  45. package/src/badge/Badge.tsx +1 -9
  46. package/src/badge/badge.css +0 -4
  47. package/src/button/Button.tsx +3 -1
  48. package/src/button/button.css +2 -2
  49. package/src/button/button.interface.tsx +2 -1
  50. package/src/card/Card.tsx +37 -11
  51. package/src/card/card.css +7 -28
  52. package/src/card/cardAction/CardAction.tsx +4 -4
  53. package/src/damier/Damier.tsx +16 -7
  54. package/src/damier/damier.css +11 -4
  55. package/src/dataTable/DataTable.tsx +542 -685
  56. package/src/dataTable/DataTable.view.tsx +24 -48
  57. package/src/dataTable/dataTable.css +159 -134
  58. package/src/dataTable/dataTable.interface.ts +19 -25
  59. package/src/dataTable/dataTableActions/DataTableAction.tsx +25 -14
  60. package/src/dataTable/dataTableColumn/DataTableColumn.tsx +14 -64
  61. package/src/dataTable/dataTableLoading/DataTableLoading.tsx +15 -4
  62. package/src/dataTable/dataTableRow/DataTableRow.tsx +180 -64
  63. package/src/expands/Expands.tsx +18 -2
  64. package/src/expands/expand/expand.tsx +128 -5
  65. package/src/expands/expands.css +8 -3
  66. package/src/form/Form.tsx +294 -99
  67. package/src/form/Form.view.tsx +9 -1
  68. package/src/form/form.css +64 -1
  69. package/src/form/form.enum.ts +2 -1
  70. package/src/form/form.interface.tsx +31 -3
  71. package/src/form/input/Input.tsx +7 -61
  72. package/src/form/input/input.css +1 -19
  73. package/src/form/inputNumber/InputNumber.tsx +11 -6
  74. package/src/form/inputPrice/InputPrice.tsx +4 -2
  75. package/src/geocoding/GeocodingService.ts +89 -0
  76. package/src/geocoding/geocoding.interface.ts +25 -0
  77. package/src/grid/Grid.tsx +34 -21
  78. package/src/grid/col/Col.tsx +24 -15
  79. package/src/grid/col/col.css +3 -0
  80. package/src/grid/col/colStyled/ColStyled.tsx +59 -41
  81. package/src/grid/container/container.css +2 -2
  82. package/src/grid/grid.interface.tsx +25 -5
  83. package/src/grid/row/Row.tsx +49 -12
  84. package/src/grid/row/row.css +11 -3
  85. package/src/header/Header.tsx +4 -2
  86. package/src/header/header.css +17 -0
  87. package/src/header/header.interface.tsx +2 -1
  88. package/src/icon/Icon.tsx +2 -6
  89. package/src/icon/icon.interface.tsx +0 -1
  90. package/src/index.css +58 -12
  91. package/src/index.ts +12 -2
  92. package/src/menus/Menus.tsx +1 -0
  93. package/src/menus/menu/Menu.tsx +2 -1
  94. package/src/select/Select.tsx +5 -3
  95. package/src/sidebar/Sidebar.tsx +107 -5
  96. package/src/sidebar/sidebar.css +18 -1
  97. package/src/tabs/Tabs.tsx +1 -20
  98. package/src/tabs/tabs.css +9 -3
  99. package/src/toaster/Toaster.tsx +7 -2
  100. package/src/toaster/Toaster.view.tsx +1 -0
  101. package/src/toaster/store/useToasterStore.tsx +2 -0
  102. package/src/toaster/toaster.css +7 -2
  103. package/dist/_core/type/generiqueType.d.ts +0 -4
  104. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.d.ts +0 -10
  105. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.d.ts +0 -9
  106. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.d.ts +0 -9
  107. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.d.ts +0 -13
  108. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.d.ts +0 -9
  109. package/dist/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.d.ts +0 -11
  110. package/dist/dataTable/dataTableFilters/DataTableFilters.d.ts +0 -7
  111. package/dist/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.d.ts +0 -12
  112. package/dist/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.d.ts +0 -11
  113. package/package/package.json +0 -56
  114. package/package/src/sidebar/Sidebar.tsx +0 -208
  115. package/package/src/sidebar/sidebar.css +0 -104
  116. package/src/_core/type/generiqueType.tsx +0 -4
  117. package/src/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.tsx +0 -36
  118. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilter.css +0 -0
  119. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.tsx +0 -39
  120. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.tsx +0 -80
  121. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.tsx +0 -89
  122. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.tsx +0 -37
  123. package/src/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.tsx +0 -42
  124. package/src/dataTable/dataTableFilters/DataTableFilters.tsx +0 -91
  125. package/src/dataTable/dataTableFilters/dataTableFilters.css +0 -16
  126. package/src/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.tsx +0 -80
  127. package/src/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.tsx +0 -123
@@ -1,92 +1,208 @@
1
- import { useRef, useState } from "react";
2
- import { DataTableColumnsInterface } from "../dataTable.interface";
3
- import { DataTableRowOverlay } from "./dataTableRowOverlay/DataTableRowOverlay";
4
- import { DataTableRowValue } from "./dataTableRowValue/DataTableRowValue";
1
+ import { Icon } from "../..";
2
+ import { Select } from "../../select/Select";
3
+ import { dataTableColumnsInterface } from "../dataTable.interface";
5
4
 
6
5
  type DataTableRowProps = {
7
- column: DataTableColumnsInterface<any>;
6
+ column: dataTableColumnsInterface<any>;
8
7
  idx: number;
8
+ rowIndex: number;
9
9
  row: any;
10
- onEditColumnByOverlay?: (row: any) => void;
11
- stickyLeft?: number;
10
+ container?: "cell" | "card";
11
+ onEnterNextColumn?: (columnIndex: number, rowIndex: number) => void;
12
12
  };
13
13
  export const DataTableRow = ({
14
14
  column,
15
15
  idx,
16
+ rowIndex,
16
17
  row,
17
- onEditColumnByOverlay,
18
- stickyLeft,
18
+ container = "cell",
19
+ onEnterNextColumn,
19
20
  }: DataTableRowProps) => {
20
21
  const value = (row as any)[column.id]; // On utilise [column.id] pour accéder aux bonnes propriétés
21
22
  const style = column.onRowStyle ? column.onRowStyle(row) : {};
22
23
  const isDisabled = column.onDisable?.(row) ?? false;
23
- const isSticky = stickyLeft !== undefined;
24
- const [openClickCell, setOpenClickCell] = useState(false);
25
- const refRow = useRef<HTMLTableCellElement>(null);
26
- const onClickRenderCell = (e: React.MouseEvent<HTMLTableCellElement>) => {
27
- if (isDisabled) {
28
- return;
24
+
25
+ const hasStepButtons = Boolean(
26
+ typeof column.showStepButtons === "function"
27
+ ? column.showStepButtons(row)
28
+ : (column.showStepButtons ??
29
+ (typeof column.stepControls === "function"
30
+ ? column.stepControls(row)
31
+ : (column.stepControls ??
32
+ (typeof column.withStepControls === "function"
33
+ ? column.withStepControls(row)
34
+ : column.withStepControls)))),
35
+ );
36
+
37
+ const handleStep = (direction: "plus" | "minus", e: React.MouseEvent) => {
38
+ e.stopPropagation();
39
+ if (isDisabled) return;
40
+ const currentNum = Number(value) || 0;
41
+ const step = column.step ?? 1;
42
+ let newNum = direction === "plus" ? currentNum + step : currentNum - step;
43
+ if (column.min !== undefined && newNum < column.min) {
44
+ newNum = column.min;
45
+ }
46
+ if (column.max !== undefined && newNum > column.max) {
47
+ newNum = column.max;
29
48
  }
30
- console.log("Cell clicked with value:", value, "in row:", row);
31
- if (column.openClickCell) {
32
- if (column.handleClickCell) {
33
- column.handleClickCell(e, row);
34
- }
35
- e.stopPropagation();
36
- setOpenClickCell((prev) => !prev);
49
+ newNum = Math.round(newNum * 1000) / 1000;
50
+ if (column.onEdit) {
51
+ column.onEdit(newNum, row);
37
52
  }
38
53
  };
54
+
55
+ const Container = container === "card" ? "div" : "td";
56
+
39
57
  return (
40
- <td
41
- ref={refRow}
58
+ <Container
59
+ className={`${isDisabled ? "disabled" : ""}`}
60
+ data-column-index={idx}
61
+ data-row-index={rowIndex}
42
62
  style={{
43
63
  minWidth: column.minWidth,
44
- textAlign: column.alignText ? column.alignText : column.align || "left",
64
+ textAlign: column.align || "left",
45
65
  maxWidth: column.maxWidth,
46
66
  width: column.width,
47
- ...(!isDisabled &&
48
- (column.openClickCell || column.renderClickCellComponent)
49
- ? { cursor: "pointer" }
50
- : {}),
51
- ...(isSticky
52
- ? {
53
- position: "sticky",
54
- left: stickyLeft,
55
- zIndex: 2,
56
- backgroundColor: "#fff",
57
- }
58
- : {}),
59
67
  ...style,
60
68
  }}
61
- onClick={onClickRenderCell}
62
69
  key={`row-${column.id}-${idx}`}
63
- className={isSticky ? "data-table-sticky-cell" : ""}
64
70
  >
65
- {column.renderComponent ? column.renderComponent(value, row) : null}
66
- {!column.renderComponent && (
67
- <DataTableRowValue
68
- editable={
69
- !isDisabled &&
70
- (column.onEditable?.(value, row) ?? column.editable ?? false)
71
- }
72
- column={column}
73
- value={value}
74
- row={row}
75
- />
76
- )}
77
- {openClickCell &&
78
- !isDisabled &&
79
- column.displayOverlay &&
80
- refRow.current && (
81
- <DataTableRowOverlay
82
- refRow={refRow}
83
- column={column}
84
- row={row}
85
- value={value}
86
- onEditColumnByOverlay={onEditColumnByOverlay}
87
- onClose={() => setOpenClickCell(false)}
71
+ {column.type === "image" ? (
72
+ value ? (
73
+ <img
74
+ src={column.imageSrc ? column.imageSrc(row) : ""}
75
+ alt={column.imageAlt ? column.imageAlt(row) : ""}
76
+ style={column.imageStyle}
88
77
  />
89
- )}
90
- </td>
78
+ ) : (
79
+ <Icon classIcon="bi-image" />
80
+ )
81
+ ) : column.editable ? (
82
+ column.type === "select" ? (
83
+ <div onClick={(e) => e.stopPropagation()}>
84
+ <Select
85
+ style={{
86
+ minWidth: column.minWidth,
87
+ maxWidth: column.maxWidth,
88
+ width: column.width,
89
+ }}
90
+ options={column.options ?? []}
91
+ value={value}
92
+ onChange={(e) => {
93
+ if (column.onEdit) {
94
+ column.onEdit(e, row);
95
+ }
96
+ }}
97
+ />
98
+ </div>
99
+ ) : (
100
+ hasStepButtons ? (
101
+ <div
102
+ className="data-table-input-number-wrapper"
103
+ style={{
104
+ display: "inline-flex",
105
+ alignItems: "center",
106
+ gap: "4px",
107
+ justifyContent:
108
+ column.align === "right"
109
+ ? "flex-end"
110
+ : column.align === "center"
111
+ ? "center"
112
+ : "flex-start",
113
+ }}
114
+ onClick={(e) => e.stopPropagation()}
115
+ >
116
+ <button
117
+ type="button"
118
+ className="data-table-step-btn data-table-step-btn--minus"
119
+ disabled={
120
+ isDisabled ||
121
+ (column.min !== undefined && Number(value) <= column.min)
122
+ }
123
+ onClick={(e) => handleStep("minus", e)}
124
+ >
125
+ <Icon classIcon="bi-dash-lg" />
126
+ </button>
127
+ <input
128
+ type={column.type}
129
+ value={value}
130
+ step={column.step ?? "0.01"}
131
+ min={column.min}
132
+ max={column.max}
133
+ disabled={isDisabled}
134
+ style={{
135
+ textAlign: column.align || "center",
136
+ minWidth: column.minWidth,
137
+ maxWidth: column.maxWidth,
138
+ width: column.width,
139
+ }}
140
+ onClick={(e) => e.stopPropagation()}
141
+ onKeyDown={(e) => {
142
+ if (e.key === "Enter") {
143
+ if (column.onEnter) {
144
+ column.onEnter(e.currentTarget.value, row);
145
+ }
146
+ if (column.enterToNextColumn) {
147
+ e.preventDefault();
148
+ onEnterNextColumn?.(idx, rowIndex);
149
+ }
150
+ }
151
+ }}
152
+ onChange={(e) => {
153
+ if (column.onEdit) {
154
+ column.onEdit(e.target.value, row);
155
+ }
156
+ }}
157
+ />
158
+ <button
159
+ type="button"
160
+ className="data-table-step-btn data-table-step-btn--plus"
161
+ disabled={
162
+ isDisabled ||
163
+ (column.max !== undefined && Number(value) >= column.max)
164
+ }
165
+ onClick={(e) => handleStep("plus", e)}
166
+ >
167
+ <Icon classIcon="bi-plus-lg" />
168
+ </button>
169
+ </div>
170
+ ) : (
171
+ <input
172
+ type={column.type}
173
+ value={value}
174
+ step="0.01"
175
+ style={{
176
+ textAlign: column.align || "left",
177
+ minWidth: column.minWidth,
178
+ maxWidth: column.maxWidth,
179
+ width: column.width,
180
+ }}
181
+ onClick={(e) => e.stopPropagation()}
182
+ onKeyDown={(e) => {
183
+ if (e.key === "Enter") {
184
+ if (column.onEnter) {
185
+ column.onEnter(e.currentTarget.value, row);
186
+ }
187
+ if (column.enterToNextColumn) {
188
+ e.preventDefault();
189
+ onEnterNextColumn?.(idx, rowIndex);
190
+ }
191
+ }
192
+ }}
193
+ onChange={(e) => {
194
+ if (column.onEdit) {
195
+ column.onEdit(e.target.value, row);
196
+ }
197
+ }}
198
+ />
199
+ )
200
+ )
201
+ ) : column.format ? (
202
+ column.format(value)
203
+ ) : (
204
+ value
205
+ )}
206
+ </Container>
91
207
  );
92
208
  };
@@ -1,3 +1,4 @@
1
+ import { useCallback, useEffect, useState } from "react";
1
2
  import { Expand } from "./expand/expand";
2
3
  import { ExpandInterface } from "./expand/expand.interface";
3
4
  import "./expands.css";
@@ -8,9 +9,23 @@ type ExpandProps = {
8
9
  onChange?: (item: ExpandInterface) => void;
9
10
  currentItem?: ExpandInterface;
10
11
  showArrow?: boolean;
12
+ catchfocusCapture?: boolean;
11
13
  };
12
14
 
13
15
  export const Expands = (props: ExpandProps) => {
16
+ const [currentExpand, setCurrentExpand] = useState<ExpandInterface>();
17
+ const onChangeExpand = useCallback(
18
+ (item: ExpandInterface) => {
19
+ if (props.onChange) {
20
+ props.onChange(item);
21
+ }
22
+ setCurrentExpand(item);
23
+ },
24
+ [setCurrentExpand, props.onChange]
25
+ );
26
+ useEffect(() => {
27
+ setCurrentExpand(props.currentItem);
28
+ }, [props.currentItem, setCurrentExpand, document.activeElement]);
14
29
  return (
15
30
  <div className={`expands ${props.className || ""}`}>
16
31
  {props.items.map((item: ExpandInterface) => (
@@ -18,8 +33,9 @@ export const Expands = (props: ExpandProps) => {
18
33
  key={item.id}
19
34
  item={item}
20
35
  showArrow={props.showArrow}
21
- onChange={props.onChange}
22
- currentExpand={props.currentItem}
36
+ onChange={onChangeExpand}
37
+ currentExpand={currentExpand}
38
+ catchfocusCapture={props.catchfocusCapture}
23
39
  />
24
40
  ))}
25
41
  </div>
@@ -1,4 +1,4 @@
1
- import { useCallback } from "react";
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { Icon } from "../../icon/Icon";
3
3
  import { ExpandInterface } from "./expand.interface";
4
4
 
@@ -7,22 +7,143 @@ export type ExpandProps = {
7
7
  item: ExpandInterface;
8
8
  className?: string;
9
9
  showArrow?: boolean;
10
- onChange?: (item: ExpandInterface) => void;
10
+ catchfocusCapture?: boolean
11
+
12
+ onChange: (item: ExpandInterface) => void;
11
13
  };
12
14
  export const Expand = ({
13
15
  currentExpand,
14
16
  item,
15
17
  className,
16
18
  showArrow = true,
19
+ catchfocusCapture = false,
17
20
  onChange,
18
21
  }: ExpandProps): JSX.Element => {
19
- const active = currentExpand?.id === item.id;
20
- console.log("render expand", item.title, "active", active);
22
+ const [active, setActive] = useState<boolean>(false);
23
+ const expandRef = useRef<HTMLDivElement>(null);
24
+
25
+ useEffect(() => {
26
+
27
+ if (item && currentExpand) {
28
+ if (currentExpand.id === item.id) {
29
+ if (!active) {
30
+ setActive(true);
31
+ }
32
+ } else {
33
+ setActive(false);
34
+ }
35
+ } else {
36
+ setActive(false);
37
+ }
38
+ }, [currentExpand, setActive, item, active]);
39
+
40
+ const scrollToHeader = useCallback(() => {
41
+ const expandElement = expandRef.current;
42
+ if (!expandElement) return;
43
+
44
+ let scrollParent: HTMLElement | null = expandElement.parentElement;
45
+ while (scrollParent) {
46
+ const style = window.getComputedStyle(scrollParent);
47
+ const isScrollable =
48
+ /(auto|scroll)/.test(style.overflow + style.overflowY) &&
49
+ scrollParent.scrollHeight > scrollParent.clientHeight;
50
+
51
+ if (isScrollable) {
52
+ const parentRect = scrollParent.getBoundingClientRect();
53
+ const targetRect = expandElement.getBoundingClientRect();
54
+ const offsetTop =
55
+ targetRect.top - parentRect.top + scrollParent.scrollTop;
56
+
57
+ scrollParent.scrollTo({
58
+ top: offsetTop,
59
+ behavior: "smooth",
60
+ });
61
+ return;
62
+ }
63
+ scrollParent = scrollParent.parentElement;
64
+ }
65
+
66
+ const header =
67
+ expandElement.querySelector<HTMLElement>(".expand-header") ||
68
+ expandElement;
69
+ header.scrollIntoView({ behavior: "smooth", block: "start" });
70
+ }, []);
71
+
72
+ useEffect(() => {
73
+ if (!catchfocusCapture) return;
74
+ if (active) {
75
+ const timer1 = setTimeout(() => {
76
+ scrollToHeader();
77
+ }, 100);
78
+ const timer2 = setTimeout(() => {
79
+ scrollToHeader();
80
+ }, 350);
81
+ return () => {
82
+ clearTimeout(timer1);
83
+ clearTimeout(timer2);
84
+ };
85
+ }
86
+ }, [active, scrollToHeader, catchfocusCapture]);
87
+
88
+ const handleFocusCapture = useCallback(
89
+ (e: React.FocusEvent<HTMLDivElement>) => {
90
+ if (!catchfocusCapture) return;
91
+ const target = e.target as HTMLElement;
92
+ if (
93
+ active &&
94
+ (target.tagName === "INPUT" ||
95
+ target.tagName === "TEXTAREA" ||
96
+ target.tagName === "SELECT")
97
+ ) {
98
+ const expandElement = expandRef.current;
99
+ if (!expandElement) return;
100
+
101
+ const performScroll = () => {
102
+ let scrollParent: HTMLElement | null = expandElement.parentElement;
103
+ while (scrollParent) {
104
+ const style = window.getComputedStyle(scrollParent);
105
+ const isScrollable =
106
+ /(auto|scroll)/.test(style.overflow + style.overflowY) &&
107
+ scrollParent.scrollHeight > scrollParent.clientHeight;
108
+
109
+ if (isScrollable) {
110
+ const parentRect = scrollParent.getBoundingClientRect();
111
+ const headerRect = expandElement.getBoundingClientRect();
112
+ const headerOffsetTop =
113
+ headerRect.top - parentRect.top + scrollParent.scrollTop;
114
+
115
+ // Si on a déjà scrollé vers ou au-delà du header, on ne remonte JAMAIS au header
116
+ if (scrollParent.scrollTop >= headerOffsetTop - 10) {
117
+ const targetRect = target.getBoundingClientRect();
118
+ if (targetRect.bottom > parentRect.bottom) {
119
+ target.scrollIntoView({ behavior: "smooth", block: "nearest" });
120
+ }
121
+ return;
122
+ }
123
+
124
+ // Si on n'a pas encore scrollé jusqu'au header, on y va
125
+ scrollParent.scrollTo({
126
+ top: headerOffsetTop,
127
+ behavior: "smooth",
128
+ });
129
+ return;
130
+ }
131
+ scrollParent = scrollParent.parentElement;
132
+ }
133
+ };
134
+
135
+ performScroll();
136
+ // Répéter après l'ouverture du clavier virtuel (spécifique tablettes / mobiles Android)
137
+ setTimeout(performScroll, 300);
138
+ }
139
+ },
140
+ [active],
141
+ );
142
+
21
143
  const handleChange = useCallback(
22
144
  (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
23
145
  e.stopPropagation();
24
146
  if (onChange) {
25
- console.log("expand", item);
26
147
  onChange(item);
27
148
  }
28
149
  },
@@ -30,7 +151,9 @@ export const Expand = ({
30
151
  );
31
152
  return (
32
153
  <div
154
+ ref={expandRef}
33
155
  onClick={handleChange}
156
+ onFocusCapture={handleFocusCapture}
34
157
  className={`expand ${active ? "expand--active" : ""} ${className ?? ""}`}
35
158
  >
36
159
  <div className={`expand-header`}>
@@ -39,10 +39,12 @@
39
39
  height: 300px;
40
40
  flex: 1;
41
41
  min-height: 200px;
42
+
42
43
  .expand-header {
43
- background-color: #1d3758;
44
+ background-color: color-mix(in srgb, var(--primary-color), white 5%);
44
45
  color: #fff;
45
46
  }
47
+
46
48
  .expand-header-custom {
47
49
  .expand-header--children {
48
50
  display: flex;
@@ -65,6 +67,7 @@
65
67
  padding: 15px;
66
68
  color: #333;
67
69
  background-color: #fff;
70
+
68
71
  &.expand-header-custom {
69
72
  margin-bottom: 1rem;
70
73
  }
@@ -77,13 +80,15 @@
77
80
  .expand-header-title-left {
78
81
  margin-right: 0.5rem;
79
82
  text-transform: uppercase;
80
- font-size: 14px;
83
+ font-size: 18px;
81
84
  font-weight: 500;
82
85
  }
83
86
  }
87
+
84
88
  & .expand-footer {
85
89
  padding: 15px;
86
90
  }
91
+
87
92
  & .expand-body {
88
93
  display: none;
89
94
  flex: 1;
@@ -94,4 +99,4 @@
94
99
  flex-direction: column;
95
100
  }
96
101
  }
97
- }
102
+ }