import * as react from 'react'; import react__default from 'react'; import * as _blocknote_core from '@blocknote/core'; import { PartialBlock, DefaultBlockSchema, DefaultInlineContentSchema, DefaultStyleSchema, BlockNoteEditor, BlockNoteSchema } from '@blocknote/core'; export { BlockNoteEditor, DefaultBlockSchema, DefaultInlineContentSchema, DefaultStyleSchema, PartialBlock } from '@blocknote/core'; /** * LumirEditor 커스텀 에러 클래스 */ type LumirErrorCode = "UPLOAD_FAILED" | "INVALID_FILE_TYPE" | "S3_CONFIG_ERROR" | "PRESIGNED_URL_ERROR" | "NETWORK_ERROR" | "EDITOR_ERROR" | "UNKNOWN_ERROR"; interface LumirErrorDetails { code: LumirErrorCode; originalError?: Error; context?: Record; } /** * LumirEditor에서 발생하는 에러를 위한 커스텀 에러 클래스 */ declare class LumirEditorError extends Error { readonly code: LumirErrorCode; readonly originalError?: Error; readonly context?: Record; constructor(message: string, details?: Partial); /** * 에러 정보를 JSON 형태로 반환 */ toJSON(): Record; /** * 사용자 친화적 에러 메시지 반환 */ getUserMessage(): string; /** * 일반 Error를 LumirEditorError로 변환 */ static fromError(error: Error, code?: LumirErrorCode, context?: Record): LumirEditorError; /** * 업로드 실패 에러 생성 */ static uploadFailed(message: string, originalError?: Error): LumirEditorError; /** * 잘못된 파일 형식 에러 생성 * @param allowVideoUpload true이면 "image and video" 메시지 사용 */ static invalidFileType(fileName: string, allowVideoUpload?: boolean): LumirEditorError; /** * S3 설정 에러 생성 */ static s3ConfigError(message: string): LumirEditorError; /** * 네트워크 에러 생성 */ static networkError(originalError?: Error): LumirEditorError; } /** * LumirEditor에서 사용하는 BlockNote 에디터 타입 */ type EditorType = BlockNoteEditor; /** * LumirEditor에서 사용하는 기본 블록 타입 */ type DefaultPartialBlock = PartialBlock; /** * LumirEditor 컴포넌트의 Props 인터페이스 */ interface LumirEditorProps { initialContent?: DefaultPartialBlock[] | string; initialEmptyBlocks?: number; placeholder?: string; uploadFile?: (file: File) => Promise; s3Upload?: { apiEndpoint: string; env: "development" | "production"; path: string; /** 파일명 변환 콜백 - 확장자를 제외한 파일명을 받아 변환합니다 */ fileNameTransform?: (nameWithoutExt: string, file: File) => string; /** true일 경우 파일명 뒤에 UUID를 자동으로 추가합니다 (예: image_abc123.png) */ appendUUID?: boolean; /** false로 설정하면 확장자를 자동으로 붙이지 않음 (기본: true) */ preserveExtension?: boolean; /** 업로드 진행률(0–100) 콜백. S3 PUT 시에만 호출됨 */ onProgress?: (percent: number) => void; /** PUT 요청 타임아웃(ms). 미설정 시 120000(120초). 대용량 비디오에 유리 */ uploadTimeoutMs?: number; /** PUT 실패 시 재시도 횟수. 기본 2(최대 3회 시도) */ maxRetries?: number; }; allowVideoUpload?: boolean; allowAudioUpload?: boolean; allowFileUpload?: boolean; /** 이미지 최대 파일 크기(바이트). 미설정 시 기본 제한(10MB) 사용 */ maxImageFileSize?: number; /** 동영상 최대 파일 크기(바이트). 미설정 시 기본 제한(100MB) 사용 */ maxVideoFileSize?: number; tables?: { splitCells?: boolean; cellBackgroundColor?: boolean; cellTextColor?: boolean; headers?: boolean; }; heading?: { levels?: (1 | 2 | 3 | 4 | 5 | 6)[]; }; defaultStyles?: boolean; disableExtensions?: string[]; tabBehavior?: "prefer-navigate-ui" | "prefer-indent"; trailingBlock?: boolean; editable?: boolean; theme?: "light" | "dark" | Partial> | { light: Partial>; dark: Partial>; }; formattingToolbar?: boolean; linkToolbar?: boolean; sideMenu?: boolean; emojiPicker?: boolean; filePanel?: boolean; tableHandles?: boolean; onSelectionChange?: () => void; className?: string; sideMenuAddButton?: boolean; columnDivider?: boolean; floatingMenu?: boolean; floatingMenuPosition?: "sticky" | "fixed"; linkPreview?: { /** 링크 메타데이터를 가져올 API 엔드포인트 (예: "/api/link-preview") */ apiEndpoint: string; }; onContentChange?: (content: DefaultPartialBlock[]) => void; /** 에러 발생 시 호출되는 콜백 */ onError?: (error: LumirEditorError) => void; /** * 이미지·비디오(미디어)가 에디터에서 삭제될 때 호출되는 콜백 * - S3 등 외부 스토리지에서 해당 미디어를 삭제하는 용도로 사용 * - 이미지 블록과 비디오 블록 삭제 시 모두 호출됨 * - Undo/Redo를 고려하여 지연 삭제를 권장 * @param imageUrl 삭제된 이미지 또는 비디오의 URL */ onImageDelete?: (imageUrl: string) => void; } /** * 글자 크기(fontSize) 직렬화 호환 레이어. * * 배경: * - BlockNote는 인라인 `styles` 맵에 스키마에 없는 키가 있으면 * `style ${name} not found in styleSchema` 예외를 던진다(blockToNode → * styledTextToNodes). 이미 배포된 구버전 SDK(≤0.4.15, fontSize 스펙 없음)가 * `styles.fontSize`가 포함된 JSON을 initialContent로 받으면 에디터 생성이 * 실패하며 React 트리가 크래시한다. * - 반면 styled-text 객체의 **형제(sibling) 키**는 BlockNote가 읽지 않으므로 * 조용히 무시된다(크래시 없음). * * 전략: * - 저장/전달용 JSON(onContentChange 출력)에서는 `styles.fontSize`를 형제 키 * `fontSize`로 내린다(lowerFontSize). * - 로드 시(initialContent)에는 형제 키를 다시 `styles.fontSize`로 올려 * 신버전 에디터가 렌더링하게 한다(liftFontSize). * * ⚠️ 불변 규칙: 에디터 외부로 블록 JSON을 내보내는 모든 경로는 반드시 * lowerFontSize를 거쳐야 한다(현재 출력 표면은 onContentChange 유일). * styles.fontSize가 저장 JSON에 유출되면 구버전 소비 앱이 크래시한다. */ /** * 직렬화(저장) 포맷의 styled-text 항목. * fontSize는 styles 맵이 아닌 형제 키로 존재한다 — 구버전 SDK(≤0.4.15)는 * styles만 순회하므로 이 키를 조용히 무시한다(파싱 오류 없음). */ type SerializedStyledText = { type: "text"; text: string; styles: Record; /** 인라인 글자 크기(예: "18px"). 구버전 SDK에서는 무시됨 */ fontSize?: string; }; /** * 출력 방향: `styles.fontSize` → 형제 키 `fontSize`. * onContentChange로 내보내는 블록 JSON에 적용해 구버전 SDK 크래시를 방지한다. * 입력을 변형하지 않는다(불변). */ declare function lowerFontSize(blocks: DefaultPartialBlock[]): DefaultPartialBlock[]; /** * 입력 방향: 형제 키 `fontSize` → `styles.fontSize`. * initialContent를 에디터에 넘기기 전에 적용해 글자 크기를 복원한다. * 입력을 변형하지 않는다(불변). */ declare function liftFontSize(blocks: DefaultPartialBlock[]): DefaultPartialBlock[]; /** * 콘텐츠 관리 유틸리티 * 기본 블록 생성 및 콘텐츠 검증 로직을 담당 */ declare class ContentUtils { /** * JSON 문자열의 유효성을 검증합니다 * @param jsonString 검증할 JSON 문자열 * @returns 유효한 JSON 문자열인지 여부 */ static isValidJSONString(jsonString: string): boolean; /** * JSON 문자열을 DefaultPartialBlock 배열로 파싱합니다 * @param jsonString JSON 문자열 * @returns 파싱된 블록 배열 또는 null (파싱 실패 시) */ static parseJSONContent(jsonString: string): DefaultPartialBlock[] | null; /** * 기본 paragraph 블록 생성 * @returns 기본 설정이 적용된 DefaultPartialBlock */ static createDefaultBlock(): DefaultPartialBlock; /** * 콘텐츠 유효성 검증 및 기본값 설정 * @param content 사용자 제공 콘텐츠 (객체 배열 또는 JSON 문자열) * @param emptyBlockCount 빈 블록 개수 (기본값: 3) * @returns 검증된 콘텐츠 배열 */ static validateContent(content?: DefaultPartialBlock[] | string, emptyBlockCount?: number): DefaultPartialBlock[]; /** * 빈 블록들을 생성합니다 * @param emptyBlockCount 생성할 블록 개수 * @returns 생성된 빈 블록 배열 */ private static createEmptyBlocks; } /** * 에디터 설정 관리 유틸리티 * 각종 설정의 기본값과 검증 로직을 담당 */ declare class EditorConfig { /** * 테이블 설정 기본값 적용 * @param userTables 사용자 테이블 설정 * @returns 기본값이 적용된 테이블 설정 */ static getDefaultTableConfig(userTables?: LumirEditorProps["tables"]): { splitCells: boolean; cellBackgroundColor: boolean; cellTextColor: boolean; headers: boolean; }; /** * 헤딩 설정 기본값 적용 * @param userHeading 사용자 헤딩 설정 * @returns 기본값이 적용된 헤딩 설정 */ static getDefaultHeadingConfig(userHeading?: LumirEditorProps["heading"]): { levels?: (1 | 2 | 3 | 4 | 5 | 6)[]; }; /** * 비활성화할 확장 기능 목록 생성 * @param userExtensions 사용자 정의 비활성 확장 * @param allowVideo 비디오 업로드 허용 여부 * @param allowAudio 오디오 업로드 허용 여부 * @param allowFile 일반 파일 업로드 허용 여부 * @returns 비활성화할 확장 기능 목록 */ static getDisabledExtensions(userExtensions?: string[], allowVideo?: boolean, allowAudio?: boolean, allowFile?: boolean): string[]; } declare function LumirEditor({ initialContent, initialEmptyBlocks, uploadFile, s3Upload, tables, heading, defaultStyles, disableExtensions, tabBehavior, trailingBlock, allowVideoUpload, allowAudioUpload, allowFileUpload, maxImageFileSize, maxVideoFileSize, linkPreview, editable, theme, formattingToolbar, linkToolbar, sideMenu, emojiPicker, filePanel, tableHandles, onSelectionChange, className, placeholder, sideMenuAddButton, columnDivider, floatingMenu, floatingMenuPosition, onContentChange, onError, onImageDelete, }: LumirEditorProps): react.JSX.Element; declare function cn(...inputs: (string | undefined | null | false)[]): string; interface S3UploaderConfig { apiEndpoint: string; env: "production" | "development"; path: string; /** 파일명 변환 콜백 - 확장자를 제외한 파일명을 받아 변환합니다 */ fileNameTransform?: (nameWithoutExt: string, file: File) => string; /** true일 경우 파일명 뒤에 UUID를 자동으로 추가합니다 (예: image_abc123.png) */ appendUUID?: boolean; /** false로 설정하면 확장자를 자동으로 붙이지 않음 (기본: true) */ preserveExtension?: boolean; /** 업로드 진행률(0–100) 콜백. S3 PUT 시에만 호출됨 */ onProgress?: (percent: number) => void; /** PUT 요청 타임아웃(ms). 미설정 시 120000(120초). 대용량 비디오에 유리 */ uploadTimeoutMs?: number; /** PUT 실패 시 재시도 횟수. 기본 2(최대 3회 시도) */ maxRetries?: number; } declare const createS3Uploader: (config: S3UploaderConfig) => (file: File) => Promise; declare const HtmlPreviewBlock: { config: { readonly type: "htmlPreview"; readonly propSchema: { readonly htmlContent: { readonly default: ""; }; readonly fileName: { readonly default: ""; }; readonly height: { readonly default: "400px"; }; }; readonly content: "none"; }; implementation: _blocknote_core.TiptapBlockImplementation<{ readonly type: "htmlPreview"; readonly propSchema: { readonly htmlContent: { readonly default: ""; }; readonly fileName: { readonly default: ""; }; readonly height: { readonly default: "400px"; }; }; readonly content: "none"; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; declare const schema: BlockNoteSchema<_blocknote_core.BlockSchemaFromSpecs<{ htmlPreview: { config: { readonly type: "htmlPreview"; readonly propSchema: { readonly htmlContent: { readonly default: ""; }; readonly fileName: { readonly default: ""; }; readonly height: { readonly default: "400px"; }; }; readonly content: "none"; }; implementation: _blocknote_core.TiptapBlockImplementation<{ readonly type: "htmlPreview"; readonly propSchema: { readonly htmlContent: { readonly default: ""; }; readonly fileName: { readonly default: ""; }; readonly height: { readonly default: "400px"; }; }; readonly content: "none"; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; linkPreview: { config: { readonly type: "linkPreview"; readonly propSchema: { readonly url: { readonly default: ""; }; readonly title: { readonly default: ""; }; readonly description: { readonly default: ""; }; readonly image: { readonly default: ""; }; readonly domain: { readonly default: ""; }; readonly previewWidth: { readonly default: 400; }; readonly previewHeight: { readonly default: 200; }; }; readonly content: "none"; }; implementation: _blocknote_core.TiptapBlockImplementation<{ readonly type: "linkPreview"; readonly propSchema: { readonly url: { readonly default: ""; }; readonly title: { readonly default: ""; }; readonly description: { readonly default: ""; }; readonly image: { readonly default: ""; }; readonly domain: { readonly default: ""; }; readonly previewWidth: { readonly default: 400; }; readonly previewHeight: { readonly default: 200; }; }; readonly content: "none"; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; video: { config: { readonly type: "video"; readonly propSchema: { readonly url: { readonly default: ""; }; readonly previewWidth: { readonly default: 640; }; readonly previewHeight: { readonly default: 360; }; }; readonly content: "none"; }; implementation: _blocknote_core.TiptapBlockImplementation<{ readonly type: "video"; readonly propSchema: { readonly url: { readonly default: ""; }; readonly previewWidth: { readonly default: 640; }; readonly previewHeight: { readonly default: 360; }; }; readonly content: "none"; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; columnList: { config: { type: "columnList"; content: "none"; propSchema: { showDivider: { default: false; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "columnList"; content: "none"; propSchema: { showDivider: { default: false; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; column: { config: { type: "column"; content: "none"; propSchema: {}; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "column"; content: "none"; propSchema: {}; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; paragraph: { config: { type: "paragraph"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "paragraph"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; heading: { config: { type: "heading"; content: "inline"; propSchema: { level: { default: number; values: readonly [1, 2, 3, 4, 5, 6]; }; isToggleable: { default: false; }; backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "heading"; content: "inline"; propSchema: { level: { default: number; values: readonly [1, 2, 3, 4, 5, 6]; }; isToggleable: { default: false; }; backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; quote: { config: { type: "quote"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "quote"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; codeBlock: { config: { type: "codeBlock"; content: "inline"; propSchema: { language: { default: string; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "codeBlock"; content: "inline"; propSchema: { language: { default: string; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; toggleListItem: { config: { type: "toggleListItem"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "toggleListItem"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; bulletListItem: { config: { type: "bulletListItem"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "bulletListItem"; content: "inline"; propSchema: { backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; numberedListItem: { config: { type: "numberedListItem"; content: "inline"; propSchema: { start: { default: undefined; type: "number"; }; backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "numberedListItem"; content: "inline"; propSchema: { start: { default: undefined; type: "number"; }; backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; checkListItem: { config: { type: "checkListItem"; content: "inline"; propSchema: { checked: { default: false; }; backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "checkListItem"; content: "inline"; propSchema: { checked: { default: false; }; backgroundColor: { default: "default"; }; textColor: { default: "default"; }; textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; table: { config: { type: "table"; content: "table"; propSchema: { textColor: { default: "default"; }; }; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "table"; content: "table"; propSchema: { textColor: { default: "default"; }; }; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; file: { config: { type: "file"; propSchema: { backgroundColor: { default: "default"; }; name: { default: ""; }; url: { default: ""; }; caption: { default: ""; }; }; content: "none"; isFileBlock: true; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "file"; propSchema: { backgroundColor: { default: "default"; }; name: { default: ""; }; url: { default: ""; }; caption: { default: ""; }; }; content: "none"; isFileBlock: true; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; image: { config: { type: "image"; propSchema: { textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; backgroundColor: { default: "default"; }; name: { default: ""; }; url: { default: ""; }; caption: { default: ""; }; showPreview: { default: true; }; previewWidth: { default: undefined; type: "number"; }; }; content: "none"; isFileBlock: true; fileBlockAccept: string[]; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "image"; propSchema: { textAlignment: { default: "left"; values: readonly ["left", "center", "right", "justify"]; }; backgroundColor: { default: "default"; }; name: { default: ""; }; url: { default: ""; }; caption: { default: ""; }; showPreview: { default: true; }; previewWidth: { default: undefined; type: "number"; }; }; content: "none"; isFileBlock: true; fileBlockAccept: string[]; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; audio: { config: { type: "audio"; propSchema: { backgroundColor: { default: "default"; }; name: { default: ""; }; url: { default: ""; }; caption: { default: ""; }; showPreview: { default: true; }; }; content: "none"; isFileBlock: true; fileBlockAccept: string[]; }; implementation: _blocknote_core.TiptapBlockImplementation<{ type: "audio"; propSchema: { backgroundColor: { default: "default"; }; name: { default: ""; }; url: { default: ""; }; caption: { default: ""; }; showPreview: { default: true; }; }; content: "none"; isFileBlock: true; fileBlockAccept: string[]; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; }>, _blocknote_core.InlineContentSchemaFromSpecs<{ text: { config: "text"; implementation: any; }; link: { config: "link"; implementation: any; }; }>, _blocknote_core.StyleSchemaFromSpecs<{ fontSize: _blocknote_core.StyleSpec<{ type: string; propSchema: "string"; }>; bold: { config: { type: string; propSchema: "boolean"; }; implementation: _blocknote_core.StyleImplementation; }; italic: { config: { type: string; propSchema: "boolean"; }; implementation: _blocknote_core.StyleImplementation; }; underline: { config: { type: string; propSchema: "boolean"; }; implementation: _blocknote_core.StyleImplementation; }; strike: { config: { type: string; propSchema: "boolean"; }; implementation: _blocknote_core.StyleImplementation; }; code: { config: { type: string; propSchema: "boolean"; }; implementation: _blocknote_core.StyleImplementation; }; textColor: { config: { type: string; propSchema: "string"; }; implementation: _blocknote_core.StyleImplementation; }; backgroundColor: { config: { type: string; propSchema: "string"; }; implementation: _blocknote_core.StyleImplementation; }; }>>; interface LinkMetadata { url: string; title: string; description?: string; image?: string; domain: string; } declare function fetchLinkMetadata(url: string, apiEndpoint: string): Promise; declare function clearMetadataCache(): void; declare const LinkPreviewBlock: { config: { readonly type: "linkPreview"; readonly propSchema: { readonly url: { readonly default: ""; }; readonly title: { readonly default: ""; }; readonly description: { readonly default: ""; }; readonly image: { readonly default: ""; }; readonly domain: { readonly default: ""; }; readonly previewWidth: { readonly default: 400; }; readonly previewHeight: { readonly default: 200; }; }; readonly content: "none"; }; implementation: _blocknote_core.TiptapBlockImplementation<{ readonly type: "linkPreview"; readonly propSchema: { readonly url: { readonly default: ""; }; readonly title: { readonly default: ""; }; readonly description: { readonly default: ""; }; readonly image: { readonly default: ""; }; readonly domain: { readonly default: ""; }; readonly previewWidth: { readonly default: 400; }; readonly previewHeight: { readonly default: 200; }; }; readonly content: "none"; }, any, _blocknote_core.InlineContentSchema, _blocknote_core.StyleSchema>; }; interface FloatingMenuProps { editor: EditorType | any; position?: "sticky" | "fixed"; className?: string; onImageUpload?: () => void; } /** * FloatingMenu - 에디터 상단 고정 툴바 */ declare const FloatingMenu: react__default.FC; /** * 인라인 글자 크기 커스텀 스타일. * * - propSchema "string": 값으로 "18px" 같은 CSS 크기를 가진다. * - HTML 직렬화: `` * (BlockNote가 data-* 속성과 파싱 규칙을 자동 생성 → 신버전 에디터 간 복사/붙여넣기 왕복 보장, * 구버전 에디터는 매칭 파싱 규칙이 없어 조용히 무시) * * ⚠️ 저장 JSON 하위호환: BlockNote는 styles 맵에 스키마에 없는 키가 있으면 * `style ... not found in styleSchema` 예외를 던지므로, 저장 JSON에는 * styles.fontSize 대신 형제 키 fontSize로 직렬화한다. * → src/utils/font-size-serialization.ts (liftFontSize/lowerFontSize) 참고. */ declare const FontSize: _blocknote_core.StyleSpec<{ type: string; propSchema: "string"; }>; /** 툴바 드롭다운에서 제공하는 프리셋 (본문 기본은 14px = "기본") */ declare const FONT_SIZE_PRESETS: readonly ["10px", "12px", "14px", "16px", "18px", "20px", "24px", "28px"]; type FontSizePreset = (typeof FONT_SIZE_PRESETS)[number]; /** 글자 크기 1px 스테퍼의 허용 범위/기본값 (사용자 결정: 8~96px). */ declare const FONT_SIZE_MIN = 8; declare const FONT_SIZE_MAX = 96; /** "기본"(명시 fontSize 없음)일 때 기준이 되는 본문 px. */ declare const FONT_SIZE_DEFAULT_PX = 14; declare const FONT_SIZE_STEP = 1; /** "18px" → 18, "" / 파싱 실패 → 14(기본). */ declare function parseFontSizePx(size: string): number; /** 8~96 범위로 보정 + 정수 반올림. */ declare function clampFontSizePx(px: number): number; /** 숫자 → "Npx" (clamp 포함). */ declare function toFontSizeValue(px: number): string; declare function FontSizeButton(): react.JSX.Element | null; /** * 색상 팔레트 상수 * BlockNote 기본 색상 팔레트와 일치 */ interface ColorItem { name: string; value: string; hex: string; } /** * 텍스트 색상 팔레트 */ declare const TEXT_COLORS: ColorItem[]; /** * 배경 색상 팔레트 */ declare const BACKGROUND_COLORS: ColorItem[]; /** * 색상 값으로 hex 색상 코드 찾기 */ declare const getHexFromColorValue: (value: string, type: "text" | "background") => string; export { BACKGROUND_COLORS, type ColorItem, ContentUtils, type DefaultPartialBlock, EditorConfig, type EditorType, FONT_SIZE_DEFAULT_PX, FONT_SIZE_MAX, FONT_SIZE_MIN, FONT_SIZE_PRESETS, FONT_SIZE_STEP, FloatingMenu, FontSize, FontSizeButton, type FontSizePreset, HtmlPreviewBlock, schema as HtmlPreviewSchema, type LinkMetadata, LinkPreviewBlock, LumirEditor, LumirEditorError, type LumirEditorProps, type LumirErrorCode, type LumirErrorDetails, type S3UploaderConfig, type SerializedStyledText, TEXT_COLORS, clampFontSizePx, clearMetadataCache, cn, createS3Uploader, fetchLinkMetadata, getHexFromColorValue, liftFontSize, lowerFontSize, parseFontSizePx, toFontSizeValue };