Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import clsx from "clsx";
|
||||
import React, {
|
||||
cloneElement,
|
||||
FC,
|
||||
HTMLAttributes,
|
||||
ReactElement,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { Button } from "~/components/Button";
|
||||
import { ConfirmModal } from "~/components/ConfirmModal";
|
||||
import { Textarea } from "~/components/Textarea";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
interface EditorWithDialogProps extends HTMLAttributes<HTMLDivElement> {
|
||||
heading: ReactElement;
|
||||
placeholder: string;
|
||||
content: string;
|
||||
editButtonLabel: string;
|
||||
addButtonLabel: string;
|
||||
onSave?: (content: string) => void;
|
||||
extraNode?: React.ReactNode;
|
||||
saveOnBlur?: boolean;
|
||||
}
|
||||
|
||||
export const EditorWithDialog: FC<EditorWithDialogProps> = ({
|
||||
addButtonLabel,
|
||||
className,
|
||||
editButtonLabel,
|
||||
content = "",
|
||||
extraNode,
|
||||
heading,
|
||||
onSave,
|
||||
placeholder,
|
||||
saveOnBlur = true,
|
||||
...props
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const textareaInput = useRef<HTMLDivElement>(null);
|
||||
const id = uuidv4();
|
||||
const headingNode = cloneElement(heading, { className: styles.heading });
|
||||
|
||||
const handleInputBlur = (content: string): void => {
|
||||
if (saveOnBlur) {
|
||||
if (onSave) onSave(content);
|
||||
}
|
||||
};
|
||||
|
||||
const handleShowModal = () => {
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const modalHeading: string = content.trim().length
|
||||
? editButtonLabel
|
||||
: addButtonLabel;
|
||||
const buttonLabel: string = modalHeading;
|
||||
|
||||
return (
|
||||
<div className={clsx([styles.container, className])} {...props}>
|
||||
<header className={styles.header}>
|
||||
{headingNode}
|
||||
<Button onClick={handleShowModal} size="xx-small" color="builder-green">
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
</header>
|
||||
{content.trim().length > 0 && (
|
||||
<div className={styles.preview} data-testid="textarea-editor-preview">
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
<ConfirmModal
|
||||
heading={modalHeading}
|
||||
open={isOpen}
|
||||
onClose={handleCloseModal}
|
||||
onConfirm={handleCloseModal}
|
||||
data-testid="textarea-editor-modal"
|
||||
modal
|
||||
variant="confirm-only"
|
||||
confirmButtonText={"Save and Close"}
|
||||
color="builder-green"
|
||||
useMobileFullScreen
|
||||
>
|
||||
<div className={styles.content}>
|
||||
<label className={styles.title} htmlFor={id}>
|
||||
{heading}
|
||||
</label>
|
||||
<Textarea
|
||||
className={styles.textarea}
|
||||
ref={textareaInput}
|
||||
id={id}
|
||||
placeholder={placeholder}
|
||||
value={content}
|
||||
onInputKeyUp={() => {}}
|
||||
onInputBlur={handleInputBlur}
|
||||
/>
|
||||
{extraNode && <div className={styles.extra}>{extraNode}</div>}
|
||||
</div>
|
||||
</ConfirmModal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user