@lumir-company/editor 0.4.11 → 0.4.13
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/README.md +1511 -1511
- package/dist/api/link-preview.js.map +1 -1
- package/dist/api/link-preview.mjs.map +1 -1
- package/dist/index.js +473 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +482 -51
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +40 -4
- package/package.json +94 -93
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/LumirEditor.tsx","../src/utils/cn.ts","../src/utils/s3-uploader.ts","../src/blocks/HtmlPreview.tsx","../src/blocks/LinkPreview.tsx","../src/blocks/defaultLogo.ts","../src/blocks/VideoBlock.tsx","../src/components/FloatingMenu/index.tsx","../src/components/FloatingMenu/Icons.tsx","../src/components/FloatingMenu/components/ToolbarDivider.tsx","../src/components/FloatingMenu/components/UndoRedoButtons.tsx","../src/components/FloatingMenu/components/TextStyleButton.tsx","../src/components/FloatingMenu/components/AlignButton.tsx","../src/components/FloatingMenu/components/ListButton.tsx","../src/components/FloatingMenu/components/ImageButton.tsx","../src/components/FloatingMenu/components/ColorButton.tsx","../src/constants/colors.ts","../src/components/FloatingMenu/components/LinkButton.tsx","../src/components/FloatingMenu/components/TableButton.tsx","../src/components/FloatingMenu/components/HTMLImportButton.tsx","../src/components/FloatingMenu/components/BlockTypeSelect.tsx","../src/errors/LumirEditorError.ts","../src/constants/limits.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { useEffect, useMemo, useCallback, useState, useRef } from \"react\";\r\nimport {\r\n useCreateBlockNote,\r\n SideMenu as BlockSideMenu,\r\n SideMenuController,\r\n DragHandleButton,\r\n SuggestionMenuController,\r\n getDefaultReactSlashMenuItems,\r\n LinkToolbarController,\r\n useBlockNoteEditor,\r\n useComponentsContext,\r\n EditLinkButton,\r\n OpenLinkButton,\r\n DeleteLinkButton,\r\n} from \"@blocknote/react\";\r\nimport { BlockNoteView } from \"@blocknote/mantine\";\r\nimport { insertOrUpdateBlock } from \"@blocknote/core\";\r\nimport { cn } from \"../utils/cn\";\r\n\r\nimport type { DefaultPartialBlock, LumirEditorProps } from \"../types\";\r\n\r\nimport { createS3Uploader } from \"../utils/s3-uploader\";\r\nimport { schema } from \"../blocks/HtmlPreview\";\r\nimport { FloatingMenu } from \"./FloatingMenu\";\r\nimport { LumirEditorError } from \"../errors/LumirEditorError\";\r\nimport {\r\n MAX_FILE_SIZE,\r\n MAX_VIDEO_FILE_SIZE,\r\n BLOCKED_EXTENSIONS,\r\n ALLOWED_VIDEO_MIME_TYPES,\r\n ALLOWED_VIDEO_EXTENSIONS,\r\n} from \"../constants/limits\";\r\n\r\n// #region agent log\r\nconst DEBUG_LOG = (loc: string, msg: string, data: Record<string, unknown>) => {\r\n const p = fetch(\"http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a\", {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\", \"X-Debug-Session-Id\": \"b73262\" },\r\n body: JSON.stringify({\r\n sessionId: \"b73262\",\r\n location: loc,\r\n message: msg,\r\n data,\r\n timestamp: Date.now(),\r\n }),\r\n });\r\n if (p && typeof (p as Promise<unknown>).catch === \"function\") (p as Promise<unknown>).catch(() => {});\r\n};\r\n// #endregion\r\n\r\n// ==========================================\r\n// 유틸리티 클래스들\r\n// ==========================================\r\n\r\n/**\r\n * 콘텐츠 관리 유틸리티\r\n * 기본 블록 생성 및 콘텐츠 검증 로직을 담당\r\n */\r\nexport class ContentUtils {\r\n /**\r\n * JSON 문자열의 유효성을 검증합니다\r\n * @param jsonString 검증할 JSON 문자열\r\n * @returns 유효한 JSON 문자열인지 여부\r\n */\r\n static isValidJSONString(jsonString: string): boolean {\r\n try {\r\n const parsed = JSON.parse(jsonString);\r\n return Array.isArray(parsed);\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * JSON 문자열을 DefaultPartialBlock 배열로 파싱합니다\r\n * @param jsonString JSON 문자열\r\n * @returns 파싱된 블록 배열 또는 null (파싱 실패 시)\r\n */\r\n static parseJSONContent(jsonString: string): DefaultPartialBlock[] | null {\r\n try {\r\n const parsed = JSON.parse(jsonString);\r\n if (Array.isArray(parsed)) {\r\n return parsed as DefaultPartialBlock[];\r\n }\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * 기본 paragraph 블록 생성\r\n * @returns 기본 설정이 적용된 DefaultPartialBlock\r\n */\r\n static createDefaultBlock(): DefaultPartialBlock {\r\n return {\r\n type: \"paragraph\",\r\n props: {\r\n textColor: \"default\",\r\n backgroundColor: \"default\",\r\n textAlignment: \"left\",\r\n },\r\n content: [{ type: \"text\", text: \"\", styles: {} }],\r\n children: [],\r\n };\r\n }\r\n\r\n /**\r\n * 콘텐츠 유효성 검증 및 기본값 설정\r\n * @param content 사용자 제공 콘텐츠 (객체 배열 또는 JSON 문자열)\r\n * @param emptyBlockCount 빈 블록 개수 (기본값: 3)\r\n * @returns 검증된 콘텐츠 배열\r\n */\r\n static validateContent(\r\n content?: DefaultPartialBlock[] | string,\r\n emptyBlockCount: number = 3\r\n ): DefaultPartialBlock[] {\r\n // 1. 문자열인 경우 JSON 파싱 시도\r\n if (typeof content === \"string\") {\r\n if (content.trim() === \"\") {\r\n return this.createEmptyBlocks(emptyBlockCount);\r\n }\r\n\r\n const parsedContent = this.parseJSONContent(content);\r\n if (parsedContent && parsedContent.length > 0) {\r\n return parsedContent;\r\n }\r\n\r\n // 파싱 실패 시 빈 블록 생성\r\n return this.createEmptyBlocks(emptyBlockCount);\r\n }\r\n\r\n // 2. 배열인 경우 기존 로직\r\n if (!content || content.length === 0) {\r\n return this.createEmptyBlocks(emptyBlockCount);\r\n }\r\n\r\n return content;\r\n }\r\n\r\n /**\r\n * 빈 블록들을 생성합니다\r\n * @param emptyBlockCount 생성할 블록 개수\r\n * @returns 생성된 빈 블록 배열\r\n */\r\n private static createEmptyBlocks(\r\n emptyBlockCount: number\r\n ): DefaultPartialBlock[] {\r\n return Array.from({ length: emptyBlockCount }, () =>\r\n this.createDefaultBlock()\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 에디터 설정 관리 유틸리티\r\n * 각종 설정의 기본값과 검증 로직을 담당\r\n */\r\nexport class EditorConfig {\r\n /**\r\n * 테이블 설정 기본값 적용\r\n * @param userTables 사용자 테이블 설정\r\n * @returns 기본값이 적용된 테이블 설정\r\n */\r\n static getDefaultTableConfig(userTables?: LumirEditorProps[\"tables\"]) {\r\n return {\r\n splitCells: userTables?.splitCells ?? true,\r\n cellBackgroundColor: userTables?.cellBackgroundColor ?? true,\r\n cellTextColor: userTables?.cellTextColor ?? true,\r\n headers: userTables?.headers ?? true,\r\n };\r\n }\r\n\r\n /**\r\n * 헤딩 설정 기본값 적용\r\n * @param userHeading 사용자 헤딩 설정\r\n * @returns 기본값이 적용된 헤딩 설정\r\n */\r\n static getDefaultHeadingConfig(userHeading?: LumirEditorProps[\"heading\"]) {\r\n return userHeading?.levels && userHeading.levels.length > 0\r\n ? userHeading\r\n : { levels: [1, 2, 3, 4, 5, 6] as (1 | 2 | 3 | 4 | 5 | 6)[] };\r\n }\r\n\r\n /**\r\n * 비활성화할 확장 기능 목록 생성\r\n * @param userExtensions 사용자 정의 비활성 확장\r\n * @param allowVideo 비디오 업로드 허용 여부\r\n * @param allowAudio 오디오 업로드 허용 여부\r\n * @param allowFile 일반 파일 업로드 허용 여부\r\n * @returns 비활성화할 확장 기능 목록\r\n */\r\n static getDisabledExtensions(\r\n userExtensions?: string[],\r\n allowVideo = false,\r\n allowAudio = false,\r\n allowFile = false\r\n ): string[] {\r\n const set = new Set<string>(userExtensions ?? []);\r\n if (!allowVideo) set.add(\"video\");\r\n if (!allowAudio) set.add(\"audio\");\r\n if (!allowFile) set.add(\"file\");\r\n return Array.from(set);\r\n }\r\n}\r\n\r\n// 파일 타입 검증 함수\r\n/** @internal 테스트용 export */\r\nexport const isImageFile = (file: File, maxSize?: number): boolean => {\r\n const limit = maxSize !== undefined ? maxSize : MAX_FILE_SIZE;\r\n if (file.size === 0 || file.size > limit) {\r\n return false;\r\n }\r\n\r\n // 🔒 보안: SVG 파일 차단 (XSS 방지)\r\n const fileName = file.name?.toLowerCase() || \"\";\r\n if (\r\n file.type === \"image/svg+xml\" ||\r\n BLOCKED_EXTENSIONS.some((ext) => fileName.endsWith(ext))\r\n ) {\r\n return false;\r\n }\r\n\r\n // 이미지 타입 검증\r\n return (\r\n file.type?.startsWith(\"image/\") ||\r\n (!file.type && /\\.(png|jpe?g|gif|webp|bmp)$/i.test(fileName))\r\n );\r\n};\r\n\r\n/** @internal 테스트용 export */\r\nexport const isVideoFile = (file: File, maxSize?: number): boolean => {\r\n const limit = maxSize !== undefined ? maxSize : MAX_VIDEO_FILE_SIZE;\r\n const sizeOk = file.size > 0 && file.size <= limit;\r\n const fileName = file.name?.toLowerCase() || \"\";\r\n const mimeMatch = ALLOWED_VIDEO_MIME_TYPES.has(file.type);\r\n const videoPrefix = typeof file.type === \"string\" && file.type.startsWith(\"video/\");\r\n const extMatch = !file.type && ALLOWED_VIDEO_EXTENSIONS.some((ext) => fileName.endsWith(ext));\r\n const result = sizeOk && (mimeMatch || videoPrefix || extMatch);\r\n // #region agent log\r\n DEBUG_LOG(\"isVideoFile:check\", \"result\", {\r\n fileName: file.name,\r\n fileType: file.type,\r\n fileSize: file.size,\r\n sizeOk,\r\n mimeMatch,\r\n videoPrefix,\r\n extMatch,\r\n result,\r\n });\r\n // #endregion\r\n return result;\r\n};\r\n\r\n/** @internal 테스트용 export */\r\nexport const isHtmlFile = (file: File): boolean => {\r\n return (\r\n file.size > 0 &&\r\n (file.type === \"text/html\" ||\r\n file.name?.toLowerCase().endsWith(\".html\") ||\r\n file.name?.toLowerCase().endsWith(\".htm\"))\r\n );\r\n};\r\n\r\n// ============================================\r\n// 🔒 보안 유틸리티 함수\r\n// ============================================\r\n\r\n/**\r\n * HTML 특수문자 이스케이프 (XSS 방지)\r\n * URL이나 사용자 입력을 HTML에 삽입할 때 사용\r\n * @internal 테스트용 export\r\n */\r\nexport const escapeHtml = (str: string): string => {\r\n const htmlEscapes: Record<string, string> = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n };\r\n return str.replace(/[&<>\"']/g, (char) => htmlEscapes[char]);\r\n};\r\n\r\n/**\r\n * 블록 배열에서 모든 이미지 URL 추출\r\n * (중첩된 children도 재귀적으로 탐색)\r\n * @internal 테스트용 export\r\n */\r\nexport const extractImageUrls = (blocks: DefaultPartialBlock[]): Set<string> => {\r\n const urls = new Set<string>();\r\n\r\n const traverse = (blockList: DefaultPartialBlock[]) => {\r\n for (const block of blockList) {\r\n // image 블록에서 URL 추출\r\n if (block.type === \"image\" && (block.props as any)?.url) {\r\n const url = (block.props as any).url;\r\n if (typeof url === \"string\" && url.trim()) {\r\n urls.add(url);\r\n }\r\n }\r\n // children이 있으면 재귀 탐색\r\n if (block.children && Array.isArray(block.children)) {\r\n traverse(block.children as DefaultPartialBlock[]);\r\n }\r\n }\r\n };\r\n\r\n traverse(blocks);\r\n return urls;\r\n};\r\n\r\n/**\r\n * 블록 배열에서 이미지·비디오(미디어) URL 추출\r\n * (중첩된 children도 재귀적으로 탐색, onImageDelete 삭제 감지용)\r\n * @internal 테스트용 export\r\n */\r\nexport const extractMediaUrls = (blocks: DefaultPartialBlock[]): Set<string> => {\r\n const urls = new Set<string>();\r\n\r\n const traverse = (blockList: DefaultPartialBlock[]) => {\r\n for (const block of blockList) {\r\n if (block.type === \"image\" && (block.props as any)?.url) {\r\n const url = (block.props as any).url;\r\n if (typeof url === \"string\" && url.trim()) urls.add(url);\r\n }\r\n if (block.type === \"video\" && (block.props as any)?.url) {\r\n const url = (block.props as any).url;\r\n if (typeof url === \"string\" && url.trim()) urls.add(url);\r\n }\r\n if (block.children && Array.isArray(block.children)) {\r\n traverse(block.children as DefaultPartialBlock[]);\r\n }\r\n }\r\n };\r\n\r\n traverse(blocks);\r\n return urls;\r\n};\r\n\r\n/**\r\n * 삭제된 미디어(이미지·비디오) URL 찾기\r\n * (이전 블록에는 있었지만 현재 블록에는 없는 URL)\r\n * @internal 테스트용 export\r\n */\r\nexport const findDeletedMediaUrls = (\r\n previousUrls: Set<string>,\r\n currentUrls: Set<string>\r\n): string[] => {\r\n const deleted: string[] = [];\r\n previousUrls.forEach((url) => {\r\n if (!currentUrls.has(url)) deleted.push(url);\r\n });\r\n return deleted;\r\n};\r\n\r\n/**\r\n * 삭제된 이미지 URL 찾기 (findDeletedMediaUrls와 동일 로직, 하위 호환용)\r\n * @internal 테스트용 export\r\n */\r\nexport const findDeletedImageUrls = (\r\n previousUrls: Set<string>,\r\n currentUrls: Set<string>\r\n): string[] => findDeletedMediaUrls(previousUrls, currentUrls);\r\n\r\nconst findBlockWithLink = (blocks: any[], targetUrl: string): any | null => {\r\n for (const block of blocks) {\r\n if (block.content) {\r\n for (const item of block.content) {\r\n if (item.type === \"link\" && item.href === targetUrl) return block;\r\n if (item.content) {\r\n for (const sub of item.content) {\r\n if (sub.type === \"link\" && sub.href === targetUrl) return block;\r\n }\r\n }\r\n }\r\n }\r\n if (block.children?.length) {\r\n const found = findBlockWithLink(block.children, targetUrl);\r\n if (found) return found;\r\n }\r\n }\r\n return null;\r\n};\r\n\r\nconst ConvertToPreviewButton = ({ url }: { url: string }) => {\r\n const editor = useBlockNoteEditor();\r\n const Components = useComponentsContext()!;\r\n\r\n return (\r\n <Components.LinkToolbar.Button\r\n className=\"bn-button\"\r\n mainTooltip=\"링크 프리뷰로 전환\"\r\n label=\"링크 프리뷰로 전환\"\r\n isSelected={false}\r\n onClick={() => {\r\n try {\r\n const allBlocks = (editor as any).document;\r\n const targetBlock = findBlockWithLink(allBlocks, url)\r\n || editor.getTextCursorPosition().block;\r\n (editor as any).replaceBlocks(\r\n [targetBlock],\r\n [{ type: \"linkPreview\", props: { url } }]\r\n );\r\n } catch (err) {\r\n console.error(\"Convert to link preview failed:\", err);\r\n }\r\n }}\r\n icon={\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <rect x=\"1\" y=\"3\" width=\"14\" height=\"10\" rx=\"2\" stroke=\"currentColor\" strokeWidth=\"1.5\" fill=\"none\" />\r\n <line x1=\"1\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\r\n <circle cx=\"5\" cy=\"6.5\" r=\"1.5\" stroke=\"currentColor\" strokeWidth=\"1\" fill=\"none\" />\r\n </svg>\r\n }\r\n />\r\n );\r\n};\r\n\r\nconst CustomLinkToolbar = (props: any) => {\r\n const editor = useBlockNoteEditor();\r\n const Components = useComponentsContext()!;\r\n const hasLinkPreview = !!(editor as any)?._linkPreviewApiEndpoint;\r\n\r\n return (\r\n <Components.LinkToolbar.Root\r\n className=\"bn-toolbar bn-link-toolbar\"\r\n onMouseEnter={props.stopHideTimer}\r\n onMouseLeave={props.startHideTimer}\r\n >\r\n <EditLinkButton url={props.url} text={props.text} editLink={props.editLink} />\r\n <OpenLinkButton url={props.url} />\r\n <DeleteLinkButton deleteLink={props.deleteLink} />\r\n {hasLinkPreview && (\r\n <ConvertToPreviewButton url={props.url} />\r\n )}\r\n </Components.LinkToolbar.Root>\r\n );\r\n};\r\n\r\nexport default function LumirEditor({\r\n // editor options\r\n initialContent,\r\n initialEmptyBlocks = 3,\r\n uploadFile,\r\n s3Upload,\r\n tables,\r\n heading,\r\n defaultStyles = true,\r\n disableExtensions,\r\n tabBehavior = \"prefer-navigate-ui\",\r\n trailingBlock = true,\r\n allowVideoUpload = false,\r\n allowAudioUpload = false,\r\n allowFileUpload = false,\r\n maxImageFileSize,\r\n maxVideoFileSize,\r\n // link preview\r\n linkPreview,\r\n // view options\r\n editable = true,\r\n theme = \"light\",\r\n formattingToolbar = true,\r\n linkToolbar = true,\r\n sideMenu = true,\r\n emojiPicker = true,\r\n filePanel = true,\r\n tableHandles = true,\r\n onSelectionChange,\r\n className = \"\",\r\n placeholder,\r\n sideMenuAddButton = false,\r\n floatingMenu = false,\r\n floatingMenuPosition = \"sticky\",\r\n // callbacks / refs\r\n onContentChange,\r\n onError,\r\n onImageDelete,\r\n}: LumirEditorProps) {\r\n // 이미지 업로드 로딩 상태\r\n const [isUploading, setIsUploading] = useState(false);\r\n /** S3 업로드 진행률 0–100. null이면 진행률 미표시 */\r\n const [uploadProgress, setUploadProgress] = useState<number | null>(null);\r\n // 에러 상태 (사용자에게 표시할 에러 메시지)\r\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\r\n // FloatingMenu: DOM에 항상 있는 file input (onchange 미발생 방지)\r\n const floatingMenuFileInputRef = useRef<HTMLInputElement | null>(null);\r\n const floatingMenuBlockRef = useRef<{ id: string } | null>(null);\r\n const floatingMenuUploadStartTimeRef = useRef<number>(0);\r\n\r\n // 에러 처리 핸들러\r\n const handleError = useCallback(\r\n (error: LumirEditorError) => {\r\n // 콜백이 있으면 호출\r\n onError?.(error);\r\n // 사용자에게 에러 메시지 표시\r\n setErrorMessage(error.getUserMessage());\r\n // 3초 후 에러 메시지 자동 숨김\r\n setTimeout(() => setErrorMessage(null), 3000);\r\n },\r\n [onError]\r\n );\r\n const validatedContent = useMemo<DefaultPartialBlock[]>(() => {\r\n return ContentUtils.validateContent(initialContent, initialEmptyBlocks);\r\n }, [initialContent, initialEmptyBlocks]);\r\n\r\n // 테이블 설정 메모이제이션\r\n const tableConfig = useMemo(() => {\r\n return EditorConfig.getDefaultTableConfig(tables);\r\n }, [\r\n tables?.splitCells,\r\n tables?.cellBackgroundColor,\r\n tables?.cellTextColor,\r\n tables?.headers,\r\n ]);\r\n\r\n // 헤딩 설정 메모이제이션\r\n const headingConfig = useMemo(() => {\r\n return EditorConfig.getDefaultHeadingConfig(heading);\r\n }, [heading?.levels?.join(\",\") ?? \"\"]);\r\n\r\n // 비활성화 확장 메모이제이션\r\n const disabledExtensions = useMemo(() => {\r\n return EditorConfig.getDisabledExtensions(\r\n disableExtensions,\r\n allowVideoUpload,\r\n allowAudioUpload,\r\n allowFileUpload\r\n );\r\n }, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);\r\n\r\n // #region agent log\r\n useEffect(() => {\r\n DEBUG_LOG(\"LumirEditor:init:disabledExtensions\", \"snapshot\", {\r\n allowVideoUpload,\r\n hasVideoInDisabled: disabledExtensions.includes(\"video\"),\r\n disabledList: disabledExtensions.slice(0, 15),\r\n });\r\n }, [allowVideoUpload, disabledExtensions]);\r\n // #endregion\r\n\r\n // fileNameTransform 콜백을 ref로 관리 (에디터 재생성 방지)\r\n const fileNameTransformRef = useRef(s3Upload?.fileNameTransform);\r\n useEffect(() => {\r\n fileNameTransformRef.current = s3Upload?.fileNameTransform;\r\n }, [s3Upload?.fileNameTransform]);\r\n\r\n // S3 업로드 설정 메모이제이션 (객체 참조 안정화)\r\n // 주의: fileNameTransform은 ref로 관리하므로 의존성에서 제외\r\n const memoizedS3Upload = useMemo(() => {\r\n if (!s3Upload) return undefined;\r\n return {\r\n apiEndpoint: s3Upload.apiEndpoint,\r\n env: s3Upload.env,\r\n path: s3Upload.path,\r\n appendUUID: s3Upload.appendUUID,\r\n preserveExtension: s3Upload.preserveExtension,\r\n uploadTimeoutMs: s3Upload.uploadTimeoutMs,\r\n maxRetries: s3Upload.maxRetries,\r\n onProgress: (percent: number) => {\r\n setUploadProgress(percent);\r\n s3Upload.onProgress?.(percent);\r\n },\r\n // 최신 콜백을 항상 사용하도록 ref를 통해 접근\r\n fileNameTransform: ((originalName: string, file: File) => {\r\n return fileNameTransformRef.current\r\n ? fileNameTransformRef.current(originalName, file)\r\n : originalName;\r\n }) as ((originalName: string, file: File) => string) | undefined,\r\n };\r\n }, [\r\n s3Upload?.apiEndpoint,\r\n s3Upload?.env,\r\n s3Upload?.path,\r\n s3Upload?.appendUUID,\r\n s3Upload?.preserveExtension,\r\n s3Upload?.uploadTimeoutMs,\r\n s3Upload?.maxRetries,\r\n s3Upload?.onProgress,\r\n ]);\r\n\r\n const editor = useCreateBlockNote(\r\n {\r\n // HTML 미리보기 블록이 포함된 커스텀 스키마 사용\r\n schema,\r\n initialContent: validatedContent as any,\r\n tables: tableConfig,\r\n heading: headingConfig,\r\n animations: false, // 기본적으로 애니메이션 비활성화\r\n defaultStyles,\r\n // 확장 비활성: 비디오/오디오/파일 제어\r\n disableExtensions: disabledExtensions,\r\n placeholders: placeholder\r\n ? { default: placeholder, emptyDocument: placeholder }\r\n : undefined,\r\n tabBehavior,\r\n trailingBlock,\r\n uploadFile: async (file) => {\r\n const allowedImage = isImageFile(file, maxImageFileSize);\r\n const allowedVideo =\r\n allowVideoUpload && isVideoFile(file, maxVideoFileSize);\r\n // #region agent log\r\n DEBUG_LOG(\"uploadFile:step1:entry\", \"editor uploadFile callback invoked\", {\r\n fileName: file.name,\r\n fileType: file.type,\r\n fileSize: file.size,\r\n allowVideoUpload,\r\n allowedImage,\r\n allowedVideo,\r\n });\r\n // #endregion\r\n if (!allowedImage && !allowedVideo) {\r\n const error = LumirEditorError.invalidFileType(\r\n file.name,\r\n allowVideoUpload\r\n );\r\n handleError(error);\r\n throw error;\r\n }\r\n\r\n try {\r\n setUploadProgress(0);\r\n let fileUrl: string;\r\n // #region agent log\r\n const branch = uploadFile ? \"custom\" : memoizedS3Upload?.apiEndpoint ? \"s3\" : \"none\";\r\n DEBUG_LOG(\"uploadFile:step2:branch\", \"upload path\", {\r\n branch,\r\n hasCustomUploadFile: !!uploadFile,\r\n hasS3ApiEndpoint: !!memoizedS3Upload?.apiEndpoint,\r\n });\r\n // #endregion\r\n // 1. 사용자 정의 uploadFile 우선\r\n if (uploadFile) {\r\n const t0 = Date.now();\r\n DEBUG_LOG(\"uploadFile:step3a:custom\", \"calling custom uploadFile\", { fileName: file.name });\r\n fileUrl = await uploadFile(file);\r\n DEBUG_LOG(\"uploadFile:step3a:done\", \"custom uploadFile returned\", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });\r\n }\r\n // 2. S3 업로드 (uploadFile 없을 때)\r\n else if (memoizedS3Upload?.apiEndpoint) {\r\n const t0 = Date.now();\r\n DEBUG_LOG(\"uploadFile:step3b:s3\", \"calling S3 uploader\", { fileName: file.name });\r\n const s3Uploader = createS3Uploader(memoizedS3Upload);\r\n fileUrl = await s3Uploader(file);\r\n DEBUG_LOG(\"uploadFile:step3b:done\", \"S3 uploader returned\", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });\r\n }\r\n // 3. 업로드 방법이 없으면 에러\r\n else {\r\n const error = LumirEditorError.s3ConfigError(\r\n \"No upload method available. Please provide uploadFile or s3Upload configuration.\"\r\n );\r\n handleError(error);\r\n throw error;\r\n }\r\n\r\n // BlockNote가 파일 타입에 따라 이미지/비디오 블록을 생성하도록 URL만 반환\r\n // #region agent log\r\n DEBUG_LOG(\"uploadFile:step4:success\", \"returning URL\", {\r\n fileName: file.name,\r\n urlPrefix: fileUrl.slice(0, 80),\r\n });\r\n // #endregion\r\n return fileUrl;\r\n } catch (error) {\r\n // #region agent log\r\n DEBUG_LOG(\"uploadFile:step5:catch\", \"uploadFile threw\", {\r\n fileName: file.name,\r\n errorMessage: error instanceof Error ? error.message : String(error),\r\n });\r\n // #endregion\r\n // 이미 LumirEditorError인 경우 다시 처리하지 않음\r\n if (error instanceof LumirEditorError) {\r\n throw error;\r\n }\r\n const lumirError = LumirEditorError.uploadFailed(\r\n error instanceof Error ? error.message : String(error),\r\n error instanceof Error ? error : undefined\r\n );\r\n handleError(lumirError);\r\n throw lumirError;\r\n } finally {\r\n setUploadProgress(null);\r\n }\r\n },\r\n pasteHandler: (ctx) => {\r\n const { event, editor, defaultPasteHandler } = ctx as any;\r\n\r\n // URL 붙여넣기 감지 → linkPreview 블록 생성\r\n if (linkPreview?.apiEndpoint) {\r\n const text = event?.clipboardData?.getData?.(\"text/plain\") || \"\";\r\n const trimmed = text.trim();\r\n if (\r\n trimmed &&\r\n /^https?:\\/\\/\\S+$/i.test(trimmed) &&\r\n !event?.clipboardData?.files?.length\r\n ) {\r\n event.preventDefault();\r\n const currentBlock = editor.getTextCursorPosition().block;\r\n const blockText = currentBlock.content\r\n ?.map((c: any) => c.text || \"\")\r\n .join(\"\")\r\n .trim();\r\n if (!blockText && currentBlock.type === \"paragraph\") {\r\n editor.updateBlock(currentBlock, {\r\n type: \"linkPreview\",\r\n props: { url: trimmed },\r\n });\r\n } else {\r\n editor.insertBlocks(\r\n [{ type: \"linkPreview\", props: { url: trimmed } }],\r\n currentBlock,\r\n \"after\"\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n\r\n const fileList =\r\n (event?.clipboardData?.files as FileList | null) ?? null;\r\n const files: File[] = fileList ? Array.from(fileList) : [];\r\n const acceptedFiles: File[] = files.filter(\r\n (f) =>\r\n isImageFile(f, maxImageFileSize) || (allowVideoUpload && isVideoFile(f, maxVideoFileSize))\r\n );\r\n // #region agent log\r\n DEBUG_LOG(\"paste:step1:files\", \"paste clipboard files\", {\r\n filesCount: files.length,\r\n acceptedCount: acceptedFiles.length,\r\n fileNames: files.map((f) => f.name),\r\n acceptedNames: acceptedFiles.map((f) => f.name),\r\n });\r\n // #endregion\r\n // 파일이 있지만 허용된 미디어가 없으면 기본 처리 막고 무시\r\n if (files.length > 0 && acceptedFiles.length === 0) {\r\n event.preventDefault();\r\n return true;\r\n }\r\n\r\n if (acceptedFiles.length === 0) {\r\n return defaultPasteHandler() ?? false;\r\n }\r\n\r\n event.preventDefault();\r\n (async () => {\r\n setIsUploading(true);\r\n try {\r\n for (const file of acceptedFiles) {\r\n try {\r\n // #region agent log\r\n DEBUG_LOG(\"paste:step2:upload\", \"calling uploadFile for paste\", {\r\n fileName: file.name,\r\n fileType: file.type,\r\n });\r\n // #endregion\r\n const url = await editor.uploadFile(file);\r\n if (isImageFile(file, maxImageFileSize)) {\r\n editor.pasteHTML(\r\n `<img src=\"${escapeHtml(url)}\" alt=\"image\" />`\r\n );\r\n } else if (isVideoFile(file, maxVideoFileSize)) {\r\n const currentBlock = editor.getTextCursorPosition().block;\r\n editor.insertBlocks(\r\n [{ type: \"video\", props: { url } }] as any,\r\n currentBlock,\r\n \"after\"\r\n );\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"Upload failed, skipped:\",\r\n file.name || \"\",\r\n err\r\n );\r\n }\r\n }\r\n } finally {\r\n setIsUploading(false);\r\n }\r\n })();\r\n return true;\r\n },\r\n },\r\n [\r\n validatedContent,\r\n tableConfig,\r\n headingConfig,\r\n defaultStyles,\r\n disabledExtensions,\r\n tabBehavior,\r\n trailingBlock,\r\n uploadFile,\r\n memoizedS3Upload,\r\n allowVideoUpload,\r\n linkPreview?.apiEndpoint,\r\n placeholder,\r\n ]\r\n );\r\n\r\n // Link Preview API endpoint를 에디터 인스턴스에 동기적으로 연결\r\n // (useEffect 사용 시 블록 렌더링보다 늦게 설정되어 첫 fetch가 실패할 수 있음)\r\n if (editor && linkPreview?.apiEndpoint) {\r\n (editor as any)._linkPreviewApiEndpoint = linkPreview.apiEndpoint;\r\n }\r\n\r\n // 편집 가능 여부 설정\r\n useEffect(() => {\r\n if (editor) {\r\n editor.isEditable = editable;\r\n }\r\n }, [editor, editable]);\r\n\r\n // 콘텐츠 변경 감지\r\n useEffect(() => {\r\n if (!editor || !onContentChange) return;\r\n\r\n const handleContentChange = () => {\r\n // BlockNote의 올바른 API 사용\r\n const blocks = editor.topLevelBlocks as DefaultPartialBlock[];\r\n onContentChange(blocks);\r\n };\r\n\r\n return editor.onEditorContentChange(handleContentChange);\r\n }, [editor, onContentChange]);\r\n\r\n // 이미지·비디오 삭제 감지 (onImageDelete 콜백 — 미디어 URL 모두 전달)\r\n const previousMediaUrlsRef = useRef<Set<string>>(new Set());\r\n\r\n useEffect(() => {\r\n if (!editor) return;\r\n\r\n const initialBlocks = editor.topLevelBlocks as DefaultPartialBlock[];\r\n previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);\r\n }, [editor]);\r\n\r\n useEffect(() => {\r\n if (!editor || !onImageDelete) return;\r\n\r\n const handleMediaDeleteCheck = () => {\r\n const currentBlocks = editor.topLevelBlocks as DefaultPartialBlock[];\r\n const currentUrls = extractMediaUrls(currentBlocks);\r\n const previousUrls = previousMediaUrlsRef.current;\r\n\r\n const deletedUrls = findDeletedMediaUrls(previousUrls, currentUrls);\r\n deletedUrls.forEach((url) => {\r\n onImageDelete(url);\r\n });\r\n\r\n previousMediaUrlsRef.current = currentUrls;\r\n };\r\n\r\n return editor.onEditorContentChange(handleMediaDeleteCheck);\r\n }, [editor, onImageDelete]);\r\n\r\n // 드래그앤드롭 이미지/HTML 처리\r\n useEffect(() => {\r\n const el = editor?.domElement as HTMLElement | undefined;\r\n if (!el) return;\r\n\r\n const handleDragOver = (e: DragEvent) => {\r\n if (e.defaultPrevented) return;\r\n const hasFiles = (\r\n e.dataTransfer?.types as unknown as string[] | undefined\r\n )?.includes?.(\"Files\");\r\n if (hasFiles) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n };\r\n\r\n const handleDrop = (e: DragEvent) => {\r\n if (!e.dataTransfer) return;\r\n const hasFiles = (\r\n (e.dataTransfer.types as unknown as string[] | undefined) ?? []\r\n ).includes(\"Files\");\r\n if (!hasFiles) return;\r\n\r\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n const items = Array.from(e.dataTransfer.items ?? []);\r\n const files = items\r\n .filter((it) => it.kind === \"file\")\r\n .map((it) => it.getAsFile())\r\n .filter((f): f is File => !!f);\r\n\r\n // 이미지, 동영상, HTML 파일 분리\r\n const imageFiles = files.filter((f) => isImageFile(f, maxImageFileSize));\r\n const videoFiles = allowVideoUpload\r\n ? files.filter((f) => isVideoFile(f, maxVideoFileSize))\r\n : [];\r\n const htmlFiles = files.filter(isHtmlFile);\r\n\r\n // #region agent log\r\n DEBUG_LOG(\"drop:step1:files\", \"drop received\", {\r\n filesCount: files.length,\r\n imageCount: imageFiles.length,\r\n videoCount: videoFiles.length,\r\n htmlCount: htmlFiles.length,\r\n allowVideoUpload,\r\n firstFile: files[0]\r\n ? {\r\n name: files[0].name,\r\n type: files[0].type,\r\n size: files[0].size,\r\n isImage: isImageFile(files[0], maxImageFileSize),\r\n isVideo: isVideoFile(files[0], maxVideoFileSize),\r\n }\r\n : null,\r\n });\r\n // #endregion\r\n\r\n if (\r\n imageFiles.length === 0 &&\r\n htmlFiles.length === 0 &&\r\n videoFiles.length === 0\r\n )\r\n return;\r\n\r\n (async () => {\r\n setIsUploading(true);\r\n try {\r\n // #region agent log\r\n DEBUG_LOG(\"drop:step2:async\", \"drop async started\", {\r\n imageCount: imageFiles.length,\r\n videoCount: videoFiles.length,\r\n });\r\n // #endregion\r\n // 이미지 파일 처리\r\n for (const file of imageFiles) {\r\n try {\r\n if (editor?.uploadFile) {\r\n const url = await editor.uploadFile(file);\r\n if (url && typeof url === \"string\") {\r\n editor.pasteHTML(\r\n `<img src=\"${escapeHtml(url)}\" alt=\"image\" />`\r\n );\r\n }\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"Image upload failed, skipped:\",\r\n file.name || \"\",\r\n err\r\n );\r\n }\r\n }\r\n\r\n // 동영상 파일 처리 - video 블록으로 삽입\r\n // #region agent log\r\n DEBUG_LOG(\"drop:step3:videoLoop\", \"video loop start\", {\r\n videoCount: videoFiles.length,\r\n names: videoFiles.map((f) => f.name),\r\n });\r\n // #endregion\r\n for (const file of videoFiles) {\r\n try {\r\n if (editor?.uploadFile) {\r\n // #region agent log\r\n DEBUG_LOG(\"drop:step4:videoUpload\", \"calling uploadFile for video\", {\r\n fileName: file.name,\r\n });\r\n // #endregion\r\n const url = await editor.uploadFile(file);\r\n if (url && typeof url === \"string\") {\r\n const currentBlock = editor.getTextCursorPosition().block;\r\n editor.insertBlocks(\r\n [{ type: \"video\", props: { url } }] as any,\r\n currentBlock,\r\n \"after\"\r\n );\r\n }\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"Video upload failed, skipped:\",\r\n file.name || \"\",\r\n err\r\n );\r\n }\r\n }\r\n\r\n // HTML 파일 처리 - htmlPreview 블록으로 삽입\r\n for (const file of htmlFiles) {\r\n try {\r\n const htmlContent = await file.text();\r\n const currentBlock = editor.getTextCursorPosition().block;\r\n\r\n // htmlPreview 블록 삽입\r\n editor.insertBlocks(\r\n [\r\n {\r\n type: \"htmlPreview\",\r\n props: {\r\n htmlContent: htmlContent,\r\n fileName: file.name,\r\n height: \"400px\",\r\n },\r\n },\r\n ],\r\n currentBlock,\r\n \"after\"\r\n );\r\n } catch (err) {\r\n console.warn(\r\n \"HTML file processing failed, skipped:\",\r\n file.name || \"\",\r\n err\r\n );\r\n }\r\n }\r\n } finally {\r\n setIsUploading(false);\r\n }\r\n })();\r\n };\r\n\r\n el.addEventListener(\"dragover\", handleDragOver, { capture: true });\r\n el.addEventListener(\"drop\", handleDrop, { capture: true });\r\n\r\n return () => {\r\n el.removeEventListener(\"dragover\", handleDragOver, {\r\n capture: true,\r\n } as any);\r\n el.removeEventListener(\"drop\", handleDrop, { capture: true } as any);\r\n };\r\n }, [editor, allowVideoUpload]);\r\n\r\n // SideMenu 설정 (Add 버튼 제어)\r\n const computedSideMenu = useMemo(() => {\r\n return sideMenuAddButton ? sideMenu : false;\r\n }, [sideMenuAddButton, sideMenu]);\r\n\r\n // Add 버튼 없는 사이드 메뉴 (드래그 핸들만) - 메모이제이션\r\n const DragHandleOnlySideMenu = useMemo(() => {\r\n return (props: any) => (\r\n <BlockSideMenu {...props}>\r\n <DragHandleButton {...props} />\r\n </BlockSideMenu>\r\n );\r\n }, []);\r\n\r\n return (\r\n <div\r\n className={cn(\"lumirEditor\", className)}\r\n style={{ position: \"relative\", display: \"flex\", flexDirection: \"column\" }}\r\n >\r\n {/* FloatingMenu를 BlockNoteView 외부로 이동 */}\r\n {floatingMenu && editor && (\r\n <>\r\n <input\r\n ref={floatingMenuFileInputRef}\r\n type=\"file\"\r\n accept={\r\n allowVideoUpload\r\n ? \"image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov\"\r\n : \"image/*\"\r\n }\r\n style={{\r\n position: \"absolute\",\r\n left: \"-9999px\",\r\n opacity: 0,\r\n pointerEvents: \"none\",\r\n }}\r\n onChange={async (e) => {\r\n const inputEl = e.target as HTMLInputElement;\r\n const file = inputEl.files?.[0];\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step3:onchange\", \"file input onchange fired\", {\r\n hasFile: !!file,\r\n fileName: file?.name,\r\n fileType: file?.type,\r\n fileSize: file?.size,\r\n hasUploadFile: !!editor?.uploadFile,\r\n });\r\n // #endregion\r\n const blockToInsertAfter = floatingMenuBlockRef.current;\r\n if (file && editor.uploadFile && blockToInsertAfter) {\r\n const allowedImage = isImageFile(file, maxImageFileSize);\r\n const allowedVideo = allowVideoUpload && isVideoFile(file, maxVideoFileSize);\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step4:fileCheck\", \"allowed check\", {\r\n fileName: file.name,\r\n allowedImage,\r\n allowedVideo,\r\n });\r\n // #endregion\r\n if (allowedImage || allowedVideo) {\r\n try {\r\n setIsUploading(true);\r\n floatingMenuUploadStartTimeRef.current = Date.now();\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step5:uploadStart\", \"calling editor.uploadFile\", {\r\n fileName: file.name,\r\n });\r\n // #endregion\r\n const url = await editor.uploadFile(file);\r\n const blockType = allowedVideo ? \"video\" : \"image\";\r\n const elapsedMs = Date.now() - floatingMenuUploadStartTimeRef.current;\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step6:uploadDone\", \"upload returned, inserting block\", {\r\n blockType,\r\n blockId: blockToInsertAfter.id,\r\n urlLen: url?.length,\r\n elapsedMs,\r\n });\r\n // #endregion\r\n editor.insertBlocks(\r\n [\r\n {\r\n type: blockType,\r\n props: { url: url as string },\r\n },\r\n ] as any,\r\n blockToInsertAfter,\r\n \"after\"\r\n );\r\n } catch (err) {\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step7:catch\", \"upload or insert failed\", {\r\n errMsg: err instanceof Error ? err.message : String(err),\r\n });\r\n // #endregion\r\n console.error(\"Upload failed:\", err);\r\n } finally {\r\n setIsUploading(false);\r\n }\r\n }\r\n }\r\n inputEl.value = \"\";\r\n }}\r\n />\r\n <FloatingMenu\r\n editor={editor as any}\r\n position={floatingMenuPosition}\r\n onImageUpload={() => {\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step1:click\", \"upload button clicked\", {\r\n allowVideoUpload,\r\n });\r\n // #endregion\r\n let blockToInsertAfter: { id: string };\r\n try {\r\n blockToInsertAfter = editor.getTextCursorPosition().block;\r\n } catch (err) {\r\n DEBUG_LOG(\"FloatingMenu:step1b:error\", \"getTextCursorPosition failed\", {\r\n err: err instanceof Error ? err.message : String(err),\r\n });\r\n return;\r\n }\r\n floatingMenuBlockRef.current = blockToInsertAfter;\r\n const input = floatingMenuFileInputRef.current;\r\n if (!input) return;\r\n input.accept = allowVideoUpload\r\n ? \"image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov\"\r\n : \"image/*\";\r\n input.value = \"\";\r\n // #region agent log\r\n DEBUG_LOG(\"FloatingMenu:step2:inputReady\", \"persistent input ref, about to click\", {\r\n accept: input.accept,\r\n });\r\n DEBUG_LOG(\"FloatingMenu:step2b:click\", \"input.click() about to be called\", {});\r\n // #endregion\r\n input.click();\r\n }}\r\n />\r\n </>\r\n )}\r\n <BlockNoteView\r\n editor={editor}\r\n editable={editable}\r\n theme={theme}\r\n formattingToolbar={formattingToolbar}\r\n linkToolbar={false}\r\n sideMenu={computedSideMenu}\r\n slashMenu={false}\r\n emojiPicker={emojiPicker}\r\n filePanel={filePanel}\r\n tableHandles={tableHandles}\r\n onSelectionChange={onSelectionChange}\r\n >\r\n {linkToolbar && (\r\n linkPreview?.apiEndpoint\r\n ? <LinkToolbarController linkToolbar={CustomLinkToolbar} />\r\n : <LinkToolbarController />\r\n )}\r\n {\r\n <SuggestionMenuController\r\n triggerCharacter=\"/\"\r\n getItems={useCallback(\r\n async (query: string) => {\r\n const items = getDefaultReactSlashMenuItems(editor);\r\n // 오디오/파일 항목 제거; 비디오는 allowVideoUpload일 때만 표시\r\n const filtered = items.filter((item: any) => {\r\n const key = (item?.key || \"\").toString().toLowerCase();\r\n const title = (item?.title || \"\").toString().toLowerCase();\r\n if (key === \"video\" || title.includes(\"video\"))\r\n return allowVideoUpload;\r\n if ([\"audio\", \"file\"].includes(key)) return false;\r\n if (title.includes(\"audio\") || title.includes(\"file\"))\r\n return false;\r\n return true;\r\n });\r\n\r\n // HTML 미리보기 슬래시 메뉴 항목 추가\r\n const htmlPreviewItem = {\r\n title: \"HTML Preview\",\r\n onItemClick: () => {\r\n // 파일 선택 다이얼로그 열기\r\n const input = document.createElement(\"input\");\r\n input.type = \"file\";\r\n input.accept = \".html,.htm\";\r\n input.onchange = async (e) => {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (file) {\r\n const htmlContent = await file.text();\r\n const currentBlock =\r\n editor.getTextCursorPosition().block;\r\n editor.insertBlocks(\r\n [\r\n {\r\n type: \"htmlPreview\",\r\n props: {\r\n htmlContent: htmlContent,\r\n fileName: file.name,\r\n height: \"400px\",\r\n },\r\n },\r\n ],\r\n currentBlock,\r\n \"after\"\r\n );\r\n }\r\n };\r\n input.click();\r\n },\r\n aliases: [\"html\", \"preview\", \"웹\", \"웹페이지\"],\r\n group: \"Embeds\",\r\n icon: (\r\n <svg\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <polyline points=\"16 18 22 12 16 6\"></polyline>\r\n <polyline points=\"8 6 2 12 8 18\"></polyline>\r\n </svg>\r\n ),\r\n subtext: \"HTML 파일을 미리보기로 삽입\",\r\n };\r\n\r\n const allItems = [...filtered, htmlPreviewItem];\r\n\r\n // Link Preview 슬래시 메뉴 항목 (linkPreview 설정이 있을 때만)\r\n if (linkPreview?.apiEndpoint) {\r\n allItems.push({\r\n title: \"Link Preview\",\r\n onItemClick: () => {\r\n insertOrUpdateBlock(editor, {\r\n type: \"linkPreview\",\r\n props: { url: \"\" },\r\n });\r\n },\r\n aliases: [\r\n \"link\",\r\n \"preview\",\r\n \"url\",\r\n \"링크\",\r\n \"미리보기\",\r\n \"프리뷰\",\r\n ],\r\n group: \"Embeds\",\r\n icon: (\r\n <svg\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\r\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\r\n </svg>\r\n ),\r\n subtext: \"URL의 미리보기 카드를 삽입\",\r\n });\r\n }\r\n\r\n if (!query) return allItems;\r\n const q = query.toLowerCase();\r\n return allItems.filter(\r\n (item: any) =>\r\n item.title?.toLowerCase().includes(q) ||\r\n (item.aliases || []).some((a: string) =>\r\n a.toLowerCase().includes(q)\r\n )\r\n );\r\n },\r\n [editor, allowVideoUpload, linkPreview?.apiEndpoint]\r\n )}\r\n />\r\n }\r\n {!sideMenuAddButton && (\r\n <SideMenuController sideMenu={DragHandleOnlySideMenu} />\r\n )}\r\n </BlockNoteView>\r\n\r\n {/* 이미지/비디오 업로드 로딩 스피너 */}\r\n {isUploading && (\r\n <div className=\"lumirEditor-upload-overlay\">\r\n <div className=\"lumirEditor-spinner\" />\r\n {uploadProgress !== null && (\r\n <span className=\"lumirEditor-upload-progress\">{uploadProgress}%</span>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* 에러 메시지 토스트 */}\r\n {errorMessage && (\r\n <div className=\"lumirEditor-error-toast\">\r\n <span className=\"lumirEditor-error-icon\">⚠️</span>\r\n <span className=\"lumirEditor-error-message\">{errorMessage}</span>\r\n <button\r\n className=\"lumirEditor-error-close\"\r\n onClick={() => setErrorMessage(null)}\r\n type=\"button\"\r\n >\r\n ✕\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","// clsx와 tailwind-merge를 사용한 className 유틸리티\r\n// 사용자가 직접 설치하도록 권장하거나, 간단한 버전 제공\r\n\r\nexport function cn(...inputs: (string | undefined | null | false)[]) {\r\n return inputs.filter(Boolean).join(' ');\r\n}\r\n","export interface S3UploaderConfig {\r\n apiEndpoint: string; // '/api/s3/presigned'(필수)\r\n env: \"production\" | \"development\"; // 환경 (필수)\r\n path: string; // 파일 경로 (필수)\r\n /** 파일명 변환 콜백 - 확장자를 제외한 파일명을 받아 변환합니다 */\r\n fileNameTransform?: (nameWithoutExt: string, file: File) => string;\r\n /** true일 경우 파일명 뒤에 UUID를 자동으로 추가합니다 (예: image_abc123.png) */\r\n appendUUID?: boolean;\r\n /** false로 설정하면 확장자를 자동으로 붙이지 않음 (기본: true) */\r\n preserveExtension?: boolean;\r\n /** 업로드 진행률(0–100) 콜백. S3 PUT 시에만 호출됨 */\r\n onProgress?: (percent: number) => void;\r\n /** PUT 요청 타임아웃(ms). 미설정 시 120000(120초). 대용량 비디오에 유리 */\r\n uploadTimeoutMs?: number;\r\n /** PUT 실패 시 재시도 횟수. 기본 2(최대 3회 시도) */\r\n maxRetries?: number;\r\n}\r\n\r\n/**\r\n * 🔒 보안: S3 URL 검증\r\n * HTTPS 프로토콜 강제 및 URL 형식 검증\r\n */\r\nfunction validateS3Url(url: unknown, fieldName: string): string {\r\n // 타입 검증\r\n if (typeof url !== \"string\" || !url || url.trim() === \"\") {\r\n throw new Error(\r\n `${fieldName} is required and must be a non-empty string`\r\n );\r\n }\r\n\r\n // HTTPS 프로토콜 강제 (SSRF 방지)\r\n if (!url.startsWith(\"https://\")) {\r\n throw new Error(`${fieldName} must use HTTPS protocol`);\r\n }\r\n\r\n // URL 형식 검증\r\n try {\r\n const urlObj = new URL(url);\r\n // 추가 검증: localhost, private IP 차단\r\n const hostname = urlObj.hostname.toLowerCase();\r\n if (\r\n hostname === \"localhost\" ||\r\n hostname.startsWith(\"127.\") ||\r\n hostname.startsWith(\"192.168.\") ||\r\n hostname.startsWith(\"10.\") ||\r\n hostname === \"169.254.169.254\" // AWS 메타데이터 서버\r\n ) {\r\n throw new Error(`${fieldName} cannot point to internal/private networks`);\r\n }\r\n } catch (error) {\r\n if (error instanceof Error && error.message.includes(\"cannot point to\")) {\r\n throw error;\r\n }\r\n throw new Error(`${fieldName} is not a valid URL format`);\r\n }\r\n\r\n return url;\r\n}\r\n\r\n// UUID 생성 함수 (crypto.randomUUID 또는 폴백)\r\nconst generateUUID = (): string => {\r\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\r\n return crypto.randomUUID();\r\n }\r\n // 폴백: 간단한 UUID v4 형식 생성\r\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n};\r\n\r\nexport const createS3Uploader = (config: S3UploaderConfig) => {\r\n const {\r\n apiEndpoint,\r\n env,\r\n path,\r\n fileNameTransform,\r\n appendUUID,\r\n preserveExtension = true,\r\n onProgress,\r\n uploadTimeoutMs = 120000,\r\n maxRetries = 2,\r\n } = config;\r\n\r\n // 필수 파라미터 검증\r\n if (!apiEndpoint || apiEndpoint.trim() === \"\") {\r\n throw new Error(\r\n \"apiEndpoint is required for S3 upload. Please provide a valid API endpoint.\"\r\n );\r\n }\r\n\r\n if (!env) {\r\n throw new Error(\"env is required. Must be 'development' or 'production'.\");\r\n }\r\n\r\n if (!path || path.trim() === \"\") {\r\n throw new Error(\"path is required and cannot be empty.\");\r\n }\r\n\r\n // 파일명에 UUID 추가하는 함수\r\n const appendUUIDToFileName = (filename: string): string => {\r\n const lastDotIndex = filename.lastIndexOf(\".\");\r\n if (lastDotIndex === -1) {\r\n // 확장자가 없는 경우\r\n return `${filename}_${generateUUID()}`;\r\n }\r\n const name = filename.substring(0, lastDotIndex);\r\n const ext = filename.substring(lastDotIndex);\r\n return `${name}_${generateUUID()}${ext}`;\r\n };\r\n\r\n // 계층 구조 파일명 생성 함수\r\n const generateHierarchicalFileName = (file: File): string => {\r\n // 0. 확장자 분리\r\n const originalName = file.name;\r\n const lastDotIndex = originalName.lastIndexOf(\".\");\r\n const nameWithoutExt =\r\n lastDotIndex === -1\r\n ? originalName\r\n : originalName.substring(0, lastDotIndex);\r\n const extension =\r\n lastDotIndex === -1 ? \"\" : originalName.substring(lastDotIndex);\r\n\r\n let filename = nameWithoutExt;\r\n\r\n // 1. 사용자 정의 파일명 변환 콜백 적용 (확장자 제외한 이름만)\r\n if (fileNameTransform) {\r\n filename = fileNameTransform(filename, file);\r\n }\r\n\r\n // 2. UUID 자동 추가 (appendUUID가 true인 경우)\r\n if (appendUUID) {\r\n filename = `${filename}_${generateUUID()}`;\r\n }\r\n\r\n // 3. 확장자 다시 붙이기 (preserveExtension이 true인 경우만)\r\n if (preserveExtension) {\r\n filename = `${filename}${extension}`;\r\n }\r\n\r\n // {env}/{path}/{filename}\r\n return `${env}/${path}/${filename}`;\r\n };\r\n\r\n const debugLog = (loc: string, msg: string, data: Record<string, unknown>) => {\r\n const p = fetch(\"http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a\", {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\", \"X-Debug-Session-Id\": \"b73262\" },\r\n body: JSON.stringify({ sessionId: \"b73262\", location: loc, message: msg, data, timestamp: Date.now() }),\r\n });\r\n if (p && typeof (p as Promise<unknown>).catch === \"function\") (p as Promise<unknown>).catch(() => {});\r\n };\r\n\r\n return async (file: File): Promise<string> => {\r\n try {\r\n if (!apiEndpoint || apiEndpoint.trim() === \"\") {\r\n throw new Error(\r\n \"Invalid apiEndpoint: Cannot upload file without a valid API ENDPOINT\"\r\n );\r\n }\r\n\r\n const fileName = generateHierarchicalFileName(file);\r\n const contentType = file.type || \"application/octet-stream\";\r\n const presignedUrlFull = `${apiEndpoint}?key=${encodeURIComponent(fileName)}&contentType=${encodeURIComponent(contentType)}`;\r\n const tPresigned = Date.now();\r\n // #region agent log\r\n debugLog(\"s3:step1:presignedReq\", \"fetching presigned URL\", {\r\n fileName,\r\n contentType,\r\n apiEndpoint,\r\n });\r\n // #endregion\r\n const response = await fetch(presignedUrlFull);\r\n\r\n // #region agent log\r\n debugLog(\"s3:step2:presignedRes\", \"presigned response\", {\r\n ok: response.ok,\r\n status: response.status,\r\n elapsedMs: Date.now() - tPresigned,\r\n });\r\n // #endregion\r\n if (!response.ok) {\r\n const errorText = (await response.text()) || \"\";\r\n debugLog(\"s3:step2b:presignedErr\", \"presigned failed\", {\r\n status: response.status,\r\n errorText: errorText.slice(0, 200),\r\n });\r\n throw new Error(\r\n `Failed to get presigned URL: ${response.statusText}, ${errorText}`\r\n );\r\n }\r\n\r\n const responseData = await response.json();\r\n const { presignedUrl, publicUrl } = responseData;\r\n const validatedPresignedUrl = validateS3Url(presignedUrl, \"presignedUrl\");\r\n const validatedPublicUrl = validateS3Url(publicUrl, \"publicUrl\");\r\n\r\n const tPut = Date.now();\r\n // #region agent log\r\n debugLog(\"s3:step3:putReq\", \"S3 PUT request\", { publicUrlLen: validatedPublicUrl?.length });\r\n // #endregion\r\n\r\n let lastError: Error | undefined;\r\n const attempts = maxRetries + 1;\r\n for (let attempt = 0; attempt < attempts; attempt++) {\r\n try {\r\n if (onProgress && typeof XMLHttpRequest !== \"undefined\") {\r\n await new Promise<void>((resolve, reject) => {\r\n const xhr = new XMLHttpRequest();\r\n xhr.timeout = uploadTimeoutMs;\r\n\r\n // --- 진행률 보간용 상태 (progress 이벤트가 드물 때 중간 % 표시) ---\r\n let lastReported = -1; // 마지막으로 콜백에 넘긴 퍼센트 (중복 호출 방지)\r\n const REPORT_INTERVAL_MS = 100; // 보간 타이머 주기(ms)\r\n const simulatedCap = 90; // 보간 진행률 상한(%). 90 이상은 실제 progress 값 사용\r\n let simulatedPercent = 0;\r\n\r\n // 보간 타이머: progress 이벤트가 잘 오지 않을 때 주기적으로 진행률 상승\r\n const simId = setInterval(() => {\r\n if (simulatedPercent >= simulatedCap) return;\r\n simulatedPercent = Math.min(simulatedCap, simulatedPercent + 3);\r\n const p = Math.min(100, simulatedPercent);\r\n if (p > lastReported) {\r\n lastReported = p;\r\n onProgress(p);\r\n }\r\n }, REPORT_INTERVAL_MS);\r\n const clearSim = () => {\r\n clearInterval(simId);\r\n };\r\n\r\n // XHR 실제 업로드 진행률 (loaded/total)\r\n xhr.upload.onprogress = (e) => {\r\n if (e.lengthComputable) {\r\n const p = Math.min(100, Math.round((e.loaded / e.total) * 100));\r\n if (p >= simulatedCap) clearSim(); // 실제 진행이 90% 넘으면 보간 타이머 중단\r\n const toReport = Math.max(p, simulatedPercent); // 실제 vs 보간 중 큰 값 사용\r\n if (toReport > lastReported) {\r\n lastReported = toReport;\r\n onProgress(toReport);\r\n }\r\n }\r\n };\r\n xhr.onload = () => {\r\n clearSim();\r\n if (xhr.status >= 200 && xhr.status < 300) {\r\n if (lastReported < 100) onProgress(100); // 완료 시 100% 한 번 더 보장\r\n resolve();\r\n } else {\r\n reject(new Error(`Failed to upload file: ${xhr.statusText}`));\r\n }\r\n };\r\n xhr.onerror = () => {\r\n clearSim();\r\n reject(new Error(\"Upload failed\"));\r\n };\r\n xhr.ontimeout = () => {\r\n clearSim();\r\n reject(new Error(\"Upload timeout\"));\r\n };\r\n xhr.open(\"PUT\", validatedPresignedUrl);\r\n xhr.setRequestHeader(\"Content-Type\", file.type || \"application/octet-stream\");\r\n onProgress(0); // 업로드 시작 직후 0% 알림\r\n lastReported = 0;\r\n xhr.send(file);\r\n });\r\n } else {\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), uploadTimeoutMs);\r\n const uploadResponse = await fetch(validatedPresignedUrl, {\r\n method: \"PUT\",\r\n headers: {\r\n \"Content-Type\": file.type || \"application/octet-stream\",\r\n },\r\n body: file,\r\n signal: controller.signal,\r\n });\r\n clearTimeout(timeoutId);\r\n\r\n // #region agent log\r\n debugLog(\"s3:step4:putRes\", \"S3 PUT response\", {\r\n ok: uploadResponse.ok,\r\n status: uploadResponse.status,\r\n putElapsedMs: Date.now() - tPut,\r\n });\r\n // #endregion\r\n if (!uploadResponse.ok) {\r\n throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);\r\n }\r\n }\r\n debugLog(\"s3:step5:return\", \"returning publicUrl\", { urlPrefix: validatedPublicUrl.slice(0, 80) });\r\n return validatedPublicUrl;\r\n } catch (err) {\r\n lastError = err instanceof Error ? err : new Error(String(err));\r\n if (attempt < attempts - 1) {\r\n debugLog(\"s3:putRetry\", \"PUT failed, retrying\", { attempt: attempt + 1, attempts });\r\n } else {\r\n throw lastError;\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(\"Upload failed\");\r\n } catch (error) {\r\n console.error(\"S3 upload failed:\", error);\r\n throw error;\r\n }\r\n };\r\n};\r\n","import { createReactBlockSpec } from \"@blocknote/react\";\r\nimport {\r\n defaultBlockSpecs,\r\n BlockNoteSchema,\r\n defaultInlineContentSpecs,\r\n defaultStyleSpecs,\r\n} from \"@blocknote/core\";\r\nimport { LinkPreviewBlock } from \"./LinkPreview\";\r\nimport { VideoBlock } from \"./VideoBlock\";\r\nimport { useState, useRef, useCallback, useEffect } from \"react\";\r\n\r\n// HTML 미리보기 블록 속성 타입\r\nexport interface HtmlPreviewProps {\r\n htmlContent: string;\r\n fileName?: string;\r\n height?: string;\r\n}\r\n\r\n// 최소/최대 높이 상수\r\n/** @internal 테스트용 export */\r\nexport const MIN_HEIGHT = 100;\r\n/** @internal 테스트용 export */\r\nexport const MAX_HEIGHT = 1200;\r\n\r\n// ============================================\r\n// 보안 유틸리티 함수\r\n// ============================================\r\n\r\n/**\r\n * HTML에 charset이 없으면 UTF-8 meta 태그 추가\r\n * (원본 HTML을 최소한으로만 수정하여 인코딩 깨짐 방지)\r\n * @internal 테스트용 export\r\n */\r\nexport const ensureCharset = (html: string): string => {\r\n // 이미 charset이 있으면 원본 그대로 반환\r\n const hasCharset = /<meta[^>]+charset\\s*=/i.test(html);\r\n if (hasCharset) {\r\n return html;\r\n }\r\n\r\n // <head> 태그가 있으면 그 안에 추가\r\n if (/<head[^>]*>/i.test(html)) {\r\n return html.replace(/(<head[^>]*>)/i, '$1\\n<meta charset=\"UTF-8\">');\r\n }\r\n\r\n // <html> 태그만 있으면 <head> 추가\r\n if (/<html[^>]*>/i.test(html)) {\r\n return html.replace(\r\n /(<html[^>]*>)/i,\r\n '$1\\n<head><meta charset=\"UTF-8\"></head>'\r\n );\r\n }\r\n\r\n // HTML fragment인 경우 최소한의 구조 추가\r\n return `<!DOCTYPE html>\r\n<html>\r\n<head><meta charset=\"UTF-8\"></head>\r\n<body>\r\n${html}\r\n</body>\r\n</html>`;\r\n};\r\n\r\n/**\r\n * 파일명 새니타이제이션 (경로 조작 방지)\r\n * @internal 테스트용 export\r\n */\r\nexport const sanitizeFileName = (fileName: string): string => {\r\n if (!fileName || typeof fileName !== \"string\") {\r\n return `document_${Date.now()}.html`;\r\n }\r\n\r\n return (\r\n fileName\r\n .replace(/\\0/g, \"\") // Null byte 제거\r\n .replace(/[\\/\\\\]/g, \"_\") // 경로 구분자 제거\r\n .replace(/[<>:\"|?*\\x00-\\x1f]/g, \"\") // 위험한 문자 제거\r\n .replace(/\\.{2,}/g, \".\") // 연속된 점 제거\r\n .trim()\r\n .replace(/^\\.+|\\.+$/g, \"\") || `document_${Date.now()}.html` // 앞뒤 점 제거\r\n );\r\n};\r\n\r\n/**\r\n * Blob URL 생성 (UTF-8 인코딩 명시)\r\n * @internal 테스트용 export\r\n */\r\nexport const createSecureBlobUrl = (htmlContent: string): string => {\r\n const htmlWithCharset = ensureCharset(htmlContent);\r\n\r\n // UTF-8 인코딩 명시\r\n const blob = new Blob([htmlWithCharset], {\r\n type: \"text/html;charset=utf-8\",\r\n });\r\n\r\n return URL.createObjectURL(blob);\r\n};\r\n\r\n// ============================================\r\n// HTML 미리보기 블록 스펙\r\n// ============================================\r\n\r\nexport const HtmlPreviewBlock = createReactBlockSpec(\r\n {\r\n type: \"htmlPreview\",\r\n propSchema: {\r\n htmlContent: {\r\n default: \"\",\r\n },\r\n fileName: {\r\n default: \"\",\r\n },\r\n height: {\r\n default: \"400px\",\r\n },\r\n },\r\n content: \"none\",\r\n },\r\n {\r\n render: (props) => {\r\n const [isExpanded, setIsExpanded] = useState(true);\r\n const [isResizing, setIsResizing] = useState(false);\r\n const [blobUrl, setBlobUrl] = useState<string>(\"\");\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n\r\n const htmlContent = props.block.props.htmlContent || \"\";\r\n const fileName = props.block.props.fileName || \"HTML Document\";\r\n const savedHeight = props.block.props.height || \"400px\";\r\n\r\n // 현재 높이 (숫자로 파싱)\r\n const currentHeight = parseInt(savedHeight, 10) || 400;\r\n\r\n // UTF-8 인코딩 보장된 Blob URL 생성\r\n useEffect(() => {\r\n if (htmlContent) {\r\n const url = createSecureBlobUrl(htmlContent);\r\n setBlobUrl(url);\r\n\r\n return () => {\r\n URL.revokeObjectURL(url);\r\n };\r\n }\r\n }, [htmlContent]);\r\n\r\n // 리사이즈 시작\r\n const handleResizeStart = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setIsResizing(true);\r\n\r\n const startY = e.clientY;\r\n const startHeight = currentHeight;\r\n\r\n const handleMouseMove = (moveEvent: MouseEvent) => {\r\n const deltaY = moveEvent.clientY - startY;\r\n const newHeight = Math.min(\r\n MAX_HEIGHT,\r\n Math.max(MIN_HEIGHT, startHeight + deltaY)\r\n );\r\n\r\n // 블록 props 업데이트 (저장됨)\r\n props.editor.updateBlock(props.block, {\r\n props: { height: `${newHeight}px` },\r\n });\r\n };\r\n\r\n const handleMouseUp = () => {\r\n setIsResizing(false);\r\n document.removeEventListener(\"mousemove\", handleMouseMove);\r\n document.removeEventListener(\"mouseup\", handleMouseUp);\r\n };\r\n\r\n document.addEventListener(\"mousemove\", handleMouseMove);\r\n document.addEventListener(\"mouseup\", handleMouseUp);\r\n },\r\n [currentHeight, props.editor, props.block]\r\n );\r\n\r\n // HTML 파일 다운로드 (원본 그대로 + 인코딩 보장)\r\n const handleExport = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n\r\n // 파일명 새니타이제이션 (경로 조작 방지)\r\n const safeFileName = sanitizeFileName(fileName);\r\n const downloadName = safeFileName.endsWith(\".html\")\r\n ? safeFileName\r\n : `${safeFileName}.html`;\r\n\r\n // UTF-8 인코딩 명시\r\n const htmlWithCharset = ensureCharset(htmlContent);\r\n const blob = new Blob([htmlWithCharset], {\r\n type: \"text/html;charset=utf-8\",\r\n });\r\n\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement(\"a\");\r\n a.href = url;\r\n a.download = downloadName;\r\n a.rel = \"noopener noreferrer\"; // 보안 속성 추가\r\n\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n },\r\n [htmlContent, fileName]\r\n );\r\n\r\n // 새 창에서 열기 (Blob URL 방식 - XSS 방지)\r\n const handleOpenNewWindow = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n\r\n // 클라이언트 사이드에서만 실행\r\n if (typeof window === \"undefined\") return;\r\n\r\n // Blob URL 생성 (UTF-8 인코딩 보장)\r\n const url = createSecureBlobUrl(htmlContent);\r\n\r\n // noopener, noreferrer로 보안 강화\r\n const newWindow = window.open(url, \"_blank\", \"noopener,noreferrer\");\r\n\r\n // Blob URL 정리\r\n if (newWindow) {\r\n setTimeout(() => URL.revokeObjectURL(url), 1000);\r\n } else {\r\n URL.revokeObjectURL(url);\r\n }\r\n },\r\n [htmlContent]\r\n );\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n style={{\r\n border: \"1px solid #e0e0e0\",\r\n borderRadius: \"8px\",\r\n overflow: \"hidden\",\r\n backgroundColor: \"#f9f9f9\",\r\n marginBottom: \"2px\",\r\n width: \"100%\",\r\n userSelect: isResizing ? \"none\" : \"auto\",\r\n outline: \"none\",\r\n boxShadow: \"none\",\r\n }}\r\n >\r\n {/* 헤더 */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n padding: \"4px 16px\",\r\n backgroundColor: \"#fff\",\r\n borderBottom: isExpanded ? \"1px solid #e0e0e0\" : \"none\",\r\n }}\r\n >\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n cursor: \"pointer\",\r\n flex: 1,\r\n }}\r\n onClick={() => setIsExpanded(!isExpanded)}\r\n >\r\n <svg\r\n width=\"16\"\r\n height=\"16\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n style={{\r\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\r\n transition: \"transform 0.2s\",\r\n }}\r\n >\r\n <polyline points=\"6 9 12 15 18 9\"></polyline>\r\n </svg>\r\n\r\n <span style={{ fontWeight: 500, fontSize: \"14px\" }}>\r\n {fileName}\r\n </span>\r\n </div>\r\n\r\n {/* 액션 버튼들 */}\r\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"4px\" }}>\r\n {/* 새 창에서 열기 버튼 */}\r\n <button\r\n onClick={handleOpenNewWindow}\r\n style={{\r\n background: \"none\",\r\n border: \"none\",\r\n cursor: \"pointer\",\r\n padding: \"4px\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n color: \"#666\",\r\n borderRadius: \"4px\",\r\n }}\r\n title=\"새 창에서 열기\"\r\n type=\"button\"\r\n onMouseEnter={(e) => {\r\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\r\n \"#f0f0f0\";\r\n }}\r\n onMouseLeave={(e) => {\r\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\r\n \"transparent\";\r\n }}\r\n >\r\n <svg\r\n width=\"16\"\r\n height=\"16\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"></path>\r\n <polyline points=\"15 3 21 3 21 9\"></polyline>\r\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"></line>\r\n </svg>\r\n </button>\r\n\r\n {/* 다운로드 버튼 */}\r\n <button\r\n onClick={handleExport}\r\n style={{\r\n background: \"none\",\r\n border: \"none\",\r\n cursor: \"pointer\",\r\n padding: \"4px\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n color: \"#666\",\r\n borderRadius: \"4px\",\r\n }}\r\n title=\"HTML 다운로드\"\r\n type=\"button\"\r\n onMouseEnter={(e) => {\r\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\r\n \"#f0f0f0\";\r\n }}\r\n onMouseLeave={(e) => {\r\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\r\n \"transparent\";\r\n }}\r\n >\r\n <svg\r\n width=\"16\"\r\n height=\"16\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\r\n <polyline points=\"7 10 12 15 17 10\"></polyline>\r\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"></line>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* iframe 미리보기 */}\r\n {isExpanded && (\r\n <div\r\n style={{\r\n padding: \"0\",\r\n backgroundColor: \"#fff\",\r\n position: \"relative\",\r\n }}\r\n >\r\n {/* 🔒 보안 강화: JavaScript 완전 차단 + 부모 페이지 접근 차단 */}\r\n <iframe\r\n src={blobUrl || \"about:blank\"}\r\n style={{\r\n width: \"100%\",\r\n height: `${currentHeight}px`,\r\n border: \"none\",\r\n display: \"block\",\r\n pointerEvents: isResizing ? \"none\" : \"auto\",\r\n }}\r\n // 🔒 allow-scripts 제거 = JavaScript 실행 차단\r\n // 🔒 allow-same-origin 제거 = 부모 페이지 접근 차단\r\n // ✅ HTML + CSS만 렌더링 (안전)\r\n sandbox=\"allow-popups allow-forms\"\r\n title={fileName}\r\n referrerPolicy=\"no-referrer\"\r\n loading=\"lazy\"\r\n />\r\n\r\n {/* 리사이즈 핸들 */}\r\n <div\r\n onMouseDown={handleResizeStart}\r\n style={{\r\n position: \"absolute\",\r\n bottom: 0,\r\n left: 0,\r\n right: 0,\r\n height: \"12px\",\r\n cursor: \"ns-resize\",\r\n backgroundColor: isResizing\r\n ? \"rgba(59, 130, 246, 0.3)\"\r\n : \"transparent\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n transition: \"background-color 0.2s\",\r\n }}\r\n onMouseEnter={(e) => {\r\n (e.currentTarget as HTMLDivElement).style.backgroundColor =\r\n \"rgba(59, 130, 246, 0.2)\";\r\n }}\r\n onMouseLeave={(e) => {\r\n if (!isResizing) {\r\n (e.currentTarget as HTMLDivElement).style.backgroundColor =\r\n \"transparent\";\r\n }\r\n }}\r\n >\r\n {/* 리사이즈 핸들 아이콘 */}\r\n <div\r\n style={{\r\n width: \"40px\",\r\n height: \"4px\",\r\n backgroundColor: \"#ccc\",\r\n borderRadius: \"2px\",\r\n }}\r\n />\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n },\r\n }\r\n);\r\n\r\n// 커스텀 블록이 포함된 스키마 생성\r\nexport const schema = BlockNoteSchema.create({\r\n blockSpecs: {\r\n ...defaultBlockSpecs,\r\n htmlPreview: HtmlPreviewBlock,\r\n linkPreview: LinkPreviewBlock,\r\n video: VideoBlock,\r\n },\r\n inlineContentSpecs: defaultInlineContentSpecs,\r\n styleSpecs: defaultStyleSpecs,\r\n});\r\n\r\n// 스키마 타입 export\r\nexport type HtmlPreviewSchema = typeof schema;\r\n","import { createReactBlockSpec } from \"@blocknote/react\";\r\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\r\nimport { DEFAULT_LINK_PREVIEW_IMAGE } from \"./defaultLogo\";\r\n\r\nexport interface LinkMetadata {\r\n url: string;\r\n title: string;\r\n description?: string;\r\n image?: string;\r\n domain: string;\r\n}\r\n\r\nconst metadataCache = new Map<string, LinkMetadata>();\r\n\r\nexport async function fetchLinkMetadata(\r\n url: string,\r\n apiEndpoint: string\r\n): Promise<LinkMetadata> {\r\n const cached = metadataCache.get(url);\r\n if (cached) return cached;\r\n\r\n const response = await fetch(\r\n `${apiEndpoint}?url=${encodeURIComponent(url)}`\r\n );\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch metadata: ${response.status}`);\r\n }\r\n\r\n const metadata: LinkMetadata = await response.json();\r\n metadataCache.set(url, metadata);\r\n return metadata;\r\n}\r\n\r\nexport function clearMetadataCache() {\r\n metadataCache.clear();\r\n}\r\n\r\nfunction extractDomain(url: string): string {\r\n try {\r\n return new URL(url).hostname.replace(/^www\\./, \"\");\r\n } catch {\r\n return url;\r\n }\r\n}\r\n\r\nconst LinkPreviewCard = ({\r\n url,\r\n title,\r\n description,\r\n image,\r\n domain,\r\n editable,\r\n onDelete,\r\n width,\r\n onWidthChange,\r\n height,\r\n onHeightChange,\r\n}: {\r\n url: string;\r\n title: string;\r\n description: string;\r\n image: string;\r\n domain: string;\r\n editable: boolean;\r\n onDelete?: () => void;\r\n width?: number;\r\n onWidthChange?: (width: number) => void;\r\n height?: number;\r\n onHeightChange?: (height: number) => void;\r\n}) => {\r\n const [imgError, setImgError] = useState(false);\r\n const [hovered, setHovered] = useState(false);\r\n\r\n type ResizeParams = {\r\n handleUsed: \"left\" | \"right\" | \"bottom\";\r\n initialClientX: number;\r\n initialClientY: number;\r\n initialWidth: number;\r\n initialHeight: number;\r\n };\r\n const [resizeParams, setResizeParams] = useState<ResizeParams | undefined>(undefined);\r\n const [localWidth, setLocalWidth] = useState<number | undefined>(width);\r\n const [localHeight, setLocalHeight] = useState<number | undefined>(height);\r\n const cardRef = useRef<HTMLDivElement>(null);\r\n const justResizedRef = useRef(false);\r\n\r\n useEffect(() => { setLocalWidth(width); }, [width]);\r\n useEffect(() => { setLocalHeight(height); }, [height]);\r\n\r\n useEffect(() => {\r\n if (!resizeParams) return;\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n if (resizeParams.handleUsed === \"bottom\") {\r\n const delta = e.clientY - resizeParams.initialClientY;\r\n setLocalHeight(Math.min(Math.max(resizeParams.initialHeight + delta, 100), 600));\r\n } else {\r\n const delta = resizeParams.handleUsed === \"left\"\r\n ? resizeParams.initialClientX - e.clientX\r\n : e.clientX - resizeParams.initialClientX;\r\n setLocalWidth(Math.min(\r\n Math.max(resizeParams.initialWidth + delta, 200),\r\n cardRef.current?.parentElement?.clientWidth || 800\r\n ));\r\n }\r\n };\r\n\r\n const onMouseUp = () => {\r\n const handle = resizeParams.handleUsed;\r\n setResizeParams(undefined);\r\n justResizedRef.current = true;\r\n setTimeout(() => { justResizedRef.current = false; }, 50);\r\n if (handle === \"bottom\") {\r\n if (localHeight && onHeightChange) onHeightChange(localHeight);\r\n } else {\r\n if (localWidth && onWidthChange) onWidthChange(localWidth);\r\n }\r\n };\r\n\r\n window.addEventListener(\"mousemove\", onMouseMove);\r\n window.addEventListener(\"mouseup\", onMouseUp);\r\n return () => {\r\n window.removeEventListener(\"mousemove\", onMouseMove);\r\n window.removeEventListener(\"mouseup\", onMouseUp);\r\n };\r\n }, [resizeParams, localWidth, localHeight, onWidthChange, onHeightChange]);\r\n\r\n const handleLeftDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setResizeParams({\r\n handleUsed: \"left\",\r\n initialWidth: cardRef.current!.clientWidth,\r\n initialHeight: localHeight || 200,\r\n initialClientX: e.clientX,\r\n initialClientY: e.clientY,\r\n });\r\n }, [localHeight]);\r\n\r\n const handleRightDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setResizeParams({\r\n handleUsed: \"right\",\r\n initialWidth: cardRef.current!.clientWidth,\r\n initialHeight: localHeight || 200,\r\n initialClientX: e.clientX,\r\n initialClientY: e.clientY,\r\n });\r\n }, [localHeight]);\r\n\r\n const handleBottomDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setResizeParams({\r\n handleUsed: \"bottom\",\r\n initialWidth: cardRef.current!.clientWidth,\r\n initialHeight: localHeight || 200,\r\n initialClientX: e.clientX,\r\n initialClientY: e.clientY,\r\n });\r\n }, [localHeight]);\r\n\r\n const handleClick = useCallback(() => {\r\n if (url && !resizeParams && !justResizedRef.current) {\r\n window.open(url, \"_blank\", \"noopener,noreferrer\");\r\n }\r\n }, [url, resizeParams]);\r\n\r\n const resizeCursor = resizeParams\r\n ? resizeParams.handleUsed === \"bottom\" ? \"ns-resize\" : \"ew-resize\"\r\n : \"pointer\";\r\n\r\n return (\r\n <div\r\n ref={cardRef}\r\n className=\"lumir-link-preview-card\"\r\n onClick={handleClick}\r\n style={{\r\n border: \"1px solid #e0e0e0\",\r\n borderRadius: \"8px\",\r\n overflow: \"hidden\",\r\n cursor: resizeCursor,\r\n width: localWidth ? `${localWidth}px` : undefined,\r\n maxWidth: \"100%\",\r\n backgroundColor: \"#fff\",\r\n transition: resizeParams ? \"none\" : \"box-shadow 0.2s\",\r\n position: \"relative\",\r\n }}\r\n onMouseEnter={() => {\r\n if (!resizeParams) setHovered(true);\r\n }}\r\n onMouseLeave={() => {\r\n if (!resizeParams) setHovered(false);\r\n }}\r\n >\r\n {editable && onDelete && (\r\n <button\r\n type=\"button\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onDelete();\r\n }}\r\n className=\"lumir-link-preview-delete\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"8px\",\r\n right: \"8px\",\r\n width: \"24px\",\r\n height: \"24px\",\r\n borderRadius: \"50%\",\r\n border: \"none\",\r\n backgroundColor: \"rgba(0,0,0,0.5)\",\r\n color: \"#fff\",\r\n cursor: \"pointer\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n fontSize: \"14px\",\r\n lineHeight: 1,\r\n zIndex: 2,\r\n opacity: 0,\r\n transition: \"opacity 0.2s\",\r\n }}\r\n title=\"삭제\"\r\n >\r\n ✕\r\n </button>\r\n )}\r\n\r\n {editable && (hovered || resizeParams) && (\r\n <>\r\n <div\r\n className=\"lumir-resize-handle\"\r\n style={{ left: \"4px\" }}\r\n onMouseDown={handleLeftDown}\r\n />\r\n <div\r\n className=\"lumir-resize-handle\"\r\n style={{ right: \"4px\" }}\r\n onMouseDown={handleRightDown}\r\n />\r\n </>\r\n )}\r\n\r\n {image && !imgError && (\r\n <div\r\n style={{\r\n width: \"100%\",\r\n height: `${localHeight || 200}px`,\r\n overflow: \"hidden\",\r\n backgroundColor: \"#f0f0f0\",\r\n position: \"relative\",\r\n }}\r\n >\r\n <img\r\n src={image}\r\n alt={title || \"Link preview\"}\r\n onError={() => setImgError(true)}\r\n style={{\r\n width: \"100%\",\r\n height: \"100%\",\r\n objectFit: \"cover\",\r\n display: \"block\",\r\n }}\r\n referrerPolicy=\"no-referrer\"\r\n loading=\"lazy\"\r\n />\r\n {editable && (hovered || resizeParams) && (\r\n <div\r\n className=\"lumir-resize-handle-bottom\"\r\n onMouseDown={handleBottomDown}\r\n />\r\n )}\r\n </div>\r\n )}\r\n\r\n <div style={{ padding: \"12px 16px\" }}>\r\n <div\r\n style={{\r\n fontSize: \"14px\",\r\n fontWeight: 600,\r\n color: \"#1a1a1a\",\r\n lineHeight: 1.4,\r\n marginBottom: description ? \"4px\" : \"8px\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {title || domain}\r\n </div>\r\n\r\n {description && (\r\n <div\r\n style={{\r\n fontSize: \"12px\",\r\n color: \"#666\",\r\n lineHeight: 1.4,\r\n marginBottom: \"8px\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n display: \"-webkit-box\",\r\n WebkitLineClamp: 2,\r\n WebkitBoxOrient: \"vertical\",\r\n }}\r\n >\r\n {description}\r\n </div>\r\n )}\r\n\r\n <div\r\n style={{\r\n fontSize: \"12px\",\r\n color: \"#999\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {domain}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nconst LinkPreviewSkeleton = () => (\r\n <div\r\n className=\"lumir-link-preview-skeleton\"\r\n style={{\r\n border: \"1px solid #e0e0e0\",\r\n borderRadius: \"8px\",\r\n overflow: \"hidden\",\r\n maxWidth: \"400px\",\r\n backgroundColor: \"#fff\",\r\n }}\r\n >\r\n <div\r\n style={{\r\n width: \"100%\",\r\n height: \"200px\",\r\n backgroundColor: \"#f0f0f0\",\r\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\r\n }}\r\n />\r\n <div style={{ padding: \"12px 16px\" }}>\r\n <div\r\n style={{\r\n height: \"16px\",\r\n width: \"70%\",\r\n backgroundColor: \"#f0f0f0\",\r\n borderRadius: \"4px\",\r\n marginBottom: \"8px\",\r\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\r\n }}\r\n />\r\n <div\r\n style={{\r\n height: \"12px\",\r\n width: \"90%\",\r\n backgroundColor: \"#f0f0f0\",\r\n borderRadius: \"4px\",\r\n marginBottom: \"8px\",\r\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\r\n }}\r\n />\r\n <div\r\n style={{\r\n height: \"12px\",\r\n width: \"40%\",\r\n backgroundColor: \"#f0f0f0\",\r\n borderRadius: \"4px\",\r\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\r\n }}\r\n />\r\n </div>\r\n </div>\r\n);\r\n\r\nconst LinkPreviewError = ({\r\n url,\r\n onRetry,\r\n}: {\r\n url: string;\r\n onRetry?: () => void;\r\n}) => {\r\n const domain = (() => {\r\n try { return new URL(url).hostname; } catch { return url; }\r\n })();\r\n\r\n return (\r\n <div\r\n className=\"lumir-link-preview-error\"\r\n style={{\r\n border: \"1px solid #e0e0e0\",\r\n borderRadius: \"8px\",\r\n overflow: \"hidden\",\r\n maxWidth: \"400px\",\r\n backgroundColor: \"#fff\",\r\n cursor: \"pointer\",\r\n position: \"relative\",\r\n }}\r\n onClick={() => window.open(url, \"_blank\", \"noopener,noreferrer\")}\r\n >\r\n <div\r\n style={{\r\n width: \"100%\",\r\n height: \"160px\",\r\n overflow: \"hidden\",\r\n backgroundColor: \"#f0f0f0\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n }}\r\n >\r\n <img\r\n src={DEFAULT_LINK_PREVIEW_IMAGE}\r\n alt=\"Lumir\"\r\n style={{\r\n width: \"100%\",\r\n height: \"100%\",\r\n objectFit: \"contain\",\r\n display: \"block\",\r\n padding: \"20px\",\r\n boxSizing: \"border-box\",\r\n }}\r\n />\r\n </div>\r\n <div style={{ padding: \"12px 16px\" }}>\r\n <div\r\n style={{\r\n fontSize: \"13px\",\r\n color: \"#999\",\r\n marginBottom: \"4px\",\r\n }}\r\n >\r\n 미리보기를 불러올 수 없습니다\r\n </div>\r\n <div\r\n style={{\r\n fontSize: \"12px\",\r\n color: \"#1a73e8\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {domain}\r\n </div>\r\n </div>\r\n {onRetry && (\r\n <button\r\n type=\"button\"\r\n onClick={(e) => { e.stopPropagation(); onRetry(); }}\r\n style={{\r\n position: \"absolute\",\r\n top: \"8px\",\r\n right: \"8px\",\r\n background: \"rgba(0,0,0,0.5)\",\r\n border: \"none\",\r\n borderRadius: \"4px\",\r\n padding: \"4px 8px\",\r\n cursor: \"pointer\",\r\n fontSize: \"12px\",\r\n color: \"#fff\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n 재시도\r\n </button>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nconst LinkPreviewUrlInput = ({\r\n onSubmit,\r\n}: {\r\n onSubmit: (url: string) => void;\r\n}) => {\r\n const [inputUrl, setInputUrl] = useState(\"\");\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n\r\n useEffect(() => {\r\n inputRef.current?.focus();\r\n }, []);\r\n\r\n const handleSubmit = useCallback(() => {\r\n const trimmed = inputUrl.trim();\r\n if (!trimmed) return;\r\n const normalized = /^https?:\\/\\//i.test(trimmed)\r\n ? trimmed\r\n : `https://${trimmed}`;\r\n onSubmit(normalized);\r\n }, [inputUrl, onSubmit]);\r\n\r\n return (\r\n <div\r\n className=\"lumir-link-preview-input\"\r\n style={{\r\n border: \"1px solid #e0e0e0\",\r\n borderRadius: \"8px\",\r\n padding: \"16px\",\r\n maxWidth: \"400px\",\r\n backgroundColor: \"#fafafa\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n }}\r\n >\r\n <svg\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"#999\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n style={{ flexShrink: 0 }}\r\n >\r\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\r\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\r\n </svg>\r\n <input\r\n ref={inputRef}\r\n type=\"text\"\r\n value={inputUrl}\r\n onChange={(e) => setInputUrl(e.target.value)}\r\n onKeyDown={(e) => {\r\n if (e.key === \"Enter\") {\r\n e.preventDefault();\r\n handleSubmit();\r\n }\r\n }}\r\n placeholder=\"URL을 입력하세요 (예: https://example.com)\"\r\n style={{\r\n flex: 1,\r\n border: \"none\",\r\n outline: \"none\",\r\n backgroundColor: \"transparent\",\r\n fontSize: \"13px\",\r\n color: \"#333\",\r\n minWidth: 0,\r\n }}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={handleSubmit}\r\n disabled={!inputUrl.trim()}\r\n style={{\r\n flexShrink: 0,\r\n padding: \"4px 12px\",\r\n border: \"none\",\r\n borderRadius: \"4px\",\r\n backgroundColor: inputUrl.trim() ? \"#3b82f6\" : \"#d1d5db\",\r\n color: \"#fff\",\r\n fontSize: \"12px\",\r\n fontWeight: 500,\r\n cursor: inputUrl.trim() ? \"pointer\" : \"not-allowed\",\r\n transition: \"background-color 0.15s\",\r\n }}\r\n >\r\n 확인\r\n </button>\r\n </div>\r\n );\r\n};\r\n\r\nexport const LinkPreviewBlock = createReactBlockSpec(\r\n {\r\n type: \"linkPreview\",\r\n propSchema: {\r\n url: { default: \"\" },\r\n title: { default: \"\" },\r\n description: { default: \"\" },\r\n image: { default: \"\" },\r\n domain: { default: \"\" },\r\n previewWidth: { default: 400 as const },\r\n previewHeight: { default: 200 as const },\r\n },\r\n content: \"none\",\r\n },\r\n {\r\n render: (props) => {\r\n const { url, title, description, image, domain } =\r\n props.block.props;\r\n const [status, setStatus] = useState<\"idle\" | \"loading\" | \"error\">(\r\n !url ? \"idle\" : title ? \"idle\" : \"loading\"\r\n );\r\n const fetchedRef = useRef(false);\r\n\r\n const editable = props.editor.isEditable;\r\n\r\n useEffect(() => {\r\n if (!url || title || fetchedRef.current) {\r\n if (!url) setStatus(\"idle\");\r\n return;\r\n }\r\n\r\n const getApiEndpoint = () =>\r\n (props.editor as any)._linkPreviewApiEndpoint as\r\n | string\r\n | undefined;\r\n\r\n const doFetch = (endpoint: string) => {\r\n fetchedRef.current = true;\r\n setStatus(\"loading\");\r\n\r\n fetchLinkMetadata(url, endpoint)\r\n .then((metadata) => {\r\n props.editor.updateBlock(props.block, {\r\n props: {\r\n title: metadata.title || \"\",\r\n description: metadata.description || \"\",\r\n image: metadata.image || \"\",\r\n domain: metadata.domain || extractDomain(url),\r\n },\r\n });\r\n setStatus(\"idle\");\r\n })\r\n .catch(() => {\r\n props.editor.updateBlock(props.block, {\r\n props: { domain: extractDomain(url) },\r\n });\r\n setStatus(\"error\");\r\n });\r\n };\r\n\r\n const endpoint = getApiEndpoint();\r\n if (endpoint) {\r\n doFetch(endpoint);\r\n } else {\r\n // endpoint가 아직 설정되지 않았을 수 있으므로 잠시 대기 후 재시도\r\n const timer = setTimeout(() => {\r\n const retryEndpoint = getApiEndpoint();\r\n if (retryEndpoint) {\r\n doFetch(retryEndpoint);\r\n } else {\r\n setStatus(\"error\");\r\n }\r\n }, 100);\r\n return () => clearTimeout(timer);\r\n }\r\n }, [url, title]);\r\n\r\n const handleRetry = useCallback(() => {\r\n const endpoint = (props.editor as any)._linkPreviewApiEndpoint as\r\n | string\r\n | undefined;\r\n if (!url || !endpoint) return;\r\n metadataCache.delete(url);\r\n fetchedRef.current = false;\r\n setStatus(\"loading\");\r\n\r\n fetchLinkMetadata(url, endpoint)\r\n .then((metadata) => {\r\n props.editor.updateBlock(props.block, {\r\n props: {\r\n title: metadata.title || \"\",\r\n description: metadata.description || \"\",\r\n image: metadata.image || \"\",\r\n domain: metadata.domain || extractDomain(url),\r\n },\r\n });\r\n setStatus(\"idle\");\r\n })\r\n .catch(() => {\r\n setStatus(\"error\");\r\n });\r\n }, [url, props.editor, props.block]);\r\n\r\n const handleDelete = useCallback(() => {\r\n props.editor.removeBlocks([props.block]);\r\n }, [props.editor, props.block]);\r\n\r\n if (!url) {\r\n if (!editable) {\r\n return null;\r\n }\r\n return (\r\n <LinkPreviewUrlInput\r\n onSubmit={(newUrl) => {\r\n props.editor.updateBlock(props.block, {\r\n props: { url: newUrl },\r\n });\r\n }}\r\n />\r\n );\r\n }\r\n\r\n if (status === \"loading\") {\r\n return <LinkPreviewSkeleton />;\r\n }\r\n\r\n if (status === \"error\") {\r\n return <LinkPreviewError url={url} onRetry={handleRetry} />;\r\n }\r\n\r\n return (\r\n <LinkPreviewCard\r\n url={url}\r\n title={title}\r\n description={description}\r\n image={image}\r\n domain={domain || extractDomain(url)}\r\n editable={editable}\r\n onDelete={handleDelete}\r\n width={props.block.props.previewWidth}\r\n onWidthChange={(newWidth) => {\r\n props.editor.updateBlock(props.block, {\r\n props: { previewWidth: newWidth },\r\n });\r\n }}\r\n height={props.block.props.previewHeight}\r\n onHeightChange={(newHeight) => {\r\n props.editor.updateBlock(props.block, {\r\n props: { previewHeight: newHeight },\r\n });\r\n }}\r\n />\r\n );\r\n },\r\n }\r\n);\r\n","export const DEFAULT_LINK_PREVIEW_IMAGE = \"data:image/png;base64,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em1RHrY9EhgB5JWPq9DabLnDWKK8KrQqj2dIoXVQj+a8flLfBJN6T2FxKe//POeH76ctPvCWE/otMJ1HREREREREREREJJlUannNa4uGYNuPAV0rjavQ2my5w1iivCq0Ko9nSKGVFQzw84U706NFvQQTe9fcpetK3v1h9h3/N7TrVaaziIiIiIiIiIiIiCSLSi2veG1Rc+BubPvEKstUaG223GEsUV4VWpXHM6TQAjilfxueOKJngon9YdJfC+d+8du8g64+ZvufTGcRERERERERERERqS2VWl7w2qJTiBdaTaosU6G12XKHsUR5VWhVHs+gQis/J8jkS3elXaM8/G7l2iL77e9iYz79Ze7xz1y8R7HpPCIiIiIiIiIiIiI1pVIrk722yAIeA4ZvU6GhQqvyGxVaniq0AC7bI8Rtw7skmNyffpu5bNWnv8w96pLDtvvQdBYRERERERERERGRmlCplYnGLA5g22cAdwMNVGhVZy6HsUR5VWhVHs+wQqtxnRymX7krjepkJ9iBf63bUMy7381655XPZxzx+nX7FprOIyIiIiIiIiIiIrItVGplmjGLO2LbTwFDgG0rNFRoVX6jQstzhRY23LF/Fy7ZI5RgBwLwxz9LV3/ww+xjLj+677ums4iIiIiIiIiIiIhUl0qtTDJm8WnY9n1AA0CFVrXmchhLlFeFVuXxDCy02jeqw+TLd6FOdqUl4mDdhmI++H7WW+9/N+uIJy7dU8/aEhEREREREREREddTqZUJxixuDjyBbR9SPqZCS4XWFrP6r9ACeOqonpy0Y5sEOxEnv85YsvzTH2fvf+m/tv/adBYRERERERERERGRLVGp5XZjFh8EPIlttygfU6GlQmuLWf1ZaPVqWZ+fL9qZgP5U22Yr1xTab07659GTh3U/z3QWERERERERERERkUR0+tetxizOB+4FzqpRMbWl11tarkJrC/tQoVWtdR23cd5tsgotgDdP7ssBPZon2JFUx4Rf58a++XPBblce32+W6SwiIiIiIiIiIiIim1Op5UZjFm8HvAr0UqFVzXVVaPm60NqtQwGfn90/wY5kW8xbsrb4va9nnnvGQb2eMJ1FREREREREREREpCKVWm4zZvFZwH1AHRVa1VxXhZavC60ANhPP3YmBVqMEO5NtVVRcyrtfRz/86NvogY9ePqTYdB4RERERERERERER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\";\r\n","import { createReactBlockSpec } from \"@blocknote/react\";\r\nimport React, { useState, useCallback, useRef, useEffect } from \"react\";\r\n\r\nconst MIN_VIDEO_WIDTH = 200;\r\nconst MAX_VIDEO_WIDTH = 1200;\r\nconst MIN_VIDEO_HEIGHT = 120;\r\nconst MAX_VIDEO_HEIGHT = 600;\r\nconst DEFAULT_VIDEO_WIDTH = 640;\r\nconst DEFAULT_VIDEO_HEIGHT = 360;\r\n\r\ntype ResizeParams = {\r\n handleUsed: \"left\" | \"right\" | \"bottom\";\r\n initialClientX: number;\r\n initialClientY: number;\r\n initialWidth: number;\r\n initialHeight: number;\r\n};\r\n\r\n/**\r\n * 비디오 블록 카드: 우클릭 방지 + 다운로드 버튼 미노출\r\n * - controlsList=\"nodownload\": 브라우저 기본 컨트롤에서 다운로드 버튼 숨김\r\n * - onContextMenu preventDefault: 우클릭 컨텍스트 메뉴(동영상 저장 등) 차단\r\n */\r\nconst VideoBlockCard = ({\r\n url,\r\n editable,\r\n width,\r\n onWidthChange,\r\n height,\r\n onHeightChange,\r\n onContextMenuBlock,\r\n}: {\r\n url: string;\r\n editable: boolean;\r\n width?: number;\r\n onWidthChange?: (width: number) => void;\r\n height?: number;\r\n onHeightChange?: (height: number) => void;\r\n onContextMenuBlock: (e: React.MouseEvent) => void;\r\n}) => {\r\n const [resizeParams, setResizeParams] = useState<ResizeParams | undefined>(\r\n undefined,\r\n );\r\n const [localWidth, setLocalWidth] = useState<number | undefined>(width);\r\n const [localHeight, setLocalHeight] = useState<number | undefined>(height);\r\n const wrapperRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n setLocalWidth(width);\r\n }, [width]);\r\n useEffect(() => {\r\n setLocalHeight(height);\r\n }, [height]);\r\n\r\n useEffect(() => {\r\n if (!resizeParams) return;\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n if (resizeParams.handleUsed === \"bottom\") {\r\n const delta = e.clientY - resizeParams.initialClientY;\r\n setLocalHeight(\r\n Math.min(\r\n Math.max(resizeParams.initialHeight + delta, MIN_VIDEO_HEIGHT),\r\n MAX_VIDEO_HEIGHT,\r\n ),\r\n );\r\n } else {\r\n const delta =\r\n resizeParams.handleUsed === \"left\"\r\n ? resizeParams.initialClientX - e.clientX\r\n : e.clientX - resizeParams.initialClientX;\r\n setLocalWidth(\r\n Math.min(\r\n Math.max(resizeParams.initialWidth + delta, MIN_VIDEO_WIDTH),\r\n wrapperRef.current?.parentElement?.clientWidth || MAX_VIDEO_WIDTH,\r\n ),\r\n );\r\n }\r\n };\r\n\r\n const onMouseUp = () => {\r\n const handle = resizeParams.handleUsed;\r\n setResizeParams(undefined);\r\n if (handle === \"bottom\") {\r\n if (localHeight != null && onHeightChange) onHeightChange(localHeight);\r\n } else {\r\n if (localWidth != null && onWidthChange) onWidthChange(localWidth);\r\n }\r\n };\r\n\r\n window.addEventListener(\"mousemove\", onMouseMove);\r\n window.addEventListener(\"mouseup\", onMouseUp);\r\n return () => {\r\n window.removeEventListener(\"mousemove\", onMouseMove);\r\n window.removeEventListener(\"mouseup\", onMouseUp);\r\n };\r\n }, [resizeParams, localWidth, localHeight, onWidthChange, onHeightChange]);\r\n\r\n const handleLeftDown = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setResizeParams({\r\n handleUsed: \"left\",\r\n initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,\r\n initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,\r\n initialClientX: e.clientX,\r\n initialClientY: e.clientY,\r\n });\r\n },\r\n [localHeight],\r\n );\r\n\r\n const handleRightDown = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setResizeParams({\r\n handleUsed: \"right\",\r\n initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,\r\n initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,\r\n initialClientX: e.clientX,\r\n initialClientY: e.clientY,\r\n });\r\n },\r\n [localHeight],\r\n );\r\n\r\n const handleBottomDown = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setResizeParams({\r\n handleUsed: \"bottom\",\r\n initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,\r\n initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,\r\n initialClientX: e.clientX,\r\n initialClientY: e.clientY,\r\n });\r\n },\r\n [localHeight],\r\n );\r\n\r\n const resizeCursor = resizeParams\r\n ? resizeParams.handleUsed === \"bottom\"\r\n ? \"ns-resize\"\r\n : \"ew-resize\"\r\n : \"default\";\r\n\r\n const [hovered, setHovered] = useState(false);\r\n\r\n return (\r\n <div\r\n ref={wrapperRef}\r\n className=\"lumir-video-block-wrapper\"\r\n onContextMenu={onContextMenuBlock}\r\n style={{\r\n position: \"relative\",\r\n width: localWidth != null ? `${localWidth}px` : undefined,\r\n maxWidth: \"100%\",\r\n cursor: resizeCursor,\r\n transition: resizeParams ? \"none\" : \"box-shadow 0.2s\",\r\n }}\r\n onMouseEnter={() => {\r\n if (!resizeParams) setHovered(true);\r\n }}\r\n onMouseLeave={() => {\r\n if (!resizeParams) setHovered(false);\r\n }}\r\n >\r\n {editable && (hovered || resizeParams) && (\r\n <>\r\n <div\r\n className=\"lumir-resize-handle\"\r\n style={{ left: \"4px\" }}\r\n onMouseDown={handleLeftDown}\r\n />\r\n <div\r\n className=\"lumir-resize-handle\"\r\n style={{ right: \"4px\" }}\r\n onMouseDown={handleRightDown}\r\n />\r\n </>\r\n )}\r\n\r\n <div\r\n style={{\r\n width: \"100%\",\r\n height: `${localHeight ?? DEFAULT_VIDEO_HEIGHT}px`,\r\n overflow: \"hidden\",\r\n backgroundColor: \"#000\",\r\n borderRadius: \"6px\",\r\n }}\r\n >\r\n <video\r\n src={url}\r\n controls\r\n controlsList=\"nodownload\"\r\n playsInline\r\n style={{\r\n width: \"100%\",\r\n height: \"100%\",\r\n objectFit: \"contain\",\r\n display: \"block\",\r\n }}\r\n onContextMenu={(e) => e.preventDefault()}\r\n />\r\n {editable && (hovered || resizeParams) && (\r\n <div\r\n className=\"lumir-resize-handle-bottom\"\r\n onMouseDown={handleBottomDown}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport const VideoBlock = createReactBlockSpec(\r\n {\r\n type: \"video\",\r\n propSchema: {\r\n url: { default: \"\" },\r\n previewWidth: { default: 640 },\r\n previewHeight: { default: 360 },\r\n },\r\n content: \"none\",\r\n },\r\n {\r\n render: (props) => {\r\n const url = props.block.props.url ?? \"\";\r\n const editable = props.editor.isEditable;\r\n\r\n const handleContextMenu = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }, []);\r\n\r\n if (!url) {\r\n return (\r\n <div\r\n className=\"lumir-video-block-placeholder\"\r\n onContextMenu={handleContextMenu}\r\n style={{\r\n width: \"100%\",\r\n maxWidth: `${DEFAULT_VIDEO_WIDTH}px`,\r\n height: `${DEFAULT_VIDEO_HEIGHT}px`,\r\n backgroundColor: \"#1a1a1a\",\r\n borderRadius: \"6px\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n color: \"rgba(255,255,255,0.5)\",\r\n fontSize: \"14px\",\r\n }}\r\n >\r\n 비디오 URL 없음\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <VideoBlockCard\r\n url={url}\r\n editable={editable}\r\n width={props.block.props.previewWidth}\r\n onWidthChange={(newWidth) => {\r\n props.editor.updateBlock(props.block, {\r\n props: { previewWidth: newWidth },\r\n });\r\n }}\r\n height={props.block.props.previewHeight}\r\n onHeightChange={(newHeight) => {\r\n props.editor.updateBlock(props.block, {\r\n props: { previewHeight: newHeight },\r\n });\r\n }}\r\n onContextMenuBlock={handleContextMenu}\r\n />\r\n );\r\n },\r\n },\r\n);\r\n","\"use client\";\r\n\r\nimport React, { useState, useEffect, useRef } from \"react\";\r\nimport type { EditorType } from \"../../types\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Icons } from \"./Icons\";\r\nimport {\r\n ToolbarDivider,\r\n UndoRedoButtons,\r\n TextStyleButton,\r\n AlignButton,\r\n ListButton,\r\n ImageButton,\r\n ColorButton,\r\n LinkButton,\r\n TableButton,\r\n HTMLImportButton,\r\n BlockTypeSelect,\r\n} from \"./components\";\r\n\r\n// 반응형 브레이크포인트 (px)\r\nconst COMPACT_BREAKPOINT = 700;\r\nconst MINIMIZED_BREAKPOINT = 400;\r\n\r\nexport interface FloatingMenuProps {\r\n editor: EditorType | any;\r\n position?: \"sticky\" | \"fixed\";\r\n className?: string;\r\n onImageUpload?: () => void;\r\n}\r\n\r\n/**\r\n * FloatingMenu - 에디터 상단 고정 툴바\r\n */\r\nexport const FloatingMenu: React.FC<FloatingMenuProps> = ({\r\n editor,\r\n position = \"sticky\",\r\n className,\r\n onImageUpload,\r\n}) => {\r\n const wrapperRef = useRef<HTMLDivElement>(null);\r\n const [isCompact, setIsCompact] = useState(false);\r\n const [isMinimizable, setIsMinimizable] = useState(false);\r\n const [isMinimized, setIsMinimized] = useState(false);\r\n // 선택 변경 시 리렌더링을 위한 카운터\r\n const [, setSelectionTick] = useState(0);\r\n\r\n // 선택 변경 감지 - 스타일 버튼 상태 업데이트를 위해 (디바운싱 적용)\r\n useEffect(() => {\r\n if (!editor) return;\r\n\r\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\r\n const DEBOUNCE_DELAY = 150;\r\n\r\n const handleSelectionChange = () => {\r\n if (debounceTimer) {\r\n clearTimeout(debounceTimer);\r\n }\r\n debounceTimer = setTimeout(() => {\r\n setSelectionTick((prev) => prev + 1);\r\n }, DEBOUNCE_DELAY);\r\n };\r\n\r\n const unsubscribe = editor.onSelectionChange?.(handleSelectionChange);\r\n const unsubscribeContent = editor.onEditorContentChange?.(() => {\r\n setSelectionTick((prev) => prev + 1);\r\n });\r\n\r\n return () => {\r\n if (debounceTimer) {\r\n clearTimeout(debounceTimer);\r\n }\r\n unsubscribe?.();\r\n unsubscribeContent?.();\r\n };\r\n }, [editor]);\r\n\r\n // 컨테이너 너비 감지\r\n useEffect(() => {\r\n const checkWidth = () => {\r\n if (wrapperRef.current) {\r\n const width = wrapperRef.current.offsetWidth;\r\n setIsCompact(width < COMPACT_BREAKPOINT);\r\n setIsMinimizable(width < MINIMIZED_BREAKPOINT);\r\n }\r\n };\r\n\r\n checkWidth();\r\n\r\n const resizeObserver = new ResizeObserver(checkWidth);\r\n if (wrapperRef.current) {\r\n resizeObserver.observe(wrapperRef.current);\r\n }\r\n\r\n return () => resizeObserver.disconnect();\r\n }, []);\r\n\r\n // 최소화된 레이아웃 (400px 이하)\r\n const MinimizedLayout = () => (\r\n <>\r\n <button\r\n className=\"lumir-toolbar-button lumir-toggle-button\"\r\n onClick={() => setIsMinimized(!isMinimized)}\r\n onMouseDown={(e) => e.preventDefault()}\r\n type=\"button\"\r\n title={isMinimized ? \"메뉴 펼치기\" : \"메뉴 접기\"}\r\n >\r\n {isMinimized ? Icons.chevronRight : Icons.chevronLeft}\r\n </button>\r\n {!isMinimized && (\r\n <>\r\n <ToolbarDivider />\r\n <UndoRedoButtons editor={editor} />\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <BlockTypeSelect editor={editor} />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <TextStyleButton editor={editor} style=\"bold\" />\r\n <TextStyleButton editor={editor} style=\"italic\" />\r\n <TextStyleButton editor={editor} style=\"underline\" />\r\n <TextStyleButton editor={editor} style=\"strike\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <AlignButton editor={editor} alignment=\"left\" />\r\n <AlignButton editor={editor} alignment=\"center\" />\r\n <AlignButton editor={editor} alignment=\"right\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ListButton editor={editor} type=\"bullet\" />\r\n <ListButton editor={editor} type=\"numbered\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ColorButton editor={editor} type=\"text\" />\r\n <ColorButton editor={editor} type=\"background\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ImageButton editor={editor} onImageUpload={onImageUpload} />\r\n <LinkButton editor={editor} />\r\n <TableButton editor={editor} />\r\n <HTMLImportButton editor={editor} />\r\n </div>\r\n </>\r\n )}\r\n </>\r\n );\r\n\r\n // 1단 레이아웃\r\n const SingleRowLayout = () => (\r\n <>\r\n <UndoRedoButtons editor={editor} />\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <BlockTypeSelect editor={editor} />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <TextStyleButton editor={editor} style=\"bold\" />\r\n <TextStyleButton editor={editor} style=\"italic\" />\r\n <TextStyleButton editor={editor} style=\"underline\" />\r\n <TextStyleButton editor={editor} style=\"strike\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <AlignButton editor={editor} alignment=\"left\" />\r\n <AlignButton editor={editor} alignment=\"center\" />\r\n <AlignButton editor={editor} alignment=\"right\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ListButton editor={editor} type=\"bullet\" />\r\n <ListButton editor={editor} type=\"numbered\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ColorButton editor={editor} type=\"text\" />\r\n <ColorButton editor={editor} type=\"background\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ImageButton editor={editor} onImageUpload={onImageUpload} />\r\n <LinkButton editor={editor} />\r\n <TableButton editor={editor} />\r\n <HTMLImportButton editor={editor} />\r\n </div>\r\n </>\r\n );\r\n\r\n // 2단 레이아웃\r\n const TwoRowLayout = () => (\r\n <>\r\n <div className=\"lumir-toolbar-row\">\r\n <UndoRedoButtons editor={editor} />\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <TextStyleButton editor={editor} style=\"bold\" />\r\n <TextStyleButton editor={editor} style=\"italic\" />\r\n <TextStyleButton editor={editor} style=\"underline\" />\r\n <TextStyleButton editor={editor} style=\"strike\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <AlignButton editor={editor} alignment=\"left\" />\r\n <AlignButton editor={editor} alignment=\"center\" />\r\n <AlignButton editor={editor} alignment=\"right\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ListButton editor={editor} type=\"bullet\" />\r\n <ListButton editor={editor} type=\"numbered\" />\r\n </div>\r\n </div>\r\n <div className=\"lumir-toolbar-row\">\r\n <div className=\"lumir-toolbar-group\">\r\n <BlockTypeSelect editor={editor} />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ColorButton editor={editor} type=\"text\" />\r\n <ColorButton editor={editor} type=\"background\" />\r\n </div>\r\n <ToolbarDivider />\r\n <div className=\"lumir-toolbar-group\">\r\n <ImageButton editor={editor} onImageUpload={onImageUpload} />\r\n <LinkButton editor={editor} />\r\n <TableButton editor={editor} />\r\n <HTMLImportButton editor={editor} />\r\n </div>\r\n </div>\r\n </>\r\n );\r\n\r\n return (\r\n <div\r\n ref={wrapperRef}\r\n className={cn(\r\n \"lumir-floating-toolbar-wrapper\",\r\n isMinimizable && \"is-minimizable\",\r\n className\r\n )}\r\n data-position={position}\r\n >\r\n <div\r\n className={cn(\r\n \"lumir-floating-toolbar\",\r\n isCompact && \"is-compact\",\r\n isMinimizable && \"is-minimizable\",\r\n isMinimized && \"is-minimized\"\r\n )}\r\n >\r\n {isMinimizable ? (\r\n <MinimizedLayout />\r\n ) : isCompact ? (\r\n <TwoRowLayout />\r\n ) : (\r\n <SingleRowLayout />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\n// 하위 호환성을 위한 default export\r\nexport default FloatingMenu;\r\n","\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\n/**\r\n * FloatingMenu에서 사용하는 SVG 아이콘 컴포넌트들\r\n */\r\nexport const Icons = {\r\n undo: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z\" />\r\n </svg>\r\n ),\r\n redo: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z\" />\r\n </svg>\r\n ),\r\n bold: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\" />\r\n </svg>\r\n ),\r\n italic: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z\" />\r\n </svg>\r\n ),\r\n underline: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z\" />\r\n </svg>\r\n ),\r\n strikethrough: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z\" />\r\n </svg>\r\n ),\r\n alignLeft: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z\" />\r\n </svg>\r\n ),\r\n alignCenter: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z\" />\r\n </svg>\r\n ),\r\n alignRight: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z\" />\r\n </svg>\r\n ),\r\n bulletList: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z\" />\r\n </svg>\r\n ),\r\n numberedList: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\" />\r\n </svg>\r\n ),\r\n image: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\" />\r\n </svg>\r\n ),\r\n expandMore: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"18\" height=\"18\">\r\n <path d=\"M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z\" />\r\n </svg>\r\n ),\r\n textColor: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z\" />\r\n </svg>\r\n ),\r\n bgColor: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M16.56 8.94L7.62 0 6.21 1.41l2.38 2.38-5.15 5.15c-.59.59-.59 1.54 0 2.12l5.5 5.5c.29.29.68.44 1.06.44s.77-.15 1.06-.44l5.5-5.5c.59-.58.59-1.53 0-2.12zM5.21 10L10 5.21 14.79 10H5.21zM19 11.5s-2 2.17-2 3.5c0 1.1.9 2 2 2s2-.9 2-2c0-1.33-2-3.5-2-3.5z\" />\r\n <path fillOpacity=\".36\" d=\"M0 20h24v4H0z\" />\r\n </svg>\r\n ),\r\n link: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\" />\r\n </svg>\r\n ),\r\n chevronRight: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\" />\r\n </svg>\r\n ),\r\n chevronLeft: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\" />\r\n </svg>\r\n ),\r\n table: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M20 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM10 17H5v-2h5v2zm0-4H5v-2h5v2zm0-4H5V7h5v2zm9 8h-7v-2h7v2zm0-4h-7v-2h7v2zm0-4h-7V7h7v2z\" />\r\n </svg>\r\n ),\r\n htmlFile: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 2v5h5l-5-5zm-4 14H7v-1h2v1zm0-2H7v-1h2v1zm-2-2h2v1H7v-1zm4 4h-2v-1h2v1zm0-2h-2v-1h2v1zm0-2h-2v-1h2v1zm6 4h-4v-1h4v1zm0-2h-4v-1h4v1zm0-2h-4v-1h4v1z\" />\r\n </svg>\r\n ),\r\n};\r\n\r\n/**\r\n * 블록 타입 아이콘들\r\n */\r\nexport const BlockTypeIcons: Record<string, React.ReactNode> = {\r\n paragraph: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M5 5h14v2H5zM5 11h14v2H5zM5 17h10v2H5z\" />\r\n </svg>\r\n ),\r\n h1: <span className=\"lumir-block-icon-text\">H1</span>,\r\n h2: <span className=\"lumir-block-icon-text\">H2</span>,\r\n h3: <span className=\"lumir-block-icon-text\">H3</span>,\r\n h4: <span className=\"lumir-block-icon-text\">H4</span>,\r\n h5: <span className=\"lumir-block-icon-text\">H5</span>,\r\n h6: <span className=\"lumir-block-icon-text\">H6</span>,\r\n toggleH1: (\r\n <span className=\"lumir-block-icon-toggle\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"8\" height=\"8\">\r\n <path d=\"M8 5v14l11-7z\" />\r\n </svg>\r\n <span>H1</span>\r\n </span>\r\n ),\r\n toggleH2: (\r\n <span className=\"lumir-block-icon-toggle\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"8\" height=\"8\">\r\n <path d=\"M8 5v14l11-7z\" />\r\n </svg>\r\n <span>H2</span>\r\n </span>\r\n ),\r\n toggleH3: (\r\n <span className=\"lumir-block-icon-toggle\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"8\" height=\"8\">\r\n <path d=\"M8 5v14l11-7z\" />\r\n </svg>\r\n <span>H3</span>\r\n </span>\r\n ),\r\n quote: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z\" />\r\n </svg>\r\n ),\r\n codeBlock: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z\" />\r\n </svg>\r\n ),\r\n toggleList: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M10 6h10v2H10zM10 11h10v2H10zM10 16h10v2H10z\" />\r\n <path\r\n d=\"M4 8l4 4-4 4\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n fill=\"none\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n </svg>\r\n ),\r\n bulletList: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <circle cx=\"4\" cy=\"6\" r=\"1.5\" />\r\n <circle cx=\"4\" cy=\"12\" r=\"1.5\" />\r\n <circle cx=\"4\" cy=\"18\" r=\"1.5\" />\r\n <path d=\"M8 5h12v2H8zM8 11h12v2H8zM8 17h12v2H8z\" />\r\n </svg>\r\n ),\r\n numberedList: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\" />\r\n </svg>\r\n ),\r\n checkList: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <rect\r\n x=\"3\"\r\n y=\"4\"\r\n width=\"6\"\r\n height=\"6\"\r\n rx=\"1\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n />\r\n <path\r\n d=\"M4.5 7l1.5 1.5 3-3\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n fill=\"none\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n <path d=\"M12 6h8v2h-8z\" />\r\n <rect\r\n x=\"3\"\r\n y=\"14\"\r\n width=\"6\"\r\n height=\"6\"\r\n rx=\"1\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n />\r\n <path d=\"M12 16h8v2h-8z\" />\r\n </svg>\r\n ),\r\n};\r\n","\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\n/**\r\n * 툴바 구분선 컴포넌트\r\n */\r\nexport const ToolbarDivider: React.FC = () => (\r\n <div className=\"lumir-toolbar-divider\" />\r\n);\r\n","\"use client\";\r\n\r\nimport React, { useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\n\r\ninterface UndoRedoButtonsProps {\r\n editor: EditorType | any;\r\n}\r\n\r\n/**\r\n * 실행 취소 / 다시 실행 버튼 컴포넌트\r\n */\r\nexport const UndoRedoButtons: React.FC<UndoRedoButtonsProps> = ({ editor }) => {\r\n const handleUndo = useCallback(() => {\r\n try {\r\n editor?.undo?.();\r\n } catch (err) {\r\n console.error(\"Undo failed:\", err);\r\n }\r\n }, [editor]);\r\n\r\n const handleRedo = useCallback(() => {\r\n try {\r\n editor?.redo?.();\r\n } catch (err) {\r\n console.error(\"Redo failed:\", err);\r\n }\r\n }, [editor]);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <div className=\"lumir-toolbar-group\">\r\n <button\r\n className=\"lumir-toolbar-btn\"\r\n onClick={handleUndo}\r\n onMouseDown={handleMouseDown}\r\n title=\"실행 취소\"\r\n type=\"button\"\r\n >\r\n {Icons.undo}\r\n </button>\r\n <button\r\n className=\"lumir-toolbar-btn\"\r\n onClick={handleRedo}\r\n onMouseDown={handleMouseDown}\r\n title=\"다시 실행\"\r\n type=\"button\"\r\n >\r\n {Icons.redo}\r\n </button>\r\n </div>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\nimport { cn } from \"../../../utils/cn\";\r\n\r\ntype TextStyle = \"bold\" | \"italic\" | \"underline\" | \"strike\";\r\n\r\ninterface TextStyleButtonProps {\r\n editor: EditorType | any;\r\n style: TextStyle;\r\n}\r\n\r\nconst iconMap: Record<TextStyle, React.ReactNode> = {\r\n bold: Icons.bold,\r\n italic: Icons.italic,\r\n underline: Icons.underline,\r\n strike: Icons.strikethrough,\r\n};\r\n\r\nconst titleMap: Record<TextStyle, string> = {\r\n bold: \"굵게\",\r\n italic: \"기울임\",\r\n underline: \"밑줄\",\r\n strike: \"취소선\",\r\n};\r\n\r\n/**\r\n * 텍스트 스타일 버튼 (굵게, 기울임, 밑줄, 취소선)\r\n */\r\nexport const TextStyleButton: React.FC<TextStyleButtonProps> = ({\r\n editor,\r\n style,\r\n}) => {\r\n // 현재 스타일 상태를 직접 계산\r\n const getIsActive = (): boolean => {\r\n try {\r\n const activeStyles = editor?.getActiveStyles?.() || {};\r\n return activeStyles[style] === true;\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n const isActive = getIsActive();\r\n\r\n const handleClick = useCallback(() => {\r\n try {\r\n editor?.toggleStyles?.({ [style]: true });\r\n } catch (err) {\r\n console.error(`Toggle ${style} failed:`, err);\r\n }\r\n }, [editor, style]);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <button\r\n className={cn(\"lumir-toolbar-btn\", isActive && \"is-active\")}\r\n onClick={handleClick}\r\n onMouseDown={handleMouseDown}\r\n title={titleMap[style]}\r\n type=\"button\"\r\n >\r\n {iconMap[style]}\r\n </button>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\nimport { cn } from \"../../../utils/cn\";\r\n\r\ntype Alignment = \"left\" | \"center\" | \"right\";\r\n\r\ninterface AlignButtonProps {\r\n editor: EditorType | any;\r\n alignment: Alignment;\r\n}\r\n\r\nconst iconMap: Record<Alignment, React.ReactNode> = {\r\n left: Icons.alignLeft,\r\n center: Icons.alignCenter,\r\n right: Icons.alignRight,\r\n};\r\n\r\nconst titleMap: Record<Alignment, string> = {\r\n left: \"왼쪽 정렬\",\r\n center: \"가운데 정렬\",\r\n right: \"오른쪽 정렬\",\r\n};\r\n\r\n/**\r\n * 텍스트 정렬 버튼 (왼쪽, 가운데, 오른쪽)\r\n */\r\nexport const AlignButton: React.FC<AlignButtonProps> = ({\r\n editor,\r\n alignment,\r\n}) => {\r\n // 현재 정렬 상태를 직접 계산\r\n const getCurrentAlignment = (): string => {\r\n try {\r\n const block = editor?.getTextCursorPosition()?.block;\r\n return block?.props?.textAlignment || \"left\";\r\n } catch {\r\n return \"left\";\r\n }\r\n };\r\n\r\n const isActive = getCurrentAlignment() === alignment;\r\n\r\n const handleClick = useCallback(() => {\r\n try {\r\n const block = editor?.getTextCursorPosition()?.block;\r\n if (block && editor?.updateBlock) {\r\n editor.updateBlock(block, { props: { textAlignment: alignment } });\r\n }\r\n } catch (err) {\r\n console.error(`Set alignment ${alignment} failed:`, err);\r\n }\r\n }, [editor, alignment]);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <button\r\n className={cn(\"lumir-toolbar-btn\", isActive && \"is-active\")}\r\n onClick={handleClick}\r\n onMouseDown={handleMouseDown}\r\n title={titleMap[alignment]}\r\n type=\"button\"\r\n >\r\n {iconMap[alignment]}\r\n </button>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\nimport { cn } from \"../../../utils/cn\";\r\n\r\ntype ListType = \"bullet\" | \"numbered\";\r\n\r\ninterface ListButtonProps {\r\n editor: EditorType | any;\r\n type: ListType;\r\n}\r\n\r\nconst iconMap: Record<ListType, React.ReactNode> = {\r\n bullet: Icons.bulletList,\r\n numbered: Icons.numberedList,\r\n};\r\n\r\nconst titleMap: Record<ListType, string> = {\r\n bullet: \"글머리 기호 목록\",\r\n numbered: \"번호 목록\",\r\n};\r\n\r\n/**\r\n * 리스트 버튼 (글머리 기호, 번호 목록)\r\n */\r\nexport const ListButton: React.FC<ListButtonProps> = ({ editor, type }) => {\r\n // 현재 리스트 상태를 직접 계산\r\n const getIsActive = (): boolean => {\r\n try {\r\n const block = editor?.getTextCursorPosition()?.block;\r\n const blockType =\r\n type === \"bullet\" ? \"bulletListItem\" : \"numberedListItem\";\r\n return block?.type === blockType;\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n const isActive = getIsActive();\r\n\r\n const handleClick = useCallback(() => {\r\n try {\r\n const block = editor?.getTextCursorPosition()?.block;\r\n if (block && editor?.updateBlock) {\r\n const targetType =\r\n type === \"bullet\" ? \"bulletListItem\" : \"numberedListItem\";\r\n const newType = block.type === targetType ? \"paragraph\" : targetType;\r\n editor.updateBlock(block, { type: newType as any });\r\n }\r\n } catch (err) {\r\n console.error(`List toggle failed:`, err);\r\n }\r\n }, [editor, type]);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <button\r\n className={cn(\"lumir-toolbar-btn\", isActive && \"is-active\")}\r\n onClick={handleClick}\r\n onMouseDown={handleMouseDown}\r\n title={titleMap[type]}\r\n type=\"button\"\r\n >\r\n {iconMap[type]}\r\n </button>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\n\r\ninterface ImageButtonProps {\r\n editor: EditorType | any;\r\n onImageUpload?: () => void;\r\n}\r\n\r\n/**\r\n * 이미지 업로드 버튼\r\n */\r\nexport const ImageButton: React.FC<ImageButtonProps> = ({\r\n editor,\r\n onImageUpload,\r\n}) => {\r\n const handleClick = useCallback(() => {\r\n if (onImageUpload) {\r\n onImageUpload();\r\n } else {\r\n const input = document.createElement(\"input\");\r\n input.type = \"file\";\r\n input.accept = \"image/*\";\r\n input.onchange = async (e) => {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (file && editor?.uploadFile) {\r\n try {\r\n const url = await editor.uploadFile(file);\r\n editor.insertBlocks(\r\n [{ type: \"image\", props: { url: url as string } }] as any,\r\n editor.getTextCursorPosition().block,\r\n \"after\"\r\n );\r\n } catch (err) {\r\n console.error(\"Image upload failed:\", err);\r\n }\r\n }\r\n };\r\n input.click();\r\n }\r\n }, [editor, onImageUpload]);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <button\r\n className=\"lumir-toolbar-btn\"\r\n onClick={handleClick}\r\n onMouseDown={handleMouseDown}\r\n title=\"이미지 삽입\"\r\n type=\"button\"\r\n >\r\n {Icons.image}\r\n </button>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\nimport { cn } from \"../../../utils/cn\";\r\nimport {\r\n TEXT_COLORS,\r\n BACKGROUND_COLORS,\r\n getHexFromColorValue,\r\n} from \"../../../constants/colors\";\r\n\r\ntype ColorType = \"text\" | \"background\";\r\n\r\ninterface ColorButtonProps {\r\n editor: EditorType | any;\r\n type: ColorType;\r\n}\r\n\r\n/**\r\n * 색상 선택 버튼 (텍스트/배경 색상)\r\n */\r\nexport const ColorButton: React.FC<ColorButtonProps> = ({ editor, type }) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [currentColor, setCurrentColor] = useState(\"default\");\r\n const dropdownRef = useRef<HTMLDivElement>(null);\r\n\r\n const colors = type === \"text\" ? TEXT_COLORS : BACKGROUND_COLORS;\r\n\r\n const getCurrentColor = useCallback((): string => {\r\n try {\r\n const activeStyles = editor?.getActiveStyles?.() || {};\r\n if (type === \"text\" && activeStyles.textColor) {\r\n return activeStyles.textColor;\r\n } else if (type === \"background\" && activeStyles.backgroundColor) {\r\n return activeStyles.backgroundColor;\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return \"default\";\r\n }, [editor, type]);\r\n\r\n // 드롭다운 열릴 때 현재 색상 업데이트\r\n useEffect(() => {\r\n if (isOpen) {\r\n const color = getCurrentColor();\r\n setCurrentColor(color);\r\n }\r\n }, [isOpen, getCurrentColor]);\r\n\r\n // 외부 클릭 감지\r\n useEffect(() => {\r\n const handleClickOutside = (e: MouseEvent) => {\r\n if (\r\n dropdownRef.current &&\r\n !dropdownRef.current.contains(e.target as Node)\r\n ) {\r\n setIsOpen(false);\r\n }\r\n };\r\n document.addEventListener(\"mousedown\", handleClickOutside);\r\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\r\n }, []);\r\n\r\n const handleColorSelect = useCallback(\r\n (color: string) => {\r\n try {\r\n if (!editor) return;\r\n\r\n if (type === \"text\") {\r\n (editor as any).toggleStyles({ textColor: color });\r\n } else {\r\n (editor as any).toggleStyles({ backgroundColor: color });\r\n }\r\n setCurrentColor(color);\r\n setIsOpen(false);\r\n } catch (err) {\r\n console.error(`Color apply failed:`, err);\r\n }\r\n },\r\n [editor, type]\r\n );\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <div className=\"lumir-dropdown-wrapper\" ref={dropdownRef}>\r\n <button\r\n className=\"lumir-toolbar-btn lumir-color-btn\"\r\n onClick={() => setIsOpen(!isOpen)}\r\n onMouseDown={handleMouseDown}\r\n title={type === \"text\" ? \"텍스트 색상\" : \"배경 색상\"}\r\n type=\"button\"\r\n >\r\n {type === \"text\" ? Icons.textColor : Icons.bgColor}\r\n <span\r\n className=\"lumir-color-indicator\"\r\n style={{\r\n backgroundColor: getHexFromColorValue(currentColor, type),\r\n }}\r\n />\r\n </button>\r\n {isOpen && (\r\n <div className=\"lumir-dropdown-menu lumir-color-menu\">\r\n <div className=\"lumir-color-grid\">\r\n {colors.map((color) => (\r\n <button\r\n key={color.value}\r\n className={cn(\r\n \"lumir-color-swatch\",\r\n currentColor === color.value && \"is-active\"\r\n )}\r\n onClick={() => handleColorSelect(color.value)}\r\n onMouseDown={handleMouseDown}\r\n title={color.name}\r\n style={{ backgroundColor: color.hex }}\r\n type=\"button\"\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n","/**\r\n * 색상 팔레트 상수\r\n * BlockNote 기본 색상 팔레트와 일치\r\n */\r\n\r\nexport interface ColorItem {\r\n name: string;\r\n value: string;\r\n hex: string;\r\n}\r\n\r\n/**\r\n * 텍스트 색상 팔레트\r\n */\r\nexport const TEXT_COLORS: ColorItem[] = [\r\n { name: \"기본\", value: \"default\", hex: \"#3f3f3f\" },\r\n { name: \"회색\", value: \"gray\", hex: \"#9b9a97\" },\r\n { name: \"갈색\", value: \"brown\", hex: \"#64473a\" },\r\n { name: \"빨간색\", value: \"red\", hex: \"#e03e3e\" },\r\n { name: \"주황색\", value: \"orange\", hex: \"#d9730d\" },\r\n { name: \"노란색\", value: \"yellow\", hex: \"#dfab01\" },\r\n { name: \"초록색\", value: \"green\", hex: \"#4d6461\" },\r\n { name: \"파란색\", value: \"blue\", hex: \"#0b6e99\" },\r\n { name: \"보라색\", value: \"purple\", hex: \"#6940a5\" },\r\n { name: \"분홍색\", value: \"pink\", hex: \"#ad1a72\" },\r\n];\r\n\r\n/**\r\n * 배경 색상 팔레트\r\n */\r\nexport const BACKGROUND_COLORS: ColorItem[] = [\r\n { name: \"기본\", value: \"default\", hex: \"transparent\" },\r\n { name: \"회색\", value: \"gray\", hex: \"#ebeced\" },\r\n { name: \"갈색\", value: \"brown\", hex: \"#e9e5e3\" },\r\n { name: \"빨간색\", value: \"red\", hex: \"#fbe4e4\" },\r\n { name: \"주황색\", value: \"orange\", hex: \"#f6e9d9\" },\r\n { name: \"노란색\", value: \"yellow\", hex: \"#fbf3db\" },\r\n { name: \"초록색\", value: \"green\", hex: \"#ddedea\" },\r\n { name: \"파란색\", value: \"blue\", hex: \"#ddebf1\" },\r\n { name: \"보라색\", value: \"purple\", hex: \"#eae4f2\" },\r\n { name: \"분홍색\", value: \"pink\", hex: \"#f4dfeb\" },\r\n];\r\n\r\n/**\r\n * 색상 값으로 hex 색상 코드 찾기\r\n */\r\nexport const getHexFromColorValue = (\r\n value: string,\r\n type: \"text\" | \"background\"\r\n): string => {\r\n const colors = type === \"text\" ? TEXT_COLORS : BACKGROUND_COLORS;\r\n const colorItem = colors.find((c) => c.value === value);\r\n return colorItem?.hex || (type === \"text\" ? \"#000000\" : \"transparent\");\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\n\r\ninterface LinkButtonProps {\r\n editor: EditorType | any;\r\n}\r\n\r\n/**\r\n * 🔒 위험한 URL 프로토콜 검증\r\n * javascript:, data:, vbscript: 등 XSS 공격에 사용될 수 있는 프로토콜 차단\r\n */\r\nexport const isDangerousProtocol = (url: string): boolean => {\r\n const trimmedUrl = url.trim().toLowerCase();\r\n // 위험한 프로토콜 패턴\r\n const dangerousPatterns = [\r\n /^javascript:/i,\r\n /^data:/i,\r\n /^vbscript:/i,\r\n /^file:/i,\r\n ];\r\n return dangerousPatterns.some((pattern) => pattern.test(trimmedUrl));\r\n};\r\n\r\n/**\r\n * URL 프로토콜 자동 추가 유틸리티 (보안 강화)\r\n */\r\nexport const normalizeUrl = (url: string): string | null => {\r\n const trimmedUrl = url.trim();\r\n\r\n // 🔒 위험한 프로토콜 차단\r\n if (isDangerousProtocol(trimmedUrl)) {\r\n console.warn(\"Blocked dangerous URL protocol:\", trimmedUrl);\r\n return null;\r\n }\r\n\r\n // 이미 프로토콜이 있는 경우 그대로 반환\r\n if (/^https?:\\/\\//i.test(trimmedUrl)) {\r\n return trimmedUrl;\r\n }\r\n\r\n // mailto: 또는 tel: 링크인 경우 그대로 반환\r\n if (/^(mailto:|tel:)/i.test(trimmedUrl)) {\r\n return trimmedUrl;\r\n }\r\n\r\n // 프로토콜이 없는 경우 https:// 추가\r\n return `https://${trimmedUrl}`;\r\n};\r\n\r\n/**\r\n * 링크 삽입 버튼\r\n */\r\nexport const LinkButton: React.FC<LinkButtonProps> = ({ editor }) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [linkUrl, setLinkUrl] = useState(\"\");\r\n const [errorMsg, setErrorMsg] = useState<string | null>(null);\r\n const dropdownRef = useRef<HTMLDivElement>(null);\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n const hasSelectionRef = useRef(false);\r\n\r\n // 외부 클릭 감지\r\n useEffect(() => {\r\n const handleClickOutside = (e: MouseEvent) => {\r\n if (\r\n dropdownRef.current &&\r\n !dropdownRef.current.contains(e.target as Node)\r\n ) {\r\n setIsOpen(false);\r\n setLinkUrl(\"\");\r\n setErrorMsg(null);\r\n }\r\n };\r\n document.addEventListener(\"mousedown\", handleClickOutside);\r\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\r\n }, []);\r\n\r\n // 드롭다운 열릴 때 선택 상태 저장 후 input에 포커스\r\n useEffect(() => {\r\n if (isOpen && inputRef.current) {\r\n try {\r\n const selectedText = editor?.getSelectedText?.() || \"\";\r\n hasSelectionRef.current = selectedText.length > 0;\r\n } catch {\r\n hasSelectionRef.current = false;\r\n }\r\n setTimeout(() => inputRef.current?.focus(), 0);\r\n }\r\n }, [isOpen, editor]);\r\n\r\n const handleSubmit = useCallback(\r\n (e?: React.FormEvent) => {\r\n e?.preventDefault();\r\n setErrorMsg(null);\r\n\r\n try {\r\n if (linkUrl.trim() && editor?.createLink) {\r\n const normalizedUrl = normalizeUrl(linkUrl);\r\n\r\n if (normalizedUrl === null) {\r\n setErrorMsg(\"허용되지 않는 URL 형식입니다.\");\r\n return;\r\n }\r\n\r\n editor.focus();\r\n\r\n if (hasSelectionRef.current) {\r\n editor.createLink(normalizedUrl);\r\n } else {\r\n editor.createLink(normalizedUrl, normalizedUrl);\r\n }\r\n\r\n setIsOpen(false);\r\n setLinkUrl(\"\");\r\n }\r\n } catch (err) {\r\n console.error(\"Create link failed:\", err);\r\n setErrorMsg(\"링크 생성에 실패했습니다.\");\r\n }\r\n },\r\n [editor, linkUrl]\r\n );\r\n\r\n const handleCancel = useCallback(() => {\r\n setIsOpen(false);\r\n setLinkUrl(\"\");\r\n setErrorMsg(null);\r\n }, []);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n const handleKeyDown = useCallback(\r\n (e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === \"Enter\") {\r\n handleSubmit();\r\n } else if (e.key === \"Escape\") {\r\n handleCancel();\r\n }\r\n },\r\n [handleSubmit, handleCancel]\r\n );\r\n\r\n return (\r\n <div className=\"lumir-dropdown-wrapper\" ref={dropdownRef}>\r\n <button\r\n className=\"lumir-toolbar-btn\"\r\n onClick={() => setIsOpen(!isOpen)}\r\n onMouseDown={handleMouseDown}\r\n title=\"링크 삽입\"\r\n type=\"button\"\r\n >\r\n {Icons.link}\r\n </button>\r\n {isOpen && (\r\n <div className=\"lumir-dropdown-menu lumir-link-menu\">\r\n <form onSubmit={handleSubmit} className=\"lumir-link-form\">\r\n <input\r\n ref={inputRef}\r\n type=\"text\"\r\n className=\"lumir-link-input\"\r\n placeholder=\"링크 URL을 입력하세요\"\r\n value={linkUrl}\r\n onChange={(e) => {\r\n setLinkUrl(e.target.value);\r\n setErrorMsg(null);\r\n }}\r\n onKeyDown={handleKeyDown}\r\n onMouseDown={handleMouseDown}\r\n />\r\n {/* 에러 메시지 표시 */}\r\n {errorMsg && (\r\n <div\r\n style={{\r\n color: \"#dc3545\",\r\n fontSize: \"12px\",\r\n marginTop: \"4px\",\r\n padding: \"0 4px\",\r\n }}\r\n >\r\n {errorMsg}\r\n </div>\r\n )}\r\n <div className=\"lumir-link-actions\">\r\n <button\r\n type=\"button\"\r\n className=\"lumir-link-btn lumir-link-cancel\"\r\n onClick={handleCancel}\r\n onMouseDown={handleMouseDown}\r\n >\r\n 취소\r\n </button>\r\n <button\r\n type=\"submit\"\r\n className=\"lumir-link-btn lumir-link-submit\"\r\n onMouseDown={handleMouseDown}\r\n disabled={!linkUrl.trim()}\r\n >\r\n 확인\r\n </button>\r\n </div>\r\n </form>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\n\r\ninterface TableButtonProps {\r\n editor: EditorType | any;\r\n}\r\n\r\n/**\r\n * 테이블 삽입 버튼\r\n */\r\nexport const TableButton: React.FC<TableButtonProps> = ({ editor }) => {\r\n const handleClick = useCallback(() => {\r\n try {\r\n const block = editor?.getTextCursorPosition()?.block;\r\n if (!block || !editor?.insertBlocks) return;\r\n\r\n // 3x3 기본 테이블 생성\r\n const defaultCell = [{ type: \"text\", text: \"\", styles: {} }];\r\n const tableContent = {\r\n type: \"tableContent\",\r\n rows: [\r\n { cells: [defaultCell, defaultCell, defaultCell] },\r\n { cells: [defaultCell, defaultCell, defaultCell] },\r\n { cells: [defaultCell, defaultCell, defaultCell] },\r\n ],\r\n };\r\n\r\n editor.insertBlocks(\r\n [{ type: \"table\", content: tableContent }] as any,\r\n block,\r\n \"after\"\r\n );\r\n } catch (err) {\r\n console.error(\"Table insert failed:\", err);\r\n }\r\n }, [editor]);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <button\r\n className=\"lumir-toolbar-btn\"\r\n onClick={handleClick}\r\n onMouseDown={handleMouseDown}\r\n title=\"테이블 삽입\"\r\n type=\"button\"\r\n >\r\n {Icons.table}\r\n </button>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useCallback, useRef } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons } from \"../Icons\";\r\n\r\ninterface HTMLImportButtonProps {\r\n editor: EditorType | any;\r\n}\r\n\r\n/**\r\n * HTML 파일 Import 버튼\r\n */\r\nexport const HTMLImportButton: React.FC<HTMLImportButtonProps> = ({\r\n editor,\r\n}) => {\r\n const fileInputRef = useRef<HTMLInputElement>(null);\r\n\r\n const handleFileUpload = useCallback(\r\n (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const file = e.target.files?.[0];\r\n if (!file) return;\r\n\r\n const reader = new FileReader();\r\n reader.onload = (event) => {\r\n const content = event.target?.result as string;\r\n\r\n try {\r\n if (!editor || !content.trim()) return;\r\n\r\n const block = editor?.getTextCursorPosition()?.block;\r\n if (!block || !editor?.insertBlocks) return;\r\n\r\n // htmlPreview 블록 삽입\r\n editor.insertBlocks(\r\n [\r\n {\r\n type: \"htmlPreview\",\r\n props: {\r\n htmlContent: content,\r\n fileName: file.name,\r\n height: \"400px\",\r\n },\r\n } as any,\r\n ],\r\n block,\r\n \"after\"\r\n );\r\n\r\n // file input 초기화\r\n if (fileInputRef.current) {\r\n fileInputRef.current.value = \"\";\r\n }\r\n } catch (err) {\r\n console.error(\"HTML insert failed:\", err);\r\n }\r\n };\r\n reader.readAsText(file);\r\n },\r\n [editor]\r\n );\r\n\r\n const handleClick = useCallback(() => {\r\n fileInputRef.current?.click();\r\n }, []);\r\n\r\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n return (\r\n <>\r\n <input\r\n ref={fileInputRef}\r\n type=\"file\"\r\n accept=\".html,.htm\"\r\n onChange={handleFileUpload}\r\n style={{ display: \"none\" }}\r\n />\r\n <button\r\n className=\"lumir-toolbar-btn\"\r\n onClick={handleClick}\r\n onMouseDown={handleMouseDown}\r\n title=\"HTML Import\"\r\n type=\"button\"\r\n >\r\n {Icons.htmlFile}\r\n </button>\r\n </>\r\n );\r\n};\r\n","\"use client\";\r\n\r\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\r\nimport type { EditorType } from \"../../../types\";\r\nimport { Icons, BlockTypeIcons } from \"../Icons\";\r\nimport { cn } from \"../../../utils/cn\";\r\n\r\ninterface BlockTypeSelectProps {\r\n editor: EditorType | any;\r\n}\r\n\r\n// 블록 타입 정의\r\ntype BlockTypeItem = {\r\n type: string;\r\n label: string;\r\n icon: string;\r\n level?: number;\r\n isToggle?: boolean;\r\n};\r\n\r\n// 카테고리별 블록 타입\r\nconst blockTypeCategories: { category: string; items: BlockTypeItem[] }[] = [\r\n {\r\n category: \"Headings\",\r\n items: [\r\n { type: \"heading\", label: \"Heading 1\", level: 1, icon: \"h1\", isToggle: false },\r\n { type: \"heading\", label: \"Heading 2\", level: 2, icon: \"h2\", isToggle: false },\r\n { type: \"heading\", label: \"Heading 3\", level: 3, icon: \"h3\", isToggle: false },\r\n { type: \"heading\", label: \"Toggle Heading 1\", level: 1, icon: \"toggleH1\", isToggle: true },\r\n { type: \"heading\", label: \"Toggle Heading 2\", level: 2, icon: \"toggleH2\", isToggle: true },\r\n { type: \"heading\", label: \"Toggle Heading 3\", level: 3, icon: \"toggleH3\", isToggle: true },\r\n ],\r\n },\r\n {\r\n category: \"Basic blocks\",\r\n items: [\r\n { type: \"paragraph\", label: \"Paragraph\", icon: \"paragraph\" },\r\n { type: \"quote\", label: \"Quote\", icon: \"quote\" },\r\n { type: \"codeBlock\", label: \"Code Block\", icon: \"codeBlock\" },\r\n { type: \"bulletListItem\", label: \"Bullet List\", icon: \"bulletList\" },\r\n { type: \"numberedListItem\", label: \"Numbered List\", icon: \"numberedList\" },\r\n { type: \"checkListItem\", label: \"Check List\", icon: \"checkList\" },\r\n { type: \"toggleListItem\", label: \"Toggle List\", icon: \"toggleList\" },\r\n ],\r\n },\r\n];\r\n\r\n// 평탄화된 블록 타입 목록\r\nconst blockTypes: BlockTypeItem[] = blockTypeCategories.flatMap(\r\n (cat) => cat.items\r\n);\r\n\r\n/**\r\n * 블록 타입 선택 드롭다운\r\n */\r\nexport const BlockTypeSelect: React.FC<BlockTypeSelectProps> = ({ editor }) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const dropdownRef = useRef<HTMLDivElement>(null);\r\n\r\n // 현재 블록 타입을 직접 계산\r\n const getCurrentBlock = () => {\r\n try {\r\n return editor?.getTextCursorPosition()?.block;\r\n } catch {\r\n return null;\r\n }\r\n };\r\n\r\n const currentBlock = getCurrentBlock();\r\n const currentType = currentBlock?.type || \"paragraph\";\r\n const currentLevel = currentBlock?.props?.level;\r\n const isCurrentToggle =\r\n currentType === \"heading\" && currentBlock?.props?.isToggleable === true;\r\n\r\n useEffect(() => {\r\n const handleClickOutside = (e: MouseEvent) => {\r\n if (\r\n dropdownRef.current &&\r\n !dropdownRef.current.contains(e.target as Node)\r\n ) {\r\n setIsOpen(false);\r\n }\r\n };\r\n document.addEventListener(\"mousedown\", handleClickOutside);\r\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\r\n }, []);\r\n\r\n const handleTypeChange = (\r\n type: string,\r\n level?: number,\r\n isToggle?: boolean\r\n ) => {\r\n try {\r\n const block = editor?.getTextCursorPosition()?.block;\r\n if (!block || !editor) return;\r\n\r\n const props: any = {};\r\n if (level) props.level = level;\r\n\r\n if (type === \"heading\" && isToggle !== undefined) {\r\n props.isToggleable = isToggle;\r\n editor.updateBlock(block, {\r\n type: \"heading\" as any,\r\n props,\r\n });\r\n } else {\r\n editor.updateBlock(block, { type: type as any, props });\r\n }\r\n\r\n setIsOpen(false);\r\n } catch (err) {\r\n console.error(\"Block type change failed:\", err);\r\n }\r\n };\r\n\r\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault();\r\n }, []);\r\n\r\n const getCurrentLabel = () => {\r\n if (currentType === \"heading\" && currentLevel) {\r\n const found = blockTypes.find(\r\n (bt) =>\r\n bt.type === \"heading\" &&\r\n bt.level === currentLevel &&\r\n bt.isToggle === isCurrentToggle\r\n );\r\n return found?.label || \"Heading\";\r\n }\r\n const found = blockTypes.find((bt) => bt.type === currentType);\r\n return found?.label || \"Paragraph\";\r\n };\r\n\r\n const getCurrentIcon = () => {\r\n if (currentType === \"heading\" && currentLevel) {\r\n const found = blockTypes.find(\r\n (bt) =>\r\n bt.type === \"heading\" &&\r\n bt.level === currentLevel &&\r\n bt.isToggle === isCurrentToggle\r\n );\r\n return found?.icon || `h${currentLevel}`;\r\n }\r\n const found = blockTypes.find((bt) => bt.type === currentType);\r\n return found?.icon || \"paragraph\";\r\n };\r\n\r\n const isActiveItem = (bt: BlockTypeItem) => {\r\n if (bt.type === \"heading\" && bt.level) {\r\n const isLevelMatch =\r\n currentType === \"heading\" && currentLevel === bt.level;\r\n const isToggleMatch = bt.isToggle === isCurrentToggle;\r\n return isLevelMatch && isToggleMatch;\r\n }\r\n return currentType === bt.type;\r\n };\r\n\r\n return (\r\n <div className=\"lumir-dropdown-wrapper\" ref={dropdownRef}>\r\n <button\r\n className=\"lumir-dropdown-btn lumir-block-type-btn\"\r\n onClick={() => setIsOpen(!isOpen)}\r\n onMouseDown={handleMouseDown}\r\n type=\"button\"\r\n >\r\n <span className=\"lumir-block-icon\">\r\n {BlockTypeIcons[getCurrentIcon()]}\r\n </span>\r\n <span className=\"lumir-block-label\">{getCurrentLabel()}</span>\r\n {Icons.expandMore}\r\n </button>\r\n {isOpen && (\r\n <div className=\"lumir-dropdown-menu lumir-block-menu\">\r\n {blockTypeCategories.map((category) => (\r\n <div key={category.category} className=\"lumir-block-category\">\r\n <div className=\"lumir-block-category-title\">\r\n {category.category}\r\n </div>\r\n {category.items.map((bt) => (\r\n <button\r\n key={bt.icon}\r\n className={cn(\r\n \"lumir-dropdown-item lumir-block-item\",\r\n isActiveItem(bt) && \"is-active\"\r\n )}\r\n onClick={() => handleTypeChange(bt.type, bt.level, bt.isToggle)}\r\n onMouseDown={handleMouseDown}\r\n >\r\n <span className=\"lumir-block-icon\">\r\n {BlockTypeIcons[bt.icon]}\r\n </span>\r\n <span className=\"lumir-block-item-title\">{bt.label}</span>\r\n </button>\r\n ))}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n","/**\r\n * LumirEditor 커스텀 에러 클래스\r\n */\r\n\r\nexport type LumirErrorCode =\r\n | \"UPLOAD_FAILED\"\r\n | \"INVALID_FILE_TYPE\"\r\n | \"S3_CONFIG_ERROR\"\r\n | \"PRESIGNED_URL_ERROR\"\r\n | \"NETWORK_ERROR\"\r\n | \"EDITOR_ERROR\"\r\n | \"UNKNOWN_ERROR\";\r\n\r\nexport interface LumirErrorDetails {\r\n code: LumirErrorCode;\r\n originalError?: Error;\r\n context?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * LumirEditor에서 발생하는 에러를 위한 커스텀 에러 클래스\r\n */\r\nexport class LumirEditorError extends Error {\r\n public readonly code: LumirErrorCode;\r\n public readonly originalError?: Error;\r\n public readonly context?: Record<string, unknown>;\r\n\r\n constructor(message: string, details: Partial<LumirErrorDetails> = {}) {\r\n super(message);\r\n this.name = \"LumirEditorError\";\r\n this.code = details.code || \"UNKNOWN_ERROR\";\r\n this.originalError = details.originalError;\r\n this.context = details.context;\r\n\r\n // Error 클래스 확장 시 프로토타입 체인 유지\r\n Object.setPrototypeOf(this, LumirEditorError.prototype);\r\n }\r\n\r\n /**\r\n * 에러 정보를 JSON 형태로 반환\r\n */\r\n toJSON(): Record<string, unknown> {\r\n return {\r\n name: this.name,\r\n message: this.message,\r\n code: this.code,\r\n context: this.context,\r\n stack: this.stack,\r\n };\r\n }\r\n\r\n /**\r\n * 사용자 친화적 에러 메시지 반환\r\n */\r\n getUserMessage(): string {\r\n switch (this.code) {\r\n case \"UPLOAD_FAILED\":\r\n return \"파일 업로드에 실패했습니다. 다시 시도해주세요.\";\r\n case \"INVALID_FILE_TYPE\":\r\n return \"지원하지 않는 파일 형식입니다. 이미지 파일만 업로드 가능합니다.\";\r\n case \"S3_CONFIG_ERROR\":\r\n return \"S3 설정이 올바르지 않습니다. 관리자에게 문의하세요.\";\r\n case \"PRESIGNED_URL_ERROR\":\r\n return \"업로드 URL 생성에 실패했습니다. 다시 시도해주세요.\";\r\n case \"NETWORK_ERROR\":\r\n return \"네트워크 연결을 확인해주세요.\";\r\n case \"EDITOR_ERROR\":\r\n return \"에디터 오류가 발생했습니다. 페이지를 새로고침해주세요.\";\r\n default:\r\n return \"알 수 없는 오류가 발생했습니다.\";\r\n }\r\n }\r\n\r\n /**\r\n * 일반 Error를 LumirEditorError로 변환\r\n */\r\n static fromError(\r\n error: Error,\r\n code: LumirErrorCode = \"UNKNOWN_ERROR\",\r\n context?: Record<string, unknown>\r\n ): LumirEditorError {\r\n return new LumirEditorError(error.message, {\r\n code,\r\n originalError: error,\r\n context,\r\n });\r\n }\r\n\r\n /**\r\n * 업로드 실패 에러 생성\r\n */\r\n static uploadFailed(\r\n message: string,\r\n originalError?: Error\r\n ): LumirEditorError {\r\n return new LumirEditorError(message, {\r\n code: \"UPLOAD_FAILED\",\r\n originalError,\r\n });\r\n }\r\n\r\n /**\r\n * 잘못된 파일 형식 에러 생성\r\n * @param allowVideoUpload true이면 \"image and video\" 메시지 사용\r\n */\r\n static invalidFileType(\r\n fileName: string,\r\n allowVideoUpload?: boolean\r\n ): LumirEditorError {\r\n const message =\r\n allowVideoUpload === true\r\n ? `Invalid file type: ${fileName}. Only image and video files are allowed.`\r\n : `Invalid file type: ${fileName}. Only image files are allowed.`;\r\n return new LumirEditorError(message, {\r\n code: \"INVALID_FILE_TYPE\",\r\n context: { fileName },\r\n });\r\n }\r\n\r\n /**\r\n * S3 설정 에러 생성\r\n */\r\n static s3ConfigError(message: string): LumirEditorError {\r\n return new LumirEditorError(message, {\r\n code: \"S3_CONFIG_ERROR\",\r\n });\r\n }\r\n\r\n /**\r\n * 네트워크 에러 생성\r\n */\r\n static networkError(originalError?: Error): LumirEditorError {\r\n return new LumirEditorError(\"Network request failed\", {\r\n code: \"NETWORK_ERROR\",\r\n originalError,\r\n });\r\n }\r\n}\r\n","/**\r\n * 보안 및 성능 제한 상수\r\n */\r\n\r\n/** 최대 파일 크기: 10MB (이미지) */\r\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024;\r\n\r\n/** 최대 동영상 파일 크기: 100MB */\r\nexport const MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;\r\n\r\n/** 업로드 타임아웃: 30초 (이미지 등) */\r\nexport const UPLOAD_TIMEOUT = 30000;\r\n\r\n/** 대용량 파일(비디오 등) 업로드 타임아웃: 120초 */\r\nexport const UPLOAD_TIMEOUT_VIDEO = 120000;\r\n\r\n/** 허용된 이미지 MIME 타입 (SVG 제외) */\r\nexport const ALLOWED_IMAGE_MIME_TYPES = new Set([\r\n \"image/jpeg\",\r\n \"image/png\",\r\n \"image/gif\",\r\n \"image/webp\",\r\n \"image/bmp\",\r\n]);\r\n\r\n/** 차단된 파일 확장자 */\r\nexport const BLOCKED_EXTENSIONS = [\".svg\", \".svgz\"];\r\n\r\n/** 허용된 이미지 확장자 */\r\nexport const ALLOWED_IMAGE_EXTENSIONS = [\r\n \".png\",\r\n \".jpg\",\r\n \".jpeg\",\r\n \".gif\",\r\n \".webp\",\r\n \".bmp\",\r\n];\r\n\r\n/** 허용된 동영상 MIME 타입 */\r\nexport const ALLOWED_VIDEO_MIME_TYPES = new Set([\r\n \"video/mp4\",\r\n \"video/webm\",\r\n \"video/ogg\",\r\n \"video/quicktime\", // .mov\r\n]);\r\n\r\n/** 허용된 동영상 확장자 */\r\nexport const ALLOWED_VIDEO_EXTENSIONS = [\r\n \".mp4\",\r\n \".webm\",\r\n \".ogg\",\r\n \".mov\",\r\n];\r\n"],"mappings":"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","names":["useEffect","useCallback","useState","useRef","createReactBlockSpec","endpoint","createReactBlockSpec","useState","useCallback","useRef","useEffect","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","jsx","jsxs","createReactBlockSpec","useState","useEffect","useRef","jsx","jsxs","jsx","useCallback","jsx","jsxs","useCallback","useCallback","jsx","useCallback","useCallback","jsx","iconMap","titleMap","useCallback","useCallback","jsx","iconMap","titleMap","useCallback","useCallback","jsx","useCallback","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useEffect","useCallback","useCallback","jsx","useCallback","useCallback","useRef","Fragment","jsx","jsxs","useRef","useCallback","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useEffect","useCallback","found","Fragment","jsx","jsxs","useRef","useState","useEffect","Fragment","jsx","jsxs","jsx","jsxs","useState","useRef","useCallback","useEffect","editor","Fragment"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/LumirEditor.tsx","../src/utils/cn.ts","../src/utils/s3-uploader.ts","../src/blocks/HtmlPreview.tsx","../src/blocks/LinkPreview.tsx","../src/blocks/defaultLogo.ts","../src/blocks/VideoBlock.tsx","../src/components/FloatingMenu/index.tsx","../src/components/FloatingMenu/Icons.tsx","../src/components/FloatingMenu/components/ToolbarDivider.tsx","../src/components/FloatingMenu/components/UndoRedoButtons.tsx","../src/components/FloatingMenu/components/TextStyleButton.tsx","../src/components/FloatingMenu/components/AlignButton.tsx","../src/components/FloatingMenu/components/ListButton.tsx","../src/components/FloatingMenu/components/ImageButton.tsx","../src/components/FloatingMenu/components/ColorButton.tsx","../src/constants/colors.ts","../src/components/FloatingMenu/components/LinkButton.tsx","../src/components/FloatingMenu/components/TableButton.tsx","../src/components/FloatingMenu/components/HTMLImportButton.tsx","../src/components/FloatingMenu/components/BlockTypeSelect.tsx","../src/errors/LumirEditorError.ts","../src/extensions/VerticalAlignmentExtension.ts","../src/components/CustomFormattingToolbar.tsx","../src/components/TextAlignButtonWithVA.tsx","../src/utils/prosemirror-table-utils.ts","../src/components/VerticalAlignButton.tsx","../src/utils/table-vertical-alignment.ts","../src/constants/limits.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useCallback, useState, useRef } from \"react\";\nimport {\n useCreateBlockNote,\n SideMenu as BlockSideMenu,\n SideMenuController,\n DragHandleButton,\n SuggestionMenuController,\n getDefaultReactSlashMenuItems,\n LinkToolbarController,\n FormattingToolbarController,\n useBlockNoteEditor,\n useComponentsContext,\n EditLinkButton,\n OpenLinkButton,\n DeleteLinkButton,\n} from \"@blocknote/react\";\nimport { BlockNoteView } from \"@blocknote/mantine\";\nimport { insertOrUpdateBlock } from \"@blocknote/core\";\nimport { cn } from \"../utils/cn\";\n\nimport type { DefaultPartialBlock, LumirEditorProps } from \"../types\";\n\nimport { createS3Uploader } from \"../utils/s3-uploader\";\nimport { schema } from \"../blocks/HtmlPreview\";\nimport { FloatingMenu } from \"./FloatingMenu\";\nimport { LumirEditorError } from \"../errors/LumirEditorError\";\nimport { VerticalAlignmentExtension } from \"../extensions/VerticalAlignmentExtension\";\nimport { CustomFormattingToolbar } from \"./CustomFormattingToolbar\";\nimport { injectVerticalAlignment } from \"../utils/table-vertical-alignment\";\nimport {\n MAX_FILE_SIZE,\n MAX_VIDEO_FILE_SIZE,\n BLOCKED_EXTENSIONS,\n ALLOWED_VIDEO_MIME_TYPES,\n ALLOWED_VIDEO_EXTENSIONS,\n} from \"../constants/limits\";\n\n// #region agent log\nconst DEBUG_LOG = (loc: string, msg: string, data: Record<string, unknown>) => {\n const p = fetch(\"http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Debug-Session-Id\": \"b73262\" },\n body: JSON.stringify({\n sessionId: \"b73262\",\n location: loc,\n message: msg,\n data,\n timestamp: Date.now(),\n }),\n });\n if (p && typeof (p as Promise<unknown>).catch === \"function\") (p as Promise<unknown>).catch(() => {});\n};\n// #endregion\n\n// ==========================================\n// 유틸리티 클래스들\n// ==========================================\n\n/**\n * 콘텐츠 관리 유틸리티\n * 기본 블록 생성 및 콘텐츠 검증 로직을 담당\n */\nexport class ContentUtils {\n /**\n * JSON 문자열의 유효성을 검증합니다\n * @param jsonString 검증할 JSON 문자열\n * @returns 유효한 JSON 문자열인지 여부\n */\n static isValidJSONString(jsonString: string): boolean {\n try {\n const parsed = JSON.parse(jsonString);\n return Array.isArray(parsed);\n } catch {\n return false;\n }\n }\n\n /**\n * JSON 문자열을 DefaultPartialBlock 배열로 파싱합니다\n * @param jsonString JSON 문자열\n * @returns 파싱된 블록 배열 또는 null (파싱 실패 시)\n */\n static parseJSONContent(jsonString: string): DefaultPartialBlock[] | null {\n try {\n const parsed = JSON.parse(jsonString);\n if (Array.isArray(parsed)) {\n return parsed as DefaultPartialBlock[];\n }\n return null;\n } catch {\n return null;\n }\n }\n\n /**\n * 기본 paragraph 블록 생성\n * @returns 기본 설정이 적용된 DefaultPartialBlock\n */\n static createDefaultBlock(): DefaultPartialBlock {\n return {\n type: \"paragraph\",\n props: {\n textColor: \"default\",\n backgroundColor: \"default\",\n textAlignment: \"left\",\n },\n content: [{ type: \"text\", text: \"\", styles: {} }],\n children: [],\n };\n }\n\n /**\n * 콘텐츠 유효성 검증 및 기본값 설정\n * @param content 사용자 제공 콘텐츠 (객체 배열 또는 JSON 문자열)\n * @param emptyBlockCount 빈 블록 개수 (기본값: 3)\n * @returns 검증된 콘텐츠 배열\n */\n static validateContent(\n content?: DefaultPartialBlock[] | string,\n emptyBlockCount: number = 3\n ): DefaultPartialBlock[] {\n // 1. 문자열인 경우 JSON 파싱 시도\n if (typeof content === \"string\") {\n if (content.trim() === \"\") {\n return this.createEmptyBlocks(emptyBlockCount);\n }\n\n const parsedContent = this.parseJSONContent(content);\n if (parsedContent && parsedContent.length > 0) {\n return parsedContent;\n }\n\n // 파싱 실패 시 빈 블록 생성\n return this.createEmptyBlocks(emptyBlockCount);\n }\n\n // 2. 배열인 경우 기존 로직\n if (!content || content.length === 0) {\n return this.createEmptyBlocks(emptyBlockCount);\n }\n\n return content;\n }\n\n /**\n * 빈 블록들을 생성합니다\n * @param emptyBlockCount 생성할 블록 개수\n * @returns 생성된 빈 블록 배열\n */\n private static createEmptyBlocks(\n emptyBlockCount: number\n ): DefaultPartialBlock[] {\n return Array.from({ length: emptyBlockCount }, () =>\n this.createDefaultBlock()\n );\n }\n}\n\n/**\n * 에디터 설정 관리 유틸리티\n * 각종 설정의 기본값과 검증 로직을 담당\n */\nexport class EditorConfig {\n /**\n * 테이블 설정 기본값 적용\n * @param userTables 사용자 테이블 설정\n * @returns 기본값이 적용된 테이블 설정\n */\n static getDefaultTableConfig(userTables?: LumirEditorProps[\"tables\"]) {\n return {\n splitCells: userTables?.splitCells ?? true,\n cellBackgroundColor: userTables?.cellBackgroundColor ?? true,\n cellTextColor: userTables?.cellTextColor ?? true,\n headers: userTables?.headers ?? true,\n };\n }\n\n /**\n * 헤딩 설정 기본값 적용\n * @param userHeading 사용자 헤딩 설정\n * @returns 기본값이 적용된 헤딩 설정\n */\n static getDefaultHeadingConfig(userHeading?: LumirEditorProps[\"heading\"]) {\n return userHeading?.levels && userHeading.levels.length > 0\n ? userHeading\n : { levels: [1, 2, 3, 4, 5, 6] as (1 | 2 | 3 | 4 | 5 | 6)[] };\n }\n\n /**\n * 비활성화할 확장 기능 목록 생성\n * @param userExtensions 사용자 정의 비활성 확장\n * @param allowVideo 비디오 업로드 허용 여부\n * @param allowAudio 오디오 업로드 허용 여부\n * @param allowFile 일반 파일 업로드 허용 여부\n * @returns 비활성화할 확장 기능 목록\n */\n static getDisabledExtensions(\n userExtensions?: string[],\n allowVideo = false,\n allowAudio = false,\n allowFile = false\n ): string[] {\n const set = new Set<string>(userExtensions ?? []);\n if (!allowVideo) set.add(\"video\");\n if (!allowAudio) set.add(\"audio\");\n if (!allowFile) set.add(\"file\");\n return Array.from(set);\n }\n}\n\n// 파일 타입 검증 함수\n/** @internal 테스트용 export */\nexport const isImageFile = (file: File, maxSize?: number): boolean => {\n const limit = maxSize !== undefined ? maxSize : MAX_FILE_SIZE;\n if (file.size === 0 || file.size > limit) {\n return false;\n }\n\n // 🔒 보안: SVG 파일 차단 (XSS 방지)\n const fileName = file.name?.toLowerCase() || \"\";\n if (\n file.type === \"image/svg+xml\" ||\n BLOCKED_EXTENSIONS.some((ext) => fileName.endsWith(ext))\n ) {\n return false;\n }\n\n // 이미지 타입 검증\n return (\n file.type?.startsWith(\"image/\") ||\n (!file.type && /\\.(png|jpe?g|gif|webp|bmp)$/i.test(fileName))\n );\n};\n\n/** @internal 테스트용 export */\nexport const isVideoFile = (file: File, maxSize?: number): boolean => {\n const limit = maxSize !== undefined ? maxSize : MAX_VIDEO_FILE_SIZE;\n const sizeOk = file.size > 0 && file.size <= limit;\n const fileName = file.name?.toLowerCase() || \"\";\n const mimeMatch = ALLOWED_VIDEO_MIME_TYPES.has(file.type);\n const videoPrefix = typeof file.type === \"string\" && file.type.startsWith(\"video/\");\n const extMatch = !file.type && ALLOWED_VIDEO_EXTENSIONS.some((ext) => fileName.endsWith(ext));\n const result = sizeOk && (mimeMatch || videoPrefix || extMatch);\n // #region agent log\n DEBUG_LOG(\"isVideoFile:check\", \"result\", {\n fileName: file.name,\n fileType: file.type,\n fileSize: file.size,\n sizeOk,\n mimeMatch,\n videoPrefix,\n extMatch,\n result,\n });\n // #endregion\n return result;\n};\n\n/** @internal 테스트용 export */\nexport const isHtmlFile = (file: File): boolean => {\n return (\n file.size > 0 &&\n (file.type === \"text/html\" ||\n file.name?.toLowerCase().endsWith(\".html\") ||\n file.name?.toLowerCase().endsWith(\".htm\"))\n );\n};\n\n// ============================================\n// 🔒 보안 유틸리티 함수\n// ============================================\n\n/**\n * HTML 특수문자 이스케이프 (XSS 방지)\n * URL이나 사용자 입력을 HTML에 삽입할 때 사용\n * @internal 테스트용 export\n */\nexport const escapeHtml = (str: string): string => {\n const htmlEscapes: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n };\n return str.replace(/[&<>\"']/g, (char) => htmlEscapes[char]);\n};\n\n/**\n * 블록 배열에서 모든 이미지 URL 추출\n * (중첩된 children도 재귀적으로 탐색)\n * @internal 테스트용 export\n */\nexport const extractImageUrls = (blocks: DefaultPartialBlock[]): Set<string> => {\n const urls = new Set<string>();\n\n const traverse = (blockList: DefaultPartialBlock[]) => {\n for (const block of blockList) {\n // image 블록에서 URL 추출\n if (block.type === \"image\" && (block.props as any)?.url) {\n const url = (block.props as any).url;\n if (typeof url === \"string\" && url.trim()) {\n urls.add(url);\n }\n }\n // children이 있으면 재귀 탐색\n if (block.children && Array.isArray(block.children)) {\n traverse(block.children as DefaultPartialBlock[]);\n }\n }\n };\n\n traverse(blocks);\n return urls;\n};\n\n/**\n * 블록 배열에서 이미지·비디오(미디어) URL 추출\n * (중첩된 children도 재귀적으로 탐색, onImageDelete 삭제 감지용)\n * @internal 테스트용 export\n */\nexport const extractMediaUrls = (blocks: DefaultPartialBlock[]): Set<string> => {\n const urls = new Set<string>();\n\n const traverse = (blockList: DefaultPartialBlock[]) => {\n for (const block of blockList) {\n if (block.type === \"image\" && (block.props as any)?.url) {\n const url = (block.props as any).url;\n if (typeof url === \"string\" && url.trim()) urls.add(url);\n }\n if (block.type === \"video\" && (block.props as any)?.url) {\n const url = (block.props as any).url;\n if (typeof url === \"string\" && url.trim()) urls.add(url);\n }\n if (block.children && Array.isArray(block.children)) {\n traverse(block.children as DefaultPartialBlock[]);\n }\n }\n };\n\n traverse(blocks);\n return urls;\n};\n\n/**\n * 삭제된 미디어(이미지·비디오) URL 찾기\n * (이전 블록에는 있었지만 현재 블록에는 없는 URL)\n * @internal 테스트용 export\n */\nexport const findDeletedMediaUrls = (\n previousUrls: Set<string>,\n currentUrls: Set<string>\n): string[] => {\n const deleted: string[] = [];\n previousUrls.forEach((url) => {\n if (!currentUrls.has(url)) deleted.push(url);\n });\n return deleted;\n};\n\n/**\n * 삭제된 이미지 URL 찾기 (findDeletedMediaUrls와 동일 로직, 하위 호환용)\n * @internal 테스트용 export\n */\nexport const findDeletedImageUrls = (\n previousUrls: Set<string>,\n currentUrls: Set<string>\n): string[] => findDeletedMediaUrls(previousUrls, currentUrls);\n\nconst findBlockWithLink = (blocks: any[], targetUrl: string): any | null => {\n for (const block of blocks) {\n if (block.content) {\n for (const item of block.content) {\n if (item.type === \"link\" && item.href === targetUrl) return block;\n if (item.content) {\n for (const sub of item.content) {\n if (sub.type === \"link\" && sub.href === targetUrl) return block;\n }\n }\n }\n }\n if (block.children?.length) {\n const found = findBlockWithLink(block.children, targetUrl);\n if (found) return found;\n }\n }\n return null;\n};\n\nconst ConvertToPreviewButton = ({ url }: { url: string }) => {\n const editor = useBlockNoteEditor();\n const Components = useComponentsContext()!;\n\n return (\n <Components.LinkToolbar.Button\n className=\"bn-button\"\n mainTooltip=\"링크 프리뷰로 전환\"\n label=\"링크 프리뷰로 전환\"\n isSelected={false}\n onClick={() => {\n try {\n const allBlocks = (editor as any).document;\n const targetBlock = findBlockWithLink(allBlocks, url)\n || editor.getTextCursorPosition().block;\n (editor as any).replaceBlocks(\n [targetBlock],\n [{ type: \"linkPreview\", props: { url } }]\n );\n } catch (err) {\n console.error(\"Convert to link preview failed:\", err);\n }\n }}\n icon={\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"1\" y=\"3\" width=\"14\" height=\"10\" rx=\"2\" stroke=\"currentColor\" strokeWidth=\"1.5\" fill=\"none\" />\n <line x1=\"1\" y1=\"9\" x2=\"15\" y2=\"9\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <circle cx=\"5\" cy=\"6.5\" r=\"1.5\" stroke=\"currentColor\" strokeWidth=\"1\" fill=\"none\" />\n </svg>\n }\n />\n );\n};\n\nconst CustomLinkToolbar = (props: any) => {\n const editor = useBlockNoteEditor();\n const Components = useComponentsContext()!;\n const hasLinkPreview = !!(editor as any)?._linkPreviewApiEndpoint;\n\n return (\n <Components.LinkToolbar.Root\n className=\"bn-toolbar bn-link-toolbar\"\n onMouseEnter={props.stopHideTimer}\n onMouseLeave={props.startHideTimer}\n >\n <EditLinkButton url={props.url} text={props.text} editLink={props.editLink} />\n <OpenLinkButton url={props.url} />\n <DeleteLinkButton deleteLink={props.deleteLink} />\n {hasLinkPreview && (\n <ConvertToPreviewButton url={props.url} />\n )}\n </Components.LinkToolbar.Root>\n );\n};\n\nexport default function LumirEditor({\n // editor options\n initialContent,\n initialEmptyBlocks = 3,\n uploadFile,\n s3Upload,\n tables,\n heading,\n defaultStyles = true,\n disableExtensions,\n tabBehavior = \"prefer-navigate-ui\",\n trailingBlock = true,\n allowVideoUpload = false,\n allowAudioUpload = false,\n allowFileUpload = false,\n maxImageFileSize,\n maxVideoFileSize,\n // link preview\n linkPreview,\n // view options\n editable = true,\n theme = \"light\",\n formattingToolbar = true,\n linkToolbar = true,\n sideMenu = true,\n emojiPicker = true,\n filePanel = true,\n tableHandles = true,\n onSelectionChange,\n className = \"\",\n placeholder,\n sideMenuAddButton = false,\n floatingMenu = false,\n floatingMenuPosition = \"sticky\",\n // callbacks / refs\n onContentChange,\n onError,\n onImageDelete,\n}: LumirEditorProps) {\n // 이미지 업로드 로딩 상태\n const [isUploading, setIsUploading] = useState(false);\n /** S3 업로드 진행률 0–100. null이면 진행률 미표시 */\n const [uploadProgress, setUploadProgress] = useState<number | null>(null);\n // 에러 상태 (사용자에게 표시할 에러 메시지)\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n // FloatingMenu: DOM에 항상 있는 file input (onchange 미발생 방지)\n const floatingMenuFileInputRef = useRef<HTMLInputElement | null>(null);\n const floatingMenuBlockRef = useRef<{ id: string } | null>(null);\n const floatingMenuUploadStartTimeRef = useRef<number>(0);\n\n // 에러 처리 핸들러\n const handleError = useCallback(\n (error: LumirEditorError) => {\n // 콜백이 있으면 호출\n onError?.(error);\n // 사용자에게 에러 메시지 표시\n setErrorMessage(error.getUserMessage());\n // 3초 후 에러 메시지 자동 숨김\n setTimeout(() => setErrorMessage(null), 3000);\n },\n [onError]\n );\n const validatedContent = useMemo<DefaultPartialBlock[]>(() => {\n return ContentUtils.validateContent(initialContent, initialEmptyBlocks);\n }, [initialContent, initialEmptyBlocks]);\n\n // 테이블 설정 메모이제이션\n const tableConfig = useMemo(() => {\n return EditorConfig.getDefaultTableConfig(tables);\n }, [\n tables?.splitCells,\n tables?.cellBackgroundColor,\n tables?.cellTextColor,\n tables?.headers,\n ]);\n\n // 헤딩 설정 메모이제이션\n const headingConfig = useMemo(() => {\n return EditorConfig.getDefaultHeadingConfig(heading);\n }, [heading?.levels?.join(\",\") ?? \"\"]);\n\n // 비활성화 확장 메모이제이션\n const disabledExtensions = useMemo(() => {\n return EditorConfig.getDisabledExtensions(\n disableExtensions,\n allowVideoUpload,\n allowAudioUpload,\n allowFileUpload\n );\n }, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);\n\n // #region agent log\n useEffect(() => {\n DEBUG_LOG(\"LumirEditor:init:disabledExtensions\", \"snapshot\", {\n allowVideoUpload,\n hasVideoInDisabled: disabledExtensions.includes(\"video\"),\n disabledList: disabledExtensions.slice(0, 15),\n });\n }, [allowVideoUpload, disabledExtensions]);\n // #endregion\n\n // fileNameTransform 콜백을 ref로 관리 (에디터 재생성 방지)\n const fileNameTransformRef = useRef(s3Upload?.fileNameTransform);\n useEffect(() => {\n fileNameTransformRef.current = s3Upload?.fileNameTransform;\n }, [s3Upload?.fileNameTransform]);\n\n // S3 업로드 설정 메모이제이션 (객체 참조 안정화)\n // 주의: fileNameTransform은 ref로 관리하므로 의존성에서 제외\n const memoizedS3Upload = useMemo(() => {\n if (!s3Upload) return undefined;\n return {\n apiEndpoint: s3Upload.apiEndpoint,\n env: s3Upload.env,\n path: s3Upload.path,\n appendUUID: s3Upload.appendUUID,\n preserveExtension: s3Upload.preserveExtension,\n uploadTimeoutMs: s3Upload.uploadTimeoutMs,\n maxRetries: s3Upload.maxRetries,\n onProgress: (percent: number) => {\n setUploadProgress(percent);\n s3Upload.onProgress?.(percent);\n },\n // 최신 콜백을 항상 사용하도록 ref를 통해 접근\n fileNameTransform: ((originalName: string, file: File) => {\n return fileNameTransformRef.current\n ? fileNameTransformRef.current(originalName, file)\n : originalName;\n }) as ((originalName: string, file: File) => string) | undefined,\n };\n }, [\n s3Upload?.apiEndpoint,\n s3Upload?.env,\n s3Upload?.path,\n s3Upload?.appendUUID,\n s3Upload?.preserveExtension,\n s3Upload?.uploadTimeoutMs,\n s3Upload?.maxRetries,\n s3Upload?.onProgress,\n ]);\n\n const editor = useCreateBlockNote(\n {\n // HTML 미리보기 블록이 포함된 커스텀 스키마 사용\n schema,\n initialContent: validatedContent as any,\n tables: tableConfig,\n heading: headingConfig,\n animations: false, // 기본적으로 애니메이션 비활성화\n defaultStyles,\n // 확장 비활성: 비디오/오디오/파일 제어\n disableExtensions: disabledExtensions,\n _tiptapOptions: {\n extensions: [VerticalAlignmentExtension],\n },\n placeholders: placeholder\n ? { default: placeholder, emptyDocument: placeholder }\n : undefined,\n tabBehavior,\n trailingBlock,\n uploadFile: async (file) => {\n const allowedImage = isImageFile(file, maxImageFileSize);\n const allowedVideo =\n allowVideoUpload && isVideoFile(file, maxVideoFileSize);\n // #region agent log\n DEBUG_LOG(\"uploadFile:step1:entry\", \"editor uploadFile callback invoked\", {\n fileName: file.name,\n fileType: file.type,\n fileSize: file.size,\n allowVideoUpload,\n allowedImage,\n allowedVideo,\n });\n // #endregion\n if (!allowedImage && !allowedVideo) {\n const error = LumirEditorError.invalidFileType(\n file.name,\n allowVideoUpload\n );\n handleError(error);\n throw error;\n }\n\n try {\n setUploadProgress(0);\n let fileUrl: string;\n // #region agent log\n const branch = uploadFile ? \"custom\" : memoizedS3Upload?.apiEndpoint ? \"s3\" : \"none\";\n DEBUG_LOG(\"uploadFile:step2:branch\", \"upload path\", {\n branch,\n hasCustomUploadFile: !!uploadFile,\n hasS3ApiEndpoint: !!memoizedS3Upload?.apiEndpoint,\n });\n // #endregion\n // 1. 사용자 정의 uploadFile 우선\n if (uploadFile) {\n const t0 = Date.now();\n DEBUG_LOG(\"uploadFile:step3a:custom\", \"calling custom uploadFile\", { fileName: file.name });\n fileUrl = await uploadFile(file);\n DEBUG_LOG(\"uploadFile:step3a:done\", \"custom uploadFile returned\", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });\n }\n // 2. S3 업로드 (uploadFile 없을 때)\n else if (memoizedS3Upload?.apiEndpoint) {\n const t0 = Date.now();\n DEBUG_LOG(\"uploadFile:step3b:s3\", \"calling S3 uploader\", { fileName: file.name });\n const s3Uploader = createS3Uploader(memoizedS3Upload);\n fileUrl = await s3Uploader(file);\n DEBUG_LOG(\"uploadFile:step3b:done\", \"S3 uploader returned\", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });\n }\n // 3. 업로드 방법이 없으면 에러\n else {\n const error = LumirEditorError.s3ConfigError(\n \"No upload method available. Please provide uploadFile or s3Upload configuration.\"\n );\n handleError(error);\n throw error;\n }\n\n // BlockNote가 파일 타입에 따라 이미지/비디오 블록을 생성하도록 URL만 반환\n // #region agent log\n DEBUG_LOG(\"uploadFile:step4:success\", \"returning URL\", {\n fileName: file.name,\n urlPrefix: fileUrl.slice(0, 80),\n });\n // #endregion\n return fileUrl;\n } catch (error) {\n // #region agent log\n DEBUG_LOG(\"uploadFile:step5:catch\", \"uploadFile threw\", {\n fileName: file.name,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n // #endregion\n // 이미 LumirEditorError인 경우 다시 처리하지 않음\n if (error instanceof LumirEditorError) {\n throw error;\n }\n const lumirError = LumirEditorError.uploadFailed(\n error instanceof Error ? error.message : String(error),\n error instanceof Error ? error : undefined\n );\n handleError(lumirError);\n throw lumirError;\n } finally {\n setUploadProgress(null);\n }\n },\n pasteHandler: (ctx) => {\n const { event, editor, defaultPasteHandler } = ctx as any;\n\n // URL 붙여넣기 감지 → linkPreview 블록 생성\n if (linkPreview?.apiEndpoint) {\n const text = event?.clipboardData?.getData?.(\"text/plain\") || \"\";\n const trimmed = text.trim();\n if (\n trimmed &&\n /^https?:\\/\\/\\S+$/i.test(trimmed) &&\n !event?.clipboardData?.files?.length\n ) {\n event.preventDefault();\n const currentBlock = editor.getTextCursorPosition().block;\n const blockText = currentBlock.content\n ?.map((c: any) => c.text || \"\")\n .join(\"\")\n .trim();\n if (!blockText && currentBlock.type === \"paragraph\") {\n editor.updateBlock(currentBlock, {\n type: \"linkPreview\",\n props: { url: trimmed },\n });\n } else {\n editor.insertBlocks(\n [{ type: \"linkPreview\", props: { url: trimmed } }],\n currentBlock,\n \"after\"\n );\n }\n return true;\n }\n }\n\n const fileList =\n (event?.clipboardData?.files as FileList | null) ?? null;\n const files: File[] = fileList ? Array.from(fileList) : [];\n const acceptedFiles: File[] = files.filter(\n (f) =>\n isImageFile(f, maxImageFileSize) || (allowVideoUpload && isVideoFile(f, maxVideoFileSize))\n );\n // #region agent log\n DEBUG_LOG(\"paste:step1:files\", \"paste clipboard files\", {\n filesCount: files.length,\n acceptedCount: acceptedFiles.length,\n fileNames: files.map((f) => f.name),\n acceptedNames: acceptedFiles.map((f) => f.name),\n });\n // #endregion\n // 파일이 있지만 허용된 미디어가 없으면 기본 처리 막고 무시\n if (files.length > 0 && acceptedFiles.length === 0) {\n event.preventDefault();\n return true;\n }\n\n if (acceptedFiles.length === 0) {\n return defaultPasteHandler() ?? false;\n }\n\n event.preventDefault();\n (async () => {\n setIsUploading(true);\n try {\n for (const file of acceptedFiles) {\n try {\n // #region agent log\n DEBUG_LOG(\"paste:step2:upload\", \"calling uploadFile for paste\", {\n fileName: file.name,\n fileType: file.type,\n });\n // #endregion\n const url = await editor.uploadFile(file);\n if (isImageFile(file, maxImageFileSize)) {\n editor.pasteHTML(\n `<img src=\"${escapeHtml(url)}\" alt=\"image\" />`\n );\n } else if (isVideoFile(file, maxVideoFileSize)) {\n const currentBlock = editor.getTextCursorPosition().block;\n editor.insertBlocks(\n [{ type: \"video\", props: { url } }] as any,\n currentBlock,\n \"after\"\n );\n }\n } catch (err) {\n console.warn(\n \"Upload failed, skipped:\",\n file.name || \"\",\n err\n );\n }\n }\n } finally {\n setIsUploading(false);\n }\n })();\n return true;\n },\n },\n [\n validatedContent,\n tableConfig,\n headingConfig,\n defaultStyles,\n disabledExtensions,\n tabBehavior,\n trailingBlock,\n uploadFile,\n memoizedS3Upload,\n allowVideoUpload,\n linkPreview?.apiEndpoint,\n placeholder,\n ]\n );\n\n // Link Preview API endpoint를 에디터 인스턴스에 동기적으로 연결\n // (useEffect 사용 시 블록 렌더링보다 늦게 설정되어 첫 fetch가 실패할 수 있음)\n if (editor && linkPreview?.apiEndpoint) {\n (editor as any)._linkPreviewApiEndpoint = linkPreview.apiEndpoint;\n }\n\n // 편집 가능 여부 설정\n useEffect(() => {\n if (editor) {\n editor.isEditable = editable;\n }\n }, [editor, editable]);\n\n // 콘텐츠 변경 감지\n useEffect(() => {\n if (!editor || !onContentChange) return;\n\n const handleContentChange = () => {\n const blocks = editor.topLevelBlocks as DefaultPartialBlock[];\n const patched = injectVerticalAlignment(blocks, editor);\n onContentChange(patched);\n };\n\n return editor.onEditorContentChange(handleContentChange);\n }, [editor, onContentChange]);\n\n // 이미지·비디오 삭제 감지 (onImageDelete 콜백 — 미디어 URL 모두 전달)\n const previousMediaUrlsRef = useRef<Set<string>>(new Set());\n\n useEffect(() => {\n if (!editor) return;\n\n const initialBlocks = editor.topLevelBlocks as DefaultPartialBlock[];\n previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);\n }, [editor]);\n\n useEffect(() => {\n if (!editor || !onImageDelete) return;\n\n const handleMediaDeleteCheck = () => {\n const currentBlocks = editor.topLevelBlocks as DefaultPartialBlock[];\n const currentUrls = extractMediaUrls(currentBlocks);\n const previousUrls = previousMediaUrlsRef.current;\n\n const deletedUrls = findDeletedMediaUrls(previousUrls, currentUrls);\n deletedUrls.forEach((url) => {\n onImageDelete(url);\n });\n\n previousMediaUrlsRef.current = currentUrls;\n };\n\n return editor.onEditorContentChange(handleMediaDeleteCheck);\n }, [editor, onImageDelete]);\n\n // 드래그앤드롭 이미지/HTML 처리\n useEffect(() => {\n const el = editor?.domElement as HTMLElement | undefined;\n if (!el) return;\n\n const handleDragOver = (e: DragEvent) => {\n if (e.defaultPrevented) return;\n const hasFiles = (\n e.dataTransfer?.types as unknown as string[] | undefined\n )?.includes?.(\"Files\");\n if (hasFiles) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n const handleDrop = (e: DragEvent) => {\n if (!e.dataTransfer) return;\n const hasFiles = (\n (e.dataTransfer.types as unknown as string[] | undefined) ?? []\n ).includes(\"Files\");\n if (!hasFiles) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n const items = Array.from(e.dataTransfer.items ?? []);\n const files = items\n .filter((it) => it.kind === \"file\")\n .map((it) => it.getAsFile())\n .filter((f): f is File => !!f);\n\n // 이미지, 동영상, HTML 파일 분리\n const imageFiles = files.filter((f) => isImageFile(f, maxImageFileSize));\n const videoFiles = allowVideoUpload\n ? files.filter((f) => isVideoFile(f, maxVideoFileSize))\n : [];\n const htmlFiles = files.filter(isHtmlFile);\n\n // #region agent log\n DEBUG_LOG(\"drop:step1:files\", \"drop received\", {\n filesCount: files.length,\n imageCount: imageFiles.length,\n videoCount: videoFiles.length,\n htmlCount: htmlFiles.length,\n allowVideoUpload,\n firstFile: files[0]\n ? {\n name: files[0].name,\n type: files[0].type,\n size: files[0].size,\n isImage: isImageFile(files[0], maxImageFileSize),\n isVideo: isVideoFile(files[0], maxVideoFileSize),\n }\n : null,\n });\n // #endregion\n\n if (\n imageFiles.length === 0 &&\n htmlFiles.length === 0 &&\n videoFiles.length === 0\n )\n return;\n\n (async () => {\n setIsUploading(true);\n try {\n // #region agent log\n DEBUG_LOG(\"drop:step2:async\", \"drop async started\", {\n imageCount: imageFiles.length,\n videoCount: videoFiles.length,\n });\n // #endregion\n // 이미지 파일 처리\n for (const file of imageFiles) {\n try {\n if (editor?.uploadFile) {\n const url = await editor.uploadFile(file);\n if (url && typeof url === \"string\") {\n editor.pasteHTML(\n `<img src=\"${escapeHtml(url)}\" alt=\"image\" />`\n );\n }\n }\n } catch (err) {\n console.warn(\n \"Image upload failed, skipped:\",\n file.name || \"\",\n err\n );\n }\n }\n\n // 동영상 파일 처리 - video 블록으로 삽입\n // #region agent log\n DEBUG_LOG(\"drop:step3:videoLoop\", \"video loop start\", {\n videoCount: videoFiles.length,\n names: videoFiles.map((f) => f.name),\n });\n // #endregion\n for (const file of videoFiles) {\n try {\n if (editor?.uploadFile) {\n // #region agent log\n DEBUG_LOG(\"drop:step4:videoUpload\", \"calling uploadFile for video\", {\n fileName: file.name,\n });\n // #endregion\n const url = await editor.uploadFile(file);\n if (url && typeof url === \"string\") {\n const currentBlock = editor.getTextCursorPosition().block;\n editor.insertBlocks(\n [{ type: \"video\", props: { url } }] as any,\n currentBlock,\n \"after\"\n );\n }\n }\n } catch (err) {\n console.warn(\n \"Video upload failed, skipped:\",\n file.name || \"\",\n err\n );\n }\n }\n\n // HTML 파일 처리 - htmlPreview 블록으로 삽입\n for (const file of htmlFiles) {\n try {\n const htmlContent = await file.text();\n const currentBlock = editor.getTextCursorPosition().block;\n\n // htmlPreview 블록 삽입\n editor.insertBlocks(\n [\n {\n type: \"htmlPreview\",\n props: {\n htmlContent: htmlContent,\n fileName: file.name,\n height: \"400px\",\n },\n },\n ],\n currentBlock,\n \"after\"\n );\n } catch (err) {\n console.warn(\n \"HTML file processing failed, skipped:\",\n file.name || \"\",\n err\n );\n }\n }\n } finally {\n setIsUploading(false);\n }\n })();\n };\n\n el.addEventListener(\"dragover\", handleDragOver, { capture: true });\n el.addEventListener(\"drop\", handleDrop, { capture: true });\n\n return () => {\n el.removeEventListener(\"dragover\", handleDragOver, {\n capture: true,\n } as any);\n el.removeEventListener(\"drop\", handleDrop, { capture: true } as any);\n };\n }, [editor, allowVideoUpload]);\n\n // SideMenu 설정 (Add 버튼 제어)\n const computedSideMenu = useMemo(() => {\n return sideMenuAddButton ? sideMenu : false;\n }, [sideMenuAddButton, sideMenu]);\n\n // Add 버튼 없는 사이드 메뉴 (드래그 핸들만) - 메모이제이션\n const DragHandleOnlySideMenu = useMemo(() => {\n return (props: any) => (\n <BlockSideMenu {...props}>\n <DragHandleButton {...props} />\n </BlockSideMenu>\n );\n }, []);\n\n return (\n <div\n className={cn(\"lumirEditor\", className)}\n style={{ position: \"relative\", display: \"flex\", flexDirection: \"column\" }}\n >\n {/* FloatingMenu를 BlockNoteView 외부로 이동 */}\n {floatingMenu && editor && (\n <>\n <input\n ref={floatingMenuFileInputRef}\n type=\"file\"\n accept={\n allowVideoUpload\n ? \"image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov\"\n : \"image/*\"\n }\n style={{\n position: \"absolute\",\n left: \"-9999px\",\n opacity: 0,\n pointerEvents: \"none\",\n }}\n onChange={async (e) => {\n const inputEl = e.target as HTMLInputElement;\n const file = inputEl.files?.[0];\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step3:onchange\", \"file input onchange fired\", {\n hasFile: !!file,\n fileName: file?.name,\n fileType: file?.type,\n fileSize: file?.size,\n hasUploadFile: !!editor?.uploadFile,\n });\n // #endregion\n const blockToInsertAfter = floatingMenuBlockRef.current;\n if (file && editor.uploadFile && blockToInsertAfter) {\n const allowedImage = isImageFile(file, maxImageFileSize);\n const allowedVideo = allowVideoUpload && isVideoFile(file, maxVideoFileSize);\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step4:fileCheck\", \"allowed check\", {\n fileName: file.name,\n allowedImage,\n allowedVideo,\n });\n // #endregion\n if (allowedImage || allowedVideo) {\n try {\n setIsUploading(true);\n floatingMenuUploadStartTimeRef.current = Date.now();\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step5:uploadStart\", \"calling editor.uploadFile\", {\n fileName: file.name,\n });\n // #endregion\n const url = await editor.uploadFile(file);\n const blockType = allowedVideo ? \"video\" : \"image\";\n const elapsedMs = Date.now() - floatingMenuUploadStartTimeRef.current;\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step6:uploadDone\", \"upload returned, inserting block\", {\n blockType,\n blockId: blockToInsertAfter.id,\n urlLen: url?.length,\n elapsedMs,\n });\n // #endregion\n editor.insertBlocks(\n [\n {\n type: blockType,\n props: { url: url as string },\n },\n ] as any,\n blockToInsertAfter,\n \"after\"\n );\n } catch (err) {\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step7:catch\", \"upload or insert failed\", {\n errMsg: err instanceof Error ? err.message : String(err),\n });\n // #endregion\n console.error(\"Upload failed:\", err);\n } finally {\n setIsUploading(false);\n }\n }\n }\n inputEl.value = \"\";\n }}\n />\n <FloatingMenu\n editor={editor as any}\n position={floatingMenuPosition}\n onImageUpload={() => {\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step1:click\", \"upload button clicked\", {\n allowVideoUpload,\n });\n // #endregion\n let blockToInsertAfter: { id: string };\n try {\n blockToInsertAfter = editor.getTextCursorPosition().block;\n } catch (err) {\n DEBUG_LOG(\"FloatingMenu:step1b:error\", \"getTextCursorPosition failed\", {\n err: err instanceof Error ? err.message : String(err),\n });\n return;\n }\n floatingMenuBlockRef.current = blockToInsertAfter;\n const input = floatingMenuFileInputRef.current;\n if (!input) return;\n input.accept = allowVideoUpload\n ? \"image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov\"\n : \"image/*\";\n input.value = \"\";\n // #region agent log\n DEBUG_LOG(\"FloatingMenu:step2:inputReady\", \"persistent input ref, about to click\", {\n accept: input.accept,\n });\n DEBUG_LOG(\"FloatingMenu:step2b:click\", \"input.click() about to be called\", {});\n // #endregion\n input.click();\n }}\n />\n </>\n )}\n <BlockNoteView\n editor={editor}\n editable={editable}\n theme={theme}\n formattingToolbar={false}\n linkToolbar={false}\n sideMenu={computedSideMenu}\n slashMenu={false}\n emojiPicker={emojiPicker}\n filePanel={filePanel}\n tableHandles={tableHandles}\n onSelectionChange={onSelectionChange}\n >\n {formattingToolbar && (\n <FormattingToolbarController\n formattingToolbar={CustomFormattingToolbar}\n />\n )}\n {linkToolbar && (\n linkPreview?.apiEndpoint\n ? <LinkToolbarController linkToolbar={CustomLinkToolbar} />\n : <LinkToolbarController />\n )}\n {\n <SuggestionMenuController\n triggerCharacter=\"/\"\n getItems={useCallback(\n async (query: string) => {\n const items = getDefaultReactSlashMenuItems(editor);\n // 오디오/파일 항목 제거; 비디오는 allowVideoUpload일 때만 표시\n const filtered = items.filter((item: any) => {\n const key = (item?.key || \"\").toString().toLowerCase();\n const title = (item?.title || \"\").toString().toLowerCase();\n if (key === \"video\" || title.includes(\"video\"))\n return allowVideoUpload;\n if ([\"audio\", \"file\"].includes(key)) return false;\n if (title.includes(\"audio\") || title.includes(\"file\"))\n return false;\n return true;\n });\n\n // HTML 미리보기 슬래시 메뉴 항목 추가\n const htmlPreviewItem = {\n title: \"HTML Preview\",\n onItemClick: () => {\n // 파일 선택 다이얼로그 열기\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \".html,.htm\";\n input.onchange = async (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (file) {\n const htmlContent = await file.text();\n const currentBlock =\n editor.getTextCursorPosition().block;\n editor.insertBlocks(\n [\n {\n type: \"htmlPreview\",\n props: {\n htmlContent: htmlContent,\n fileName: file.name,\n height: \"400px\",\n },\n },\n ],\n currentBlock,\n \"after\"\n );\n }\n };\n input.click();\n },\n aliases: [\"html\", \"preview\", \"웹\", \"웹페이지\"],\n group: \"Embeds\",\n icon: (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"16 18 22 12 16 6\"></polyline>\n <polyline points=\"8 6 2 12 8 18\"></polyline>\n </svg>\n ),\n subtext: \"HTML 파일을 미리보기로 삽입\",\n };\n\n const allItems = [...filtered, htmlPreviewItem];\n\n // Link Preview 슬래시 메뉴 항목 (linkPreview 설정이 있을 때만)\n if (linkPreview?.apiEndpoint) {\n allItems.push({\n title: \"Link Preview\",\n onItemClick: () => {\n insertOrUpdateBlock(editor, {\n type: \"linkPreview\",\n props: { url: \"\" },\n });\n },\n aliases: [\n \"link\",\n \"preview\",\n \"url\",\n \"링크\",\n \"미리보기\",\n \"프리뷰\",\n ],\n group: \"Embeds\",\n icon: (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </svg>\n ),\n subtext: \"URL의 미리보기 카드를 삽입\",\n });\n }\n\n if (!query) return allItems;\n const q = query.toLowerCase();\n return allItems.filter(\n (item: any) =>\n item.title?.toLowerCase().includes(q) ||\n (item.aliases || []).some((a: string) =>\n a.toLowerCase().includes(q)\n )\n );\n },\n [editor, allowVideoUpload, linkPreview?.apiEndpoint]\n )}\n />\n }\n {!sideMenuAddButton && (\n <SideMenuController sideMenu={DragHandleOnlySideMenu} />\n )}\n </BlockNoteView>\n\n {/* 이미지/비디오 업로드 로딩 스피너 */}\n {isUploading && (\n <div className=\"lumirEditor-upload-overlay\">\n <div className=\"lumirEditor-spinner\" />\n {uploadProgress !== null && (\n <span className=\"lumirEditor-upload-progress\">{uploadProgress}%</span>\n )}\n </div>\n )}\n\n {/* 에러 메시지 토스트 */}\n {errorMessage && (\n <div className=\"lumirEditor-error-toast\">\n <span className=\"lumirEditor-error-icon\">⚠️</span>\n <span className=\"lumirEditor-error-message\">{errorMessage}</span>\n <button\n className=\"lumirEditor-error-close\"\n onClick={() => setErrorMessage(null)}\n type=\"button\"\n >\n ✕\n </button>\n </div>\n )}\n </div>\n );\n}\n","// clsx와 tailwind-merge를 사용한 className 유틸리티\n// 사용자가 직접 설치하도록 권장하거나, 간단한 버전 제공\n\nexport function cn(...inputs: (string | undefined | null | false)[]) {\n return inputs.filter(Boolean).join(' ');\n}\n","export interface S3UploaderConfig {\n apiEndpoint: string; // '/api/s3/presigned'(필수)\n env: \"production\" | \"development\"; // 환경 (필수)\n path: string; // 파일 경로 (필수)\n /** 파일명 변환 콜백 - 확장자를 제외한 파일명을 받아 변환합니다 */\n fileNameTransform?: (nameWithoutExt: string, file: File) => string;\n /** true일 경우 파일명 뒤에 UUID를 자동으로 추가합니다 (예: image_abc123.png) */\n appendUUID?: boolean;\n /** false로 설정하면 확장자를 자동으로 붙이지 않음 (기본: true) */\n preserveExtension?: boolean;\n /** 업로드 진행률(0–100) 콜백. S3 PUT 시에만 호출됨 */\n onProgress?: (percent: number) => void;\n /** PUT 요청 타임아웃(ms). 미설정 시 120000(120초). 대용량 비디오에 유리 */\n uploadTimeoutMs?: number;\n /** PUT 실패 시 재시도 횟수. 기본 2(최대 3회 시도) */\n maxRetries?: number;\n}\n\n/**\n * 🔒 보안: S3 URL 검증\n * HTTPS 프로토콜 강제 및 URL 형식 검증\n */\nfunction validateS3Url(url: unknown, fieldName: string): string {\n // 타입 검증\n if (typeof url !== \"string\" || !url || url.trim() === \"\") {\n throw new Error(\n `${fieldName} is required and must be a non-empty string`\n );\n }\n\n // HTTPS 프로토콜 강제 (SSRF 방지)\n if (!url.startsWith(\"https://\")) {\n throw new Error(`${fieldName} must use HTTPS protocol`);\n }\n\n // URL 형식 검증\n try {\n const urlObj = new URL(url);\n // 추가 검증: localhost, private IP 차단\n const hostname = urlObj.hostname.toLowerCase();\n if (\n hostname === \"localhost\" ||\n hostname.startsWith(\"127.\") ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname === \"169.254.169.254\" // AWS 메타데이터 서버\n ) {\n throw new Error(`${fieldName} cannot point to internal/private networks`);\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"cannot point to\")) {\n throw error;\n }\n throw new Error(`${fieldName} is not a valid URL format`);\n }\n\n return url;\n}\n\n// UUID 생성 함수 (crypto.randomUUID 또는 폴백)\nconst generateUUID = (): string => {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // 폴백: 간단한 UUID v4 형식 생성\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n};\n\nexport const createS3Uploader = (config: S3UploaderConfig) => {\n const {\n apiEndpoint,\n env,\n path,\n fileNameTransform,\n appendUUID,\n preserveExtension = true,\n onProgress,\n uploadTimeoutMs = 120000,\n maxRetries = 2,\n } = config;\n\n // 필수 파라미터 검증\n if (!apiEndpoint || apiEndpoint.trim() === \"\") {\n throw new Error(\n \"apiEndpoint is required for S3 upload. Please provide a valid API endpoint.\"\n );\n }\n\n if (!env) {\n throw new Error(\"env is required. Must be 'development' or 'production'.\");\n }\n\n if (!path || path.trim() === \"\") {\n throw new Error(\"path is required and cannot be empty.\");\n }\n\n // 파일명에 UUID 추가하는 함수\n const appendUUIDToFileName = (filename: string): string => {\n const lastDotIndex = filename.lastIndexOf(\".\");\n if (lastDotIndex === -1) {\n // 확장자가 없는 경우\n return `${filename}_${generateUUID()}`;\n }\n const name = filename.substring(0, lastDotIndex);\n const ext = filename.substring(lastDotIndex);\n return `${name}_${generateUUID()}${ext}`;\n };\n\n // 계층 구조 파일명 생성 함수\n const generateHierarchicalFileName = (file: File): string => {\n // 0. 확장자 분리\n const originalName = file.name;\n const lastDotIndex = originalName.lastIndexOf(\".\");\n const nameWithoutExt =\n lastDotIndex === -1\n ? originalName\n : originalName.substring(0, lastDotIndex);\n const extension =\n lastDotIndex === -1 ? \"\" : originalName.substring(lastDotIndex);\n\n let filename = nameWithoutExt;\n\n // 1. 사용자 정의 파일명 변환 콜백 적용 (확장자 제외한 이름만)\n if (fileNameTransform) {\n filename = fileNameTransform(filename, file);\n }\n\n // 2. UUID 자동 추가 (appendUUID가 true인 경우)\n if (appendUUID) {\n filename = `${filename}_${generateUUID()}`;\n }\n\n // 3. 확장자 다시 붙이기 (preserveExtension이 true인 경우만)\n if (preserveExtension) {\n filename = `${filename}${extension}`;\n }\n\n // {env}/{path}/{filename}\n return `${env}/${path}/${filename}`;\n };\n\n const debugLog = (loc: string, msg: string, data: Record<string, unknown>) => {\n const p = fetch(\"http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Debug-Session-Id\": \"b73262\" },\n body: JSON.stringify({ sessionId: \"b73262\", location: loc, message: msg, data, timestamp: Date.now() }),\n });\n if (p && typeof (p as Promise<unknown>).catch === \"function\") (p as Promise<unknown>).catch(() => {});\n };\n\n return async (file: File): Promise<string> => {\n try {\n if (!apiEndpoint || apiEndpoint.trim() === \"\") {\n throw new Error(\n \"Invalid apiEndpoint: Cannot upload file without a valid API ENDPOINT\"\n );\n }\n\n const fileName = generateHierarchicalFileName(file);\n const contentType = file.type || \"application/octet-stream\";\n const presignedUrlFull = `${apiEndpoint}?key=${encodeURIComponent(fileName)}&contentType=${encodeURIComponent(contentType)}`;\n const tPresigned = Date.now();\n // #region agent log\n debugLog(\"s3:step1:presignedReq\", \"fetching presigned URL\", {\n fileName,\n contentType,\n apiEndpoint,\n });\n // #endregion\n const response = await fetch(presignedUrlFull);\n\n // #region agent log\n debugLog(\"s3:step2:presignedRes\", \"presigned response\", {\n ok: response.ok,\n status: response.status,\n elapsedMs: Date.now() - tPresigned,\n });\n // #endregion\n if (!response.ok) {\n const errorText = (await response.text()) || \"\";\n debugLog(\"s3:step2b:presignedErr\", \"presigned failed\", {\n status: response.status,\n errorText: errorText.slice(0, 200),\n });\n throw new Error(\n `Failed to get presigned URL: ${response.statusText}, ${errorText}`\n );\n }\n\n const responseData = await response.json();\n const { presignedUrl, publicUrl } = responseData;\n const validatedPresignedUrl = validateS3Url(presignedUrl, \"presignedUrl\");\n const validatedPublicUrl = validateS3Url(publicUrl, \"publicUrl\");\n\n const tPut = Date.now();\n // #region agent log\n debugLog(\"s3:step3:putReq\", \"S3 PUT request\", { publicUrlLen: validatedPublicUrl?.length });\n // #endregion\n\n let lastError: Error | undefined;\n const attempts = maxRetries + 1;\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n if (onProgress && typeof XMLHttpRequest !== \"undefined\") {\n await new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.timeout = uploadTimeoutMs;\n\n // --- 진행률 보간용 상태 (progress 이벤트가 드물 때 중간 % 표시) ---\n let lastReported = -1; // 마지막으로 콜백에 넘긴 퍼센트 (중복 호출 방지)\n const REPORT_INTERVAL_MS = 100; // 보간 타이머 주기(ms)\n const simulatedCap = 90; // 보간 진행률 상한(%). 90 이상은 실제 progress 값 사용\n let simulatedPercent = 0;\n\n // 보간 타이머: progress 이벤트가 잘 오지 않을 때 주기적으로 진행률 상승\n const simId = setInterval(() => {\n if (simulatedPercent >= simulatedCap) return;\n simulatedPercent = Math.min(simulatedCap, simulatedPercent + 3);\n const p = Math.min(100, simulatedPercent);\n if (p > lastReported) {\n lastReported = p;\n onProgress(p);\n }\n }, REPORT_INTERVAL_MS);\n const clearSim = () => {\n clearInterval(simId);\n };\n\n // XHR 실제 업로드 진행률 (loaded/total)\n xhr.upload.onprogress = (e) => {\n if (e.lengthComputable) {\n const p = Math.min(100, Math.round((e.loaded / e.total) * 100));\n if (p >= simulatedCap) clearSim(); // 실제 진행이 90% 넘으면 보간 타이머 중단\n const toReport = Math.max(p, simulatedPercent); // 실제 vs 보간 중 큰 값 사용\n if (toReport > lastReported) {\n lastReported = toReport;\n onProgress(toReport);\n }\n }\n };\n xhr.onload = () => {\n clearSim();\n if (xhr.status >= 200 && xhr.status < 300) {\n if (lastReported < 100) onProgress(100); // 완료 시 100% 한 번 더 보장\n resolve();\n } else {\n reject(new Error(`Failed to upload file: ${xhr.statusText}`));\n }\n };\n xhr.onerror = () => {\n clearSim();\n reject(new Error(\"Upload failed\"));\n };\n xhr.ontimeout = () => {\n clearSim();\n reject(new Error(\"Upload timeout\"));\n };\n xhr.open(\"PUT\", validatedPresignedUrl);\n xhr.setRequestHeader(\"Content-Type\", file.type || \"application/octet-stream\");\n onProgress(0); // 업로드 시작 직후 0% 알림\n lastReported = 0;\n xhr.send(file);\n });\n } else {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), uploadTimeoutMs);\n const uploadResponse = await fetch(validatedPresignedUrl, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": file.type || \"application/octet-stream\",\n },\n body: file,\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n\n // #region agent log\n debugLog(\"s3:step4:putRes\", \"S3 PUT response\", {\n ok: uploadResponse.ok,\n status: uploadResponse.status,\n putElapsedMs: Date.now() - tPut,\n });\n // #endregion\n if (!uploadResponse.ok) {\n throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);\n }\n }\n debugLog(\"s3:step5:return\", \"returning publicUrl\", { urlPrefix: validatedPublicUrl.slice(0, 80) });\n return validatedPublicUrl;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < attempts - 1) {\n debugLog(\"s3:putRetry\", \"PUT failed, retrying\", { attempt: attempt + 1, attempts });\n } else {\n throw lastError;\n }\n }\n }\n\n throw lastError ?? new Error(\"Upload failed\");\n } catch (error) {\n console.error(\"S3 upload failed:\", error);\n throw error;\n }\n };\n};\n","import { createReactBlockSpec } from \"@blocknote/react\";\nimport {\n defaultBlockSpecs,\n BlockNoteSchema,\n defaultInlineContentSpecs,\n defaultStyleSpecs,\n} from \"@blocknote/core\";\nimport { LinkPreviewBlock } from \"./LinkPreview\";\nimport { VideoBlock } from \"./VideoBlock\";\nimport { useState, useRef, useCallback, useEffect } from \"react\";\n\n// HTML 미리보기 블록 속성 타입\nexport interface HtmlPreviewProps {\n htmlContent: string;\n fileName?: string;\n height?: string;\n}\n\n// 최소/최대 높이 상수\n/** @internal 테스트용 export */\nexport const MIN_HEIGHT = 100;\n/** @internal 테스트용 export */\nexport const MAX_HEIGHT = 1200;\n\n// ============================================\n// 보안 유틸리티 함수\n// ============================================\n\n/**\n * HTML에 charset이 없으면 UTF-8 meta 태그 추가\n * (원본 HTML을 최소한으로만 수정하여 인코딩 깨짐 방지)\n * @internal 테스트용 export\n */\nexport const ensureCharset = (html: string): string => {\n // 이미 charset이 있으면 원본 그대로 반환\n const hasCharset = /<meta[^>]+charset\\s*=/i.test(html);\n if (hasCharset) {\n return html;\n }\n\n // <head> 태그가 있으면 그 안에 추가\n if (/<head[^>]*>/i.test(html)) {\n return html.replace(/(<head[^>]*>)/i, '$1\\n<meta charset=\"UTF-8\">');\n }\n\n // <html> 태그만 있으면 <head> 추가\n if (/<html[^>]*>/i.test(html)) {\n return html.replace(\n /(<html[^>]*>)/i,\n '$1\\n<head><meta charset=\"UTF-8\"></head>'\n );\n }\n\n // HTML fragment인 경우 최소한의 구조 추가\n return `<!DOCTYPE html>\n<html>\n<head><meta charset=\"UTF-8\"></head>\n<body>\n${html}\n</body>\n</html>`;\n};\n\n/**\n * 파일명 새니타이제이션 (경로 조작 방지)\n * @internal 테스트용 export\n */\nexport const sanitizeFileName = (fileName: string): string => {\n if (!fileName || typeof fileName !== \"string\") {\n return `document_${Date.now()}.html`;\n }\n\n return (\n fileName\n .replace(/\\0/g, \"\") // Null byte 제거\n .replace(/[\\/\\\\]/g, \"_\") // 경로 구분자 제거\n .replace(/[<>:\"|?*\\x00-\\x1f]/g, \"\") // 위험한 문자 제거\n .replace(/\\.{2,}/g, \".\") // 연속된 점 제거\n .trim()\n .replace(/^\\.+|\\.+$/g, \"\") || `document_${Date.now()}.html` // 앞뒤 점 제거\n );\n};\n\n/**\n * Blob URL 생성 (UTF-8 인코딩 명시)\n * @internal 테스트용 export\n */\nexport const createSecureBlobUrl = (htmlContent: string): string => {\n const htmlWithCharset = ensureCharset(htmlContent);\n\n // UTF-8 인코딩 명시\n const blob = new Blob([htmlWithCharset], {\n type: \"text/html;charset=utf-8\",\n });\n\n return URL.createObjectURL(blob);\n};\n\n// ============================================\n// HTML 미리보기 블록 스펙\n// ============================================\n\nexport const HtmlPreviewBlock = createReactBlockSpec(\n {\n type: \"htmlPreview\",\n propSchema: {\n htmlContent: {\n default: \"\",\n },\n fileName: {\n default: \"\",\n },\n height: {\n default: \"400px\",\n },\n },\n content: \"none\",\n },\n {\n render: (props) => {\n const [isExpanded, setIsExpanded] = useState(true);\n const [isResizing, setIsResizing] = useState(false);\n const [blobUrl, setBlobUrl] = useState<string>(\"\");\n const containerRef = useRef<HTMLDivElement>(null);\n\n const htmlContent = props.block.props.htmlContent || \"\";\n const fileName = props.block.props.fileName || \"HTML Document\";\n const savedHeight = props.block.props.height || \"400px\";\n\n // 현재 높이 (숫자로 파싱)\n const currentHeight = parseInt(savedHeight, 10) || 400;\n\n // UTF-8 인코딩 보장된 Blob URL 생성\n useEffect(() => {\n if (htmlContent) {\n const url = createSecureBlobUrl(htmlContent);\n setBlobUrl(url);\n\n return () => {\n URL.revokeObjectURL(url);\n };\n }\n }, [htmlContent]);\n\n // 리사이즈 시작\n const handleResizeStart = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsResizing(true);\n\n const startY = e.clientY;\n const startHeight = currentHeight;\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const deltaY = moveEvent.clientY - startY;\n const newHeight = Math.min(\n MAX_HEIGHT,\n Math.max(MIN_HEIGHT, startHeight + deltaY)\n );\n\n // 블록 props 업데이트 (저장됨)\n props.editor.updateBlock(props.block, {\n props: { height: `${newHeight}px` },\n });\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n },\n [currentHeight, props.editor, props.block]\n );\n\n // HTML 파일 다운로드 (원본 그대로 + 인코딩 보장)\n const handleExport = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n\n // 파일명 새니타이제이션 (경로 조작 방지)\n const safeFileName = sanitizeFileName(fileName);\n const downloadName = safeFileName.endsWith(\".html\")\n ? safeFileName\n : `${safeFileName}.html`;\n\n // UTF-8 인코딩 명시\n const htmlWithCharset = ensureCharset(htmlContent);\n const blob = new Blob([htmlWithCharset], {\n type: \"text/html;charset=utf-8\",\n });\n\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = downloadName;\n a.rel = \"noopener noreferrer\"; // 보안 속성 추가\n\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n },\n [htmlContent, fileName]\n );\n\n // 새 창에서 열기 (Blob URL 방식 - XSS 방지)\n const handleOpenNewWindow = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n\n // 클라이언트 사이드에서만 실행\n if (typeof window === \"undefined\") return;\n\n // Blob URL 생성 (UTF-8 인코딩 보장)\n const url = createSecureBlobUrl(htmlContent);\n\n // noopener, noreferrer로 보안 강화\n const newWindow = window.open(url, \"_blank\", \"noopener,noreferrer\");\n\n // Blob URL 정리\n if (newWindow) {\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n } else {\n URL.revokeObjectURL(url);\n }\n },\n [htmlContent]\n );\n\n return (\n <div\n ref={containerRef}\n style={{\n border: \"1px solid #e0e0e0\",\n borderRadius: \"8px\",\n overflow: \"hidden\",\n backgroundColor: \"#f9f9f9\",\n marginBottom: \"2px\",\n width: \"100%\",\n userSelect: isResizing ? \"none\" : \"auto\",\n outline: \"none\",\n boxShadow: \"none\",\n }}\n >\n {/* 헤더 */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"4px 16px\",\n backgroundColor: \"#fff\",\n borderBottom: isExpanded ? \"1px solid #e0e0e0\" : \"none\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n cursor: \"pointer\",\n flex: 1,\n }}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n transition: \"transform 0.2s\",\n }}\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n\n <span style={{ fontWeight: 500, fontSize: \"14px\" }}>\n {fileName}\n </span>\n </div>\n\n {/* 액션 버튼들 */}\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"4px\" }}>\n {/* 새 창에서 열기 버튼 */}\n <button\n onClick={handleOpenNewWindow}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#666\",\n borderRadius: \"4px\",\n }}\n title=\"새 창에서 열기\"\n type=\"button\"\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n \"#f0f0f0\";\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n \"transparent\";\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"></path>\n <polyline points=\"15 3 21 3 21 9\"></polyline>\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"></line>\n </svg>\n </button>\n\n {/* 다운로드 버튼 */}\n <button\n onClick={handleExport}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#666\",\n borderRadius: \"4px\",\n }}\n title=\"HTML 다운로드\"\n type=\"button\"\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n \"#f0f0f0\";\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n \"transparent\";\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\n <polyline points=\"7 10 12 15 17 10\"></polyline>\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"></line>\n </svg>\n </button>\n </div>\n </div>\n\n {/* iframe 미리보기 */}\n {isExpanded && (\n <div\n style={{\n padding: \"0\",\n backgroundColor: \"#fff\",\n position: \"relative\",\n }}\n >\n {/* 🔒 보안 강화: JavaScript 완전 차단 + 부모 페이지 접근 차단 */}\n <iframe\n src={blobUrl || \"about:blank\"}\n style={{\n width: \"100%\",\n height: `${currentHeight}px`,\n border: \"none\",\n display: \"block\",\n pointerEvents: isResizing ? \"none\" : \"auto\",\n }}\n // 🔒 allow-scripts 제거 = JavaScript 실행 차단\n // 🔒 allow-same-origin 제거 = 부모 페이지 접근 차단\n // ✅ HTML + CSS만 렌더링 (안전)\n sandbox=\"allow-popups allow-forms\"\n title={fileName}\n referrerPolicy=\"no-referrer\"\n loading=\"lazy\"\n />\n\n {/* 리사이즈 핸들 */}\n <div\n onMouseDown={handleResizeStart}\n style={{\n position: \"absolute\",\n bottom: 0,\n left: 0,\n right: 0,\n height: \"12px\",\n cursor: \"ns-resize\",\n backgroundColor: isResizing\n ? \"rgba(59, 130, 246, 0.3)\"\n : \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"background-color 0.2s\",\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLDivElement).style.backgroundColor =\n \"rgba(59, 130, 246, 0.2)\";\n }}\n onMouseLeave={(e) => {\n if (!isResizing) {\n (e.currentTarget as HTMLDivElement).style.backgroundColor =\n \"transparent\";\n }\n }}\n >\n {/* 리사이즈 핸들 아이콘 */}\n <div\n style={{\n width: \"40px\",\n height: \"4px\",\n backgroundColor: \"#ccc\",\n borderRadius: \"2px\",\n }}\n />\n </div>\n </div>\n )}\n </div>\n );\n },\n }\n);\n\n// 커스텀 블록이 포함된 스키마 생성\nexport const schema = BlockNoteSchema.create({\n blockSpecs: {\n ...defaultBlockSpecs,\n htmlPreview: HtmlPreviewBlock,\n linkPreview: LinkPreviewBlock,\n video: VideoBlock,\n },\n inlineContentSpecs: defaultInlineContentSpecs,\n styleSpecs: defaultStyleSpecs,\n});\n\n// 스키마 타입 export\nexport type HtmlPreviewSchema = typeof schema;\n","import { createReactBlockSpec } from \"@blocknote/react\";\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport { DEFAULT_LINK_PREVIEW_IMAGE } from \"./defaultLogo\";\n\nexport interface LinkMetadata {\n url: string;\n title: string;\n description?: string;\n image?: string;\n domain: string;\n}\n\nconst metadataCache = new Map<string, LinkMetadata>();\n\nexport async function fetchLinkMetadata(\n url: string,\n apiEndpoint: string\n): Promise<LinkMetadata> {\n const cached = metadataCache.get(url);\n if (cached) return cached;\n\n const response = await fetch(\n `${apiEndpoint}?url=${encodeURIComponent(url)}`\n );\n if (!response.ok) {\n throw new Error(`Failed to fetch metadata: ${response.status}`);\n }\n\n const metadata: LinkMetadata = await response.json();\n metadataCache.set(url, metadata);\n return metadata;\n}\n\nexport function clearMetadataCache() {\n metadataCache.clear();\n}\n\nfunction extractDomain(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n } catch {\n return url;\n }\n}\n\nconst LinkPreviewCard = ({\n url,\n title,\n description,\n image,\n domain,\n editable,\n onDelete,\n width,\n onWidthChange,\n height,\n onHeightChange,\n}: {\n url: string;\n title: string;\n description: string;\n image: string;\n domain: string;\n editable: boolean;\n onDelete?: () => void;\n width?: number;\n onWidthChange?: (width: number) => void;\n height?: number;\n onHeightChange?: (height: number) => void;\n}) => {\n const [imgError, setImgError] = useState(false);\n const [hovered, setHovered] = useState(false);\n\n type ResizeParams = {\n handleUsed: \"left\" | \"right\" | \"bottom\";\n initialClientX: number;\n initialClientY: number;\n initialWidth: number;\n initialHeight: number;\n };\n const [resizeParams, setResizeParams] = useState<ResizeParams | undefined>(undefined);\n const [localWidth, setLocalWidth] = useState<number | undefined>(width);\n const [localHeight, setLocalHeight] = useState<number | undefined>(height);\n const cardRef = useRef<HTMLDivElement>(null);\n const justResizedRef = useRef(false);\n\n useEffect(() => { setLocalWidth(width); }, [width]);\n useEffect(() => { setLocalHeight(height); }, [height]);\n\n useEffect(() => {\n if (!resizeParams) return;\n\n const onMouseMove = (e: MouseEvent) => {\n if (resizeParams.handleUsed === \"bottom\") {\n const delta = e.clientY - resizeParams.initialClientY;\n setLocalHeight(Math.min(Math.max(resizeParams.initialHeight + delta, 100), 600));\n } else {\n const delta = resizeParams.handleUsed === \"left\"\n ? resizeParams.initialClientX - e.clientX\n : e.clientX - resizeParams.initialClientX;\n setLocalWidth(Math.min(\n Math.max(resizeParams.initialWidth + delta, 200),\n cardRef.current?.parentElement?.clientWidth || 800\n ));\n }\n };\n\n const onMouseUp = () => {\n const handle = resizeParams.handleUsed;\n setResizeParams(undefined);\n justResizedRef.current = true;\n setTimeout(() => { justResizedRef.current = false; }, 50);\n if (handle === \"bottom\") {\n if (localHeight && onHeightChange) onHeightChange(localHeight);\n } else {\n if (localWidth && onWidthChange) onWidthChange(localWidth);\n }\n };\n\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mouseup\", onMouseUp);\n };\n }, [resizeParams, localWidth, localHeight, onWidthChange, onHeightChange]);\n\n const handleLeftDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setResizeParams({\n handleUsed: \"left\",\n initialWidth: cardRef.current!.clientWidth,\n initialHeight: localHeight || 200,\n initialClientX: e.clientX,\n initialClientY: e.clientY,\n });\n }, [localHeight]);\n\n const handleRightDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setResizeParams({\n handleUsed: \"right\",\n initialWidth: cardRef.current!.clientWidth,\n initialHeight: localHeight || 200,\n initialClientX: e.clientX,\n initialClientY: e.clientY,\n });\n }, [localHeight]);\n\n const handleBottomDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setResizeParams({\n handleUsed: \"bottom\",\n initialWidth: cardRef.current!.clientWidth,\n initialHeight: localHeight || 200,\n initialClientX: e.clientX,\n initialClientY: e.clientY,\n });\n }, [localHeight]);\n\n const handleClick = useCallback(() => {\n if (url && !resizeParams && !justResizedRef.current) {\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n }\n }, [url, resizeParams]);\n\n const resizeCursor = resizeParams\n ? resizeParams.handleUsed === \"bottom\" ? \"ns-resize\" : \"ew-resize\"\n : \"pointer\";\n\n return (\n <div\n ref={cardRef}\n className=\"lumir-link-preview-card\"\n onClick={handleClick}\n style={{\n border: \"1px solid #e0e0e0\",\n borderRadius: \"8px\",\n overflow: \"hidden\",\n cursor: resizeCursor,\n width: localWidth ? `${localWidth}px` : undefined,\n maxWidth: \"100%\",\n backgroundColor: \"#fff\",\n transition: resizeParams ? \"none\" : \"box-shadow 0.2s\",\n position: \"relative\",\n }}\n onMouseEnter={() => {\n if (!resizeParams) setHovered(true);\n }}\n onMouseLeave={() => {\n if (!resizeParams) setHovered(false);\n }}\n >\n {editable && onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete();\n }}\n className=\"lumir-link-preview-delete\"\n style={{\n position: \"absolute\",\n top: \"8px\",\n right: \"8px\",\n width: \"24px\",\n height: \"24px\",\n borderRadius: \"50%\",\n border: \"none\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n color: \"#fff\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"14px\",\n lineHeight: 1,\n zIndex: 2,\n opacity: 0,\n transition: \"opacity 0.2s\",\n }}\n title=\"삭제\"\n >\n ✕\n </button>\n )}\n\n {editable && (hovered || resizeParams) && (\n <>\n <div\n className=\"lumir-resize-handle\"\n style={{ left: \"4px\" }}\n onMouseDown={handleLeftDown}\n />\n <div\n className=\"lumir-resize-handle\"\n style={{ right: \"4px\" }}\n onMouseDown={handleRightDown}\n />\n </>\n )}\n\n {image && !imgError && (\n <div\n style={{\n width: \"100%\",\n height: `${localHeight || 200}px`,\n overflow: \"hidden\",\n backgroundColor: \"#f0f0f0\",\n position: \"relative\",\n }}\n >\n <img\n src={image}\n alt={title || \"Link preview\"}\n onError={() => setImgError(true)}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n display: \"block\",\n }}\n referrerPolicy=\"no-referrer\"\n loading=\"lazy\"\n />\n {editable && (hovered || resizeParams) && (\n <div\n className=\"lumir-resize-handle-bottom\"\n onMouseDown={handleBottomDown}\n />\n )}\n </div>\n )}\n\n <div style={{ padding: \"12px 16px\" }}>\n <div\n style={{\n fontSize: \"14px\",\n fontWeight: 600,\n color: \"#1a1a1a\",\n lineHeight: 1.4,\n marginBottom: description ? \"4px\" : \"8px\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {title || domain}\n </div>\n\n {description && (\n <div\n style={{\n fontSize: \"12px\",\n color: \"#666\",\n lineHeight: 1.4,\n marginBottom: \"8px\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n display: \"-webkit-box\",\n WebkitLineClamp: 2,\n WebkitBoxOrient: \"vertical\",\n }}\n >\n {description}\n </div>\n )}\n\n <div\n style={{\n fontSize: \"12px\",\n color: \"#999\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {domain}\n </div>\n </div>\n </div>\n );\n};\n\nconst LinkPreviewSkeleton = () => (\n <div\n className=\"lumir-link-preview-skeleton\"\n style={{\n border: \"1px solid #e0e0e0\",\n borderRadius: \"8px\",\n overflow: \"hidden\",\n maxWidth: \"400px\",\n backgroundColor: \"#fff\",\n }}\n >\n <div\n style={{\n width: \"100%\",\n height: \"200px\",\n backgroundColor: \"#f0f0f0\",\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\n }}\n />\n <div style={{ padding: \"12px 16px\" }}>\n <div\n style={{\n height: \"16px\",\n width: \"70%\",\n backgroundColor: \"#f0f0f0\",\n borderRadius: \"4px\",\n marginBottom: \"8px\",\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\n }}\n />\n <div\n style={{\n height: \"12px\",\n width: \"90%\",\n backgroundColor: \"#f0f0f0\",\n borderRadius: \"4px\",\n marginBottom: \"8px\",\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\n }}\n />\n <div\n style={{\n height: \"12px\",\n width: \"40%\",\n backgroundColor: \"#f0f0f0\",\n borderRadius: \"4px\",\n animation: \"lumir-skeleton-pulse 1.5s ease-in-out infinite\",\n }}\n />\n </div>\n </div>\n);\n\nconst LinkPreviewError = ({\n url,\n onRetry,\n}: {\n url: string;\n onRetry?: () => void;\n}) => {\n const domain = (() => {\n try { return new URL(url).hostname; } catch { return url; }\n })();\n\n return (\n <div\n className=\"lumir-link-preview-error\"\n style={{\n border: \"1px solid #e0e0e0\",\n borderRadius: \"8px\",\n overflow: \"hidden\",\n maxWidth: \"400px\",\n backgroundColor: \"#fff\",\n cursor: \"pointer\",\n position: \"relative\",\n }}\n onClick={() => window.open(url, \"_blank\", \"noopener,noreferrer\")}\n >\n <div\n style={{\n width: \"100%\",\n height: \"160px\",\n overflow: \"hidden\",\n backgroundColor: \"#f0f0f0\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <img\n src={DEFAULT_LINK_PREVIEW_IMAGE}\n alt=\"Lumir\"\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n }}\n />\n </div>\n <div style={{ padding: \"12px 16px\" }}>\n <div\n style={{\n fontSize: \"13px\",\n color: \"#999\",\n marginBottom: \"4px\",\n }}\n >\n 미리보기를 불러올 수 없습니다\n </div>\n <div\n style={{\n fontSize: \"12px\",\n color: \"#1a73e8\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {domain}\n </div>\n </div>\n {onRetry && (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onRetry(); }}\n style={{\n position: \"absolute\",\n top: \"8px\",\n right: \"8px\",\n background: \"rgba(0,0,0,0.5)\",\n border: \"none\",\n borderRadius: \"4px\",\n padding: \"4px 8px\",\n cursor: \"pointer\",\n fontSize: \"12px\",\n color: \"#fff\",\n whiteSpace: \"nowrap\",\n }}\n >\n 재시도\n </button>\n )}\n </div>\n );\n};\n\nconst LinkPreviewUrlInput = ({\n onSubmit,\n}: {\n onSubmit: (url: string) => void;\n}) => {\n const [inputUrl, setInputUrl] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const handleSubmit = useCallback(() => {\n const trimmed = inputUrl.trim();\n if (!trimmed) return;\n const normalized = /^https?:\\/\\//i.test(trimmed)\n ? trimmed\n : `https://${trimmed}`;\n onSubmit(normalized);\n }, [inputUrl, onSubmit]);\n\n return (\n <div\n className=\"lumir-link-preview-input\"\n style={{\n border: \"1px solid #e0e0e0\",\n borderRadius: \"8px\",\n padding: \"16px\",\n maxWidth: \"400px\",\n backgroundColor: \"#fafafa\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"#999\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ flexShrink: 0 }}\n >\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </svg>\n <input\n ref={inputRef}\n type=\"text\"\n value={inputUrl}\n onChange={(e) => setInputUrl(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleSubmit();\n }\n }}\n placeholder=\"URL을 입력하세요 (예: https://example.com)\"\n style={{\n flex: 1,\n border: \"none\",\n outline: \"none\",\n backgroundColor: \"transparent\",\n fontSize: \"13px\",\n color: \"#333\",\n minWidth: 0,\n }}\n />\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!inputUrl.trim()}\n style={{\n flexShrink: 0,\n padding: \"4px 12px\",\n border: \"none\",\n borderRadius: \"4px\",\n backgroundColor: inputUrl.trim() ? \"#3b82f6\" : \"#d1d5db\",\n color: \"#fff\",\n fontSize: \"12px\",\n fontWeight: 500,\n cursor: inputUrl.trim() ? \"pointer\" : \"not-allowed\",\n transition: \"background-color 0.15s\",\n }}\n >\n 확인\n </button>\n </div>\n );\n};\n\nexport const LinkPreviewBlock = createReactBlockSpec(\n {\n type: \"linkPreview\",\n propSchema: {\n url: { default: \"\" },\n title: { default: \"\" },\n description: { default: \"\" },\n image: { default: \"\" },\n domain: { default: \"\" },\n previewWidth: { default: 400 as const },\n previewHeight: { default: 200 as const },\n },\n content: \"none\",\n },\n {\n render: (props) => {\n const { url, title, description, image, domain } =\n props.block.props;\n const [status, setStatus] = useState<\"idle\" | \"loading\" | \"error\">(\n !url ? \"idle\" : title ? \"idle\" : \"loading\"\n );\n const fetchedRef = useRef(false);\n\n const editable = props.editor.isEditable;\n\n useEffect(() => {\n if (!url || title || fetchedRef.current) {\n if (!url) setStatus(\"idle\");\n return;\n }\n\n const getApiEndpoint = () =>\n (props.editor as any)._linkPreviewApiEndpoint as\n | string\n | undefined;\n\n const doFetch = (endpoint: string) => {\n fetchedRef.current = true;\n setStatus(\"loading\");\n\n fetchLinkMetadata(url, endpoint)\n .then((metadata) => {\n props.editor.updateBlock(props.block, {\n props: {\n title: metadata.title || \"\",\n description: metadata.description || \"\",\n image: metadata.image || \"\",\n domain: metadata.domain || extractDomain(url),\n },\n });\n setStatus(\"idle\");\n })\n .catch(() => {\n props.editor.updateBlock(props.block, {\n props: { domain: extractDomain(url) },\n });\n setStatus(\"error\");\n });\n };\n\n const endpoint = getApiEndpoint();\n if (endpoint) {\n doFetch(endpoint);\n } else {\n // endpoint가 아직 설정되지 않았을 수 있으므로 잠시 대기 후 재시도\n const timer = setTimeout(() => {\n const retryEndpoint = getApiEndpoint();\n if (retryEndpoint) {\n doFetch(retryEndpoint);\n } else {\n setStatus(\"error\");\n }\n }, 100);\n return () => clearTimeout(timer);\n }\n }, [url, title]);\n\n const handleRetry = useCallback(() => {\n const endpoint = (props.editor as any)._linkPreviewApiEndpoint as\n | string\n | undefined;\n if (!url || !endpoint) return;\n metadataCache.delete(url);\n fetchedRef.current = false;\n setStatus(\"loading\");\n\n fetchLinkMetadata(url, endpoint)\n .then((metadata) => {\n props.editor.updateBlock(props.block, {\n props: {\n title: metadata.title || \"\",\n description: metadata.description || \"\",\n image: metadata.image || \"\",\n domain: metadata.domain || extractDomain(url),\n },\n });\n setStatus(\"idle\");\n })\n .catch(() => {\n setStatus(\"error\");\n });\n }, [url, props.editor, props.block]);\n\n const handleDelete = useCallback(() => {\n props.editor.removeBlocks([props.block]);\n }, [props.editor, props.block]);\n\n if (!url) {\n if (!editable) {\n return null;\n }\n return (\n <LinkPreviewUrlInput\n onSubmit={(newUrl) => {\n props.editor.updateBlock(props.block, {\n props: { url: newUrl },\n });\n }}\n />\n );\n }\n\n if (status === \"loading\") {\n return <LinkPreviewSkeleton />;\n }\n\n if (status === \"error\") {\n return <LinkPreviewError url={url} onRetry={handleRetry} />;\n }\n\n return (\n <LinkPreviewCard\n url={url}\n title={title}\n description={description}\n image={image}\n domain={domain || extractDomain(url)}\n editable={editable}\n onDelete={handleDelete}\n width={props.block.props.previewWidth}\n onWidthChange={(newWidth) => {\n props.editor.updateBlock(props.block, {\n props: { previewWidth: newWidth },\n });\n }}\n height={props.block.props.previewHeight}\n onHeightChange={(newHeight) => {\n props.editor.updateBlock(props.block, {\n props: { previewHeight: newHeight },\n });\n }}\n />\n );\n },\n }\n);\n","export const DEFAULT_LINK_PREVIEW_IMAGE = \"data:image/png;base64,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em1RHrY9EhgB5JWPq9DabLnDWKK8KrQqj2dIoXVQj+a8flLfBJN6T2FxKe//POeH76ctPvCWE/otMJ1HREREREREREREJJlUannNa4uGYNuPAV0rjavQ2my5w1iivCq0Ko9nSKGVFQzw84U706NFvQQTe9fcpetK3v1h9h3/N7TrVaaziIiIiIiIiIiIiCSLSi2veG1Rc+BubPvEKstUaG223GEsUV4VWpXHM6TQAjilfxueOKJngon9YdJfC+d+8du8g64+ZvufTGcRERERERERERERqS2VWl7w2qJTiBdaTaosU6G12XKHsUR5VWhVHs+gQis/J8jkS3elXaM8/G7l2iL77e9iYz79Ze7xz1y8R7HpPCIiIiIiIiIiIiI1pVIrk722yAIeA4ZvU6GhQqvyGxVaniq0AC7bI8Rtw7skmNyffpu5bNWnv8w96pLDtvvQdBYRERERERERERGRmlCplYnGLA5g22cAdwMNVGhVZy6HsUR5VWhVHs+wQqtxnRymX7krjepkJ9iBf63bUMy7381655XPZxzx+nX7FprOIyIiIiIiIiIiIrItVGplmjGLO2LbTwFDgG0rNFRoVX6jQstzhRY23LF/Fy7ZI5RgBwLwxz9LV3/ww+xjLj+677ums4iIiIiIiIiIiIhUl0qtTDJm8WnY9n1AA0CFVrXmchhLlFeFVuXxDCy02jeqw+TLd6FOdqUl4mDdhmI++H7WW+9/N+uIJy7dU8/aEhEREREREREREddTqZUJxixuDjyBbR9SPqZCS4XWFrP6r9ACeOqonpy0Y5sEOxEnv85YsvzTH2fvf+m/tv/adBYRERERERERERGRLVGp5XZjFh8EPIlttygfU6GlQmuLWf1ZaPVqWZ+fL9qZgP5U22Yr1xTab07659GTh3U/z3QWERERERERERERkUR0+tetxizOB+4FzqpRMbWl11tarkJrC/tQoVWtdR23cd5tsgotgDdP7ssBPZon2JFUx4Rf58a++XPBblce32+W6SwiIiIiIiIiIiIim1Op5UZjFm8HvAr0UqFVzXVVaPm60NqtQwGfn90/wY5kW8xbsrb4va9nnnvGQb2eMJ1FREREREREREREpCKVWm4zZvFZwH1AHRVa1VxXhZavC60ANhPP3YmBVqMEO5NtVVRcyrtfRz/86NvogY9ePqTYdB4RERERERERERER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\";\n","import { createReactBlockSpec } from \"@blocknote/react\";\nimport React, { useState, useCallback, useRef, useEffect } from \"react\";\n\nconst MIN_VIDEO_WIDTH = 200;\nconst MAX_VIDEO_WIDTH = 1200;\nconst MIN_VIDEO_HEIGHT = 120;\nconst MAX_VIDEO_HEIGHT = 600;\nconst DEFAULT_VIDEO_WIDTH = 640;\nconst DEFAULT_VIDEO_HEIGHT = 360;\n\ntype ResizeParams = {\n handleUsed: \"left\" | \"right\" | \"bottom\";\n initialClientX: number;\n initialClientY: number;\n initialWidth: number;\n initialHeight: number;\n};\n\n/**\n * 비디오 블록 카드: 우클릭 방지 + 다운로드 버튼 미노출\n * - controlsList=\"nodownload\": 브라우저 기본 컨트롤에서 다운로드 버튼 숨김\n * - onContextMenu preventDefault: 우클릭 컨텍스트 메뉴(동영상 저장 등) 차단\n */\nconst VideoBlockCard = ({\n url,\n editable,\n width,\n onWidthChange,\n height,\n onHeightChange,\n onContextMenuBlock,\n}: {\n url: string;\n editable: boolean;\n width?: number;\n onWidthChange?: (width: number) => void;\n height?: number;\n onHeightChange?: (height: number) => void;\n onContextMenuBlock: (e: React.MouseEvent) => void;\n}) => {\n const [resizeParams, setResizeParams] = useState<ResizeParams | undefined>(\n undefined,\n );\n const [localWidth, setLocalWidth] = useState<number | undefined>(width);\n const [localHeight, setLocalHeight] = useState<number | undefined>(height);\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setLocalWidth(width);\n }, [width]);\n useEffect(() => {\n setLocalHeight(height);\n }, [height]);\n\n useEffect(() => {\n if (!resizeParams) return;\n\n const onMouseMove = (e: MouseEvent) => {\n if (resizeParams.handleUsed === \"bottom\") {\n const delta = e.clientY - resizeParams.initialClientY;\n setLocalHeight(\n Math.min(\n Math.max(resizeParams.initialHeight + delta, MIN_VIDEO_HEIGHT),\n MAX_VIDEO_HEIGHT,\n ),\n );\n } else {\n const delta =\n resizeParams.handleUsed === \"left\"\n ? resizeParams.initialClientX - e.clientX\n : e.clientX - resizeParams.initialClientX;\n setLocalWidth(\n Math.min(\n Math.max(resizeParams.initialWidth + delta, MIN_VIDEO_WIDTH),\n wrapperRef.current?.parentElement?.clientWidth || MAX_VIDEO_WIDTH,\n ),\n );\n }\n };\n\n const onMouseUp = () => {\n const handle = resizeParams.handleUsed;\n setResizeParams(undefined);\n if (handle === \"bottom\") {\n if (localHeight != null && onHeightChange) onHeightChange(localHeight);\n } else {\n if (localWidth != null && onWidthChange) onWidthChange(localWidth);\n }\n };\n\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mouseup\", onMouseUp);\n };\n }, [resizeParams, localWidth, localHeight, onWidthChange, onHeightChange]);\n\n const handleLeftDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setResizeParams({\n handleUsed: \"left\",\n initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,\n initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,\n initialClientX: e.clientX,\n initialClientY: e.clientY,\n });\n },\n [localHeight],\n );\n\n const handleRightDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setResizeParams({\n handleUsed: \"right\",\n initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,\n initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,\n initialClientX: e.clientX,\n initialClientY: e.clientY,\n });\n },\n [localHeight],\n );\n\n const handleBottomDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setResizeParams({\n handleUsed: \"bottom\",\n initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,\n initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,\n initialClientX: e.clientX,\n initialClientY: e.clientY,\n });\n },\n [localHeight],\n );\n\n const resizeCursor = resizeParams\n ? resizeParams.handleUsed === \"bottom\"\n ? \"ns-resize\"\n : \"ew-resize\"\n : \"default\";\n\n const [hovered, setHovered] = useState(false);\n\n return (\n <div\n ref={wrapperRef}\n className=\"lumir-video-block-wrapper\"\n onContextMenu={onContextMenuBlock}\n style={{\n position: \"relative\",\n width: localWidth != null ? `${localWidth}px` : undefined,\n maxWidth: \"100%\",\n cursor: resizeCursor,\n transition: resizeParams ? \"none\" : \"box-shadow 0.2s\",\n }}\n onMouseEnter={() => {\n if (!resizeParams) setHovered(true);\n }}\n onMouseLeave={() => {\n if (!resizeParams) setHovered(false);\n }}\n >\n {editable && (hovered || resizeParams) && (\n <>\n <div\n className=\"lumir-resize-handle\"\n style={{ left: \"4px\" }}\n onMouseDown={handleLeftDown}\n />\n <div\n className=\"lumir-resize-handle\"\n style={{ right: \"4px\" }}\n onMouseDown={handleRightDown}\n />\n </>\n )}\n\n <div\n style={{\n width: \"100%\",\n height: `${localHeight ?? DEFAULT_VIDEO_HEIGHT}px`,\n overflow: \"hidden\",\n backgroundColor: \"#000\",\n borderRadius: \"6px\",\n }}\n >\n <video\n src={url}\n controls\n controlsList=\"nodownload\"\n playsInline\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n }}\n onContextMenu={(e) => e.preventDefault()}\n />\n {editable && (hovered || resizeParams) && (\n <div\n className=\"lumir-resize-handle-bottom\"\n onMouseDown={handleBottomDown}\n />\n )}\n </div>\n </div>\n );\n};\n\nexport const VideoBlock = createReactBlockSpec(\n {\n type: \"video\",\n propSchema: {\n url: { default: \"\" },\n previewWidth: { default: 640 },\n previewHeight: { default: 360 },\n },\n content: \"none\",\n },\n {\n render: (props) => {\n const url = props.block.props.url ?? \"\";\n const editable = props.editor.isEditable;\n\n const handleContextMenu = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n if (!url) {\n return (\n <div\n className=\"lumir-video-block-placeholder\"\n onContextMenu={handleContextMenu}\n style={{\n width: \"100%\",\n maxWidth: `${DEFAULT_VIDEO_WIDTH}px`,\n height: `${DEFAULT_VIDEO_HEIGHT}px`,\n backgroundColor: \"#1a1a1a\",\n borderRadius: \"6px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"rgba(255,255,255,0.5)\",\n fontSize: \"14px\",\n }}\n >\n 비디오 URL 없음\n </div>\n );\n }\n\n return (\n <VideoBlockCard\n url={url}\n editable={editable}\n width={props.block.props.previewWidth}\n onWidthChange={(newWidth) => {\n props.editor.updateBlock(props.block, {\n props: { previewWidth: newWidth },\n });\n }}\n height={props.block.props.previewHeight}\n onHeightChange={(newHeight) => {\n props.editor.updateBlock(props.block, {\n props: { previewHeight: newHeight },\n });\n }}\n onContextMenuBlock={handleContextMenu}\n />\n );\n },\n },\n);\n","\"use client\";\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport type { EditorType } from \"../../types\";\nimport { cn } from \"../../utils/cn\";\nimport { Icons } from \"./Icons\";\nimport {\n ToolbarDivider,\n UndoRedoButtons,\n TextStyleButton,\n AlignButton,\n ListButton,\n ImageButton,\n ColorButton,\n LinkButton,\n TableButton,\n HTMLImportButton,\n BlockTypeSelect,\n} from \"./components\";\n\n// 반응형 브레이크포인트 (px)\nconst COMPACT_BREAKPOINT = 700;\nconst MINIMIZED_BREAKPOINT = 400;\n\nexport interface FloatingMenuProps {\n editor: EditorType | any;\n position?: \"sticky\" | \"fixed\";\n className?: string;\n onImageUpload?: () => void;\n}\n\n/**\n * FloatingMenu - 에디터 상단 고정 툴바\n */\nexport const FloatingMenu: React.FC<FloatingMenuProps> = ({\n editor,\n position = \"sticky\",\n className,\n onImageUpload,\n}) => {\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [isCompact, setIsCompact] = useState(false);\n const [isMinimizable, setIsMinimizable] = useState(false);\n const [isMinimized, setIsMinimized] = useState(false);\n // 선택 변경 시 리렌더링을 위한 카운터\n const [, setSelectionTick] = useState(0);\n\n // 선택 변경 감지 - 스타일 버튼 상태 업데이트를 위해 (디바운싱 적용)\n useEffect(() => {\n if (!editor) return;\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const DEBOUNCE_DELAY = 150;\n\n const handleSelectionChange = () => {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(() => {\n setSelectionTick((prev) => prev + 1);\n }, DEBOUNCE_DELAY);\n };\n\n const unsubscribe = editor.onSelectionChange?.(handleSelectionChange);\n const unsubscribeContent = editor.onEditorContentChange?.(() => {\n setSelectionTick((prev) => prev + 1);\n });\n\n return () => {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n unsubscribe?.();\n unsubscribeContent?.();\n };\n }, [editor]);\n\n // 컨테이너 너비 감지\n useEffect(() => {\n const checkWidth = () => {\n if (wrapperRef.current) {\n const width = wrapperRef.current.offsetWidth;\n setIsCompact(width < COMPACT_BREAKPOINT);\n setIsMinimizable(width < MINIMIZED_BREAKPOINT);\n }\n };\n\n checkWidth();\n\n const resizeObserver = new ResizeObserver(checkWidth);\n if (wrapperRef.current) {\n resizeObserver.observe(wrapperRef.current);\n }\n\n return () => resizeObserver.disconnect();\n }, []);\n\n // 최소화된 레이아웃 (400px 이하)\n const MinimizedLayout = () => (\n <>\n <button\n className=\"lumir-toolbar-button lumir-toggle-button\"\n onClick={() => setIsMinimized(!isMinimized)}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n title={isMinimized ? \"메뉴 펼치기\" : \"메뉴 접기\"}\n >\n {isMinimized ? Icons.chevronRight : Icons.chevronLeft}\n </button>\n {!isMinimized && (\n <>\n <ToolbarDivider />\n <UndoRedoButtons editor={editor} />\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <BlockTypeSelect editor={editor} />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <TextStyleButton editor={editor} style=\"bold\" />\n <TextStyleButton editor={editor} style=\"italic\" />\n <TextStyleButton editor={editor} style=\"underline\" />\n <TextStyleButton editor={editor} style=\"strike\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <AlignButton editor={editor} alignment=\"left\" />\n <AlignButton editor={editor} alignment=\"center\" />\n <AlignButton editor={editor} alignment=\"right\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ListButton editor={editor} type=\"bullet\" />\n <ListButton editor={editor} type=\"numbered\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ColorButton editor={editor} type=\"text\" />\n <ColorButton editor={editor} type=\"background\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ImageButton editor={editor} onImageUpload={onImageUpload} />\n <LinkButton editor={editor} />\n <TableButton editor={editor} />\n <HTMLImportButton editor={editor} />\n </div>\n </>\n )}\n </>\n );\n\n // 1단 레이아웃\n const SingleRowLayout = () => (\n <>\n <UndoRedoButtons editor={editor} />\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <BlockTypeSelect editor={editor} />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <TextStyleButton editor={editor} style=\"bold\" />\n <TextStyleButton editor={editor} style=\"italic\" />\n <TextStyleButton editor={editor} style=\"underline\" />\n <TextStyleButton editor={editor} style=\"strike\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <AlignButton editor={editor} alignment=\"left\" />\n <AlignButton editor={editor} alignment=\"center\" />\n <AlignButton editor={editor} alignment=\"right\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ListButton editor={editor} type=\"bullet\" />\n <ListButton editor={editor} type=\"numbered\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ColorButton editor={editor} type=\"text\" />\n <ColorButton editor={editor} type=\"background\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ImageButton editor={editor} onImageUpload={onImageUpload} />\n <LinkButton editor={editor} />\n <TableButton editor={editor} />\n <HTMLImportButton editor={editor} />\n </div>\n </>\n );\n\n // 2단 레이아웃\n const TwoRowLayout = () => (\n <>\n <div className=\"lumir-toolbar-row\">\n <UndoRedoButtons editor={editor} />\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <TextStyleButton editor={editor} style=\"bold\" />\n <TextStyleButton editor={editor} style=\"italic\" />\n <TextStyleButton editor={editor} style=\"underline\" />\n <TextStyleButton editor={editor} style=\"strike\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <AlignButton editor={editor} alignment=\"left\" />\n <AlignButton editor={editor} alignment=\"center\" />\n <AlignButton editor={editor} alignment=\"right\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ListButton editor={editor} type=\"bullet\" />\n <ListButton editor={editor} type=\"numbered\" />\n </div>\n </div>\n <div className=\"lumir-toolbar-row\">\n <div className=\"lumir-toolbar-group\">\n <BlockTypeSelect editor={editor} />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ColorButton editor={editor} type=\"text\" />\n <ColorButton editor={editor} type=\"background\" />\n </div>\n <ToolbarDivider />\n <div className=\"lumir-toolbar-group\">\n <ImageButton editor={editor} onImageUpload={onImageUpload} />\n <LinkButton editor={editor} />\n <TableButton editor={editor} />\n <HTMLImportButton editor={editor} />\n </div>\n </div>\n </>\n );\n\n return (\n <div\n ref={wrapperRef}\n className={cn(\n \"lumir-floating-toolbar-wrapper\",\n isMinimizable && \"is-minimizable\",\n className\n )}\n data-position={position}\n >\n <div\n className={cn(\n \"lumir-floating-toolbar\",\n isCompact && \"is-compact\",\n isMinimizable && \"is-minimizable\",\n isMinimized && \"is-minimized\"\n )}\n >\n {isMinimizable ? (\n <MinimizedLayout />\n ) : isCompact ? (\n <TwoRowLayout />\n ) : (\n <SingleRowLayout />\n )}\n </div>\n </div>\n );\n};\n\n// 하위 호환성을 위한 default export\nexport default FloatingMenu;\n","\"use client\";\n\nimport React from \"react\";\n\n/**\n * FloatingMenu에서 사용하는 SVG 아이콘 컴포넌트들\n */\nexport const Icons = {\n undo: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z\" />\n </svg>\n ),\n redo: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z\" />\n </svg>\n ),\n bold: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\" />\n </svg>\n ),\n italic: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z\" />\n </svg>\n ),\n underline: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z\" />\n </svg>\n ),\n strikethrough: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z\" />\n </svg>\n ),\n alignLeft: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z\" />\n </svg>\n ),\n alignCenter: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z\" />\n </svg>\n ),\n alignRight: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z\" />\n </svg>\n ),\n bulletList: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z\" />\n </svg>\n ),\n numberedList: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\" />\n </svg>\n ),\n image: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\" />\n </svg>\n ),\n expandMore: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"18\" height=\"18\">\n <path d=\"M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z\" />\n </svg>\n ),\n textColor: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z\" />\n </svg>\n ),\n bgColor: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M16.56 8.94L7.62 0 6.21 1.41l2.38 2.38-5.15 5.15c-.59.59-.59 1.54 0 2.12l5.5 5.5c.29.29.68.44 1.06.44s.77-.15 1.06-.44l5.5-5.5c.59-.58.59-1.53 0-2.12zM5.21 10L10 5.21 14.79 10H5.21zM19 11.5s-2 2.17-2 3.5c0 1.1.9 2 2 2s2-.9 2-2c0-1.33-2-3.5-2-3.5z\" />\n <path fillOpacity=\".36\" d=\"M0 20h24v4H0z\" />\n </svg>\n ),\n link: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\" />\n </svg>\n ),\n chevronRight: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\" />\n </svg>\n ),\n chevronLeft: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\" />\n </svg>\n ),\n table: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M20 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM10 17H5v-2h5v2zm0-4H5v-2h5v2zm0-4H5V7h5v2zm9 8h-7v-2h7v2zm0-4h-7v-2h7v2zm0-4h-7V7h7v2z\" />\n </svg>\n ),\n htmlFile: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 2v5h5l-5-5zm-4 14H7v-1h2v1zm0-2H7v-1h2v1zm-2-2h2v1H7v-1zm4 4h-2v-1h2v1zm0-2h-2v-1h2v1zm0-2h-2v-1h2v1zm6 4h-4v-1h4v1zm0-2h-4v-1h4v1zm0-2h-4v-1h4v1z\" />\n </svg>\n ),\n};\n\n/**\n * 블록 타입 아이콘들\n */\nexport const BlockTypeIcons: Record<string, React.ReactNode> = {\n paragraph: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M5 5h14v2H5zM5 11h14v2H5zM5 17h10v2H5z\" />\n </svg>\n ),\n h1: <span className=\"lumir-block-icon-text\">H1</span>,\n h2: <span className=\"lumir-block-icon-text\">H2</span>,\n h3: <span className=\"lumir-block-icon-text\">H3</span>,\n h4: <span className=\"lumir-block-icon-text\">H4</span>,\n h5: <span className=\"lumir-block-icon-text\">H5</span>,\n h6: <span className=\"lumir-block-icon-text\">H6</span>,\n toggleH1: (\n <span className=\"lumir-block-icon-toggle\">\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"8\" height=\"8\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n <span>H1</span>\n </span>\n ),\n toggleH2: (\n <span className=\"lumir-block-icon-toggle\">\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"8\" height=\"8\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n <span>H2</span>\n </span>\n ),\n toggleH3: (\n <span className=\"lumir-block-icon-toggle\">\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"8\" height=\"8\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n <span>H3</span>\n </span>\n ),\n quote: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z\" />\n </svg>\n ),\n codeBlock: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z\" />\n </svg>\n ),\n toggleList: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M10 6h10v2H10zM10 11h10v2H10zM10 16h10v2H10z\" />\n <path\n d=\"M4 8l4 4-4 4\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n ),\n bulletList: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <circle cx=\"4\" cy=\"6\" r=\"1.5\" />\n <circle cx=\"4\" cy=\"12\" r=\"1.5\" />\n <circle cx=\"4\" cy=\"18\" r=\"1.5\" />\n <path d=\"M8 5h12v2H8zM8 11h12v2H8zM8 17h12v2H8z\" />\n </svg>\n ),\n numberedList: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\" />\n </svg>\n ),\n checkList: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <rect\n x=\"3\"\n y=\"4\"\n width=\"6\"\n height=\"6\"\n rx=\"1\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M4.5 7l1.5 1.5 3-3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path d=\"M12 6h8v2h-8z\" />\n <rect\n x=\"3\"\n y=\"14\"\n width=\"6\"\n height=\"6\"\n rx=\"1\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path d=\"M12 16h8v2h-8z\" />\n </svg>\n ),\n};\n","\"use client\";\n\nimport React from \"react\";\n\n/**\n * 툴바 구분선 컴포넌트\n */\nexport const ToolbarDivider: React.FC = () => (\n <div className=\"lumir-toolbar-divider\" />\n);\n","\"use client\";\n\nimport React, { useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\n\ninterface UndoRedoButtonsProps {\n editor: EditorType | any;\n}\n\n/**\n * 실행 취소 / 다시 실행 버튼 컴포넌트\n */\nexport const UndoRedoButtons: React.FC<UndoRedoButtonsProps> = ({ editor }) => {\n const handleUndo = useCallback(() => {\n try {\n editor?.undo?.();\n } catch (err) {\n console.error(\"Undo failed:\", err);\n }\n }, [editor]);\n\n const handleRedo = useCallback(() => {\n try {\n editor?.redo?.();\n } catch (err) {\n console.error(\"Redo failed:\", err);\n }\n }, [editor]);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <div className=\"lumir-toolbar-group\">\n <button\n className=\"lumir-toolbar-btn\"\n onClick={handleUndo}\n onMouseDown={handleMouseDown}\n title=\"실행 취소\"\n type=\"button\"\n >\n {Icons.undo}\n </button>\n <button\n className=\"lumir-toolbar-btn\"\n onClick={handleRedo}\n onMouseDown={handleMouseDown}\n title=\"다시 실행\"\n type=\"button\"\n >\n {Icons.redo}\n </button>\n </div>\n );\n};\n","\"use client\";\n\nimport React, { useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\nimport { cn } from \"../../../utils/cn\";\n\ntype TextStyle = \"bold\" | \"italic\" | \"underline\" | \"strike\";\n\ninterface TextStyleButtonProps {\n editor: EditorType | any;\n style: TextStyle;\n}\n\nconst iconMap: Record<TextStyle, React.ReactNode> = {\n bold: Icons.bold,\n italic: Icons.italic,\n underline: Icons.underline,\n strike: Icons.strikethrough,\n};\n\nconst titleMap: Record<TextStyle, string> = {\n bold: \"굵게\",\n italic: \"기울임\",\n underline: \"밑줄\",\n strike: \"취소선\",\n};\n\n/**\n * 텍스트 스타일 버튼 (굵게, 기울임, 밑줄, 취소선)\n */\nexport const TextStyleButton: React.FC<TextStyleButtonProps> = ({\n editor,\n style,\n}) => {\n // 현재 스타일 상태를 직접 계산\n const getIsActive = (): boolean => {\n try {\n const activeStyles = editor?.getActiveStyles?.() || {};\n return activeStyles[style] === true;\n } catch {\n return false;\n }\n };\n\n const isActive = getIsActive();\n\n const handleClick = useCallback(() => {\n try {\n editor?.toggleStyles?.({ [style]: true });\n } catch (err) {\n console.error(`Toggle ${style} failed:`, err);\n }\n }, [editor, style]);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <button\n className={cn(\"lumir-toolbar-btn\", isActive && \"is-active\")}\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n title={titleMap[style]}\n type=\"button\"\n >\n {iconMap[style]}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\nimport { cn } from \"../../../utils/cn\";\n\ntype Alignment = \"left\" | \"center\" | \"right\";\n\ninterface AlignButtonProps {\n editor: EditorType | any;\n alignment: Alignment;\n}\n\nconst iconMap: Record<Alignment, React.ReactNode> = {\n left: Icons.alignLeft,\n center: Icons.alignCenter,\n right: Icons.alignRight,\n};\n\nconst titleMap: Record<Alignment, string> = {\n left: \"왼쪽 정렬\",\n center: \"가운데 정렬\",\n right: \"오른쪽 정렬\",\n};\n\n/**\n * 텍스트 정렬 버튼 (왼쪽, 가운데, 오른쪽)\n */\nexport const AlignButton: React.FC<AlignButtonProps> = ({\n editor,\n alignment,\n}) => {\n // 현재 정렬 상태를 직접 계산\n const getCurrentAlignment = (): string => {\n try {\n const block = editor?.getTextCursorPosition()?.block;\n return block?.props?.textAlignment || \"left\";\n } catch {\n return \"left\";\n }\n };\n\n const isActive = getCurrentAlignment() === alignment;\n\n const handleClick = useCallback(() => {\n try {\n const block = editor?.getTextCursorPosition()?.block;\n if (block && editor?.updateBlock) {\n editor.updateBlock(block, { props: { textAlignment: alignment } });\n }\n } catch (err) {\n console.error(`Set alignment ${alignment} failed:`, err);\n }\n }, [editor, alignment]);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <button\n className={cn(\"lumir-toolbar-btn\", isActive && \"is-active\")}\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n title={titleMap[alignment]}\n type=\"button\"\n >\n {iconMap[alignment]}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\nimport { cn } from \"../../../utils/cn\";\n\ntype ListType = \"bullet\" | \"numbered\";\n\ninterface ListButtonProps {\n editor: EditorType | any;\n type: ListType;\n}\n\nconst iconMap: Record<ListType, React.ReactNode> = {\n bullet: Icons.bulletList,\n numbered: Icons.numberedList,\n};\n\nconst titleMap: Record<ListType, string> = {\n bullet: \"글머리 기호 목록\",\n numbered: \"번호 목록\",\n};\n\n/**\n * 리스트 버튼 (글머리 기호, 번호 목록)\n */\nexport const ListButton: React.FC<ListButtonProps> = ({ editor, type }) => {\n // 현재 리스트 상태를 직접 계산\n const getIsActive = (): boolean => {\n try {\n const block = editor?.getTextCursorPosition()?.block;\n const blockType =\n type === \"bullet\" ? \"bulletListItem\" : \"numberedListItem\";\n return block?.type === blockType;\n } catch {\n return false;\n }\n };\n\n const isActive = getIsActive();\n\n const handleClick = useCallback(() => {\n try {\n const block = editor?.getTextCursorPosition()?.block;\n if (block && editor?.updateBlock) {\n const targetType =\n type === \"bullet\" ? \"bulletListItem\" : \"numberedListItem\";\n const newType = block.type === targetType ? \"paragraph\" : targetType;\n editor.updateBlock(block, { type: newType as any });\n }\n } catch (err) {\n console.error(`List toggle failed:`, err);\n }\n }, [editor, type]);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <button\n className={cn(\"lumir-toolbar-btn\", isActive && \"is-active\")}\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n title={titleMap[type]}\n type=\"button\"\n >\n {iconMap[type]}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\n\ninterface ImageButtonProps {\n editor: EditorType | any;\n onImageUpload?: () => void;\n}\n\n/**\n * 이미지 업로드 버튼\n */\nexport const ImageButton: React.FC<ImageButtonProps> = ({\n editor,\n onImageUpload,\n}) => {\n const handleClick = useCallback(() => {\n if (onImageUpload) {\n onImageUpload();\n } else {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"image/*\";\n input.onchange = async (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (file && editor?.uploadFile) {\n try {\n const url = await editor.uploadFile(file);\n editor.insertBlocks(\n [{ type: \"image\", props: { url: url as string } }] as any,\n editor.getTextCursorPosition().block,\n \"after\"\n );\n } catch (err) {\n console.error(\"Image upload failed:\", err);\n }\n }\n };\n input.click();\n }\n }, [editor, onImageUpload]);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <button\n className=\"lumir-toolbar-btn\"\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n title=\"이미지 삽입\"\n type=\"button\"\n >\n {Icons.image}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\nimport { cn } from \"../../../utils/cn\";\nimport {\n TEXT_COLORS,\n BACKGROUND_COLORS,\n getHexFromColorValue,\n} from \"../../../constants/colors\";\n\ntype ColorType = \"text\" | \"background\";\n\ninterface ColorButtonProps {\n editor: EditorType | any;\n type: ColorType;\n}\n\n/**\n * 색상 선택 버튼 (텍스트/배경 색상)\n */\nexport const ColorButton: React.FC<ColorButtonProps> = ({ editor, type }) => {\n const [isOpen, setIsOpen] = useState(false);\n const [currentColor, setCurrentColor] = useState(\"default\");\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const colors = type === \"text\" ? TEXT_COLORS : BACKGROUND_COLORS;\n\n const getCurrentColor = useCallback((): string => {\n try {\n const activeStyles = editor?.getActiveStyles?.() || {};\n if (type === \"text\" && activeStyles.textColor) {\n return activeStyles.textColor;\n } else if (type === \"background\" && activeStyles.backgroundColor) {\n return activeStyles.backgroundColor;\n }\n } catch {\n // ignore\n }\n return \"default\";\n }, [editor, type]);\n\n // 드롭다운 열릴 때 현재 색상 업데이트\n useEffect(() => {\n if (isOpen) {\n const color = getCurrentColor();\n setCurrentColor(color);\n }\n }, [isOpen, getCurrentColor]);\n\n // 외부 클릭 감지\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n const handleColorSelect = useCallback(\n (color: string) => {\n try {\n if (!editor) return;\n\n if (type === \"text\") {\n (editor as any).toggleStyles({ textColor: color });\n } else {\n (editor as any).toggleStyles({ backgroundColor: color });\n }\n setCurrentColor(color);\n setIsOpen(false);\n } catch (err) {\n console.error(`Color apply failed:`, err);\n }\n },\n [editor, type]\n );\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <div className=\"lumir-dropdown-wrapper\" ref={dropdownRef}>\n <button\n className=\"lumir-toolbar-btn lumir-color-btn\"\n onClick={() => setIsOpen(!isOpen)}\n onMouseDown={handleMouseDown}\n title={type === \"text\" ? \"텍스트 색상\" : \"배경 색상\"}\n type=\"button\"\n >\n {type === \"text\" ? Icons.textColor : Icons.bgColor}\n <span\n className=\"lumir-color-indicator\"\n style={{\n backgroundColor: getHexFromColorValue(currentColor, type),\n }}\n />\n </button>\n {isOpen && (\n <div className=\"lumir-dropdown-menu lumir-color-menu\">\n <div className=\"lumir-color-grid\">\n {colors.map((color) => (\n <button\n key={color.value}\n className={cn(\n \"lumir-color-swatch\",\n currentColor === color.value && \"is-active\"\n )}\n onClick={() => handleColorSelect(color.value)}\n onMouseDown={handleMouseDown}\n title={color.name}\n style={{ backgroundColor: color.hex }}\n type=\"button\"\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n};\n","/**\n * 색상 팔레트 상수\n * BlockNote 기본 색상 팔레트와 일치\n */\n\nexport interface ColorItem {\n name: string;\n value: string;\n hex: string;\n}\n\n/**\n * 텍스트 색상 팔레트\n */\nexport const TEXT_COLORS: ColorItem[] = [\n { name: \"기본\", value: \"default\", hex: \"#3f3f3f\" },\n { name: \"회색\", value: \"gray\", hex: \"#9b9a97\" },\n { name: \"갈색\", value: \"brown\", hex: \"#64473a\" },\n { name: \"빨간색\", value: \"red\", hex: \"#e03e3e\" },\n { name: \"주황색\", value: \"orange\", hex: \"#d9730d\" },\n { name: \"노란색\", value: \"yellow\", hex: \"#dfab01\" },\n { name: \"초록색\", value: \"green\", hex: \"#4d6461\" },\n { name: \"파란색\", value: \"blue\", hex: \"#0b6e99\" },\n { name: \"보라색\", value: \"purple\", hex: \"#6940a5\" },\n { name: \"분홍색\", value: \"pink\", hex: \"#ad1a72\" },\n];\n\n/**\n * 배경 색상 팔레트\n */\nexport const BACKGROUND_COLORS: ColorItem[] = [\n { name: \"기본\", value: \"default\", hex: \"transparent\" },\n { name: \"회색\", value: \"gray\", hex: \"#ebeced\" },\n { name: \"갈색\", value: \"brown\", hex: \"#e9e5e3\" },\n { name: \"빨간색\", value: \"red\", hex: \"#fbe4e4\" },\n { name: \"주황색\", value: \"orange\", hex: \"#f6e9d9\" },\n { name: \"노란색\", value: \"yellow\", hex: \"#fbf3db\" },\n { name: \"초록색\", value: \"green\", hex: \"#ddedea\" },\n { name: \"파란색\", value: \"blue\", hex: \"#ddebf1\" },\n { name: \"보라색\", value: \"purple\", hex: \"#eae4f2\" },\n { name: \"분홍색\", value: \"pink\", hex: \"#f4dfeb\" },\n];\n\n/**\n * 색상 값으로 hex 색상 코드 찾기\n */\nexport const getHexFromColorValue = (\n value: string,\n type: \"text\" | \"background\"\n): string => {\n const colors = type === \"text\" ? TEXT_COLORS : BACKGROUND_COLORS;\n const colorItem = colors.find((c) => c.value === value);\n return colorItem?.hex || (type === \"text\" ? \"#000000\" : \"transparent\");\n};\n","\"use client\";\n\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\n\ninterface LinkButtonProps {\n editor: EditorType | any;\n}\n\n/**\n * 🔒 위험한 URL 프로토콜 검증\n * javascript:, data:, vbscript: 등 XSS 공격에 사용될 수 있는 프로토콜 차단\n */\nexport const isDangerousProtocol = (url: string): boolean => {\n const trimmedUrl = url.trim().toLowerCase();\n // 위험한 프로토콜 패턴\n const dangerousPatterns = [\n /^javascript:/i,\n /^data:/i,\n /^vbscript:/i,\n /^file:/i,\n ];\n return dangerousPatterns.some((pattern) => pattern.test(trimmedUrl));\n};\n\n/**\n * URL 프로토콜 자동 추가 유틸리티 (보안 강화)\n */\nexport const normalizeUrl = (url: string): string | null => {\n const trimmedUrl = url.trim();\n\n // 🔒 위험한 프로토콜 차단\n if (isDangerousProtocol(trimmedUrl)) {\n console.warn(\"Blocked dangerous URL protocol:\", trimmedUrl);\n return null;\n }\n\n // 이미 프로토콜이 있는 경우 그대로 반환\n if (/^https?:\\/\\//i.test(trimmedUrl)) {\n return trimmedUrl;\n }\n\n // mailto: 또는 tel: 링크인 경우 그대로 반환\n if (/^(mailto:|tel:)/i.test(trimmedUrl)) {\n return trimmedUrl;\n }\n\n // 프로토콜이 없는 경우 https:// 추가\n return `https://${trimmedUrl}`;\n};\n\n/**\n * 링크 삽입 버튼\n */\nexport const LinkButton: React.FC<LinkButtonProps> = ({ editor }) => {\n const [isOpen, setIsOpen] = useState(false);\n const [linkUrl, setLinkUrl] = useState(\"\");\n const [errorMsg, setErrorMsg] = useState<string | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const hasSelectionRef = useRef(false);\n\n // 외부 클릭 감지\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n setLinkUrl(\"\");\n setErrorMsg(null);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n // 드롭다운 열릴 때 선택 상태 저장 후 input에 포커스\n useEffect(() => {\n if (isOpen && inputRef.current) {\n try {\n const selectedText = editor?.getSelectedText?.() || \"\";\n hasSelectionRef.current = selectedText.length > 0;\n } catch {\n hasSelectionRef.current = false;\n }\n setTimeout(() => inputRef.current?.focus(), 0);\n }\n }, [isOpen, editor]);\n\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n setErrorMsg(null);\n\n try {\n if (linkUrl.trim() && editor?.createLink) {\n const normalizedUrl = normalizeUrl(linkUrl);\n\n if (normalizedUrl === null) {\n setErrorMsg(\"허용되지 않는 URL 형식입니다.\");\n return;\n }\n\n editor.focus();\n\n if (hasSelectionRef.current) {\n editor.createLink(normalizedUrl);\n } else {\n editor.createLink(normalizedUrl, normalizedUrl);\n }\n\n setIsOpen(false);\n setLinkUrl(\"\");\n }\n } catch (err) {\n console.error(\"Create link failed:\", err);\n setErrorMsg(\"링크 생성에 실패했습니다.\");\n }\n },\n [editor, linkUrl]\n );\n\n const handleCancel = useCallback(() => {\n setIsOpen(false);\n setLinkUrl(\"\");\n setErrorMsg(null);\n }, []);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n handleSubmit();\n } else if (e.key === \"Escape\") {\n handleCancel();\n }\n },\n [handleSubmit, handleCancel]\n );\n\n return (\n <div className=\"lumir-dropdown-wrapper\" ref={dropdownRef}>\n <button\n className=\"lumir-toolbar-btn\"\n onClick={() => setIsOpen(!isOpen)}\n onMouseDown={handleMouseDown}\n title=\"링크 삽입\"\n type=\"button\"\n >\n {Icons.link}\n </button>\n {isOpen && (\n <div className=\"lumir-dropdown-menu lumir-link-menu\">\n <form onSubmit={handleSubmit} className=\"lumir-link-form\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"lumir-link-input\"\n placeholder=\"링크 URL을 입력하세요\"\n value={linkUrl}\n onChange={(e) => {\n setLinkUrl(e.target.value);\n setErrorMsg(null);\n }}\n onKeyDown={handleKeyDown}\n onMouseDown={handleMouseDown}\n />\n {/* 에러 메시지 표시 */}\n {errorMsg && (\n <div\n style={{\n color: \"#dc3545\",\n fontSize: \"12px\",\n marginTop: \"4px\",\n padding: \"0 4px\",\n }}\n >\n {errorMsg}\n </div>\n )}\n <div className=\"lumir-link-actions\">\n <button\n type=\"button\"\n className=\"lumir-link-btn lumir-link-cancel\"\n onClick={handleCancel}\n onMouseDown={handleMouseDown}\n >\n 취소\n </button>\n <button\n type=\"submit\"\n className=\"lumir-link-btn lumir-link-submit\"\n onMouseDown={handleMouseDown}\n disabled={!linkUrl.trim()}\n >\n 확인\n </button>\n </div>\n </form>\n </div>\n )}\n </div>\n );\n};\n","\"use client\";\n\nimport React, { useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\n\ninterface TableButtonProps {\n editor: EditorType | any;\n}\n\n/**\n * 테이블 삽입 버튼\n */\nexport const TableButton: React.FC<TableButtonProps> = ({ editor }) => {\n const handleClick = useCallback(() => {\n try {\n const block = editor?.getTextCursorPosition()?.block;\n if (!block || !editor?.insertBlocks) return;\n\n // 3x3 기본 테이블 생성\n const defaultCell = [{ type: \"text\", text: \"\", styles: {} }];\n const tableContent = {\n type: \"tableContent\",\n rows: [\n { cells: [defaultCell, defaultCell, defaultCell] },\n { cells: [defaultCell, defaultCell, defaultCell] },\n { cells: [defaultCell, defaultCell, defaultCell] },\n ],\n };\n\n editor.insertBlocks(\n [{ type: \"table\", content: tableContent }] as any,\n block,\n \"after\"\n );\n } catch (err) {\n console.error(\"Table insert failed:\", err);\n }\n }, [editor]);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <button\n className=\"lumir-toolbar-btn\"\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n title=\"테이블 삽입\"\n type=\"button\"\n >\n {Icons.table}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useCallback, useRef } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons } from \"../Icons\";\n\ninterface HTMLImportButtonProps {\n editor: EditorType | any;\n}\n\n/**\n * HTML 파일 Import 버튼\n */\nexport const HTMLImportButton: React.FC<HTMLImportButtonProps> = ({\n editor,\n}) => {\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleFileUpload = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n const reader = new FileReader();\n reader.onload = (event) => {\n const content = event.target?.result as string;\n\n try {\n if (!editor || !content.trim()) return;\n\n const block = editor?.getTextCursorPosition()?.block;\n if (!block || !editor?.insertBlocks) return;\n\n // htmlPreview 블록 삽입\n editor.insertBlocks(\n [\n {\n type: \"htmlPreview\",\n props: {\n htmlContent: content,\n fileName: file.name,\n height: \"400px\",\n },\n } as any,\n ],\n block,\n \"after\"\n );\n\n // file input 초기화\n if (fileInputRef.current) {\n fileInputRef.current.value = \"\";\n }\n } catch (err) {\n console.error(\"HTML insert failed:\", err);\n }\n };\n reader.readAsText(file);\n },\n [editor]\n );\n\n const handleClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // 버튼 클릭 시 에디터 포커스/선택 영역 유지\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n return (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".html,.htm\"\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n <button\n className=\"lumir-toolbar-btn\"\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n title=\"HTML Import\"\n type=\"button\"\n >\n {Icons.htmlFile}\n </button>\n </>\n );\n};\n","\"use client\";\n\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport type { EditorType } from \"../../../types\";\nimport { Icons, BlockTypeIcons } from \"../Icons\";\nimport { cn } from \"../../../utils/cn\";\n\ninterface BlockTypeSelectProps {\n editor: EditorType | any;\n}\n\n// 블록 타입 정의\ntype BlockTypeItem = {\n type: string;\n label: string;\n icon: string;\n level?: number;\n isToggle?: boolean;\n};\n\n// 카테고리별 블록 타입\nconst blockTypeCategories: { category: string; items: BlockTypeItem[] }[] = [\n {\n category: \"Headings\",\n items: [\n { type: \"heading\", label: \"Heading 1\", level: 1, icon: \"h1\", isToggle: false },\n { type: \"heading\", label: \"Heading 2\", level: 2, icon: \"h2\", isToggle: false },\n { type: \"heading\", label: \"Heading 3\", level: 3, icon: \"h3\", isToggle: false },\n { type: \"heading\", label: \"Toggle Heading 1\", level: 1, icon: \"toggleH1\", isToggle: true },\n { type: \"heading\", label: \"Toggle Heading 2\", level: 2, icon: \"toggleH2\", isToggle: true },\n { type: \"heading\", label: \"Toggle Heading 3\", level: 3, icon: \"toggleH3\", isToggle: true },\n ],\n },\n {\n category: \"Basic blocks\",\n items: [\n { type: \"paragraph\", label: \"Paragraph\", icon: \"paragraph\" },\n { type: \"quote\", label: \"Quote\", icon: \"quote\" },\n { type: \"codeBlock\", label: \"Code Block\", icon: \"codeBlock\" },\n { type: \"bulletListItem\", label: \"Bullet List\", icon: \"bulletList\" },\n { type: \"numberedListItem\", label: \"Numbered List\", icon: \"numberedList\" },\n { type: \"checkListItem\", label: \"Check List\", icon: \"checkList\" },\n { type: \"toggleListItem\", label: \"Toggle List\", icon: \"toggleList\" },\n ],\n },\n];\n\n// 평탄화된 블록 타입 목록\nconst blockTypes: BlockTypeItem[] = blockTypeCategories.flatMap(\n (cat) => cat.items\n);\n\n/**\n * 블록 타입 선택 드롭다운\n */\nexport const BlockTypeSelect: React.FC<BlockTypeSelectProps> = ({ editor }) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // 현재 블록 타입을 직접 계산\n const getCurrentBlock = () => {\n try {\n return editor?.getTextCursorPosition()?.block;\n } catch {\n return null;\n }\n };\n\n const currentBlock = getCurrentBlock();\n const currentType = currentBlock?.type || \"paragraph\";\n const currentLevel = currentBlock?.props?.level;\n const isCurrentToggle =\n currentType === \"heading\" && currentBlock?.props?.isToggleable === true;\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n const handleTypeChange = (\n type: string,\n level?: number,\n isToggle?: boolean\n ) => {\n try {\n const block = editor?.getTextCursorPosition()?.block;\n if (!block || !editor) return;\n\n const props: any = {};\n if (level) props.level = level;\n\n if (type === \"heading\" && isToggle !== undefined) {\n props.isToggleable = isToggle;\n editor.updateBlock(block, {\n type: \"heading\" as any,\n props,\n });\n } else {\n editor.updateBlock(block, { type: type as any, props });\n }\n\n setIsOpen(false);\n } catch (err) {\n console.error(\"Block type change failed:\", err);\n }\n };\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n }, []);\n\n const getCurrentLabel = () => {\n if (currentType === \"heading\" && currentLevel) {\n const found = blockTypes.find(\n (bt) =>\n bt.type === \"heading\" &&\n bt.level === currentLevel &&\n bt.isToggle === isCurrentToggle\n );\n return found?.label || \"Heading\";\n }\n const found = blockTypes.find((bt) => bt.type === currentType);\n return found?.label || \"Paragraph\";\n };\n\n const getCurrentIcon = () => {\n if (currentType === \"heading\" && currentLevel) {\n const found = blockTypes.find(\n (bt) =>\n bt.type === \"heading\" &&\n bt.level === currentLevel &&\n bt.isToggle === isCurrentToggle\n );\n return found?.icon || `h${currentLevel}`;\n }\n const found = blockTypes.find((bt) => bt.type === currentType);\n return found?.icon || \"paragraph\";\n };\n\n const isActiveItem = (bt: BlockTypeItem) => {\n if (bt.type === \"heading\" && bt.level) {\n const isLevelMatch =\n currentType === \"heading\" && currentLevel === bt.level;\n const isToggleMatch = bt.isToggle === isCurrentToggle;\n return isLevelMatch && isToggleMatch;\n }\n return currentType === bt.type;\n };\n\n return (\n <div className=\"lumir-dropdown-wrapper\" ref={dropdownRef}>\n <button\n className=\"lumir-dropdown-btn lumir-block-type-btn\"\n onClick={() => setIsOpen(!isOpen)}\n onMouseDown={handleMouseDown}\n type=\"button\"\n >\n <span className=\"lumir-block-icon\">\n {BlockTypeIcons[getCurrentIcon()]}\n </span>\n <span className=\"lumir-block-label\">{getCurrentLabel()}</span>\n {Icons.expandMore}\n </button>\n {isOpen && (\n <div className=\"lumir-dropdown-menu lumir-block-menu\">\n {blockTypeCategories.map((category) => (\n <div key={category.category} className=\"lumir-block-category\">\n <div className=\"lumir-block-category-title\">\n {category.category}\n </div>\n {category.items.map((bt) => (\n <button\n key={bt.icon}\n className={cn(\n \"lumir-dropdown-item lumir-block-item\",\n isActiveItem(bt) && \"is-active\"\n )}\n onClick={() => handleTypeChange(bt.type, bt.level, bt.isToggle)}\n onMouseDown={handleMouseDown}\n >\n <span className=\"lumir-block-icon\">\n {BlockTypeIcons[bt.icon]}\n </span>\n <span className=\"lumir-block-item-title\">{bt.label}</span>\n </button>\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n","/**\n * LumirEditor 커스텀 에러 클래스\n */\n\nexport type LumirErrorCode =\n | \"UPLOAD_FAILED\"\n | \"INVALID_FILE_TYPE\"\n | \"S3_CONFIG_ERROR\"\n | \"PRESIGNED_URL_ERROR\"\n | \"NETWORK_ERROR\"\n | \"EDITOR_ERROR\"\n | \"UNKNOWN_ERROR\";\n\nexport interface LumirErrorDetails {\n code: LumirErrorCode;\n originalError?: Error;\n context?: Record<string, unknown>;\n}\n\n/**\n * LumirEditor에서 발생하는 에러를 위한 커스텀 에러 클래스\n */\nexport class LumirEditorError extends Error {\n public readonly code: LumirErrorCode;\n public readonly originalError?: Error;\n public readonly context?: Record<string, unknown>;\n\n constructor(message: string, details: Partial<LumirErrorDetails> = {}) {\n super(message);\n this.name = \"LumirEditorError\";\n this.code = details.code || \"UNKNOWN_ERROR\";\n this.originalError = details.originalError;\n this.context = details.context;\n\n // Error 클래스 확장 시 프로토타입 체인 유지\n Object.setPrototypeOf(this, LumirEditorError.prototype);\n }\n\n /**\n * 에러 정보를 JSON 형태로 반환\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n context: this.context,\n stack: this.stack,\n };\n }\n\n /**\n * 사용자 친화적 에러 메시지 반환\n */\n getUserMessage(): string {\n switch (this.code) {\n case \"UPLOAD_FAILED\":\n return \"파일 업로드에 실패했습니다. 다시 시도해주세요.\";\n case \"INVALID_FILE_TYPE\":\n return \"지원하지 않는 파일 형식입니다. 이미지 파일만 업로드 가능합니다.\";\n case \"S3_CONFIG_ERROR\":\n return \"S3 설정이 올바르지 않습니다. 관리자에게 문의하세요.\";\n case \"PRESIGNED_URL_ERROR\":\n return \"업로드 URL 생성에 실패했습니다. 다시 시도해주세요.\";\n case \"NETWORK_ERROR\":\n return \"네트워크 연결을 확인해주세요.\";\n case \"EDITOR_ERROR\":\n return \"에디터 오류가 발생했습니다. 페이지를 새로고침해주세요.\";\n default:\n return \"알 수 없는 오류가 발생했습니다.\";\n }\n }\n\n /**\n * 일반 Error를 LumirEditorError로 변환\n */\n static fromError(\n error: Error,\n code: LumirErrorCode = \"UNKNOWN_ERROR\",\n context?: Record<string, unknown>\n ): LumirEditorError {\n return new LumirEditorError(error.message, {\n code,\n originalError: error,\n context,\n });\n }\n\n /**\n * 업로드 실패 에러 생성\n */\n static uploadFailed(\n message: string,\n originalError?: Error\n ): LumirEditorError {\n return new LumirEditorError(message, {\n code: \"UPLOAD_FAILED\",\n originalError,\n });\n }\n\n /**\n * 잘못된 파일 형식 에러 생성\n * @param allowVideoUpload true이면 \"image and video\" 메시지 사용\n */\n static invalidFileType(\n fileName: string,\n allowVideoUpload?: boolean\n ): LumirEditorError {\n const message =\n allowVideoUpload === true\n ? `Invalid file type: ${fileName}. Only image and video files are allowed.`\n : `Invalid file type: ${fileName}. Only image files are allowed.`;\n return new LumirEditorError(message, {\n code: \"INVALID_FILE_TYPE\",\n context: { fileName },\n });\n }\n\n /**\n * S3 설정 에러 생성\n */\n static s3ConfigError(message: string): LumirEditorError {\n return new LumirEditorError(message, {\n code: \"S3_CONFIG_ERROR\",\n });\n }\n\n /**\n * 네트워크 에러 생성\n */\n static networkError(originalError?: Error): LumirEditorError {\n return new LumirEditorError(\"Network request failed\", {\n code: \"NETWORK_ERROR\",\n originalError,\n });\n }\n}\n","import { Extension } from \"@tiptap/core\";\n\nexport type VerticalAlignment = \"top\" | \"middle\" | \"bottom\";\n\nexport const VerticalAlignmentExtension = Extension.create({\n name: \"verticalAlignment\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n verticalAlignment: {\n default: \"top\",\n parseHTML: (element) => {\n return (\n element.getAttribute(\"data-vertical-alignment\") || \"top\"\n );\n },\n renderHTML: (attributes) => {\n if (\n !attributes.verticalAlignment ||\n attributes.verticalAlignment === \"top\"\n ) {\n return {};\n }\n return {\n \"data-vertical-alignment\": attributes.verticalAlignment,\n };\n },\n },\n },\n },\n ];\n },\n\n addProseMirrorPlugins() {\n return [];\n },\n});\n","\"use client\";\n\nimport {\n BasicTextStyleButton,\n BlockTypeSelect,\n ColorStyleButton,\n CreateLinkButton,\n FileCaptionButton,\n FileDeleteButton,\n FileRenameButton,\n FileReplaceButton,\n FileDownloadButton,\n FilePreviewButton,\n FormattingToolbar,\n NestBlockButton,\n UnnestBlockButton,\n TableCellMergeButton,\n} from \"@blocknote/react\";\nimport { TextAlignButtonWithVA } from \"./TextAlignButtonWithVA\";\nimport { VerticalAlignButton } from \"./VerticalAlignButton\";\n\n/**\n * BlockNote 기본 FormattingToolbar + 세로 정렬 버튼(top/middle/bottom)\n *\n * @see https://www.blocknotejs.org/examples/ui-components/formatting-toolbar-buttons\n */\nexport const CustomFormattingToolbar = () => {\n return (\n <FormattingToolbar>\n <BlockTypeSelect key={\"blockTypeSelect\"} />\n <TableCellMergeButton key={\"tableCellMergeButton\"} />\n\n <FileCaptionButton key={\"fileCaptionButton\"} />\n <FileReplaceButton key={\"replaceFileButton\"} />\n <FileRenameButton key={\"fileRenameButton\"} />\n <FileDeleteButton key={\"fileDeleteButton\"} />\n <FileDownloadButton key={\"fileDownloadButton\"} />\n <FilePreviewButton key={\"filePreviewButton\"} />\n\n <BasicTextStyleButton basicTextStyle={\"bold\"} key={\"boldStyleButton\"} />\n <BasicTextStyleButton\n basicTextStyle={\"italic\"}\n key={\"italicStyleButton\"}\n />\n <BasicTextStyleButton\n basicTextStyle={\"underline\"}\n key={\"underlineStyleButton\"}\n />\n <BasicTextStyleButton\n basicTextStyle={\"strike\"}\n key={\"strikeStyleButton\"}\n />\n\n <TextAlignButtonWithVA textAlignment={\"left\"} key={\"textAlignLeftButton\"} />\n <TextAlignButtonWithVA\n textAlignment={\"center\"}\n key={\"textAlignCenterButton\"}\n />\n <TextAlignButtonWithVA textAlignment={\"right\"} key={\"textAlignRightButton\"} />\n\n {/* 세로 정렬 버튼 (테이블 셀 선택 시에만 표시) */}\n <VerticalAlignButton\n verticalAlignment=\"top\"\n key={\"verticalAlignTop\"}\n />\n <VerticalAlignButton\n verticalAlignment=\"middle\"\n key={\"verticalAlignMiddle\"}\n />\n <VerticalAlignButton\n verticalAlignment=\"bottom\"\n key={\"verticalAlignBottom\"}\n />\n\n <ColorStyleButton key={\"colorStyleButton\"} />\n <NestBlockButton key={\"nestBlockButton\"} />\n <UnnestBlockButton key={\"unnestBlockButton\"} />\n <CreateLinkButton key={\"createLinkButton\"} />\n </FormattingToolbar>\n );\n};\n","\"use client\";\n\n/**\n * BlockNote 기본 TextAlignButton의 커스텀 버전.\n * 테이블 셀에서 가로 정렬 변경 시 ProseMirror 트랜잭션을 직접 사용하여\n * selection이 유지되고 verticalAlignment가 초기화되지 않도록 한다.\n */\n\nimport {\n BlockSchema,\n checkBlockHasDefaultProp,\n checkBlockTypeHasDefaultProp,\n InlineContentSchema,\n mapTableCell,\n StyleSchema,\n TableContent,\n} from \"@blocknote/core\";\nimport { useCallback, useMemo } from \"react\";\nimport {\n useComponentsContext,\n useBlockNoteEditor,\n useSelectedBlocks,\n} from \"@blocknote/react\";\nimport { getSelectedCellPositions } from \"../utils/prosemirror-table-utils\";\n\ntype TextAlignment = \"left\" | \"center\" | \"right\" | \"justify\";\n\nconst icons: Record<TextAlignment, JSX.Element> = {\n left: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"18\" height=\"18\">\n <path d=\"M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z\" />\n </svg>\n ),\n center: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"18\" height=\"18\">\n <path d=\"M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z\" />\n </svg>\n ),\n right: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"18\" height=\"18\">\n <path d=\"M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z\" />\n </svg>\n ),\n justify: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"18\" height=\"18\">\n <path d=\"M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zM3 3v2h18V3H3z\" />\n </svg>\n ),\n};\n\nconst tooltipMap: Record<TextAlignment, string> = {\n left: \"왼쪽 정렬\",\n center: \"가운데 정렬\",\n right: \"오른쪽 정렬\",\n justify: \"양쪽 정렬\",\n};\n\nexport const TextAlignButtonWithVA = (props: {\n textAlignment: TextAlignment;\n}) => {\n const Components = useComponentsContext()!;\n const editor = useBlockNoteEditor<\n BlockSchema,\n InlineContentSchema,\n StyleSchema\n >();\n\n const selectedBlocks = useSelectedBlocks(editor);\n\n const textAlignment = useMemo(() => {\n const block = selectedBlocks[0];\n\n if (checkBlockHasDefaultProp(\"textAlignment\", block, editor)) {\n return block.props.textAlignment;\n }\n if (block.type === \"table\") {\n const cellSelection = editor.tableHandles?.getCellSelection();\n if (!cellSelection) {\n return;\n }\n const allCellsInTable = cellSelection.cells.map(\n ({ row, col }: { row: number; col: number }) =>\n mapTableCell(\n (block.content as TableContent<any, any>).rows[row].cells[col],\n ).props.textAlignment,\n );\n const firstAlignment = allCellsInTable[0];\n\n if (allCellsInTable.every((alignment: string) => alignment === firstAlignment)) {\n return firstAlignment;\n }\n }\n\n return;\n }, [editor, selectedBlocks]);\n\n const setTextAlignment = useCallback(\n (newAlignment: TextAlignment) => {\n editor.focus();\n\n for (const block of selectedBlocks) {\n if (block.type === \"table\") {\n const tiptap = editor._tiptapEditor;\n if (!tiptap) continue;\n\n const positions = getSelectedCellPositions(editor);\n if (positions.length === 0) continue;\n\n const { state } = tiptap;\n let tr = state.tr;\n\n for (const pos of positions) {\n const node = tr.doc.nodeAt(pos);\n if (node) {\n tr = tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n textAlignment: newAlignment,\n });\n }\n }\n\n tiptap.view?.dispatch(tr);\n } else if (checkBlockTypeHasDefaultProp(\"textAlignment\", block.type, editor)) {\n editor.updateBlock(block, {\n props: { textAlignment: newAlignment },\n });\n }\n }\n },\n [editor, selectedBlocks],\n );\n\n const show = useMemo(() => {\n return !!selectedBlocks.find(\n (block) =>\n \"textAlignment\" in block.props ||\n (block.type === \"table\" && block.children),\n );\n }, [selectedBlocks]);\n\n if (!show || !editor.isEditable) {\n return null;\n }\n\n return (\n <Components.FormattingToolbar.Button\n className={\"bn-button\"}\n data-test={`alignText${\n props.textAlignment.slice(0, 1).toUpperCase() +\n props.textAlignment.slice(1)\n }`}\n onClick={() => setTextAlignment(props.textAlignment)}\n isSelected={textAlignment === props.textAlignment}\n label={tooltipMap[props.textAlignment]}\n mainTooltip={tooltipMap[props.textAlignment]}\n icon={icons[props.textAlignment]}\n />\n );\n};\n","/**\n * ProseMirror selection에서 현재 선택된 테이블 셀의 위치(pos)를 반환한다.\n * CellSelection이면 선택된 모든 셀, 일반 selection이면 커서가 있는 셀.\n * prosemirror-tables 직접 임포트 없이 duck-typing으로 CellSelection을 감지한다.\n */\nexport function getSelectedCellPositions(editor: any): number[] {\n const tiptap = editor._tiptapEditor;\n if (!tiptap) return [];\n\n const { state } = tiptap;\n const { selection } = state;\n\n if (typeof selection.forEachCell === \"function\") {\n const positions: number[] = [];\n selection.forEachCell((_node: any, pos: number) => {\n positions.push(pos);\n });\n return positions;\n }\n\n const $pos = selection.$from;\n for (let depth = $pos.depth; depth > 0; depth--) {\n const node = $pos.node(depth);\n if (\n node.type.name === \"tableCell\" ||\n node.type.name === \"tableHeader\"\n ) {\n return [$pos.before(depth)];\n }\n }\n\n return [];\n}\n","\"use client\";\n\nimport { useCallback, useMemo } from \"react\";\nimport {\n useBlockNoteEditor,\n useComponentsContext,\n useSelectedBlocks,\n} from \"@blocknote/react\";\nimport type {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"@blocknote/core\";\nimport type { VerticalAlignment } from \"../extensions/VerticalAlignmentExtension\";\nimport { getSelectedCellPositions } from \"../utils/prosemirror-table-utils\";\n\nconst icons: Record<VerticalAlignment, JSX.Element> = {\n top: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\">\n <rect x=\"2\" y=\"2\" width=\"12\" height=\"12\" rx=\"1\" />\n <line x1=\"5\" y1=\"5\" x2=\"11\" y2=\"5\" />\n </svg>\n ),\n middle: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\">\n <rect x=\"2\" y=\"2\" width=\"12\" height=\"12\" rx=\"1\" />\n <line x1=\"5\" y1=\"8\" x2=\"11\" y2=\"8\" />\n </svg>\n ),\n bottom: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\">\n <rect x=\"2\" y=\"2\" width=\"12\" height=\"12\" rx=\"1\" />\n <line x1=\"5\" y1=\"11\" x2=\"11\" y2=\"11\" />\n </svg>\n ),\n};\n\nconst tooltips: Record<VerticalAlignment, string> = {\n top: \"위쪽 정렬\",\n middle: \"세로 가운데 정렬\",\n bottom: \"아래쪽 정렬\",\n};\n\nfunction getCurrentVerticalAlignment(editor: any): VerticalAlignment | undefined {\n const tiptap = editor._tiptapEditor;\n if (!tiptap) return undefined;\n\n const positions = getSelectedCellPositions(editor);\n if (positions.length === 0) return undefined;\n\n const { state } = tiptap;\n const alignments = positions.map((pos) => {\n const node = state.doc.nodeAt(pos);\n return (node?.attrs?.verticalAlignment as VerticalAlignment) || \"top\";\n });\n\n const first = alignments[0];\n return alignments.every((a) => a === first) ? first : undefined;\n}\n\nexport const VerticalAlignButton = (props: {\n verticalAlignment: VerticalAlignment;\n}) => {\n const Components = useComponentsContext()!;\n const editor = useBlockNoteEditor<\n BlockSchema,\n InlineContentSchema,\n StyleSchema\n >();\n\n const selectedBlocks = useSelectedBlocks(editor);\n\n const currentAlignment = useMemo(() => {\n return getCurrentVerticalAlignment(editor);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor, selectedBlocks]);\n\n const setVerticalAlignment = useCallback(\n (alignment: VerticalAlignment) => {\n const tiptap = editor._tiptapEditor;\n if (!tiptap) return;\n\n const positions = getSelectedCellPositions(editor);\n if (positions.length === 0) return;\n\n editor.focus();\n\n const { state } = tiptap;\n let tr = state.tr;\n\n for (const pos of positions) {\n const node = tr.doc.nodeAt(pos);\n if (node) {\n tr = tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n verticalAlignment: alignment,\n });\n }\n }\n\n tiptap.view?.dispatch(tr);\n },\n [editor],\n );\n\n const isInTable = useMemo(() => {\n return selectedBlocks.some((block) => block.type === \"table\");\n }, [selectedBlocks]);\n\n if (!isInTable || !editor.isEditable) {\n return null;\n }\n\n return (\n <Components.FormattingToolbar.Button\n className={\"bn-button\"}\n data-test={`verticalAlign${props.verticalAlignment.charAt(0).toUpperCase() + props.verticalAlignment.slice(1)}`}\n onClick={() => setVerticalAlignment(props.verticalAlignment)}\n isSelected={currentAlignment === props.verticalAlignment}\n label={tooltips[props.verticalAlignment]}\n mainTooltip={tooltips[props.verticalAlignment]}\n icon={icons[props.verticalAlignment]}\n />\n );\n};\n","import type { VerticalAlignment } from \"../extensions/VerticalAlignmentExtension\";\nimport type { DefaultPartialBlock } from \"../types\";\n\n/**\n * BlockNote의 nodeToBlock은 verticalAlignment를 TableCellProps에 포함하지 않으므로,\n * ProseMirror 상태에서 직접 읽어 블록 JSON에 주입한다.\n *\n * blocks 배열 내 table 블록을 찾고, 해당 테이블의 PM 노드에서 셀별 verticalAlignment를 가져온다.\n */\nexport function injectVerticalAlignment(\n blocks: DefaultPartialBlock[],\n editor: any,\n): DefaultPartialBlock[] {\n const tiptap = editor?._tiptapEditor;\n if (!tiptap) return blocks;\n\n const { doc } = tiptap.state;\n\n const tableVAMap = buildTableVerticalAlignmentMap(doc);\n if (tableVAMap.size === 0) return blocks;\n\n return patchBlocks(blocks, tableVAMap);\n}\n\ntype CellVA = { row: number; col: number; va: VerticalAlignment };\n\n/**\n * ProseMirror 문서에서 각 blockContainer의 id → 셀별 verticalAlignment 맵을 구축\n */\nfunction buildTableVerticalAlignmentMap(\n doc: any,\n): Map<string, CellVA[]> {\n const result = new Map<string, CellVA[]>();\n\n doc.descendants((node: any) => {\n if (node.type.name === \"blockContainer\") {\n const blockId = node.attrs?.id;\n const contentNode = node.firstChild;\n if (\n blockId &&\n contentNode?.type.name === \"table\"\n ) {\n const cells: CellVA[] = [];\n let rowIndex = 0;\n contentNode.forEach((rowNode: any) => {\n if (rowNode.type.name === \"tableRow\") {\n let colIndex = 0;\n rowNode.forEach((cellNode: any) => {\n const va = cellNode.attrs?.verticalAlignment;\n if (va && va !== \"top\") {\n cells.push({ row: rowIndex, col: colIndex, va });\n }\n colIndex++;\n });\n rowIndex++;\n }\n });\n if (cells.length > 0) {\n result.set(blockId, cells);\n }\n }\n return false;\n }\n });\n\n return result;\n}\n\nfunction patchBlocks(\n blocks: DefaultPartialBlock[],\n tableVAMap: Map<string, CellVA[]>,\n): DefaultPartialBlock[] {\n return blocks.map((block) => {\n if (\n block.type !== \"table\" ||\n !block.id ||\n !block.content\n ) {\n if (block.children && block.children.length > 0) {\n return {\n ...block,\n children: patchBlocks(block.children as DefaultPartialBlock[], tableVAMap),\n };\n }\n return block;\n }\n\n const cells = tableVAMap.get(block.id);\n if (!cells || cells.length === 0) {\n return block;\n }\n\n const content = block.content as any;\n if (content.type !== \"tableContent\" || !content.rows) {\n return block;\n }\n\n const newRows = content.rows.map((row: any, rowIndex: number) => {\n const newCells = row.cells.map((cell: any, colIndex: number) => {\n const match = cells.find(\n (c) => c.row === rowIndex && c.col === colIndex,\n );\n if (!match) return cell;\n\n if (\n cell &&\n typeof cell === \"object\" &&\n cell.type === \"tableCell\"\n ) {\n return {\n ...cell,\n props: { ...cell.props, verticalAlignment: match.va },\n };\n }\n return cell;\n });\n return { ...row, cells: newCells };\n });\n\n return {\n ...block,\n content: { ...content, rows: newRows },\n };\n });\n}\n","/**\n * 보안 및 성능 제한 상수\n */\n\n/** 최대 파일 크기: 10MB (이미지) */\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n/** 최대 동영상 파일 크기: 100MB */\nexport const MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;\n\n/** 업로드 타임아웃: 30초 (이미지 등) */\nexport const UPLOAD_TIMEOUT = 30000;\n\n/** 대용량 파일(비디오 등) 업로드 타임아웃: 120초 */\nexport const UPLOAD_TIMEOUT_VIDEO = 120000;\n\n/** 허용된 이미지 MIME 타입 (SVG 제외) */\nexport const ALLOWED_IMAGE_MIME_TYPES = new Set([\n \"image/jpeg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\",\n \"image/bmp\",\n]);\n\n/** 차단된 파일 확장자 */\nexport const BLOCKED_EXTENSIONS = [\".svg\", \".svgz\"];\n\n/** 허용된 이미지 확장자 */\nexport const ALLOWED_IMAGE_EXTENSIONS = [\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".webp\",\n \".bmp\",\n];\n\n/** 허용된 동영상 MIME 타입 */\nexport const ALLOWED_VIDEO_MIME_TYPES = new Set([\n \"video/mp4\",\n \"video/webm\",\n \"video/ogg\",\n \"video/quicktime\", // .mov\n]);\n\n/** 허용된 동영상 확장자 */\nexport const ALLOWED_VIDEO_EXTENSIONS = [\n \".mp4\",\n \".webm\",\n \".ogg\",\n \".mov\",\n];\n"],"mappings":"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","names":["useEffect","useMemo","useCallback","useState","useRef","useBlockNoteEditor","useComponentsContext","createReactBlockSpec","endpoint","createReactBlockSpec","useState","useCallback","useRef","useEffect","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","jsx","jsxs","createReactBlockSpec","useState","useEffect","useRef","jsx","jsxs","jsx","useCallback","jsx","jsxs","useCallback","useCallback","jsx","useCallback","useCallback","jsx","iconMap","titleMap","useCallback","useCallback","jsx","iconMap","titleMap","useCallback","useCallback","jsx","useCallback","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useEffect","useCallback","useCallback","jsx","useCallback","useCallback","useRef","Fragment","jsx","jsxs","useRef","useCallback","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useEffect","useCallback","found","Fragment","jsx","jsxs","useRef","useState","useEffect","BlockTypeSelect","useCallback","jsx","useCallback","useCallback","useMemo","useBlockNoteEditor","useComponentsContext","useSelectedBlocks","jsx","jsxs","icons","useComponentsContext","useBlockNoteEditor","useSelectedBlocks","useMemo","useCallback","jsx","jsxs","BlockTypeSelect","Fragment","jsx","jsxs","useBlockNoteEditor","useComponentsContext","jsx","jsxs","useState","useRef","useCallback","useMemo","useEffect","editor","Fragment"]}
|