Skip to content

Commit 43da1cf

Browse files
committed
Feedback
1 parent 6b41a07 commit 43da1cf

File tree

3 files changed

+28
-20
lines changed

3 files changed

+28
-20
lines changed

README.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,19 @@ How does it work under the hood?
115115

116116
This creates a detached DOM node, with a little extra functionality attached to allow transmitting props later on.
117117

118-
This node will contain your portal contents later, within a `<div>`, and will eventually be attached in the target location.
118+
This node will contain your portal contents later, and will eventually be attached in the target location.
119119

120-
An optional options object parameter can be passed to configure the node. The only supported option is `attributes`: this can be used to set the HTML attributes (style, class, etc.) of the intermediary, like so:
120+
An optional options object parameter can be passed to configure the node.
121121

122-
```javascript
123-
const portalNode = portals.createHtmlPortalNode({
124-
attributes: { id: "div-1", style: "background-color: #aaf; width: 100px;" }
125-
});
126-
```
122+
- `options.containerElement` can be set to `'div'` or `'span'` to contigure the detached DOM node container type.
127123

128-
### `portals.createHtmlInlinePortalNode([options])`
124+
- `options.attributes` can be used to set the HTML attributes (style, class, etc.) of the intermediary, like so:
129125

130-
Same as `portal.createHtmlPortalNode`, except it uses `<span>` instead of `<div>`. This can be helpful to avoid invalid HTML when portalling videos, etc into [phrasing content](https://developer.mozilla.org/en-US/docs/Web/HTML/Content_categories#phrasing_content), which is invalid HTML markup and triggers [React validateDOMNesting](https://www.dhiwise.com/post/mastering-validatedomnesting-best-practices).
126+
```javascript
127+
const portalNode = portals.createHtmlPortalNode({
128+
attributes: { id: "div-1", style: "background-color: #aaf; width: 100px;" }
129+
});
130+
```
131131

132132
### `portals.createSvgPortalNode([options])`
133133

src/index.tsx

+17-9
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,20 @@ const ELEMENT_TYPE_SVG = 'svg';
88

99
type ANY_ELEMENT_TYPE = typeof ELEMENT_TYPE_HTML_BLOCK | typeof ELEMENT_TYPE_HTML_INLINE | typeof ELEMENT_TYPE_SVG;
1010

11-
type Options = {
12-
attributes: { [key: string]: string };
11+
type BaseOptions = {
12+
attributes?: { [key: string]: string };
1313
};
1414

15+
type HtmlOptions = BaseOptions & {
16+
containerElement?: typeof ELEMENT_TYPE_HTML_BLOCK | typeof ELEMENT_TYPE_HTML_INLINE;
17+
};
18+
19+
type SvgOptions = BaseOptions & {
20+
containerElement?: typeof ELEMENT_TYPE_SVG;
21+
};
22+
23+
type Options = HtmlOptions | SvgOptions;
24+
1525
// ReactDOM can handle several different namespaces, but they're not exported publicly
1626
// https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/shared/DOMNamespaces.js#L8-L10
1727
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
@@ -63,9 +73,10 @@ const validateElementType = (domElement: Element, elementType: ANY_ELEMENT_TYPE)
6373

6474
// This is the internal implementation: the public entry points set elementType to an appropriate value
6575
const createPortalNode = <C extends Component<any>>(
66-
elementType: ANY_ELEMENT_TYPE,
76+
defaultElementType: ANY_ELEMENT_TYPE,
6777
options?: Options
6878
): AnyPortalNode<C> => {
79+
const elementType = options?.containerElement ?? defaultElementType;
6980
let initialProps = {} as ComponentProps<C>;
7081

7182
let parent: Node | undefined;
@@ -85,7 +96,7 @@ const createPortalNode = <C extends Component<any>>(
8596
throw new Error(`Invalid element type "${elementType}" for createPortalNode: must be "div", "span" or "svg".`);
8697
}
8798

88-
if (options && typeof options === "object") {
99+
if (options && typeof options === "object" && options.attributes) {
89100
for (const [key, value] of Object.entries(options.attributes)) {
90101
element.setAttribute(key, value);
91102
}
@@ -253,15 +264,12 @@ class OutPortal<C extends Component<any>> extends React.PureComponent<OutPortalP
253264
}
254265

255266
const createHtmlPortalNode = createPortalNode.bind(null, ELEMENT_TYPE_HTML_BLOCK) as
256-
<C extends Component<any> = Component<any>>(options?: Options) => HtmlPortalNode<C>;
257-
const createHtmlInlinePortalNode = createPortalNode.bind(null, ELEMENT_TYPE_HTML_INLINE) as
258-
<C extends Component<any> = Component<any>>(options?: Options) => HtmlPortalNode<C>;
267+
<C extends Component<any> = Component<any>>(options?: HtmlOptions) => HtmlPortalNode<C>;
259268
const createSvgPortalNode = createPortalNode.bind(null, ELEMENT_TYPE_SVG) as
260-
<C extends Component<any> = Component<any>>(options?: Options) => SvgPortalNode<C>;
269+
<C extends Component<any> = Component<any>>(options?: SvgOptions) => SvgPortalNode<C>;
261270

262271
export {
263272
createHtmlPortalNode,
264-
createHtmlInlinePortalNode,
265273
createSvgPortalNode,
266274
InPortal,
267275
OutPortal,

stories/html.stories.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22

33
import { storiesOf } from '@storybook/react';
44

5-
import { createHtmlPortalNode, createHtmlInlinePortalNode, InPortal, OutPortal } from '..';
5+
import { createHtmlPortalNode, InPortal, OutPortal } from '..';
66

77
const Container = (props) =>
88
<div style={{ "border": "1px solid #222", "padding": "10px" }}>
@@ -290,7 +290,7 @@ storiesOf('Portals', module)
290290
});
291291
})
292292
.add('can render inline portal', () => {
293-
const portalNode = createHtmlInlinePortalNode();
293+
const portalNode = createHtmlPortalNode({ containerElement: 'span' });
294294

295295
return <div>
296296
<p>

0 commit comments

Comments
 (0)