craft.js
craft.js copied to clipboard
Conditionally wrapping `Element` causes an error, works without wrapping
I'm trying to conditionally render either an Elemen
or the actual dom node based on whether or not I'm editing or exporting. Currently my own solution for exporting the nodes to Next.js or HTML, otherwise it requires two separate copies of the same node, one for editing and one for exporting which I'm trying to avoid.
Copying the same Element
implementation you have, I try to hand down the exact same information.
let isExporting = false;
export type Element<T extends React.ElementType> = {
id?: NodeId;
is?: T;
custom?: Record<string, any>;
children?: React.ReactNode;
canvas?: boolean;
} & React.ComponentProps<T>;
export function Element<T extends React.ElementType>({
id,
children,
...props
}: Element<T>) {
// const testElement1 = React.createElement(
// CraftElement,
// { id, is: "div", custom: props.custom, canvas: props.canvas },
// children
// );
const testElement2 = (
<CraftElement id={id} {...props}>
{children}
</CraftElement>
);
return (isExporting
? (React.createElement(props.is, props.elementProps, children))
: testElement2);
// return (
// <CraftElement id={id} {...props}>
// {children}
// </CraftElement>
// );
}
This actually works, but only as long as there are no children Element
s, as having children causes
Error: Invariant failed: The component type specified for this node (Element) does not exist in the resolver
I've tried various implementations, all failing: directly supply the props, change the is
to div
to see if it's a scope issue, etc.
Is there any way I can get this to work?
Where're you using this <Element /> component?
@prevwong I'm using it inside of a custom Element implementation. So if I'm exporting it uses React.createElement()
, else <Element id={id} is={is} {...elementProps}>{children}</Element>
And otherwise it's an exact placement where you would use Element
inside a user component.
And it works fine with text as children but not elements or components.
Weird, would it be possible for you to create a codesandbox reproducing the behaviour?
Hi I can confirm this error is still happening. It happens to me when I have < element >{children}< /element >
Has anyone managed to solve this? I appear to be having the same issue.
This is my user component that make use of the same Element
component as @xsmithdev
import React from "react";
import { Text } from "./Text";
import { Button } from "./Button";
import { Container } from "./Container";
import { Element } from "components/Element";
interface PromptProps {
background?: string;
padding?: number;
}
export const Prompt = ({ background = "#fff", padding = 20 }: PromptProps) => {
return (
<Element
id="prompt-canvas"
is={Container}
background={background}
padding={padding}
canvas
>
<div className="text-only">
<Text text="Title" fontSize={20} />
<Text text="Subtitle" fontSize={15} />
</div>
<div className="buttons-only">
<Button size="small" variant="contained" color="primary">
Learn more
</Button>
</div>
</Element>
);
};
But it gives me the following error
Error: Invariant failed: The component type specified for this node (fe) does not exist in the resolver
Weird, would it be possible for you to create a codesandbox reproducing the behaviour?
I went ahead and reproduce the behavior. Basically I'm attempting to create a custom <Element/> that wraps around <CraftJSElement/> that takes an extra prop isSSR
. If the <Element isSSR={true}/>
, the element return a React element (rather than returning a CraftJSElement/>).
https://codesandbox.io/s/craftjs-cond-element-9szcsl
Any update on this?
This issue needs attention. When you use Element
inside custom component it throws error.
I fixed this by ensuring my Container
was listed in the resolver list.
<Editor resolver={{Button, Text, Container}}> .... </Editor>
I fixed this by ensuring my
Container
was listed in the resolver list.
<Editor resolver={{Button, Text, Container}}> .... </Editor>
why would this resolve the issue
I fixed this by ensuring my
Container
was listed in the resolver list.
<Editor resolver={{Button, Text, Container}}> .... </Editor>
The reproduce code sandbox I created above (https://codesandbox.io/s/craftjs-cond-element-9szcsl) clearly has Container
in the Resolver
list and yet the issue persists.
The issue is about craft.js not resolving the default "div" I got the following error
and looking the dist folder from node_modules I was able to confirm that it was the div
Also the source code indicates that div is the default "is" value
So I finally fixed it by creating a dumb Div component
import type { ComponentProps } from 'react'
import { type Node, useNode } from '@craftjs/core'
export const Div = (
props: ComponentProps<'div'>,
) => {
const {
connectors: { connect, drag },
} = useNode()
return <div {...props} ref={ref => connect(drag(ref!))} />
}
Div.craft = {
rules: {
canDrag: (node: Node) => node.data.props.text !== 'Drag',
},
}
then I passed the Div component to the editor component
<Editor resolver={{ Card, Button, Text, Container, Div }}>
and finally where I was using Element without a "is" prop I changed it to
<Element is={Div} id="text" canvas>
I hope this is useful for someone
@Yhozen Dammnnnn!.... This is God-tier debugging! 🙌 I had to follow immediately.
This btw doesn't work
The issue is about craft.js not resolving the default "div" I got the following error
and looking the dist folder from node_modules I was able to confirm that it was the div
Also the source code indicates that div is the default "is" value
So I finally fixed it by creating a dumb Div component
import type { ComponentProps } from 'react' import { type Node, useNode } from '@craftjs/core' export const Div = ( props: ComponentProps<'div'>, ) => { const { connectors: { connect, drag }, } = useNode() return <div {...props} ref={ref => connect(drag(ref!))} /> } Div.craft = { rules: { canDrag: (node: Node) => node.data.props.text !== 'Drag', }, }
then I passed the Div component to the editor component
<Editor resolver={{ Card, Button, Text, Container, Div }}>
and finally where I was using Element without a "is" prop I changed it to
<Element is={Div} id="text" canvas>
I hope this is useful for someone
What kind of error are you getting? It is working fine for me now
This btw doesn't work
Invariant failed: The component type specified for this node (ke2) does not exist in the resolver.
I've been testing on WilsonLe's sandbox to no avail. You could try working on the sandbox and share a link to yours if you're successful. It would be very helpful 🙏
What kind of error are you getting? It is working fine for me now
This btw doesn't work