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

feat: add transform option #987

Merged
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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
- [replace element and children](#replace-element-and-children)
- [replace element attributes](#replace-element-attributes)
- [replace and remove element](#replace-and-remove-element)
- [transform](#transform)
- [library](#library)
- [htmlparser2](#htmlparser2)
- [trim](#trim)
Expand Down Expand Up @@ -303,6 +304,21 @@ HTML output:
<p></p>
```

### transform

The `transform` option allows you to transform each element individually after it's parsed.

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

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

### library

The `library` option specifies the UI library. The default library is **React**.
Expand Down
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export interface HTMLReactParserOptions {
domNode: DOMNode
) => JSX.Element | object | void | undefined | null | false;

transform?: (
reactNode: JSX.Element | string,
domNode: DOMNode,
index: number
) => JSX.Element | string | null;

trim?: boolean;
}

Expand Down
8 changes: 5 additions & 3 deletions lib/dom-to-react.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var canTextBeChildOfNode = utilities.canTextBeChildOfNode;
* @param {DomElement[]} nodes - DOM nodes.
* @param {object} [options={}] - Options.
* @param {Function} [options.replace] - Replacer.
* @param {Function} [options.transform] - Transform.
* @param {object} [options.library] - Library (React, Preact, etc.).
* @returns - String or JSX element(s).
*/
Expand All @@ -26,6 +27,7 @@ function domToReact(nodes, options) {
var node;
var isWhitespace;
var hasReplace = typeof options.replace === 'function';
var transform = options.transform || utilities.returnFirstArg;
var replaceElement;
var props;
var children;
Expand All @@ -46,7 +48,7 @@ function domToReact(nodes, options) {
key: replaceElement.key || i
});
}
result.push(replaceElement);
result.push(transform(replaceElement, node, i));
continue;
}
}
Expand All @@ -68,7 +70,7 @@ function domToReact(nodes, options) {

// We have a text node that's not whitespace and it can be nested
// in its parent so add it to the results
result.push(node.data);
result.push(transform(node.data, node, i));
continue;
}

Expand Down Expand Up @@ -115,7 +117,7 @@ function domToReact(nodes, options) {
props.key = i;
}

result.push(createElement(node.name, props, children));
result.push(transform(createElement(node.name, props, children), node, i));
}

return result.length === 1 ? result[0] : result;
Expand Down
7 changes: 6 additions & 1 deletion lib/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,16 @@ function canTextBeChildOfNode(node) {
return !elementsWithNoTextChildren.has(node.name);
}

function returnFirstArg(arg) {
return arg;
}

module.exports = {
PRESERVE_CUSTOM_ATTRIBUTES: PRESERVE_CUSTOM_ATTRIBUTES,
invertObject: invertObject,
isCustomComponent: isCustomComponent,
setStyleProp: setStyleProp,
canTextBeChildOfNode: canTextBeChildOfNode,
elementsWithNoTextChildren: elementsWithNoTextChildren
elementsWithNoTextChildren: elementsWithNoTextChildren,
returnFirstArg: returnFirstArg
};
37 changes: 37 additions & 0 deletions test/dom-to-react.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,43 @@ describe('domToReact replace option', () => {
});
});

describe('domToReact transform option', () => {
it('can wrap all elements', () => {
const options = {
transform: (reactNode, domNode, i) => {
return React.createElement('div', { key: i }, reactNode);
}
};

const reactElement = domToReact(htmlToDOM(html.list), options);
expect(reactElement.key).toBe('0');
expect(reactElement.props.children.props.children[0].key).toBe('0');
expect(reactElement.props.children.props.children[1].key).toBe('1');
expect(reactElement).toMatchInlineSnapshot(`
<div>
<ol>
<div>
<li>
<div>
One
</div>
</li>
</div>
<div>
<li
value="2"
>
<div>
Two
</div>
</li>
</div>
</ol>
</div>
`);
});
});

describe('domToReact', () => {
describe('when React >=16', () => {
it('preserves unknown attributes', () => {
Expand Down
Loading