@liveblocks/react-ui
Version:
A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.
1 lines • 63.3 kB
Source Map (JSON)
{"version":3,"file":"Markdown.cjs","sources":["../../src/primitives/Markdown.tsx"],"sourcesContent":["import { assertNever, isUrl, type Relax, sanitizeUrl } from \"@liveblocks/core\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport {\n Lexer,\n type MarkedToken,\n type Token as DefaultToken,\n type Tokens,\n} from \"marked\";\nimport {\n type ComponentType,\n forwardRef,\n memo,\n type ReactNode,\n useMemo,\n} from \"react\";\n\nimport type { ComponentPropsWithSlot } from \"../types\";\n\nconst LIST_ITEM_CHECKBOX_REGEX = /^\\[\\s?(x)?\\]?$/i;\nconst PARTIAL_LINK_IMAGE_REGEX =\n /(?<!\\\\)(?<image>!)?\\[(?!\\^)(?<text>[^\\]]*)(?:\\](?:\\((?<url>[^)]*)?)?)?$/;\nconst PARTIAL_TABLE_HEADER_REGEX =\n /^\\s*\\|(?:[^|\\n]+(?:\\|[^|\\n]+)*?)?\\|?\\s*(?:\\n\\s*\\|\\s*[-:|\\s]*\\s*)?$/;\nconst PARTIAL_EMOJI_REGEX =\n /(?:\\u200D|\\uFE0F|\\u20E3|\\p{Regional_Indicator}|\\p{Emoji_Presentation}|\\p{Emoji_Modifier_Base}|\\p{Emoji_Modifier})+$/u;\nconst TRAILING_NON_WHITESPACE_REGEX = /^\\S*/;\nconst WHITESPACE_REGEX = /\\s/;\nconst NEWLINE_REGEX = /\\r\\n?/g;\nconst BUFFERED_CHARACTERS_REGEX =\n /(?<!\\\\)((\\*+|_+|~+|`+|\\++|-{0,2}|={0,2}|\\\\|!|<\\/?)\\s*)$/;\nconst SINGLE_CHARACTER_REGEX = /^\\s*(\\S\\s*)$/;\nconst LEFT_ANGLE_BRACKET_REGEX = /</g;\nconst RIGHT_ANGLE_BRACKET_REGEX = />/g;\nconst AMPERSAND_REGEX = /&(?!#?[0-9A-Za-z]+;)/g;\nconst DEFAULT_PARTIAL_LINK_URL = \"#\";\n\ntype CheckboxToken = {\n type: \"checkbox\";\n checked: boolean;\n raw: string;\n};\n\ntype Token = MarkedToken | CheckboxToken;\n\ntype AnyToken = Token | DefaultToken;\n\ntype PotentiallyPartialToken = Relax<\n | Tokens.Text\n | Tokens.Paragraph\n | Tokens.Heading\n | Tokens.Blockquote\n | Tokens.ListItem\n | Tokens.TableCell\n | Tokens.Code\n>;\n\nexport type MarkdownComponents = {\n /**\n * The component used to render paragraphs.\n *\n * @example\n * ```md\n * A paragraph.\n *\n * Another paragraph.\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Paragraph: ({ children }) => <p className=\"...\">{children}</p>\n * }}\n * />\n * ```\n */\n Paragraph: ComponentType<MarkdownComponentsParagraphProps>;\n\n /**\n * The component used to render inline elements (bold, italic, strikethrough, and inline code).\n *\n * @example\n * ```md\n * **Bold**, _italic_, ~~strikethrough~~, and `inline code`.\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Inline: ({ type, children }) => {\n * const Component = type;\n * return <Component className=\"...\">{children}</Component>;\n * }\n * }}\n * />\n * ```\n */\n Inline: ComponentType<MarkdownComponentsInlineProps>;\n\n /**\n * The component used to render links.\n *\n * @example\n * ```md\n * A [link](https://liveblocks.io).\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Link: ({ href, children }) => <a href={href} className=\"...\">{children}</a>\n * }}\n * />\n * ```\n */\n Link: ComponentType<MarkdownComponentsLinkProps>;\n\n /**\n * The component used to render headings.\n *\n * @example\n * ```md\n * # Heading 1\n * ## Heading 2\n * ### Heading 3\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Heading: ({ level, children }) => {\n * const Heading = `h${level}` as const;\n * return <Heading className=\"...\">{children}</Heading>;\n * }\n * }}\n * />\n * ```\n */\n Heading: ComponentType<MarkdownComponentsHeadingProps>;\n\n /**\n * The component used to render blockquotes.\n *\n * @example\n * ```md\n * > A blockquote.\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Blockquote: ({ children }) => <blockquote className=\"...\">{children}</blockquote>\n * }}\n * />\n * ```\n */\n Blockquote: ComponentType<MarkdownComponentsBlockquoteProps>;\n\n /**\n * The component used to render code blocks.\n *\n * @example\n * ```md\n * ```javascript\n * const a = 1;\n * ```\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * CodeBlock: ({ language, code }) => (\n * <pre data-language={language} className=\"...\">\n * <code className=\"...\">{code}</code>\n * </pre>\n * )\n * }}\n * />\n * ```\n */\n CodeBlock: ComponentType<MarkdownComponentsCodeBlockProps>;\n\n /**\n * The component used to render images.\n *\n * @example\n * ```md\n * \n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Image: ({ src, alt }) => <img src={src} alt={alt} className=\"...\">\n * }}\n * />\n * ```\n */\n Image: ComponentType<MarkdownComponentsImageProps>;\n\n /**\n * The component used to render lists.\n *\n * @example\n * ```md\n * 1. An ordered list item\n * - An unordered list item\n * - [x] A checked list item\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * List: ({ type, items, start }) => {\n * const List = type === \"ordered\" ? \"ol\" : \"ul\";\n * return (\n * <List start={start}>\n * {items.map((item, index) => (\n * <li key={index}>\n * {item.children}\n * </li>\n * ))}\n * </List>\n * );\n * }\n * }}\n * />\n * ```\n */\n List: ComponentType<MarkdownComponentsListProps>;\n\n /**\n * The component used to render tables.\n *\n * @example\n * ```md\n * | Heading 1 | Heading 2 |\n * |-----------|-----------|\n * | Cell 1 | Cell 2 |\n * | Cell 3 | Cell 4 |\n * ```\n * ```tsx\n * <Markdown\n * components={{\n * Table: ({ headings, rows }) => (\n * <table>\n * <thead>\n * <tr>\n * {headings.map(({ children }, index) => (\n * <th key={index}>{children}</th>\n * ))}\n * </tr>\n * </thead>\n * <tbody>\n * {rows.map((row, index) => (\n * <tr key={index}>\n * {row.map(({ children }, index) => (\n * <td key={index}>{children}</td>\n * ))}\n * </tr>\n * ))}\n * </tbody>\n * </table>\n * )\n * }}\n * />\n * ```\n */\n Table: ComponentType<MarkdownComponentsTableProps>;\n\n /**\n * The component used to render separators.\n *\n * @example\n * ```md\n * ---\n * ```\n * ```tsx\n * <Markdown components={{ Separator: () => <hr className=\"...\" /> }} />\n * ```\n */\n Separator: ComponentType;\n};\n\nexport interface MarkdownComponentsInlineProps {\n type: \"strong\" | \"em\" | \"code\" | \"del\";\n children: ReactNode;\n}\n\nexport interface MarkdownComponentsParagraphProps {\n children: ReactNode;\n}\n\ninterface MarkdownComponentsTableCell {\n align?: \"left\" | \"center\" | \"right\";\n children: ReactNode;\n}\n\nexport interface MarkdownComponentsTableProps {\n headings: MarkdownComponentsTableCell[];\n rows: MarkdownComponentsTableCell[][];\n}\n\ninterface MarkdownComponentsListItem {\n checked?: boolean;\n children: ReactNode;\n}\n\nexport type MarkdownComponentsListProps = Relax<\n MarkdownComponentsOrderedListProps | MarkdownComponentsUnorderedListProps\n>;\n\ninterface MarkdownComponentsOrderedListProps {\n type: \"ordered\";\n items: MarkdownComponentsListItem[];\n start: number;\n}\n\ninterface MarkdownComponentsUnorderedListProps {\n type: \"unordered\";\n items: MarkdownComponentsListItem[];\n}\n\nexport interface MarkdownComponentsBlockquoteProps {\n children: ReactNode;\n}\n\nexport interface MarkdownComponentsImageProps {\n src: string;\n alt: string;\n title?: string;\n}\n\nexport interface MarkdownComponentsHeadingProps {\n level: 1 | 2 | 3 | 4 | 5 | 6;\n children: ReactNode;\n}\n\nexport interface MarkdownComponentsLinkProps {\n href: string;\n title?: string;\n children: ReactNode;\n}\n\nexport interface MarkdownComponentsCodeBlockProps {\n code: string;\n language?: string;\n}\n\nexport interface MarkdownProps extends ComponentPropsWithSlot<\"div\"> {\n content: string;\n partial?: boolean;\n components?: Partial<MarkdownComponents>;\n}\n\nconst defaultComponents: MarkdownComponents = {\n Paragraph: ({ children }) => {\n return <p>{children}</p>;\n },\n Inline: ({ type, children }) => {\n switch (type) {\n case \"strong\":\n return <strong>{children}</strong>;\n case \"em\":\n return <em>{children}</em>;\n case \"code\":\n return <code>{children}</code>;\n case \"del\":\n return <del>{children}</del>;\n default:\n assertNever(type, \"Unknown inline type\");\n }\n },\n CodeBlock: ({ language, code }) => {\n return (\n <pre data-language={language ?? undefined}>\n <code>{code}</code>\n </pre>\n );\n },\n Link: ({ href, title, children }) => {\n return (\n <a href={href} title={title} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n },\n Heading: ({ level, children }) => {\n const Heading = `h${level}` as const;\n\n return <Heading>{children}</Heading>;\n },\n Image: ({ src, alt, title }) => {\n return <img src={src} alt={alt} title={title} />;\n },\n Blockquote: ({ children }) => {\n return <blockquote>{children}</blockquote>;\n },\n Table: ({ headings, rows }) => {\n return (\n <table>\n <thead>\n <tr>\n {headings.map((heading, index) => {\n return (\n <th key={index} align={heading.align}>\n {heading.children}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, index) => {\n return (\n <tr key={index}>\n {row.map((cell, index) => {\n return (\n <td key={index} align={cell.align}>\n {cell.children}\n </td>\n );\n })}\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n },\n List: ({ type, items, start }) => {\n const List = type === \"ordered\" ? \"ol\" : \"ul\";\n\n return (\n <List start={start === 1 ? undefined : start}>\n {items.map((item, index) => (\n <li key={index}>{item.children}</li>\n ))}\n </List>\n );\n },\n Separator: () => {\n return <hr />;\n },\n};\n\nexport const Markdown = forwardRef<HTMLDivElement, MarkdownProps>(\n ({ content, partial, components, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const tokens = useMemo(() => {\n if (!content) {\n return [];\n }\n\n return partial ? tokenizePartial(content) : tokenize(content);\n }, [content, partial]);\n\n return (\n <Component {...props} ref={forwardedRef}>\n {tokens.map((token, index) => {\n return (\n <MemoizedMarkdownToken\n token={token}\n key={index}\n components={components}\n partial={partial}\n />\n );\n })}\n </Component>\n );\n }\n);\n\nconst MemoizedMarkdownToken = memo(\n ({\n token,\n components,\n }: {\n token: Token;\n components?: Partial<MarkdownComponents>;\n partial?: boolean;\n }) => {\n return <MarkdownToken token={token} components={components} />;\n },\n (previousProps, nextProps) => {\n const previousToken = previousProps.token;\n const nextToken = nextProps.token;\n\n // 1️⃣ Start with the fastest comparisons\n if (\n previousToken.type !== nextToken.type ||\n previousProps.partial !== nextProps.partial\n ) {\n return false;\n }\n\n let previousContent = previousToken.raw;\n let nextContent = nextToken.raw;\n\n if (\"text\" in previousToken && \"text\" in nextToken) {\n previousContent = previousToken.text;\n nextContent = nextToken.text;\n }\n\n // 2️⃣ Then only compare the tokens' content lengths first\n if (previousContent.length !== nextContent.length) {\n return false;\n }\n\n // 3️⃣ And finally compare the actual tokens' content\n return previousContent === nextContent;\n }\n);\n\nexport function MarkdownToken({\n token,\n components,\n}: {\n token: Token;\n components: Partial<MarkdownComponents> | undefined;\n}) {\n switch (token.type) {\n case \"escape\": {\n return token.text;\n }\n\n case \"space\": {\n return null;\n }\n\n case \"text\": {\n if (token.tokens !== undefined) {\n return <MarkdownTokens tokens={token.tokens} components={components} />;\n } else {\n return parseHtmlEntities(token.text);\n }\n }\n\n case \"br\": {\n return <br />;\n }\n\n case \"paragraph\": {\n const Paragraph = components?.Paragraph ?? defaultComponents.Paragraph;\n\n return (\n <Paragraph>\n <MarkdownTokens tokens={token.tokens} components={components} />\n </Paragraph>\n );\n }\n\n case \"heading\": {\n const Heading = components?.Heading ?? defaultComponents.Heading;\n\n return (\n <Heading level={clampHeadingLevel(token.depth)}>\n <MarkdownTokens tokens={token.tokens} components={components} />\n </Heading>\n );\n }\n\n case \"strong\": {\n const Inline = components?.Inline ?? defaultComponents.Inline;\n\n return (\n <Inline type=\"strong\">\n <MarkdownTokens tokens={token.tokens} components={components} />\n </Inline>\n );\n }\n\n case \"em\": {\n const Inline = components?.Inline ?? defaultComponents.Inline;\n\n return (\n <Inline type=\"em\">\n <MarkdownTokens tokens={token.tokens} components={components} />\n </Inline>\n );\n }\n\n case \"codespan\": {\n const Inline = components?.Inline ?? defaultComponents.Inline;\n\n return <Inline type=\"code\">{parseHtmlEntities(token.text)}</Inline>;\n }\n\n case \"del\": {\n const Inline = components?.Inline ?? defaultComponents.Inline;\n\n return (\n <Inline type=\"del\">\n <MarkdownTokens tokens={token.tokens} components={components} />\n </Inline>\n );\n }\n\n case \"link\": {\n const href = sanitizeUrl(token.href);\n\n if (href === null) {\n return <MarkdownTokens tokens={token.tokens} components={components} />;\n }\n\n const Link = components?.Link ?? defaultComponents.Link;\n\n return (\n <Link href={href} title={token.title ?? undefined}>\n <MarkdownTokens tokens={token.tokens} components={components} />\n </Link>\n );\n }\n\n case \"code\": {\n let language: string | undefined = undefined;\n if (token.lang !== undefined) {\n language =\n token.lang.match(TRAILING_NON_WHITESPACE_REGEX)?.[0] ?? undefined;\n }\n\n const CodeBlock = components?.CodeBlock ?? defaultComponents.CodeBlock;\n\n return <CodeBlock language={language} code={token.text || \" \"} />;\n }\n\n case \"blockquote\": {\n const Blockquote = components?.Blockquote ?? defaultComponents.Blockquote;\n\n return (\n <Blockquote>\n <MarkdownTokens\n tokens={token.tokens}\n components={components}\n normalizeToBlockTokens\n />\n </Blockquote>\n );\n }\n\n case \"list\": {\n const List = components?.List ?? defaultComponents.List;\n const items: MarkdownComponentsListItem[] = token.items.map((item) => {\n let tokens = item.tokens;\n\n if (item.task) {\n tokens = [\n {\n type: \"checkbox\",\n checked: Boolean(item.checked),\n raw: `[${item.checked ? \"x\" : \" \"}]`,\n },\n ...tokens,\n ];\n }\n\n return {\n checked: item.task ? item.checked : undefined,\n children: (\n <MarkdownTokens\n tokens={tokens}\n components={components}\n normalizeToBlockTokens={\n // A non-loose list item doesn't need to be wrapped in block tokens.\n item.tokens.length > 0 ? item.loose : false\n }\n />\n ),\n };\n });\n\n const props: MarkdownComponentsListProps = token.ordered\n ? { type: \"ordered\", items, start: token.start || 1 }\n : { type: \"unordered\", items };\n\n return <List {...props} />;\n }\n\n case \"checkbox\": {\n return (\n <>\n <input type=\"checkbox\" disabled checked={token.checked} />{\" \"}\n </>\n );\n }\n\n case \"table\": {\n const Table = components?.Table ?? defaultComponents.Table;\n const headings: MarkdownComponentsTableCell[] = token.header.map(\n (cell) => ({\n align: cell.align ?? undefined,\n children: (\n <MarkdownTokens tokens={cell.tokens} components={components} />\n ),\n })\n );\n\n const rows: MarkdownComponentsTableCell[][] = token.rows.map((row) =>\n row.map((cell) => ({\n align: cell.align ?? undefined,\n children: (\n <MarkdownTokens tokens={cell.tokens} components={components} />\n ),\n }))\n );\n\n return <Table headings={headings} rows={rows} />;\n }\n\n case \"image\": {\n const href = sanitizeUrl(token.href);\n\n if (href === null) {\n return token.text;\n }\n\n const Image = components?.Image ?? defaultComponents.Image;\n\n return (\n <Image src={href} alt={token.text} title={token.title ?? undefined} />\n );\n }\n\n case \"hr\": {\n const Separator = components?.Separator ?? defaultComponents.Separator;\n\n return <Separator />;\n }\n\n case \"html\": {\n return parseHtmlEntities(token.text);\n }\n\n default: {\n return null;\n }\n }\n}\n\nfunction MarkdownTokens({\n tokens,\n components,\n normalizeToBlockTokens = false,\n}: {\n tokens: AnyToken[];\n components: Partial<MarkdownComponents> | undefined;\n normalizeToBlockTokens?: boolean;\n}) {\n assertTokens(tokens);\n\n let normalizedTokens: Token[] = [];\n\n if (normalizeToBlockTokens) {\n let leadingCheckboxToken =\n tokens[0]?.type === \"checkbox\" ? tokens[0] : null;\n\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]!;\n\n switch (token.type) {\n case \"text\": {\n const paragraphTextTokens: Tokens.Text[] = [token];\n\n // Wrap consecutive text tokens into a paragraph.\n while (i + 1 < tokens.length && tokens[i + 1]!.type === \"text\") {\n i++;\n paragraphTextTokens.push(tokens[i] as Tokens.Text);\n }\n\n const paragraphRaw = paragraphTextTokens\n .map((text) => text.raw)\n .join(\"\");\n const paragraphText = paragraphTextTokens\n .map((text) => text.text)\n .join(\"\");\n\n // When wrapping loose task list items into paragraphs, we need to\n // move the checkbox into the first paragraph.\n normalizedTokens.push({\n type: \"paragraph\",\n tokens: leadingCheckboxToken\n ? [leadingCheckboxToken, ...paragraphTextTokens]\n : paragraphTextTokens,\n raw: paragraphRaw,\n text: paragraphText,\n } satisfies Tokens.Paragraph);\n leadingCheckboxToken = null;\n\n break;\n }\n\n case \"checkbox\":\n break;\n\n default: {\n normalizedTokens.push(token);\n }\n }\n }\n } else {\n normalizedTokens = tokens;\n }\n\n return normalizedTokens.map((token, index) => (\n <MarkdownToken key={index} token={token} components={components} />\n ));\n}\n\n/**\n * Marked.js' `Token` union type includes a `Generic` token type which is\n * too broad and makes narrowing difficult, we don't use generic/custom tokens\n * so we can assert the `Generic` type away.\n */\nfunction assertTokens(_: AnyToken): asserts _ is Token;\nfunction assertTokens(_: AnyToken[]): asserts _ is Token[];\nfunction assertTokens(_: AnyToken | AnyToken[]): asserts _ is Token | Token[] {}\n\nfunction isBlockToken(\n token: Token | Tokens.Generic\n): token is\n | Tokens.Paragraph\n | Tokens.Heading\n | Tokens.Blockquote\n | Tokens.ListItem {\n return (\n token.type === \"paragraph\" ||\n token.type === \"heading\" ||\n token.type === \"blockquote\" ||\n token.type === \"list_item\"\n );\n}\n\nfunction tokenize(markdown: string) {\n return new Lexer().lex(markdown) as Token[];\n}\n\nfunction tokenizePartial(markdown: string) {\n const preprocessedContent = trimPartialMarkdown(normalizeNewlines(markdown));\n\n const tokens = tokenize(preprocessedContent);\n\n try {\n return completePartialTokens(tokens);\n } catch {\n return tokens;\n }\n}\n\n/**\n * Find the last partial token that we could potentially complete.\n */\nfunction findPotentiallyPartialToken(\n tokens: AnyToken[],\n parentToken?: PotentiallyPartialToken\n): PotentiallyPartialToken | undefined {\n if (tokens.length === 0) {\n return parentToken;\n }\n\n assertTokens(tokens);\n\n const lastIndex = tokens.length - 1;\n let lastToken = tokens[lastIndex]!;\n\n if (lastToken.type === \"space\") {\n const penultimateToken = tokens[lastIndex - 1];\n\n if (!penultimateToken) {\n return parentToken;\n }\n\n lastToken = penultimateToken;\n }\n\n if (lastToken.type === \"list\") {\n const listToken = lastToken;\n const lastListItem = listToken.items[listToken.items.length - 1];\n\n if (!lastListItem) {\n return parentToken;\n }\n\n const lastListItemTokens = lastListItem.tokens as Token[];\n\n // List items containing empty lines are handled differently,\n // instead of using the list item's tokens, we use the last one\n // if it's a text or block token.\n if (\n lastListItemTokens.some((token) => token.type === \"space\") &&\n lastListItemTokens.length > 0\n ) {\n const lastListItemLastToken =\n lastListItemTokens[lastListItemTokens.length - 1];\n\n if (lastListItemLastToken) {\n if (lastListItemLastToken.type === \"text\") {\n return lastListItemLastToken;\n }\n\n if (isBlockToken(lastListItemLastToken)) {\n return findPotentiallyPartialToken(\n lastListItemLastToken.tokens,\n lastListItemLastToken\n );\n }\n\n return undefined;\n }\n }\n\n return findPotentiallyPartialToken(lastListItem.tokens, lastListItem);\n }\n\n if (lastToken.type === \"table\") {\n const tableToken = lastToken;\n const lastTableRow = tableToken.rows[tableToken.rows.length - 1];\n\n if (!lastTableRow) {\n return parentToken;\n }\n\n // Marked.js creates all cells in advance when creating rows,\n // we want the cell where the end currently is.\n const firstEmptyTableCellIndex = lastTableRow.findIndex(\n (cell) => cell.tokens.length === 0\n );\n const lastNonEmptyTableCell =\n firstEmptyTableCellIndex === -1\n ? undefined\n : firstEmptyTableCellIndex === 0\n ? lastTableRow[firstEmptyTableCellIndex]\n : lastTableRow[firstEmptyTableCellIndex - 1];\n\n if (!lastNonEmptyTableCell) {\n return parentToken;\n }\n\n return findPotentiallyPartialToken(\n lastNonEmptyTableCell.tokens,\n lastNonEmptyTableCell\n );\n }\n\n if (isBlockToken(lastToken)) {\n return findPotentiallyPartialToken(lastToken.tokens, lastToken);\n }\n\n return parentToken;\n}\n\nfunction normalizeNewlines(string: string) {\n return string.replace(NEWLINE_REGEX, \"\\n\");\n}\n\n/**\n * Trim a partial Markdown string to avoid incomplete tokens.\n */\nfunction trimPartialMarkdown(markdown: string) {\n const lines = markdown.split(\"\\n\");\n\n if (lines.length === 0) {\n return markdown;\n }\n\n // If the last line contains a single non-whitespace character,\n // we can remove it for now.\n const [singleCharacterMatch] =\n lines[lines.length - 1]!.match(SINGLE_CHARACTER_REGEX) ?? [];\n\n if (singleCharacterMatch) {\n lines[lines.length - 1] = lines[lines.length - 1]!.slice(\n 0,\n -singleCharacterMatch.length\n );\n\n return lines.join(\"\\n\");\n }\n\n // If the last line ends with partial syntax, we can remove it for now.\n const [bufferedCharactersMatch] =\n lines[lines.length - 1]!.match(BUFFERED_CHARACTERS_REGEX) ?? [];\n\n if (bufferedCharactersMatch) {\n lines[lines.length - 1] = lines[lines.length - 1]!.slice(\n 0,\n -bufferedCharactersMatch.length\n );\n\n return lines.join(\"\\n\");\n }\n\n return markdown;\n}\n\n/**\n * Optimistically complete a Markdown string of inline content:\n *\n * - Bold, italic, strikethrough, and inline code\n * - Links\n *\n * Remove any remaining partial content:\n *\n * - Emoji\n */\nfunction completePartialInlineMarkdown(\n markdown: string,\n options: { allowLinksImages?: boolean } = {}\n): string {\n const stack: { string: string; length: number; index: number }[] = [];\n const allowLinksImages = options.allowLinksImages ?? true;\n let completedMarkdown = markdown;\n\n // Trim any partial emoji.\n //\n // We do this here rather than in `trimPartialMarkdown` because\n // `trimPartialMarkdown` needs to run before Marked.js to prevent\n // it from parsing partial Markdown syntax, emojis won't be parsed\n // by Marked.js so we can trim them here to be a bit more efficient.\n const partialEmojiMatch = completedMarkdown.match(PARTIAL_EMOJI_REGEX);\n\n if (partialEmojiMatch) {\n const partialEmoji = partialEmojiMatch[0];\n completedMarkdown = completedMarkdown.slice(0, -partialEmoji.length);\n\n // If the removed partial emoji contains a special modifier (VS16 or keycap),\n // we also remove the preceding code point.\n if (partialEmoji.includes(\"\\uFE0F\") || partialEmoji.includes(\"\\u20E3\")) {\n const codepoints = Array.from(completedMarkdown);\n\n if (codepoints.length > 0) {\n completedMarkdown = codepoints.slice(0, -1).join(\"\");\n }\n }\n }\n\n // Move forward through the string to collect delimiters.\n for (let i = 0; i < completedMarkdown.length; i++) {\n const character = completedMarkdown[i]!;\n const isEscaped = i > 0 ? completedMarkdown[i - 1] === \"\\\\\" : false;\n\n if (isEscaped) {\n continue;\n }\n\n if (character === \"`\") {\n const lastDelimiter = stack[stack.length - 1];\n const isClosingPreviousDelimiter =\n lastDelimiter?.string === \"`\" && i > lastDelimiter.index;\n\n if (isClosingPreviousDelimiter) {\n // If the delimiter is closing a previous delimiter,\n // we remove it from the stack.\n stack.pop();\n } else {\n const characterAfterDelimiter = completedMarkdown[i + 1];\n\n // If the delimiter is opening and is followed by a\n // non-whitespace character, we add it to the stack.\n if (\n characterAfterDelimiter &&\n !WHITESPACE_REGEX.test(characterAfterDelimiter)\n ) {\n stack.push({ string: \"`\", length: 1, index: i });\n }\n }\n\n continue;\n }\n\n if (character === \"*\" || character === \"_\" || character === \"~\") {\n const isInsideInlineCode = stack[stack.length - 1]?.string === \"`\";\n\n let j = i;\n while (\n j < completedMarkdown.length &&\n completedMarkdown[j] === character\n ) {\n j++;\n }\n const consecutiveDelimiterCharacters = j - i;\n\n // Delimiters inside inline code shouldn't be closed so we skip them.\n if (isInsideInlineCode) {\n i += consecutiveDelimiterCharacters - 1;\n\n continue;\n }\n\n let remainingConsecutiveDelimiterCharacters =\n consecutiveDelimiterCharacters;\n let consecutiveDelimiterCharacterIndex = 0;\n\n while (remainingConsecutiveDelimiterCharacters > 0) {\n const lastDelimiter = stack[stack.length - 1];\n\n if (!lastDelimiter || lastDelimiter.string[0] !== character) {\n break;\n }\n\n // We close as many matching open delimiters as possible from the stack.\n if (remainingConsecutiveDelimiterCharacters >= lastDelimiter.length) {\n stack.pop();\n remainingConsecutiveDelimiterCharacters -= lastDelimiter.length;\n consecutiveDelimiterCharacterIndex += lastDelimiter.length;\n\n continue;\n }\n\n break;\n }\n\n if (remainingConsecutiveDelimiterCharacters > 0) {\n // If there are any unmatched delimiters at the end of the string,\n // we can remove them from the string.\n if (i + consecutiveDelimiterCharacters >= completedMarkdown.length) {\n completedMarkdown = completedMarkdown.slice(\n 0,\n completedMarkdown.length - remainingConsecutiveDelimiterCharacters\n );\n\n break;\n }\n\n const characterAfterDelimiters =\n completedMarkdown[i + consecutiveDelimiterCharacters];\n\n if (\n characterAfterDelimiters &&\n !WHITESPACE_REGEX.test(characterAfterDelimiters)\n ) {\n let delimiterStartIndex = i + consecutiveDelimiterCharacterIndex;\n\n // If there's an odd number of unmatched delimiters,\n // we match a single-character delimiter.\n if (remainingConsecutiveDelimiterCharacters % 2 === 1) {\n stack.push({\n string: character,\n length: 1,\n index: delimiterStartIndex,\n });\n delimiterStartIndex += 1;\n remainingConsecutiveDelimiterCharacters -= 1;\n }\n\n // If there are any unmatched delimiters remaining,\n // we match double-character delimiters.\n while (remainingConsecutiveDelimiterCharacters >= 2) {\n stack.push({\n string: character + character,\n length: 2,\n index: delimiterStartIndex,\n });\n delimiterStartIndex += 2;\n remainingConsecutiveDelimiterCharacters -= 2;\n }\n }\n }\n\n i += consecutiveDelimiterCharacters - 1;\n\n continue;\n }\n }\n\n if (allowLinksImages) {\n const partialLinkImageMatch = completedMarkdown.match(\n PARTIAL_LINK_IMAGE_REGEX\n );\n\n if (partialLinkImageMatch) {\n const linkImageStartIndex = partialLinkImageMatch.index!;\n const linkImageEndIndex =\n linkImageStartIndex + partialLinkImageMatch[0].length;\n\n const isInsideInlineCode = stack.some(\n (delimiter) =>\n delimiter.string === \"`\" && delimiter.index < linkImageStartIndex\n );\n\n if (!isInsideInlineCode) {\n const partialLinkImageContent = partialLinkImageMatch[0];\n const {\n text: partialLinkText,\n url: partialLinkUrl,\n image: isImage,\n } = partialLinkImageMatch.groups!;\n\n if (isImage) {\n // We can't optimistically complete images, so we remove them until they are complete.\n completedMarkdown = completedMarkdown.slice(\n 0,\n -partialLinkImageContent.length\n );\n } else {\n // We can remove delimiters from the stack that are inside the completed link,\n // since they are now closed.\n for (let i = stack.length - 1; i >= 0; i--) {\n const delimiter = stack[i]!;\n\n if (\n delimiter.index >= linkImageStartIndex &&\n delimiter.index < linkImageEndIndex\n ) {\n stack.splice(i, 1);\n }\n }\n\n const completedLinkText = partialLinkText\n ? partialLinkUrl\n ? // If there's a partial URL, the text is already completed.\n partialLinkText\n : // Otherwise, we complete the text and its potential nested elements.\n completePartialInlineMarkdown(partialLinkText, {\n // Links/images cannot be nested.\n allowLinksImages: false,\n })\n : \"\";\n const completedLinkUrl =\n partialLinkUrl &&\n !WHITESPACE_REGEX.test(partialLinkUrl) &&\n isUrl(partialLinkUrl)\n ? // We only use the partial URL if it's valid.\n partialLinkUrl\n : DEFAULT_PARTIAL_LINK_URL;\n const completedLink = `[${completedLinkText}](${completedLinkUrl})`;\n\n completedMarkdown = completedMarkdown.slice(\n 0,\n -partialLinkImageContent.length\n );\n completedMarkdown += completedLink;\n }\n }\n }\n }\n\n // Move through the stack to close open formatting tokens.\n for (let i = stack.length - 1; i >= 0; i--) {\n const delimiter = stack[i]!;\n\n // If the open token is at the end of the string,\n // we can't close it yet so we remove it.\n if (delimiter.index + delimiter.length >= completedMarkdown.length) {\n completedMarkdown = completedMarkdown.slice(0, delimiter.index);\n continue;\n }\n\n // Bold, italic, and strikethrough cannot end with whitespace so\n // we trim their content before closing them.\n if (delimiter.string !== \"`\") {\n completedMarkdown = completedMarkdown.trimEnd();\n }\n\n // We can close that open token at this point.\n completedMarkdown += delimiter.string;\n }\n\n return completedMarkdown;\n}\n\n/**\n * Optimistically complete a Markdown string of a table.\n */\nfunction completePartialTableMarkdown(markdown: string): string | undefined {\n const tableLines = markdown.split(\"\\n\");\n\n if (tableLines.length === 0) {\n return undefined;\n }\n\n const tableHeader = tableLines[0]!;\n\n if (tableHeader === \"|\") {\n return undefined;\n }\n\n const tableHeadings = tableHeader\n .split(\"|\")\n .map((cell) => cell.trim())\n .filter((cell) => cell !== \"\");\n\n if (tableHeadings.length === 0) {\n return undefined;\n }\n\n // If the last header cell is partial, it might also contain partial elements.\n if (!tableHeader.endsWith(\"|\")) {\n const lastTableHeading = tableHeadings[tableHeadings.length - 1]!;\n const completedLastTableHeading =\n completePartialInlineMarkdown(lastTableHeading);\n\n tableHeadings[tableHeadings.length - 1] = completedLastTableHeading;\n }\n\n return `| ${tableHeadings.join(\" | \")} |\\n| ${tableHeadings.map(() => \"---\").join(\" | \")} |`;\n}\n\nfunction completePartialTokens(tokens: Token[]) {\n const potentiallyPartialToken = findPotentiallyPartialToken(tokens);\n\n if (!potentiallyPartialToken) {\n return tokens;\n }\n\n if (\n potentiallyPartialToken.type === \"paragraph\" ||\n potentiallyPartialToken.type === \"text\"\n ) {\n // Marked.js only creates tables when the table header and its\n // separator below are complete.\n //\n // We optimistically create tables sooner if the current text looks\n // like a partial table header.\n if (PARTIAL_TABLE_HEADER_REGEX.test(potentiallyPartialToken.raw)) {\n const completedTableMarkdown = completePartialTableMarkdown(\n potentiallyPartialToken.raw\n );\n\n if (completedTableMarkdown) {\n // We optimistically complete the table as a string then re-tokenize\n // it to get an optimistically complete table token.\n const completedTable = tokenize(completedTableMarkdown)[0] as\n | Tokens.Table\n | undefined;\n\n if (completedTable) {\n // We replace the paragraph/text by the optimistically completed table.\n const table = potentiallyPartialToken as unknown as Tokens.Table;\n\n table.type = \"table\";\n table.header = completedTable.header;\n table.align = completedTable.align;\n table.rows = completedTable.rows;\n\n return tokens;\n }\n } else {\n // Otherwise, we hide it for now.\n potentiallyPartialToken.text = \"\";\n potentiallyPartialToken.tokens = [];\n }\n }\n }\n\n if (potentiallyPartialToken.type === \"list_item\") {\n const listItem = potentiallyPartialToken;\n const listItemTokens = listItem.tokens as Token[];\n\n // Marked.js only turns list items into tasks when the list marker\n // and the task checkbox are complete and followed by a space. (e.g. \"- [x] \")\n //\n // We optimistically mark list items as tasks sooner,\n // whenever a list item starts with \"- [\", \"- [x\", etc.\n if (\n !listItem.task &&\n listItemTokens.length === 1 &&\n listItemTokens[0]!.type === \"text\"\n ) {\n const listItemText = listItemTokens[0];\n const checkboxMatch = listItemText.text.match(LIST_ITEM_CHECKBOX_REGEX);\n\n if (checkboxMatch) {\n listItem.task = true;\n\n if (checkboxMatch[1] === \"x\") {\n listItem.checked = true;\n } else {\n listItem.checked = false;\n }\n\n listItem.text = \"\";\n listItem.tokens = [];\n }\n }\n }\n\n if (potentiallyPartialToken.text.length === 0) {\n return tokens;\n }\n\n // We optimistically complete inline content as a string then re-tokenize\n // it to get optimistically complete tokens.\n const completedMarkdown = completePartialInlineMarkdown(\n potentiallyPartialToken.text\n );\n const completedMarkdownTokens =\n (tokenize(completedMarkdown)[0] as Tokens.Paragraph | undefined)?.tokens ??\n [];\n\n potentiallyPartialToken.text = completedMarkdown;\n potentiallyPartialToken.tokens = completedMarkdownTokens;\n\n return tokens;\n}\n\nfunction parseHtmlEntities(input: string) {\n const document = new DOMParser().parseFromString(\n `<!doctype html><body>${input\n // Prevent some characters from being interpreted as markup.\n .replace(AMPERSAND_REGEX, \"&\")\n .replace(LEFT_ANGLE_BRACKET_REGEX, \"<\")\n .replace(RIGHT_ANGLE_BRACKET_REGEX, \">\")}`,\n \"text/html\"\n );\n\n return document.body.textContent;\n}\n\nfunction clampHeadingLevel(level: number) {\n return Math.max(1, Math.min(6, level)) as 1 | 2 | 3 | 4 | 5 | 6;\n}\n"],"names":["jsx","assertNever","index","forwardRef","Slot","useMemo","memo","sanitizeUrl","jsxs","Fragment","Lexer","isUrl"],"mappings":"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