@adamjanicki/ui 1.6.3 → 1.6.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/components/Accordion/Accordion.d.ts +9 -3
- package/components/Accordion/Accordion.js +5 -17
- package/components/Animated/Animated.d.ts +17 -3
- package/components/Animated/Animated.js +48 -29
- package/components/ClickOutside/ClickOutside.d.ts +11 -1
- package/components/ClickOutside/ClickOutside.js +26 -11
- package/components/Layer/Layer.js +3 -1
- package/components/Modal/Modal.js +1 -1
- package/hooks/index.d.ts +1 -0
- package/hooks/index.js +1 -0
- package/hooks/useMergeRefs.d.ts +9 -0
- package/hooks/useMergeRefs.js +24 -0
- package/package.json +1 -1
|
@@ -25,13 +25,19 @@ type Drawer = {
|
|
|
25
25
|
* Content hidden within this accordion drawer
|
|
26
26
|
*/
|
|
27
27
|
content: React.ReactNode;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Whether the drawer is open
|
|
30
|
+
*/
|
|
30
31
|
open: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Callback that fires when the open state changes for this drawer
|
|
34
|
+
*/
|
|
31
35
|
onOpenChange: (open: boolean) => void;
|
|
36
|
+
};
|
|
37
|
+
type DrawerProps = {
|
|
32
38
|
item: Drawer;
|
|
33
39
|
duration?: number;
|
|
34
40
|
showDivider: boolean;
|
|
35
41
|
};
|
|
36
|
-
declare const Drawer: ({ item,
|
|
42
|
+
declare const Drawer: ({ item, duration, showDivider }: DrawerProps) => import("react/jsx-runtime").JSX.Element;
|
|
37
43
|
export default Accordion;
|
|
@@ -21,7 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
21
21
|
return t;
|
|
22
22
|
};
|
|
23
23
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
24
|
-
import React, {
|
|
24
|
+
import React, { useRef, useState, useEffect } from "react";
|
|
25
25
|
import Box from "../Box/Box";
|
|
26
26
|
import Icon from "../Icon";
|
|
27
27
|
import { UnstyledButton } from "../Button";
|
|
@@ -29,25 +29,13 @@ import Animated from "../Animated";
|
|
|
29
29
|
import { classNames } from "../../functions";
|
|
30
30
|
var Accordion = React.forwardRef(function (_a, ref) {
|
|
31
31
|
var drawers = _a.drawers, className = _a.className, duration = _a.duration, hideDividers = _a.hideDividers, layout = _a.layout, rest = __rest(_a, ["drawers", "className", "duration", "hideDividers", "layout"]);
|
|
32
|
-
|
|
33
|
-
return (_jsx(Box, __assign({ layout: __assign({ axis: "y" }, layout) }, rest, { className: classNames("aui-accordion aui-corners--rounded", className), ref: ref, children: drawers.map(function (item, i) { return (_jsx(Drawer, { item: item, open: openIndices.has(i), onOpenChange: function (open) {
|
|
34
|
-
return setOpenIndices(function (prev) {
|
|
35
|
-
var next = new Set(prev);
|
|
36
|
-
if (open) {
|
|
37
|
-
next.add(i);
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
next.delete(i);
|
|
41
|
-
}
|
|
42
|
-
return next;
|
|
43
|
-
});
|
|
44
|
-
}, duration: duration, showDivider: !hideDividers && i < drawers.length - 1 }, i)); }) })));
|
|
32
|
+
return (_jsx(Box, __assign({ layout: __assign({ axis: "y" }, layout) }, rest, { className: classNames("aui-accordion aui-corners--rounded", className), ref: ref, children: drawers.map(function (item, i) { return (_jsx(Drawer, { item: item, duration: duration, showDivider: !hideDividers && i < drawers.length - 1 }, i)); }) })));
|
|
45
33
|
});
|
|
46
34
|
var Drawer = function (_a) {
|
|
47
|
-
var item = _a.item,
|
|
35
|
+
var item = _a.item, duration = _a.duration, showDivider = _a.showDivider;
|
|
48
36
|
var boxRef = useRef(null);
|
|
49
37
|
var _b = useState(), height = _b[0], setHeight = _b[1];
|
|
50
|
-
var children = item.content;
|
|
38
|
+
var children = item.content, open = item.open, onOpenChange = item.onOpenChange;
|
|
51
39
|
useEffect(function () {
|
|
52
40
|
if (open && children && boxRef.current) {
|
|
53
41
|
setHeight(boxRef.current.offsetHeight);
|
|
@@ -55,7 +43,7 @@ var Drawer = function (_a) {
|
|
|
55
43
|
}, [open, children]);
|
|
56
44
|
// TODO: change this to use calc-size when supported
|
|
57
45
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/calc-size#browser_compatibility
|
|
58
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Box, { layout: { axis: "y" }, children: [_jsx(UnstyledButton, { onClick: function () { return onOpenChange(!open); }, children: _jsxs(Box, { layout: { axis: "x", align: "center", gap: "s", padding: "m" }, children: [_jsx(Icon, { size: "xs", icon: open ? "chevron-down" : "chevron-right", className: "aui-accordion-arrow" }), _jsx("span", { className: "aui-accordion-label", children: item.label })] }) }), _jsx(Animated, { style: { overflow: "hidden" }, keepMounted: true, duration: duration,
|
|
46
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { layout: { axis: "y" }, children: [_jsx(UnstyledButton, { onClick: function () { return onOpenChange(!open); }, children: _jsxs(Box, { layout: { axis: "x", align: "center", gap: "s", padding: "m" }, children: [_jsx(Icon, { size: "xs", icon: open ? "chevron-down" : "chevron-right", className: "aui-accordion-arrow" }), _jsx("span", { className: "aui-accordion-label", children: item.label })] }) }), _jsx(Animated, { style: { overflow: "hidden" }, keepMounted: true, duration: duration, visible: open, animateFrom: {
|
|
59
47
|
style: {
|
|
60
48
|
visibility: "hidden",
|
|
61
49
|
height: 0,
|
|
@@ -3,15 +3,24 @@ import type { Style } from "../../utils/types";
|
|
|
3
3
|
import { type BoxProps } from "../Box/Box";
|
|
4
4
|
type Props = BoxProps & {
|
|
5
5
|
/**
|
|
6
|
-
* Whether to begin the animation.
|
|
6
|
+
* Whether to begin the animation and render the component.
|
|
7
7
|
* Set to true to start animation, false to start the exit animation.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
visible: boolean;
|
|
10
10
|
/**
|
|
11
11
|
* Duration of the animation in seconds
|
|
12
12
|
* @default 0.25
|
|
13
13
|
*/
|
|
14
|
-
duration?: number
|
|
14
|
+
duration?: number | {
|
|
15
|
+
/**
|
|
16
|
+
* Length of the forward direction
|
|
17
|
+
*/
|
|
18
|
+
forward: number;
|
|
19
|
+
/**
|
|
20
|
+
* Length of the reverse direction
|
|
21
|
+
*/
|
|
22
|
+
reverse: number;
|
|
23
|
+
};
|
|
15
24
|
/**
|
|
16
25
|
* Whether to keep the component mounted when it is not animated
|
|
17
26
|
* @default false
|
|
@@ -40,6 +49,11 @@ type Props = BoxProps & {
|
|
|
40
49
|
*/
|
|
41
50
|
style?: Style;
|
|
42
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* The properties to apply a transition
|
|
54
|
+
* @default ['all']
|
|
55
|
+
*/
|
|
56
|
+
transitionProperties?: string[];
|
|
43
57
|
};
|
|
44
58
|
declare const Animated: React.ForwardRefExoticComponent<Omit<Props, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
45
59
|
export default Animated;
|
|
@@ -25,9 +25,12 @@ import React, { useState, useEffect, useRef } from "react";
|
|
|
25
25
|
import classNames from "../../functions/classNames";
|
|
26
26
|
import Box from "../Box/Box";
|
|
27
27
|
var Animated = React.forwardRef(function (props, ref) {
|
|
28
|
-
var
|
|
29
|
-
var
|
|
30
|
-
var
|
|
28
|
+
var visible = props.visible, _a = props.duration, duration = _a === void 0 ? 0.25 : _a, _b = props.keepMounted, keepMounted = _b === void 0 ? false : _b, _c = props.transitionProperties, transitionProperties = _c === void 0 ? ["all"] : _c, animateTo = props.animateTo, animateFrom = props.animateFrom, className = props.className, style = props.style, rest = __rest(props, ["visible", "duration", "keepMounted", "transitionProperties", "animateTo", "animateFrom", "className", "style"]);
|
|
29
|
+
var forwardDuration = typeof duration === "number" ? duration : duration.forward;
|
|
30
|
+
var reverseDuration = typeof duration === "number" ? duration : duration.reverse;
|
|
31
|
+
var instantForward = forwardDuration <= 0;
|
|
32
|
+
var instantReverse = reverseDuration <= 0;
|
|
33
|
+
var _d = useState("from"), phase = _d[0], setPhase = _d[1];
|
|
31
34
|
var timeoutRef = useRef(null);
|
|
32
35
|
var animationFrameRef = useRef(null);
|
|
33
36
|
var clearRefs = function () {
|
|
@@ -41,35 +44,51 @@ var Animated = React.forwardRef(function (props, ref) {
|
|
|
41
44
|
}
|
|
42
45
|
};
|
|
43
46
|
useEffect(function () {
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return clearRefs;
|
|
52
|
-
}, [animated, shouldRender]);
|
|
53
|
-
useEffect(function () {
|
|
54
|
-
// make container element appear on DOM
|
|
55
|
-
if (animated) {
|
|
56
|
-
setShouldRender(true);
|
|
57
|
-
}
|
|
58
|
-
// initiate reverse animation
|
|
59
|
-
else {
|
|
60
|
-
clearRefs();
|
|
61
|
-
setIsAnimatingForward(false);
|
|
62
|
-
timeoutRef.current = window.setTimeout(function () {
|
|
63
|
-
if (!keepMounted) {
|
|
64
|
-
setShouldRender(false);
|
|
47
|
+
clearRefs();
|
|
48
|
+
if (visible) {
|
|
49
|
+
if (phase !== "forward") {
|
|
50
|
+
if (instantForward) {
|
|
51
|
+
setPhase("forward");
|
|
65
52
|
}
|
|
66
|
-
|
|
53
|
+
else {
|
|
54
|
+
animationFrameRef.current = requestAnimationFrame(function () {
|
|
55
|
+
return setPhase("forward");
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (phase !== "from") {
|
|
61
|
+
if (instantReverse) {
|
|
62
|
+
setPhase("from");
|
|
63
|
+
}
|
|
64
|
+
else if (phase !== "reverse") {
|
|
65
|
+
setPhase("reverse");
|
|
66
|
+
}
|
|
67
|
+
else if (phase === "reverse") {
|
|
68
|
+
timeoutRef.current = window.setTimeout(function () { return setPhase("from"); }, reverseDuration * 1000);
|
|
69
|
+
}
|
|
67
70
|
}
|
|
68
71
|
return clearRefs;
|
|
69
|
-
}, [
|
|
70
|
-
if (!
|
|
72
|
+
}, [visible, phase, instantForward, instantReverse, reverseDuration]);
|
|
73
|
+
if (phase === "from" && !keepMounted && !visible)
|
|
71
74
|
return null;
|
|
72
|
-
var currentAnimation =
|
|
73
|
-
|
|
75
|
+
var currentAnimation = phase === "forward" || (visible && instantForward)
|
|
76
|
+
? animateTo
|
|
77
|
+
: animateFrom;
|
|
78
|
+
var transition = undefined;
|
|
79
|
+
if (phase === "forward" && !instantForward) {
|
|
80
|
+
transition = makeTransition(transitionProperties, forwardDuration);
|
|
81
|
+
}
|
|
82
|
+
else if (phase === "reverse" && !instantReverse) {
|
|
83
|
+
transition = makeTransition(transitionProperties, reverseDuration);
|
|
84
|
+
}
|
|
85
|
+
return (_jsx(Box, __assign({ className: classNames(className, currentAnimation === null || currentAnimation === void 0 ? void 0 : currentAnimation.className), style: __assign(__assign({ transition: transition }, style), currentAnimation === null || currentAnimation === void 0 ? void 0 : currentAnimation.style) }, rest, { ref: ref })));
|
|
74
86
|
});
|
|
87
|
+
var makeTransition = function (transitionProperties, duration) {
|
|
88
|
+
return transitionProperties.length > 0
|
|
89
|
+
? transitionProperties
|
|
90
|
+
.map(function (prop) { return "".concat(prop, " ").concat(duration, "s ease-in-out"); })
|
|
91
|
+
.join(", ")
|
|
92
|
+
: undefined;
|
|
93
|
+
};
|
|
75
94
|
export default Animated;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
declare const mouseEvents: {
|
|
3
|
+
readonly click: "onClick";
|
|
4
|
+
readonly mousedown: "onMouseDown";
|
|
5
|
+
readonly mouseup: "onMouseUp";
|
|
6
|
+
};
|
|
2
7
|
type Props = {
|
|
3
8
|
/**
|
|
4
9
|
* The children to render.
|
|
@@ -11,6 +16,11 @@ type Props = {
|
|
|
11
16
|
* @param event - The mouse event object
|
|
12
17
|
*/
|
|
13
18
|
onClickOutside: (event: MouseEvent) => void;
|
|
19
|
+
/**
|
|
20
|
+
* The mouse event to trigger on
|
|
21
|
+
* @default "click"
|
|
22
|
+
*/
|
|
23
|
+
mouseEvent?: keyof typeof mouseEvents;
|
|
14
24
|
};
|
|
15
|
-
declare const ClickOutside: ({ children, onClickOutside, }: Props) => React.JSX.Element;
|
|
25
|
+
declare const ClickOutside: ({ children, onClickOutside, mouseEvent, }: Props) => React.JSX.Element;
|
|
16
26
|
export default ClickOutside;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { cloneElement, useCallback, useEffect, useRef } from "react";
|
|
2
|
+
import useMergeRefs from "../../hooks/useMergeRefs";
|
|
3
|
+
var mouseEvents = {
|
|
4
|
+
click: "onClick",
|
|
5
|
+
mousedown: "onMouseDown",
|
|
6
|
+
mouseup: "onMouseUp",
|
|
7
|
+
};
|
|
2
8
|
var ClickOutside = function (_a) {
|
|
3
|
-
var
|
|
9
|
+
var _b;
|
|
10
|
+
var children = _a.children, onClickOutside = _a.onClickOutside, _c = _a.mouseEvent, mouseEvent = _c === void 0 ? "click" : _c;
|
|
4
11
|
var ref = useRef(null);
|
|
5
12
|
var clickWithinChildRef = useRef(false);
|
|
6
13
|
var startedRef = useRef(false);
|
|
@@ -14,27 +21,35 @@ var ClickOutside = function (_a) {
|
|
|
14
21
|
};
|
|
15
22
|
}, []);
|
|
16
23
|
var handleClickOutside = useCallback(function (event) {
|
|
24
|
+
var _a;
|
|
17
25
|
var clickedWithinChild = clickWithinChildRef.current;
|
|
18
26
|
clickWithinChildRef.current = false;
|
|
19
|
-
|
|
27
|
+
var childElement = ref.current;
|
|
28
|
+
if (!startedRef.current || !childElement || clickedWithinChild)
|
|
20
29
|
return;
|
|
21
|
-
|
|
30
|
+
var path = ((_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)) || [];
|
|
31
|
+
var isInside = path.includes(childElement) ||
|
|
32
|
+
childElement.contains(event.target);
|
|
33
|
+
if (!isInside) {
|
|
22
34
|
onClickOutside(event);
|
|
23
35
|
}
|
|
24
36
|
}, [onClickOutside]);
|
|
25
37
|
useEffect(function () {
|
|
26
|
-
document.addEventListener(
|
|
27
|
-
return function () { return document.removeEventListener(
|
|
28
|
-
}, [handleClickOutside]);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
document.addEventListener(mouseEvent, handleClickOutside);
|
|
39
|
+
return function () { return document.removeEventListener(mouseEvent, handleClickOutside); };
|
|
40
|
+
}, [handleClickOutside, mouseEvent]);
|
|
41
|
+
var mergedRef = useMergeRefs(ref, children.props.ref);
|
|
42
|
+
var mouseEventPropName = mouseEvents[mouseEvent];
|
|
43
|
+
return cloneElement(children, (_b = {
|
|
44
|
+
ref: mergedRef
|
|
45
|
+
},
|
|
46
|
+
_b[mouseEventPropName] = function (event) {
|
|
32
47
|
var _a, _b;
|
|
33
48
|
// point of this is to let us know that click originated
|
|
34
49
|
// from the child element, so we can ignore it
|
|
35
50
|
clickWithinChildRef.current = true;
|
|
36
|
-
(_b = (_a = children.props) === null || _a === void 0 ? void 0 : _a
|
|
51
|
+
(_b = (_a = children.props) === null || _a === void 0 ? void 0 : _a[mouseEventPropName]) === null || _b === void 0 ? void 0 : _b.call(_a, event);
|
|
37
52
|
},
|
|
38
|
-
|
|
53
|
+
_b));
|
|
39
54
|
};
|
|
40
55
|
export default ClickOutside;
|
|
@@ -25,6 +25,7 @@ import React, { useEffect } from "react";
|
|
|
25
25
|
import { useFocusTrap, useScrollLock } from "../../hooks";
|
|
26
26
|
import classNames from "../../functions/classNames";
|
|
27
27
|
import Box from "../Box/Box";
|
|
28
|
+
import useMergeRefs from "../../hooks/useMergeRefs";
|
|
28
29
|
var Layer = React.forwardRef(function (_a, ref) {
|
|
29
30
|
var returnFocusOnEscape = _a.returnFocusOnEscape, disableScrollLock = _a.disableScrollLock, onClose = _a.onClose, children = _a.children, className = _a.className, onMouseDown = _a.onMouseDown, layout = _a.layout, rest = __rest(_a, ["returnFocusOnEscape", "disableScrollLock", "onClose", "children", "className", "onMouseDown", "layout"]);
|
|
30
31
|
var focusRef = useFocusTrap(true);
|
|
@@ -46,11 +47,12 @@ var Layer = React.forwardRef(function (_a, ref) {
|
|
|
46
47
|
document.removeEventListener("keydown", handleEscape);
|
|
47
48
|
};
|
|
48
49
|
}, [onClose, returnFocusOnEscape]);
|
|
50
|
+
var mergedRef = useMergeRefs(focusRef, children.props.ref);
|
|
49
51
|
return (_jsx(Box, __assign({ layout: __assign({ axis: "y", align: "center", justify: "center" }, layout) }, rest, { className: classNames("aui-layer-backdrop", className), onMouseDown: function (e) {
|
|
50
52
|
onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(e);
|
|
51
53
|
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
52
54
|
}, ref: ref, children: React.cloneElement(children, {
|
|
53
|
-
ref:
|
|
55
|
+
ref: mergedRef,
|
|
54
56
|
onMouseDown: function (e) {
|
|
55
57
|
var _a, _b;
|
|
56
58
|
e.stopPropagation();
|
|
@@ -28,7 +28,7 @@ import Button, { IconButton } from "../Button";
|
|
|
28
28
|
import Animated from "../Animated";
|
|
29
29
|
var Modal = React.forwardRef(function (_a, ref) {
|
|
30
30
|
var open = _a.open, onClose = _a.onClose, onConfirm = _a.onConfirm, _b = _a.confirmLabel, confirmLabel = _b === void 0 ? "Ok" : _b, _c = _a.cancelLabel, cancelLabel = _c === void 0 ? "Cancel" : _c, returnFocusOnEscape = _a.returnFocusOnEscape, rest = __rest(_a, ["open", "onClose", "onConfirm", "confirmLabel", "cancelLabel", "returnFocusOnEscape"]);
|
|
31
|
-
return (_jsx(Animated, { className: "aui-modal-backdrop",
|
|
31
|
+
return (_jsx(Animated, { className: "aui-modal-backdrop", visible: open, animateTo: { style: { opacity: 1 } }, animateFrom: { style: { opacity: 0 } }, children: _jsx(Layer, { onClose: onClose, returnFocusOnEscape: returnFocusOnEscape, children: _jsxs(Box, { role: "dialog", "aria-modal": "true", className: "aui-modal aui-corners--rounded", layout: { axis: "y", padding: "m", gap: "m" }, children: [_jsx(Box, { layout: {
|
|
32
32
|
axis: "x",
|
|
33
33
|
align: "center",
|
|
34
34
|
justify: "end",
|
package/hooks/index.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export { default as useScroll } from "./useScroll";
|
|
|
4
4
|
export { default as useFocusTrap } from "./useFocusTrap";
|
|
5
5
|
export { default as useScrollToHash } from "./useScrollToHash";
|
|
6
6
|
export { default as useWindowResize } from "./useWindowResize";
|
|
7
|
+
export { default as useMergeRefs } from "./useMergeRefs";
|
package/hooks/index.js
CHANGED
|
@@ -4,3 +4,4 @@ export { default as useScroll } from "./useScroll";
|
|
|
4
4
|
export { default as useFocusTrap } from "./useFocusTrap";
|
|
5
5
|
export { default as useScrollToHash } from "./useScrollToHash";
|
|
6
6
|
export { default as useWindowResize } from "./useWindowResize";
|
|
7
|
+
export { default as useMergeRefs } from "./useMergeRefs";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Simple hook that merges N refs into one callback
|
|
4
|
+
*
|
|
5
|
+
* @param refs all the refs you want to merge
|
|
6
|
+
* @returns one combined ref
|
|
7
|
+
*/
|
|
8
|
+
declare const useMergeRefs: <T>(...refs: (React.Ref<T> | null | undefined)[]) => React.Ref<T>;
|
|
9
|
+
export default useMergeRefs;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Simple hook that merges N refs into one callback
|
|
4
|
+
*
|
|
5
|
+
* @param refs all the refs you want to merge
|
|
6
|
+
* @returns one combined ref
|
|
7
|
+
*/
|
|
8
|
+
var useMergeRefs = function () {
|
|
9
|
+
var refs = [];
|
|
10
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
11
|
+
refs[_i] = arguments[_i];
|
|
12
|
+
}
|
|
13
|
+
return useCallback(function (node) {
|
|
14
|
+
refs.forEach(function (ref) {
|
|
15
|
+
if (typeof ref === "function") {
|
|
16
|
+
ref(node);
|
|
17
|
+
}
|
|
18
|
+
else if (ref && typeof ref === "object") {
|
|
19
|
+
ref.current = node;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}, [refs]);
|
|
23
|
+
};
|
|
24
|
+
export default useMergeRefs;
|