cherry-styled-components 0.2.1 → 0.2.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.
- package/dist/modal.d.ts +10 -1
- package/dist/modal.js +40 -16
- package/dist/utils/use-on-click-outside.js +14 -3
- package/package.json +1 -1
package/dist/modal.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ export interface ModalProps {
|
|
|
5
5
|
$onClose: () => void;
|
|
6
6
|
$title?: string;
|
|
7
7
|
$width?: number;
|
|
8
|
+
$hideCloseButton?: boolean;
|
|
9
|
+
/** Escape hatches for app-level restyling, both applied to the overlay
|
|
10
|
+
root. Note that wrapping with styled(Modal) does NOT work for the $-props
|
|
11
|
+
API (styled-components strips transient props before they reach the
|
|
12
|
+
wrapped component), so restyle by targeting a passed class instead. The
|
|
13
|
+
inner parts expose stable class hooks: .modal-inner, .modal-close,
|
|
14
|
+
.modal-title, .modal-content. */
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
8
17
|
}
|
|
9
|
-
declare function Modal({ children, $isOpen, $onClose, $title, $width }: ModalProps): React.ReactPortal | null;
|
|
18
|
+
declare function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton, className, style, }: ModalProps): React.ReactPortal | null;
|
|
10
19
|
export { Modal };
|
package/dist/modal.js
CHANGED
|
@@ -6,8 +6,8 @@ import { useOnClickOutside } from "./utils/use-on-click-outside.js";
|
|
|
6
6
|
import { Icon } from "./icon.js";
|
|
7
7
|
import { IconButton } from "./icon-button.js";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
|
|
10
|
-
import styled, { css } from "styled-components";
|
|
9
|
+
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
10
|
+
import styled, { css, keyframes } from "styled-components";
|
|
11
11
|
import { rgba } from "polished";
|
|
12
12
|
import { createPortal } from "react-dom";
|
|
13
13
|
//#region src/lib/modal.tsx
|
|
@@ -15,26 +15,31 @@ var emptySubscribe = () => () => {};
|
|
|
15
15
|
function useIsClient() {
|
|
16
16
|
return useSyncExternalStore(emptySubscribe, () => true, () => false);
|
|
17
17
|
}
|
|
18
|
+
var overlayFadeIn = keyframes([`from{opacity:0;}to{opacity:1;}`]);
|
|
19
|
+
var overlayFadeOut = keyframes([`from{opacity:1;}to{opacity:0;}`]);
|
|
20
|
+
var innerRiseIn = keyframes([`from{transform:translateY(40px);}to{transform:translateY(0);}`]);
|
|
21
|
+
var innerSinkOut = keyframes([`from{transform:translateY(0);}to{transform:translateY(40px);}`]);
|
|
18
22
|
var StyledModal = styled.div.withConfig({
|
|
19
23
|
displayName: "modal__StyledModal",
|
|
20
|
-
componentId: "sc-
|
|
24
|
+
componentId: "sc-14a8d5c-0"
|
|
21
25
|
})([
|
|
22
26
|
`position:fixed;top:0;left:0;width:100%;height:100%;background:`,
|
|
23
|
-
`;display:flex;justify-content:center;align-items:center;z-index:1010;
|
|
27
|
+
`;display:flex;justify-content:center;align-items:center;z-index:1010;animation:`,
|
|
28
|
+
` 0.3s ease both;`,
|
|
24
29
|
` & .modal-inner{background:`,
|
|
25
30
|
`;border-radius:`,
|
|
26
|
-
`;padding:20px;max-width:calc(100% - 40px);width:100%;margin:auto;position:relative;
|
|
27
|
-
`
|
|
31
|
+
`;padding:20px;max-width:calc(100% - 40px);width:100%;margin:auto;position:relative;animation:`,
|
|
32
|
+
` 0.3s ease both;`,
|
|
28
33
|
`{max-width:500px;`,
|
|
29
34
|
`}}`
|
|
30
|
-
], ({ theme }) => rgba(theme.colors.primary, .5), ({ $
|
|
35
|
+
], ({ theme }) => rgba(theme.colors.primary, .5), ({ $isClosing }) => $isClosing ? overlayFadeOut : overlayFadeIn, ({ $isClosing }) => $isClosing && css([`pointer-events:none;`]), ({ theme }) => theme.colors.light, ({ theme }) => theme.spacing.radius.lg, ({ $isClosing }) => $isClosing ? innerSinkOut : innerRiseIn, mq("lg"), ({ $width }) => $width && css([`max-width:`, `px;`], $width));
|
|
31
36
|
var StyledModalClose = styled(IconButton).withConfig({
|
|
32
37
|
displayName: "modal__StyledModalClose",
|
|
33
|
-
componentId: "sc-
|
|
38
|
+
componentId: "sc-14a8d5c-1"
|
|
34
39
|
})([`position:absolute;top:20px;right:20px;z-index:10;`]);
|
|
35
40
|
var StyledModalTitle = styled.h2.withConfig({
|
|
36
41
|
displayName: "modal__StyledModalTitle",
|
|
37
|
-
componentId: "sc-
|
|
42
|
+
componentId: "sc-14a8d5c-2"
|
|
38
43
|
})([
|
|
39
44
|
`--divider-color:`,
|
|
40
45
|
`;margin:0 0 15px 0;padding:0 0 15px 0;color:`,
|
|
@@ -43,16 +48,19 @@ var StyledModalTitle = styled.h2.withConfig({
|
|
|
43
48
|
], ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.dark, ({ theme }) => styledH5(theme));
|
|
44
49
|
var StyledModalContent = styled.div.withConfig({
|
|
45
50
|
displayName: "modal__StyledModalContent",
|
|
46
|
-
componentId: "sc-
|
|
51
|
+
componentId: "sc-14a8d5c-3"
|
|
47
52
|
})([
|
|
48
53
|
`max-height:calc(100svh - 200px);overflow-y:auto;padding:5px;margin:-5px;--divider-color:`,
|
|
49
54
|
`;`,
|
|
50
55
|
`;& hr{margin:20px 0;border:none;border-bottom:solid 1px var(--divider-color);}`
|
|
51
56
|
], ({ theme }) => theme.colors.grayLight, ({ theme }) => styledText(theme));
|
|
52
|
-
function Modal({ children, $isOpen, $onClose, $title, $width }) {
|
|
57
|
+
function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton, className, style }) {
|
|
53
58
|
const wrapperRef = useRef(null);
|
|
54
59
|
const elmRef = useRef(null);
|
|
55
60
|
const isClient = useIsClient();
|
|
61
|
+
const [shouldRender, setShouldRender] = useState($isOpen);
|
|
62
|
+
if ($isOpen && !shouldRender) setShouldRender(true);
|
|
63
|
+
const isClosing = !$isOpen && shouldRender;
|
|
56
64
|
const closeModal = useCallback(() => {
|
|
57
65
|
$onClose();
|
|
58
66
|
}, [$onClose]);
|
|
@@ -68,15 +76,25 @@ function Modal({ children, $isOpen, $onClose, $title, $width }) {
|
|
|
68
76
|
return () => document.removeEventListener("keydown", handleKeydown);
|
|
69
77
|
}, [$isOpen, closeModal]);
|
|
70
78
|
useOnClickOutside([elmRef, wrapperRef], $isOpen ? closeModal : () => {});
|
|
71
|
-
|
|
79
|
+
const handleAnimationEnd = useCallback((event) => {
|
|
80
|
+
if (event.target !== event.currentTarget) return;
|
|
81
|
+
if (!$isOpen) setShouldRender(false);
|
|
82
|
+
}, [$isOpen]);
|
|
83
|
+
if (!isClient || !shouldRender) return null;
|
|
72
84
|
return /*#__PURE__*/ createPortal(/*#__PURE__*/ jsx(StyledModal, {
|
|
73
|
-
$
|
|
85
|
+
$isClosing: isClosing,
|
|
74
86
|
$width,
|
|
87
|
+
className,
|
|
88
|
+
style,
|
|
89
|
+
onAnimationEnd: handleAnimationEnd,
|
|
75
90
|
children: /*#__PURE__*/ jsxs("div", {
|
|
76
91
|
className: "modal-inner",
|
|
77
92
|
ref: wrapperRef,
|
|
93
|
+
role: "dialog",
|
|
94
|
+
"aria-modal": "true",
|
|
95
|
+
"aria-label": $title,
|
|
78
96
|
children: [
|
|
79
|
-
/*#__PURE__*/ jsx("span", {
|
|
97
|
+
!$hideCloseButton && /*#__PURE__*/ jsx("span", {
|
|
80
98
|
ref: elmRef,
|
|
81
99
|
children: /*#__PURE__*/ jsx(StyledModalClose, {
|
|
82
100
|
$size: "small",
|
|
@@ -86,8 +104,14 @@ function Modal({ children, $isOpen, $onClose, $title, $width }) {
|
|
|
86
104
|
children: /*#__PURE__*/ jsx(Icon, { name: "X" })
|
|
87
105
|
})
|
|
88
106
|
}),
|
|
89
|
-
$title && /*#__PURE__*/ jsx(StyledModalTitle, {
|
|
90
|
-
|
|
107
|
+
$title && /*#__PURE__*/ jsx(StyledModalTitle, {
|
|
108
|
+
className: "modal-title",
|
|
109
|
+
children: $title
|
|
110
|
+
}),
|
|
111
|
+
/*#__PURE__*/ jsx(StyledModalContent, {
|
|
112
|
+
className: "modal-content",
|
|
113
|
+
children
|
|
114
|
+
})
|
|
91
115
|
]
|
|
92
116
|
})
|
|
93
117
|
}), document.body);
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
|
-
import { useEffect } from "react";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
4
|
//#region src/lib/utils/use-on-click-outside.tsx
|
|
5
5
|
function useOnClickOutside(refs, cb) {
|
|
6
|
+
const latest = useRef({
|
|
7
|
+
refs,
|
|
8
|
+
cb
|
|
9
|
+
});
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
latest.current = {
|
|
12
|
+
refs,
|
|
13
|
+
cb
|
|
14
|
+
};
|
|
15
|
+
});
|
|
6
16
|
useEffect(() => {
|
|
7
17
|
function handleClickOutside(event) {
|
|
8
|
-
|
|
18
|
+
const { refs, cb } = latest.current;
|
|
19
|
+
if (refs.every((ref) => !ref.current || !ref.current.contains(event.target))) cb();
|
|
9
20
|
}
|
|
10
21
|
document.addEventListener("mousedown", handleClickOutside);
|
|
11
22
|
return () => {
|
|
12
23
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
13
24
|
};
|
|
14
|
-
}, [
|
|
25
|
+
}, []);
|
|
15
26
|
}
|
|
16
27
|
//#endregion
|
|
17
28
|
export { useOnClickOutside };
|
package/package.json
CHANGED