@pixerate/editor 0.18.0 → 0.20.0
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 +91 -2
- package/dist/agent/index.cjs +625 -2
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +286 -2
- package/dist/agent/index.d.ts +286 -2
- package/dist/agent/index.js +624 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +1240 -22
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +515 -3
- package/dist/canvas/index.d.ts +515 -3
- package/dist/canvas/index.js +1219 -1
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-3TYMNULT.js +1367 -0
- package/dist/chunk-3TYMNULT.js.map +1 -0
- package/dist/chunk-4QPLEUL2.cjs +4480 -0
- package/dist/chunk-4QPLEUL2.cjs.map +1 -0
- package/dist/chunk-4SUNJZWB.cjs +553 -0
- package/dist/chunk-4SUNJZWB.cjs.map +1 -0
- package/dist/chunk-A7DKIA72.js +2657 -0
- package/dist/chunk-A7DKIA72.js.map +1 -0
- package/dist/chunk-AXV2ZW34.cjs +118 -0
- package/dist/chunk-AXV2ZW34.cjs.map +1 -0
- package/dist/chunk-B2ZRLN4S.js +118 -0
- package/dist/chunk-B2ZRLN4S.js.map +1 -0
- package/dist/chunk-CYFJCKC4.js +4480 -0
- package/dist/chunk-CYFJCKC4.js.map +1 -0
- package/dist/chunk-GVW4P7BG.js +2706 -0
- package/dist/chunk-GVW4P7BG.js.map +1 -0
- package/dist/chunk-JACER6TE.cjs +1 -0
- package/dist/chunk-JACER6TE.cjs.map +1 -0
- package/dist/chunk-JYRIOFEN.cjs +2657 -0
- package/dist/chunk-JYRIOFEN.cjs.map +1 -0
- package/dist/chunk-KYRZDWM4.js +299 -0
- package/dist/chunk-KYRZDWM4.js.map +1 -0
- package/dist/chunk-LA7PEGU3.cjs +299 -0
- package/dist/chunk-LA7PEGU3.cjs.map +1 -0
- package/dist/chunk-N7FG6CBO.js +1 -0
- package/dist/chunk-N7FG6CBO.js.map +1 -0
- package/dist/chunk-OYXSKQFR.js +553 -0
- package/dist/chunk-OYXSKQFR.js.map +1 -0
- package/dist/chunk-TVRC4KVT.cjs +1367 -0
- package/dist/chunk-TVRC4KVT.cjs.map +1 -0
- package/dist/chunk-U6NDQFOK.cjs +2706 -0
- package/dist/chunk-U6NDQFOK.cjs.map +1 -0
- package/dist/controller-OUdxPY-X.d.cts +754 -0
- package/dist/controller-OUdxPY-X.d.ts +754 -0
- package/dist/extensions/index.cjs +144 -3
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +9 -144
- package/dist/extensions/index.d.ts +9 -144
- package/dist/extensions/index.js +145 -4
- package/dist/grammar/index.cjs +31 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +239 -19
- package/dist/grammar/index.d.ts +239 -19
- package/dist/grammar/index.js +31 -3
- package/dist/history/index.d.cts +2 -41
- package/dist/history/index.d.ts +2 -41
- package/dist/image-editor/index.cjs +732 -497
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +105 -9
- package/dist/image-editor/index.d.ts +105 -9
- package/dist/image-editor/index.js +721 -486
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index-Ng1pG7JE.d.ts +899 -0
- package/dist/index-k3mFbPx_.d.cts +899 -0
- package/dist/index.cjs +457 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -12
- package/dist/index.d.ts +99 -12
- package/dist/index.js +457 -20
- package/dist/index.js.map +1 -1
- package/dist/registry-iAHbqkYt.d.cts +128 -0
- package/dist/registry-iAHbqkYt.d.ts +128 -0
- package/dist/serializers/index.cjs +26 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +119 -6
- package/dist/serializers/index.d.ts +119 -6
- package/dist/serializers/index.js +24 -1
- package/dist/spreadsheet/index.cjs +122 -2
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +371 -313
- package/dist/spreadsheet/index.d.ts +371 -313
- package/dist/spreadsheet/index.js +127 -7
- package/dist/tokens-CyLZmIei.d.cts +76 -0
- package/dist/tokens-CyLZmIei.d.ts +76 -0
- package/dist/track-changes-G8JcWB8b.d.cts +306 -0
- package/dist/track-changes-G8JcWB8b.d.ts +306 -0
- package/dist/types-BZgcDsC5.d.cts +42 -0
- package/dist/types-BZgcDsC5.d.ts +42 -0
- package/dist/{types-JV3S8VeR.d.cts → types-DMe0vFB1.d.cts} +1 -1
- package/dist/{types-JV3S8VeR.d.ts → types-DMe0vFB1.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-7FWEWE6T.js +0 -1888
- package/dist/chunk-7FWEWE6T.js.map +0 -1
- package/dist/chunk-AIZUKWTL.js +0 -1715
- package/dist/chunk-AIZUKWTL.js.map +0 -1
- package/dist/chunk-GLSIZKOX.js +0 -17
- package/dist/chunk-GLSIZKOX.js.map +0 -1
- package/dist/chunk-LDES3EOS.cjs +0 -1888
- package/dist/chunk-LDES3EOS.cjs.map +0 -1
- package/dist/chunk-LLUAKTLW.cjs +0 -532
- package/dist/chunk-LLUAKTLW.cjs.map +0 -1
- package/dist/chunk-MPPXH7U5.cjs +0 -336
- package/dist/chunk-MPPXH7U5.cjs.map +0 -1
- package/dist/chunk-O7LOPQMH.js +0 -336
- package/dist/chunk-O7LOPQMH.js.map +0 -1
- package/dist/chunk-QGVMBCT5.js +0 -532
- package/dist/chunk-QGVMBCT5.js.map +0 -1
- package/dist/chunk-SEDR75VH.cjs +0 -17
- package/dist/chunk-SEDR75VH.cjs.map +0 -1
- package/dist/chunk-YQCI4CCN.cjs +0 -1715
- package/dist/chunk-YQCI4CCN.cjs.map +0 -1
- package/dist/mention-Dcevh3ff.d.cts +0 -32
- package/dist/mention-Dcevh3ff.d.ts +0 -32
- package/dist/tokens-7kRTEtPb.d.cts +0 -39
- package/dist/tokens-7kRTEtPb.d.ts +0 -39
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/controller.ts","../src/dirty.ts"],"sourcesContent":["import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/controller.ts","../src/dirty.ts","../src/import/controller.ts"],"sourcesContent":["import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n // Opt-in rich clipboard / file import must not bypass the plain-text invariant.\n const richClipboard = this.editor.storage?.richClipboard;\n if (richClipboard) richClipboard.plainTextMode = true;\n const fileImport = this.editor.extensionManager?.extensions.find(\n (ext) => ext.name === \"fileImport\",\n );\n if (fileImport) fileImport.options.asPlainText = true;\n\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n","import { defaultImportRegistry, type DocumentImport } from \"./adapters\";\nimport {\n importFilesIntoEditor,\n type ImportEditorTarget,\n type ImportFilesIntoEditorOptions,\n} from \"./editor\";\nimport type { FileLike, ImportOutcome } from \"./registry\";\n\n/**\n * Opens the browser file picker and resolves with the chosen files (an empty\n * array when the dialog is cancelled). `accept` defaults to every extension\n * and MIME type the default registry can import as a document.\n */\nexport function pickImportFiles(options: { accept?: string; multiple?: boolean } = {}): Promise<File[]> {\n if (typeof document === \"undefined\") return Promise.resolve([]);\n return new Promise((resolve) => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = options.accept ?? defaultImportRegistry.accept(\"document\");\n input.multiple = options.multiple ?? true;\n input.style.display = \"none\";\n const finish = (files: File[]) => {\n input.remove();\n resolve(files);\n };\n input.addEventListener(\"change\", () => finish(Array.from(input.files ?? [])), { once: true });\n input.addEventListener(\"cancel\", () => finish([]), { once: true });\n document.body.appendChild(input);\n input.click();\n });\n}\n\nexport interface FileImportState {\n isImporting: boolean;\n /** Last import error (cleared when a new import starts). */\n error: Error | null;\n /** Outcomes of the most recent import. */\n lastOutcomes: ImportOutcome<DocumentImport>[];\n}\n\nexport interface FileImportControllerOptions extends Omit<ImportFilesIntoEditorOptions, \"at\"> {\n /** Allow choosing several files in the picker (default `true`). */\n multiple?: boolean;\n}\n\n/**\n * Framework-agnostic state for a file-import button: tracks `isImporting` /\n * `error`, opens the file picker and inserts the imported content into the\n * editor returned by `getTarget`. React's `useFileImport` and Svelte's\n * `createFileImport` wrap it.\n */\nexport class FileImportController {\n private state: FileImportState = { isImporting: false, error: null, lastOutcomes: [] };\n private readonly listeners = new Set<(state: FileImportState) => void>();\n private pending = 0;\n\n constructor(\n private readonly getTarget: () => ImportEditorTarget | null | undefined,\n private options: FileImportControllerOptions = {},\n ) {}\n\n setOptions(options: FileImportControllerOptions): void {\n this.options = options;\n }\n\n /** `accept` attribute value for document imports. */\n get accept(): string {\n return (this.options.registry ?? defaultImportRegistry).accept(\"document\");\n }\n\n getState = (): FileImportState => this.state;\n\n subscribe = (listener: (state: FileImportState) => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n private setState(patch: Partial<FileImportState>) {\n this.state = { ...this.state, ...patch };\n this.listeners.forEach((listener) => listener(this.state));\n }\n\n /** Imports files into the editor at `at` (default: the selection). */\n importFiles = async (\n files: Iterable<FileLike> | ArrayLike<FileLike>,\n at?: number,\n ): Promise<ImportOutcome<DocumentImport>[]> => {\n const target = this.getTarget();\n const list = Array.from(files as ArrayLike<FileLike>);\n if (!target || list.length === 0) return [];\n this.pending++;\n this.setState({ isImporting: true, error: null });\n let error: Error | null = null;\n try {\n const outcomes = await importFilesIntoEditor(target, list, {\n ...this.options,\n at,\n onError: (err, file) => {\n error = err;\n this.options.onError?.(err, file);\n },\n });\n this.pending--;\n this.setState({ isImporting: this.pending > 0, error, lastOutcomes: outcomes });\n return outcomes;\n } catch (err) {\n this.pending--;\n this.setState({ isImporting: this.pending > 0, error: err instanceof Error ? err : new Error(String(err)) });\n return [];\n }\n };\n\n /** Opens the file picker and imports the chosen files at the selection. */\n openFilePicker = async (): Promise<ImportOutcome<DocumentImport>[]> => {\n const files = await pickImportFiles({ accept: this.accept, multiple: this.options.multiple });\n return this.importFiles(files);\n };\n}\n\nexport function createFileImportController(\n getTarget: () => ImportEditorTarget | null | undefined,\n options?: FileImportControllerOptions,\n): FileImportController {\n return new FileImportController(getTarget, options);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import adapter registry: maps file types (MIME types and extensions) to
|
|
3
|
+
* converters that turn a file into editor content. Modelled on the desktop
|
|
4
|
+
* import pipelines of document apps, where each source format declares the
|
|
5
|
+
* MIME types and extensions it accepts.
|
|
6
|
+
*
|
|
7
|
+
* Built-in adapters cover markdown, HTML, plain text and RTF for the
|
|
8
|
+
* `document` target. Binary formats (DOCX, PDF, zipped exports) and other
|
|
9
|
+
* targets (e.g. CSV → `spreadsheet`) plug in with `registerImportAdapter`.
|
|
10
|
+
*/
|
|
11
|
+
/** What an import produces content for. Custom targets are plain strings. */
|
|
12
|
+
type ImportTarget = "document" | "spreadsheet" | (string & {});
|
|
13
|
+
/** A `File`/`Blob`-like object; only the members present are used. */
|
|
14
|
+
interface FileLike {
|
|
15
|
+
name?: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
size?: number;
|
|
18
|
+
text?(): Promise<string>;
|
|
19
|
+
arrayBuffer?(): Promise<ArrayBuffer>;
|
|
20
|
+
}
|
|
21
|
+
/** Anything an adapter can import: raw text, binary data, or a file. */
|
|
22
|
+
type ImportInput = string | ArrayBuffer | ArrayBufferView | FileLike;
|
|
23
|
+
/** Helpers passed to adapters so they don't each re-implement decoding. */
|
|
24
|
+
interface ImportContext {
|
|
25
|
+
fileName?: string;
|
|
26
|
+
mimeType?: string;
|
|
27
|
+
target: ImportTarget;
|
|
28
|
+
/** Reads the input as UTF-8 text (a leading byte-order mark is removed). */
|
|
29
|
+
readText(): Promise<string>;
|
|
30
|
+
/** Reads the input as binary data (strings are UTF-8 encoded). */
|
|
31
|
+
readArrayBuffer(): Promise<ArrayBuffer>;
|
|
32
|
+
}
|
|
33
|
+
interface ImportAdapter<TResult = unknown> {
|
|
34
|
+
/** Unique id, e.g. `markdown`, `html`, `csv`. */
|
|
35
|
+
id: string;
|
|
36
|
+
/** Human-readable name for menus, e.g. "Markdown". */
|
|
37
|
+
label: string;
|
|
38
|
+
/** Accepted MIME types; `type/*` wildcards are allowed. */
|
|
39
|
+
mimeTypes: readonly string[];
|
|
40
|
+
/** Accepted extensions with a leading dot; multi-part ones (`.md.txt`) are allowed. */
|
|
41
|
+
extensions: readonly string[];
|
|
42
|
+
target: ImportTarget;
|
|
43
|
+
/** Tie-breaker between equally specific matches (default 0, higher wins). */
|
|
44
|
+
priority?: number;
|
|
45
|
+
import(input: ImportInput, context: ImportContext): Promise<TResult> | TResult;
|
|
46
|
+
}
|
|
47
|
+
interface FindImportAdapterQuery {
|
|
48
|
+
mimeType?: string;
|
|
49
|
+
fileName?: string;
|
|
50
|
+
/** Only consider adapters for this target. */
|
|
51
|
+
target?: ImportTarget;
|
|
52
|
+
}
|
|
53
|
+
interface ImportFileOptions {
|
|
54
|
+
/** Only consider adapters for this target. */
|
|
55
|
+
target?: ImportTarget;
|
|
56
|
+
/** Use this adapter instead of matching by type. */
|
|
57
|
+
adapterId?: string;
|
|
58
|
+
/** Overrides the input's own `name` (required to match string/binary input by extension). */
|
|
59
|
+
fileName?: string;
|
|
60
|
+
/** Overrides the input's own `type`. */
|
|
61
|
+
mimeType?: string;
|
|
62
|
+
}
|
|
63
|
+
interface ImportOutcome<TResult = unknown> {
|
|
64
|
+
adapterId: string;
|
|
65
|
+
target: ImportTarget;
|
|
66
|
+
fileName?: string;
|
|
67
|
+
mimeType?: string;
|
|
68
|
+
result: TResult;
|
|
69
|
+
}
|
|
70
|
+
type ImportErrorCode = "unsupported_type" | "unknown_adapter" | "adapter_failed";
|
|
71
|
+
declare class ImportError extends Error {
|
|
72
|
+
readonly code: ImportErrorCode;
|
|
73
|
+
readonly fileName?: string;
|
|
74
|
+
constructor(code: ImportErrorCode, message: string, details?: {
|
|
75
|
+
fileName?: string;
|
|
76
|
+
cause?: unknown;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
interface RegisterImportAdapterOptions {
|
|
80
|
+
/** Replace an adapter with the same id instead of throwing. */
|
|
81
|
+
replace?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/** Creates the {@link ImportContext} helpers for an input. */
|
|
84
|
+
declare function createImportContext(input: ImportInput, details: {
|
|
85
|
+
fileName?: string;
|
|
86
|
+
mimeType?: string;
|
|
87
|
+
target: ImportTarget;
|
|
88
|
+
}): ImportContext;
|
|
89
|
+
/**
|
|
90
|
+
* A set of import adapters with type matching. Use the default registry via
|
|
91
|
+
* the module-level helpers (`registerImportAdapter`, `importFile`, …) or
|
|
92
|
+
* create isolated ones with `createImportAdapterRegistry`.
|
|
93
|
+
*/
|
|
94
|
+
declare class ImportAdapterRegistry {
|
|
95
|
+
private adapters;
|
|
96
|
+
/** Registers an adapter and returns a function that unregisters it. */
|
|
97
|
+
register<TResult>(adapter: ImportAdapter<TResult>, options?: RegisterImportAdapterOptions): () => void;
|
|
98
|
+
/** Removes an adapter by id or instance. Returns whether it was registered. */
|
|
99
|
+
unregister(adapterOrId: string | ImportAdapter<any>): boolean;
|
|
100
|
+
get(id: string): ImportAdapter | undefined;
|
|
101
|
+
/** Registered adapters in registration order, optionally for one target. */
|
|
102
|
+
list(target?: ImportTarget): ImportAdapter[];
|
|
103
|
+
/**
|
|
104
|
+
* Finds the best adapter for a file. Extensions win over MIME types (browsers
|
|
105
|
+
* often report `""` or `text/plain` for markdown), the longest matching
|
|
106
|
+
* extension wins (`.md.txt` beats `.txt`), exact MIME types beat `type/*`
|
|
107
|
+
* wildcards, then higher `priority`, then the most recently registered.
|
|
108
|
+
*/
|
|
109
|
+
find(query: FindImportAdapterQuery): ImportAdapter | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Returns a value for `<input type="file" accept="…">` covering every
|
|
112
|
+
* registered extension and MIME type (optionally for one target).
|
|
113
|
+
*/
|
|
114
|
+
accept(target?: ImportTarget): string;
|
|
115
|
+
/** Whether some adapter (optionally for `target`) accepts this file. */
|
|
116
|
+
canImport(file: {
|
|
117
|
+
name?: string;
|
|
118
|
+
type?: string;
|
|
119
|
+
}, target?: ImportTarget): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Imports a file (or string / binary input) with the matching adapter.
|
|
122
|
+
* Rejects with an {@link ImportError} when no adapter matches or the
|
|
123
|
+
* adapter fails.
|
|
124
|
+
*/
|
|
125
|
+
importFile<TResult = unknown>(input: ImportInput, options?: ImportFileOptions): Promise<ImportOutcome<TResult>>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { type FileLike as F, ImportAdapterRegistry as I, type RegisterImportAdapterOptions as R, type ImportOutcome as a, type FindImportAdapterQuery as b, type ImportAdapter as c, type ImportContext as d, ImportError as e, type ImportErrorCode as f, type ImportFileOptions as g, type ImportInput as h, type ImportTarget as i, createImportContext as j };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import adapter registry: maps file types (MIME types and extensions) to
|
|
3
|
+
* converters that turn a file into editor content. Modelled on the desktop
|
|
4
|
+
* import pipelines of document apps, where each source format declares the
|
|
5
|
+
* MIME types and extensions it accepts.
|
|
6
|
+
*
|
|
7
|
+
* Built-in adapters cover markdown, HTML, plain text and RTF for the
|
|
8
|
+
* `document` target. Binary formats (DOCX, PDF, zipped exports) and other
|
|
9
|
+
* targets (e.g. CSV → `spreadsheet`) plug in with `registerImportAdapter`.
|
|
10
|
+
*/
|
|
11
|
+
/** What an import produces content for. Custom targets are plain strings. */
|
|
12
|
+
type ImportTarget = "document" | "spreadsheet" | (string & {});
|
|
13
|
+
/** A `File`/`Blob`-like object; only the members present are used. */
|
|
14
|
+
interface FileLike {
|
|
15
|
+
name?: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
size?: number;
|
|
18
|
+
text?(): Promise<string>;
|
|
19
|
+
arrayBuffer?(): Promise<ArrayBuffer>;
|
|
20
|
+
}
|
|
21
|
+
/** Anything an adapter can import: raw text, binary data, or a file. */
|
|
22
|
+
type ImportInput = string | ArrayBuffer | ArrayBufferView | FileLike;
|
|
23
|
+
/** Helpers passed to adapters so they don't each re-implement decoding. */
|
|
24
|
+
interface ImportContext {
|
|
25
|
+
fileName?: string;
|
|
26
|
+
mimeType?: string;
|
|
27
|
+
target: ImportTarget;
|
|
28
|
+
/** Reads the input as UTF-8 text (a leading byte-order mark is removed). */
|
|
29
|
+
readText(): Promise<string>;
|
|
30
|
+
/** Reads the input as binary data (strings are UTF-8 encoded). */
|
|
31
|
+
readArrayBuffer(): Promise<ArrayBuffer>;
|
|
32
|
+
}
|
|
33
|
+
interface ImportAdapter<TResult = unknown> {
|
|
34
|
+
/** Unique id, e.g. `markdown`, `html`, `csv`. */
|
|
35
|
+
id: string;
|
|
36
|
+
/** Human-readable name for menus, e.g. "Markdown". */
|
|
37
|
+
label: string;
|
|
38
|
+
/** Accepted MIME types; `type/*` wildcards are allowed. */
|
|
39
|
+
mimeTypes: readonly string[];
|
|
40
|
+
/** Accepted extensions with a leading dot; multi-part ones (`.md.txt`) are allowed. */
|
|
41
|
+
extensions: readonly string[];
|
|
42
|
+
target: ImportTarget;
|
|
43
|
+
/** Tie-breaker between equally specific matches (default 0, higher wins). */
|
|
44
|
+
priority?: number;
|
|
45
|
+
import(input: ImportInput, context: ImportContext): Promise<TResult> | TResult;
|
|
46
|
+
}
|
|
47
|
+
interface FindImportAdapterQuery {
|
|
48
|
+
mimeType?: string;
|
|
49
|
+
fileName?: string;
|
|
50
|
+
/** Only consider adapters for this target. */
|
|
51
|
+
target?: ImportTarget;
|
|
52
|
+
}
|
|
53
|
+
interface ImportFileOptions {
|
|
54
|
+
/** Only consider adapters for this target. */
|
|
55
|
+
target?: ImportTarget;
|
|
56
|
+
/** Use this adapter instead of matching by type. */
|
|
57
|
+
adapterId?: string;
|
|
58
|
+
/** Overrides the input's own `name` (required to match string/binary input by extension). */
|
|
59
|
+
fileName?: string;
|
|
60
|
+
/** Overrides the input's own `type`. */
|
|
61
|
+
mimeType?: string;
|
|
62
|
+
}
|
|
63
|
+
interface ImportOutcome<TResult = unknown> {
|
|
64
|
+
adapterId: string;
|
|
65
|
+
target: ImportTarget;
|
|
66
|
+
fileName?: string;
|
|
67
|
+
mimeType?: string;
|
|
68
|
+
result: TResult;
|
|
69
|
+
}
|
|
70
|
+
type ImportErrorCode = "unsupported_type" | "unknown_adapter" | "adapter_failed";
|
|
71
|
+
declare class ImportError extends Error {
|
|
72
|
+
readonly code: ImportErrorCode;
|
|
73
|
+
readonly fileName?: string;
|
|
74
|
+
constructor(code: ImportErrorCode, message: string, details?: {
|
|
75
|
+
fileName?: string;
|
|
76
|
+
cause?: unknown;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
interface RegisterImportAdapterOptions {
|
|
80
|
+
/** Replace an adapter with the same id instead of throwing. */
|
|
81
|
+
replace?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/** Creates the {@link ImportContext} helpers for an input. */
|
|
84
|
+
declare function createImportContext(input: ImportInput, details: {
|
|
85
|
+
fileName?: string;
|
|
86
|
+
mimeType?: string;
|
|
87
|
+
target: ImportTarget;
|
|
88
|
+
}): ImportContext;
|
|
89
|
+
/**
|
|
90
|
+
* A set of import adapters with type matching. Use the default registry via
|
|
91
|
+
* the module-level helpers (`registerImportAdapter`, `importFile`, …) or
|
|
92
|
+
* create isolated ones with `createImportAdapterRegistry`.
|
|
93
|
+
*/
|
|
94
|
+
declare class ImportAdapterRegistry {
|
|
95
|
+
private adapters;
|
|
96
|
+
/** Registers an adapter and returns a function that unregisters it. */
|
|
97
|
+
register<TResult>(adapter: ImportAdapter<TResult>, options?: RegisterImportAdapterOptions): () => void;
|
|
98
|
+
/** Removes an adapter by id or instance. Returns whether it was registered. */
|
|
99
|
+
unregister(adapterOrId: string | ImportAdapter<any>): boolean;
|
|
100
|
+
get(id: string): ImportAdapter | undefined;
|
|
101
|
+
/** Registered adapters in registration order, optionally for one target. */
|
|
102
|
+
list(target?: ImportTarget): ImportAdapter[];
|
|
103
|
+
/**
|
|
104
|
+
* Finds the best adapter for a file. Extensions win over MIME types (browsers
|
|
105
|
+
* often report `""` or `text/plain` for markdown), the longest matching
|
|
106
|
+
* extension wins (`.md.txt` beats `.txt`), exact MIME types beat `type/*`
|
|
107
|
+
* wildcards, then higher `priority`, then the most recently registered.
|
|
108
|
+
*/
|
|
109
|
+
find(query: FindImportAdapterQuery): ImportAdapter | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Returns a value for `<input type="file" accept="…">` covering every
|
|
112
|
+
* registered extension and MIME type (optionally for one target).
|
|
113
|
+
*/
|
|
114
|
+
accept(target?: ImportTarget): string;
|
|
115
|
+
/** Whether some adapter (optionally for `target`) accepts this file. */
|
|
116
|
+
canImport(file: {
|
|
117
|
+
name?: string;
|
|
118
|
+
type?: string;
|
|
119
|
+
}, target?: ImportTarget): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Imports a file (or string / binary input) with the matching adapter.
|
|
122
|
+
* Rejects with an {@link ImportError} when no adapter matches or the
|
|
123
|
+
* adapter fails.
|
|
124
|
+
*/
|
|
125
|
+
importFile<TResult = unknown>(input: ImportInput, options?: ImportFileOptions): Promise<ImportOutcome<TResult>>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { type FileLike as F, ImportAdapterRegistry as I, type RegisterImportAdapterOptions as R, type ImportOutcome as a, type FindImportAdapterQuery as b, type ImportAdapter as c, type ImportContext as d, ImportError as e, type ImportErrorCode as f, type ImportFileOptions as g, type ImportInput as h, type ImportTarget as i, createImportContext as j };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../chunk-JACER6TE.cjs');
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
var _chunkLA7PEGU3cjs = require('../chunk-LA7PEGU3.cjs');
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
var _chunkLLUAKTLWcjs = require('../chunk-LLUAKTLW.cjs');
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
@@ -27,9 +27,32 @@ var _chunkLLUAKTLWcjs = require('../chunk-LLUAKTLW.cjs');
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
var _chunkTVRC4KVTcjs = require('../chunk-TVRC4KVT.cjs');
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkTVRC4KVTcjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkTVRC4KVTcjs.MENTION_REGEX; exports.PIXERATE_DOCUMENT_MIME = _chunkLA7PEGU3cjs.PIXERATE_DOCUMENT_MIME; exports.escapeHtml = _chunkTVRC4KVTcjs.escapeHtml; exports.extractMentions = _chunkTVRC4KVTcjs.extractMentions; exports.extractMentionsFromDoc = _chunkTVRC4KVTcjs.extractMentionsFromDoc; exports.getClipboardData = _chunkLA7PEGU3cjs.getClipboardData; exports.getEditorMarkdown = _chunkTVRC4KVTcjs.getEditorMarkdown; exports.getEditorText = _chunkTVRC4KVTcjs.getEditorText; exports.getSchemaSignature = _chunkLA7PEGU3cjs.getSchemaSignature; exports.htmlToPlainText = _chunkTVRC4KVTcjs.htmlToPlainText; exports.markdownToTipTapHtml = _chunkTVRC4KVTcjs.markdownToTipTapHtml; exports.parseMentionSegments = _chunkTVRC4KVTcjs.parseMentionSegments; exports.parseRichClipboardPayload = _chunkLA7PEGU3cjs.parseRichClipboardPayload; exports.plainTextToParagraphHtml = _chunkLA7PEGU3cjs.plainTextToParagraphHtml; exports.plainTextToSlice = _chunkTVRC4KVTcjs.plainTextToSlice; exports.plainTextToTipTapHtml = _chunkTVRC4KVTcjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkTVRC4KVTcjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkTVRC4KVTcjs.preprocessMarkdownMentions; exports.readRichClipboard = _chunkLA7PEGU3cjs.readRichClipboard; exports.rtfToPlainText = _chunkLA7PEGU3cjs.rtfToPlainText; exports.sanitizeHtml = _chunkTVRC4KVTcjs.sanitizeHtml; exports.sanitizeImportedHtml = _chunkLA7PEGU3cjs.sanitizeImportedHtml; exports.serializeRichClipboardPayload = _chunkLA7PEGU3cjs.serializeRichClipboardPayload; exports.stripMarkdownCode = _chunkTVRC4KVTcjs.stripMarkdownCode;
|
|
35
58
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"],"names":[],"mappings":"AAAA,0GAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,gsDAAC","file":"/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"}
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { Schema, Slice } from '@tiptap/pm/model';
|
|
2
|
-
import {
|
|
2
|
+
import { r as TrackedChangesView, h as MentionEntity } from '../track-changes-G8JcWB8b.cjs';
|
|
3
3
|
import '@tiptap/core';
|
|
4
4
|
import '@tiptap/extension-mention';
|
|
5
5
|
import '@tiptap/suggestion';
|
|
6
|
+
import '@tiptap/pm/state';
|
|
6
7
|
|
|
8
|
+
interface PlainTextOptions {
|
|
9
|
+
/**
|
|
10
|
+
* How tracked changes (`TrackChanges` extension) appear in the text.
|
|
11
|
+
* Defaults to `"accepted"`: deleted text is dropped and inserted text kept,
|
|
12
|
+
* so suggested deletions never leak into exported text. `"original"` drops
|
|
13
|
+
* insertions and keeps deletions; `"all"` keeps both.
|
|
14
|
+
*/
|
|
15
|
+
trackedChanges?: TrackedChangesView;
|
|
16
|
+
}
|
|
7
17
|
/**
|
|
8
18
|
* Escapes characters that have syntactic meaning in HTML text.
|
|
9
19
|
*/
|
|
@@ -23,12 +33,13 @@ declare function plainTextToSlice(text: string, schema: Schema): Slice;
|
|
|
23
33
|
/**
|
|
24
34
|
* Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.
|
|
25
35
|
*/
|
|
26
|
-
declare function htmlToPlainText(html: string): string;
|
|
36
|
+
declare function htmlToPlainText(html: string, options?: PlainTextOptions): string;
|
|
27
37
|
/**
|
|
28
38
|
* Extracts plain text from a TipTap editor instance, preserving newline separators
|
|
29
|
-
* between block nodes and converting mention nodes to @label.
|
|
39
|
+
* between block nodes and converting mention nodes to @label. Tracked changes
|
|
40
|
+
* are rendered as accepted unless `options.trackedChanges` says otherwise.
|
|
30
41
|
*/
|
|
31
|
-
declare function getEditorText(editor: any): string;
|
|
42
|
+
declare function getEditorText(editor: any, options?: PlainTextOptions): string;
|
|
32
43
|
interface ExtractedMention {
|
|
33
44
|
id: string;
|
|
34
45
|
label: string;
|
|
@@ -101,6 +112,21 @@ declare function parseMentionSegments(content: string): MentionSegment[];
|
|
|
101
112
|
*/
|
|
102
113
|
declare function preprocessMarkdownMentions(content: string, optionsOrMentionables?: MentionEntity[] | PreprocessMarkdownMentionsOptions): string;
|
|
103
114
|
|
|
115
|
+
interface SanitizeHtmlOptions {
|
|
116
|
+
/**
|
|
117
|
+
* What to do with tags outside the allowlist: `escape` (default) renders
|
|
118
|
+
* them as literal text, `strip` removes the tag but keeps its text content.
|
|
119
|
+
*/
|
|
120
|
+
disallowedTags?: "escape" | "strip";
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Sanitizes raw HTML with the same allowlist the markdown renderer applies to
|
|
124
|
+
* embedded HTML: event handlers, `style` and unsafe URL schemes are dropped,
|
|
125
|
+
* and disallowed tags are escaped (or removed with `disallowedTags: "strip"`).
|
|
126
|
+
* It is string-based, so it works without a DOM and never runs handlers.
|
|
127
|
+
*/
|
|
128
|
+
declare function sanitizeHtml(html: string, options?: SanitizeHtmlOptions): string;
|
|
129
|
+
|
|
104
130
|
/**
|
|
105
131
|
* Preprocesses file-protocol and editor-protocol links in markdown content:
|
|
106
132
|
* converts [label](file://...), vscode://, and cursor:// links into anchor tags
|
|
@@ -141,7 +167,94 @@ declare function markdownToTipTapHtml(markdown: string, options?: MarkdownToHtml
|
|
|
141
167
|
* Extracts clean markdown from a TipTap editor instance.
|
|
142
168
|
* If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().
|
|
143
169
|
* Otherwise, it falls back to getEditorText(editor).
|
|
170
|
+
* Tracked changes are exported as accepted unless `options.trackedChanges`
|
|
171
|
+
* says otherwise (`"all"` renders deletions as `~~strikethrough~~`).
|
|
172
|
+
*/
|
|
173
|
+
declare function getEditorMarkdown(editor: any, options?: PlainTextOptions): string;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Sanitizes a full HTML document or fragment for insertion into the editor,
|
|
177
|
+
* e.g. an imported `.html` file or HTML from another application.
|
|
178
|
+
*
|
|
179
|
+
* - Keeps only the `<body>` content when the input is a full document.
|
|
180
|
+
* - Removes comments, doctype/XML declarations, CDATA, scripts, styles and
|
|
181
|
+
* other non-text elements together with their content.
|
|
182
|
+
* - Applies the same tag/attribute/URL allowlist as embedded HTML in markdown
|
|
183
|
+
* (see `sanitizeHtml`), but strips disallowed tags instead of escaping them,
|
|
184
|
+
* so wrappers such as `<section>` or `<font>` keep their text.
|
|
185
|
+
*
|
|
186
|
+
* It is string-based (no live DOM), so handlers such as `<img onerror>` never run.
|
|
187
|
+
*/
|
|
188
|
+
declare function sanitizeImportedHtml(html: string): string;
|
|
189
|
+
/**
|
|
190
|
+
* Converts untrusted plain text to TipTap paragraph HTML, always escaping it.
|
|
191
|
+
*
|
|
192
|
+
* Unlike `plainTextToTipTapHtml`, text that already looks like `<p>…</p>` is
|
|
193
|
+
* not passed through as HTML, which matters for imported files.
|
|
194
|
+
*/
|
|
195
|
+
declare function plainTextToParagraphHtml(text: string): string;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Best-effort plain-text extraction from an RTF document.
|
|
199
|
+
*
|
|
200
|
+
* Handles paragraphs/line breaks/tabs, escaped braces and backslashes,
|
|
201
|
+
* `\'hh` hex escapes (decoded as Windows-1252), `\uN` Unicode escapes with
|
|
202
|
+
* their `\ucN` fallback characters, common typographic control words, and
|
|
203
|
+
* skips metadata destinations (font/colour tables, `\info`, pictures, field
|
|
204
|
+
* instructions, `\*` destinations). Formatting (bold, lists, tables) is not
|
|
205
|
+
* preserved. Input that does not start with `{\rtf` is returned unchanged.
|
|
206
|
+
*/
|
|
207
|
+
declare function rtfToPlainText(rtf: string): string;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Custom clipboard MIME type for content copied from a @pixerate/editor
|
|
211
|
+
* rich-text editor. It carries the ProseMirror slice as JSON so pasting back
|
|
212
|
+
* into a compatible editor is lossless (no HTML round trip).
|
|
213
|
+
*/
|
|
214
|
+
declare const PIXERATE_DOCUMENT_MIME = "application/x.pixerate.document+json";
|
|
215
|
+
/** Payload written under {@link PIXERATE_DOCUMENT_MIME}. */
|
|
216
|
+
interface RichClipboardPayload {
|
|
217
|
+
version: 1;
|
|
218
|
+
/** {@link getSchemaSignature} of the source editor's schema. */
|
|
219
|
+
schema: string;
|
|
220
|
+
/** `Slice.toJSON()` of the copied selection. */
|
|
221
|
+
slice: {
|
|
222
|
+
content?: unknown[];
|
|
223
|
+
openStart?: number;
|
|
224
|
+
openEnd?: number;
|
|
225
|
+
} | null;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Returns a stable signature for a ProseMirror schema: node names, content
|
|
229
|
+
* expressions, groups, attribute names and mark names. Two editors with the
|
|
230
|
+
* same extensions produce the same signature, so a slice copied from one can
|
|
231
|
+
* be deserialized in the other without losing or rejecting nodes.
|
|
232
|
+
*/
|
|
233
|
+
declare function getSchemaSignature(schema: Schema): string;
|
|
234
|
+
/** Serializes a slice into the {@link PIXERATE_DOCUMENT_MIME} payload string. */
|
|
235
|
+
declare function serializeRichClipboardPayload(slice: Slice, schema: Schema): string;
|
|
236
|
+
/**
|
|
237
|
+
* Parses a {@link PIXERATE_DOCUMENT_MIME} payload into a slice for `schema`.
|
|
238
|
+
* Returns `null` (so callers fall back to HTML / plain text) when the payload
|
|
239
|
+
* is malformed, from another payload version, or from an editor whose schema
|
|
240
|
+
* signature differs.
|
|
241
|
+
*/
|
|
242
|
+
declare function parseRichClipboardPayload(data: string | null | undefined, schema: Schema): Slice | null;
|
|
243
|
+
/** Minimal clipboard data surface (`DataTransfer`). */
|
|
244
|
+
interface ClipboardDataLike {
|
|
245
|
+
getData(format: string): string;
|
|
246
|
+
setData(format: string, data: string): void;
|
|
247
|
+
clearData?(format?: string): void;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Returns the `clipboardData` of a native `ClipboardEvent` or of a React
|
|
251
|
+
* synthetic clipboard event (which wraps the native event in `nativeEvent`).
|
|
252
|
+
*/
|
|
253
|
+
declare function getClipboardData(event: unknown): ClipboardDataLike | null;
|
|
254
|
+
/**
|
|
255
|
+
* Reads a slice from a paste event's {@link PIXERATE_DOCUMENT_MIME} data.
|
|
256
|
+
* Returns `null` when the data is missing or its schema does not match.
|
|
144
257
|
*/
|
|
145
|
-
declare function
|
|
258
|
+
declare function readRichClipboard(event: unknown, schema: Schema, mimeType?: string): Slice | null;
|
|
146
259
|
|
|
147
|
-
export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };
|
|
260
|
+
export { type ClipboardDataLike, type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, PIXERATE_DOCUMENT_MIME, type PlainTextOptions, type PreprocessMarkdownMentionsOptions, type RichClipboardPayload, type SanitizeHtmlOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getClipboardData, getEditorMarkdown, getEditorText, getSchemaSignature, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, parseRichClipboardPayload, plainTextToParagraphHtml, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, readRichClipboard, rtfToPlainText, sanitizeHtml, sanitizeImportedHtml, serializeRichClipboardPayload, stripMarkdownCode };
|