UNPKG

@cerberus-design/react

Version:

The Cerberus Design React component library.

208 lines (205 loc) 8.16 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { useRef, useState, useMemo, useCallback, createContext, useContext } from 'react'; import { VStack, HStack } from 'styled-system/jsx'; import { css } from 'styled-system/css'; import { hstack } from 'styled-system/patterns'; import { FieldRoot, FieldLabel, Input } from '../components/field/primitives.js'; import { Button } from '../components/button/button.js'; import { Clipboard } from '../components/clipboard/parts.js'; import { Show } from '../components/show/show.js'; import { Avatar } from '../components/avatar/avatar.js'; import { Text } from '../components/text/text.js'; import { DialogProvider, DialogHeading, DialogDescription } from '../components/dialog/primitives.js'; import { Dialog } from '../components/dialog/dialog.js'; import { useCerberusContext } from './cerberus.js'; import { DialogCloseTrigger } from '../node_modules/.pnpm/@ark-ui_react@5.29.1_react-dom@19.2.1_react@19.2.1__react@19.2.1/node_modules/@ark-ui/react/dist/components/dialog/dialog-close-trigger.js'; import { IconButton } from '../components/icon-button/button.js'; const PromptModalContext = createContext(null); function PromptModal(props) { const resolveRef = useRef(null); const [open, setOpen] = useState(false); const [content, setContent] = useState(null); const [inputValue, setInputValue] = useState(""); const { icons } = useCerberusContext(); const { promptModal: PromptIcon } = icons; const isValid = useMemo( () => inputValue === content?.key, [inputValue, content] ); const palette = useMemo( () => content?.kind === "destructive" ? "danger" : "action", [content] ); const handleChange = useCallback((e) => { setInputValue(e.currentTarget.value); }, []); const handleChoice = useCallback( (e) => { const target = e.currentTarget; if (target.value === "true") { resolveRef.current?.(inputValue); } setOpen(false); }, [inputValue, setOpen] ); const handleShow = useCallback( (options) => { return new Promise((resolve) => { setContent({ ...options, kind: options.kind || "non-destructive" }); setOpen(true); resolveRef.current = resolve; }); }, [setOpen] ); const value = useMemo( () => ({ show: handleShow }), [handleShow] ); return /* @__PURE__ */ jsxs(PromptModalContext.Provider, { value, children: [ props.children, /* @__PURE__ */ jsx( DialogProvider, { lazyMount: true, open, onOpenChange: (e) => setOpen(e.open), unmountOnExit: true, children: /* @__PURE__ */ jsx( Dialog, { size: "sm", style: { "--dialog-content-min-h": "auto" }, children: /* @__PURE__ */ jsxs( VStack, { alignItems: "flex-start", h: "full", justify: "space-between", w: "full", children: [ /* @__PURE__ */ jsx( HStack, { alignSelf: "center", justify: "center", paddingBlockEnd: "md", w: "full", children: /* @__PURE__ */ jsx( Show, { when: palette === "danger", fallback: /* @__PURE__ */ jsx( Avatar, { gradient: "charon-light", fallback: /* @__PURE__ */ jsx(PromptIcon, { size: 24 }) } ), children: /* @__PURE__ */ jsx( Avatar, { gradient: "hades-dark", fallback: /* @__PURE__ */ jsx(PromptIcon, { size: 24 }) } ) } ) } ), /* @__PURE__ */ jsx(DialogHeading, { children: content?.heading }), /* @__PURE__ */ jsx(DialogDescription, { children: content?.description }), /* @__PURE__ */ jsx( VStack, { alignItems: "flex-start", marginBlockStart: "md", marginBlockEnd: "lg", w: "full", children: /* @__PURE__ */ jsxs(FieldRoot, { invalid: !isValid, children: [ /* @__PURE__ */ jsxs( FieldLabel, { className: hstack({ gap: "xs", justify: "flex-start", marginBlockEnd: "xs", textStyle: "label-md", w: "initial" }), children: [ "Type", /* @__PURE__ */ jsx(Clipboard.Root, { value: content?.key || "", children: /* @__PURE__ */ jsx(Clipboard.Control, { asChild: true, children: /* @__PURE__ */ jsxs(HStack, { gap: "xs", w: "full", children: [ /* @__PURE__ */ jsx(Clipboard.Label, { asChild: true, children: /* @__PURE__ */ jsx(Text, { as: "strong", userSelect: "text", children: content?.key }) }), /* @__PURE__ */ jsx(Clipboard.Trigger, { asChild: true, children: /* @__PURE__ */ jsx( IconButton, { clipboard: true, shape: "square", size: "sm", rounded: "xs", children: /* @__PURE__ */ jsx(Clipboard.Indicator, {}) } ) }) ] }) }) }), "to confirm" ] } ), /* @__PURE__ */ jsx(Input, { name: "confirm", onChange: handleChange, type: "text" }) ] }) } ), /* @__PURE__ */ jsxs(HStack, { gap: "md", justify: "stretch", w: "full", children: [ /* @__PURE__ */ jsx( Button, { autoFocus: true, className: css({ w: "1/2" }), disabled: !isValid, name: "confirm", onClick: handleChoice, palette, value: "true", children: content?.actionText } ), /* @__PURE__ */ jsx(DialogCloseTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { className: css({ w: "1/2" }), name: "cancel", onClick: handleChoice, usage: "outlined", value: "false", children: content?.cancelText } ) }) ] }) ] } ) } ) } ) ] }); } function usePromptModal() { const context = useContext(PromptModalContext); if (context === null) { throw new Error("usePromptModal must be used within a PromptModal Provider"); } return context; } export { PromptModal, usePromptModal };