feat: provide Fragment component

Adds a new Fragment component that provides the same functionality as
React.Fragment. See issue #9 for details.

closes issue #9
This commit is contained in:
M. George Hansen 2020-06-04 11:25:34 -07:00
parent b112dc2d97
commit da241efb59
Signed by: mgeorgehansen
SSH key fingerprint: SHA256:JlIGiQLPyQ2RHTH3a2oVlb20Xkh9Glr8DUF4YTXHJxM
4 changed files with 43 additions and 4 deletions

View file

@ -44,3 +44,9 @@ export interface Component<P extends object = {}> {
}
): HTMLElement;
}
export const Fragment: Component<{}> = ({ children }) => ({
tag: "#fragment",
attributes: {},
children: children || [],
});

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
export { HTMLElement, Component } from "./component";
export { HTMLElement, Component, Fragment } from "./component";
export { UserConfig as Config } from "./config";
export { createElement } from "./create-element";
export * from "./jsx";

View file

@ -42,6 +42,10 @@ const renderElement = (elem: Element): string => {
};
const startTag = (elem: HTMLElement): string => {
if (elem.tag === "#fragment") {
return "";
}
let output = `<${escapeHtml(elem.tag)}`;
for (const [attrName, attrValue] of Object.entries(elem.attributes)) {
@ -68,7 +72,12 @@ const startTag = (elem: HTMLElement): string => {
return output;
};
const endTag = (elem: HTMLElement): string => `</${escapeHtml(elem.tag)}>`;
const endTag = (elem: HTMLElement): string => {
if (elem.tag === "#fragment") {
return "";
}
return `</${escapeHtml(elem.tag)}>`;
};
/**
* Render a complete HTML page from an HTMLElement. Note that the root element
@ -78,7 +87,17 @@ const endTag = (elem: HTMLElement): string => `</${escapeHtml(elem.tag)}>`;
*
* @return Fully rendered HTML document as a string.
*/
export const renderPage = (rootElem: HTMLElement): string => {
export const renderPage = (rootElem: Element): string => {
if (rootElem == undefined) {
throw new Error(`root page element cannot be null`);
}
if (typeof rootElem !== "object" || !("tag" in rootElem)) {
throw new Error(
`root page element must be a valid HTMLElement, got ${JSON.stringify(
rootElem
)}`
);
}
if (rootElem.tag.toLowerCase() !== "html") {
throw new Error(
`attempted to render page with non-HTML root element ${rootElem.tag}`

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { Component, createElement } from "../../dist";
import { Component, createElement, Fragment } from "../../dist";
import { renderPage } from "../../dist/render";
import { testSuite } from "../lib";
@ -103,4 +103,18 @@ testSuite("renderPage", ({ test, expect }) => {
"<!DOCTYPE html><html>There are <div>3 lights</div>!</html>"
);
});
test("renders fragment children only", () => {
const html = renderPage(
<html>
<Fragment>
<div>test of</div>
<div>fragments</div>
</Fragment>
</html>
);
expect(html).toEqual(
"<!DOCTYPE html><html><div>test of</div><div>fragments</div></html>"
);
});
});