{
  "version": 3,
  "sources": ["../../../../src/lib/utils/text/richText.ts"],
  "sourcesContent": ["import {\n\tExtension,\n\tExtensions,\n\textensions,\n\tgenerateHTML,\n\tgenerateJSON,\n\tgenerateText,\n\tJSONContent,\n} from '@tiptap/core'\nimport { Code } from '@tiptap/extension-code'\nimport { Highlight } from '@tiptap/extension-highlight'\nimport { Node } from '@tiptap/pm/model'\nimport { StarterKit, type StarterKitOptions } from '@tiptap/starter-kit'\nimport {\n\tEditor,\n\tgetOwnProperty,\n\tRichTextFontVisitorState,\n\tTLFontFace,\n\tTLRichText,\n\tWeakCache,\n} from '@tldraw/editor'\nimport { DefaultFontFaces } from '../../shapes/shared/defaultFonts'\n\n/** @public */\nexport const KeyboardShiftEnterTweakExtension = Extension.create({\n\tname: 'keyboardShiftEnterHandler',\n\taddKeyboardShortcuts() {\n\t\treturn {\n\t\t\t// We don't support soft breaks, so we just use the default enter command.\n\t\t\t'Shift-Enter': ({ editor }) => editor.commands.enter(),\n\t\t}\n\t},\n})\n\n// We change the default Code to override what's in the StarterKit.\n// It allows for other attributes/extensions.\n// @ts-ignore this is fine.\nCode.config.excludes = undefined\n\n// We want the highlighting to take precedence over bolding/italics/links\n// as far as rendering is concerned. Otherwise, the highlighting\n// looks broken up.\nHighlight.config.priority = 1100\n\n/**\n * Build tldraw's default TipTap extension set, optionally overriding the bundled `StarterKit`\n * options. The one lever most consumers want is turning individual nodes off (e.g. comments use a\n * headingless set via `getTipTapDefaultExtensions({ heading: false })`); because `StarterKit` is a\n * single umbrella extension, its sub-extensions can only be disabled through its config, not by\n * filtering the returned array.\n *\n * @public\n */\nexport function getTipTapDefaultExtensions(\n\tstarterKitOptions?: Partial<StarterKitOptions>\n): Extensions {\n\treturn [\n\t\tStarterKit.configure({\n\t\t\tblockquote: false,\n\t\t\tcodeBlock: false,\n\t\t\thorizontalRule: false,\n\t\t\tlink: {\n\t\t\t\topenOnClick: false,\n\t\t\t\tautolink: true,\n\t\t\t},\n\t\t\t// Prevent trailing paragraph insertion after lists (fixes #7641)\n\t\t\ttrailingNode: {\n\t\t\t\tnotAfter: ['paragraph', 'bulletList', 'orderedList', 'listItem'],\n\t\t\t},\n\t\t\t...starterKitOptions,\n\t\t}),\n\t\tHighlight,\n\t\tKeyboardShiftEnterTweakExtension,\n\n\t\t// N.B. We disable the text direction core extension in RichTextArea,\n\t\t// but we add it back in again here in our own extensions list so that\n\t\t// people can omit/override it if they want to.\n\t\textensions.TextDirection.configure({ direction: 'auto' }),\n\t]\n}\n\n/**\n * Default extensions for the TipTap editor.\n *\n * @public\n */\nexport const tipTapDefaultExtensions: Extensions = getTipTapDefaultExtensions()\n\n// todo: bust this if the editor changes, too\nconst htmlCache = new WeakCache<TLRichText, string>()\n\n/**\n * Renders HTML from a rich text string using an explicit set of TipTap extensions, rather than the\n * ones configured on an editor. Use this when rendering rich text outside of a shape's editor\n * config (e.g. comments, which render through their own headingless extension set).\n *\n * @param richText - The rich text content.\n * @param extensions - The TipTap extensions to render with.\n *\n * @public\n */\nexport function renderHtmlFromRichTextWithExtensions(\n\trichText: TLRichText,\n\textensions: Extensions\n): string {\n\tconst html = generateHTML(richText as JSONContent, extensions)\n\t// We replace empty paragraphs with a single line break to prevent the browser from collapsing\n\t// them. The paragraph's attributes are kept: paragraphs render with a `dir` attribute, usually\n\t// `auto` but `ltr` or `rtl` when the direction was set explicitly or parsed from pasted HTML.\n\treturn html.replace(/<p([^>]*)><\\/p>/g, '<p$1><br /></p>')\n}\n\n/**\n * Renders HTML from a rich text string.\n *\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderHtmlFromRichText(editor: Editor, richText: TLRichText) {\n\treturn htmlCache.get(richText, () => {\n\t\tconst tipTapExtensions =\n\t\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\t\treturn renderHtmlFromRichTextWithExtensions(richText, tipTapExtensions)\n\t})\n}\n\n/**\n * Renders HTML from a rich text string for measurement.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderHtmlFromRichTextForMeasurement(editor: Editor, richText: TLRichText) {\n\tconst html = renderHtmlFromRichText(editor, richText)\n\treturn `<div class=\"tl-rich-text\">${html}</div>`\n}\n\n// A weak cache used to store plaintext that's been extracted from rich text.\nconst plainTextFromRichTextCache = new WeakCache<TLRichText, string>()\n\nexport function isEmptyRichText(richText: TLRichText) {\n\t// An empty document has no text. It can be encoded several equally-valid ways:\n\t// an empty `content` array at the doc level, or a single paragraph whose own\n\t// `content` is missing or an empty array. The interactive editor emits the\n\t// single-paragraph / missing-`content` form; programmatic authoring (snapshot\n\t// loads, and agents/importers emitting tldraw JSON) commonly emits the\n\t// empty-array forms. Treat them all as empty.\n\tif (richText.content.length === 0) return true\n\tif (richText.content.length === 1) {\n\t\tconst node = richText.content[0] as any\n\t\tif (!node.content || node.content.length === 0) return true\n\t}\n\treturn false\n}\n\n/**\n * Whether the editor's active rich text selection is inside a bullet or ordered list.\n * @internal\n */\nexport function isEditingRichTextList(editor: Editor) {\n\tconst textEditor = editor.getRichTextEditor()\n\treturn !!(textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList'))\n}\n\n/**\n * Renders plaintext from a rich text string.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderPlaintextFromRichText(editor: Editor, richText: TLRichText) {\n\tif (isEmptyRichText(richText)) return ''\n\n\treturn plainTextFromRichTextCache.get(richText, () => {\n\t\tconst tipTapExtensions =\n\t\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\t\treturn generateText(richText as JSONContent, tipTapExtensions, {\n\t\t\tblockSeparator: '\\n',\n\t\t})\n\t})\n}\n\n/**\n * Renders JSONContent from html.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderRichTextFromHTML(editor: Editor, html: string): TLRichText {\n\tconst tipTapExtensions =\n\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\treturn generateJSON(html, tipTapExtensions) as TLRichText\n}\n\n/** @public */\nexport function defaultAddFontsFromNode(\n\tnode: Node,\n\tstate: RichTextFontVisitorState,\n\taddFont: (font: TLFontFace) => void\n) {\n\tfor (const mark of node.marks) {\n\t\tif (mark.type.name === 'bold' && state.weight !== 'bold') {\n\t\t\tstate = { ...state, weight: 'bold' }\n\t\t}\n\t\tif (mark.type.name === 'italic' && state.style !== 'italic') {\n\t\t\tstate = { ...state, style: 'italic' }\n\t\t}\n\t\tif (mark.type.name === 'code' && state.family !== 'tldraw_mono') {\n\t\t\tstate = { ...state, family: 'tldraw_mono' }\n\t\t}\n\t}\n\n\tconst fontsForFamily = getOwnProperty(DefaultFontFaces, state.family)\n\tif (!fontsForFamily) return state\n\n\tconst fontsForStyle = getOwnProperty(fontsForFamily, state.style)\n\tif (!fontsForStyle) return state\n\n\tconst fontsForWeight = getOwnProperty(fontsForStyle, state.weight)\n\tif (!fontsForWeight) return state\n\n\taddFont(fontsForWeight)\n\n\treturn state\n}\n"],
  "mappings": "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",
  "names": ["extensions"]
}
