@thecb/components 7.0.1-beta.1 → 7.0.2-beta.1
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.cjs.js +131 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.esm.js +131 -2
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/atoms/icons/ClipboardIcon.js +42 -0
- package/src/components/molecules/copyable/Copyable.js +85 -0
- package/src/components/molecules/copyable/index.d.ts +17 -0
- package/src/components/molecules/copyable/index.js +3 -0
- package/src/components/molecules/index.d.ts +2 -0
- package/src/components/molecules/index.js +1 -0
- package/src/components/molecules/modal/Modal.js +8 -3
- package/src/components/molecules/popover/Popover.js +1 -1
- package/src/components/molecules/popover/index.d.ts +26 -0
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { fallbackValues } from "./Icons.theme";
|
|
3
|
+
import { themeComponent } from "../../../util/themeUtils";
|
|
4
|
+
|
|
5
|
+
const ClipboardIcon = ({ themeValues }) => {
|
|
6
|
+
return (
|
|
7
|
+
<svg
|
|
8
|
+
width="24"
|
|
9
|
+
height="24"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
fill="none"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
>
|
|
14
|
+
<mask
|
|
15
|
+
id="mask0_1104_623"
|
|
16
|
+
style={{ maskType: "alpha" }}
|
|
17
|
+
maskUnits="userSpaceOnUse"
|
|
18
|
+
x="4"
|
|
19
|
+
y="2"
|
|
20
|
+
width="16"
|
|
21
|
+
height="18"
|
|
22
|
+
>
|
|
23
|
+
<path
|
|
24
|
+
fill-rule="evenodd"
|
|
25
|
+
clip-rule="evenodd"
|
|
26
|
+
d="M9.83929 3.43753H14.1607V5.59825H9.83929L9.83929 3.43753ZM8.75893 3.43753C8.75893 2.84087 9.24262 2.35718 9.83929 2.35718H14.1607C14.7574 2.35718 15.2411 2.84087 15.2411 3.43753V5.59825C15.2411 6.19491 14.7574 6.67861 14.1607 6.67861H9.83929C9.24262 6.67861 8.75893 6.19491 8.75893 5.59825V3.43753ZM6.59821 3.70762H7.94866V5.32816H6.59821C6.29988 5.32816 6.05804 5.57001 6.05804 5.86834V17.4822C6.05804 17.7805 6.29988 18.0224 6.59821 18.0224H17.4018C17.7001 18.0224 17.942 17.7805 17.942 17.4822V5.86834C17.942 5.57001 17.7001 5.32816 17.4018 5.32816H16.0513V3.70762H17.4018C18.5951 3.70762 19.5625 4.67501 19.5625 5.86834V17.4822C19.5625 18.6755 18.5951 19.6429 17.4018 19.6429H6.59821C5.40488 19.6429 4.4375 18.6755 4.4375 17.4822V5.86834C4.4375 4.67501 5.40488 3.70762 6.59821 3.70762Z"
|
|
27
|
+
fill={themeValues.singleIconColor}
|
|
28
|
+
/>
|
|
29
|
+
</mask>
|
|
30
|
+
<g mask="url(#mask0_1104_623)">
|
|
31
|
+
<rect width="24" height="24" fill={themeValues.singleIconColor} />
|
|
32
|
+
</g>
|
|
33
|
+
</svg>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default themeComponent(
|
|
38
|
+
ClipboardIcon,
|
|
39
|
+
"Icons",
|
|
40
|
+
fallbackValues,
|
|
41
|
+
"primary"
|
|
42
|
+
);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import ButtonWithAction from "../../atoms/button-with-action";
|
|
3
|
+
import ClipboardIcon from "../../atoms/icons/ClipboardIcon";
|
|
4
|
+
import Popover from "../popover";
|
|
5
|
+
import Stack from "../../atoms/layouts/Stack";
|
|
6
|
+
import Text from "../../atoms/text";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
This component will render `text` and a clipboard icon. When hovered, a popover with content `initialPopoverContent` will be displayed.
|
|
10
|
+
When clicked, `text` will be copied to the clipboard, the popover content will change to `copiedPopoverContent` for `copiedPopoverContentDuration` milliseconds,
|
|
11
|
+
and the `onCopy` callback will be executed.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const CopyableText = ({ text, onClick }) => {
|
|
15
|
+
return (
|
|
16
|
+
<ButtonWithAction
|
|
17
|
+
data-testid="copyable-trigger"
|
|
18
|
+
contentOverride
|
|
19
|
+
action={onClick}
|
|
20
|
+
variant="ghost"
|
|
21
|
+
extraStyles="padding: 0; margin: 0; min-height: initial; min-width: initial"
|
|
22
|
+
>
|
|
23
|
+
<Stack direction="row" childGap="0.25rem">
|
|
24
|
+
<Text>{text}</Text>
|
|
25
|
+
<ClipboardIcon />
|
|
26
|
+
</Stack>
|
|
27
|
+
</ButtonWithAction>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const Copyable = ({
|
|
32
|
+
text,
|
|
33
|
+
onCopy,
|
|
34
|
+
initialPopoverContent = "Click to copy to clipboard",
|
|
35
|
+
copiedPopoverContent = "Copied!",
|
|
36
|
+
withPopover = true,
|
|
37
|
+
popoverMinWidth = "210px",
|
|
38
|
+
copiedPopoverContentDuration = 1000,
|
|
39
|
+
popoverID = 0,
|
|
40
|
+
extraStyles
|
|
41
|
+
}) => {
|
|
42
|
+
const popoverPosition = {
|
|
43
|
+
top: "-65px",
|
|
44
|
+
right: "auto",
|
|
45
|
+
bottom: "auto",
|
|
46
|
+
left: "50%"
|
|
47
|
+
};
|
|
48
|
+
const popoverArrowPosition = {
|
|
49
|
+
arrowTop: "auto",
|
|
50
|
+
arrowRight: "auto",
|
|
51
|
+
arrowBottom: "-8px",
|
|
52
|
+
arrowLeft: "calc(50% - 4px)" // Popover arrow is 8px wide. This places the middle of the arrow in the middle of the popover.
|
|
53
|
+
};
|
|
54
|
+
const [popoverContent, setPopoverContent] = useState(initialPopoverContent);
|
|
55
|
+
const [timer, setTimer] = useState(undefined);
|
|
56
|
+
const onClick = () => {
|
|
57
|
+
setPopoverContent(copiedPopoverContent);
|
|
58
|
+
navigator.clipboard.writeText(text).catch(e => console.error(e));
|
|
59
|
+
onCopy?.();
|
|
60
|
+
if (timer) {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
setTimer(
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
setPopoverContent(initialPopoverContent);
|
|
66
|
+
setTimer(undefined);
|
|
67
|
+
}, copiedPopoverContentDuration)
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
return withPopover ? (
|
|
71
|
+
<Popover
|
|
72
|
+
minWidth={popoverMinWidth}
|
|
73
|
+
position={popoverPosition}
|
|
74
|
+
arrowPosition={popoverArrowPosition}
|
|
75
|
+
popoverID={popoverID}
|
|
76
|
+
extraStyles={`> button#btnPopover${popoverID} { margin: 0 }; #Disclosed${popoverID} { transform: translateX(-50%); }; ${extraStyles}`}
|
|
77
|
+
triggerText={CopyableText({ text, onClick })}
|
|
78
|
+
content={popoverContent}
|
|
79
|
+
></Popover>
|
|
80
|
+
) : (
|
|
81
|
+
CopyableText({ text, onClick })
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default Copyable;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Expand from "../../../util/expand";
|
|
3
|
+
|
|
4
|
+
export interface CopyableProps {
|
|
5
|
+
text: string;
|
|
6
|
+
initialPopoverContent?: string;
|
|
7
|
+
copiedPopoverContent?: string;
|
|
8
|
+
copiedPopoverContentDuration?: number;
|
|
9
|
+
withPopover?: boolean;
|
|
10
|
+
popoverID?: number;
|
|
11
|
+
popoverMinWidth?: string;
|
|
12
|
+
onCopy?: () => void;
|
|
13
|
+
extraStyles?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const Copyable: React.FC<Expand<CopyableProps> &
|
|
17
|
+
React.HTMLAttributes<HTMLElement>>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as AddressForm } from "./address-form";
|
|
2
2
|
export { default as ChangePasswordForm } from "./change-password-form";
|
|
3
3
|
export { default as CollapsibleSection } from "./collapsible-section";
|
|
4
|
+
export { default as Copyable } from "./copyable";
|
|
4
5
|
export { default as EditNameForm } from "./edit-name-form";
|
|
5
6
|
export { default as EditableList } from "./editable-list";
|
|
6
7
|
export * from "./editable-table";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { Fragment, useContext } from "react";
|
|
1
|
+
import React, { Fragment, useContext, useRef } from "react";
|
|
2
2
|
import { ThemeContext } from "styled-components";
|
|
3
3
|
import AriaModal from "react-aria-modal";
|
|
4
4
|
import { WHITE, ATHENS_GREY, SILVER_GREY } from "../../../constants/colors";
|
|
@@ -47,10 +47,15 @@ const Modal = ({
|
|
|
47
47
|
children
|
|
48
48
|
}) => {
|
|
49
49
|
const { isMobile } = useContext(ThemeContext);
|
|
50
|
+
const modalContainerRef = useRef(null);
|
|
50
51
|
return (
|
|
51
|
-
<
|
|
52
|
+
<div ref={modalContainerRef}>
|
|
52
53
|
{modalOpen && (
|
|
53
54
|
<AriaModal
|
|
55
|
+
// fallback to resolve Jest unit test errors when tabbable doesn't exist in jsdom https://github.com/focus-trap/focus-trap-react/issues/91
|
|
56
|
+
focusTrapOptions={{
|
|
57
|
+
fallbackFocus: modalContainerRef?.current
|
|
58
|
+
}}
|
|
54
59
|
onExit={onExit}
|
|
55
60
|
getApplicationNode={getApplicationNode}
|
|
56
61
|
titleText={modalHeaderText}
|
|
@@ -188,7 +193,7 @@ const Modal = ({
|
|
|
188
193
|
</AriaModal>
|
|
189
194
|
)}
|
|
190
195
|
{children}
|
|
191
|
-
</
|
|
196
|
+
</div>
|
|
192
197
|
);
|
|
193
198
|
};
|
|
194
199
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Expand from "../../../util/expand";
|
|
3
|
+
|
|
4
|
+
export interface PopoverProps {
|
|
5
|
+
triggerText?: string | JSX.Element;
|
|
6
|
+
content?: string | JSX.Element;
|
|
7
|
+
hasIcon?: boolean;
|
|
8
|
+
iconHelpText?: string; // for screen-readers, required if using an icon for trigger
|
|
9
|
+
popoverID?: number;
|
|
10
|
+
popoverFocus?: boolean;
|
|
11
|
+
extraStyles?: string;
|
|
12
|
+
textExtraStyles?: string;
|
|
13
|
+
minWidth?: string;
|
|
14
|
+
maxWidth?: string;
|
|
15
|
+
height?: string;
|
|
16
|
+
position?: { top: string; right: string; bottom: string; left: string };
|
|
17
|
+
arrowPosition?: {
|
|
18
|
+
arrowTop: string;
|
|
19
|
+
arrowRight: string;
|
|
20
|
+
arrowBottom: string;
|
|
21
|
+
arrowLeft: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const Popover: React.FC<Expand<PopoverProps> &
|
|
26
|
+
React.HTMLAttributes<HTMLElement>>;
|