Compare commits

...

4 commits

Author SHA1 Message Date
Matthew Phillips
ecb0f0f939 Adds changeset 2021-07-14 08:34:09 -04:00
Matthew Phillips
2f61a8c745 Support passing children as props in Preact as well 2021-07-14 08:32:52 -04:00
Matthew Phillips
f177cb451e Adding a changeset 2021-07-13 17:06:19 -04:00
Matthew Phillips
0de469d273 Allow children to be passed as props in React
Closes #681
2021-07-13 17:04:11 -04:00
10 changed files with 91 additions and 8 deletions

View file

@ -0,0 +1,5 @@
---
'@astrojs/renderer-react': patch
---
Allows passing children to react components via props

View file

@ -0,0 +1,5 @@
---
'@astrojs/renderer-preact': patch
---
Allows passing children as props to Preact components

View file

@ -0,0 +1,7 @@
import { h } from 'preact';
export default ({ id, children }) => {
return (
<div id={id}>{children}</div>
);
}

View file

@ -0,0 +1,12 @@
---
import Child from '../components/Child.jsx';
---
<html>
<head><title>Children tests</title></head>
<body>
<Child id="content"><span>content</span></Child>
<Child id="prop" children={<span>prop</span>} />
<Child id="prop-and-content" children={<span>prop</span>}><span>content</span></Child>
</body>
</html>

View file

@ -0,0 +1,7 @@
import React from 'react';
export default ({ id, children }) => {
return (
<div id={id}>{children}</div>
);
}

View file

@ -0,0 +1,12 @@
---
import Child from '../components/Child.jsx';
---
<html>
<head><title>Children tests</title></head>
<body>
<Child id="content"><span>content</span></Child>
<Child id="prop" children={<span>prop</span>} />
<Child id="prop-and-content" children={<span>prop</span>}><span>content</span></Child>
</body>
</html>

View file

@ -40,4 +40,14 @@ PreactComponent('Can export a Fragment', async ({ runtime }) => {
assert.equal($('body').children().length, 0, "nothing rendered but it didn't throw."); assert.equal($('body').children().length, 0, "nothing rendered but it didn't throw.");
}); });
PreactComponent('Children passed as props', async ({ runtime }) => {
const result = await runtime.load('/child-prop');
const html = result.contents;
const $ = doc(html);
assert.equal($('#content').html(), '<span>content</span>');
assert.equal($('#prop').html(), '<span>prop</span>');
assert.equal($('#prop-and-content').html(), '<span>content</span>');
});
PreactComponent.run(); PreactComponent.run();

View file

@ -79,4 +79,14 @@ React('Get good error message when react import is forgotten', async () => {
assert.equal(result.error.message, 'React is not defined'); assert.equal(result.error.message, 'React is not defined');
}); });
React('Children passed as props', async () => {
const result = await runtime.load('/child-prop');
const html = result.contents;
const $ = doc(html);
assert.equal($('#content').html(), '<span>content</span>');
assert.equal($('#prop').html(), '<span>prop</span>');
assert.equal($('#prop-and-content').html(), '<span>content</span>');
});
React.run(); React.run();

View file

@ -2,19 +2,26 @@ import { h, Component as BaseComponent } from 'preact';
import { renderToString } from 'preact-render-to-string'; import { renderToString } from 'preact-render-to-string';
import StaticHtml from './static-html.js'; import StaticHtml from './static-html.js';
function check(Component, props, children) { async function check(Component, props, children) {
if (typeof Component !== 'function') return false; if (typeof Component !== 'function') return false;
if (Component.prototype != null && typeof Component.prototype.render === 'function') { if (Component.prototype != null && typeof Component.prototype.render === 'function') {
return BaseComponent.isPrototypeOf(Component); return BaseComponent.isPrototypeOf(Component);
} }
const { html } = renderToStaticMarkup(Component, props, children); const { html } = await renderToStaticMarkup(Component, props, children);
return typeof html === 'string'; return typeof html === 'string';
} }
function renderToStaticMarkup(Component, props, children) { async function renderToStaticMarkup(Component, props, children) {
const html = renderToString(h(Component, { ...props, children: h(StaticHtml, { value: children }), innerHTML: children })); const childrenValue = children || (await props.children);
const html = renderToString(h(Component, {
...props,
children: h(StaticHtml, {
value: childrenValue
}),
innerHTML: children
}));
return { html }; return { html };
} }

View file

@ -4,7 +4,7 @@ import StaticHtml from './static-html.js';
const reactTypeof = Symbol.for('react.element'); const reactTypeof = Symbol.for('react.element');
function check(Component, props, children) { async function check(Component, props, children) {
if (typeof Component !== 'function') return false; if (typeof Component !== 'function') return false;
if (Component.prototype != null && typeof Component.prototype.render === 'function') { if (Component.prototype != null && typeof Component.prototype.render === 'function') {
@ -26,16 +26,24 @@ function check(Component, props, children) {
return h('div'); return h('div');
} }
renderToStaticMarkup(Tester, props, children, {}); await renderToStaticMarkup(Tester, props, children, {});
if (error) { if (error) {
throw error; throw error;
} }
return isReactComponent; return isReactComponent;
} }
function renderToStaticMarkup(Component, props, children, metadata) { async function renderToStaticMarkup(Component, props, children, metadata) {
const vnode = h(Component, { ...props, children: h(StaticHtml, { value: children }), innerHTML: children }); const childrenValue = children || (await props.children);
const vnode = h(Component, {
...props,
children: h(StaticHtml, {
value: childrenValue
}),
innerHTML: children
});
let html; let html;
if (metadata && metadata.hydrate) { if (metadata && metadata.hydrate) {
html = renderToString(vnode); html = renderToString(vnode);