@tipp/ui-quill-editor 1.4.7 → 1.4.8

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.
@@ -114,7 +114,7 @@ function ReadCard(props) {
114
114
  size: "small",
115
115
  variant: "outline",
116
116
  children: [
117
- "\uBA54\uBAA8 \uD3BC\uCE58\uAE30",
117
+ "\uD3BC\uCE58\uAE30",
118
118
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.ChevronDownIcon, {})
119
119
  ]
120
120
  }
@@ -127,9 +127,10 @@ function ReadCard(props) {
127
127
  onClick: () => {
128
128
  setClassName("closed");
129
129
  },
130
+ size: "small",
130
131
  variant: "outline",
131
132
  children: [
132
- "\uBA54\uBAA8 \uC811\uAE30",
133
+ "\uC811\uAE30",
133
134
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.ChevronUpIcon, {})
134
135
  ]
135
136
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/read-card.tsx","../src/html-container.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n FileIcon,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n Grid,\n DownloadIcon,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactElement {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 메모 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n variant=\"outline\"\n >\n 메모 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Grid columns=\"1fr auto\" width=\"100%\">\n <Grid\n align=\"center\"\n columns={{ initial: '1', sm: 'auto 1fr' }}\n gap=\"2\"\n width=\"100%\"\n >\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n\n <Flex\n align=\"center\"\n gap=\"4\"\n justify={{ initial: 'start', sm: 'between' }}\n width=\"100%\"\n >\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n {createAt ? (\n <Typo\n style={{ whiteSpace: 'nowrap' }}\n >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Grid>\n\n {/* ... 옵션 버튼 */}\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton ml=\"2\" mt=\"1\" variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Grid>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"2\" mt=\"2\" width=\"100%\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n target=\"_blank\"\n >\n <IconButton style={{ width: '100%' }} variant=\"surface\">\n <Flex align=\"center\" gap=\"2\" pl=\"2\" width=\"100%\">\n <DownloadIcon />\n <Typo>{file.fileName}</Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n","import React, { forwardRef } from 'react';\n\ninterface QuillHtmlOutputContainerProps {\n html: string;\n className?: string;\n}\n\nconst QuillHtmlOutputContainer = forwardRef<\n HTMLDivElement,\n QuillHtmlOutputContainerProps\n>(({ html, className }, ref): React.ReactNode => {\n return (\n <div className=\"ql-snow ql-container read-mode\">\n <div\n className={`ql-editor ${className || ''}`}\n dangerouslySetInnerHTML={{ __html: html }}\n ref={ref}\n />\n </div>\n );\n});\n\nQuillHtmlOutputContainer.displayName = 'QuillHtmlOutputContainer';\n\nexport default QuillHtmlOutputContainer;\n"],"mappings":"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","names":["import_react","import_jsx_runtime","Dompurify"]}
1
+ {"version":3,"sources":["../src/read-card.tsx","../src/html-container.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n Grid,\n DownloadIcon,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactElement {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Grid columns=\"1fr auto\" width=\"100%\">\n <Grid\n align=\"center\"\n columns={{ initial: '1', sm: 'auto 1fr' }}\n gap=\"2\"\n width=\"100%\"\n >\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n\n <Flex\n align=\"center\"\n gap=\"4\"\n justify={{ initial: 'start', sm: 'between' }}\n width=\"100%\"\n >\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n {createAt ? (\n <Typo\n style={{ whiteSpace: 'nowrap' }}\n >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Grid>\n\n {/* ... 옵션 버튼 */}\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton ml=\"2\" mt=\"1\" variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Grid>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"2\" mt=\"2\" width=\"100%\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n target=\"_blank\"\n >\n <IconButton style={{ width: '100%' }} variant=\"surface\">\n <Flex align=\"center\" gap=\"2\" pl=\"2\" width=\"100%\">\n <DownloadIcon />\n <Typo>{file.fileName}</Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n","import React, { forwardRef } from 'react';\n\ninterface QuillHtmlOutputContainerProps {\n html: string;\n className?: string;\n}\n\nconst QuillHtmlOutputContainer = forwardRef<\n HTMLDivElement,\n QuillHtmlOutputContainerProps\n>(({ html, className }, ref): React.ReactNode => {\n return (\n <div className=\"ql-snow ql-container read-mode\">\n <div\n className={`ql-editor ${className || ''}`}\n dangerouslySetInnerHTML={{ __html: html }}\n ref={ref}\n />\n </div>\n );\n});\n\nQuillHtmlOutputContainer.displayName = 'QuillHtmlOutputContainer';\n\nexport default QuillHtmlOutputContainer;\n"],"mappings":"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","names":["import_react","import_jsx_runtime","Dompurify"]}
package/dist/read-card.js CHANGED
@@ -86,7 +86,7 @@ function ReadCard(props) {
86
86
  size: "small",
87
87
  variant: "outline",
88
88
  children: [
89
- "\uBA54\uBAA8 \uD3BC\uCE58\uAE30",
89
+ "\uD3BC\uCE58\uAE30",
90
90
  /* @__PURE__ */ jsx(ChevronDownIcon, {})
91
91
  ]
92
92
  }
@@ -99,9 +99,10 @@ function ReadCard(props) {
99
99
  onClick: () => {
100
100
  setClassName("closed");
101
101
  },
102
+ size: "small",
102
103
  variant: "outline",
103
104
  children: [
104
- "\uBA54\uBAA8 \uC811\uAE30",
105
+ "\uC811\uAE30",
105
106
  /* @__PURE__ */ jsx(ChevronUpIcon, {})
106
107
  ]
107
108
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/read-card.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n FileIcon,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n Grid,\n DownloadIcon,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactElement {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 메모 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n variant=\"outline\"\n >\n 메모 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Grid columns=\"1fr auto\" width=\"100%\">\n <Grid\n align=\"center\"\n columns={{ initial: '1', sm: 'auto 1fr' }}\n gap=\"2\"\n width=\"100%\"\n >\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n\n <Flex\n align=\"center\"\n gap=\"4\"\n justify={{ initial: 'start', sm: 'between' }}\n width=\"100%\"\n >\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n {createAt ? (\n <Typo\n style={{ whiteSpace: 'nowrap' }}\n >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Grid>\n\n {/* ... 옵션 버튼 */}\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton ml=\"2\" mt=\"1\" variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Grid>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"2\" mt=\"2\" width=\"100%\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n target=\"_blank\"\n >\n <IconButton style={{ width: '100%' }} variant=\"surface\">\n <Flex align=\"center\" gap=\"2\" pl=\"2\" width=\"100%\">\n <DownloadIcon />\n <Typo>{file.fileName}</Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n"],"mappings":";;;;;;AAAA,SAAgB,WAAW,SAAS,QAAQ,gBAAgB;AAC5D,OAAO,eAAe;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAyCO,SAkKN,UAlKM,KA+BJ,YA/BI;AA3BP,SAAS,SAAS,OAA0C;AACjE,QAAM;AAAA,IACJ,eAAe;AAAA,IACf,aAAa;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,MAAM,OAAuB,IAAI;AACvC,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,KAAK;AAE9D,QAAM,cAAc,QAAQ,MAAM;AAChC,WAAO,UAAU,SAAS,WAAW,EAAE;AAAA,EACzC,GAAG,CAAC,OAAO,CAAC;AAOZ,QAAM,cAAc,QAAsB,MAAM;AAC9C,UAAM,SAAuB,CAAC;AAC9B,QAAI,kBAAkB;AACpB,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,MAAM,oBAAC,eAAY;AAAA,QACnB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,QAAI,oBAAoB;AACtB,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,SAAS,MAAM;AACb,8BAAoB,IAAI;AAAA,QAC1B;AAAA,QACA,MAAM,oBAAC,aAAU;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,oBAAoB,gBAAgB,CAAC;AAEzC,QAAM,CAAC,WAAW,YAAY,IAAI,SAA+B,QAAQ;AACzE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAE1D,YAAU,MAAM;AACd,QAAI,CAAC,IAAI;AAAS;AAClB,sBAAkB,IAAI,QAAQ,eAAe,IAAI,QAAQ,YAAY;AACrE,QAAI,QAAQ,MAAM,SAAS,GAAG,IAAI,QAAQ,YAAY;AAAA,EACxD,GAAG,CAAC,KAAK,OAAO,CAAC;AAEjB,QAAM,iBAAiB,MAAuB;AAC5C,QAAI,gBAAgB;AAClB,UAAI,WAAW;AACb,eACE;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,SAAS,MAAM;AACb,2BAAa,MAAS;AACtB,kBAAI,IAAI,SAAS;AACf,oBAAI,QAAQ,MAAM,SAAS;AAAA,cAC7B;AAAA,YACF;AAAA,YACA,MAAK;AAAA,YACL,SAAQ;AAAA,YACT;AAAA;AAAA,cAEC,oBAAC,mBAAgB;AAAA;AAAA;AAAA,QACnB;AAAA,MAEJ;AACA,aACE;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,SAAS,MAAM;AACb,yBAAa,QAAQ;AAAA,UACvB;AAAA,UACA,SAAQ;AAAA,UACT;AAAA;AAAA,YAEC,oBAAC,iBAAc;AAAA;AAAA;AAAA,MACjB;AAAA,IAEJ;AACA,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,QAAK,MAAK,KACT;AAAA,yBAAC,QAAK,SAAQ,YAAW,OAAM,QAC7B;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,SAAS,EAAE,SAAS,KAAK,IAAI,WAAW;AAAA,UACxC,KAAI;AAAA,UACJ,OAAM;AAAA,UAEN;AAAA,gCAAC,WAAQ,SAAQ,YAAW,QAAO,WAChC,iBACH;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,KAAI;AAAA,gBACJ,SAAS,EAAE,SAAS,SAAS,IAAI,UAAU;AAAA,gBAC3C,OAAM;AAAA,gBAEL;AAAA,2BACC,oBAAC,SAAM,OAAM,WAAU,MAAK,SAAS,kCAAS,MAAM,IAAG,IACrD;AAAA,kBACH,WACC;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,EAAE,YAAY,SAAS;AAAA,sBAC9B,0BAAM,SAAS,YAAY,CAAC,IAAI,SAAS,SAAS,IAAI,CAAC,IAAI,SAAS,QAAQ,CAAC;AAAA;AAAA,kBAAI,IACjF;AAAA;AAAA;AAAA,YACN;AAAA,YAEA;AAAA,cAAC,YAAY;AAAA,cAAZ;AAAA,gBACC,cAAc;AAAA,gBACd,MAAM;AAAA,gBAEN,+BAAC,YAAY,SAAZ,EACC;AAAA,sCAAC,YAAY,OAAZ,EAAkB,kFAAa;AAAA,kBAChC,oBAAC,YAAY,aAAZ,EAAwB,yJAEzB;AAAA,kBACA,qBAAC,QAAK,KAAI,KAAI,SAAQ,OACpB;AAAA,wCAAC,YAAY,QAAZ,EACC,8BAAC,UAAO,OAAM,QAAO,SAAQ,WAAU,0BAEvC,GACF;AAAA,oBACA,oBAAC,YAAY,QAAZ,EACC,8BAAC,UAAO,OAAM,UAAS,SAAS,oBAAoB,0BAEpD,GACF;AAAA,qBACF;AAAA,mBACF;AAAA;AAAA,YACF;AAAA;AAAA;AAAA,MACF;AAAA,MAGC,YAAY,SACX,qBAAC,aAAa,MAAb,EACC;AAAA,4BAAC,aAAa,SAAb,EACC,8BAAC,cAAW,IAAG,KAAI,IAAG,KAAI,SAAQ,SAChC,8BAAC,oBAAiB,GACpB,GACF;AAAA,QACA,oBAAC,aAAa,SAAb,EACE,sBAAY,IAAI,CAAC,SAAS;AACzB,iBACE,qBAAC,aAAa,MAAb,EAAmC,SAAS,KAAK,SAC/C;AAAA,iBAAK;AAAA,YACL,KAAK;AAAA,eAFgB,KAAK,KAG7B;AAAA,QAEJ,CAAC,GACH;AAAA,SACF,IACE;AAAA,OACN;AAAA,IAEC,QAAQ,+BAAO,MAAM,KACpB,oBAAC,QAAK,WAAU,UAAS,KAAI,KAAI,IAAG,KAAI,OAAM,QAC3C,yCAAO,IAAI,CAAC,SAAS;AA5MhC;AA6MY,aACE;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,KAAK;AAAA,UACf,MAAM,KAAK;AAAA,UAEX,QAAO;AAAA,UAEP,8BAAC,cAAW,OAAO,EAAE,OAAO,OAAO,GAAG,SAAQ,WAC5C,+BAAC,QAAK,OAAM,UAAS,KAAI,KAAI,IAAG,KAAI,OAAM,QACxC;AAAA,gCAAC,gBAAa;AAAA,YACd,oBAAC,QAAM,eAAK,UAAS;AAAA,aACvB,GACF;AAAA;AAAA,UARK,UAAK,cAAL,mBAAgB,aAAY,KAAK;AAAA,MASxC;AAAA,IAEJ,IACF;AAAA,IAGD,UACC,iCACE;AAAA,0BAAC,aAAU,IAAG,KAAI,IAAG,KAAI,OAAO,EAAE,OAAO,OAAO,GAAG;AAAA,MAEnD,qBAAC,QAAK,OAAM,UAAS,WAAU,UAAS,KAAI,KAC1C;AAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,MAAM;AAAA,YACN;AAAA;AAAA,QACF;AAAA,QACC,eAAe;AAAA,SAClB;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/read-card.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Dompurify from 'dompurify';\nimport {\n AlertDialog,\n Badge,\n Button,\n Card,\n ChevronDownIcon,\n ChevronUpIcon,\n DotsVerticalIcon,\n Flex,\n Heading,\n IconButton,\n Link,\n Typo,\n Separator,\n DropdownMenu,\n Pencil1Icon,\n TrashIcon,\n Grid,\n DownloadIcon,\n} from '@tipp/ui';\nimport QuillHtmlOutputContainer from './html-container';\nimport type { Attachment } from './type';\n\ninterface ReadCardProps {\n onClickDelete?: () => void;\n onClickEdit?: () => void;\n content?: string;\n title?: string;\n writer?: string;\n createAt?: Date;\n files?: Attachment[];\n}\n\nexport function ReadCard(props: ReadCardProps): React.ReactElement {\n const {\n onClickDelete: propsOnClickDelete,\n onClickEdit: propsOnClickEdit,\n content = '',\n title = '',\n writer,\n createAt,\n files,\n } = props;\n const ref = useRef<HTMLDivElement>(null);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\n const safeContent = useMemo(() => {\n return Dompurify.sanitize(content || '');\n }, [content]);\n\n interface OptionItem {\n title: string;\n icon: React.ReactNode;\n onClick: () => void;\n }\n const optionItems = useMemo<OptionItem[]>(() => {\n const result: OptionItem[] = [];\n if (propsOnClickEdit) {\n result.push({\n title: '수정하기',\n icon: <Pencil1Icon />,\n onClick: propsOnClickEdit,\n });\n }\n\n if (propsOnClickDelete) {\n result.push({\n title: '삭제하기',\n onClick: () => {\n setDeleteDialogOpen(true);\n },\n icon: <TrashIcon />,\n });\n }\n\n return result;\n }, [propsOnClickDelete, propsOnClickEdit]);\n\n const [className, setClassName] = useState<undefined | 'closed'>('closed');\n const [openBtnVisible, setOpenBtnVisible] = useState(false);\n\n useEffect(() => {\n if (!ref.current) return;\n setOpenBtnVisible(ref.current.clientHeight < ref.current.scrollHeight);\n ref.current.style.height = `${ref.current.clientHeight}px`;\n }, [ref, content]);\n\n const renderOpenBtns = (): React.ReactNode => {\n if (openBtnVisible) {\n if (className) {\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName(undefined);\n if (ref.current) {\n ref.current.style.height = 'initial';\n }\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 펼치기\n <ChevronDownIcon />\n </Button>\n );\n }\n return (\n <Button\n color=\"gray\"\n onClick={() => {\n setClassName('closed');\n }}\n size=\"small\"\n variant=\"outline\"\n >\n 접기\n <ChevronUpIcon />\n </Button>\n );\n }\n return null;\n };\n\n return (\n <Card size=\"2\">\n <Grid columns=\"1fr auto\" width=\"100%\">\n <Grid\n align=\"center\"\n columns={{ initial: '1', sm: 'auto 1fr' }}\n gap=\"2\"\n width=\"100%\"\n >\n <Heading variant=\"heading5\" weight=\"regular\">\n {title}\n </Heading>\n\n <Flex\n align=\"center\"\n gap=\"4\"\n justify={{ initial: 'start', sm: 'between' }}\n width=\"100%\"\n >\n {writer ? (\n <Badge color=\"neutral\" size=\"small\">{`작성자 : ${writer}`}</Badge>\n ) : null}\n {createAt ? (\n <Typo\n style={{ whiteSpace: 'nowrap' }}\n >{`등록 ${createAt.getFullYear()}.${createAt.getMonth() + 1}.${createAt.getDate()} `}</Typo>\n ) : null}\n </Flex>\n\n <AlertDialog.Root\n onOpenChange={setDeleteDialogOpen}\n open={deleteDialogOpen}\n >\n <AlertDialog.Content>\n <AlertDialog.Title>노트를 삭제하시겠습니까?</AlertDialog.Title>\n <AlertDialog.Description>\n 삭제된 노트는 복구할 수 없습니다. 삭제하시겠습니까?\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\">\n <AlertDialog.Cancel>\n <Button color=\"gray\" variant=\"outline\">\n 취소\n </Button>\n </AlertDialog.Cancel>\n <AlertDialog.Action>\n <Button color=\"tomato\" onClick={propsOnClickDelete}>\n 삭제\n </Button>\n </AlertDialog.Action>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n </Grid>\n\n {/* ... 옵션 버튼 */}\n {optionItems.length ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton ml=\"2\" mt=\"1\" variant=\"ghost\">\n <DotsVerticalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n {optionItems.map((item) => {\n return (\n <DropdownMenu.Item key={item.title} onClick={item.onClick}>\n {item.icon}\n {item.title}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n </Grid>\n\n {Boolean(files?.length) && (\n <Flex direction=\"column\" gap=\"2\" mt=\"2\" width=\"100%\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n target=\"_blank\"\n >\n <IconButton style={{ width: '100%' }} variant=\"surface\">\n <Flex align=\"center\" gap=\"2\" pl=\"2\" width=\"100%\">\n <DownloadIcon />\n <Typo>{file.fileName}</Typo>\n </Flex>\n </IconButton>\n </Link>\n );\n })}\n </Flex>\n )}\n\n {content ? (\n <>\n <Separator mb=\"4\" mt=\"4\" style={{ width: '100%' }} />\n\n <Flex align=\"center\" direction=\"column\" gap=\"3\">\n <QuillHtmlOutputContainer\n className={className}\n html={safeContent}\n ref={ref}\n />\n {renderOpenBtns()}\n </Flex>\n </>\n ) : null}\n </Card>\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tipp/ui-quill-editor",
3
- "version": "1.4.7",
3
+ "version": "1.4.8",
4
4
  "private": false,
5
5
  "description": "tipp 디자인 시스템이 적용된 quillEditor 패키지, quillEditor의 사이즈가 커서 별도 패키지로 분리했습니다.",
6
6
  "sideEffects": false,
@@ -58,8 +58,8 @@
58
58
  "postcss-nesting": "12.0.2",
59
59
  "tsup": "^8.0.2",
60
60
  "typescript": "^5.3.3",
61
- "@tipp/typescript-config": "1.0.1",
62
- "@tipp/eslint-config": "1.0.1"
61
+ "@tipp/eslint-config": "1.0.1",
62
+ "@tipp/typescript-config": "1.0.1"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "pnpm run build:js && pnpm run build:css",
package/src/read-card.tsx CHANGED
@@ -3,7 +3,6 @@ import Dompurify from 'dompurify';
3
3
  import {
4
4
  AlertDialog,
5
5
  Badge,
6
- FileIcon,
7
6
  Button,
8
7
  Card,
9
8
  ChevronDownIcon,
@@ -103,7 +102,7 @@ export function ReadCard(props: ReadCardProps): React.ReactElement {
103
102
  size="small"
104
103
  variant="outline"
105
104
  >
106
- 메모 펼치기
105
+ 펼치기
107
106
  <ChevronDownIcon />
108
107
  </Button>
109
108
  );
@@ -114,9 +113,10 @@ export function ReadCard(props: ReadCardProps): React.ReactElement {
114
113
  onClick={() => {
115
114
  setClassName('closed');
116
115
  }}
116
+ size="small"
117
117
  variant="outline"
118
118
  >
119
- 메모 접기
119
+ 접기
120
120
  <ChevronUpIcon />
121
121
  </Button>
122
122
  );