{"version":3,"sources":["../src/html.ts","../src/utils/dom.ts"],"sourcesContent":["import merge from 'lodash.merge'\nimport { Editor, Text, Node } from '@editablejs/models'\nimport { htmlAttributesToString, cssStyleToString } from './utils/dom'\nimport { TextSerializer } from './text'\n\nexport type HTMLSerializerAttributes =\n  | Omit<\n      Omit<React.AllHTMLAttributes<HTMLElement>, 'value'>,\n      keyof React.DOMAttributes<HTMLElement> | 'style'\n    >\n  | Record<string, string | boolean | number | undefined>\n\nexport type HTMLSerializerStyle = Partial<CSSStyleDeclaration>\nexport interface HTMLSerializerOptions {\n  attributes?: HTMLSerializerAttributes\n  style?: HTMLSerializerStyle\n}\n\nexport interface HTMLSerializerWithOptions {\n  attributes?: HTMLSerializerAttributes | ((node: Node) => HTMLSerializerAttributes)\n  style?: HTMLSerializerStyle | ((node: Node) => HTMLSerializerStyle)\n}\n\nexport type HTMLSerializerTransform = typeof HTMLSerializer.transform\n\nexport type HTMLSerializerWithTransform<T = HTMLSerializerWithOptions> = (\n  next: HTMLSerializerTransform,\n  serializer: typeof HTMLSerializer,\n  options: T,\n) => HTMLSerializerTransform\n\nexport interface EditorHTMLSerializerWithTransform<T = HTMLSerializerWithOptions> {\n  transform: HTMLSerializerWithTransform<T>\n  options: T\n}\n\nconst HTML_SERIALIZER_TRANSFORMS: WeakMap<Editor, EditorHTMLSerializerWithTransform[]> =\n  new WeakMap()\n\nexport interface EditorHTMLSerializerOptions extends HTMLSerializerOptions {\n  editor: Editor\n}\n\nconst withEditorHTMLSerializerTransform: HTMLSerializerWithTransform<\n  EditorHTMLSerializerOptions\n> = (next, _, { editor }) => {\n  return (node, options = {}) => {\n    if (Text.isText(node)) return TextSerializer.transformWithEditor(editor, node)\n    return next(node, options)\n  }\n}\n\nexport const HTMLSerializer = {\n  transform(node: Node, options: HTMLSerializerOptions = {}): string {\n    const { attributes, style } = options\n    if (Text.isText(node)) return TextSerializer.transform(node)\n    const { children } = node\n    const html = children.map(child => this.transform(child)).join('')\n    if (Editor.isEditor(node)) return html\n    const { type } = node\n    let nodeName = type ?? 'p'\n    switch (type) {\n      case 'paragraph':\n        nodeName = 'p'\n        break\n    }\n    return this.create(nodeName, attributes, style, html)\n  },\n\n  create(\n    tag: string,\n    attributes: HTMLSerializerAttributes = {},\n    style?: HTMLSerializerStyle,\n    children: string = '',\n  ) {\n    const attributesString = htmlAttributesToString(attributes)\n    const styleString = style ? cssStyleToString(style) : ''\n    const lineStyle = styleString ? ` style=\"${styleString}\"` : \"\"\n\n    return `<${tag} ${attributesString}${lineStyle}>${children}</${tag}>`\n  },\n\n  mergeOptions<T = HTMLSerializerAttributes | HTMLSerializerStyle>(\n    node: Node,\n    options: T,\n    ...customOptions: (T | ((node: Node) => T))[]\n  ) {\n    let mergedOptions = options\n    for (const customOption of customOptions) {\n      mergedOptions = merge(\n        mergedOptions,\n        customOption instanceof Function ? customOption(node) : customOption,\n      )\n    }\n    return mergedOptions\n  },\n\n  with<T = HTMLSerializerOptions>(transform: HTMLSerializerWithTransform<T>, options: T) {\n    const { transform: t } = this\n    this.transform = transform(t.bind(this), this, options)\n  },\n\n  withEditor<T = HTMLSerializerOptions>(\n    editor: Editor,\n    transform: HTMLSerializerWithTransform<T>,\n    options: T,\n  ) {\n    const fns = HTML_SERIALIZER_TRANSFORMS.get(editor) ?? []\n    if (fns.find(fn => fn.transform === transform)) return\n    fns.push({\n      transform: transform as HTMLSerializerWithTransform,\n      options: options as HTMLSerializerOptions,\n    })\n    HTML_SERIALIZER_TRANSFORMS.set(editor, fns)\n  },\n\n  transformWithEditor(editor: Editor, node: Node = editor) {\n    const HTMLSerializerEditor = Object.assign({}, HTMLSerializer)\n    const transforms = HTML_SERIALIZER_TRANSFORMS.get(editor) ?? []\n\n    HTMLSerializerEditor.with(withEditorHTMLSerializerTransform, { editor })\n\n    for (const { transform, options } of transforms) {\n      HTMLSerializerEditor.with(transform, options)\n    }\n\n    return HTMLSerializerEditor.transform(node)\n  },\n}\n","const kebabCase = (str: string) => {\n  const regex = new RegExp(/[A-Z]/g)\n  return str.replace(regex, v => `-${v.toLowerCase()}`)\n}\n/**\n * CSSStyle 转换为 style 字符串\n */\nexport const cssStyleToString = (style: Partial<CSSStyleDeclaration>): string => {\n  return Object.keys(style).reduce((accumulator, key) => {\n    // transform the key from camelCase to kebab-case\n    const cssKey = kebabCase(key)\n    // remove ' in value\n    const cssValue = (style as Record<string, any>)[key].replace(\"'\", '')\n    // build the result\n    // you can break the line, add indent for it if you need\n    return `${accumulator}${cssKey}:${cssValue};`\n  }, '')\n}\n\n/**\n * React.HTMLAttributes<HTMLElement> 转换为 attributes 字符串\n */\nexport const htmlAttributesToString = (attributes: Record<string, any>): string => {\n  return Object.keys(attributes).reduce((accumulator, key) => {\n    // transform the key from camelCase to kebab-case\n    const attrKey = kebabCase(key)\n    // remove ' in value\n    const attrValue = String(attributes[key]).replace(\"'\", '')\n    // build the result\n    // you can break the line, add indent for it if you need\n    return `${accumulator}${attrKey}=\"${attrValue}\" `\n  }, '')\n}\n"],"mappings":"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","names":[]}