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

refactor: migrate to TypeScript #1123

Merged
merged 1 commit into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: npm run lint

- name: Type check
run: npm run lint:dts
run: npm run lint:tsc

- name: Run unit tests
run: npm run test:ci
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ jspm_packages
.node_repl_history

# Build files
build
dist
dist/
lib/

# Vim swap files
*.swp
Expand Down
1 change: 0 additions & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"trailingComma": "none",
"singleQuote": true
}
124 changes: 74 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ To replace an element with another element, check out the [`replace`](#replace)

#### Example

```js
const parse = require('html-react-parser');
```ts
import parse from 'html-react-parser';

parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
```

Expand All @@ -43,6 +44,7 @@ parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
- [htmlparser2](#htmlparser2)
- [trim](#trim)
- [Migration](#migration)
- [v5](#v5)
- [v4](#v4)
- [v3](#v3)
- [v2](#v2)
Expand Down Expand Up @@ -100,31 +102,31 @@ yarn add html-react-parser

Import ES module:

```js
```ts
import parse from 'html-react-parser';
```

Or require CommonJS module:

```js
const parse = require('html-react-parser');
```ts
const parse = require('html-react-parser').default;
```

Parse single element:

```js
```ts
parse('<h1>single</h1>');
```

Parse multiple elements:

```js
```ts
parse('<li>Item 1</li><li>Item 2</li>');
```

Make sure to render parsed adjacent elements under a parent element:

```jsx
```tsx
<ul>
{parse(`
<li>Item 1</li>
Expand All @@ -135,15 +137,15 @@ Make sure to render parsed adjacent elements under a parent element:

Parse nested elements:

```js
```ts
parse('<body><p>Lorem ipsum</p></body>');
```

Parse element with attributes:

```js
```ts
parse(
'<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">'
'<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">',
);
```

Expand All @@ -153,19 +155,19 @@ The `replace` option allows you to replace an element with another element.

The `replace` callback's first argument is [domhandler](https://github.com/fb55/domhandler#example)'s node:

```js
```ts
parse('<br>', {
replace: (domNode) => {
replace(domNode) {
console.dir(domNode, { depth: null });
}
},
});
```

<details>
<summary>Console output</summary>
<p>

```js
```ts
Element {
type: 'tag',
parent: null,
Expand All @@ -184,29 +186,43 @@ Element {

The element is replaced if a **valid** React element is returned:

```jsx
```tsx
parse('<p id="replace">text</p>', {
replace: (domNode) => {
replace(domNode) {
if (domNode.attribs && domNode.attribs.id === 'replace') {
return <span>replaced</span>;
}
}
},
});
```

#### replace with TypeScript

For TypeScript projects, you may need to check that `domNode` is an instance of domhandler's `Element`:
For TypeScript, you'll need to check that `domNode` is an instance of domhandler's `Element`:

```tsx
import { HTMLReactParserOptions, Element } from 'html-react-parser';

const options: HTMLReactParserOptions = {
replace: (domNode) => {
replace(domNode) {
if (domNode instanceof Element && domNode.attribs) {
// ...
}
}
},
};
```

Or use a type assertion:

```tsx
import { HTMLReactParserOptions, Element } from 'html-react-parser';

const options: HTMLReactParserOptions = {
replace(domNode) {
if ((domNode as Element).attribs) {
// ...
}
},
};
```

Expand All @@ -216,7 +232,7 @@ If you're having issues take a look at our [Create React App example](./examples

Replace the element and its children (see [demo](https://replit.com/@remarkablemark/html-react-parser-replace-example)):

```jsx
```tsx
import parse, { domToReact } from 'html-react-parser';

const html = `
Expand All @@ -228,7 +244,7 @@ const html = `
`;

const options = {
replace: ({ attribs, children }) => {
replace({ attribs, children }) {
if (!attribs) {
return;
}
Expand All @@ -244,7 +260,7 @@ const options = {
</span>
);
}
}
},
};

parse(html, options);
Expand Down Expand Up @@ -273,20 +289,20 @@ parse(html, options);

Convert DOM attributes to React props with `attributesToProps`:

```jsx
```tsx
import parse, { attributesToProps } from 'html-react-parser';

const html = `
<main class="prettify" style="background: #fff; text-align: center;" />
`;

const options = {
replace: (domNode) => {
replace(domNode) {
if (domNode.attribs && domNode.name === 'main') {
const props = attributesToProps(domNode.attribs);
return <div {...props} />;
}
}
},
};

parse(html, options);
Expand All @@ -307,9 +323,9 @@ parse(html, options);

[Exclude](https://replit.com/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`:

```jsx
```tsx
parse('<p><br id="remove"></p>', {
replace: ({ attribs }) => attribs && attribs.id === 'remove' && <></>
replace: ({ attribs }) => attribs?.id === 'remove' && <></>,
});
```

Expand All @@ -330,12 +346,12 @@ The `transform` option allows you to transform each element individually after i

The `transform` callback's first argument is the React element:

```jsx
```tsx
parse('<br>', {
transform: (reactNode, domNode, index) => {
transform(reactNode, domNode, index) {
// this will wrap every element in a div
return <div>{reactNode}</div>;
}
},
});
```

Expand All @@ -345,15 +361,15 @@ The `library` option specifies the UI library. The default library is **React**.

To use Preact:

```js
```ts
parse('<br>', {
library: require('preact')
library: require('preact'),
});
```

Or a custom library:

```js
```ts
parse('<br>', {
library: {
cloneElement: () => {
Expand All @@ -364,8 +380,8 @@ parse('<br>', {
},
isValidElement: () => {
/* ... */
}
}
},
},
});
```

Expand All @@ -377,42 +393,50 @@ Default [htmlparser2 options](https://github.com/fb55/htmlparser2/wiki/Parser-op

To enable [`xmlMode`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-xmlmode):

```js
```ts
parse('<p /><p />', {
htmlparser2: {
xmlMode: true
}
xmlMode: true,
},
});
```

### trim

By default, whitespace is preserved:

```js
```ts
parse('<br>\n'); // [React.createElement('br'), '\n']
```

But certain elements like `<table>` will strip out invalid whitespace:

```js
```ts
parse('<table>\n</table>'); // React.createElement('table')
```

To remove whitespace, enable the `trim` option:

```js
```ts
parse('<br>\n', { trim: true }); // React.createElement('br')
```

However, intentional whitespace may be stripped out:

```js
```ts
parse('<p> </p>', { trim: true }); // React.createElement('p')
```

## Migration

### v5

Migrated to TypeScript. CommonJS imports require the `.default` key:

```ts
const parse = require('html-react-parser').default;
```

### v4

[htmlparser2](https://github.com/fb55/htmlparser2) has been upgraded to [v9](https://github.com/fb55/htmlparser2/releases/tag/v9.0.0).
Expand All @@ -437,11 +461,11 @@ For the `replace` option, you may need to do the following:
import { Element } from 'domhandler/lib/node';

parse('<br class="remove">', {
replace: (domNode) => {
replace(domNode) {
if (domNode instanceof Element && domNode.attribs.class === 'remove') {
return <></>;
}
}
},
});
```

Expand Down Expand Up @@ -490,8 +514,8 @@ Tags are lowercased by default. To prevent that from happening, pass the [htmlpa
```js
const options = {
htmlparser2: {
lowerCaseTags: false
}
lowerCaseTags: false,
},
};
parse('<CustomElement>', options); // React.createElement('CustomElement')
```
Expand Down Expand Up @@ -527,8 +551,8 @@ Then update your Webpack config to:
module.exports = {
// ...
resolve: {
mainFields: ['browser', 'main', 'module']
}
mainFields: ['browser', 'main', 'module'],
},
};
```

Expand Down
Loading