@react-email/editor 0.0.0-experimental.0 → 0.0.0-experimental.1
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/dist/index.mjs.map +1 -1
- package/package.json +9 -10
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["styleObject: { [key: string]: string }","attrs: Record<string, string>","attrs: Record<string, string>","ReactEmailButton","decorations: Decoration[]","pluginView: EditorView | null","prismjsPlugin: Plugin<DecorationSet>","CodeBlock","ReactEmailCodeBlock","attrs: Record<string, string>","ReactEmailSection"],"sources":["../src/core/email-node.ts","../src/utils/attribute-helpers.ts","../src/utils/styles.ts","../src/extensions/body.tsx","../src/extensions/button.tsx","../src/utils/prism-utils.ts","../src/extensions/prism-plugin.ts","../src/extensions/code-block.tsx","../src/extensions/div.tsx","../src/utils/get-text-alignment.ts","../src/extensions/section.tsx"],"sourcesContent":["import {\n type Editor,\n type JSONContent,\n Node,\n type NodeConfig,\n type NodeType,\n} from '@tiptap/core';\nimport type { CssJs } from '../utils/types';\n\nexport type RendererComponent = (props: {\n node: JSONContent;\n styles: CssJs;\n children?: React.ReactNode;\n}) => React.ReactNode;\n\nexport interface EmailNodeConfig<Options, Storage>\n extends NodeConfig<Options, Storage> {\n renderToReactEmail: RendererComponent;\n}\n\ntype ConfigParameter<Options, Storage> = Partial<\n Omit<EmailNodeConfig<Options, Storage>, 'renderToReactEmail'>\n> &\n Pick<EmailNodeConfig<Options, Storage>, 'renderToReactEmail'>;\n\nexport class EmailNode<\n Options = Record<string, never>,\n Storage = Record<string, never>,\n> extends Node<Options, Storage> {\n declare config: EmailNodeConfig<Options, Storage>;\n\n // biome-ignore lint/complexity/noUselessConstructor: This is only meant to change the types for config, hence why we keep it\n constructor(config: ConfigParameter<Options, Storage>) {\n super(config);\n }\n\n /**\n * Create a new Node instance\n * @param config - Node configuration object or a function that returns a configuration object\n */\n static create<O = Record<string, never>, S = Record<string, never>>(\n config: ConfigParameter<O, S> | (() => ConfigParameter<O, S>),\n ) {\n // If the config is a function, execute it to get the configuration object\n const resolvedConfig = typeof config === 'function' ? config() : config;\n return new EmailNode<O, S>(resolvedConfig);\n }\n\n static from<O, S>(\n node: Node<O, S>,\n renderToReactEmail: RendererComponent,\n ): EmailNode<O, S> {\n const customNode = EmailNode.create({} as ConfigParameter<O, S>);\n // This only makes a shallow copy, so if there's nested objects here mutating things will be dangerous\n Object.assign(customNode, { ...node });\n customNode.config = { ...node.config, renderToReactEmail };\n return customNode;\n }\n\n configure(options?: Partial<Options>) {\n return super.configure(options) as EmailNode<Options, Storage>;\n }\n\n extend<\n ExtendedOptions = Options,\n ExtendedStorage = Storage,\n ExtendedConfig extends NodeConfig<\n ExtendedOptions,\n ExtendedStorage\n > = EmailNodeConfig<ExtendedOptions, ExtendedStorage>,\n >(\n extendedConfig?:\n | (() => Partial<ExtendedConfig>)\n | (Partial<ExtendedConfig> &\n ThisType<{\n name: string;\n options: ExtendedOptions;\n storage: ExtendedStorage;\n editor: Editor;\n type: NodeType;\n }>),\n ): EmailNode<ExtendedOptions, ExtendedStorage> {\n // If the extended config is a function, execute it to get the configuration object\n const resolvedConfig =\n typeof extendedConfig === 'function' ? extendedConfig() : extendedConfig;\n return super.extend(resolvedConfig) as EmailNode<\n ExtendedOptions,\n ExtendedStorage\n >;\n }\n}\n","/**\n * Creates TipTap attribute definitions for a list of HTML attributes.\n * Each attribute will have the same pattern:\n * - default: null\n * - parseHTML: extracts the attribute from the element\n * - renderHTML: conditionally renders the attribute if it has a value\n *\n * @param attributeNames - Array of HTML attribute names to create definitions for\n * @returns Object with TipTap attribute definitions\n *\n * @example\n * const attrs = createStandardAttributes(['class', 'id', 'title']);\n * // Returns:\n * // {\n * // class: {\n * // default: null,\n * // parseHTML: (element) => element.getAttribute('class'),\n * // renderHTML: (attributes) => attributes.class ? { class: attributes.class } : {}\n * // },\n * // ...\n * // }\n */\nexport function createStandardAttributes(attributeNames: readonly string[]) {\n return Object.fromEntries(\n attributeNames.map((attr) => [\n attr,\n {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute(attr),\n renderHTML: (attributes: Record<string, unknown>) => {\n if (!attributes[attr]) {\n return {};\n }\n\n return {\n [attr]: attributes[attr],\n };\n },\n },\n ]),\n );\n}\n\n/**\n * Common HTML attributes used across multiple extensions.\n * These preserve attributes during HTML import and editing for better\n * fidelity when importing existing email templates.\n */\nexport const COMMON_HTML_ATTRIBUTES = [\n 'id',\n 'class',\n 'title',\n 'lang',\n 'dir',\n 'data-id',\n] as const;\n\n/**\n * Layout-specific HTML attributes used for positioning and sizing.\n */\nexport const LAYOUT_ATTRIBUTES = ['align', 'width', 'height'] as const;\n\n/**\n * Table-specific HTML attributes used for table layout and styling.\n */\nexport const TABLE_ATTRIBUTES = [\n 'border',\n 'cellpadding',\n 'cellspacing',\n] as const;\n\n/**\n * Table cell-specific HTML attributes.\n */\nexport const TABLE_CELL_ATTRIBUTES = [\n 'valign',\n 'bgcolor',\n 'colspan',\n 'rowspan',\n] as const;\n\n/**\n * Table header cell-specific HTML attributes.\n * These are additional attributes that only apply to <th> elements.\n */\nexport const TABLE_HEADER_ATTRIBUTES = [\n ...TABLE_CELL_ATTRIBUTES,\n 'scope',\n] as const;\n","const WHITE_SPACE_REGEX = /\\s+/;\n\nexport const jsToInlineCss = (styleObject: { [key: string]: any }) => {\n const parts: string[] = [];\n\n for (const key in styleObject) {\n const value = styleObject[key];\n if (value !== 0 && value !== undefined && value !== null && value !== '') {\n const KEBAB_CASE_REGEX = /[A-Z]/g;\n const formattedKey = key.replace(\n KEBAB_CASE_REGEX,\n (match) => `-${match.toLowerCase()}`,\n );\n parts.push(`${formattedKey}:${value}`);\n }\n }\n\n return parts.join(';') + (parts.length ? ';' : '');\n};\n\nexport const inlineCssToJs = (\n inlineStyle: string,\n options: { removeUnit?: boolean } = {},\n) => {\n const styleObject: { [key: string]: string } = {};\n\n if (!inlineStyle || inlineStyle === '' || typeof inlineStyle === 'object') {\n return styleObject;\n }\n\n inlineStyle.split(';').forEach((style: string) => {\n if (style.trim()) {\n const [key, value] = style.split(':');\n const valueTrimmed = value?.trim();\n\n if (!valueTrimmed) {\n return;\n }\n\n const formattedKey = key\n .trim()\n .replace(/-\\w/g, (match) => match[1].toUpperCase());\n\n const UNIT_REGEX = /px|%/g;\n const sanitizedValue = options?.removeUnit\n ? valueTrimmed.replace(UNIT_REGEX, '')\n : valueTrimmed;\n\n styleObject[formattedKey] = sanitizedValue;\n }\n });\n\n return styleObject;\n};\n\n/**\n * Expands CSS shorthand properties (margin, padding) into their longhand equivalents.\n * This prevents shorthand properties from overriding specific longhand properties in email clients.\n *\n * @param styles - Style object that may contain shorthand properties\n * @returns New style object with shorthand properties expanded to longhand\n *\n * @example\n * expandShorthandProperties({ margin: '0', paddingTop: '10px' })\n * // Returns: { marginTop: '0', marginRight: '0', marginBottom: '0', marginLeft: '0', paddingTop: '10px' }\n */\nexport function expandShorthandProperties(\n styles: Record<string, string>,\n): Record<string, string> {\n if (!styles || typeof styles !== 'object') {\n return {};\n }\n\n const expanded: Record<string, any> = {};\n\n for (const key in styles) {\n const value = styles[key];\n if (value === undefined || value === null || value === '') {\n continue;\n }\n\n switch (key) {\n case 'margin': {\n const values = parseShorthandValue(value);\n expanded.marginTop = values.top;\n expanded.marginRight = values.right;\n expanded.marginBottom = values.bottom;\n expanded.marginLeft = values.left;\n break;\n }\n case 'padding': {\n const values = parseShorthandValue(value);\n expanded.paddingTop = values.top;\n expanded.paddingRight = values.right;\n expanded.paddingBottom = values.bottom;\n expanded.paddingLeft = values.left;\n break;\n }\n case 'border': {\n const values = convertBorderValue(value);\n expanded.borderStyle = values.style;\n expanded.borderWidth = values.width;\n expanded.borderColor = values.color;\n break;\n }\n case 'borderTopLeftRadius':\n case 'borderTopRightRadius':\n case 'borderBottomLeftRadius':\n case 'borderBottomRightRadius': {\n // Always preserve the longhand property\n expanded[key] = value;\n\n // When all four corners are present and identical, also add the shorthand\n if (\n styles.borderTopLeftRadius &&\n styles.borderTopRightRadius &&\n styles.borderBottomLeftRadius &&\n styles.borderBottomRightRadius\n ) {\n const values = [\n styles.borderTopLeftRadius,\n styles.borderTopRightRadius,\n styles.borderBottomLeftRadius,\n styles.borderBottomRightRadius,\n ];\n\n if (new Set(values).size === 1) {\n expanded.borderRadius = values[0];\n }\n }\n\n break;\n }\n\n default: {\n // Keep all other properties as-is\n expanded[key] = value;\n }\n }\n }\n\n return expanded;\n}\n\n/**\n * Parses CSS shorthand value (1-4 values) into individual side values.\n * Follows CSS specification for shorthand property value parsing.\n *\n * @param value - Shorthand value string (e.g., '0', '10px 20px', '5px 10px 15px 20px')\n * @returns Object with top, right, bottom, left values\n */\nfunction parseShorthandValue(value: string | number): {\n top: string;\n right: string;\n bottom: string;\n left: string;\n} {\n const stringValue = String(value).trim();\n const parts = stringValue.split(WHITE_SPACE_REGEX);\n const len = parts.length;\n\n if (len === 1) {\n return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };\n }\n if (len === 2) {\n return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };\n }\n if (len === 3) {\n return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[1] };\n }\n if (len === 4) {\n return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };\n }\n\n return {\n top: stringValue,\n right: stringValue,\n bottom: stringValue,\n left: stringValue,\n };\n}\n\nfunction convertBorderValue(value: string | number): {\n style: string;\n width: string;\n color: string;\n} {\n const stringValue = String(value).trim();\n const parts = stringValue.split(WHITE_SPACE_REGEX);\n\n switch (parts.length) {\n case 1:\n // border: 1px → all sides\n return {\n style: 'solid',\n width: parts[0],\n color: 'black',\n };\n case 2:\n // border: 1px solid → top/bottom, left/right\n return {\n style: parts[1],\n width: parts[0],\n color: 'black',\n };\n case 3:\n // border: 1px solid #000 → top, left/right, bottom\n return {\n style: parts[1],\n width: parts[0],\n color: parts[2],\n };\n case 4:\n // border: 1px solid #000 #fff → top, right, bottom, left\n return {\n style: parts[1],\n width: parts[0],\n color: parts[2],\n };\n default:\n // Invalid format, return the original value for all sides\n return {\n style: 'solid',\n width: stringValue,\n color: 'black',\n };\n }\n}\n","import { mergeAttributes } from '@tiptap/core';\nimport { EmailNode } from '../core/email-node';\nimport {\n COMMON_HTML_ATTRIBUTES,\n createStandardAttributes,\n LAYOUT_ATTRIBUTES,\n} from '../utils/attribute-helpers';\nimport { inlineCssToJs } from '../utils/styles';\n\nexport interface BodyOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\nexport const Body = EmailNode.create<BodyOptions>({\n name: 'body',\n\n group: 'block',\n\n content: 'block+',\n\n defining: true,\n isolating: true,\n\n addAttributes() {\n return {\n ...createStandardAttributes([\n ...COMMON_HTML_ATTRIBUTES,\n ...LAYOUT_ATTRIBUTES,\n ]),\n };\n },\n\n parseHTML() {\n return [\n {\n tag: 'body',\n getAttrs: (node) => {\n if (typeof node === 'string') {\n return false;\n }\n const element = node as HTMLElement;\n const attrs: Record<string, string> = {};\n\n // Preserve all attributes\n Array.from(element.attributes).forEach((attr) => {\n attrs[attr.name] = attr.value;\n });\n\n return attrs;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n 0,\n ];\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n return (\n <div\n className={node.attrs?.class || undefined}\n style={{\n ...styles.reset,\n ...inlineStyles,\n }}\n >\n {children}\n </div>\n );\n },\n});\n","import {\n Column,\n Button as ReactEmailButton,\n Row,\n} from '@react-email/components';\nimport { mergeAttributes } from '@tiptap/core';\nimport { EmailNode } from '../core/email-node';\nimport { inlineCssToJs } from '../utils/styles';\n\ninterface EditorButtonOptions {\n HTMLAttributes: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n button: {\n setButton: () => ReturnType;\n updateButton: (attributes: Record<string, unknown>) => ReturnType;\n };\n }\n}\n\nexport const Button = EmailNode.create<EditorButtonOptions>({\n name: 'button',\n group: 'block',\n content: 'inline*',\n defining: true,\n draggable: true,\n marks: 'bold',\n\n addAttributes() {\n return {\n class: {\n default: 'button',\n },\n href: {\n default: '#',\n },\n alignment: {\n default: 'left',\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: 'a[data-id=\"react-email-button\"]',\n getAttrs: (node) => {\n if (typeof node === 'string') {\n return false;\n }\n const element = node as HTMLElement;\n const attrs: Record<string, string> = {};\n\n // Preserve all attributes\n Array.from(element.attributes).forEach((attr) => {\n attrs[attr.name] = attr.value;\n });\n\n return attrs;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes({\n class: `align-${HTMLAttributes?.alignment}`,\n }),\n [\n 'a',\n mergeAttributes({\n class: `node-button ${HTMLAttributes?.class}`,\n style: HTMLAttributes?.style,\n 'data-id': 'react-email-button',\n 'data-href': HTMLAttributes?.href,\n }),\n 0,\n ],\n ];\n },\n\n addCommands() {\n return {\n updateButton:\n (attributes) =>\n ({ commands }) => {\n return commands.updateAttributes('button', attributes);\n },\n\n setButton:\n () =>\n ({ commands }) => {\n return commands.insertContent({\n type: 'button',\n content: [\n {\n type: 'text',\n text: 'Button',\n },\n ],\n });\n },\n };\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n return (\n <Row>\n <Column align={node.attrs?.align || node.attrs?.alignment}>\n <ReactEmailButton\n className={node.attrs?.class || undefined}\n href={node.attrs?.href}\n style={{\n ...styles.reset,\n ...styles.button,\n ...inlineStyles,\n }}\n >\n {children}\n </ReactEmailButton>\n </Column>\n </Row>\n );\n },\n});\n","const publicURL = '/styles/prism';\n\nexport function loadPrismTheme(theme: string) {\n // Create new link element for the new theme\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = `${publicURL}/prism-${theme}.css`;\n link.setAttribute('data-prism-theme', ''); // Mark this link as the Prism theme\n\n // Append the new link element to the head\n document.head.appendChild(link);\n}\n\nexport function removePrismTheme() {\n const existingTheme = document.querySelectorAll(\n 'link[rel=\"stylesheet\"][data-prism-theme]',\n );\n if (existingTheme.length > 0) {\n existingTheme.forEach((cssLinkTag) => {\n cssLinkTag.remove();\n });\n }\n}\n\nexport function hasPrismThemeLoaded(theme: string) {\n const existingTheme = document.querySelector(\n `link[rel=\"stylesheet\"][data-prism-theme][href=\"${publicURL}/prism-${theme}.css\"]`,\n );\n return !!existingTheme;\n}\n","import { findChildren } from '@tiptap/core';\nimport type { Node as ProsemirrorNode } from '@tiptap/pm/model';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport type { EditorView } from '@tiptap/pm/view';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport { fromHtml } from 'hast-util-from-html';\nimport Prism from 'prismjs';\nimport {\n hasPrismThemeLoaded,\n loadPrismTheme,\n removePrismTheme,\n} from '../utils/prism-utils';\n\nconst PRISM_LANGUAGE_LOADED_META = 'prismLanguageLoaded';\n\ninterface RefractorNode {\n properties?: { className: string[] };\n children?: RefractorNode[];\n value?: string;\n}\n\nfunction parseNodes(\n nodes: RefractorNode[],\n className: string[] = [],\n): { text: string; classes: string[] }[] {\n return nodes.flatMap((node) => {\n const classes = [\n ...className,\n ...(node.properties ? node.properties.className : []),\n ];\n\n if (node.children) {\n return parseNodes(node.children, classes);\n }\n\n return {\n text: node.value ?? '',\n classes,\n };\n });\n}\n\nfunction getHighlightNodes(html: string) {\n return fromHtml(html, { fragment: true }).children;\n}\n\nfunction registeredLang(aliasOrLanguage: string) {\n const allSupportLang = Object.keys(Prism.languages).filter(\n (id) => typeof Prism.languages[id] === 'object',\n );\n return Boolean(allSupportLang.find((x) => x === aliasOrLanguage));\n}\n\nfunction getDecorations({\n doc,\n name,\n defaultLanguage,\n defaultTheme,\n loadingLanguages,\n onLanguageLoaded,\n}: {\n doc: ProsemirrorNode;\n name: string;\n defaultLanguage: string | null | undefined;\n defaultTheme: string | null | undefined;\n loadingLanguages: Set<string>;\n onLanguageLoaded: (language: string) => void;\n}) {\n const decorations: Decoration[] = [];\n\n findChildren(doc, (node) => node.type.name === name).forEach((block) => {\n let from = block.pos + 1;\n const language = block.node.attrs.language || defaultLanguage;\n const theme = block.node.attrs.theme || defaultTheme;\n let html = '';\n\n try {\n if (!registeredLang(language) && !loadingLanguages.has(language)) {\n loadingLanguages.add(language);\n import(`prismjs/components/prism-${language}`)\n .then(() => {\n loadingLanguages.delete(language);\n onLanguageLoaded(language);\n })\n .catch(() => {\n loadingLanguages.delete(language);\n });\n }\n\n if (!hasPrismThemeLoaded(theme)) {\n loadPrismTheme(theme);\n }\n\n html = Prism.highlight(\n block.node.textContent,\n Prism.languages[language],\n language,\n );\n } catch {\n html = Prism.highlight(\n block.node.textContent,\n Prism.languages.javascript,\n 'js',\n );\n }\n\n const nodes = getHighlightNodes(html);\n\n parseNodes(nodes as RefractorNode[]).forEach((node) => {\n const to = from + node.text.length;\n\n if (node.classes.length) {\n const decoration = Decoration.inline(from, to, {\n class: node.classes.join(' '),\n });\n\n decorations.push(decoration);\n }\n\n from = to;\n });\n });\n\n return DecorationSet.create(doc, decorations);\n}\n\nexport function PrismPlugin({\n name,\n defaultLanguage,\n defaultTheme,\n}: {\n name: string;\n defaultLanguage: string;\n defaultTheme: string;\n}) {\n if (!defaultLanguage) {\n throw Error('You must specify the defaultLanguage parameter');\n }\n\n const loadingLanguages = new Set<string>();\n let pluginView: EditorView | null = null;\n\n const onLanguageLoaded = (language: string) => {\n if (pluginView) {\n pluginView.dispatch(\n pluginView.state.tr.setMeta(PRISM_LANGUAGE_LOADED_META, language),\n );\n }\n };\n\n const prismjsPlugin: Plugin<DecorationSet> = new Plugin({\n key: new PluginKey('prism'),\n\n view(view) {\n pluginView = view;\n return {\n destroy() {\n pluginView = null;\n },\n };\n },\n\n state: {\n init: (_, { doc }) => {\n return getDecorations({\n doc,\n name,\n defaultLanguage,\n defaultTheme,\n loadingLanguages,\n onLanguageLoaded,\n });\n },\n apply: (transaction, decorationSet, oldState, newState) => {\n const oldNodeName = oldState.selection.$head.parent.type.name;\n const newNodeName = newState.selection.$head.parent.type.name;\n\n const oldNodes = findChildren(\n oldState.doc,\n (node) => node.type.name === name,\n );\n const newNodes = findChildren(\n newState.doc,\n (node) => node.type.name === name,\n );\n\n if (\n transaction.getMeta(PRISM_LANGUAGE_LOADED_META) ||\n (transaction.docChanged &&\n // Apply decorations if:\n // selection includes named node,\n ([oldNodeName, newNodeName].includes(name) ||\n // OR transaction adds/removes named node,\n newNodes.length !== oldNodes.length ||\n // OR transaction has changes that completely encapsulate a node\n // (for example, a transaction that affects the entire document).\n // Such transactions can happen during collab syncing via y-prosemirror, for example.\n transaction.steps.some((step) => {\n const rangeStep = step as unknown as {\n from?: number;\n to?: number;\n };\n return (\n rangeStep.from !== undefined &&\n rangeStep.to !== undefined &&\n oldNodes.some((node) => {\n return (\n node.pos >= rangeStep.from! &&\n node.pos + node.node.nodeSize <= rangeStep.to!\n );\n })\n );\n })))\n ) {\n return getDecorations({\n doc: transaction.doc,\n name,\n defaultLanguage,\n defaultTheme,\n loadingLanguages,\n onLanguageLoaded,\n });\n }\n\n return decorationSet.map(transaction.mapping, transaction.doc);\n },\n },\n\n props: {\n decorations(state) {\n return prismjsPlugin.getState(state);\n },\n },\n\n destroy() {\n pluginView = null;\n removePrismTheme();\n },\n });\n\n return prismjsPlugin;\n}\n","import * as ReactEmailComponents from '@react-email/components';\nimport {\n type PrismLanguage,\n CodeBlock as ReactEmailCodeBlock,\n} from '@react-email/components';\nimport { mergeAttributes } from '@tiptap/core';\nimport type { CodeBlockOptions } from '@tiptap/extension-code-block';\nimport CodeBlock from '@tiptap/extension-code-block';\nimport { EmailNode } from '../core/email-node';\nimport { PrismPlugin } from './prism-plugin';\n\nexport interface CodeBlockPrismOptions extends CodeBlockOptions {\n defaultLanguage: string;\n defaultTheme: string;\n}\n\nexport const CodeBlockPrism = EmailNode.from(\n CodeBlock.extend<CodeBlockPrismOptions>({\n addOptions(): CodeBlockPrismOptions {\n return {\n languageClassPrefix: 'language-',\n exitOnTripleEnter: false,\n exitOnArrowDown: false,\n enableTabIndentation: true,\n tabSize: 2,\n defaultLanguage: 'javascript',\n defaultTheme: 'default',\n HTMLAttributes: {},\n };\n },\n\n addAttributes() {\n return {\n ...this.parent?.(),\n language: {\n default: this.options.defaultLanguage,\n parseHTML: (element: HTMLElement | null) => {\n if (!element) {\n return null;\n }\n const { languageClassPrefix } = this.options;\n if (!languageClassPrefix) {\n return null;\n }\n const classNames = [\n ...(element.firstElementChild?.classList || []),\n ];\n const languages = classNames\n .filter((className) =>\n className.startsWith(languageClassPrefix || ''),\n )\n .map((className) => className.replace(languageClassPrefix, ''));\n const language = languages[0];\n\n if (!language) {\n return null;\n }\n\n return language;\n },\n rendered: false,\n },\n theme: {\n default: this.options.defaultTheme,\n rendered: false,\n },\n };\n },\n\n renderHTML({ node, HTMLAttributes }) {\n return [\n 'pre',\n mergeAttributes(\n this.options.HTMLAttributes,\n HTMLAttributes,\n {\n class: node.attrs.language\n ? `${this.options.languageClassPrefix}${node.attrs.language}`\n : null,\n },\n { 'data-theme': node.attrs.theme },\n ),\n [\n 'code',\n {\n class: node.attrs.language\n ? `${this.options.languageClassPrefix}${node.attrs.language} node-codeTag`\n : 'node-codeTag',\n },\n 0,\n ],\n ];\n },\n\n addProseMirrorPlugins() {\n return [\n ...(this.parent?.() || []),\n PrismPlugin({\n name: this.name,\n defaultLanguage: this.options.defaultLanguage,\n defaultTheme: this.options.defaultTheme,\n }),\n ];\n },\n }),\n ({ node, styles }) => {\n const language = node.attrs?.language\n ? `${node.attrs.language}`\n : 'javascript';\n\n const userTheme = ReactEmailComponents[node.attrs?.theme];\n\n // Without theme, render a gray codeblock\n const theme = userTheme\n ? {\n ...userTheme,\n base: {\n ...userTheme.base,\n borderRadius: '0.125rem',\n padding: '0.75rem 1rem',\n },\n }\n : {\n base: {\n color: '#1e293b',\n background: '#f1f5f9',\n lineHeight: '1.5',\n fontFamily:\n '\"Fira Code\", \"Fira Mono\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace',\n padding: '0.75rem 1rem',\n borderRadius: '0.125rem',\n },\n };\n\n return (\n <ReactEmailCodeBlock\n code={node.content?.[0]?.text ?? ''}\n language={language as PrismLanguage}\n theme={theme}\n style={{\n width: 'auto',\n ...styles.codeBlock,\n }}\n />\n );\n },\n);\n","import { mergeAttributes } from '@tiptap/core';\nimport { EmailNode } from '../core/email-node';\nimport {\n COMMON_HTML_ATTRIBUTES,\n createStandardAttributes,\n LAYOUT_ATTRIBUTES,\n} from '../utils/attribute-helpers';\nimport { inlineCssToJs } from '../utils/styles';\n\nexport interface DivOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\nexport const Div = EmailNode.create<DivOptions>({\n name: 'div',\n\n group: 'block',\n\n content: 'block+',\n\n defining: true,\n isolating: true,\n\n parseHTML() {\n return [\n {\n tag: 'div:not([data-type])',\n getAttrs: (node) => {\n if (typeof node === 'string') {\n return false;\n }\n const element = node as HTMLElement;\n const attrs: Record<string, string> = {};\n\n // Preserve all attributes\n Array.from(element.attributes).forEach((attr) => {\n attrs[attr.name] = attr.value;\n });\n\n return attrs;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n 0,\n ];\n },\n\n addAttributes() {\n return {\n ...createStandardAttributes([\n ...COMMON_HTML_ATTRIBUTES,\n ...LAYOUT_ATTRIBUTES,\n ]),\n };\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n return (\n <div\n className={node.attrs?.class || undefined}\n style={{\n ...styles.reset,\n ...inlineStyles,\n }}\n >\n {children}\n </div>\n );\n },\n});\n","export function getTextAlignment(alignment: string | undefined) {\n switch (alignment) {\n case 'left':\n return { textAlign: 'left' };\n case 'center':\n return { textAlign: 'center' };\n case 'right':\n return { textAlign: 'right' };\n default:\n return {};\n }\n}\n","import { Section as ReactEmailSection } from '@react-email/components';\nimport { mergeAttributes } from '@tiptap/core';\nimport type * as React from 'react';\nimport { EmailNode } from '../core/email-node';\nimport { getTextAlignment } from '../utils/get-text-alignment';\nimport { inlineCssToJs } from '../utils/styles';\n\ninterface SectionOptions {\n HTMLAttributes: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n section: {\n insertSection: () => ReturnType;\n };\n }\n}\n\nexport const Section = EmailNode.create<SectionOptions>({\n name: 'section',\n group: 'block',\n content: 'block+',\n isolating: true,\n defining: true,\n\n parseHTML() {\n return [{ tag: 'section[data-type=\"section\"]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'section',\n mergeAttributes(\n { 'data-type': 'section', class: 'node-section' },\n HTMLAttributes,\n ),\n 0,\n ];\n },\n\n addCommands() {\n return {\n insertSection:\n () =>\n ({ commands }) => {\n return commands.insertContent({\n type: this.name,\n content: [\n {\n type: 'paragraph',\n content: [],\n },\n ],\n });\n },\n };\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n const textAlign = node.attrs?.align || node.attrs?.alignment;\n\n return (\n <ReactEmailSection\n className={node.attrs?.class || undefined}\n align={textAlign}\n style={\n {\n ...styles.section,\n ...inlineStyles,\n ...getTextAlignment(textAlign),\n } as React.CSSProperties\n }\n >\n {children}\n </ReactEmailSection>\n );\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["styleObject: { [key: string]: string }","attrs: Record<string, string>","attrs: Record<string, string>","ReactEmailButton","decorations: Decoration[]","pluginView: EditorView | null","prismjsPlugin: Plugin<DecorationSet>","CodeBlock","ReactEmailCodeBlock","attrs: Record<string, string>","ReactEmailSection"],"sources":["../src/core/email-node.ts","../src/utils/attribute-helpers.ts","../src/utils/styles.ts","../src/extensions/body.tsx","../src/extensions/button.tsx","../src/utils/prism-utils.ts","../src/extensions/prism-plugin.ts","../src/extensions/code-block.tsx","../src/extensions/div.tsx","../src/utils/get-text-alignment.ts","../src/extensions/section.tsx"],"sourcesContent":["import {\n type Editor,\n type JSONContent,\n Node,\n type NodeConfig,\n type NodeType,\n} from '@tiptap/core';\nimport type { CssJs } from '../utils/types';\n\nexport type RendererComponent = (props: {\n node: JSONContent;\n styles: CssJs;\n children?: React.ReactNode;\n}) => React.ReactNode;\n\nexport interface EmailNodeConfig<Options, Storage>\n extends NodeConfig<Options, Storage> {\n renderToReactEmail: RendererComponent;\n}\n\ntype ConfigParameter<Options, Storage> = Partial<\n Omit<EmailNodeConfig<Options, Storage>, 'renderToReactEmail'>\n> &\n Pick<EmailNodeConfig<Options, Storage>, 'renderToReactEmail'>;\n\nexport class EmailNode<\n Options = Record<string, never>,\n Storage = Record<string, never>,\n> extends Node<Options, Storage> {\n declare config: EmailNodeConfig<Options, Storage>;\n\n // biome-ignore lint/complexity/noUselessConstructor: This is only meant to change the types for config, hence why we keep it\n constructor(config: ConfigParameter<Options, Storage>) {\n super(config);\n }\n\n /**\n * Create a new Node instance\n * @param config - Node configuration object or a function that returns a configuration object\n */\n static create<O = Record<string, never>, S = Record<string, never>>(\n config: ConfigParameter<O, S> | (() => ConfigParameter<O, S>),\n ) {\n // If the config is a function, execute it to get the configuration object\n const resolvedConfig = typeof config === 'function' ? config() : config;\n return new EmailNode<O, S>(resolvedConfig);\n }\n\n static from<O, S>(\n node: Node<O, S>,\n renderToReactEmail: RendererComponent,\n ): EmailNode<O, S> {\n const customNode = EmailNode.create({} as ConfigParameter<O, S>);\n // This only makes a shallow copy, so if there's nested objects here mutating things will be dangerous\n Object.assign(customNode, { ...node });\n customNode.config = { ...node.config, renderToReactEmail };\n return customNode;\n }\n\n configure(options?: Partial<Options>) {\n return super.configure(options) as EmailNode<Options, Storage>;\n }\n\n extend<\n ExtendedOptions = Options,\n ExtendedStorage = Storage,\n ExtendedConfig extends NodeConfig<\n ExtendedOptions,\n ExtendedStorage\n > = EmailNodeConfig<ExtendedOptions, ExtendedStorage>,\n >(\n extendedConfig?:\n | (() => Partial<ExtendedConfig>)\n | (Partial<ExtendedConfig> &\n ThisType<{\n name: string;\n options: ExtendedOptions;\n storage: ExtendedStorage;\n editor: Editor;\n type: NodeType;\n }>),\n ): EmailNode<ExtendedOptions, ExtendedStorage> {\n // If the extended config is a function, execute it to get the configuration object\n const resolvedConfig =\n typeof extendedConfig === 'function' ? extendedConfig() : extendedConfig;\n return super.extend(resolvedConfig) as EmailNode<\n ExtendedOptions,\n ExtendedStorage\n >;\n }\n}\n","/**\n * Creates TipTap attribute definitions for a list of HTML attributes.\n * Each attribute will have the same pattern:\n * - default: null\n * - parseHTML: extracts the attribute from the element\n * - renderHTML: conditionally renders the attribute if it has a value\n *\n * @param attributeNames - Array of HTML attribute names to create definitions for\n * @returns Object with TipTap attribute definitions\n *\n * @example\n * const attrs = createStandardAttributes(['class', 'id', 'title']);\n * // Returns:\n * // {\n * // class: {\n * // default: null,\n * // parseHTML: (element) => element.getAttribute('class'),\n * // renderHTML: (attributes) => attributes.class ? { class: attributes.class } : {}\n * // },\n * // ...\n * // }\n */\nexport function createStandardAttributes(attributeNames: readonly string[]) {\n return Object.fromEntries(\n attributeNames.map((attr) => [\n attr,\n {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute(attr),\n renderHTML: (attributes: Record<string, unknown>) => {\n if (!attributes[attr]) {\n return {};\n }\n\n return {\n [attr]: attributes[attr],\n };\n },\n },\n ]),\n );\n}\n\n/**\n * Common HTML attributes used across multiple extensions.\n * These preserve attributes during HTML import and editing for better\n * fidelity when importing existing email templates.\n */\nexport const COMMON_HTML_ATTRIBUTES = [\n 'id',\n 'class',\n 'title',\n 'lang',\n 'dir',\n 'data-id',\n] as const;\n\n/**\n * Layout-specific HTML attributes used for positioning and sizing.\n */\nexport const LAYOUT_ATTRIBUTES = ['align', 'width', 'height'] as const;\n\n/**\n * Table-specific HTML attributes used for table layout and styling.\n */\nexport const TABLE_ATTRIBUTES = [\n 'border',\n 'cellpadding',\n 'cellspacing',\n] as const;\n\n/**\n * Table cell-specific HTML attributes.\n */\nexport const TABLE_CELL_ATTRIBUTES = [\n 'valign',\n 'bgcolor',\n 'colspan',\n 'rowspan',\n] as const;\n\n/**\n * Table header cell-specific HTML attributes.\n * These are additional attributes that only apply to <th> elements.\n */\nexport const TABLE_HEADER_ATTRIBUTES = [\n ...TABLE_CELL_ATTRIBUTES,\n 'scope',\n] as const;\n","const WHITE_SPACE_REGEX = /\\s+/;\n\nexport const jsToInlineCss = (styleObject: { [key: string]: any }) => {\n const parts: string[] = [];\n\n for (const key in styleObject) {\n const value = styleObject[key];\n if (value !== 0 && value !== undefined && value !== null && value !== '') {\n const KEBAB_CASE_REGEX = /[A-Z]/g;\n const formattedKey = key.replace(\n KEBAB_CASE_REGEX,\n (match) => `-${match.toLowerCase()}`,\n );\n parts.push(`${formattedKey}:${value}`);\n }\n }\n\n return parts.join(';') + (parts.length ? ';' : '');\n};\n\nexport const inlineCssToJs = (\n inlineStyle: string,\n options: { removeUnit?: boolean } = {},\n) => {\n const styleObject: { [key: string]: string } = {};\n\n if (!inlineStyle || inlineStyle === '' || typeof inlineStyle === 'object') {\n return styleObject;\n }\n\n inlineStyle.split(';').forEach((style: string) => {\n if (style.trim()) {\n const [key, value] = style.split(':');\n const valueTrimmed = value?.trim();\n\n if (!valueTrimmed) {\n return;\n }\n\n const formattedKey = key\n .trim()\n .replace(/-\\w/g, (match) => match[1].toUpperCase());\n\n const UNIT_REGEX = /px|%/g;\n const sanitizedValue = options?.removeUnit\n ? valueTrimmed.replace(UNIT_REGEX, '')\n : valueTrimmed;\n\n styleObject[formattedKey] = sanitizedValue;\n }\n });\n\n return styleObject;\n};\n\n/**\n * Expands CSS shorthand properties (margin, padding) into their longhand equivalents.\n * This prevents shorthand properties from overriding specific longhand properties in email clients.\n *\n * @param styles - Style object that may contain shorthand properties\n * @returns New style object with shorthand properties expanded to longhand\n *\n * @example\n * expandShorthandProperties({ margin: '0', paddingTop: '10px' })\n * // Returns: { marginTop: '0', marginRight: '0', marginBottom: '0', marginLeft: '0', paddingTop: '10px' }\n */\nexport function expandShorthandProperties(\n styles: Record<string, string>,\n): Record<string, string> {\n if (!styles || typeof styles !== 'object') {\n return {};\n }\n\n const expanded: Record<string, any> = {};\n\n for (const key in styles) {\n const value = styles[key];\n if (value === undefined || value === null || value === '') {\n continue;\n }\n\n switch (key) {\n case 'margin': {\n const values = parseShorthandValue(value);\n expanded.marginTop = values.top;\n expanded.marginRight = values.right;\n expanded.marginBottom = values.bottom;\n expanded.marginLeft = values.left;\n break;\n }\n case 'padding': {\n const values = parseShorthandValue(value);\n expanded.paddingTop = values.top;\n expanded.paddingRight = values.right;\n expanded.paddingBottom = values.bottom;\n expanded.paddingLeft = values.left;\n break;\n }\n case 'border': {\n const values = convertBorderValue(value);\n expanded.borderStyle = values.style;\n expanded.borderWidth = values.width;\n expanded.borderColor = values.color;\n break;\n }\n case 'borderTopLeftRadius':\n case 'borderTopRightRadius':\n case 'borderBottomLeftRadius':\n case 'borderBottomRightRadius': {\n // Always preserve the longhand property\n expanded[key] = value;\n\n // When all four corners are present and identical, also add the shorthand\n if (\n styles.borderTopLeftRadius &&\n styles.borderTopRightRadius &&\n styles.borderBottomLeftRadius &&\n styles.borderBottomRightRadius\n ) {\n const values = [\n styles.borderTopLeftRadius,\n styles.borderTopRightRadius,\n styles.borderBottomLeftRadius,\n styles.borderBottomRightRadius,\n ];\n\n if (new Set(values).size === 1) {\n expanded.borderRadius = values[0];\n }\n }\n\n break;\n }\n\n default: {\n // Keep all other properties as-is\n expanded[key] = value;\n }\n }\n }\n\n return expanded;\n}\n\n/**\n * Parses CSS shorthand value (1-4 values) into individual side values.\n * Follows CSS specification for shorthand property value parsing.\n *\n * @param value - Shorthand value string (e.g., '0', '10px 20px', '5px 10px 15px 20px')\n * @returns Object with top, right, bottom, left values\n */\nfunction parseShorthandValue(value: string | number): {\n top: string;\n right: string;\n bottom: string;\n left: string;\n} {\n const stringValue = String(value).trim();\n const parts = stringValue.split(WHITE_SPACE_REGEX);\n const len = parts.length;\n\n if (len === 1) {\n return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };\n }\n if (len === 2) {\n return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };\n }\n if (len === 3) {\n return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[1] };\n }\n if (len === 4) {\n return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };\n }\n\n return {\n top: stringValue,\n right: stringValue,\n bottom: stringValue,\n left: stringValue,\n };\n}\n\nfunction convertBorderValue(value: string | number): {\n style: string;\n width: string;\n color: string;\n} {\n const stringValue = String(value).trim();\n const parts = stringValue.split(WHITE_SPACE_REGEX);\n\n switch (parts.length) {\n case 1:\n // border: 1px → all sides\n return {\n style: 'solid',\n width: parts[0],\n color: 'black',\n };\n case 2:\n // border: 1px solid → top/bottom, left/right\n return {\n style: parts[1],\n width: parts[0],\n color: 'black',\n };\n case 3:\n // border: 1px solid #000 → top, left/right, bottom\n return {\n style: parts[1],\n width: parts[0],\n color: parts[2],\n };\n case 4:\n // border: 1px solid #000 #fff → top, right, bottom, left\n return {\n style: parts[1],\n width: parts[0],\n color: parts[2],\n };\n default:\n // Invalid format, return the original value for all sides\n return {\n style: 'solid',\n width: stringValue,\n color: 'black',\n };\n }\n}\n","import { mergeAttributes } from '@tiptap/core';\nimport { EmailNode } from '../core/email-node';\nimport {\n COMMON_HTML_ATTRIBUTES,\n createStandardAttributes,\n LAYOUT_ATTRIBUTES,\n} from '../utils/attribute-helpers';\nimport { inlineCssToJs } from '../utils/styles';\n\nexport interface BodyOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\nexport const Body = EmailNode.create<BodyOptions>({\n name: 'body',\n\n group: 'block',\n\n content: 'block+',\n\n defining: true,\n isolating: true,\n\n addAttributes() {\n return {\n ...createStandardAttributes([\n ...COMMON_HTML_ATTRIBUTES,\n ...LAYOUT_ATTRIBUTES,\n ]),\n };\n },\n\n parseHTML() {\n return [\n {\n tag: 'body',\n getAttrs: (node) => {\n if (typeof node === 'string') {\n return false;\n }\n const element = node as HTMLElement;\n const attrs: Record<string, string> = {};\n\n // Preserve all attributes\n Array.from(element.attributes).forEach((attr) => {\n attrs[attr.name] = attr.value;\n });\n\n return attrs;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n 0,\n ];\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n return (\n <div\n className={node.attrs?.class || undefined}\n style={{\n ...styles.reset,\n ...inlineStyles,\n }}\n >\n {children}\n </div>\n );\n },\n});\n","import {\n Column,\n Button as ReactEmailButton,\n Row,\n} from '@react-email/components';\nimport { mergeAttributes } from '@tiptap/core';\nimport { EmailNode } from '../core/email-node';\nimport { inlineCssToJs } from '../utils/styles';\n\ninterface EditorButtonOptions {\n HTMLAttributes: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n button: {\n setButton: () => ReturnType;\n updateButton: (attributes: Record<string, unknown>) => ReturnType;\n };\n }\n}\n\nexport const Button = EmailNode.create<EditorButtonOptions>({\n name: 'button',\n group: 'block',\n content: 'inline*',\n defining: true,\n draggable: true,\n marks: 'bold',\n\n addAttributes() {\n return {\n class: {\n default: 'button',\n },\n href: {\n default: '#',\n },\n alignment: {\n default: 'left',\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: 'a[data-id=\"react-email-button\"]',\n getAttrs: (node) => {\n if (typeof node === 'string') {\n return false;\n }\n const element = node as HTMLElement;\n const attrs: Record<string, string> = {};\n\n // Preserve all attributes\n Array.from(element.attributes).forEach((attr) => {\n attrs[attr.name] = attr.value;\n });\n\n return attrs;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes({\n class: `align-${HTMLAttributes?.alignment}`,\n }),\n [\n 'a',\n mergeAttributes({\n class: `node-button ${HTMLAttributes?.class}`,\n style: HTMLAttributes?.style,\n 'data-id': 'react-email-button',\n 'data-href': HTMLAttributes?.href,\n }),\n 0,\n ],\n ];\n },\n\n addCommands() {\n return {\n updateButton:\n (attributes) =>\n ({ commands }) => {\n return commands.updateAttributes('button', attributes);\n },\n\n setButton:\n () =>\n ({ commands }) => {\n return commands.insertContent({\n type: 'button',\n content: [\n {\n type: 'text',\n text: 'Button',\n },\n ],\n });\n },\n };\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n return (\n <Row>\n <Column align={node.attrs?.align || node.attrs?.alignment}>\n <ReactEmailButton\n className={node.attrs?.class || undefined}\n href={node.attrs?.href}\n style={{\n ...styles.reset,\n ...styles.button,\n ...inlineStyles,\n }}\n >\n {children}\n </ReactEmailButton>\n </Column>\n </Row>\n );\n },\n});\n","const publicURL = '/styles/prism';\n\nexport function loadPrismTheme(theme: string) {\n // Create new link element for the new theme\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = `${publicURL}/prism-${theme}.css`;\n link.setAttribute('data-prism-theme', ''); // Mark this link as the Prism theme\n\n // Append the new link element to the head\n document.head.appendChild(link);\n}\n\nexport function removePrismTheme() {\n const existingTheme = document.querySelectorAll(\n 'link[rel=\"stylesheet\"][data-prism-theme]',\n );\n if (existingTheme.length > 0) {\n existingTheme.forEach((cssLinkTag) => {\n cssLinkTag.remove();\n });\n }\n}\n\nexport function hasPrismThemeLoaded(theme: string) {\n const existingTheme = document.querySelector(\n `link[rel=\"stylesheet\"][data-prism-theme][href=\"${publicURL}/prism-${theme}.css\"]`,\n );\n return !!existingTheme;\n}\n","import { findChildren } from '@tiptap/core';\nimport type { Node as ProsemirrorNode } from '@tiptap/pm/model';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport type { EditorView } from '@tiptap/pm/view';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport { fromHtml } from 'hast-util-from-html';\nimport Prism from 'prismjs';\nimport {\n hasPrismThemeLoaded,\n loadPrismTheme,\n removePrismTheme,\n} from '../utils/prism-utils';\n\nconst PRISM_LANGUAGE_LOADED_META = 'prismLanguageLoaded';\n\ninterface RefractorNode {\n properties?: { className: string[] };\n children?: RefractorNode[];\n value?: string;\n}\n\nfunction parseNodes(\n nodes: RefractorNode[],\n className: string[] = [],\n): { text: string; classes: string[] }[] {\n return nodes.flatMap((node) => {\n const classes = [\n ...className,\n ...(node.properties ? node.properties.className : []),\n ];\n\n if (node.children) {\n return parseNodes(node.children, classes);\n }\n\n return {\n text: node.value ?? '',\n classes,\n };\n });\n}\n\nfunction getHighlightNodes(html: string) {\n return fromHtml(html, { fragment: true }).children;\n}\n\nfunction registeredLang(aliasOrLanguage: string) {\n const allSupportLang = Object.keys(Prism.languages).filter(\n (id) => typeof Prism.languages[id] === 'object',\n );\n return Boolean(allSupportLang.find((x) => x === aliasOrLanguage));\n}\n\nfunction getDecorations({\n doc,\n name,\n defaultLanguage,\n defaultTheme,\n loadingLanguages,\n onLanguageLoaded,\n}: {\n doc: ProsemirrorNode;\n name: string;\n defaultLanguage: string | null | undefined;\n defaultTheme: string | null | undefined;\n loadingLanguages: Set<string>;\n onLanguageLoaded: (language: string) => void;\n}) {\n const decorations: Decoration[] = [];\n\n findChildren(doc, (node) => node.type.name === name).forEach((block) => {\n let from = block.pos + 1;\n const language = block.node.attrs.language || defaultLanguage;\n const theme = block.node.attrs.theme || defaultTheme;\n let html = '';\n\n try {\n if (!registeredLang(language) && !loadingLanguages.has(language)) {\n loadingLanguages.add(language);\n import(`prismjs/components/prism-${language}`)\n .then(() => {\n loadingLanguages.delete(language);\n onLanguageLoaded(language);\n })\n .catch(() => {\n loadingLanguages.delete(language);\n });\n }\n\n if (!hasPrismThemeLoaded(theme)) {\n loadPrismTheme(theme);\n }\n\n html = Prism.highlight(\n block.node.textContent,\n Prism.languages[language],\n language,\n );\n } catch {\n html = Prism.highlight(\n block.node.textContent,\n Prism.languages.javascript,\n 'js',\n );\n }\n\n const nodes = getHighlightNodes(html);\n\n parseNodes(nodes as RefractorNode[]).forEach((node) => {\n const to = from + node.text.length;\n\n if (node.classes.length) {\n const decoration = Decoration.inline(from, to, {\n class: node.classes.join(' '),\n });\n\n decorations.push(decoration);\n }\n\n from = to;\n });\n });\n\n return DecorationSet.create(doc, decorations);\n}\n\nexport function PrismPlugin({\n name,\n defaultLanguage,\n defaultTheme,\n}: {\n name: string;\n defaultLanguage: string;\n defaultTheme: string;\n}) {\n if (!defaultLanguage) {\n throw Error('You must specify the defaultLanguage parameter');\n }\n\n const loadingLanguages = new Set<string>();\n let pluginView: EditorView | null = null;\n\n const onLanguageLoaded = (language: string) => {\n if (pluginView) {\n pluginView.dispatch(\n pluginView.state.tr.setMeta(PRISM_LANGUAGE_LOADED_META, language),\n );\n }\n };\n\n const prismjsPlugin: Plugin<DecorationSet> = new Plugin({\n key: new PluginKey('prism'),\n\n view(view) {\n pluginView = view;\n return {\n destroy() {\n pluginView = null;\n },\n };\n },\n\n state: {\n init: (_, { doc }) => {\n return getDecorations({\n doc,\n name,\n defaultLanguage,\n defaultTheme,\n loadingLanguages,\n onLanguageLoaded,\n });\n },\n apply: (transaction, decorationSet, oldState, newState) => {\n const oldNodeName = oldState.selection.$head.parent.type.name;\n const newNodeName = newState.selection.$head.parent.type.name;\n\n const oldNodes = findChildren(\n oldState.doc,\n (node) => node.type.name === name,\n );\n const newNodes = findChildren(\n newState.doc,\n (node) => node.type.name === name,\n );\n\n if (\n transaction.getMeta(PRISM_LANGUAGE_LOADED_META) ||\n (transaction.docChanged &&\n // Apply decorations if:\n // selection includes named node,\n ([oldNodeName, newNodeName].includes(name) ||\n // OR transaction adds/removes named node,\n newNodes.length !== oldNodes.length ||\n // OR transaction has changes that completely encapsulate a node\n // (for example, a transaction that affects the entire document).\n // Such transactions can happen during collab syncing via y-prosemirror, for example.\n transaction.steps.some((step) => {\n const rangeStep = step as unknown as {\n from?: number;\n to?: number;\n };\n return (\n rangeStep.from !== undefined &&\n rangeStep.to !== undefined &&\n oldNodes.some((node) => {\n return (\n node.pos >= rangeStep.from! &&\n node.pos + node.node.nodeSize <= rangeStep.to!\n );\n })\n );\n })))\n ) {\n return getDecorations({\n doc: transaction.doc,\n name,\n defaultLanguage,\n defaultTheme,\n loadingLanguages,\n onLanguageLoaded,\n });\n }\n\n return decorationSet.map(transaction.mapping, transaction.doc);\n },\n },\n\n props: {\n decorations(state) {\n return prismjsPlugin.getState(state);\n },\n },\n\n destroy() {\n pluginView = null;\n removePrismTheme();\n },\n });\n\n return prismjsPlugin;\n}\n","import * as ReactEmailComponents from '@react-email/components';\nimport {\n type PrismLanguage,\n CodeBlock as ReactEmailCodeBlock,\n} from '@react-email/components';\nimport { mergeAttributes } from '@tiptap/core';\nimport type { CodeBlockOptions } from '@tiptap/extension-code-block';\nimport CodeBlock from '@tiptap/extension-code-block';\nimport { EmailNode } from '../core/email-node';\nimport { PrismPlugin } from './prism-plugin';\n\nexport interface CodeBlockPrismOptions extends CodeBlockOptions {\n defaultLanguage: string;\n defaultTheme: string;\n}\n\nexport const CodeBlockPrism = EmailNode.from(\n CodeBlock.extend<CodeBlockPrismOptions>({\n addOptions(): CodeBlockPrismOptions {\n return {\n languageClassPrefix: 'language-',\n exitOnTripleEnter: false,\n exitOnArrowDown: false,\n enableTabIndentation: true,\n tabSize: 2,\n defaultLanguage: 'javascript',\n defaultTheme: 'default',\n HTMLAttributes: {},\n };\n },\n\n addAttributes() {\n return {\n ...this.parent?.(),\n language: {\n default: this.options.defaultLanguage,\n parseHTML: (element: HTMLElement | null) => {\n if (!element) {\n return null;\n }\n const { languageClassPrefix } = this.options;\n if (!languageClassPrefix) {\n return null;\n }\n const classNames = [\n ...(element.firstElementChild?.classList || []),\n ];\n const languages = classNames\n .filter((className) =>\n className.startsWith(languageClassPrefix || ''),\n )\n .map((className) => className.replace(languageClassPrefix, ''));\n const language = languages[0];\n\n if (!language) {\n return null;\n }\n\n return language;\n },\n rendered: false,\n },\n theme: {\n default: this.options.defaultTheme,\n rendered: false,\n },\n };\n },\n\n renderHTML({ node, HTMLAttributes }) {\n return [\n 'pre',\n mergeAttributes(\n this.options.HTMLAttributes,\n HTMLAttributes,\n {\n class: node.attrs.language\n ? `${this.options.languageClassPrefix}${node.attrs.language}`\n : null,\n },\n { 'data-theme': node.attrs.theme },\n ),\n [\n 'code',\n {\n class: node.attrs.language\n ? `${this.options.languageClassPrefix}${node.attrs.language} node-codeTag`\n : 'node-codeTag',\n },\n 0,\n ],\n ];\n },\n\n addProseMirrorPlugins() {\n return [\n ...(this.parent?.() || []),\n PrismPlugin({\n name: this.name,\n defaultLanguage: this.options.defaultLanguage,\n defaultTheme: this.options.defaultTheme,\n }),\n ];\n },\n }),\n ({ node, styles }) => {\n const language = node.attrs?.language\n ? `${node.attrs.language}`\n : 'javascript';\n\n // @ts-expect-error -- @react-email/components does not export theme objects by name; dynamic access needed for user-selected themes\n const userTheme = ReactEmailComponents[node.attrs?.theme];\n\n // Without theme, render a gray code block\n const theme = userTheme\n ? {\n ...userTheme,\n base: {\n ...userTheme.base,\n borderRadius: '0.125rem',\n padding: '0.75rem 1rem',\n },\n }\n : {\n base: {\n color: '#1e293b',\n background: '#f1f5f9',\n lineHeight: '1.5',\n fontFamily:\n '\"Fira Code\", \"Fira Mono\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace',\n padding: '0.75rem 1rem',\n borderRadius: '0.125rem',\n },\n };\n\n return (\n <ReactEmailCodeBlock\n code={node.content?.[0]?.text ?? ''}\n language={language as PrismLanguage}\n theme={theme}\n style={{\n width: 'auto',\n ...styles.codeBlock,\n }}\n />\n );\n },\n);\n","import { mergeAttributes } from '@tiptap/core';\nimport { EmailNode } from '../core/email-node';\nimport {\n COMMON_HTML_ATTRIBUTES,\n createStandardAttributes,\n LAYOUT_ATTRIBUTES,\n} from '../utils/attribute-helpers';\nimport { inlineCssToJs } from '../utils/styles';\n\nexport interface DivOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\nexport const Div = EmailNode.create<DivOptions>({\n name: 'div',\n\n group: 'block',\n\n content: 'block+',\n\n defining: true,\n isolating: true,\n\n parseHTML() {\n return [\n {\n tag: 'div:not([data-type])',\n getAttrs: (node) => {\n if (typeof node === 'string') {\n return false;\n }\n const element = node as HTMLElement;\n const attrs: Record<string, string> = {};\n\n // Preserve all attributes\n Array.from(element.attributes).forEach((attr) => {\n attrs[attr.name] = attr.value;\n });\n\n return attrs;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n 0,\n ];\n },\n\n addAttributes() {\n return {\n ...createStandardAttributes([\n ...COMMON_HTML_ATTRIBUTES,\n ...LAYOUT_ATTRIBUTES,\n ]),\n };\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n return (\n <div\n className={node.attrs?.class || undefined}\n style={{\n ...styles.reset,\n ...inlineStyles,\n }}\n >\n {children}\n </div>\n );\n },\n});\n","export function getTextAlignment(alignment: string | undefined) {\n switch (alignment) {\n case 'left':\n return { textAlign: 'left' };\n case 'center':\n return { textAlign: 'center' };\n case 'right':\n return { textAlign: 'right' };\n default:\n return {};\n }\n}\n","import { Section as ReactEmailSection } from '@react-email/components';\nimport { mergeAttributes } from '@tiptap/core';\nimport type * as React from 'react';\nimport { EmailNode } from '../core/email-node';\nimport { getTextAlignment } from '../utils/get-text-alignment';\nimport { inlineCssToJs } from '../utils/styles';\n\ninterface SectionOptions {\n HTMLAttributes: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n section: {\n insertSection: () => ReturnType;\n };\n }\n}\n\nexport const Section = EmailNode.create<SectionOptions>({\n name: 'section',\n group: 'block',\n content: 'block+',\n isolating: true,\n defining: true,\n\n parseHTML() {\n return [{ tag: 'section[data-type=\"section\"]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'section',\n mergeAttributes(\n { 'data-type': 'section', class: 'node-section' },\n HTMLAttributes,\n ),\n 0,\n ];\n },\n\n addCommands() {\n return {\n insertSection:\n () =>\n ({ commands }) => {\n return commands.insertContent({\n type: this.name,\n content: [\n {\n type: 'paragraph',\n content: [],\n },\n ],\n });\n },\n };\n },\n\n renderToReactEmail({ children, node, styles }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n const textAlign = node.attrs?.align || node.attrs?.alignment;\n\n return (\n <ReactEmailSection\n className={node.attrs?.class || undefined}\n align={textAlign}\n style={\n {\n ...styles.section,\n ...inlineStyles,\n ...getTextAlignment(textAlign),\n } as React.CSSProperties\n }\n >\n {children}\n </ReactEmailSection>\n );\n },\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-email/editor",
|
|
3
|
-
"version": "0.0.0-experimental.
|
|
3
|
+
"version": "0.0.0-experimental.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,19 +39,18 @@
|
|
|
39
39
|
"@react-email/components": "1.0.8"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@tiptap/core": "3.10.7",
|
|
43
|
-
"@tiptap/extension-code-block": "3.10.7",
|
|
44
|
-
"@tiptap/extension-heading": "3.10.7",
|
|
45
|
-
"@tiptap/extension-horizontal-rule": "3.10.7",
|
|
46
|
-
"@tiptap/pm": "3.10.7",
|
|
47
|
-
"@tiptap/react": "3.10.7",
|
|
48
|
-
"hast-util-from-html": "2.0.3",
|
|
49
|
-
"prismjs": "1.30.0"
|
|
42
|
+
"@tiptap/core": "^3.10.7",
|
|
43
|
+
"@tiptap/extension-code-block": "^3.10.7",
|
|
44
|
+
"@tiptap/extension-heading": "^3.10.7",
|
|
45
|
+
"@tiptap/extension-horizontal-rule": "^3.10.7",
|
|
46
|
+
"@tiptap/pm": "^3.10.7",
|
|
47
|
+
"@tiptap/react": "^3.10.7",
|
|
48
|
+
"hast-util-from-html": "^2.0.3",
|
|
49
|
+
"prismjs": "^1.30.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/prismjs": "1.26.5",
|
|
53
53
|
"typescript": "5.8.3",
|
|
54
|
-
"@react-email/render": "2.0.4",
|
|
55
54
|
"tsconfig": "0.0.0"
|
|
56
55
|
},
|
|
57
56
|
"publishConfig": {
|