Support rendering @motionone/solid components (#5233)

This commit is contained in:
Bjorn Lu 2022-10-28 22:42:37 +08:00 committed by GitHub
parent c6b149bc0a
commit 7f8987085c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Support rendering `@motionone/solid` components

View file

@ -57,7 +57,7 @@ export function isAstroComponent(obj: any): obj is AstroComponent {
} }
export function isAstroComponentFactory(obj: any): obj is AstroComponentFactory { export function isAstroComponentFactory(obj: any): obj is AstroComponentFactory {
return obj == null ? false : !!obj.isAstroComponentFactory; return obj == null ? false : obj.isAstroComponentFactory === true;
} }
export async function* renderAstroComponent( export async function* renderAstroComponent(

View file

@ -56,7 +56,7 @@ export async function renderComponent(
_props: Record<string | number, any>, _props: Record<string | number, any>,
slots: any = {} slots: any = {}
): Promise<ComponentIterable> { ): Promise<ComponentIterable> {
Component = await Component; Component = (await Component) ?? Component;
switch (getComponentType(Component)) { switch (getComponentType(Component)) {
case 'fragment': { case 'fragment': {
@ -133,7 +133,14 @@ Did you mean to add ${formatList(probableRendererNames.map((r) => '`' + r + '`')
// If this component ran through `__astro_tag_component__`, we already know // If this component ran through `__astro_tag_component__`, we already know
// which renderer to match to and can skip the usual `check` calls. // which renderer to match to and can skip the usual `check` calls.
// This will help us throw most relevant error message for modules with runtime errors // This will help us throw most relevant error message for modules with runtime errors
if (Component && (Component as any)[Renderer]) { let isTagged = false;
try {
isTagged = Component && (Component as any)[Renderer];
} catch {
// Accessing `Component[Renderer]` may throw if `Component` is a Proxy that doesn't
// return the actual read-only value. In this case, ignore.
}
if (isTagged) {
const rendererName = (Component as any)[Renderer]; const rendererName = (Component as any)[Renderer];
renderer = renderers.find(({ name }) => name === rendererName); renderer = renderers.find(({ name }) => name === rendererName);
} }

View file

@ -0,0 +1,16 @@
import { Dynamic } from 'solid-js/web'
const BaseComponent = ({ tag } = {}) => {
return <Dynamic id="proxy-component" component={tag || 'div'}>Hello world</Dynamic>;
}
// Motion uses a Proxy to support syntax like `<Motion.div />` and `<Motion.button />` etc
// https://cdn.jsdelivr.net/npm/@motionone/solid@10.14.2/dist/source/motion.jsx
const ProxyComponent = new Proxy(BaseComponent, {
get: (_, tag) => (props) => {
delete props.tag
return <BaseComponent {...props} tag={tag} />;
}
})
export default ProxyComponent;

View file

@ -2,6 +2,7 @@
import Hello from '../components/Hello.jsx'; import Hello from '../components/Hello.jsx';
import WithNewlines from '../components/WithNewlines.jsx'; import WithNewlines from '../components/WithNewlines.jsx';
import { Router } from "@solidjs/router"; import { Router } from "@solidjs/router";
import ProxyComponent from '../components/ProxyComponent.jsx';
--- ---
<html> <html>
<head><title>Solid</title></head> <head><title>Solid</title></head>
@ -10,6 +11,7 @@ import { Router } from "@solidjs/router";
<Hello client:load /> <Hello client:load />
<WithNewlines client:load /> <WithNewlines client:load />
<Router /> <Router />
<ProxyComponent client:load />
</div> </div>
</body> </body>
</html> </html>

View file

@ -22,6 +22,9 @@ describe('Solid component', () => {
// test 1: Works // test 1: Works
expect($('.hello')).to.have.lengthOf(1); expect($('.hello')).to.have.lengthOf(1);
// test 2: Support rendering proxy components
expect($('#proxy-component').text()).to.be.equal('Hello world');
}); });
}); });
@ -38,6 +41,17 @@ describe('Solid component', () => {
await devServer.stop(); await devServer.stop();
}); });
it('Can load a component', async () => {
const html = await fixture.fetch('/').then((res) => res.text());
const $ = cheerio.load(html);
// test 1: Works
expect($('.hello')).to.have.lengthOf(1);
// test 2: Support rendering proxy components
expect($('#proxy-component').text()).to.be.equal('Hello world');
});
it('scripts proxy correctly', async () => { it('scripts proxy correctly', async () => {
const html = await fixture.fetch('/').then((res) => res.text()); const html = await fixture.fetch('/').then((res) => res.text());
const $ = cheerio.load(html); const $ = cheerio.load(html);