forstok-ui-lib 8.9.4 → 8.9.6
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.d.ts +1 -1
- package/dist/index.js +19 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +19 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/assets/images/icons/export-download.svg +11 -6
- package/src/components/dropdown/index.tsx +374 -185
- package/src/components/dropdown/styles.ts +101 -60
|
@@ -1,33 +1,73 @@
|
|
|
1
|
-
import { useEffect, useRef, isValidElement } from
|
|
2
|
-
import ReactPortalComponent from
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { useEffect, useRef, isValidElement } from "react";
|
|
2
|
+
import ReactPortalComponent from "../portal";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
DropDownContainer,
|
|
6
|
+
DropDownTitle,
|
|
7
|
+
DropDownSubTitle,
|
|
8
|
+
DropDownWrapper,
|
|
9
|
+
DropDownOverlayWrapper,
|
|
10
|
+
DropDownControl,
|
|
11
|
+
DropDownBody,
|
|
12
|
+
DropDownAction,
|
|
13
|
+
DropdownControlWrapper,
|
|
14
|
+
DropdownPortalContainer,
|
|
15
|
+
} from "./styles";
|
|
16
|
+
|
|
17
|
+
import type { TMouseEvent } from "../../typeds/base.typed";
|
|
18
|
+
import type { TDropdown } from "./typed";
|
|
8
19
|
|
|
9
20
|
const DEFAULT_TOP_OFFSET = 40;
|
|
10
21
|
const DEFAULT_BOTTOM_OFFSET = 35;
|
|
11
22
|
const MOBILE_BREAKPOINT = 768;
|
|
12
23
|
|
|
13
|
-
const DropDownComponent = ({
|
|
24
|
+
const DropDownComponent = ({
|
|
25
|
+
children,
|
|
26
|
+
title,
|
|
27
|
+
subTitle,
|
|
28
|
+
$externalWidth,
|
|
29
|
+
$externalMinWidth,
|
|
30
|
+
$internalWidth,
|
|
31
|
+
$area,
|
|
32
|
+
$openPosition,
|
|
33
|
+
$placement,
|
|
34
|
+
$top,
|
|
35
|
+
onClick,
|
|
36
|
+
$alias,
|
|
37
|
+
type,
|
|
38
|
+
portalId,
|
|
39
|
+
$bottom,
|
|
40
|
+
$isPopup,
|
|
41
|
+
...props
|
|
42
|
+
}: TDropdown) => {
|
|
14
43
|
const buttonRef = useRef<HTMLElement>(null);
|
|
15
44
|
|
|
16
45
|
const getOffsetValue = (value: string | undefined, fallbackValue: number) => {
|
|
17
|
-
const parsedValue = Number.parseInt(value ||
|
|
46
|
+
const parsedValue = Number.parseInt(value || "", 10);
|
|
18
47
|
return Number.isNaN(parsedValue) ? fallbackValue : parsedValue;
|
|
19
48
|
};
|
|
20
49
|
|
|
21
|
-
const getViewportHeight = () =>
|
|
22
|
-
|
|
50
|
+
const getViewportHeight = () =>
|
|
51
|
+
window.innerHeight ||
|
|
52
|
+
document.documentElement.clientHeight ||
|
|
53
|
+
document.body.clientHeight;
|
|
54
|
+
const getViewportWidth = () =>
|
|
55
|
+
window.innerWidth ||
|
|
56
|
+
document.documentElement.clientWidth ||
|
|
57
|
+
document.body.clientWidth;
|
|
23
58
|
const isMobileViewport = () => getViewportWidth() < MOBILE_BREAKPOINT;
|
|
24
59
|
|
|
25
|
-
const getDropdownWrapperElement = (parentEl: ParentNode | null) =>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
60
|
+
const getDropdownWrapperElement = (parentEl: ParentNode | null) =>
|
|
61
|
+
parentEl?.querySelector("._refDropdownWrapper") as HTMLElement | null;
|
|
62
|
+
const withNextFrame = (callback: () => void) =>
|
|
63
|
+
window.requestAnimationFrame(() => callback());
|
|
64
|
+
|
|
65
|
+
const getDropdownPlacement = (
|
|
66
|
+
containerEl: HTMLElement,
|
|
67
|
+
wrapperEl: HTMLElement,
|
|
68
|
+
) => {
|
|
69
|
+
if ($placement === "top") {
|
|
70
|
+
return "top";
|
|
31
71
|
}
|
|
32
72
|
|
|
33
73
|
const containerRect = containerEl.getBoundingClientRect();
|
|
@@ -37,54 +77,62 @@ const DropDownComponent = ({ children, title, subTitle, $externalWidth, $externa
|
|
|
37
77
|
const bottomOffset = getOffsetValue($bottom, DEFAULT_BOTTOM_OFFSET);
|
|
38
78
|
const spaceBelow = getViewportHeight() - containerRect.bottom;
|
|
39
79
|
const spaceAbove = containerRect.top;
|
|
40
|
-
const requiredSpaceBelow =
|
|
41
|
-
|
|
80
|
+
const requiredSpaceBelow =
|
|
81
|
+
wrapperHeight + Math.max(topOffset - containerRect.height, 0);
|
|
82
|
+
const requiredSpaceAbove =
|
|
83
|
+
wrapperHeight + Math.max(bottomOffset - containerRect.height, 0);
|
|
42
84
|
|
|
43
85
|
if (spaceBelow >= requiredSpaceBelow) {
|
|
44
|
-
return
|
|
86
|
+
return "bottom";
|
|
45
87
|
}
|
|
46
88
|
|
|
47
89
|
if (spaceAbove >= requiredSpaceAbove) {
|
|
48
|
-
return
|
|
90
|
+
return "top";
|
|
49
91
|
}
|
|
50
92
|
|
|
51
|
-
return spaceAbove > spaceBelow ?
|
|
93
|
+
return spaceAbove > spaceBelow ? "top" : "bottom";
|
|
52
94
|
};
|
|
53
95
|
|
|
54
|
-
const applyDropdownPlacement = (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
96
|
+
const applyDropdownPlacement = (
|
|
97
|
+
wrapperEl: HTMLElement,
|
|
98
|
+
placement: "top" | "bottom",
|
|
99
|
+
) => {
|
|
100
|
+
if (placement === "top") {
|
|
101
|
+
wrapperEl.style.animation = "none"; // stop CSS animation from overriding top:auto
|
|
102
|
+
wrapperEl.style.top = "auto";
|
|
58
103
|
wrapperEl.style.bottom = `${getOffsetValue($bottom, DEFAULT_BOTTOM_OFFSET)}px`;
|
|
59
104
|
return;
|
|
60
105
|
}
|
|
61
106
|
|
|
62
107
|
wrapperEl.style.top = `${getOffsetValue($top, DEFAULT_TOP_OFFSET)}px`;
|
|
63
|
-
wrapperEl.style.bottom =
|
|
108
|
+
wrapperEl.style.bottom = "auto";
|
|
64
109
|
};
|
|
65
110
|
|
|
66
111
|
const applyMobileDropdownPlacement = (wrapperEl: HTMLElement) => {
|
|
67
|
-
wrapperEl.style.top =
|
|
68
|
-
wrapperEl.style.bottom =
|
|
69
|
-
wrapperEl.style.left =
|
|
70
|
-
wrapperEl.style.right =
|
|
71
|
-
wrapperEl.style.transform =
|
|
112
|
+
wrapperEl.style.top = "auto";
|
|
113
|
+
wrapperEl.style.bottom = "0";
|
|
114
|
+
wrapperEl.style.left = "0";
|
|
115
|
+
wrapperEl.style.right = "auto";
|
|
116
|
+
wrapperEl.style.transform = "none";
|
|
72
117
|
};
|
|
73
118
|
|
|
74
119
|
const resetDropdownInlineStyle = (parentEl: ParentNode | null) => {
|
|
75
120
|
const wrapperEl = getDropdownWrapperElement(parentEl);
|
|
76
121
|
if (wrapperEl) {
|
|
77
|
-
wrapperEl.style.top =
|
|
78
|
-
wrapperEl.style.bottom =
|
|
79
|
-
wrapperEl.style.left =
|
|
80
|
-
wrapperEl.style.right =
|
|
81
|
-
wrapperEl.style.transform =
|
|
82
|
-
wrapperEl.style.visibility =
|
|
83
|
-
wrapperEl.style.animation =
|
|
122
|
+
wrapperEl.style.top = "";
|
|
123
|
+
wrapperEl.style.bottom = "";
|
|
124
|
+
wrapperEl.style.left = "";
|
|
125
|
+
wrapperEl.style.right = "";
|
|
126
|
+
wrapperEl.style.transform = "";
|
|
127
|
+
wrapperEl.style.visibility = "";
|
|
128
|
+
wrapperEl.style.animation = "";
|
|
84
129
|
}
|
|
85
130
|
};
|
|
86
131
|
|
|
87
|
-
const setDropdownVisibility = (
|
|
132
|
+
const setDropdownVisibility = (
|
|
133
|
+
parentEl: ParentNode | null,
|
|
134
|
+
visibility: "hidden" | "visible",
|
|
135
|
+
) => {
|
|
88
136
|
const wrapperEl = getDropdownWrapperElement(parentEl);
|
|
89
137
|
if (wrapperEl) {
|
|
90
138
|
wrapperEl.style.visibility = visibility;
|
|
@@ -96,7 +144,9 @@ const DropDownComponent = ({ children, title, subTitle, $externalWidth, $externa
|
|
|
96
144
|
return;
|
|
97
145
|
}
|
|
98
146
|
|
|
99
|
-
const portalContainerRef = document.querySelector(
|
|
147
|
+
const portalContainerRef = document.querySelector(
|
|
148
|
+
`#${portalId} ._refDropdownPortal`,
|
|
149
|
+
) as HTMLElement | null;
|
|
100
150
|
const wrapperRef = getDropdownWrapperElement(portalContainerRef);
|
|
101
151
|
|
|
102
152
|
if (!portalContainerRef || !wrapperRef) {
|
|
@@ -105,35 +155,39 @@ const DropDownComponent = ({ children, title, subTitle, $externalWidth, $externa
|
|
|
105
155
|
|
|
106
156
|
if (isMobileViewport()) {
|
|
107
157
|
applyMobileDropdownPlacement(wrapperRef);
|
|
108
|
-
portalContainerRef.style.left = '
|
|
109
|
-
portalContainerRef.style.top = '
|
|
110
|
-
portalContainerRef.style.zIndex = $isPopup ?
|
|
158
|
+
portalContainerRef.style.left = "'-100%'";
|
|
159
|
+
portalContainerRef.style.top = "'-100%'";
|
|
160
|
+
portalContainerRef.style.zIndex = $isPopup ? "101" : "8";
|
|
111
161
|
return;
|
|
112
162
|
}
|
|
113
163
|
|
|
114
164
|
const offsetPos = containerEl.getBoundingClientRect();
|
|
115
165
|
const placement = getDropdownPlacement(containerEl, wrapperRef);
|
|
116
|
-
const wrapperWidth =
|
|
166
|
+
const wrapperWidth =
|
|
167
|
+
wrapperRef.getBoundingClientRect().width || wrapperRef.offsetWidth;
|
|
117
168
|
const viewportWidth = getViewportWidth();
|
|
118
169
|
|
|
119
170
|
let leftValue = offsetPos.left + offsetPos.width - wrapperWidth;
|
|
120
171
|
|
|
121
|
-
if ($openPosition ===
|
|
172
|
+
if ($openPosition === "left") {
|
|
122
173
|
leftValue = offsetPos.left;
|
|
123
|
-
} else if ($openPosition ===
|
|
124
|
-
leftValue = offsetPos.left +
|
|
174
|
+
} else if ($openPosition === "center") {
|
|
175
|
+
leftValue = offsetPos.left + offsetPos.width / 2 - wrapperWidth / 2;
|
|
125
176
|
}
|
|
126
177
|
|
|
127
|
-
leftValue = Math.max(
|
|
178
|
+
leftValue = Math.max(
|
|
179
|
+
0,
|
|
180
|
+
Math.min(leftValue, Math.max(viewportWidth - wrapperWidth, 0)),
|
|
181
|
+
);
|
|
128
182
|
|
|
129
|
-
wrapperRef.style.left =
|
|
130
|
-
wrapperRef.style.right =
|
|
131
|
-
wrapperRef.style.transform =
|
|
183
|
+
wrapperRef.style.left = "0";
|
|
184
|
+
wrapperRef.style.right = "auto";
|
|
185
|
+
wrapperRef.style.transform = "none";
|
|
132
186
|
applyDropdownPlacement(wrapperRef, placement);
|
|
133
187
|
|
|
134
188
|
portalContainerRef.style.left = `${leftValue}px`;
|
|
135
|
-
portalContainerRef.style.top = `${placement ===
|
|
136
|
-
portalContainerRef.style.zIndex = $isPopup ?
|
|
189
|
+
portalContainerRef.style.top = `${placement === "top" ? offsetPos.bottom : offsetPos.top}px`;
|
|
190
|
+
portalContainerRef.style.zIndex = $isPopup ? "101" : "8";
|
|
137
191
|
};
|
|
138
192
|
|
|
139
193
|
const setInlineDropdownPlacement = (containerEl: HTMLElement) => {
|
|
@@ -152,95 +206,134 @@ const DropDownComponent = ({ children, title, subTitle, $externalWidth, $externa
|
|
|
152
206
|
};
|
|
153
207
|
|
|
154
208
|
const evScrollDropdown = () => {
|
|
155
|
-
const containerEl = document.getElementsByClassName(
|
|
209
|
+
const containerEl = document.getElementsByClassName(
|
|
210
|
+
"_refContainer is-shown",
|
|
211
|
+
)[0] as HTMLElement;
|
|
156
212
|
if (containerEl && portalId) {
|
|
157
213
|
setPortalDropdownPosition(containerEl);
|
|
158
214
|
}
|
|
159
|
-
}
|
|
215
|
+
};
|
|
160
216
|
|
|
161
217
|
const evResetDropdown = () => {
|
|
162
|
-
const containerRef = document.getElementsByClassName(
|
|
163
|
-
|
|
218
|
+
const containerRef = document.getElementsByClassName(
|
|
219
|
+
"_refContainer is-shown",
|
|
220
|
+
) as HTMLCollectionOf<HTMLElement>;
|
|
221
|
+
const bodyEl = document.getElementsByTagName("BODY")[0] as HTMLBodyElement;
|
|
164
222
|
if (containerRef.length) {
|
|
165
|
-
bodyEl.classList.remove(
|
|
223
|
+
bodyEl.classList.remove("is-immuned");
|
|
166
224
|
for (let i = 0; i < containerRef.length; i++) {
|
|
167
|
-
const overlayEl = containerRef[i].querySelector(
|
|
168
|
-
|
|
169
|
-
|
|
225
|
+
const overlayEl = containerRef[i].querySelector(
|
|
226
|
+
`._refDropdownOverlay`,
|
|
227
|
+
) as HTMLDivElement;
|
|
228
|
+
overlayEl.style.display = "none";
|
|
229
|
+
containerRef[i].classList.remove("is-shown");
|
|
170
230
|
resetDropdownInlineStyle(containerRef[i]);
|
|
171
231
|
}
|
|
172
|
-
}
|
|
173
|
-
const refScrollContainerEl = document.querySelector(
|
|
174
|
-
|
|
232
|
+
}
|
|
233
|
+
const refScrollContainerEl = document.querySelector(
|
|
234
|
+
"._refScrollContainer",
|
|
235
|
+
) as HTMLElement;
|
|
236
|
+
refScrollContainerEl &&
|
|
237
|
+
refScrollContainerEl.removeEventListener(
|
|
238
|
+
"scroll",
|
|
239
|
+
evScrollDropdown,
|
|
240
|
+
true,
|
|
241
|
+
);
|
|
175
242
|
setTimeout(() => {
|
|
176
243
|
if (portalId) {
|
|
177
|
-
const portalContainerRef = document.getElementsByClassName(
|
|
244
|
+
const portalContainerRef = document.getElementsByClassName(
|
|
245
|
+
"_refDropdownPortal is-shown",
|
|
246
|
+
) as HTMLCollectionOf<HTMLElement>;
|
|
178
247
|
if (portalContainerRef.length) {
|
|
179
248
|
for (let i = 0; i < portalContainerRef.length; i++) {
|
|
180
249
|
resetDropdownInlineStyle(portalContainerRef[i]);
|
|
181
|
-
portalContainerRef[i].style.left = '
|
|
182
|
-
portalContainerRef[i].style.top = '
|
|
183
|
-
portalContainerRef[i].classList.remove(
|
|
250
|
+
portalContainerRef[i].style.left = "'-100%'";
|
|
251
|
+
portalContainerRef[i].style.top = "'-100%'";
|
|
252
|
+
portalContainerRef[i].classList.remove("is-shown");
|
|
184
253
|
}
|
|
185
|
-
}
|
|
254
|
+
}
|
|
186
255
|
}
|
|
187
|
-
},10);
|
|
188
|
-
}
|
|
256
|
+
}, 10);
|
|
257
|
+
};
|
|
189
258
|
|
|
190
|
-
const evToogleDropdown: TMouseEvent = e => {
|
|
259
|
+
const evToogleDropdown: TMouseEvent = (e) => {
|
|
191
260
|
const currRefEl = buttonRef.current;
|
|
192
261
|
if (currRefEl) {
|
|
193
|
-
const buttonEl = (e.target as HTMLElement).closest(
|
|
262
|
+
const buttonEl = (e.target as HTMLElement).closest(
|
|
263
|
+
`.${currRefEl.classList[0]}`,
|
|
264
|
+
);
|
|
194
265
|
if (!buttonEl) {
|
|
195
266
|
return;
|
|
196
267
|
}
|
|
197
|
-
const containerEl = buttonEl.closest(
|
|
198
|
-
const bodyEl = document.getElementsByTagName(
|
|
268
|
+
const containerEl = buttonEl.closest("._refContainer") as HTMLElement;
|
|
269
|
+
const bodyEl = document.getElementsByTagName(
|
|
270
|
+
"BODY",
|
|
271
|
+
)[0] as HTMLBodyElement;
|
|
199
272
|
if (containerEl) {
|
|
200
|
-
const overlayEl = containerEl.querySelector(
|
|
201
|
-
|
|
273
|
+
const overlayEl = containerEl.querySelector(
|
|
274
|
+
`._refDropdownOverlay`,
|
|
275
|
+
) as HTMLDivElement;
|
|
276
|
+
const isCurOpen = containerEl.classList.contains("is-shown");
|
|
202
277
|
|
|
203
278
|
if (!isCurOpen) {
|
|
204
|
-
evResetDropdown();
|
|
205
|
-
overlayEl.style.display =
|
|
206
|
-
bodyEl.classList.add(
|
|
279
|
+
evResetDropdown();
|
|
280
|
+
overlayEl.style.display = "block";
|
|
281
|
+
bodyEl.classList.add("is-immuned");
|
|
207
282
|
if (!portalId) {
|
|
208
|
-
setDropdownVisibility(containerEl,
|
|
283
|
+
setDropdownVisibility(containerEl, "hidden");
|
|
209
284
|
}
|
|
210
|
-
containerEl.classList.add(
|
|
285
|
+
containerEl.classList.add("is-shown");
|
|
211
286
|
setTimeout(() => {
|
|
212
287
|
if (portalId) {
|
|
213
|
-
const portalContainerRef = document.querySelector(
|
|
214
|
-
|
|
288
|
+
const portalContainerRef = document.querySelector(
|
|
289
|
+
`#${portalId} ._refDropdownPortal`,
|
|
290
|
+
) as HTMLElement;
|
|
291
|
+
const refScrollContainerEl = document.querySelector(
|
|
292
|
+
"._refScrollContainer",
|
|
293
|
+
) as HTMLElement;
|
|
215
294
|
if (portalContainerRef) {
|
|
216
|
-
portalContainerRef.classList.add(
|
|
295
|
+
portalContainerRef.classList.add("is-shown");
|
|
217
296
|
setTimeout(() => {
|
|
218
297
|
setPortalDropdownPosition(containerEl);
|
|
219
|
-
refScrollContainerEl &&
|
|
298
|
+
refScrollContainerEl &&
|
|
299
|
+
refScrollContainerEl.addEventListener(
|
|
300
|
+
"scroll",
|
|
301
|
+
evScrollDropdown,
|
|
302
|
+
true,
|
|
303
|
+
);
|
|
220
304
|
}, 10);
|
|
221
305
|
}
|
|
222
306
|
} else {
|
|
223
307
|
withNextFrame(() => {
|
|
224
308
|
setInlineDropdownPlacement(containerEl);
|
|
225
|
-
setDropdownVisibility(containerEl,
|
|
309
|
+
setDropdownVisibility(containerEl, "visible");
|
|
226
310
|
});
|
|
227
311
|
}
|
|
228
312
|
}, 10);
|
|
229
313
|
onClick && onClick(e);
|
|
230
314
|
} else {
|
|
231
|
-
overlayEl.style.display =
|
|
232
|
-
bodyEl.classList.remove(
|
|
233
|
-
containerEl.classList.remove(
|
|
315
|
+
overlayEl.style.display = "none";
|
|
316
|
+
bodyEl.classList.remove("is-immuned");
|
|
317
|
+
containerEl.classList.remove("is-shown");
|
|
234
318
|
setTimeout(() => {
|
|
235
319
|
if (portalId) {
|
|
236
|
-
const portalContainerRef = document.querySelector(
|
|
237
|
-
|
|
320
|
+
const portalContainerRef = document.querySelector(
|
|
321
|
+
`#${portalId} ._refDropdownPortal`,
|
|
322
|
+
) as HTMLElement;
|
|
323
|
+
const refScrollContainerEl = document.querySelector(
|
|
324
|
+
"._refScrollContainer",
|
|
325
|
+
) as HTMLElement;
|
|
238
326
|
if (portalContainerRef) {
|
|
239
327
|
resetDropdownInlineStyle(portalContainerRef);
|
|
240
|
-
portalContainerRef.classList.remove(
|
|
241
|
-
portalContainerRef.style.left =
|
|
242
|
-
portalContainerRef.style.top =
|
|
243
|
-
refScrollContainerEl &&
|
|
328
|
+
portalContainerRef.classList.remove("is-shown");
|
|
329
|
+
portalContainerRef.style.left = "-100%";
|
|
330
|
+
portalContainerRef.style.top = "-100%";
|
|
331
|
+
refScrollContainerEl &&
|
|
332
|
+
refScrollContainerEl.removeEventListener(
|
|
333
|
+
"scroll",
|
|
334
|
+
evScrollDropdown,
|
|
335
|
+
true,
|
|
336
|
+
);
|
|
244
337
|
}
|
|
245
338
|
}
|
|
246
339
|
}, 10);
|
|
@@ -248,138 +341,234 @@ const DropDownComponent = ({ children, title, subTitle, $externalWidth, $externa
|
|
|
248
341
|
}
|
|
249
342
|
}
|
|
250
343
|
}
|
|
251
|
-
}
|
|
344
|
+
};
|
|
252
345
|
|
|
253
|
-
const evMouseEnter: TMouseEvent = e => {
|
|
346
|
+
const evMouseEnter: TMouseEvent = (e) => {
|
|
254
347
|
const currRefEl = buttonRef.current;
|
|
255
348
|
if (currRefEl) {
|
|
256
|
-
const buttonEl = (e.target as HTMLElement).closest(
|
|
349
|
+
const buttonEl = (e.target as HTMLElement).closest(
|
|
350
|
+
`.${currRefEl.classList[0]}`,
|
|
351
|
+
);
|
|
257
352
|
if (!buttonEl) {
|
|
258
353
|
return;
|
|
259
354
|
}
|
|
260
|
-
const portalContainerRefs = document.querySelectorAll(
|
|
355
|
+
const portalContainerRefs = document.querySelectorAll(
|
|
356
|
+
`._refDropdownPortal`,
|
|
357
|
+
) as NodeListOf<HTMLElement>;
|
|
261
358
|
for (const portalContainerRef of portalContainerRefs) {
|
|
262
|
-
portalContainerRef.classList.remove(
|
|
263
|
-
portalContainerRef.style.left =
|
|
264
|
-
portalContainerRef.style.top =
|
|
359
|
+
portalContainerRef.classList.remove("is-shown");
|
|
360
|
+
portalContainerRef.style.left = "-100%";
|
|
361
|
+
portalContainerRef.style.top = "-100%";
|
|
265
362
|
}
|
|
266
|
-
const containerEl = buttonEl.closest(
|
|
363
|
+
const containerEl = buttonEl.closest("._refContainer") as HTMLElement;
|
|
267
364
|
if (containerEl) {
|
|
268
|
-
const portalContainerRef = document.querySelector(
|
|
365
|
+
const portalContainerRef = document.querySelector(
|
|
366
|
+
`#${portalId} ._refDropdownPortal`,
|
|
367
|
+
) as HTMLElement;
|
|
269
368
|
if (portalContainerRef) {
|
|
270
|
-
portalContainerRef.classList.add(
|
|
369
|
+
portalContainerRef.classList.add("is-shown");
|
|
271
370
|
setTimeout(() => {
|
|
272
371
|
setPortalDropdownPosition(containerEl);
|
|
273
372
|
}, 10);
|
|
274
373
|
}
|
|
275
374
|
}
|
|
276
375
|
}
|
|
277
|
-
}
|
|
376
|
+
};
|
|
278
377
|
|
|
279
378
|
useEffect(() => {
|
|
280
379
|
setTimeout(() => {
|
|
281
|
-
const portalContainerRefs = document.querySelectorAll(
|
|
380
|
+
const portalContainerRefs = document.querySelectorAll(
|
|
381
|
+
`._refDropdownPortal._refHover`,
|
|
382
|
+
) as NodeListOf<HTMLElement>;
|
|
282
383
|
for (let portalContainerRef of portalContainerRefs) {
|
|
283
|
-
portalContainerRef &&
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
384
|
+
portalContainerRef &&
|
|
385
|
+
portalContainerRef.addEventListener("mouseenter", (event) => {
|
|
386
|
+
const el = event.target as HTMLElement;
|
|
387
|
+
el.classList.add("is-shown");
|
|
388
|
+
el.classList.add("unhiddenable");
|
|
389
|
+
});
|
|
390
|
+
portalContainerRef &&
|
|
391
|
+
portalContainerRef.addEventListener("mouseleave", (event) => {
|
|
392
|
+
const el = event.target as HTMLElement;
|
|
393
|
+
el.classList.remove("is-shown");
|
|
394
|
+
el.classList.remove("unhiddenable");
|
|
395
|
+
el.style.left = "-100%";
|
|
396
|
+
el.style.top = "-100%";
|
|
397
|
+
});
|
|
295
398
|
}
|
|
296
399
|
}, 1);
|
|
297
400
|
return () => {
|
|
298
|
-
const portalContainerRefs = document.querySelectorAll(
|
|
401
|
+
const portalContainerRefs = document.querySelectorAll(
|
|
402
|
+
`._refDropdownPortal._refHover`,
|
|
403
|
+
) as NodeListOf<HTMLElement>;
|
|
299
404
|
for (let portalContainerRef of portalContainerRefs) {
|
|
300
|
-
portalContainerRef &&
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
405
|
+
portalContainerRef &&
|
|
406
|
+
portalContainerRef.removeEventListener(
|
|
407
|
+
"mouseenter",
|
|
408
|
+
(event) => {
|
|
409
|
+
const el = event.target as HTMLElement;
|
|
410
|
+
el.classList.add("is-shown");
|
|
411
|
+
el.classList.add("unhiddenable");
|
|
412
|
+
},
|
|
413
|
+
true,
|
|
414
|
+
);
|
|
415
|
+
portalContainerRef &&
|
|
416
|
+
portalContainerRef.removeEventListener(
|
|
417
|
+
"mouseleave",
|
|
418
|
+
(event) => {
|
|
419
|
+
const el = event.target as HTMLElement;
|
|
420
|
+
el.classList.remove("is-shown");
|
|
421
|
+
el.classList.remove("unhiddenable");
|
|
422
|
+
el.style.left = "-100%";
|
|
423
|
+
el.style.top = "-100%";
|
|
424
|
+
},
|
|
425
|
+
true,
|
|
426
|
+
);
|
|
312
427
|
}
|
|
313
428
|
};
|
|
314
|
-
}, [portalId])
|
|
429
|
+
}, [portalId]);
|
|
315
430
|
|
|
316
|
-
const evMouseLeave: TMouseEvent = e => {
|
|
431
|
+
const evMouseLeave: TMouseEvent = (e) => {
|
|
317
432
|
const currRefEl = buttonRef.current;
|
|
318
433
|
if (currRefEl) {
|
|
319
|
-
const buttonEl = (e.target as HTMLElement).closest(
|
|
434
|
+
const buttonEl = (e.target as HTMLElement).closest(
|
|
435
|
+
`.${currRefEl.classList[0]}`,
|
|
436
|
+
);
|
|
320
437
|
if (!buttonEl) {
|
|
321
438
|
return;
|
|
322
439
|
}
|
|
323
440
|
setTimeout(() => {
|
|
324
|
-
const portalContainerRef = document.querySelector(
|
|
325
|
-
|
|
441
|
+
const portalContainerRef = document.querySelector(
|
|
442
|
+
`#${portalId} ._refDropdownPortal`,
|
|
443
|
+
) as HTMLElement;
|
|
444
|
+
if (
|
|
445
|
+
portalContainerRef &&
|
|
446
|
+
!portalContainerRef.classList.contains("unhiddenable")
|
|
447
|
+
) {
|
|
326
448
|
resetDropdownInlineStyle(portalContainerRef);
|
|
327
|
-
portalContainerRef.classList.remove(
|
|
328
|
-
portalContainerRef.style.left =
|
|
329
|
-
portalContainerRef.style.top =
|
|
449
|
+
portalContainerRef.classList.remove("is-shown");
|
|
450
|
+
portalContainerRef.style.left = "-100%";
|
|
451
|
+
portalContainerRef.style.top = "-100%";
|
|
330
452
|
}
|
|
331
453
|
}, 150);
|
|
332
454
|
}
|
|
333
|
-
}
|
|
455
|
+
};
|
|
334
456
|
|
|
335
457
|
const evCloseDropdown = () => {
|
|
336
458
|
evResetDropdown();
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const DropDownSubTitleEl =
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const DropDownSubTitleEl = subTitle ? (
|
|
462
|
+
<DropDownSubTitle>{subTitle}</DropDownSubTitle>
|
|
463
|
+
) : null;
|
|
464
|
+
const DropDownTitleEl = title ? (
|
|
465
|
+
<DropDownTitle>
|
|
466
|
+
{title} {DropDownSubTitleEl}
|
|
467
|
+
</DropDownTitle>
|
|
468
|
+
) : null;
|
|
469
|
+
const ControlChildrenFilter = children.filter((child: any) =>
|
|
470
|
+
isValidElement(child)
|
|
471
|
+
? (child.props as any)["aria-label"] === "control"
|
|
472
|
+
: null,
|
|
473
|
+
);
|
|
474
|
+
const DropDownControlEl =
|
|
475
|
+
ControlChildrenFilter && isValidElement(ControlChildrenFilter[0]) ? (
|
|
476
|
+
type === "hover" ? (
|
|
477
|
+
<DropdownControlWrapper>
|
|
478
|
+
<DropDownControl
|
|
479
|
+
className="_refDropdownControl"
|
|
480
|
+
{...(portalId && {
|
|
481
|
+
onMouseEnter: evMouseEnter,
|
|
482
|
+
onMouseLeave: evMouseLeave,
|
|
483
|
+
})}
|
|
484
|
+
>
|
|
485
|
+
{(ControlChildrenFilter[0].props as any).children}
|
|
486
|
+
</DropDownControl>
|
|
487
|
+
<DropDownControl
|
|
488
|
+
className="_refDropdownControlMobile"
|
|
489
|
+
ref={buttonRef}
|
|
490
|
+
onClick={evToogleDropdown}
|
|
491
|
+
>
|
|
492
|
+
{(ControlChildrenFilter[0].props as any).children}
|
|
493
|
+
</DropDownControl>
|
|
494
|
+
</DropdownControlWrapper>
|
|
495
|
+
) : (
|
|
496
|
+
<DropDownControl ref={buttonRef} onClick={evToogleDropdown}>
|
|
497
|
+
{(ControlChildrenFilter[0].props as any).children}
|
|
498
|
+
</DropDownControl>
|
|
499
|
+
)
|
|
500
|
+
) : null;
|
|
501
|
+
const BodyChildrenFilter = children.filter((child: any) =>
|
|
502
|
+
isValidElement(child)
|
|
503
|
+
? (child.props as any)["aria-label"] === "body"
|
|
504
|
+
: null,
|
|
505
|
+
);
|
|
506
|
+
const DropDownBodyEl =
|
|
507
|
+
BodyChildrenFilter && isValidElement(BodyChildrenFilter[0]) ? (
|
|
508
|
+
<DropDownBody $area={$area}>
|
|
509
|
+
{(BodyChildrenFilter[0].props as any).children}
|
|
510
|
+
</DropDownBody>
|
|
511
|
+
) : null;
|
|
512
|
+
const ActionChildrenFilter = children.filter((child: any) =>
|
|
513
|
+
isValidElement(child)
|
|
514
|
+
? (child.props as any)["aria-label"] === "action"
|
|
515
|
+
: null,
|
|
516
|
+
);
|
|
517
|
+
const DropDownActionEl =
|
|
518
|
+
ActionChildrenFilter && isValidElement(ActionChildrenFilter[0]) ? (
|
|
519
|
+
<DropDownAction
|
|
520
|
+
$position={(ActionChildrenFilter[0].props as any)["data-position"]}
|
|
521
|
+
className={(ActionChildrenFilter[0].props as any).className}
|
|
522
|
+
>
|
|
523
|
+
{(ActionChildrenFilter[0].props as any).children}
|
|
524
|
+
</DropDownAction>
|
|
525
|
+
) : null;
|
|
526
|
+
|
|
527
|
+
const dropdownWrapperEl = (
|
|
528
|
+
<DropDownWrapper
|
|
529
|
+
className="_refDropdownWrapper"
|
|
530
|
+
{...($internalWidth && { $internalWidth: $internalWidth })}
|
|
531
|
+
{...($top && { $top: $top })}
|
|
532
|
+
{...($openPosition && { $openPosition: $openPosition })}
|
|
533
|
+
{...($placement && { $placement: $placement })}
|
|
534
|
+
{...($bottom && { $bottom: $bottom })}
|
|
535
|
+
>
|
|
536
|
+
{DropDownTitleEl}
|
|
537
|
+
{DropDownBodyEl}
|
|
538
|
+
{DropDownActionEl}
|
|
539
|
+
</DropDownWrapper>
|
|
540
|
+
);
|
|
366
541
|
return (
|
|
367
|
-
<DropDownContainer
|
|
542
|
+
<DropDownContainer
|
|
368
543
|
className={`_refContainer ${type ? `_refContainer${type}` : ``}`}
|
|
369
|
-
{
|
|
370
|
-
{
|
|
371
|
-
{
|
|
372
|
-
{
|
|
373
|
-
{
|
|
374
|
-
{
|
|
375
|
-
{
|
|
376
|
-
{
|
|
377
|
-
{...props}
|
|
544
|
+
{...($externalWidth && { $externalWidth: $externalWidth })}
|
|
545
|
+
{...($externalMinWidth && { $externalMinWidth: $externalMinWidth })}
|
|
546
|
+
{...($area && { $area: $area })}
|
|
547
|
+
{...($top && { $top: $top })}
|
|
548
|
+
{...($alias && { $alias: $alias })}
|
|
549
|
+
{...($openPosition && { $openPosition: $openPosition })}
|
|
550
|
+
{...($placement && { $placement: $placement })}
|
|
551
|
+
{...($bottom && { $bottom: $bottom })}
|
|
552
|
+
{...props}
|
|
553
|
+
>
|
|
378
554
|
{DropDownControlEl}
|
|
379
|
-
<DropDownOverlayWrapper
|
|
380
|
-
|
|
555
|
+
<DropDownOverlayWrapper
|
|
556
|
+
className="_refDropdownOverlay"
|
|
557
|
+
onClick={evCloseDropdown}
|
|
558
|
+
/>
|
|
559
|
+
{portalId ? (
|
|
560
|
+
<ReactPortalComponent wrapperId={portalId}>
|
|
561
|
+
<DropdownPortalContainer
|
|
562
|
+
className={`_refDropdownPortal ${type === "hover" ? "_refHover" : ""}`}
|
|
563
|
+
>
|
|
564
|
+
{dropdownWrapperEl}
|
|
565
|
+
</DropdownPortalContainer>
|
|
566
|
+
</ReactPortalComponent>
|
|
567
|
+
) : (
|
|
568
|
+
dropdownWrapperEl
|
|
569
|
+
)}
|
|
381
570
|
</DropDownContainer>
|
|
382
571
|
);
|
|
383
|
-
}
|
|
572
|
+
};
|
|
384
573
|
|
|
385
574
|
export default DropDownComponent;
|