Skip to content

Instantly share code, notes, and snippets.

@JosephScript
Created July 26, 2024 19:23
Show Gist options
  • Save JosephScript/3abac1facaa71ae27b90597a34b4e31f to your computer and use it in GitHub Desktop.
Save JosephScript/3abac1facaa71ae27b90597a34b4e31f to your computer and use it in GitHub Desktop.
CraftJS generateEditorJson with only JSON
import { ROOT_NODE, UserComponent } from '@craftjs/core'
import { getRandomId } from '@craftjs/utils'
// We can infer the NodeConfig type from the UserComponent's props
type NodeConfig<T extends UserComponent> = {
node: T
props: React.ComponentProps<T>
}
export const generateEditorJson = <T extends UserComponent>(
nodes: NodeConfig<T>[],
) => {
// Initial nodes, directly add to root
const initialNodes: Record<string, any> = {
[ROOT_NODE]: {
type: { resolvedName: 'Container' }, // swap Container with whatever you like as your root node
displayName: 'Container', // this also assumes you have a component registered named "Container"
isCanvas: true,
hidden: false,
custom: {},
props: {},
nodes: [],
linkedNodes: {},
},
}
nodes.forEach((nodeConfig) => {
const nodeId = getRandomId()
const { node, props } = nodeConfig
const resolvedName = node.name
const defaultProps = node.craft?.props
initialNodes[ROOT_NODE].nodes.push(nodeId)
initialNodes[nodeId] = {
type: { resolvedName },
displayName: node.craft?.displayName || resolvedName, // Fallback to resolvedName if displayName is not provided
parent: ROOT_NODE,
isCanvas: false,
hidden: false,
custom: {},
props: { ...defaultProps, ...props }, // Merge default and provided props
nodes: [], // Add child nodes if necessary,
linkedNodes: {},
}
})
return JSON.stringify(initialNodes)
}
@JosephScript
Copy link
Author

Usage example:

import React from 'react';
import { Editor, Frame, Element } from '@craftjs/core';
import { generateEditorJson } from './utils/generateEditorJson'; // Assuming the provided function is in a file named generateEditorJson.ts

// Define your User Components
const Text: UserComponent<{ text: string; fontSize: number }> = ({ text, fontSize }) => (
  <span style={{ fontSize }}>{text}</span>
);

Text.craft = {
  props: {
    text: 'Hello',
    fontSize: 16,
  },
};

const Button: UserComponent<{ children: React.ReactNode }> = ({ children }) => (
  <button>{children}</button>
);

// Example usage
const nodes = [
  {
    node: Text,
    props: { text: 'Welcome to CraftJS!', fontSize: 24 },
  },
  {
    node: Button,
    props: { children: 'Learn More' },
  },
];

const App = () => {
  const initialEditorJson = generateEditorJson(nodes);

  return (
    <Editor resolver={{ Text, Button, Container }}> 
      <Frame json={initialEditorJson}>
        {/* This will be empty as the initial state is loaded from the JSON */}
      </Frame>
    </Editor>
  );
};

export default App;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment