@tipp/ui-quill-editor 1.4.6 → 1.4.7

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.
@@ -195,35 +195,18 @@ function ReadCard(props) {
195
195
  }) })
196
196
  ] }) : null
197
197
  ] }),
198
- Boolean(files == null ? void 0 : files.length) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Flex, { direction: "column", gap: "1", children: files == null ? void 0 : files.map((file) => {
198
+ Boolean(files == null ? void 0 : files.length) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Flex, { direction: "column", gap: "2", mt: "2", width: "100%", children: files == null ? void 0 : files.map((file) => {
199
199
  var _a;
200
200
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
201
201
  import_ui.Link,
202
202
  {
203
203
  download: file.fileName,
204
204
  href: file.url,
205
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
206
- import_ui.IconButton,
207
- {
208
- mt: "3",
209
- size: "4",
210
- style: { width: "100%", height: 56 },
211
- variant: "soft",
212
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { gap: "3", pl: "4", width: "100%", children: [
213
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Typo, { color: "gray", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.FileIcon, { height: 16, width: 16 }) }),
214
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
215
- import_ui.Typo,
216
- {
217
- as: "p",
218
- color: "gray",
219
- style: { width: "100%", textAlign: "left" },
220
- variant: "caption",
221
- children: file.fileName
222
- }
223
- )
224
- ] })
225
- }
226
- )
205
+ target: "_blank",
206
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.IconButton, { style: { width: "100%" }, variant: "surface", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ui.Flex, { align: "center", gap: "2", pl: "2", width: "100%", children: [
207
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.DownloadIcon, {}),
208
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui.Typo, { children: file.fileName })
209
+ ] }) })
227
210
  },
228
211
  ((_a = file.createdAt) == null ? void 0 : _a.valueOf()) + file.fileName
229
212
  );
@@ -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} 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.ReactNode {\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=\"1\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n >\n <IconButton\n mt=\"3\"\n size=\"4\"\n style={{ width: '100%', height: 56 }}\n variant=\"soft\"\n >\n <Flex gap=\"3\" pl=\"4\" width=\"100%\">\n <Typo color=\"gray\">\n <FileIcon height={16} width={16} />\n </Typo>\n <Typo\n as=\"p\"\n color=\"gray\"\n style={{ width: '100%', textAlign: 'left' }}\n variant=\"caption\"\n >\n {file.fileName}\n </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 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"]}
@@ -10,6 +10,6 @@ interface ReadCardProps {
10
10
  createAt?: Date;
11
11
  files?: Attachment[];
12
12
  }
13
- declare function ReadCard(props: ReadCardProps): React.ReactNode;
13
+ declare function ReadCard(props: ReadCardProps): React.ReactElement;
14
14
 
15
15
  export { ReadCard };
@@ -10,6 +10,6 @@ interface ReadCardProps {
10
10
  createAt?: Date;
11
11
  files?: Attachment[];
12
12
  }
13
- declare function ReadCard(props: ReadCardProps): React.ReactNode;
13
+ declare function ReadCard(props: ReadCardProps): React.ReactElement;
14
14
 
15
15
  export { ReadCard };
package/dist/read-card.js CHANGED
@@ -9,7 +9,6 @@ import Dompurify from "dompurify";
9
9
  import {
10
10
  AlertDialog,
11
11
  Badge,
12
- FileIcon,
13
12
  Button,
14
13
  Card,
15
14
  ChevronDownIcon,
@@ -24,7 +23,8 @@ import {
24
23
  DropdownMenu,
25
24
  Pencil1Icon,
26
25
  TrashIcon,
27
- Grid
26
+ Grid,
27
+ DownloadIcon
28
28
  } from "@tipp/ui";
29
29
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
30
30
  function ReadCard(props) {
@@ -167,35 +167,18 @@ function ReadCard(props) {
167
167
  }) })
168
168
  ] }) : null
169
169
  ] }),
170
- Boolean(files == null ? void 0 : files.length) && /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "1", children: files == null ? void 0 : files.map((file) => {
170
+ Boolean(files == null ? void 0 : files.length) && /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "2", mt: "2", width: "100%", children: files == null ? void 0 : files.map((file) => {
171
171
  var _a;
172
172
  return /* @__PURE__ */ jsx(
173
173
  Link,
174
174
  {
175
175
  download: file.fileName,
176
176
  href: file.url,
177
- children: /* @__PURE__ */ jsx(
178
- IconButton,
179
- {
180
- mt: "3",
181
- size: "4",
182
- style: { width: "100%", height: 56 },
183
- variant: "soft",
184
- children: /* @__PURE__ */ jsxs(Flex, { gap: "3", pl: "4", width: "100%", children: [
185
- /* @__PURE__ */ jsx(Typo, { color: "gray", children: /* @__PURE__ */ jsx(FileIcon, { height: 16, width: 16 }) }),
186
- /* @__PURE__ */ jsx(
187
- Typo,
188
- {
189
- as: "p",
190
- color: "gray",
191
- style: { width: "100%", textAlign: "left" },
192
- variant: "caption",
193
- children: file.fileName
194
- }
195
- )
196
- ] })
197
- }
198
- )
177
+ target: "_blank",
178
+ children: /* @__PURE__ */ jsx(IconButton, { style: { width: "100%" }, variant: "surface", children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", pl: "2", width: "100%", children: [
179
+ /* @__PURE__ */ jsx(DownloadIcon, {}),
180
+ /* @__PURE__ */ jsx(Typo, { children: file.fileName })
181
+ ] }) })
199
182
  },
200
183
  ((_a = file.createdAt) == null ? void 0 : _a.valueOf()) + file.fileName
201
184
  );
@@ -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} 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.ReactNode {\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=\"1\">\n {files?.map((file) => {\n return (\n <Link\n download={file.fileName}\n href={file.url}\n key={file.createdAt?.valueOf() + file.fileName}\n >\n <IconButton\n mt=\"3\"\n size=\"4\"\n style={{ width: '100%', height: 56 }}\n variant=\"soft\"\n >\n <Flex gap=\"3\" pl=\"4\" width=\"100%\">\n <Typo color=\"gray\">\n <FileIcon height={16} width={16} />\n </Typo>\n <Typo\n as=\"p\"\n color=\"gray\"\n style={{ width: '100%', textAlign: 'left' }}\n variant=\"caption\"\n >\n {file.fileName}\n </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":[]}
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":"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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.6",
3
+ "version": "1.4.7",
4
4
  "private": false,
5
5
  "description": "tipp 디자인 시스템이 적용된 quillEditor 패키지, quillEditor의 사이즈가 커서 별도 패키지로 분리했습니다.",
6
6
  "sideEffects": false,
@@ -40,7 +40,7 @@
40
40
  "react": "^18.3.1",
41
41
  "react-dom": "^18.3.1",
42
42
  "react-quill": "^2.0.0",
43
- "@tipp/ui": "1.5.6"
43
+ "@tipp/ui": "1.5.7"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/dompurify": "^3.0.5",
package/src/read-card.tsx CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  Pencil1Icon,
20
20
  TrashIcon,
21
21
  Grid,
22
+ DownloadIcon,
22
23
  } from '@tipp/ui';
23
24
  import QuillHtmlOutputContainer from './html-container';
24
25
  import type { Attachment } from './type';
@@ -33,7 +34,7 @@ interface ReadCardProps {
33
34
  files?: Attachment[];
34
35
  }
35
36
 
36
- export function ReadCard(props: ReadCardProps): React.ReactNode {
37
+ export function ReadCard(props: ReadCardProps): React.ReactElement {
37
38
  const {
38
39
  onClickDelete: propsOnClickDelete,
39
40
  onClickEdit: propsOnClickEdit,
@@ -200,32 +201,19 @@ export function ReadCard(props: ReadCardProps): React.ReactNode {
200
201
  </Grid>
201
202
 
202
203
  {Boolean(files?.length) && (
203
- <Flex direction="column" gap="1">
204
+ <Flex direction="column" gap="2" mt="2" width="100%">
204
205
  {files?.map((file) => {
205
206
  return (
206
207
  <Link
207
208
  download={file.fileName}
208
209
  href={file.url}
209
210
  key={file.createdAt?.valueOf() + file.fileName}
211
+ target="_blank"
210
212
  >
211
- <IconButton
212
- mt="3"
213
- size="4"
214
- style={{ width: '100%', height: 56 }}
215
- variant="soft"
216
- >
217
- <Flex gap="3" pl="4" width="100%">
218
- <Typo color="gray">
219
- <FileIcon height={16} width={16} />
220
- </Typo>
221
- <Typo
222
- as="p"
223
- color="gray"
224
- style={{ width: '100%', textAlign: 'left' }}
225
- variant="caption"
226
- >
227
- {file.fileName}
228
- </Typo>
213
+ <IconButton style={{ width: '100%' }} variant="surface">
214
+ <Flex align="center" gap="2" pl="2" width="100%">
215
+ <DownloadIcon />
216
+ <Typo>{file.fileName}</Typo>
229
217
  </Flex>
230
218
  </IconButton>
231
219
  </Link>