Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

which file/package actually exports Element #182

Open
mikeycoxon opened this issue Jan 2, 2025 · 3 comments
Open

which file/package actually exports Element #182

mikeycoxon opened this issue Jan 2, 2025 · 3 comments

Comments

@mikeycoxon
Copy link

I'm trying to configure slatetohtml to convert a slate image representation to an html one as in:

<img src="..."/>

for that I need your Element type definition.

file after file says:

import { Element, Text } from 'domhandler'

but when I go to domhandler.ts it says....wait for it...the same damned thing!

so how do I import Element here:

import { SlateToHtmlConfig, payloadSlateToHtmlConfig as defaultConfig, Element } from "@slate-serializers/html";

export const config: SlateToHtmlConfig = {
  ...defaultConfig,
  elementTransforms: {
    ...defaultConfig.elementTransforms,
    image: ({ node, children = [] }) => {
      const attrs: any = {}
      return new Element(
        'img',
        {
          src: node.url,
          ...attrs,
        },
      )
    },
  },
}

??

error: Module '"@slate-serializers/html"' has no exported member 'Element'

@mikeycoxon
Copy link
Author

oh my god! - i finally found the package.json that refers to it - i had no idea that there was a npm package called "domhandler" - ok, so that's how I import it.

You should probably add that to the howto docs - i spent a few hours trying to find it.

@mikeycoxon
Copy link
Author

OK, so this is now feedback, if you're needing to add some custom configuration, for your slatetohtml serializer, I had to pull all of the default configuration out of the repo.

Therefore, in order to have this:

const html = slateToHtml(slateJson, serializerConfig);

I not only needed this:

export const serializerConfig: SlateToHtmlConfig = {
  ...config,
  elementTransforms: {
    ...config.elementTransforms,
    
    image: ({ node, children = [] }) => {
      return new Element(
        'img',
        {
          src: node.url,
        },
      )
    },
  },
}

but all of this as well:

import { SlateToHtmlConfig } from "@slate-serializers/html";
import { ChildNode, Element } from 'domhandler'

type MarkTransform = ({ node, attribs }: {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  node?: any;
  attribs?: { [key: string]: string }
}) => Element | undefined
interface MarkTransforms {
  [key: string]: MarkTransform
}

export type ElementTransform = ({
  node,
  attribs,
  children,
}: {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  node?: any
  attribs?: { [key: string]: string }
  children?: ChildNode[]
}) => Element | undefined
type AttributeTransform = ({
  node,
}: {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  node: any
}) => { [key: string]: string } | undefined

interface ElementTransforms {
  [key: string]: ElementTransform
}
interface BaseConfig {
  markMap: { [key: string]: string[] }
  elementMap: { [key: string]: string }
  // markAttributeTransform?: AttributeTransform
  elementAttributeTransform?: AttributeTransform
  defaultTag?: string
  encodeEntities?: boolean
  alwaysEncodeBreakingEntities?: boolean
  alwaysEncodeCodeEntities?: boolean
  convertLineBreakToBr?: boolean
}
interface Config extends BaseConfig {
  markTransforms?: MarkTransforms
  elementTransforms: ElementTransforms
}

const ELEMENT_NAME_TAG_MAP = {
  p: 'p',
  paragraph: 'p',
  h1: 'h1',
  h2: 'h2',
  h3: 'h3',
  h4: 'h4',
  h5: 'h5',
  h6: 'h6',
  ul: 'ul',
  ol: 'ol',
  li: 'li',
  blockquote: 'blockquote',
}

const MARK_ELEMENT_TAG_MAP = {
  strikethrough: ['s'],
  bold: ['strong'],
  underline: ['u'],
  italic: ['i'],
  code: ['pre', 'code'],
}

const styleToString = (style: { [key: string]: string }) => {
  return Object.keys(style).reduce(
    (acc, key) =>
      acc +
      key
        .split(/(?=[A-Z])/)
        .join('-')
        .toLowerCase() +
      ':' +
      style[key] +
      ';',
    '',
  )
}
const config: Config = {
  markMap: MARK_ELEMENT_TAG_MAP,
  elementMap: ELEMENT_NAME_TAG_MAP,
  elementAttributeTransform: ({ node }) => {
    if (node.align) {
      return {
        style: styleToString({
          ['text-align']: node.align,
        })
      }
    }
    return
  },
  elementTransforms: {
    quote: ({ children = [] }) => {
      const p = [new Element('p', {}, children)]
      return new Element('blockquote', {}, p)
    },
    link: ({ node, children = [] }) => {
      const attrs: any = {}
      if (node.newTab) {
        attrs.target = '_blank'
      }
      return new Element(
        'a',
        {
          href: node.url,
          ...attrs,
        },
        children,
      )
    },
  },
  encodeEntities: false,
  alwaysEncodeBreakingEntities: true,
  alwaysEncodeCodeEntities: false,
  convertLineBreakToBr: false,
}

I think for anyone to be able to extend the configuration, you need to export the whole default configuration as well as making it clear that the implementor would need to run

npm i domhandler @types/domhandler

as well

@mikeycoxon
Copy link
Author

I'm basically suggesting that your documentation needs a little more detail here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant