kelt-ui-kit-react 1.9.4 → 1.9.5
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/dist/index.js +1045 -988
- package/package.json +1 -1
- package/src/expands/expand/expand.tsx +106 -3
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } 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
|
|
|
@@ -17,6 +17,8 @@ export const Expand = ({
|
|
|
17
17
|
onChange,
|
|
18
18
|
}: ExpandProps): JSX.Element => {
|
|
19
19
|
const [active, setActive] = useState<boolean>(false);
|
|
20
|
+
const expandRef = useRef<HTMLDivElement>(null);
|
|
21
|
+
|
|
20
22
|
useEffect(() => {
|
|
21
23
|
if (item && currentExpand) {
|
|
22
24
|
if (currentExpand.id === item.id) {
|
|
@@ -29,7 +31,106 @@ export const Expand = ({
|
|
|
29
31
|
} else {
|
|
30
32
|
setActive(false);
|
|
31
33
|
}
|
|
32
|
-
}, [currentExpand, setActive, item]);
|
|
34
|
+
}, [currentExpand, setActive, item, active]);
|
|
35
|
+
|
|
36
|
+
const scrollToHeader = useCallback(() => {
|
|
37
|
+
const expandElement = expandRef.current;
|
|
38
|
+
if (!expandElement) return;
|
|
39
|
+
|
|
40
|
+
let scrollParent: HTMLElement | null = expandElement.parentElement;
|
|
41
|
+
while (scrollParent) {
|
|
42
|
+
const style = window.getComputedStyle(scrollParent);
|
|
43
|
+
const isScrollable =
|
|
44
|
+
/(auto|scroll)/.test(style.overflow + style.overflowY) &&
|
|
45
|
+
scrollParent.scrollHeight > scrollParent.clientHeight;
|
|
46
|
+
|
|
47
|
+
if (isScrollable) {
|
|
48
|
+
const parentRect = scrollParent.getBoundingClientRect();
|
|
49
|
+
const targetRect = expandElement.getBoundingClientRect();
|
|
50
|
+
const offsetTop =
|
|
51
|
+
targetRect.top - parentRect.top + scrollParent.scrollTop;
|
|
52
|
+
|
|
53
|
+
scrollParent.scrollTo({
|
|
54
|
+
top: offsetTop,
|
|
55
|
+
behavior: "smooth",
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
scrollParent = scrollParent.parentElement;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const header =
|
|
63
|
+
expandElement.querySelector<HTMLElement>(".expand-header") ||
|
|
64
|
+
expandElement;
|
|
65
|
+
header.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (active) {
|
|
70
|
+
const timer = setTimeout(() => {
|
|
71
|
+
scrollToHeader();
|
|
72
|
+
}, 100);
|
|
73
|
+
return () => clearTimeout(timer);
|
|
74
|
+
}
|
|
75
|
+
}, [active, scrollToHeader]);
|
|
76
|
+
|
|
77
|
+
const handleFocusCapture = useCallback(
|
|
78
|
+
(e: React.FocusEvent<HTMLDivElement>) => {
|
|
79
|
+
const target = e.target as HTMLElement;
|
|
80
|
+
if (
|
|
81
|
+
active &&
|
|
82
|
+
(target.tagName === "INPUT" ||
|
|
83
|
+
target.tagName === "TEXTAREA" ||
|
|
84
|
+
target.tagName === "SELECT")
|
|
85
|
+
) {
|
|
86
|
+
const expandElement = expandRef.current;
|
|
87
|
+
if (!expandElement) return;
|
|
88
|
+
|
|
89
|
+
let scrollParent: HTMLElement | null = expandElement.parentElement;
|
|
90
|
+
while (scrollParent) {
|
|
91
|
+
const style = window.getComputedStyle(scrollParent);
|
|
92
|
+
const isScrollable =
|
|
93
|
+
/(auto|scroll)/.test(style.overflow + style.overflowY) &&
|
|
94
|
+
scrollParent.scrollHeight > scrollParent.clientHeight;
|
|
95
|
+
|
|
96
|
+
if (isScrollable) {
|
|
97
|
+
const parentRect = scrollParent.getBoundingClientRect();
|
|
98
|
+
const targetRect = target.getBoundingClientRect();
|
|
99
|
+
|
|
100
|
+
// 1. Si l'input est déjà visible dans le conteneur, on ne scrolle pas
|
|
101
|
+
const isVisible =
|
|
102
|
+
targetRect.top >= parentRect.top &&
|
|
103
|
+
targetRect.bottom <= parentRect.bottom;
|
|
104
|
+
|
|
105
|
+
if (isVisible) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const headerRect = expandElement.getBoundingClientRect();
|
|
110
|
+
const headerOffsetTop =
|
|
111
|
+
headerRect.top - parentRect.top + scrollParent.scrollTop;
|
|
112
|
+
|
|
113
|
+
// 2. Si on a déjà scrollé vers ou au-delà du header, on ne remonte JAMAIS
|
|
114
|
+
if (scrollParent.scrollTop >= headerOffsetTop - 5) {
|
|
115
|
+
if (targetRect.bottom > parentRect.bottom) {
|
|
116
|
+
target.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 3. Sinon, on scrolle vers le header
|
|
122
|
+
scrollParent.scrollTo({
|
|
123
|
+
top: headerOffsetTop,
|
|
124
|
+
behavior: "smooth",
|
|
125
|
+
});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
scrollParent = scrollParent.parentElement;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
[active],
|
|
133
|
+
);
|
|
33
134
|
|
|
34
135
|
const handleChange = useCallback(
|
|
35
136
|
(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
@@ -38,11 +139,13 @@ export const Expand = ({
|
|
|
38
139
|
onChange(item);
|
|
39
140
|
}
|
|
40
141
|
},
|
|
41
|
-
[onChange, item]
|
|
142
|
+
[onChange, item],
|
|
42
143
|
);
|
|
43
144
|
return (
|
|
44
145
|
<div
|
|
146
|
+
ref={expandRef}
|
|
45
147
|
onClick={handleChange}
|
|
148
|
+
onFocusCapture={handleFocusCapture}
|
|
46
149
|
className={`expand ${active ? "expand--active" : ""} ${className ?? ""}`}
|
|
47
150
|
>
|
|
48
151
|
<div className={`expand-header`}>
|