@puzzle-ui/ui 0.3.0 → 0.4.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 +71 -70
- package/dist/components/data-display/empty-state/empty-state.css +128 -0
- package/dist/components/data-display/empty-state/empty-state.utils.cjs +6 -0
- package/dist/components/data-display/empty-state/empty-state.utils.cjs.map +1 -0
- package/dist/components/data-display/empty-state/empty-state.utils.js +6 -0
- package/dist/components/data-display/empty-state/empty-state.utils.js.map +1 -0
- package/dist/components/data-display/empty-state/index.cjs +49 -0
- package/dist/components/data-display/empty-state/index.cjs.map +1 -0
- package/dist/components/data-display/empty-state/index.d.cts +19 -0
- package/dist/components/data-display/empty-state/index.d.ts +19 -0
- package/dist/components/data-display/empty-state/index.js +44 -0
- package/dist/components/data-display/empty-state/index.js.map +1 -0
- package/dist/components/editors/text-editor/editor.cjs.map +1 -1
- package/dist/components/editors/text-editor/editor.js.map +1 -1
- package/dist/components/editors/text-editor/text-document.cjs.map +1 -1
- package/dist/components/editors/text-editor/text-document.js.map +1 -1
- package/dist/components/editors/text-editor/text-parser.cjs.map +1 -1
- package/dist/components/editors/text-editor/text-parser.js.map +1 -1
- package/dist/components/editors/text-editor/text-renderer.cjs.map +1 -1
- package/dist/components/editors/text-editor/text-renderer.js.map +1 -1
- package/dist/components/forms/autocomplete/index.cjs.map +1 -1
- package/dist/components/forms/autocomplete/index.js.map +1 -1
- package/dist/components/forms/color-picker/color-picker.css +351 -0
- package/dist/components/forms/color-picker/color-picker.types.d.cts +25 -0
- package/dist/components/forms/color-picker/color-picker.types.d.ts +25 -0
- package/dist/components/forms/color-picker/color-picker.utils.cjs +116 -0
- package/dist/components/forms/color-picker/color-picker.utils.cjs.map +1 -0
- package/dist/components/forms/color-picker/color-picker.utils.js +109 -0
- package/dist/components/forms/color-picker/color-picker.utils.js.map +1 -0
- package/dist/components/forms/color-picker/index.cjs +340 -0
- package/dist/components/forms/color-picker/index.cjs.map +1 -0
- package/dist/components/forms/color-picker/index.d.cts +3 -0
- package/dist/components/forms/color-picker/index.d.ts +3 -0
- package/dist/components/forms/color-picker/index.js +340 -0
- package/dist/components/forms/color-picker/index.js.map +1 -0
- package/dist/components/forms/file-upload/file-upload.utils.cjs.map +1 -1
- package/dist/components/forms/file-upload/file-upload.utils.js.map +1 -1
- package/dist/components/forms/input/number-input.js +5 -5
- package/dist/components/forms/input/number-input.js.map +1 -1
- package/dist/components/forms/input-group/index.d.cts +3 -0
- package/dist/components/forms/input-group/index.d.ts +3 -0
- package/dist/components/forms/input-group/input-group.cjs +18 -0
- package/dist/components/forms/input-group/input-group.cjs.map +1 -0
- package/dist/components/forms/input-group/input-group.css +62 -0
- package/dist/components/forms/input-group/input-group.d.cts +5 -0
- package/dist/components/forms/input-group/input-group.d.ts +5 -0
- package/dist/components/forms/input-group/input-group.js +18 -0
- package/dist/components/forms/input-group/input-group.js.map +1 -0
- package/dist/components/forms/input-group/input-group.types.d.cts +7 -0
- package/dist/components/forms/input-group/input-group.types.d.ts +7 -0
- package/dist/components/forms/input-group/input-group.utils.cjs +5 -0
- package/dist/components/forms/input-group/input-group.utils.cjs.map +1 -0
- package/dist/components/forms/input-group/input-group.utils.js +5 -0
- package/dist/components/forms/input-group/input-group.utils.js.map +1 -0
- package/dist/components/forms/select/index.cjs.map +1 -1
- package/dist/components/forms/select/index.js.map +1 -1
- package/dist/components/forms/slider/index.cjs +1 -1
- package/dist/components/forms/slider/index.cjs.map +1 -1
- package/dist/components/forms/slider/index.js +1 -1
- package/dist/components/forms/slider/index.js.map +1 -1
- package/dist/components/layout/resizable-panels/index.cjs +1 -1
- package/dist/components/layout/resizable-panels/index.cjs.map +1 -1
- package/dist/components/layout/resizable-panels/index.js +1 -1
- package/dist/components/layout/resizable-panels/index.js.map +1 -1
- package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -1
- package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -1
- package/dist/components/navigation/accordion/index.cjs.map +1 -1
- package/dist/components/navigation/accordion/index.js.map +1 -1
- package/dist/components/navigation/carousel/index.cjs +1 -1
- package/dist/components/navigation/carousel/index.cjs.map +1 -1
- package/dist/components/navigation/carousel/index.js +1 -1
- package/dist/components/navigation/carousel/index.js.map +1 -1
- package/dist/components/navigation/pagination/index.cjs +146 -0
- package/dist/components/navigation/pagination/index.cjs.map +1 -0
- package/dist/components/navigation/pagination/index.d.cts +3 -0
- package/dist/components/navigation/pagination/index.d.ts +3 -0
- package/dist/components/navigation/pagination/index.js +146 -0
- package/dist/components/navigation/pagination/index.js.map +1 -0
- package/dist/components/navigation/pagination/pagination.css +134 -0
- package/dist/components/navigation/pagination/pagination.types.d.cts +38 -0
- package/dist/components/navigation/pagination/pagination.types.d.ts +38 -0
- package/dist/components/navigation/pagination/pagination.utils.cjs +54 -0
- package/dist/components/navigation/pagination/pagination.utils.cjs.map +1 -0
- package/dist/components/navigation/pagination/pagination.utils.js +53 -0
- package/dist/components/navigation/pagination/pagination.utils.js.map +1 -0
- package/dist/components/navigation/tree-view/index.cjs.map +1 -1
- package/dist/components/navigation/tree-view/index.js.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.cjs.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.js.map +1 -1
- package/dist/components/utilities/preview/index.cjs +1 -1
- package/dist/components/utilities/preview/index.cjs.map +1 -1
- package/dist/components/utilities/preview/index.js +1 -1
- package/dist/components/utilities/preview/index.js.map +1 -1
- package/dist/index.cjs +110 -97
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +5 -1
- package/package.json +6 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-document.cjs","names":[],"sources":["../../../../src/components/editors/text-editor/text-document.ts"],"sourcesContent":["import type {\n TextBlock,\n TextDocument,\n TextInline,\n TextMark,\n TextPoint,\n TextSelection,\n TextBlockVariant,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\n\nconst HEADING_VARIANTS = new Set<TextBlockVariant>([\n \"display1\",\n \"display2\",\n \"headline1\",\n \"headline2\",\n \"headline3\",\n \"headline4\",\n]);\n\nconst MARK_ORDER: TextMark[] = [\"bold\", \"italic\", \"underline\", \"strike\"];\n\nexport const isHeadingVariant = (variant: TextBlockVariant): boolean =>\n HEADING_VARIANTS.has(variant);\n\nexport const createTextDocument = (text = \"\"): TextDocument => ({\n type: \"doc\",\n content: [\n {\n type: \"paragraph\",\n variant: \"body1\",\n children: text ? [{ text }] : [],\n },\n ],\n});\n\nexport const createTextSelection = (block = 0, offset = 0): TextSelection => ({\n anchor: { block, offset },\n focus: { block, offset },\n});\n\nexport const getBlockText = (block: TextBlock): string =>\n block.children.map((child) => child.text).join(\"\");\n\nexport const getBlockLength = (block: TextBlock): number =>\n block.children.reduce((length, child) => length + child.text.length, 0);\n\nexport const isCollapsedSelection = (selection: TextSelection): boolean =>\n selection.anchor.block === selection.focus.block &&\n selection.anchor.offset === selection.focus.offset;\n\nexport const getOrderedSelection = (\n selection: TextSelection,\n): { start: TextPoint; end: TextPoint } => {\n const { anchor, focus } = selection;\n if (\n anchor.block < focus.block ||\n (anchor.block === focus.block && anchor.offset <= focus.offset)\n ) {\n return { start: anchor, end: focus };\n }\n\n return { start: focus, end: anchor };\n};\n\nconst normalizeMarks = (marks: TextMark[] = []): TextMark[] =>\n MARK_ORDER.filter((mark) => marks.includes(mark));\n\nconst sameMarks = (left: TextMark[] = [], right: TextMark[] = []): boolean => {\n const a = normalizeMarks(left);\n const b = normalizeMarks(right);\n return a.length === b.length && a.every((mark, index) => mark === b[index]);\n};\n\nexport const normalizeInlines = (inlines: TextInline[]): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const inline of inlines) {\n if (!inline.text) continue;\n\n const marks = normalizeMarks(inline.marks);\n const previous = result[result.length - 1];\n\n if (previous && sameMarks(previous.marks, marks)) {\n previous.text += inline.text;\n continue;\n }\n\n result.push({\n text: inline.text,\n ...(marks.length ? { marks } : {}),\n });\n }\n\n return result;\n};\n\nconst isTextMark = (value: unknown): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst isTextVariant = (value: unknown): value is TextBlockVariant =>\n value === \"display1\" ||\n value === \"display2\" ||\n value === \"headline1\" ||\n value === \"headline2\" ||\n value === \"headline3\" ||\n value === \"headline4\" ||\n value === \"subtitle1\" ||\n value === \"subtitle2\" ||\n value === \"body1\" ||\n value === \"body2\" ||\n value === \"button\" ||\n value === \"caption\" ||\n value === \"overline\";\n\nexport const normalizeTextDocument = (input: TextDocument): TextDocument => {\n const content = Array.isArray(input?.content)\n ? input.content.flatMap((candidate) => {\n if (!candidate || !Array.isArray(candidate.children)) return [];\n\n const variant = isTextVariant(candidate.variant)\n ? candidate.variant\n : \"body1\";\n\n const children = normalizeInlines(\n candidate.children.flatMap((inline) => {\n if (!inline || typeof inline.text !== \"string\") return [];\n const marks = Array.isArray(inline.marks)\n ? inline.marks.filter(isTextMark)\n : [];\n return [{ text: inline.text, marks }];\n }),\n );\n\n const listType =\n candidate.listType === \"bullet\" || candidate.listType === \"ordered\"\n ? candidate.listType\n : undefined;\n const align =\n candidate.align === \"left\" ||\n candidate.align === \"center\" ||\n candidate.align === \"right\" ||\n candidate.align === \"justify\"\n ? (candidate.align as TextAlign)\n : undefined;\n\n const type = listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\";\n const headingLevel =\n type === \"heading\" &&\n Number.isInteger(candidate.headingLevel) &&\n candidate.headingLevel! >= 1 &&\n candidate.headingLevel! <= 6\n ? candidate.headingLevel\n : undefined;\n\n return [\n {\n type: listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n children,\n ...(listType ? { listType } : {}),\n ...(align ? { align } : {}),\n ...(headingLevel ? { headingLevel } : {}),\n } satisfies TextBlock,\n ];\n })\n : [];\n\n return {\n type: \"doc\",\n content: content.length\n ? content\n : [{ type: \"paragraph\", variant: \"body1\", children: [] }],\n };\n};\n\nconst sliceInlines = (\n inlines: TextInline[],\n from: number,\n to: number,\n): TextInline[] => {\n if (to <= from) return [];\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = position + inline.text.length;\n const overlapStart = Math.max(start, from);\n const overlapEnd = Math.min(end, to);\n\n if (overlapStart < overlapEnd) {\n result.push({\n text: inline.text.slice(overlapStart - start, overlapEnd - start),\n ...(inline.marks?.length ? { marks: [...inline.marks] } : {}),\n });\n }\n\n position = end;\n if (position >= to) break;\n }\n\n return normalizeInlines(result);\n};\n\nconst transformInlineRange = (\n inlines: TextInline[],\n from: number,\n to: number,\n transform: (marks: TextMark[]) => TextMark[],\n): TextInline[] => {\n if (to <= from) return inlines.map((inline) => ({ ...inline }));\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = start + inline.text.length;\n\n if (end <= from || start >= to) {\n result.push({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n });\n } else {\n const leftLength = Math.max(0, from - start);\n const rightStart = Math.max(0, to - start);\n const marks = inline.marks ?? [];\n\n if (leftLength > 0) {\n result.push({\n text: inline.text.slice(0, leftLength),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n\n const middleEnd = Math.min(inline.text.length, to - start);\n if (middleEnd > leftLength) {\n result.push({\n text: inline.text.slice(leftLength, middleEnd),\n marks: transform([...marks]),\n });\n }\n\n if (rightStart < inline.text.length) {\n result.push({\n text: inline.text.slice(Math.max(0, rightStart)),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n }\n\n position = end;\n }\n\n return normalizeInlines(result);\n};\n\nexport const applyMark = (\n document: TextDocument,\n selection: TextSelection,\n mark: TextMark,\n force?: boolean,\n): TextDocument => {\n if (isCollapsedSelection(selection)) return document;\n\n const { start, end } = getOrderedSelection(selection);\n const allMarked = document.content.every((block, index) => {\n if (index < start.block || index > end.block) return true;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return true;\n\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = position + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n if (!inline.marks?.includes(mark)) return false;\n }\n return true;\n });\n\n const addMark = force ?? !allMarked;\n const content = document.content.map((block, index) => {\n if (index < start.block || index > end.block) return block;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return block;\n\n return {\n ...block,\n children: transformInlineRange(block.children, from, to, (marks) => {\n const next = new Set(marks);\n if (addMark) next.add(mark);\n else next.delete(mark);\n return MARK_ORDER.filter((item) => next.has(item));\n }),\n };\n });\n\n return { type: \"doc\", content };\n};\n\nexport const setTextVariant = (\n document: TextDocument,\n selection: TextSelection,\n variant: TextBlockVariant,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return {\n ...block,\n type: block.listType\n ? \"listItem\"\n : isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n };\n }),\n };\n};\n\nconst inlineWithOffset = (\n inlines: TextInline[],\n offset: number,\n): { before: TextInline[]; after: TextInline[] } => ({\n before: sliceInlines(inlines, 0, offset),\n after: sliceInlines(\n inlines,\n offset,\n inlines.reduce((sum, item) => sum + item.text.length, 0),\n ),\n});\n\nexport const insertDocumentAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n insertedDocument: TextDocument,\n): { document: TextDocument; selection: TextSelection } => {\n const source = normalizeTextDocument(document);\n const inserted = normalizeTextDocument(insertedDocument);\n const { start, end } = getOrderedSelection(selection);\n const startIndex = Math.max(\n 0,\n Math.min(start.block, source.content.length - 1),\n );\n const endIndex = Math.max(\n startIndex,\n Math.min(end.block, source.content.length - 1),\n );\n const startBlock = source.content[startIndex];\n const endBlock = source.content[endIndex];\n const startOffset = Math.max(\n 0,\n Math.min(start.offset, getBlockLength(startBlock)),\n );\n const endOffset = Math.max(0, Math.min(end.offset, getBlockLength(endBlock)));\n const prefix = inlineWithOffset(startBlock.children, startOffset).before;\n const suffix = inlineWithOffset(endBlock.children, endOffset).after;\n const insertedBlocks = inserted.content.map((block) => ({\n ...block,\n children: block.children.map((inline) => ({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n })),\n }));\n\n const leftSurvives = prefix.length > 0 || startOffset > 0;\n const rightSurvives =\n suffix.length > 0 || endOffset < getBlockLength(endBlock);\n const first = insertedBlocks[0];\n const last = insertedBlocks[insertedBlocks.length - 1];\n const separatePrefix = leftSurvives && first.type === \"heading\";\n const separateSuffix = rightSurvives && last.type === \"heading\";\n const replacement: TextBlock[] = [];\n\n if (separatePrefix) {\n replacement.push({\n ...startBlock,\n children: prefix,\n });\n }\n\n if (insertedBlocks.length === 1) {\n if (separatePrefix || separateSuffix) {\n replacement.push({\n ...first,\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n if (separateSuffix) {\n replacement.push({ ...endBlock, children: suffix });\n } else {\n const finalIndex = replacement.length - 1;\n replacement[finalIndex] = {\n ...replacement[finalIndex],\n children: normalizeInlines([\n ...replacement[finalIndex].children,\n ...suffix,\n ]),\n };\n }\n } else {\n const useInsertedStyle = !leftSurvives && !rightSurvives;\n replacement.push({\n ...(useInsertedStyle ? first : startBlock),\n type: useInsertedStyle ? first.type : startBlock.type,\n variant: useInsertedStyle ? first.variant : startBlock.variant,\n children: normalizeInlines([...prefix, ...first.children, ...suffix]),\n });\n }\n } else {\n replacement.push({\n ...(separatePrefix || !leftSurvives ? first : startBlock),\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n\n for (let index = 1; index < insertedBlocks.length - 1; index += 1) {\n replacement.push(insertedBlocks[index]);\n }\n\n if (separateSuffix) {\n replacement.push(last);\n replacement.push({ ...endBlock, children: suffix });\n } else {\n replacement.push({\n ...(rightSurvives ? endBlock : last),\n type: rightSurvives ? endBlock.type : last.type,\n variant: rightSurvives ? endBlock.variant : last.variant,\n children: normalizeInlines([...last.children, ...suffix]),\n });\n }\n }\n\n const content = [\n ...source.content.slice(0, startIndex),\n ...replacement,\n ...source.content.slice(endIndex + 1),\n ];\n const caretReplacementIndex = separateSuffix\n ? replacement.length - 2\n : replacement.length - 1;\n const caretBlock = replacement[Math.max(0, caretReplacementIndex)];\n const suffixLength = suffix.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n const caretOffset = separateSuffix\n ? getBlockLength(caretBlock)\n : Math.max(0, getBlockLength(caretBlock) - suffixLength);\n const caret = {\n block: startIndex + Math.max(0, caretReplacementIndex),\n offset: caretOffset,\n };\n\n return {\n document: {\n type: \"doc\",\n content: content.length ? content : createTextDocument().content,\n },\n selection: { anchor: caret, focus: caret },\n };\n};\n\nexport const insertTextAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n text: string,\n marks: TextMark[] = [],\n): { document: TextDocument; selection: TextSelection } => {\n const inserted: TextDocument = {\n type: \"doc\",\n content: text.split(\"\\n\").map((line) => ({\n type: \"paragraph\",\n variant: \"body1\",\n children: line\n ? [{ text: line, ...(marks.length ? { marks: [...marks] } : {}) }]\n : [],\n })),\n };\n return insertDocumentAtSelection(document, selection, inserted);\n};\n\n/** Apply text alignment to every block touched by the current selection. */\nexport const setTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n align: TextAlign,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return { ...block, align };\n }),\n };\n};\n\nexport const getTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n): TextAlign | null => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n if (selected.length === 0) return null;\n const align = selected[0].align ?? null;\n return selected.every((block) => (block.align ?? null) === align)\n ? align\n : null;\n};\n\n/** Toggle a list type for the selected blocks; null removes list formatting. */\nexport const setListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType | null,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n const remove =\n listType != null &&\n selected.length > 0 &&\n selected.every((block) => block.listType === listType);\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n if (remove || listType == null) {\n const { listType: _listType, ...rest } = block;\n return {\n ...rest,\n type: block.type === \"listItem\" ? \"paragraph\" : block.type,\n };\n }\n return { ...block, type: \"listItem\", listType };\n }),\n };\n};\n\nexport const getListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType,\n): boolean => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n return (\n selected.length > 0 &&\n selected.every((block) => block.listType === listType)\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text-document.cjs","names":[],"sources":["../../../../src/components/editors/text-editor/text-document.ts"],"sourcesContent":["import type {\n TextBlock,\n TextDocument,\n TextInline,\n TextMark,\n TextPoint,\n TextSelection,\n TextBlockVariant,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\n\nconst HEADING_VARIANTS = new Set<TextBlockVariant>([\n \"display1\",\n \"display2\",\n \"headline1\",\n \"headline2\",\n \"headline3\",\n \"headline4\",\n]);\n\nconst MARK_ORDER: TextMark[] = [\"bold\", \"italic\", \"underline\", \"strike\"];\n\nexport const isHeadingVariant = (variant: TextBlockVariant): boolean =>\n HEADING_VARIANTS.has(variant);\n\nexport const createTextDocument = (text = \"\"): TextDocument => ({\n type: \"doc\",\n content: [\n {\n type: \"paragraph\",\n variant: \"body1\",\n children: text ? [{ text }] : [],\n },\n ],\n});\n\nexport const createTextSelection = (block = 0, offset = 0): TextSelection => ({\n anchor: { block, offset },\n focus: { block, offset },\n});\n\nexport const getBlockText = (block: TextBlock): string =>\n block.children.map((child) => child.text).join(\"\");\n\nexport const getBlockLength = (block: TextBlock): number =>\n block.children.reduce((length, child) => length + child.text.length, 0);\n\nexport const isCollapsedSelection = (selection: TextSelection): boolean =>\n selection.anchor.block === selection.focus.block &&\n selection.anchor.offset === selection.focus.offset;\n\nexport const getOrderedSelection = (\n selection: TextSelection,\n): { start: TextPoint; end: TextPoint } => {\n const { anchor, focus } = selection;\n if (\n anchor.block < focus.block ||\n (anchor.block === focus.block && anchor.offset <= focus.offset)\n ) {\n return { start: anchor, end: focus };\n }\n\n return { start: focus, end: anchor };\n};\n\nconst normalizeMarks = (marks: TextMark[] = []): TextMark[] =>\n MARK_ORDER.filter((mark) => marks.includes(mark));\n\nconst sameMarks = (left: TextMark[] = [], right: TextMark[] = []): boolean => {\n const a = normalizeMarks(left);\n const b = normalizeMarks(right);\n return a.length === b.length && a.every((mark, index) => mark === b[index]);\n};\n\nexport const normalizeInlines = (inlines: TextInline[]): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const inline of inlines) {\n if (!inline.text) continue;\n\n const marks = normalizeMarks(inline.marks);\n const previous = result[result.length - 1];\n\n if (previous && sameMarks(previous.marks, marks)) {\n previous.text += inline.text;\n continue;\n }\n\n result.push({\n text: inline.text,\n ...(marks.length ? { marks } : {}),\n });\n }\n\n return result;\n};\n\nconst isTextMark = (value: unknown): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst isTextVariant = (value: unknown): value is TextBlockVariant =>\n value === \"display1\" ||\n value === \"display2\" ||\n value === \"headline1\" ||\n value === \"headline2\" ||\n value === \"headline3\" ||\n value === \"headline4\" ||\n value === \"subtitle1\" ||\n value === \"subtitle2\" ||\n value === \"body1\" ||\n value === \"body2\" ||\n value === \"button\" ||\n value === \"caption\" ||\n value === \"overline\";\n\nexport const normalizeTextDocument = (input: TextDocument): TextDocument => {\n const content = Array.isArray(input?.content)\n ? input.content.flatMap((candidate) => {\n if (!candidate || !Array.isArray(candidate.children)) return [];\n\n const variant = isTextVariant(candidate.variant)\n ? candidate.variant\n : \"body1\";\n\n const children = normalizeInlines(\n candidate.children.flatMap((inline) => {\n if (!inline || typeof inline.text !== \"string\") return [];\n const marks = Array.isArray(inline.marks)\n ? inline.marks.filter(isTextMark)\n : [];\n return [{ text: inline.text, marks }];\n }),\n );\n\n const listType =\n candidate.listType === \"bullet\" || candidate.listType === \"ordered\"\n ? candidate.listType\n : undefined;\n const align =\n candidate.align === \"left\" ||\n candidate.align === \"center\" ||\n candidate.align === \"right\" ||\n candidate.align === \"justify\"\n ? (candidate.align as TextAlign)\n : undefined;\n\n const type = listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\";\n const headingLevel =\n type === \"heading\" &&\n Number.isInteger(candidate.headingLevel) &&\n candidate.headingLevel! >= 1 &&\n candidate.headingLevel! <= 6\n ? candidate.headingLevel\n : undefined;\n\n return [\n {\n type: listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n children,\n ...(listType ? { listType } : {}),\n ...(align ? { align } : {}),\n ...(headingLevel ? { headingLevel } : {}),\n } satisfies TextBlock,\n ];\n })\n : [];\n\n return {\n type: \"doc\",\n content: content.length\n ? content\n : [{ type: \"paragraph\", variant: \"body1\", children: [] }],\n };\n};\n\nconst sliceInlines = (\n inlines: TextInline[],\n from: number,\n to: number,\n): TextInline[] => {\n if (to <= from) return [];\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = position + inline.text.length;\n const overlapStart = Math.max(start, from);\n const overlapEnd = Math.min(end, to);\n\n if (overlapStart < overlapEnd) {\n result.push({\n text: inline.text.slice(overlapStart - start, overlapEnd - start),\n ...(inline.marks?.length ? { marks: [...inline.marks] } : {}),\n });\n }\n\n position = end;\n if (position >= to) break;\n }\n\n return normalizeInlines(result);\n};\n\nconst transformInlineRange = (\n inlines: TextInline[],\n from: number,\n to: number,\n transform: (marks: TextMark[]) => TextMark[],\n): TextInline[] => {\n if (to <= from) return inlines.map((inline) => ({ ...inline }));\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = start + inline.text.length;\n\n if (end <= from || start >= to) {\n result.push({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n });\n } else {\n const leftLength = Math.max(0, from - start);\n const rightStart = Math.max(0, to - start);\n const marks = inline.marks ?? [];\n\n if (leftLength > 0) {\n result.push({\n text: inline.text.slice(0, leftLength),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n\n const middleEnd = Math.min(inline.text.length, to - start);\n if (middleEnd > leftLength) {\n result.push({\n text: inline.text.slice(leftLength, middleEnd),\n marks: transform([...marks]),\n });\n }\n\n if (rightStart < inline.text.length) {\n result.push({\n text: inline.text.slice(Math.max(0, rightStart)),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n }\n\n position = end;\n }\n\n return normalizeInlines(result);\n};\n\nexport const applyMark = (\n document: TextDocument,\n selection: TextSelection,\n mark: TextMark,\n force?: boolean,\n): TextDocument => {\n if (isCollapsedSelection(selection)) return document;\n\n const { start, end } = getOrderedSelection(selection);\n const allMarked = document.content.every((block, index) => {\n if (index < start.block || index > end.block) return true;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return true;\n\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = position + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n if (!inline.marks?.includes(mark)) return false;\n }\n return true;\n });\n\n const addMark = force ?? !allMarked;\n const content = document.content.map((block, index) => {\n if (index < start.block || index > end.block) return block;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return block;\n\n return {\n ...block,\n children: transformInlineRange(block.children, from, to, (marks) => {\n const next = new Set(marks);\n if (addMark) next.add(mark);\n else next.delete(mark);\n return MARK_ORDER.filter((item) => next.has(item));\n }),\n };\n });\n\n return { type: \"doc\", content };\n};\n\nexport const setTextVariant = (\n document: TextDocument,\n selection: TextSelection,\n variant: TextBlockVariant,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return {\n ...block,\n type: block.listType\n ? \"listItem\"\n : isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n };\n }),\n };\n};\n\nconst inlineWithOffset = (\n inlines: TextInline[],\n offset: number,\n): { before: TextInline[]; after: TextInline[] } => ({\n before: sliceInlines(inlines, 0, offset),\n after: sliceInlines(\n inlines,\n offset,\n inlines.reduce((sum, item) => sum + item.text.length, 0),\n ),\n});\n\nexport const insertDocumentAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n insertedDocument: TextDocument,\n): { document: TextDocument; selection: TextSelection } => {\n const source = normalizeTextDocument(document);\n const inserted = normalizeTextDocument(insertedDocument);\n const { start, end } = getOrderedSelection(selection);\n const startIndex = Math.max(\n 0,\n Math.min(start.block, source.content.length - 1),\n );\n const endIndex = Math.max(\n startIndex,\n Math.min(end.block, source.content.length - 1),\n );\n const startBlock = source.content[startIndex]!;\n const endBlock = source.content[endIndex]!;\n const startOffset = Math.max(\n 0,\n Math.min(start.offset, getBlockLength(startBlock)),\n );\n const endOffset = Math.max(0, Math.min(end.offset, getBlockLength(endBlock)));\n const prefix = inlineWithOffset(startBlock.children, startOffset).before;\n const suffix = inlineWithOffset(endBlock.children, endOffset).after;\n const insertedBlocks = inserted.content.map((block) => ({\n ...block,\n children: block.children.map((inline) => ({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n })),\n }));\n\n const leftSurvives = prefix.length > 0 || startOffset > 0;\n const rightSurvives =\n suffix.length > 0 || endOffset < getBlockLength(endBlock);\n const first = insertedBlocks[0]!;\n const last = insertedBlocks[insertedBlocks.length - 1]!;\n const separatePrefix = leftSurvives && first.type === \"heading\";\n const separateSuffix = rightSurvives && last.type === \"heading\";\n const replacement: TextBlock[] = [];\n\n if (separatePrefix) {\n replacement.push({\n ...startBlock,\n children: prefix,\n });\n }\n\n if (insertedBlocks.length === 1) {\n if (separatePrefix || separateSuffix) {\n replacement.push({\n ...first,\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n if (separateSuffix) {\n replacement.push({ ...endBlock, children: suffix });\n } else {\n const finalIndex = replacement.length - 1;\n replacement[finalIndex] = {\n ...replacement[finalIndex]!,\n children: normalizeInlines([\n ...replacement[finalIndex]!.children,\n ...suffix,\n ]),\n };\n }\n } else {\n const useInsertedStyle = !leftSurvives && !rightSurvives;\n replacement.push({\n ...(useInsertedStyle ? first : startBlock),\n type: useInsertedStyle ? first.type : startBlock.type,\n variant: useInsertedStyle ? first.variant : startBlock.variant,\n children: normalizeInlines([...prefix, ...first.children, ...suffix]),\n });\n }\n } else {\n replacement.push({\n ...(separatePrefix || !leftSurvives ? first : startBlock),\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n\n for (let index = 1; index < insertedBlocks.length - 1; index += 1) {\n replacement.push(insertedBlocks[index]!);\n }\n\n if (separateSuffix) {\n replacement.push(last);\n replacement.push({ ...endBlock, children: suffix });\n } else {\n replacement.push({\n ...(rightSurvives ? endBlock : last),\n type: rightSurvives ? endBlock.type : last.type,\n variant: rightSurvives ? endBlock.variant : last.variant,\n children: normalizeInlines([...last.children, ...suffix]),\n });\n }\n }\n\n const content = [\n ...source.content.slice(0, startIndex),\n ...replacement,\n ...source.content.slice(endIndex + 1),\n ];\n const caretReplacementIndex = separateSuffix\n ? replacement.length - 2\n : replacement.length - 1;\n const caretBlock = replacement[Math.max(0, caretReplacementIndex)]!;\n const suffixLength = suffix.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n const caretOffset = separateSuffix\n ? getBlockLength(caretBlock)\n : Math.max(0, getBlockLength(caretBlock) - suffixLength);\n const caret = {\n block: startIndex + Math.max(0, caretReplacementIndex),\n offset: caretOffset,\n };\n\n return {\n document: {\n type: \"doc\",\n content: content.length ? content : createTextDocument().content,\n },\n selection: { anchor: caret, focus: caret },\n };\n};\n\nexport const insertTextAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n text: string,\n marks: TextMark[] = [],\n): { document: TextDocument; selection: TextSelection } => {\n const inserted: TextDocument = {\n type: \"doc\",\n content: text.split(\"\\n\").map((line) => ({\n type: \"paragraph\",\n variant: \"body1\",\n children: line\n ? [{ text: line, ...(marks.length ? { marks: [...marks] } : {}) }]\n : [],\n })),\n };\n return insertDocumentAtSelection(document, selection, inserted);\n};\n\n/** Apply text alignment to every block touched by the current selection. */\nexport const setTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n align: TextAlign,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return { ...block, align };\n }),\n };\n};\n\nexport const getTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n): TextAlign | null => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n if (selected.length === 0) return null;\n const align = selected[0]!.align ?? null;\n return selected.every((block) => (block.align ?? null) === align)\n ? align\n : null;\n};\n\n/** Toggle a list type for the selected blocks; null removes list formatting. */\nexport const setListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType | null,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n const remove =\n listType != null &&\n selected.length > 0 &&\n selected.every((block) => block.listType === listType);\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n if (remove || listType == null) {\n const { listType: _listType, ...rest } = block;\n return {\n ...rest,\n type: block.type === \"listItem\" ? \"paragraph\" : block.type,\n };\n }\n return { ...block, type: \"listItem\", listType };\n }),\n };\n};\n\nexport const getListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType,\n): boolean => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n return (\n selected.length > 0 &&\n selected.every((block) => block.listType === listType)\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-document.js","names":[],"sources":["../../../../src/components/editors/text-editor/text-document.ts"],"sourcesContent":["import type {\n TextBlock,\n TextDocument,\n TextInline,\n TextMark,\n TextPoint,\n TextSelection,\n TextBlockVariant,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\n\nconst HEADING_VARIANTS = new Set<TextBlockVariant>([\n \"display1\",\n \"display2\",\n \"headline1\",\n \"headline2\",\n \"headline3\",\n \"headline4\",\n]);\n\nconst MARK_ORDER: TextMark[] = [\"bold\", \"italic\", \"underline\", \"strike\"];\n\nexport const isHeadingVariant = (variant: TextBlockVariant): boolean =>\n HEADING_VARIANTS.has(variant);\n\nexport const createTextDocument = (text = \"\"): TextDocument => ({\n type: \"doc\",\n content: [\n {\n type: \"paragraph\",\n variant: \"body1\",\n children: text ? [{ text }] : [],\n },\n ],\n});\n\nexport const createTextSelection = (block = 0, offset = 0): TextSelection => ({\n anchor: { block, offset },\n focus: { block, offset },\n});\n\nexport const getBlockText = (block: TextBlock): string =>\n block.children.map((child) => child.text).join(\"\");\n\nexport const getBlockLength = (block: TextBlock): number =>\n block.children.reduce((length, child) => length + child.text.length, 0);\n\nexport const isCollapsedSelection = (selection: TextSelection): boolean =>\n selection.anchor.block === selection.focus.block &&\n selection.anchor.offset === selection.focus.offset;\n\nexport const getOrderedSelection = (\n selection: TextSelection,\n): { start: TextPoint; end: TextPoint } => {\n const { anchor, focus } = selection;\n if (\n anchor.block < focus.block ||\n (anchor.block === focus.block && anchor.offset <= focus.offset)\n ) {\n return { start: anchor, end: focus };\n }\n\n return { start: focus, end: anchor };\n};\n\nconst normalizeMarks = (marks: TextMark[] = []): TextMark[] =>\n MARK_ORDER.filter((mark) => marks.includes(mark));\n\nconst sameMarks = (left: TextMark[] = [], right: TextMark[] = []): boolean => {\n const a = normalizeMarks(left);\n const b = normalizeMarks(right);\n return a.length === b.length && a.every((mark, index) => mark === b[index]);\n};\n\nexport const normalizeInlines = (inlines: TextInline[]): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const inline of inlines) {\n if (!inline.text) continue;\n\n const marks = normalizeMarks(inline.marks);\n const previous = result[result.length - 1];\n\n if (previous && sameMarks(previous.marks, marks)) {\n previous.text += inline.text;\n continue;\n }\n\n result.push({\n text: inline.text,\n ...(marks.length ? { marks } : {}),\n });\n }\n\n return result;\n};\n\nconst isTextMark = (value: unknown): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst isTextVariant = (value: unknown): value is TextBlockVariant =>\n value === \"display1\" ||\n value === \"display2\" ||\n value === \"headline1\" ||\n value === \"headline2\" ||\n value === \"headline3\" ||\n value === \"headline4\" ||\n value === \"subtitle1\" ||\n value === \"subtitle2\" ||\n value === \"body1\" ||\n value === \"body2\" ||\n value === \"button\" ||\n value === \"caption\" ||\n value === \"overline\";\n\nexport const normalizeTextDocument = (input: TextDocument): TextDocument => {\n const content = Array.isArray(input?.content)\n ? input.content.flatMap((candidate) => {\n if (!candidate || !Array.isArray(candidate.children)) return [];\n\n const variant = isTextVariant(candidate.variant)\n ? candidate.variant\n : \"body1\";\n\n const children = normalizeInlines(\n candidate.children.flatMap((inline) => {\n if (!inline || typeof inline.text !== \"string\") return [];\n const marks = Array.isArray(inline.marks)\n ? inline.marks.filter(isTextMark)\n : [];\n return [{ text: inline.text, marks }];\n }),\n );\n\n const listType =\n candidate.listType === \"bullet\" || candidate.listType === \"ordered\"\n ? candidate.listType\n : undefined;\n const align =\n candidate.align === \"left\" ||\n candidate.align === \"center\" ||\n candidate.align === \"right\" ||\n candidate.align === \"justify\"\n ? (candidate.align as TextAlign)\n : undefined;\n\n const type = listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\";\n const headingLevel =\n type === \"heading\" &&\n Number.isInteger(candidate.headingLevel) &&\n candidate.headingLevel! >= 1 &&\n candidate.headingLevel! <= 6\n ? candidate.headingLevel\n : undefined;\n\n return [\n {\n type: listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n children,\n ...(listType ? { listType } : {}),\n ...(align ? { align } : {}),\n ...(headingLevel ? { headingLevel } : {}),\n } satisfies TextBlock,\n ];\n })\n : [];\n\n return {\n type: \"doc\",\n content: content.length\n ? content\n : [{ type: \"paragraph\", variant: \"body1\", children: [] }],\n };\n};\n\nconst sliceInlines = (\n inlines: TextInline[],\n from: number,\n to: number,\n): TextInline[] => {\n if (to <= from) return [];\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = position + inline.text.length;\n const overlapStart = Math.max(start, from);\n const overlapEnd = Math.min(end, to);\n\n if (overlapStart < overlapEnd) {\n result.push({\n text: inline.text.slice(overlapStart - start, overlapEnd - start),\n ...(inline.marks?.length ? { marks: [...inline.marks] } : {}),\n });\n }\n\n position = end;\n if (position >= to) break;\n }\n\n return normalizeInlines(result);\n};\n\nconst transformInlineRange = (\n inlines: TextInline[],\n from: number,\n to: number,\n transform: (marks: TextMark[]) => TextMark[],\n): TextInline[] => {\n if (to <= from) return inlines.map((inline) => ({ ...inline }));\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = start + inline.text.length;\n\n if (end <= from || start >= to) {\n result.push({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n });\n } else {\n const leftLength = Math.max(0, from - start);\n const rightStart = Math.max(0, to - start);\n const marks = inline.marks ?? [];\n\n if (leftLength > 0) {\n result.push({\n text: inline.text.slice(0, leftLength),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n\n const middleEnd = Math.min(inline.text.length, to - start);\n if (middleEnd > leftLength) {\n result.push({\n text: inline.text.slice(leftLength, middleEnd),\n marks: transform([...marks]),\n });\n }\n\n if (rightStart < inline.text.length) {\n result.push({\n text: inline.text.slice(Math.max(0, rightStart)),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n }\n\n position = end;\n }\n\n return normalizeInlines(result);\n};\n\nexport const applyMark = (\n document: TextDocument,\n selection: TextSelection,\n mark: TextMark,\n force?: boolean,\n): TextDocument => {\n if (isCollapsedSelection(selection)) return document;\n\n const { start, end } = getOrderedSelection(selection);\n const allMarked = document.content.every((block, index) => {\n if (index < start.block || index > end.block) return true;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return true;\n\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = position + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n if (!inline.marks?.includes(mark)) return false;\n }\n return true;\n });\n\n const addMark = force ?? !allMarked;\n const content = document.content.map((block, index) => {\n if (index < start.block || index > end.block) return block;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return block;\n\n return {\n ...block,\n children: transformInlineRange(block.children, from, to, (marks) => {\n const next = new Set(marks);\n if (addMark) next.add(mark);\n else next.delete(mark);\n return MARK_ORDER.filter((item) => next.has(item));\n }),\n };\n });\n\n return { type: \"doc\", content };\n};\n\nexport const setTextVariant = (\n document: TextDocument,\n selection: TextSelection,\n variant: TextBlockVariant,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return {\n ...block,\n type: block.listType\n ? \"listItem\"\n : isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n };\n }),\n };\n};\n\nconst inlineWithOffset = (\n inlines: TextInline[],\n offset: number,\n): { before: TextInline[]; after: TextInline[] } => ({\n before: sliceInlines(inlines, 0, offset),\n after: sliceInlines(\n inlines,\n offset,\n inlines.reduce((sum, item) => sum + item.text.length, 0),\n ),\n});\n\nexport const insertDocumentAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n insertedDocument: TextDocument,\n): { document: TextDocument; selection: TextSelection } => {\n const source = normalizeTextDocument(document);\n const inserted = normalizeTextDocument(insertedDocument);\n const { start, end } = getOrderedSelection(selection);\n const startIndex = Math.max(\n 0,\n Math.min(start.block, source.content.length - 1),\n );\n const endIndex = Math.max(\n startIndex,\n Math.min(end.block, source.content.length - 1),\n );\n const startBlock = source.content[startIndex];\n const endBlock = source.content[endIndex];\n const startOffset = Math.max(\n 0,\n Math.min(start.offset, getBlockLength(startBlock)),\n );\n const endOffset = Math.max(0, Math.min(end.offset, getBlockLength(endBlock)));\n const prefix = inlineWithOffset(startBlock.children, startOffset).before;\n const suffix = inlineWithOffset(endBlock.children, endOffset).after;\n const insertedBlocks = inserted.content.map((block) => ({\n ...block,\n children: block.children.map((inline) => ({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n })),\n }));\n\n const leftSurvives = prefix.length > 0 || startOffset > 0;\n const rightSurvives =\n suffix.length > 0 || endOffset < getBlockLength(endBlock);\n const first = insertedBlocks[0];\n const last = insertedBlocks[insertedBlocks.length - 1];\n const separatePrefix = leftSurvives && first.type === \"heading\";\n const separateSuffix = rightSurvives && last.type === \"heading\";\n const replacement: TextBlock[] = [];\n\n if (separatePrefix) {\n replacement.push({\n ...startBlock,\n children: prefix,\n });\n }\n\n if (insertedBlocks.length === 1) {\n if (separatePrefix || separateSuffix) {\n replacement.push({\n ...first,\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n if (separateSuffix) {\n replacement.push({ ...endBlock, children: suffix });\n } else {\n const finalIndex = replacement.length - 1;\n replacement[finalIndex] = {\n ...replacement[finalIndex],\n children: normalizeInlines([\n ...replacement[finalIndex].children,\n ...suffix,\n ]),\n };\n }\n } else {\n const useInsertedStyle = !leftSurvives && !rightSurvives;\n replacement.push({\n ...(useInsertedStyle ? first : startBlock),\n type: useInsertedStyle ? first.type : startBlock.type,\n variant: useInsertedStyle ? first.variant : startBlock.variant,\n children: normalizeInlines([...prefix, ...first.children, ...suffix]),\n });\n }\n } else {\n replacement.push({\n ...(separatePrefix || !leftSurvives ? first : startBlock),\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n\n for (let index = 1; index < insertedBlocks.length - 1; index += 1) {\n replacement.push(insertedBlocks[index]);\n }\n\n if (separateSuffix) {\n replacement.push(last);\n replacement.push({ ...endBlock, children: suffix });\n } else {\n replacement.push({\n ...(rightSurvives ? endBlock : last),\n type: rightSurvives ? endBlock.type : last.type,\n variant: rightSurvives ? endBlock.variant : last.variant,\n children: normalizeInlines([...last.children, ...suffix]),\n });\n }\n }\n\n const content = [\n ...source.content.slice(0, startIndex),\n ...replacement,\n ...source.content.slice(endIndex + 1),\n ];\n const caretReplacementIndex = separateSuffix\n ? replacement.length - 2\n : replacement.length - 1;\n const caretBlock = replacement[Math.max(0, caretReplacementIndex)];\n const suffixLength = suffix.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n const caretOffset = separateSuffix\n ? getBlockLength(caretBlock)\n : Math.max(0, getBlockLength(caretBlock) - suffixLength);\n const caret = {\n block: startIndex + Math.max(0, caretReplacementIndex),\n offset: caretOffset,\n };\n\n return {\n document: {\n type: \"doc\",\n content: content.length ? content : createTextDocument().content,\n },\n selection: { anchor: caret, focus: caret },\n };\n};\n\nexport const insertTextAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n text: string,\n marks: TextMark[] = [],\n): { document: TextDocument; selection: TextSelection } => {\n const inserted: TextDocument = {\n type: \"doc\",\n content: text.split(\"\\n\").map((line) => ({\n type: \"paragraph\",\n variant: \"body1\",\n children: line\n ? [{ text: line, ...(marks.length ? { marks: [...marks] } : {}) }]\n : [],\n })),\n };\n return insertDocumentAtSelection(document, selection, inserted);\n};\n\n/** Apply text alignment to every block touched by the current selection. */\nexport const setTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n align: TextAlign,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return { ...block, align };\n }),\n };\n};\n\nexport const getTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n): TextAlign | null => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n if (selected.length === 0) return null;\n const align = selected[0].align ?? null;\n return selected.every((block) => (block.align ?? null) === align)\n ? align\n : null;\n};\n\n/** Toggle a list type for the selected blocks; null removes list formatting. */\nexport const setListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType | null,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n const remove =\n listType != null &&\n selected.length > 0 &&\n selected.every((block) => block.listType === listType);\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n if (remove || listType == null) {\n const { listType: _listType, ...rest } = block;\n return {\n ...rest,\n type: block.type === \"listItem\" ? \"paragraph\" : block.type,\n };\n }\n return { ...block, type: \"listItem\", listType };\n }),\n };\n};\n\nexport const getListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType,\n): boolean => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n return (\n selected.length > 0 &&\n selected.every((block) => block.listType === listType)\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text-document.js","names":[],"sources":["../../../../src/components/editors/text-editor/text-document.ts"],"sourcesContent":["import type {\n TextBlock,\n TextDocument,\n TextInline,\n TextMark,\n TextPoint,\n TextSelection,\n TextBlockVariant,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\n\nconst HEADING_VARIANTS = new Set<TextBlockVariant>([\n \"display1\",\n \"display2\",\n \"headline1\",\n \"headline2\",\n \"headline3\",\n \"headline4\",\n]);\n\nconst MARK_ORDER: TextMark[] = [\"bold\", \"italic\", \"underline\", \"strike\"];\n\nexport const isHeadingVariant = (variant: TextBlockVariant): boolean =>\n HEADING_VARIANTS.has(variant);\n\nexport const createTextDocument = (text = \"\"): TextDocument => ({\n type: \"doc\",\n content: [\n {\n type: \"paragraph\",\n variant: \"body1\",\n children: text ? [{ text }] : [],\n },\n ],\n});\n\nexport const createTextSelection = (block = 0, offset = 0): TextSelection => ({\n anchor: { block, offset },\n focus: { block, offset },\n});\n\nexport const getBlockText = (block: TextBlock): string =>\n block.children.map((child) => child.text).join(\"\");\n\nexport const getBlockLength = (block: TextBlock): number =>\n block.children.reduce((length, child) => length + child.text.length, 0);\n\nexport const isCollapsedSelection = (selection: TextSelection): boolean =>\n selection.anchor.block === selection.focus.block &&\n selection.anchor.offset === selection.focus.offset;\n\nexport const getOrderedSelection = (\n selection: TextSelection,\n): { start: TextPoint; end: TextPoint } => {\n const { anchor, focus } = selection;\n if (\n anchor.block < focus.block ||\n (anchor.block === focus.block && anchor.offset <= focus.offset)\n ) {\n return { start: anchor, end: focus };\n }\n\n return { start: focus, end: anchor };\n};\n\nconst normalizeMarks = (marks: TextMark[] = []): TextMark[] =>\n MARK_ORDER.filter((mark) => marks.includes(mark));\n\nconst sameMarks = (left: TextMark[] = [], right: TextMark[] = []): boolean => {\n const a = normalizeMarks(left);\n const b = normalizeMarks(right);\n return a.length === b.length && a.every((mark, index) => mark === b[index]);\n};\n\nexport const normalizeInlines = (inlines: TextInline[]): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const inline of inlines) {\n if (!inline.text) continue;\n\n const marks = normalizeMarks(inline.marks);\n const previous = result[result.length - 1];\n\n if (previous && sameMarks(previous.marks, marks)) {\n previous.text += inline.text;\n continue;\n }\n\n result.push({\n text: inline.text,\n ...(marks.length ? { marks } : {}),\n });\n }\n\n return result;\n};\n\nconst isTextMark = (value: unknown): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst isTextVariant = (value: unknown): value is TextBlockVariant =>\n value === \"display1\" ||\n value === \"display2\" ||\n value === \"headline1\" ||\n value === \"headline2\" ||\n value === \"headline3\" ||\n value === \"headline4\" ||\n value === \"subtitle1\" ||\n value === \"subtitle2\" ||\n value === \"body1\" ||\n value === \"body2\" ||\n value === \"button\" ||\n value === \"caption\" ||\n value === \"overline\";\n\nexport const normalizeTextDocument = (input: TextDocument): TextDocument => {\n const content = Array.isArray(input?.content)\n ? input.content.flatMap((candidate) => {\n if (!candidate || !Array.isArray(candidate.children)) return [];\n\n const variant = isTextVariant(candidate.variant)\n ? candidate.variant\n : \"body1\";\n\n const children = normalizeInlines(\n candidate.children.flatMap((inline) => {\n if (!inline || typeof inline.text !== \"string\") return [];\n const marks = Array.isArray(inline.marks)\n ? inline.marks.filter(isTextMark)\n : [];\n return [{ text: inline.text, marks }];\n }),\n );\n\n const listType =\n candidate.listType === \"bullet\" || candidate.listType === \"ordered\"\n ? candidate.listType\n : undefined;\n const align =\n candidate.align === \"left\" ||\n candidate.align === \"center\" ||\n candidate.align === \"right\" ||\n candidate.align === \"justify\"\n ? (candidate.align as TextAlign)\n : undefined;\n\n const type = listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\";\n const headingLevel =\n type === \"heading\" &&\n Number.isInteger(candidate.headingLevel) &&\n candidate.headingLevel! >= 1 &&\n candidate.headingLevel! <= 6\n ? candidate.headingLevel\n : undefined;\n\n return [\n {\n type: listType\n ? \"listItem\"\n : candidate.type === \"heading\" && isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n children,\n ...(listType ? { listType } : {}),\n ...(align ? { align } : {}),\n ...(headingLevel ? { headingLevel } : {}),\n } satisfies TextBlock,\n ];\n })\n : [];\n\n return {\n type: \"doc\",\n content: content.length\n ? content\n : [{ type: \"paragraph\", variant: \"body1\", children: [] }],\n };\n};\n\nconst sliceInlines = (\n inlines: TextInline[],\n from: number,\n to: number,\n): TextInline[] => {\n if (to <= from) return [];\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = position + inline.text.length;\n const overlapStart = Math.max(start, from);\n const overlapEnd = Math.min(end, to);\n\n if (overlapStart < overlapEnd) {\n result.push({\n text: inline.text.slice(overlapStart - start, overlapEnd - start),\n ...(inline.marks?.length ? { marks: [...inline.marks] } : {}),\n });\n }\n\n position = end;\n if (position >= to) break;\n }\n\n return normalizeInlines(result);\n};\n\nconst transformInlineRange = (\n inlines: TextInline[],\n from: number,\n to: number,\n transform: (marks: TextMark[]) => TextMark[],\n): TextInline[] => {\n if (to <= from) return inlines.map((inline) => ({ ...inline }));\n\n const result: TextInline[] = [];\n let position = 0;\n\n for (const inline of inlines) {\n const start = position;\n const end = start + inline.text.length;\n\n if (end <= from || start >= to) {\n result.push({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n });\n } else {\n const leftLength = Math.max(0, from - start);\n const rightStart = Math.max(0, to - start);\n const marks = inline.marks ?? [];\n\n if (leftLength > 0) {\n result.push({\n text: inline.text.slice(0, leftLength),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n\n const middleEnd = Math.min(inline.text.length, to - start);\n if (middleEnd > leftLength) {\n result.push({\n text: inline.text.slice(leftLength, middleEnd),\n marks: transform([...marks]),\n });\n }\n\n if (rightStart < inline.text.length) {\n result.push({\n text: inline.text.slice(Math.max(0, rightStart)),\n ...(marks.length ? { marks: [...marks] } : {}),\n });\n }\n }\n\n position = end;\n }\n\n return normalizeInlines(result);\n};\n\nexport const applyMark = (\n document: TextDocument,\n selection: TextSelection,\n mark: TextMark,\n force?: boolean,\n): TextDocument => {\n if (isCollapsedSelection(selection)) return document;\n\n const { start, end } = getOrderedSelection(selection);\n const allMarked = document.content.every((block, index) => {\n if (index < start.block || index > end.block) return true;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return true;\n\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = position + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n if (!inline.marks?.includes(mark)) return false;\n }\n return true;\n });\n\n const addMark = force ?? !allMarked;\n const content = document.content.map((block, index) => {\n if (index < start.block || index > end.block) return block;\n const from = index === start.block ? start.offset : 0;\n const to = index === end.block ? end.offset : getBlockLength(block);\n if (to <= from) return block;\n\n return {\n ...block,\n children: transformInlineRange(block.children, from, to, (marks) => {\n const next = new Set(marks);\n if (addMark) next.add(mark);\n else next.delete(mark);\n return MARK_ORDER.filter((item) => next.has(item));\n }),\n };\n });\n\n return { type: \"doc\", content };\n};\n\nexport const setTextVariant = (\n document: TextDocument,\n selection: TextSelection,\n variant: TextBlockVariant,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return {\n ...block,\n type: block.listType\n ? \"listItem\"\n : isHeadingVariant(variant)\n ? \"heading\"\n : \"paragraph\",\n variant,\n };\n }),\n };\n};\n\nconst inlineWithOffset = (\n inlines: TextInline[],\n offset: number,\n): { before: TextInline[]; after: TextInline[] } => ({\n before: sliceInlines(inlines, 0, offset),\n after: sliceInlines(\n inlines,\n offset,\n inlines.reduce((sum, item) => sum + item.text.length, 0),\n ),\n});\n\nexport const insertDocumentAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n insertedDocument: TextDocument,\n): { document: TextDocument; selection: TextSelection } => {\n const source = normalizeTextDocument(document);\n const inserted = normalizeTextDocument(insertedDocument);\n const { start, end } = getOrderedSelection(selection);\n const startIndex = Math.max(\n 0,\n Math.min(start.block, source.content.length - 1),\n );\n const endIndex = Math.max(\n startIndex,\n Math.min(end.block, source.content.length - 1),\n );\n const startBlock = source.content[startIndex]!;\n const endBlock = source.content[endIndex]!;\n const startOffset = Math.max(\n 0,\n Math.min(start.offset, getBlockLength(startBlock)),\n );\n const endOffset = Math.max(0, Math.min(end.offset, getBlockLength(endBlock)));\n const prefix = inlineWithOffset(startBlock.children, startOffset).before;\n const suffix = inlineWithOffset(endBlock.children, endOffset).after;\n const insertedBlocks = inserted.content.map((block) => ({\n ...block,\n children: block.children.map((inline) => ({\n ...inline,\n ...(inline.marks ? { marks: [...inline.marks] } : {}),\n })),\n }));\n\n const leftSurvives = prefix.length > 0 || startOffset > 0;\n const rightSurvives =\n suffix.length > 0 || endOffset < getBlockLength(endBlock);\n const first = insertedBlocks[0]!;\n const last = insertedBlocks[insertedBlocks.length - 1]!;\n const separatePrefix = leftSurvives && first.type === \"heading\";\n const separateSuffix = rightSurvives && last.type === \"heading\";\n const replacement: TextBlock[] = [];\n\n if (separatePrefix) {\n replacement.push({\n ...startBlock,\n children: prefix,\n });\n }\n\n if (insertedBlocks.length === 1) {\n if (separatePrefix || separateSuffix) {\n replacement.push({\n ...first,\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n if (separateSuffix) {\n replacement.push({ ...endBlock, children: suffix });\n } else {\n const finalIndex = replacement.length - 1;\n replacement[finalIndex] = {\n ...replacement[finalIndex]!,\n children: normalizeInlines([\n ...replacement[finalIndex]!.children,\n ...suffix,\n ]),\n };\n }\n } else {\n const useInsertedStyle = !leftSurvives && !rightSurvives;\n replacement.push({\n ...(useInsertedStyle ? first : startBlock),\n type: useInsertedStyle ? first.type : startBlock.type,\n variant: useInsertedStyle ? first.variant : startBlock.variant,\n children: normalizeInlines([...prefix, ...first.children, ...suffix]),\n });\n }\n } else {\n replacement.push({\n ...(separatePrefix || !leftSurvives ? first : startBlock),\n type: separatePrefix || !leftSurvives ? first.type : startBlock.type,\n variant:\n separatePrefix || !leftSurvives ? first.variant : startBlock.variant,\n children: separatePrefix\n ? first.children\n : normalizeInlines([...prefix, ...first.children]),\n });\n\n for (let index = 1; index < insertedBlocks.length - 1; index += 1) {\n replacement.push(insertedBlocks[index]!);\n }\n\n if (separateSuffix) {\n replacement.push(last);\n replacement.push({ ...endBlock, children: suffix });\n } else {\n replacement.push({\n ...(rightSurvives ? endBlock : last),\n type: rightSurvives ? endBlock.type : last.type,\n variant: rightSurvives ? endBlock.variant : last.variant,\n children: normalizeInlines([...last.children, ...suffix]),\n });\n }\n }\n\n const content = [\n ...source.content.slice(0, startIndex),\n ...replacement,\n ...source.content.slice(endIndex + 1),\n ];\n const caretReplacementIndex = separateSuffix\n ? replacement.length - 2\n : replacement.length - 1;\n const caretBlock = replacement[Math.max(0, caretReplacementIndex)]!;\n const suffixLength = suffix.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n const caretOffset = separateSuffix\n ? getBlockLength(caretBlock)\n : Math.max(0, getBlockLength(caretBlock) - suffixLength);\n const caret = {\n block: startIndex + Math.max(0, caretReplacementIndex),\n offset: caretOffset,\n };\n\n return {\n document: {\n type: \"doc\",\n content: content.length ? content : createTextDocument().content,\n },\n selection: { anchor: caret, focus: caret },\n };\n};\n\nexport const insertTextAtSelection = (\n document: TextDocument,\n selection: TextSelection,\n text: string,\n marks: TextMark[] = [],\n): { document: TextDocument; selection: TextSelection } => {\n const inserted: TextDocument = {\n type: \"doc\",\n content: text.split(\"\\n\").map((line) => ({\n type: \"paragraph\",\n variant: \"body1\",\n children: line\n ? [{ text: line, ...(marks.length ? { marks: [...marks] } : {}) }]\n : [],\n })),\n };\n return insertDocumentAtSelection(document, selection, inserted);\n};\n\n/** Apply text alignment to every block touched by the current selection. */\nexport const setTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n align: TextAlign,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n return { ...block, align };\n }),\n };\n};\n\nexport const getTextAlign = (\n document: TextDocument,\n selection: TextSelection,\n): TextAlign | null => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n if (selected.length === 0) return null;\n const align = selected[0]!.align ?? null;\n return selected.every((block) => (block.align ?? null) === align)\n ? align\n : null;\n};\n\n/** Toggle a list type for the selected blocks; null removes list formatting. */\nexport const setListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType | null,\n): TextDocument => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n const remove =\n listType != null &&\n selected.length > 0 &&\n selected.every((block) => block.listType === listType);\n return {\n type: \"doc\",\n content: document.content.map((block, index) => {\n if (index < start.block || index > lastBlock) return block;\n if (remove || listType == null) {\n const { listType: _listType, ...rest } = block;\n return {\n ...rest,\n type: block.type === \"listItem\" ? \"paragraph\" : block.type,\n };\n }\n return { ...block, type: \"listItem\", listType };\n }),\n };\n};\n\nexport const getListType = (\n document: TextDocument,\n selection: TextSelection,\n listType: TextListType,\n): boolean => {\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const selected = document.content.slice(start.block, lastBlock + 1);\n return (\n selected.length > 0 &&\n selected.every((block) => block.listType === listType)\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-parser.cjs","names":["normalizeInlines","isHeadingVariant","createTextDocument","normalizeTextDocument"],"sources":["../../../../src/components/editors/text-editor/text-parser.ts"],"sourcesContent":["import { createTextDocument, isHeadingVariant, normalizeInlines, normalizeTextDocument } from \"./text-document\";\nimport type { TextBlock, TextDocument, TextInline, TextMark, TextBlockVariant, TextAlign, TextListType } from \"./text-editor.types\";\n\nconst VARIANTS = new Set<TextBlockVariant>([\n \"display1\", \"display2\", \"headline1\", \"headline2\", \"headline3\", \"headline4\",\n \"subtitle1\", \"subtitle2\", \"body1\", \"body2\", \"button\", \"caption\", \"overline\",\n]);\n\nconst MARK_TAGS: Record<string, TextMark> = {\n b: \"bold\",\n strong: \"bold\",\n i: \"italic\",\n em: \"italic\",\n u: \"underline\",\n s: \"strike\",\n strike: \"strike\",\n del: \"strike\",\n};\n\nconst HEADING_VARIANTS: Record<string, TextBlockVariant> = {\n h1: \"headline1\",\n h2: \"headline2\",\n h3: \"headline3\",\n h4: \"headline4\",\n};\n\nconst appendText = (target: TextInline[], text: string, marks: TextMark[]) => {\n if (!text) return;\n target.push({ text, ...(marks.length ? { marks: [...marks] } : {}) });\n};\n\nconst readInlineNodes = (\n nodes: NodeListOf<ChildNode> | ChildNode[],\n inheritedMarks: TextMark[] = [],\n): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const node of Array.from(nodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n appendText(result, node.textContent ?? \"\", inheritedMarks);\n continue;\n }\n\n if (!(node instanceof Element)) continue;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) continue;\n\n if (tag === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n appendText(result, \"\\n\", inheritedMarks);\n }\n continue;\n }\n\n if (\n node.children.length === 1 &&\n node.firstElementChild?.tagName.toLowerCase() === \"br\" &&\n node.textContent === \"\"\n ) {\n // Browsers often represent an empty contenteditable block as <p><br></p>.\n continue;\n }\n\n const mark = MARK_TAGS[tag];\n const nextMarks = mark\n ? Array.from(new Set([...inheritedMarks, mark]))\n : inheritedMarks;\n\n // Unsupported elements are transparent: keep their readable children but\n // deliberately discard their styling, attributes and behavior.\n result.push(...readInlineNodes(Array.from(node.childNodes), nextMarks));\n }\n\n return normalizeInlines(result);\n};\n\nconst createBlock = (\n variant: TextBlockVariant,\n children: TextInline[],\n forceHeading?: boolean,\n align?: TextAlign,\n listType?: TextListType,\n): TextBlock => ({\n type: listType ? \"listItem\" : forceHeading || isHeadingVariant(variant) ? \"heading\" : \"paragraph\",\n variant,\n children: normalizeInlines(children),\n ...(align ? { align } : {}),\n ...(listType ? { listType } : {}),\n});\n\nconst getBlockAlign = (element: Element): TextAlign | undefined => {\n const align =\n element.getAttribute(\"data-puzzle-align\") ??\n (element as HTMLElement).style.textAlign;\n return align === \"left\" || align === \"center\" || align === \"right\" || align === \"justify\"\n ? align\n : undefined;\n};\n\nconst getBlockVariant = (element: Element): TextBlockVariant | undefined => {\n const provided = element.getAttribute(\"data-puzzle-variant\");\n if (provided && VARIANTS.has(provided as TextBlockVariant)) {\n return provided as TextBlockVariant;\n }\n\n return HEADING_VARIANTS[element.tagName.toLowerCase()];\n};\n\nconst containsBlockChild = (element: Element): boolean =>\n Array.from(element.children).some((child) =>\n [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\", \"ul\", \"ol\", \"li\"].includes(\n child.tagName.toLowerCase(),\n ),\n );\n\nconst readHtmlBlocks = (nodes: NodeListOf<ChildNode> | ChildNode[]): TextBlock[] => {\n const blocks: TextBlock[] = [];\n let looseInlines: TextInline[] = [];\n\n const flushLoose = () => {\n if (!looseInlines.length) return;\n blocks.push(createBlock(\"body1\", looseInlines));\n looseInlines = [];\n };\n\n const visit = (node: ChildNode) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent ?? \"\";\n if (looseInlines.length === 0 && !text.trim()) return;\n appendText(looseInlines, text, []);\n return;\n }\n\n if (!(node instanceof Element)) return;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) return;\n const isKnownBlock = [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\"].includes(tag);\n\n if (isKnownBlock && containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (isKnownBlock) {\n flushLoose();\n const variant = getBlockVariant(node) ?? \"body1\";\n const forceHeading = Boolean(HEADING_VARIANTS[tag]);\n const dataListType = node.getAttribute(\"data-puzzle-list-type\");\n const listType: TextListType | undefined = dataListType === \"bullet\" || dataListType === \"ordered\" ? dataListType : undefined;\n blocks.push(createBlock(variant, readInlineNodes(Array.from(node.childNodes)), forceHeading, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"li\") {\n flushLoose();\n const parentTag = node.parentElement?.tagName.toLowerCase();\n const listType: TextListType | undefined = parentTag === \"ul\" ? \"bullet\" : parentTag === \"ol\" ? \"ordered\" : undefined;\n blocks.push(createBlock(\"body1\", readInlineNodes(Array.from(node.childNodes)), false, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"ul\" || tag === \"ol\") {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (tag === \"br\") {\n appendText(looseInlines, \"\\n\", []);\n return;\n }\n\n if (containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n // Text directly inside an unknown wrapper is retained; the wrapper itself\n // and all unsupported attributes are discarded.\n looseInlines.push(...readInlineNodes([node]));\n };\n\n for (const node of Array.from(nodes)) visit(node);\n flushLoose();\n return blocks;\n};\n\n/** Parse HTML into the supported document model. Runs in a browser environment. */\nexport const parseHtmlToDocument = (html: string): TextDocument => {\n if (typeof DOMParser === \"undefined\") {\n const withoutUnsafeContent = html.replace(\n /<(script|style|iframe|object|embed|noscript)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi,\n \"\",\n );\n return createTextDocument(withoutUnsafeContent.replace(/<[^>]*>/g, \"\"));\n }\n\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const blocks = readHtmlBlocks(Array.from(parsed.body.childNodes));\n\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n\nconst parseInlineMarkdown = (input: string): TextInline[] => {\n const pattern = /!\\[([^\\]]*)\\]\\([^)]+\\)|\\[([^\\]]+)\\]\\([^)]+\\)|\\*\\*(.+?)\\*\\*|__(.+?)__|~~(.+?)~~|\\*(.+?)\\*|_(.+?)_|`([^`]+)`/g;\n const result: TextInline[] = [];\n let previousIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(input)) !== null) {\n appendText(result, input.slice(previousIndex, match.index), []);\n\n if (match[1] !== undefined) {\n // Images are not supported nodes; preserve their useful alt text.\n appendText(result, match[1], []);\n } else if (match[2] !== undefined) {\n // Links are not supported nodes; preserve the link label only.\n appendText(result, match[2], []);\n } else if (match[3] !== undefined || match[4] !== undefined) {\n appendText(result, match[3] ?? match[4] ?? \"\", [\"bold\"]);\n } else if (match[5] !== undefined) {\n appendText(result, match[5], [\"strike\"]);\n } else if (match[6] !== undefined || match[7] !== undefined) {\n appendText(result, match[6] ?? match[7] ?? \"\", [\"italic\"]);\n } else if (match[8] !== undefined) {\n // Inline code is not supported; preserve its contents as regular text.\n appendText(result, match[8], []);\n }\n\n previousIndex = pattern.lastIndex;\n }\n\n appendText(result, input.slice(previousIndex), []);\n return normalizeInlines(result);\n};\n\n/**\n * Parse a small Markdown subset without a dependency. Unsupported constructs\n * are flattened to readable text; supported inline marks, headings and lists remain semantic.\n */\nexport const parseMarkdownToDocument = (markdown: string): TextDocument => {\n const normalized = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const blocks: TextBlock[] = [];\n let paragraphLines: string[] = [];\n let insideCodeFence = false;\n\n const flushParagraph = () => {\n if (!paragraphLines.length) return;\n const text = paragraphLines.join(\"\\n\");\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(text)));\n paragraphLines = [];\n };\n\n for (const line of lines) {\n if (/^\\s*```/.test(line) || /^\\s*~~~/.test(line)) {\n flushParagraph();\n insideCodeFence = !insideCodeFence;\n continue;\n }\n\n if (!insideCodeFence && !line.trim()) {\n flushParagraph();\n continue;\n }\n\n if (!insideCodeFence) {\n const heading = line.match(/^\\s{0,3}(#{1,4})\\s+(.+?)\\s*#*\\s*$/);\n if (heading) {\n flushParagraph();\n const level = heading[1].length;\n const variant = (`headline${level}`) as TextBlockVariant;\n blocks.push(createBlock(variant, parseInlineMarkdown(heading[2]), true));\n continue;\n }\n\n if (/^\\s{0,3}(?:[-*_]\\s*){3,}$/.test(line)) {\n flushParagraph();\n continue;\n }\n\n const listItem = line.match(/^\\s{0,3}([-+*]|\\d+[.)])\\s+(.+)$/);\n if (listItem) {\n flushParagraph();\n const listType: TextListType = /^\\d/.test(listItem[1]) ? \"ordered\" : \"bullet\";\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(listItem[2]), false, undefined, listType));\n continue;\n }\n\n const quote = line.match(/^\\s{0,3}>\\s?(.*)$/);\n if (quote) {\n paragraphLines.push(quote[1]);\n continue;\n }\n }\n\n paragraphLines.push(line);\n }\n\n flushParagraph();\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text-parser.cjs","names":["normalizeInlines","isHeadingVariant","createTextDocument","normalizeTextDocument"],"sources":["../../../../src/components/editors/text-editor/text-parser.ts"],"sourcesContent":["import { createTextDocument, isHeadingVariant, normalizeInlines, normalizeTextDocument } from \"./text-document\";\nimport type { TextBlock, TextDocument, TextInline, TextMark, TextBlockVariant, TextAlign, TextListType } from \"./text-editor.types\";\n\nconst VARIANTS = new Set<TextBlockVariant>([\n \"display1\", \"display2\", \"headline1\", \"headline2\", \"headline3\", \"headline4\",\n \"subtitle1\", \"subtitle2\", \"body1\", \"body2\", \"button\", \"caption\", \"overline\",\n]);\n\nconst MARK_TAGS: Record<string, TextMark> = {\n b: \"bold\",\n strong: \"bold\",\n i: \"italic\",\n em: \"italic\",\n u: \"underline\",\n s: \"strike\",\n strike: \"strike\",\n del: \"strike\",\n};\n\nconst HEADING_VARIANTS: Record<string, TextBlockVariant> = {\n h1: \"headline1\",\n h2: \"headline2\",\n h3: \"headline3\",\n h4: \"headline4\",\n};\n\nconst appendText = (target: TextInline[], text: string, marks: TextMark[]) => {\n if (!text) return;\n target.push({ text, ...(marks.length ? { marks: [...marks] } : {}) });\n};\n\nconst readInlineNodes = (\n nodes: NodeListOf<ChildNode> | ChildNode[],\n inheritedMarks: TextMark[] = [],\n): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const node of Array.from(nodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n appendText(result, node.textContent ?? \"\", inheritedMarks);\n continue;\n }\n\n if (!(node instanceof Element)) continue;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) continue;\n\n if (tag === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n appendText(result, \"\\n\", inheritedMarks);\n }\n continue;\n }\n\n if (\n node.children.length === 1 &&\n node.firstElementChild?.tagName.toLowerCase() === \"br\" &&\n node.textContent === \"\"\n ) {\n // Browsers often represent an empty contenteditable block as <p><br></p>.\n continue;\n }\n\n const mark = MARK_TAGS[tag];\n const nextMarks = mark\n ? Array.from(new Set([...inheritedMarks, mark]))\n : inheritedMarks;\n\n // Unsupported elements are transparent: keep their readable children but\n // deliberately discard their styling, attributes and behavior.\n result.push(...readInlineNodes(Array.from(node.childNodes), nextMarks));\n }\n\n return normalizeInlines(result);\n};\n\nconst createBlock = (\n variant: TextBlockVariant,\n children: TextInline[],\n forceHeading?: boolean,\n align?: TextAlign,\n listType?: TextListType,\n): TextBlock => ({\n type: listType ? \"listItem\" : forceHeading || isHeadingVariant(variant) ? \"heading\" : \"paragraph\",\n variant,\n children: normalizeInlines(children),\n ...(align ? { align } : {}),\n ...(listType ? { listType } : {}),\n});\n\nconst getBlockAlign = (element: Element): TextAlign | undefined => {\n const align =\n element.getAttribute(\"data-puzzle-align\") ??\n (element as HTMLElement).style.textAlign;\n return align === \"left\" || align === \"center\" || align === \"right\" || align === \"justify\"\n ? align\n : undefined;\n};\n\nconst getBlockVariant = (element: Element): TextBlockVariant | undefined => {\n const provided = element.getAttribute(\"data-puzzle-variant\");\n if (provided && VARIANTS.has(provided as TextBlockVariant)) {\n return provided as TextBlockVariant;\n }\n\n return HEADING_VARIANTS[element.tagName.toLowerCase()];\n};\n\nconst containsBlockChild = (element: Element): boolean =>\n Array.from(element.children).some((child) =>\n [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\", \"ul\", \"ol\", \"li\"].includes(\n child.tagName.toLowerCase(),\n ),\n );\n\nconst readHtmlBlocks = (nodes: NodeListOf<ChildNode> | ChildNode[]): TextBlock[] => {\n const blocks: TextBlock[] = [];\n let looseInlines: TextInline[] = [];\n\n const flushLoose = () => {\n if (!looseInlines.length) return;\n blocks.push(createBlock(\"body1\", looseInlines));\n looseInlines = [];\n };\n\n const visit = (node: ChildNode) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent ?? \"\";\n if (looseInlines.length === 0 && !text.trim()) return;\n appendText(looseInlines, text, []);\n return;\n }\n\n if (!(node instanceof Element)) return;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) return;\n const isKnownBlock = [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\"].includes(tag);\n\n if (isKnownBlock && containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (isKnownBlock) {\n flushLoose();\n const variant = getBlockVariant(node) ?? \"body1\";\n const forceHeading = Boolean(HEADING_VARIANTS[tag]);\n const dataListType = node.getAttribute(\"data-puzzle-list-type\");\n const listType: TextListType | undefined = dataListType === \"bullet\" || dataListType === \"ordered\" ? dataListType : undefined;\n blocks.push(createBlock(variant, readInlineNodes(Array.from(node.childNodes)), forceHeading, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"li\") {\n flushLoose();\n const parentTag = node.parentElement?.tagName.toLowerCase();\n const listType: TextListType | undefined = parentTag === \"ul\" ? \"bullet\" : parentTag === \"ol\" ? \"ordered\" : undefined;\n blocks.push(createBlock(\"body1\", readInlineNodes(Array.from(node.childNodes)), false, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"ul\" || tag === \"ol\") {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (tag === \"br\") {\n appendText(looseInlines, \"\\n\", []);\n return;\n }\n\n if (containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n // Text directly inside an unknown wrapper is retained; the wrapper itself\n // and all unsupported attributes are discarded.\n looseInlines.push(...readInlineNodes([node]));\n };\n\n for (const node of Array.from(nodes)) visit(node);\n flushLoose();\n return blocks;\n};\n\n/** Parse HTML into the supported document model. Runs in a browser environment. */\nexport const parseHtmlToDocument = (html: string): TextDocument => {\n if (typeof DOMParser === \"undefined\") {\n const withoutUnsafeContent = html.replace(\n /<(script|style|iframe|object|embed|noscript)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi,\n \"\",\n );\n return createTextDocument(withoutUnsafeContent.replace(/<[^>]*>/g, \"\"));\n }\n\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const blocks = readHtmlBlocks(Array.from(parsed.body.childNodes));\n\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n\nconst parseInlineMarkdown = (input: string): TextInline[] => {\n const pattern = /!\\[([^\\]]*)\\]\\([^)]+\\)|\\[([^\\]]+)\\]\\([^)]+\\)|\\*\\*(.+?)\\*\\*|__(.+?)__|~~(.+?)~~|\\*(.+?)\\*|_(.+?)_|`([^`]+)`/g;\n const result: TextInline[] = [];\n let previousIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(input)) !== null) {\n appendText(result, input.slice(previousIndex, match.index), []);\n\n if (match[1] !== undefined) {\n // Images are not supported nodes; preserve their useful alt text.\n appendText(result, match[1], []);\n } else if (match[2] !== undefined) {\n // Links are not supported nodes; preserve the link label only.\n appendText(result, match[2], []);\n } else if (match[3] !== undefined || match[4] !== undefined) {\n appendText(result, match[3] ?? match[4] ?? \"\", [\"bold\"]);\n } else if (match[5] !== undefined) {\n appendText(result, match[5], [\"strike\"]);\n } else if (match[6] !== undefined || match[7] !== undefined) {\n appendText(result, match[6] ?? match[7] ?? \"\", [\"italic\"]);\n } else if (match[8] !== undefined) {\n // Inline code is not supported; preserve its contents as regular text.\n appendText(result, match[8], []);\n }\n\n previousIndex = pattern.lastIndex;\n }\n\n appendText(result, input.slice(previousIndex), []);\n return normalizeInlines(result);\n};\n\n/**\n * Parse a small Markdown subset without a dependency. Unsupported constructs\n * are flattened to readable text; supported inline marks, headings and lists remain semantic.\n */\nexport const parseMarkdownToDocument = (markdown: string): TextDocument => {\n const normalized = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const blocks: TextBlock[] = [];\n let paragraphLines: string[] = [];\n let insideCodeFence = false;\n\n const flushParagraph = () => {\n if (!paragraphLines.length) return;\n const text = paragraphLines.join(\"\\n\");\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(text)));\n paragraphLines = [];\n };\n\n for (const line of lines) {\n if (/^\\s*```/.test(line) || /^\\s*~~~/.test(line)) {\n flushParagraph();\n insideCodeFence = !insideCodeFence;\n continue;\n }\n\n if (!insideCodeFence && !line.trim()) {\n flushParagraph();\n continue;\n }\n\n if (!insideCodeFence) {\n const heading = line.match(/^\\s{0,3}(#{1,4})\\s+(.+?)\\s*#*\\s*$/);\n if (heading) {\n flushParagraph();\n const level = heading[1]!.length;\n const variant = (`headline${level}`) as TextBlockVariant;\n blocks.push(createBlock(variant, parseInlineMarkdown(heading[2]!), true));\n continue;\n }\n\n if (/^\\s{0,3}(?:[-*_]\\s*){3,}$/.test(line)) {\n flushParagraph();\n continue;\n }\n\n const listItem = line.match(/^\\s{0,3}([-+*]|\\d+[.)])\\s+(.+)$/);\n if (listItem) {\n flushParagraph();\n const listType: TextListType = /^\\d/.test(listItem[1]!) ? \"ordered\" : \"bullet\";\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(listItem[2]!), false, undefined, listType));\n continue;\n }\n\n const quote = line.match(/^\\s{0,3}>\\s?(.*)$/);\n if (quote) {\n paragraphLines.push(quote[1]!);\n continue;\n }\n }\n\n paragraphLines.push(line);\n }\n\n flushParagraph();\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-parser.js","names":[],"sources":["../../../../src/components/editors/text-editor/text-parser.ts"],"sourcesContent":["import { createTextDocument, isHeadingVariant, normalizeInlines, normalizeTextDocument } from \"./text-document\";\nimport type { TextBlock, TextDocument, TextInline, TextMark, TextBlockVariant, TextAlign, TextListType } from \"./text-editor.types\";\n\nconst VARIANTS = new Set<TextBlockVariant>([\n \"display1\", \"display2\", \"headline1\", \"headline2\", \"headline3\", \"headline4\",\n \"subtitle1\", \"subtitle2\", \"body1\", \"body2\", \"button\", \"caption\", \"overline\",\n]);\n\nconst MARK_TAGS: Record<string, TextMark> = {\n b: \"bold\",\n strong: \"bold\",\n i: \"italic\",\n em: \"italic\",\n u: \"underline\",\n s: \"strike\",\n strike: \"strike\",\n del: \"strike\",\n};\n\nconst HEADING_VARIANTS: Record<string, TextBlockVariant> = {\n h1: \"headline1\",\n h2: \"headline2\",\n h3: \"headline3\",\n h4: \"headline4\",\n};\n\nconst appendText = (target: TextInline[], text: string, marks: TextMark[]) => {\n if (!text) return;\n target.push({ text, ...(marks.length ? { marks: [...marks] } : {}) });\n};\n\nconst readInlineNodes = (\n nodes: NodeListOf<ChildNode> | ChildNode[],\n inheritedMarks: TextMark[] = [],\n): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const node of Array.from(nodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n appendText(result, node.textContent ?? \"\", inheritedMarks);\n continue;\n }\n\n if (!(node instanceof Element)) continue;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) continue;\n\n if (tag === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n appendText(result, \"\\n\", inheritedMarks);\n }\n continue;\n }\n\n if (\n node.children.length === 1 &&\n node.firstElementChild?.tagName.toLowerCase() === \"br\" &&\n node.textContent === \"\"\n ) {\n // Browsers often represent an empty contenteditable block as <p><br></p>.\n continue;\n }\n\n const mark = MARK_TAGS[tag];\n const nextMarks = mark\n ? Array.from(new Set([...inheritedMarks, mark]))\n : inheritedMarks;\n\n // Unsupported elements are transparent: keep their readable children but\n // deliberately discard their styling, attributes and behavior.\n result.push(...readInlineNodes(Array.from(node.childNodes), nextMarks));\n }\n\n return normalizeInlines(result);\n};\n\nconst createBlock = (\n variant: TextBlockVariant,\n children: TextInline[],\n forceHeading?: boolean,\n align?: TextAlign,\n listType?: TextListType,\n): TextBlock => ({\n type: listType ? \"listItem\" : forceHeading || isHeadingVariant(variant) ? \"heading\" : \"paragraph\",\n variant,\n children: normalizeInlines(children),\n ...(align ? { align } : {}),\n ...(listType ? { listType } : {}),\n});\n\nconst getBlockAlign = (element: Element): TextAlign | undefined => {\n const align =\n element.getAttribute(\"data-puzzle-align\") ??\n (element as HTMLElement).style.textAlign;\n return align === \"left\" || align === \"center\" || align === \"right\" || align === \"justify\"\n ? align\n : undefined;\n};\n\nconst getBlockVariant = (element: Element): TextBlockVariant | undefined => {\n const provided = element.getAttribute(\"data-puzzle-variant\");\n if (provided && VARIANTS.has(provided as TextBlockVariant)) {\n return provided as TextBlockVariant;\n }\n\n return HEADING_VARIANTS[element.tagName.toLowerCase()];\n};\n\nconst containsBlockChild = (element: Element): boolean =>\n Array.from(element.children).some((child) =>\n [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\", \"ul\", \"ol\", \"li\"].includes(\n child.tagName.toLowerCase(),\n ),\n );\n\nconst readHtmlBlocks = (nodes: NodeListOf<ChildNode> | ChildNode[]): TextBlock[] => {\n const blocks: TextBlock[] = [];\n let looseInlines: TextInline[] = [];\n\n const flushLoose = () => {\n if (!looseInlines.length) return;\n blocks.push(createBlock(\"body1\", looseInlines));\n looseInlines = [];\n };\n\n const visit = (node: ChildNode) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent ?? \"\";\n if (looseInlines.length === 0 && !text.trim()) return;\n appendText(looseInlines, text, []);\n return;\n }\n\n if (!(node instanceof Element)) return;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) return;\n const isKnownBlock = [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\"].includes(tag);\n\n if (isKnownBlock && containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (isKnownBlock) {\n flushLoose();\n const variant = getBlockVariant(node) ?? \"body1\";\n const forceHeading = Boolean(HEADING_VARIANTS[tag]);\n const dataListType = node.getAttribute(\"data-puzzle-list-type\");\n const listType: TextListType | undefined = dataListType === \"bullet\" || dataListType === \"ordered\" ? dataListType : undefined;\n blocks.push(createBlock(variant, readInlineNodes(Array.from(node.childNodes)), forceHeading, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"li\") {\n flushLoose();\n const parentTag = node.parentElement?.tagName.toLowerCase();\n const listType: TextListType | undefined = parentTag === \"ul\" ? \"bullet\" : parentTag === \"ol\" ? \"ordered\" : undefined;\n blocks.push(createBlock(\"body1\", readInlineNodes(Array.from(node.childNodes)), false, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"ul\" || tag === \"ol\") {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (tag === \"br\") {\n appendText(looseInlines, \"\\n\", []);\n return;\n }\n\n if (containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n // Text directly inside an unknown wrapper is retained; the wrapper itself\n // and all unsupported attributes are discarded.\n looseInlines.push(...readInlineNodes([node]));\n };\n\n for (const node of Array.from(nodes)) visit(node);\n flushLoose();\n return blocks;\n};\n\n/** Parse HTML into the supported document model. Runs in a browser environment. */\nexport const parseHtmlToDocument = (html: string): TextDocument => {\n if (typeof DOMParser === \"undefined\") {\n const withoutUnsafeContent = html.replace(\n /<(script|style|iframe|object|embed|noscript)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi,\n \"\",\n );\n return createTextDocument(withoutUnsafeContent.replace(/<[^>]*>/g, \"\"));\n }\n\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const blocks = readHtmlBlocks(Array.from(parsed.body.childNodes));\n\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n\nconst parseInlineMarkdown = (input: string): TextInline[] => {\n const pattern = /!\\[([^\\]]*)\\]\\([^)]+\\)|\\[([^\\]]+)\\]\\([^)]+\\)|\\*\\*(.+?)\\*\\*|__(.+?)__|~~(.+?)~~|\\*(.+?)\\*|_(.+?)_|`([^`]+)`/g;\n const result: TextInline[] = [];\n let previousIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(input)) !== null) {\n appendText(result, input.slice(previousIndex, match.index), []);\n\n if (match[1] !== undefined) {\n // Images are not supported nodes; preserve their useful alt text.\n appendText(result, match[1], []);\n } else if (match[2] !== undefined) {\n // Links are not supported nodes; preserve the link label only.\n appendText(result, match[2], []);\n } else if (match[3] !== undefined || match[4] !== undefined) {\n appendText(result, match[3] ?? match[4] ?? \"\", [\"bold\"]);\n } else if (match[5] !== undefined) {\n appendText(result, match[5], [\"strike\"]);\n } else if (match[6] !== undefined || match[7] !== undefined) {\n appendText(result, match[6] ?? match[7] ?? \"\", [\"italic\"]);\n } else if (match[8] !== undefined) {\n // Inline code is not supported; preserve its contents as regular text.\n appendText(result, match[8], []);\n }\n\n previousIndex = pattern.lastIndex;\n }\n\n appendText(result, input.slice(previousIndex), []);\n return normalizeInlines(result);\n};\n\n/**\n * Parse a small Markdown subset without a dependency. Unsupported constructs\n * are flattened to readable text; supported inline marks, headings and lists remain semantic.\n */\nexport const parseMarkdownToDocument = (markdown: string): TextDocument => {\n const normalized = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const blocks: TextBlock[] = [];\n let paragraphLines: string[] = [];\n let insideCodeFence = false;\n\n const flushParagraph = () => {\n if (!paragraphLines.length) return;\n const text = paragraphLines.join(\"\\n\");\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(text)));\n paragraphLines = [];\n };\n\n for (const line of lines) {\n if (/^\\s*```/.test(line) || /^\\s*~~~/.test(line)) {\n flushParagraph();\n insideCodeFence = !insideCodeFence;\n continue;\n }\n\n if (!insideCodeFence && !line.trim()) {\n flushParagraph();\n continue;\n }\n\n if (!insideCodeFence) {\n const heading = line.match(/^\\s{0,3}(#{1,4})\\s+(.+?)\\s*#*\\s*$/);\n if (heading) {\n flushParagraph();\n const level = heading[1].length;\n const variant = (`headline${level}`) as TextBlockVariant;\n blocks.push(createBlock(variant, parseInlineMarkdown(heading[2]), true));\n continue;\n }\n\n if (/^\\s{0,3}(?:[-*_]\\s*){3,}$/.test(line)) {\n flushParagraph();\n continue;\n }\n\n const listItem = line.match(/^\\s{0,3}([-+*]|\\d+[.)])\\s+(.+)$/);\n if (listItem) {\n flushParagraph();\n const listType: TextListType = /^\\d/.test(listItem[1]) ? \"ordered\" : \"bullet\";\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(listItem[2]), false, undefined, listType));\n continue;\n }\n\n const quote = line.match(/^\\s{0,3}>\\s?(.*)$/);\n if (quote) {\n paragraphLines.push(quote[1]);\n continue;\n }\n }\n\n paragraphLines.push(line);\n }\n\n flushParagraph();\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n"],"mappings":";;AAGA,MAAM,2BAAW,IAAI,IAAsB;CACzC;CAAY;CAAY;CAAa;CAAa;CAAa;CAC/D;CAAa;CAAa;CAAS;CAAS;CAAU;CAAW;AACnE,CAAC;AAED,MAAM,YAAsC;CAC1C,GAAG;CACH,QAAQ;CACR,GAAG;CACH,IAAI;CACJ,GAAG;CACH,GAAG;CACH,QAAQ;CACR,KAAK;AACP;AAEA,MAAM,mBAAqD;CACzD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,MAAM,cAAc,QAAsB,MAAc,UAAsB;CAC5E,IAAI,CAAC,MAAM;CACX,OAAO,KAAK;EAAE;EAAM,GAAI,MAAM,SAAS,EAAE,OAAO,CAAC,GAAG,KAAK,EAAE,IAAI,CAAC;CAAG,CAAC;AACtE;AAEA,MAAM,mBACJ,OACA,iBAA6B,CAAC,MACb;CACjB,MAAM,SAAuB,CAAC;CAE9B,KAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG;EACpC,IAAI,KAAK,aAAa,KAAK,WAAW;GACpC,WAAW,QAAQ,KAAK,eAAe,IAAI,cAAc;GACzD;EACF;EAEA,IAAI,EAAE,gBAAgB,UAAU;EAChC,MAAM,MAAM,KAAK,QAAQ,YAAY;EACrC,IAAI;GAAC;GAAU;GAAS;GAAU;GAAU;GAAS;EAAU,CAAC,CAAC,SAAS,GAAG,GAAG;EAEhF,IAAI,QAAQ,MAAM;GAChB,IAAI,CAAC,KAAK,aAAa,yBAAyB,GAC9C,WAAW,QAAQ,MAAM,cAAc;GAEzC;EACF;EAEA,IACE,KAAK,SAAS,WAAW,KACzB,KAAK,mBAAmB,QAAQ,YAAY,MAAM,QAClD,KAAK,gBAAgB,IAGrB;EAGF,MAAM,OAAO,UAAU;EACvB,MAAM,YAAY,OACd,MAAM,qBAAK,IAAI,IAAI,CAAC,GAAG,gBAAgB,IAAI,CAAC,CAAC,IAC7C;EAIJ,OAAO,KAAK,GAAG,gBAAgB,MAAM,KAAK,KAAK,UAAU,GAAG,SAAS,CAAC;CACxE;CAEA,OAAO,iBAAiB,MAAM;AAChC;AAEA,MAAM,eACJ,SACA,UACA,cACA,OACA,cACe;CACf,MAAM,WAAW,aAAa,gBAAgB,iBAAiB,OAAO,IAAI,YAAY;CACtF;CACA,UAAU,iBAAiB,QAAQ;CACnC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;CACzB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AACjC;AAEA,MAAM,iBAAiB,YAA4C;CACjE,MAAM,QACJ,QAAQ,aAAa,mBAAmB,KACvC,QAAwB,MAAM;CACjC,OAAO,UAAU,UAAU,UAAU,YAAY,UAAU,WAAW,UAAU,YAC5E,QACA,KAAA;AACN;AAEA,MAAM,mBAAmB,YAAmD;CAC1E,MAAM,WAAW,QAAQ,aAAa,qBAAqB;CAC3D,IAAI,YAAY,SAAS,IAAI,QAA4B,GACvD,OAAO;CAGT,OAAO,iBAAiB,QAAQ,QAAQ,YAAY;AACtD;AAEA,MAAM,sBAAsB,YAC1B,MAAM,KAAK,QAAQ,QAAQ,CAAC,CAAC,MAAM,UACjC;CAAC;CAAK;CAAO;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC,CAAC,SACrD,MAAM,QAAQ,YAAY,CAC5B,CACF;AAEF,MAAM,kBAAkB,UAA4D;CAClF,MAAM,SAAsB,CAAC;CAC7B,IAAI,eAA6B,CAAC;CAElC,MAAM,mBAAmB;EACvB,IAAI,CAAC,aAAa,QAAQ;EAC1B,OAAO,KAAK,YAAY,SAAS,YAAY,CAAC;EAC9C,eAAe,CAAC;CAClB;CAEA,MAAM,SAAS,SAAoB;EACjC,IAAI,KAAK,aAAa,KAAK,WAAW;GACpC,MAAM,OAAO,KAAK,eAAe;GACjC,IAAI,aAAa,WAAW,KAAK,CAAC,KAAK,KAAK,GAAG;GAC/C,WAAW,cAAc,MAAM,CAAC,CAAC;GACjC;EACF;EAEA,IAAI,EAAE,gBAAgB,UAAU;EAChC,MAAM,MAAM,KAAK,QAAQ,YAAY;EACrC,IAAI;GAAC;GAAU;GAAS;GAAU;GAAU;GAAS;EAAU,CAAC,CAAC,SAAS,GAAG,GAAG;EAChF,MAAM,eAAe;GAAC;GAAK;GAAO;GAAM;GAAM;GAAM;EAAI,CAAC,CAAC,SAAS,GAAG;EAEtE,IAAI,gBAAgB,mBAAmB,IAAI,GAAG;GAC5C,WAAW;GACX,KAAK,MAAM,SAAS,MAAM,KAAK,KAAK,UAAU,GAAG,MAAM,KAAK;GAC5D;EACF;EAEA,IAAI,cAAc;GAChB,WAAW;GACX,MAAM,UAAU,gBAAgB,IAAI,KAAK;GACzC,MAAM,eAAe,QAAQ,iBAAiB,IAAI;GAClD,MAAM,eAAe,KAAK,aAAa,uBAAuB;GAC9D,MAAM,WAAqC,iBAAiB,YAAY,iBAAiB,YAAY,eAAe,KAAA;GACpH,OAAO,KAAK,YAAY,SAAS,gBAAgB,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG,cAAc,cAAc,IAAI,GAAG,QAAQ,CAAC;GAC3H;EACF;EAEA,IAAI,QAAQ,MAAM;GAChB,WAAW;GACX,MAAM,YAAY,KAAK,eAAe,QAAQ,YAAY;GAC1D,MAAM,WAAqC,cAAc,OAAO,WAAW,cAAc,OAAO,YAAY,KAAA;GAC5G,OAAO,KAAK,YAAY,SAAS,gBAAgB,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG,OAAO,cAAc,IAAI,GAAG,QAAQ,CAAC;GACpH;EACF;EAEA,IAAI,QAAQ,QAAQ,QAAQ,MAAM;GAChC,WAAW;GACX,KAAK,MAAM,SAAS,MAAM,KAAK,KAAK,UAAU,GAAG,MAAM,KAAK;GAC5D;EACF;EAEA,IAAI,QAAQ,MAAM;GAChB,WAAW,cAAc,MAAM,CAAC,CAAC;GACjC;EACF;EAEA,IAAI,mBAAmB,IAAI,GAAG;GAC5B,WAAW;GACX,KAAK,MAAM,SAAS,MAAM,KAAK,KAAK,UAAU,GAAG,MAAM,KAAK;GAC5D;EACF;EAIA,aAAa,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;CAC9C;CAEA,KAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG,MAAM,IAAI;CAChD,WAAW;CACX,OAAO;AACT;;AAGA,MAAa,uBAAuB,SAA+B;CACjE,IAAI,OAAO,cAAc,aAAa;EACpC,MAAM,uBAAuB,KAAK,QAChC,2EACA,EACF;EACA,OAAO,mBAAmB,qBAAqB,QAAQ,YAAY,EAAE,CAAC;CACxE;CAEA,MAAM,SAAS,IAAI,UAAU,CAAC,CAAC,gBAAgB,MAAM,WAAW;CAChE,MAAM,SAAS,eAAe,MAAM,KAAK,OAAO,KAAK,UAAU,CAAC;CAEhE,OAAO,sBAAsB;EAC3B,MAAM;EACN,SAAS,OAAO,SAAS,SAAS,mBAAmB,CAAC,CAAC;CACzD,CAAC;AACH;AAEA,MAAM,uBAAuB,UAAgC;CAC3D,MAAM,UAAU;CAChB,MAAM,SAAuB,CAAC;CAC9B,IAAI,gBAAgB;CACpB,IAAI;CAEJ,QAAQ,QAAQ,QAAQ,KAAK,KAAK,OAAO,MAAM;EAC7C,WAAW,QAAQ,MAAM,MAAM,eAAe,MAAM,KAAK,GAAG,CAAC,CAAC;EAE9D,IAAI,MAAM,OAAO,KAAA,GAEf,WAAW,QAAQ,MAAM,IAAI,CAAC,CAAC;OAC1B,IAAI,MAAM,OAAO,KAAA,GAEtB,WAAW,QAAQ,MAAM,IAAI,CAAC,CAAC;OAC1B,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,KAAA,GAChD,WAAW,QAAQ,MAAM,MAAM,MAAM,MAAM,IAAI,CAAC,MAAM,CAAC;OAClD,IAAI,MAAM,OAAO,KAAA,GACtB,WAAW,QAAQ,MAAM,IAAI,CAAC,QAAQ,CAAC;OAClC,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,KAAA,GAChD,WAAW,QAAQ,MAAM,MAAM,MAAM,MAAM,IAAI,CAAC,QAAQ,CAAC;OACpD,IAAI,MAAM,OAAO,KAAA,GAEtB,WAAW,QAAQ,MAAM,IAAI,CAAC,CAAC;EAGjC,gBAAgB,QAAQ;CAC1B;CAEA,WAAW,QAAQ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC;CACjD,OAAO,iBAAiB,MAAM;AAChC;;;;;AAMA,MAAa,2BAA2B,aAAmC;CAEzE,MAAM,QADa,SAAS,QAAQ,UAAU,IACvB,CAAC,CAAC,MAAM,IAAI;CACnC,MAAM,SAAsB,CAAC;CAC7B,IAAI,iBAA2B,CAAC;CAChC,IAAI,kBAAkB;CAEtB,MAAM,uBAAuB;EAC3B,IAAI,CAAC,eAAe,QAAQ;EAC5B,MAAM,OAAO,eAAe,KAAK,IAAI;EACrC,OAAO,KAAK,YAAY,SAAS,oBAAoB,IAAI,CAAC,CAAC;EAC3D,iBAAiB,CAAC;CACpB;CAEA,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,UAAU,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI,GAAG;GAChD,eAAe;GACf,kBAAkB,CAAC;GACnB;EACF;EAEA,IAAI,CAAC,mBAAmB,CAAC,KAAK,KAAK,GAAG;GACpC,eAAe;GACf;EACF;EAEA,IAAI,CAAC,iBAAiB;GACpB,MAAM,UAAU,KAAK,MAAM,mCAAmC;GAC9D,IAAI,SAAS;IACX,eAAe;IAEf,MAAM,UAAW,WADH,QAAQ,EAAE,CAAC;IAEzB,OAAO,KAAK,YAAY,SAAS,oBAAoB,QAAQ,EAAE,GAAG,IAAI,CAAC;IACvE;GACF;GAEA,IAAI,4BAA4B,KAAK,IAAI,GAAG;IAC1C,eAAe;IACf;GACF;GAEA,MAAM,WAAW,KAAK,MAAM,iCAAiC;GAC7D,IAAI,UAAU;IACZ,eAAe;IACf,MAAM,WAAyB,MAAM,KAAK,SAAS,EAAE,IAAI,YAAY;IACrE,OAAO,KAAK,YAAY,SAAS,oBAAoB,SAAS,EAAE,GAAG,OAAO,KAAA,GAAW,QAAQ,CAAC;IAC9F;GACF;GAEA,MAAM,QAAQ,KAAK,MAAM,mBAAmB;GAC5C,IAAI,OAAO;IACT,eAAe,KAAK,MAAM,EAAE;IAC5B;GACF;EACF;EAEA,eAAe,KAAK,IAAI;CAC1B;CAEA,eAAe;CACf,OAAO,sBAAsB;EAC3B,MAAM;EACN,SAAS,OAAO,SAAS,SAAS,mBAAmB,CAAC,CAAC;CACzD,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"text-parser.js","names":[],"sources":["../../../../src/components/editors/text-editor/text-parser.ts"],"sourcesContent":["import { createTextDocument, isHeadingVariant, normalizeInlines, normalizeTextDocument } from \"./text-document\";\nimport type { TextBlock, TextDocument, TextInline, TextMark, TextBlockVariant, TextAlign, TextListType } from \"./text-editor.types\";\n\nconst VARIANTS = new Set<TextBlockVariant>([\n \"display1\", \"display2\", \"headline1\", \"headline2\", \"headline3\", \"headline4\",\n \"subtitle1\", \"subtitle2\", \"body1\", \"body2\", \"button\", \"caption\", \"overline\",\n]);\n\nconst MARK_TAGS: Record<string, TextMark> = {\n b: \"bold\",\n strong: \"bold\",\n i: \"italic\",\n em: \"italic\",\n u: \"underline\",\n s: \"strike\",\n strike: \"strike\",\n del: \"strike\",\n};\n\nconst HEADING_VARIANTS: Record<string, TextBlockVariant> = {\n h1: \"headline1\",\n h2: \"headline2\",\n h3: \"headline3\",\n h4: \"headline4\",\n};\n\nconst appendText = (target: TextInline[], text: string, marks: TextMark[]) => {\n if (!text) return;\n target.push({ text, ...(marks.length ? { marks: [...marks] } : {}) });\n};\n\nconst readInlineNodes = (\n nodes: NodeListOf<ChildNode> | ChildNode[],\n inheritedMarks: TextMark[] = [],\n): TextInline[] => {\n const result: TextInline[] = [];\n\n for (const node of Array.from(nodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n appendText(result, node.textContent ?? \"\", inheritedMarks);\n continue;\n }\n\n if (!(node instanceof Element)) continue;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) continue;\n\n if (tag === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n appendText(result, \"\\n\", inheritedMarks);\n }\n continue;\n }\n\n if (\n node.children.length === 1 &&\n node.firstElementChild?.tagName.toLowerCase() === \"br\" &&\n node.textContent === \"\"\n ) {\n // Browsers often represent an empty contenteditable block as <p><br></p>.\n continue;\n }\n\n const mark = MARK_TAGS[tag];\n const nextMarks = mark\n ? Array.from(new Set([...inheritedMarks, mark]))\n : inheritedMarks;\n\n // Unsupported elements are transparent: keep their readable children but\n // deliberately discard their styling, attributes and behavior.\n result.push(...readInlineNodes(Array.from(node.childNodes), nextMarks));\n }\n\n return normalizeInlines(result);\n};\n\nconst createBlock = (\n variant: TextBlockVariant,\n children: TextInline[],\n forceHeading?: boolean,\n align?: TextAlign,\n listType?: TextListType,\n): TextBlock => ({\n type: listType ? \"listItem\" : forceHeading || isHeadingVariant(variant) ? \"heading\" : \"paragraph\",\n variant,\n children: normalizeInlines(children),\n ...(align ? { align } : {}),\n ...(listType ? { listType } : {}),\n});\n\nconst getBlockAlign = (element: Element): TextAlign | undefined => {\n const align =\n element.getAttribute(\"data-puzzle-align\") ??\n (element as HTMLElement).style.textAlign;\n return align === \"left\" || align === \"center\" || align === \"right\" || align === \"justify\"\n ? align\n : undefined;\n};\n\nconst getBlockVariant = (element: Element): TextBlockVariant | undefined => {\n const provided = element.getAttribute(\"data-puzzle-variant\");\n if (provided && VARIANTS.has(provided as TextBlockVariant)) {\n return provided as TextBlockVariant;\n }\n\n return HEADING_VARIANTS[element.tagName.toLowerCase()];\n};\n\nconst containsBlockChild = (element: Element): boolean =>\n Array.from(element.children).some((child) =>\n [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\", \"ul\", \"ol\", \"li\"].includes(\n child.tagName.toLowerCase(),\n ),\n );\n\nconst readHtmlBlocks = (nodes: NodeListOf<ChildNode> | ChildNode[]): TextBlock[] => {\n const blocks: TextBlock[] = [];\n let looseInlines: TextInline[] = [];\n\n const flushLoose = () => {\n if (!looseInlines.length) return;\n blocks.push(createBlock(\"body1\", looseInlines));\n looseInlines = [];\n };\n\n const visit = (node: ChildNode) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent ?? \"\";\n if (looseInlines.length === 0 && !text.trim()) return;\n appendText(looseInlines, text, []);\n return;\n }\n\n if (!(node instanceof Element)) return;\n const tag = node.tagName.toLowerCase();\n if ([\"script\", \"style\", \"iframe\", \"object\", \"embed\", \"noscript\"].includes(tag)) return;\n const isKnownBlock = [\"p\", \"div\", \"h1\", \"h2\", \"h3\", \"h4\"].includes(tag);\n\n if (isKnownBlock && containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (isKnownBlock) {\n flushLoose();\n const variant = getBlockVariant(node) ?? \"body1\";\n const forceHeading = Boolean(HEADING_VARIANTS[tag]);\n const dataListType = node.getAttribute(\"data-puzzle-list-type\");\n const listType: TextListType | undefined = dataListType === \"bullet\" || dataListType === \"ordered\" ? dataListType : undefined;\n blocks.push(createBlock(variant, readInlineNodes(Array.from(node.childNodes)), forceHeading, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"li\") {\n flushLoose();\n const parentTag = node.parentElement?.tagName.toLowerCase();\n const listType: TextListType | undefined = parentTag === \"ul\" ? \"bullet\" : parentTag === \"ol\" ? \"ordered\" : undefined;\n blocks.push(createBlock(\"body1\", readInlineNodes(Array.from(node.childNodes)), false, getBlockAlign(node), listType));\n return;\n }\n\n if (tag === \"ul\" || tag === \"ol\") {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n if (tag === \"br\") {\n appendText(looseInlines, \"\\n\", []);\n return;\n }\n\n if (containsBlockChild(node)) {\n flushLoose();\n for (const child of Array.from(node.childNodes)) visit(child);\n return;\n }\n\n // Text directly inside an unknown wrapper is retained; the wrapper itself\n // and all unsupported attributes are discarded.\n looseInlines.push(...readInlineNodes([node]));\n };\n\n for (const node of Array.from(nodes)) visit(node);\n flushLoose();\n return blocks;\n};\n\n/** Parse HTML into the supported document model. Runs in a browser environment. */\nexport const parseHtmlToDocument = (html: string): TextDocument => {\n if (typeof DOMParser === \"undefined\") {\n const withoutUnsafeContent = html.replace(\n /<(script|style|iframe|object|embed|noscript)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi,\n \"\",\n );\n return createTextDocument(withoutUnsafeContent.replace(/<[^>]*>/g, \"\"));\n }\n\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const blocks = readHtmlBlocks(Array.from(parsed.body.childNodes));\n\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n\nconst parseInlineMarkdown = (input: string): TextInline[] => {\n const pattern = /!\\[([^\\]]*)\\]\\([^)]+\\)|\\[([^\\]]+)\\]\\([^)]+\\)|\\*\\*(.+?)\\*\\*|__(.+?)__|~~(.+?)~~|\\*(.+?)\\*|_(.+?)_|`([^`]+)`/g;\n const result: TextInline[] = [];\n let previousIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(input)) !== null) {\n appendText(result, input.slice(previousIndex, match.index), []);\n\n if (match[1] !== undefined) {\n // Images are not supported nodes; preserve their useful alt text.\n appendText(result, match[1], []);\n } else if (match[2] !== undefined) {\n // Links are not supported nodes; preserve the link label only.\n appendText(result, match[2], []);\n } else if (match[3] !== undefined || match[4] !== undefined) {\n appendText(result, match[3] ?? match[4] ?? \"\", [\"bold\"]);\n } else if (match[5] !== undefined) {\n appendText(result, match[5], [\"strike\"]);\n } else if (match[6] !== undefined || match[7] !== undefined) {\n appendText(result, match[6] ?? match[7] ?? \"\", [\"italic\"]);\n } else if (match[8] !== undefined) {\n // Inline code is not supported; preserve its contents as regular text.\n appendText(result, match[8], []);\n }\n\n previousIndex = pattern.lastIndex;\n }\n\n appendText(result, input.slice(previousIndex), []);\n return normalizeInlines(result);\n};\n\n/**\n * Parse a small Markdown subset without a dependency. Unsupported constructs\n * are flattened to readable text; supported inline marks, headings and lists remain semantic.\n */\nexport const parseMarkdownToDocument = (markdown: string): TextDocument => {\n const normalized = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const blocks: TextBlock[] = [];\n let paragraphLines: string[] = [];\n let insideCodeFence = false;\n\n const flushParagraph = () => {\n if (!paragraphLines.length) return;\n const text = paragraphLines.join(\"\\n\");\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(text)));\n paragraphLines = [];\n };\n\n for (const line of lines) {\n if (/^\\s*```/.test(line) || /^\\s*~~~/.test(line)) {\n flushParagraph();\n insideCodeFence = !insideCodeFence;\n continue;\n }\n\n if (!insideCodeFence && !line.trim()) {\n flushParagraph();\n continue;\n }\n\n if (!insideCodeFence) {\n const heading = line.match(/^\\s{0,3}(#{1,4})\\s+(.+?)\\s*#*\\s*$/);\n if (heading) {\n flushParagraph();\n const level = heading[1]!.length;\n const variant = (`headline${level}`) as TextBlockVariant;\n blocks.push(createBlock(variant, parseInlineMarkdown(heading[2]!), true));\n continue;\n }\n\n if (/^\\s{0,3}(?:[-*_]\\s*){3,}$/.test(line)) {\n flushParagraph();\n continue;\n }\n\n const listItem = line.match(/^\\s{0,3}([-+*]|\\d+[.)])\\s+(.+)$/);\n if (listItem) {\n flushParagraph();\n const listType: TextListType = /^\\d/.test(listItem[1]!) ? \"ordered\" : \"bullet\";\n blocks.push(createBlock(\"body1\", parseInlineMarkdown(listItem[2]!), false, undefined, listType));\n continue;\n }\n\n const quote = line.match(/^\\s{0,3}>\\s?(.*)$/);\n if (quote) {\n paragraphLines.push(quote[1]!);\n continue;\n }\n }\n\n paragraphLines.push(line);\n }\n\n flushParagraph();\n return normalizeTextDocument({\n type: \"doc\",\n content: blocks.length ? blocks : createTextDocument().content,\n });\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-renderer.cjs","names":["cn"],"sources":["../../../../src/components/editors/text-editor/text-renderer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport \"./text-editor.css\";\nimport type { TextBlock, TextDocument, TextMark } from \"./text-editor.types\";\n\nexport type TextRendererProps = { document: TextDocument; className?: string };\n\nconst MARK_COMPONENTS: Record<TextMark, (children: ReactNode) => ReactNode> = {\n bold: (children) => <strong>{children}</strong>,\n italic: (children) => <em>{children}</em>,\n underline: (children) => <u>{children}</u>,\n strike: (children) => <s>{children}</s>,\n};\n\nconst renderInline = (block: TextBlock, blockIndex: number): ReactNode[] =>\n block.children.map((inline, inlineIndex) => {\n const parts = inline.text.split(\"\\n\");\n let node: ReactNode = parts.flatMap((part, partIndex) => partIndex === 0\n ? [part]\n : [<br key={`break-${blockIndex}-${inlineIndex}-${partIndex}`} />, part]);\n for (const mark of [...(inline.marks ?? [])].reverse()) node = MARK_COMPONENTS[mark](node);\n return <span key={`${blockIndex}-${inlineIndex}`}>{node}</span>;\n });\n\nconst HEADING_TAGS = [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"] as const;\n\n// Without an explicit level, fall back to the level implied by the variant.\nconst getHeadingTag = (block: TextBlock): (typeof HEADING_TAGS)[number] => {\n if (block.headingLevel) return HEADING_TAGS[block.headingLevel - 1]
|
|
1
|
+
{"version":3,"file":"text-renderer.cjs","names":["cn"],"sources":["../../../../src/components/editors/text-editor/text-renderer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport \"./text-editor.css\";\nimport type { TextBlock, TextDocument, TextMark } from \"./text-editor.types\";\n\nexport type TextRendererProps = { document: TextDocument; className?: string };\n\nconst MARK_COMPONENTS: Record<TextMark, (children: ReactNode) => ReactNode> = {\n bold: (children) => <strong>{children}</strong>,\n italic: (children) => <em>{children}</em>,\n underline: (children) => <u>{children}</u>,\n strike: (children) => <s>{children}</s>,\n};\n\nconst renderInline = (block: TextBlock, blockIndex: number): ReactNode[] =>\n block.children.map((inline, inlineIndex) => {\n const parts = inline.text.split(\"\\n\");\n let node: ReactNode = parts.flatMap((part, partIndex) => partIndex === 0\n ? [part]\n : [<br key={`break-${blockIndex}-${inlineIndex}-${partIndex}`} />, part]);\n for (const mark of [...(inline.marks ?? [])].reverse()) node = MARK_COMPONENTS[mark](node);\n return <span key={`${blockIndex}-${inlineIndex}`}>{node}</span>;\n });\n\nconst HEADING_TAGS = [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"] as const;\n\n// Without an explicit level, fall back to the level implied by the variant.\nconst getHeadingTag = (block: TextBlock): (typeof HEADING_TAGS)[number] => {\n if (block.headingLevel) return HEADING_TAGS[block.headingLevel - 1]!;\n\n switch (block.variant) {\n case \"display1\": case \"headline1\": return \"h1\";\n case \"display2\": case \"headline2\": return \"h2\";\n case \"headline3\": return \"h3\";\n default: return \"h4\";\n }\n};\n\nconst TextRenderer = ({ document, className }: TextRendererProps) => {\n const blocks = document.content;\n const output: ReactNode[] = [];\n let index = 0;\n while (index < blocks.length) {\n const block = blocks[index]!;\n if (block.listType) {\n const listType = block.listType;\n const items: ReactNode[] = [];\n while (index < blocks.length && blocks[index]!.listType === listType) {\n const item = blocks[index]!;\n const itemChildren = renderInline(item, index);\n items.push(<li key={index} className={cn(\"puzzle-text-renderer__block\", `puzzle-typography-${item.variant}`)} style={{ textAlign: item.align }}>\n {itemChildren.length ? itemChildren : <br />}\n </li>);\n index++;\n }\n const List = listType === \"ordered\" ? \"ol\" : \"ul\";\n output.push(<List key={`list-${index}`} className=\"puzzle-text-renderer__list\">{items}</List>);\n continue;\n }\n const blockClass = cn(\"puzzle-text-renderer__block\", `puzzle-typography-${block.variant}`);\n const children = renderInline(block, index);\n const style = { textAlign: block.align };\n if (block.type === \"heading\") {\n const HeadingTag = getHeadingTag(block);\n output.push(<HeadingTag key={index} className={blockClass} style={style}>{children.length ? children : <br />}</HeadingTag>);\n } else {\n output.push(<p key={index} className={blockClass} style={style}>{children.length ? children : <br />}</p>);\n }\n index++;\n }\n return <div className={cn(\"puzzle-text-renderer\", className)}>{output}</div>;\n};\n\nexport { TextRenderer };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-renderer.js","names":[],"sources":["../../../../src/components/editors/text-editor/text-renderer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport \"./text-editor.css\";\nimport type { TextBlock, TextDocument, TextMark } from \"./text-editor.types\";\n\nexport type TextRendererProps = { document: TextDocument; className?: string };\n\nconst MARK_COMPONENTS: Record<TextMark, (children: ReactNode) => ReactNode> = {\n bold: (children) => <strong>{children}</strong>,\n italic: (children) => <em>{children}</em>,\n underline: (children) => <u>{children}</u>,\n strike: (children) => <s>{children}</s>,\n};\n\nconst renderInline = (block: TextBlock, blockIndex: number): ReactNode[] =>\n block.children.map((inline, inlineIndex) => {\n const parts = inline.text.split(\"\\n\");\n let node: ReactNode = parts.flatMap((part, partIndex) => partIndex === 0\n ? [part]\n : [<br key={`break-${blockIndex}-${inlineIndex}-${partIndex}`} />, part]);\n for (const mark of [...(inline.marks ?? [])].reverse()) node = MARK_COMPONENTS[mark](node);\n return <span key={`${blockIndex}-${inlineIndex}`}>{node}</span>;\n });\n\nconst HEADING_TAGS = [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"] as const;\n\n// Without an explicit level, fall back to the level implied by the variant.\nconst getHeadingTag = (block: TextBlock): (typeof HEADING_TAGS)[number] => {\n if (block.headingLevel) return HEADING_TAGS[block.headingLevel - 1]
|
|
1
|
+
{"version":3,"file":"text-renderer.js","names":[],"sources":["../../../../src/components/editors/text-editor/text-renderer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport \"./text-editor.css\";\nimport type { TextBlock, TextDocument, TextMark } from \"./text-editor.types\";\n\nexport type TextRendererProps = { document: TextDocument; className?: string };\n\nconst MARK_COMPONENTS: Record<TextMark, (children: ReactNode) => ReactNode> = {\n bold: (children) => <strong>{children}</strong>,\n italic: (children) => <em>{children}</em>,\n underline: (children) => <u>{children}</u>,\n strike: (children) => <s>{children}</s>,\n};\n\nconst renderInline = (block: TextBlock, blockIndex: number): ReactNode[] =>\n block.children.map((inline, inlineIndex) => {\n const parts = inline.text.split(\"\\n\");\n let node: ReactNode = parts.flatMap((part, partIndex) => partIndex === 0\n ? [part]\n : [<br key={`break-${blockIndex}-${inlineIndex}-${partIndex}`} />, part]);\n for (const mark of [...(inline.marks ?? [])].reverse()) node = MARK_COMPONENTS[mark](node);\n return <span key={`${blockIndex}-${inlineIndex}`}>{node}</span>;\n });\n\nconst HEADING_TAGS = [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"] as const;\n\n// Without an explicit level, fall back to the level implied by the variant.\nconst getHeadingTag = (block: TextBlock): (typeof HEADING_TAGS)[number] => {\n if (block.headingLevel) return HEADING_TAGS[block.headingLevel - 1]!;\n\n switch (block.variant) {\n case \"display1\": case \"headline1\": return \"h1\";\n case \"display2\": case \"headline2\": return \"h2\";\n case \"headline3\": return \"h3\";\n default: return \"h4\";\n }\n};\n\nconst TextRenderer = ({ document, className }: TextRendererProps) => {\n const blocks = document.content;\n const output: ReactNode[] = [];\n let index = 0;\n while (index < blocks.length) {\n const block = blocks[index]!;\n if (block.listType) {\n const listType = block.listType;\n const items: ReactNode[] = [];\n while (index < blocks.length && blocks[index]!.listType === listType) {\n const item = blocks[index]!;\n const itemChildren = renderInline(item, index);\n items.push(<li key={index} className={cn(\"puzzle-text-renderer__block\", `puzzle-typography-${item.variant}`)} style={{ textAlign: item.align }}>\n {itemChildren.length ? itemChildren : <br />}\n </li>);\n index++;\n }\n const List = listType === \"ordered\" ? \"ol\" : \"ul\";\n output.push(<List key={`list-${index}`} className=\"puzzle-text-renderer__list\">{items}</List>);\n continue;\n }\n const blockClass = cn(\"puzzle-text-renderer__block\", `puzzle-typography-${block.variant}`);\n const children = renderInline(block, index);\n const style = { textAlign: block.align };\n if (block.type === \"heading\") {\n const HeadingTag = getHeadingTag(block);\n output.push(<HeadingTag key={index} className={blockClass} style={style}>{children.length ? children : <br />}</HeadingTag>);\n } else {\n output.push(<p key={index} className={blockClass} style={style}>{children.length ? children : <br />}</p>);\n }\n index++;\n }\n return <div className={cn(\"puzzle-text-renderer\", className)}>{output}</div>;\n};\n\nexport { TextRenderer };\n"],"mappings":";;;;AAOA,MAAM,kBAAwE;CAC5E,OAAO,aAAa,oBAAC,UAAD,EAAS,SAAiB,CAAA;CAC9C,SAAS,aAAa,oBAAC,MAAD,EAAK,SAAa,CAAA;CACxC,YAAY,aAAa,oBAAC,KAAD,EAAI,SAAY,CAAA;CACzC,SAAS,aAAa,oBAAC,KAAD,EAAI,SAAY,CAAA;AACxC;AAEA,MAAM,gBAAgB,OAAkB,eACtC,MAAM,SAAS,KAAK,QAAQ,gBAAgB;CAE1C,IAAI,OADU,OAAO,KAAK,MAAM,IACN,CAAC,CAAC,SAAS,MAAM,cAAc,cAAc,IACnE,CAAC,IAAI,IACL,CAAC,oBAAC,MAAD,CAA6D,GAApD,SAAS,WAAW,GAAG,YAAY,GAAG,WAAc,GAAG,IAAI,CAAC;CAC1E,KAAK,MAAM,QAAQ,CAAC,GAAI,OAAO,SAAS,CAAC,CAAE,CAAC,CAAC,QAAQ,GAAG,OAAO,gBAAgB,KAAK,CAAC,IAAI;CACzF,OAAO,oBAAC,QAAD,EAAA,UAA4C,KAAW,GAA5C,GAAG,WAAW,GAAG,aAA2B;AAChE,CAAC;AAEH,MAAM,eAAe;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI;AAGxD,MAAM,iBAAiB,UAAoD;CACzE,IAAI,MAAM,cAAc,OAAO,aAAa,MAAM,eAAe;CAEjE,QAAQ,MAAM,SAAd;EACE,KAAK;EAAY,KAAK,aAAa,OAAO;EAC1C,KAAK;EAAY,KAAK,aAAa,OAAO;EAC1C,KAAK,aAAa,OAAO;EACzB,SAAS,OAAO;CAClB;AACF;AAEA,MAAM,gBAAgB,EAAE,UAAU,gBAAmC;CACnE,MAAM,SAAS,SAAS;CACxB,MAAM,SAAsB,CAAC;CAC7B,IAAI,QAAQ;CACZ,OAAO,QAAQ,OAAO,QAAQ;EAC5B,MAAM,QAAQ,OAAO;EACrB,IAAI,MAAM,UAAU;GAClB,MAAM,WAAW,MAAM;GACvB,MAAM,QAAqB,CAAC;GAC5B,OAAO,QAAQ,OAAO,UAAU,OAAO,MAAM,CAAE,aAAa,UAAU;IACpE,MAAM,OAAO,OAAO;IACpB,MAAM,eAAe,aAAa,MAAM,KAAK;IAC7C,MAAM,KAAK,oBAAC,MAAD;KAAgB,WAAW,GAAG,+BAA+B,qBAAqB,KAAK,SAAS;KAAG,OAAO,EAAE,WAAW,KAAK,MAAM;KAC1I,UAAA,aAAa,SAAS,eAAe,oBAAC,MAAD,CAAK,CAAA;IACzC,GAFgB,KAEhB,CAAC;IACL;GACF;GACA,MAAM,OAAO,aAAa,YAAY,OAAO;GAC7C,OAAO,KAAK,oBAAC,MAAD;IAA4B,WAAU;IAA8B,UAAA;GAAY,GAArE,QAAQ,OAA6D,CAAC;GAC7F;EACF;EACA,MAAM,aAAa,GAAG,+BAA+B,qBAAqB,MAAM,SAAS;EACzF,MAAM,WAAW,aAAa,OAAO,KAAK;EAC1C,MAAM,QAAQ,EAAE,WAAW,MAAM,MAAM;EACvC,IAAI,MAAM,SAAS,WAAW;GAC5B,MAAM,aAAa,cAAc,KAAK;GACtC,OAAO,KAAK,oBAAC,YAAD;IAAwB,WAAW;IAAmB;IAAQ,UAAA,SAAS,SAAS,WAAW,oBAAC,MAAD,CAAK,CAAA;GAAc,GAA7F,KAA6F,CAAC;EAC7H,OACE,OAAO,KAAK,oBAAC,KAAD;GAAe,WAAW;GAAmB;GAAQ,UAAA,SAAS,SAAS,WAAW,oBAAC,MAAD,CAAK,CAAA;EAAK,GAApF,KAAoF,CAAC;EAE3G;CACF;CACA,OAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,wBAAwB,SAAS;EAAI,UAAA;CAAY,CAAA;AAC7E"}
|