From 73c893947603548ba2a995550779a47b2e0e19f4 Mon Sep 17 00:00:00 2001 From: oleast Date: Wed, 21 Dec 2022 12:29:32 +0100 Subject: [PATCH] feat(readme): add a readme to the project --- README.md | 213 ++++++++++++++++++++ src/examples/divToParagraphConverter.ts | 36 ++++ src/examples/imgToEmbeddedAssetConverter.ts | 33 +++ src/examples/spanWithMarksConverter.ts | 39 ++++ tsconfig.build.json | 2 +- 5 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 src/examples/divToParagraphConverter.ts create mode 100644 src/examples/imgToEmbeddedAssetConverter.ts create mode 100644 src/examples/spanWithMarksConverter.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..7cb85ab --- /dev/null +++ b/README.md @@ -0,0 +1,213 @@ +# Contentful Rich Text HTML Parser + +_Convert just about any HTML document to the Contentful Rich Text format!_ + +This library aims to make it easy to convert any HTML to the Contentful Rich Text format. It will convert relevant HTML elements without any configuration and can be configured to support different styles of rich text formats. + +## Installation + +```bash +npm install contentful-rich-text-html-parser +``` + +## Usage + +```typescript +import { htmlStringToDocument } from "contentful-rich-text-html-parser"; + +const htmlString = `

Hello world!

`; + +htmlStringToDocument(htmlString); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'paragraph', +// content: [ +// { +// nodeType: 'text', +// value: 'Hello world!', +// marks: [], +// }, +// ], +// }, +// ], +// }; +``` + +## HTML tag and rich text node support + +The default configuration supports the following list of HTML tags which by default map to the corresponding rich text node type. + +- `"h1" => BLOCKS.HEADING_1` +- `"h2" => BLOCKS.HEADING_2` +- `"h3" => BLOCKS.HEADING_3` +- `"h4" => BLOCKS.HEADING_4` +- `"h5" => BLOCKS.HEADING_5` +- `"h6" => BLOCKS.HEADING_6` +- `"hr" => BLOCKS.HR` +- `"li" => BLOCKS.LIST_ITEM` +- `"ol" => BLOCKS.OL_LIST` +- `"p" => BLOCKS.PARAGRAPH` +- `"blockquote" => BLOCKS.QUOTE` +- `"table" => BLOCKS.TABLE` +- `"td" => BLOCKS.TABLE_CELL` +- `"th" => BLOCKS.TABLE_HEADER_CELL` +- `"tr" => BLOCKS.TABLE_ROW` +- `"ul" => BLOCKS.UL_LIST` +- `"b" => MARKS.BOLD` +- `"strong" => MARKS.BOLD` +- `"pre" => MARKS.CODE` +- `"i" => MARKS.ITALIC` +- `"sub" => MARKS.SUBSCRIPT` +- `"sup" => MARKS.SUPERSCRIPT` +- `"u" => MARKS.UNDERLINE` +- `"a" => INLINES.HYPERLINK` + +## Adding support for other HTML elements or node types + +This library can be configured to support custom HTML structures to fit your needs by using a custom `options`-object. + +### Example 1: Change all "div" elements to "p" elements + +```typescript +import { Block, BLOCKS } from "@contentful/rich-text-types"; +import { + htmlStringToDocument, + Options, + TagConverter, +} from "contentful-rich-text-html-parser"; + +const divToParagraphConverter: TagConverter = (node, next) => { + return { + nodeType: BLOCKS.PARAGRAPH, + content: next(node), + data: {}, + }; +}; + +const options: Options = { + convertTag: { + div: divToParagraphConverter, + }, +}; + +const htmlString = `
Text in a div!
`; + +htmlStringToDocument(htmlString, options); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'paragraph', +// content: [ +// { +// nodeType: 'text', +// value: 'Text in a div!', +// marks: [], +// }, +// ], +// }, +// ], +// }; +``` + +### Example 2: use a CSS class name to add a mark + +```typescript +import { Inline, Mark } from "@contentful/rich-text-types"; +import { + htmlStringToDocument, + Options, + TagConverter, +} from "contentful-rich-text-html-parser"; + +const boldMark: Mark = { + type: "bold", +}; + +const spanWithMarksConverter: TagConverter = (node, next) => { + const isBold = node.attrs.class === "bold"; + + // Ignore the "span" element while adding marks to all text element children. + return next(node, isBold ? boldMark : undefined); +}; + +const options: Options = { + convertTag: { + span: spanWithMarksConverter, + }, +}; + +const htmlString = `

Bold text in a span!

`; + +htmlStringToDocument(htmlString, options); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'paragraph', +// content: [ +// { +// nodeType: 'text', +// value: 'Bold text in a span!', +// marks: [{ type: 'bold' }], +// }, +// ], +// }, +// ], +// }; +``` + +## Assets, images, videos, other media, and files + +By default, all `img`, `video`, `source`, and other media elements are ignored by the parser. + +It is however possible to add a `convertTag` option to configure support for these elements yourself! + +**It is however important to note that you would have to find your own way of converting these images to valid assets that could be uploaded to Contentful if that is your goal"** + +### Example 3: Custom "img" converter + +```typescript +import { Block, BLOCKS } from "@contentful/rich-text-types"; +import { + htmlStringToDocument, + Options, + TagConverter, +} from "contentful-rich-text-html-parser"; + +const imgToEmbeddedAssetConverter: TagConverter = (node, next) => { + return { + nodeType: BLOCKS.EMBEDDED_ASSET, + content: next(node), + data: { + src: node.attrs.src, + }, + }; +}; + +const options: Options = { + convertTag: { + img: imgToEmbeddedAssetConverter, + }, +}; + +const htmlString = ``; + +htmlStringToDocument(htmlString, options); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'embedded-asset-block', +// content: [], +// data: { src: 'https://path-to-image' } +// }, +// ], +// }; +``` diff --git a/src/examples/divToParagraphConverter.ts b/src/examples/divToParagraphConverter.ts new file mode 100644 index 0000000..67dbe99 --- /dev/null +++ b/src/examples/divToParagraphConverter.ts @@ -0,0 +1,36 @@ +import { Block, BLOCKS } from "@contentful/rich-text-types"; +import { htmlStringToDocument, Options, TagConverter } from "../index"; + +const divToParagraphConverter: TagConverter = (node, next) => { + return { + nodeType: BLOCKS.PARAGRAPH, + content: next(node), + data: {}, + }; +}; + +const options: Options = { + convertTag: { + div: divToParagraphConverter, + }, +}; + +const htmlString = `
Text in a div!
`; + +htmlStringToDocument(htmlString, options); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'paragraph', +// content: [ +// { +// nodeType: 'text', +// value: 'Text in a div!', +// marks: [], +// }, +// ], +// }, +// ], +// }; diff --git a/src/examples/imgToEmbeddedAssetConverter.ts b/src/examples/imgToEmbeddedAssetConverter.ts new file mode 100644 index 0000000..2b8df29 --- /dev/null +++ b/src/examples/imgToEmbeddedAssetConverter.ts @@ -0,0 +1,33 @@ +import { Block, BLOCKS } from "@contentful/rich-text-types"; +import { htmlStringToDocument, Options, TagConverter } from "../index"; + +const imgToEmbeddedAssetConverter: TagConverter = (node, next) => { + return { + nodeType: BLOCKS.EMBEDDED_ASSET, + content: next(node), + data: { + src: node.attrs.src, + }, + }; +}; + +const options: Options = { + convertTag: { + img: imgToEmbeddedAssetConverter, + }, +}; + +const htmlString = ``; + +htmlStringToDocument(htmlString, options); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'embedded-asset-block', +// content: [], +// data: { src: 'https://path-to-image' } +// }, +// ], +// }; diff --git a/src/examples/spanWithMarksConverter.ts b/src/examples/spanWithMarksConverter.ts new file mode 100644 index 0000000..621af1a --- /dev/null +++ b/src/examples/spanWithMarksConverter.ts @@ -0,0 +1,39 @@ +import { Inline, Mark } from "@contentful/rich-text-types"; +import { htmlStringToDocument, Options, TagConverter } from "../index"; + +const boldMark: Mark = { + type: "bold", +}; + +const spanWithMarksConverter: TagConverter = (node, next) => { + const isBold = node.attrs.class === "bold"; + + // Ignore the "span" element while adding marks to all text element children. + return next(node, isBold ? boldMark : undefined); +}; + +const options: Options = { + convertTag: { + span: spanWithMarksConverter, + }, +}; + +const htmlString = `

Bold text in a span!

`; + +htmlStringToDocument(htmlString, options); + +// { +// nodeType: 'document', +// content: [ +// { +// nodeType: 'paragraph', +// content: [ +// { +// nodeType: 'text', +// value: 'Bold text in a span!', +// marks: [{ type: 'bold' }], +// }, +// ], +// }, +// ], +// }; diff --git a/tsconfig.build.json b/tsconfig.build.json index c618221..44f12f8 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,5 +1,5 @@ { "extends": "./tsconfig", "compilerOptions": {}, - "exclude": ["src/test", "node_modules", "dist"] + "exclude": ["src/test", "src/examples", "node_modules", "dist"] }