From a46fbef65846d46db6d0ae1824447ac66d8de32c Mon Sep 17 00:00:00 2001 From: Prev Wong Date: Sat, 11 Jan 2020 17:27:15 +0800 Subject: [PATCH 1/5] update docs --- CONTRIBUTING.md | 33 ++++ packages/docs/docs/dev.md | 263 +++++++++++++++++++++++++++++ packages/docs/docusaurus.config.js | 2 +- 3 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTING.md create mode 100644 packages/docs/docs/dev.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..014f16565 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# Contributing +Thank you for considering to contribute to Craft.js! + +There are many ways to contribute - from proofreading, writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests or writing code. + +To get started right away, have a look at our [project tracker](https://github.com/prevwong/craft.js/projects) to check out a list of things that we'd like to work on right now. + +If you're interested in proposing a new feature, or found a bug that you'd like to fix - please first file a new [issue](https://github.com/prevwong/craft.js/issues) + +# Setup +1. Fork this repository and create your branch from `master` +```bash +git clone https://github.com/your-name/craft.js.git +cd craft.js +``` + +2. Install the dependencies and start the development server +```bash +> yarn install +> yarn dev +``` + +3. Here are some additional npm scripts that might be useful +```bash +> yarn clean # clean all build files from all packages in the monorepo +> yarn build # create production build for all craftjs packages +> yarn lint # run tests across the monorepo +``` +4. Profit 😁 + +# License +By contributing, you agree that your contributions will be licensed under its MIT License. + diff --git a/packages/docs/docs/dev.md b/packages/docs/docs/dev.md new file mode 100644 index 000000000..2ef206fa1 --- /dev/null +++ b/packages/docs/docs/dev.md @@ -0,0 +1,263 @@ +--- +id: dev +title: Craft.js - Build any page editor with React +--- + + + +You know a web application is fancy when it has a page editor. Without a doubt, they help boost user experience significantly. If you're a frontend developer though, and have been tasked to be build one before, then you know precisely the difficulty and challenges of building one. + +Existing libraries such as Grape.js or react-page are great for a working out-of-the-box page editor solution. However, as soon as you need to customize the look and feel of the page editor itself, you will find yourself hacking in the library's code. + + +## Introducing Craft.js +Craft.js is a React framework to build any type of page editor. Rather than providing a working page editor implementation with an user interface, Craft.js instead provides an abstraction for you to implement your own page editor upon. It comes backed-in with a extensible drag-n-drop system; handles the way React elements should be rendered/updated; and a cohesive API to interact with the editor which you can additionally implement your own features on top of. + +### TL;DR +- Design your own user interface for your page editor +- Write React components that end-user could edit +- Govern drag-and-drop conditions for your components +- Control how your components should be edited. From simple text fields to content editables and drag to resize - if you can do it in React, then it's you can do it with Craft.js. + + +## Editable React Components +Let's start with a simple Card component like so: + +```jsx +const Card = ({title}) => { + return ( +
+

{title}

+
+

Hi

+
+
+ ) +} +``` + +First, to integrate it with with Craft.js' drag-and-drop system, we just need to do the following modifications: + +```jsx +import {useNode} from "@craftjs/core"; + +const Card = ({title}) => { + const { connectors: { connect, drag } } = useNode(); + return ( +
connect(drag(dom))}> +

{title}

+
+

Hi

+
+
+ ) +} +``` + +What's happening here ? +- We passed the `connect` connector to the root element of our component; this tells Craft.js that this element represents the `Card` component. Hence, the dimensions of the specified element will be taken into considerations during drag and drop events. +- Then, we also passed `drag` connector to the same root element; this adds the drag handlers to the DOM. If the component is rendered as child of a ``, then the user will be able to drag this element and it will move the entire Text component. + + +Next, we might want to be able to control the drag-n-drop rules of our Card component. For example purposes, let's say we only want our Card component to be draggable as long as it's `title` prop is not "No Drag". We can achieve this easily like so: +```jsx +const Card = () => {...} + +Card.craft = { + rules: { + canDrag: (node) => node.data.props.title != "No Drag" + } +} +``` + +#### Droppable regions +Next, let's take a look at the `#p-only` element we specified in our Card component. What if we want this area to be droppable, where only `p` could be dropped ? + +This is where the`` component provided by Craft.js becomes useful. It defines a droppable region, where each of it's immediate child is draggable. + + +```jsx +import {useNode, Canvas} from "@craftjs/core"; + +const Card = ({title}) => { + const { connectors: { connect, drag } } = useNode(); + return ( +
connect(drag(dom))}> +

{title}

+ +

Hi

+
+
+ ) +} +``` +Your next question might be how do we control the our newly created droppable region. The `` component accepts an `is` prop which can be either a HTML element or a React component (by default, it's a `div`). So, if we supplied a React component, we could essentially achieve the same design flexibility as we've with our Card component: + +```jsx +import {useNode, Canvas} from "@craftjs/core"; + +const Container = ({children}) => { + const { connectors: {connect} } = useNode(); + return ( +
connect(dom)}> + {children} +
+ ) +} + +Container.craft = { + rules: { + canMoveIn: (incomingNode) => incomingNode.data.type == "p" + } +} + +const Card = ({title}) => { + const { connectors: { connect, drag } } = useNode(); + return ( +
connect(drag(dom))}> +

{title}

+ +

Hi

+
+
+ ) +} +``` + +Let's break this down a bit. Our `` component is being rendered as a droppable region - this means, all dropped elements will be rendered in the component's `children` prop. Next, we also specified the `connectors` just as we did previously. This time, we specified a `canMoveIn` rule where only elements with the `p` tag will be accepted into the component. + +## Control editing behaviours +Of course, any page editor must allow the end-user to edit the elements that are rendered. With Craft.js, you are in control of this as well. + +Let's implement make our `h2` element content editable so our users could visually edit the `title` prop: + +```jsx +const Card = ({title}) => { + const { connectors: { connect, drag }, setProp } = useNode(); + return ( +
connect(drag(dom))}> +

setProp(e.target.innerText)}>{title}

+ ... +
+ ) +} +``` +> In a real application, you may want to consider using react-contenteditable + +Obviously, we do not want the element to be content editable all the time; perhaps only when our Card component is actually clicked: + +```jsx +const Card = ({title}) => { + const { connectors: { connect, drag }, setProp, isSelected } = useNode((node) => ({ + isSelected: node.events.selected + })); + + return ( +
connect(drag(dom))}> +

setProp(e.target.innerText)}>{title}

+ ... +
+ ) +} +``` +What we are doing is essentially accessing Craft's internal state and retrieving information about the current instance of our Card component. In this case, we are retrieving the `selected` event state which returns `true` when the user clicks on the DOM specified by the `connect` connector of the Component. + +## Your page editor, your user interface + +Essentially, Craft.js exposes these few React components: +- `Editor` creates the Editor context and sets everything up +- `Frame` defines the editable area + +As you may have notice, none of these are UI components, instead they are intended to be plugged into any user interface that you would like to implement for your page editor. + +Let's take a look at a super simple interface that we could design: + +```jsx +// pages/index.js +import React from 'react'; + +export default function App() { + return ( + <> +

My page editor

+ {/* sets everything up */ } +
+ {/* This part is now editable */ } + { /* Creates a gray droppable div */ } +

Drag me around

+

I'm draggable too + {/* a div that is both droppable and draggable */} +

Hi

{/* a draggable h2 */} +
+ + +
+
+ + ); +} +``` + +### Interacting with the editor +Your user interface will most likely need to display some information or perform certain editor-related actions. + +Let's say we want to design a Toolbar component that does the following things: + - Tells us the the type of the currently selected element + - A button to save the current editor state + - Another button to load the last saved editor state + +```jsx +import React, {useState} from 'react'; + +export default function App() { + return ( + <> +

My page editor

+ + {/* Add this */} +
+ + ... + +
+
+ + ); +} + +const Toolbar = () => { + const [savedState, setSavedState] = useState(); + const { selectedType, actions, query } = useEditor(state => { + const selectedId = state.events.selected; + return { + selectedType: selectedId && state.nodes[selectedId].data.type + } + }); + + return ( + + ) +} +``` + +Let's break this down: +- First, we access the editor's state to retrieve the type of the currently selected element +- Then, when our "Save Checkpoint" button is clicked, we use the `serialize` query which tells the editor to return its state in a serialised JSON form. We then save the JSON output in our component's state +- Once we have the JSON, we display the "Load from checkpoint" button. When this button is clicked, we simply call the `deserialize` editor action which essentially returns the editor to the state stored in the JSON output. + + +## Closing words +These has been a high-level overview of Craft.js and we've only covered some very basic examples. We've seen how we could easily control almost every aspect of the page editor experience. Hopefully, this article has given you an idea on the possibilities of what you can do with Craft.js. diff --git a/packages/docs/docusaurus.config.js b/packages/docs/docusaurus.config.js index ce2125b59..9bbbd4ec0 100755 --- a/packages/docs/docusaurus.config.js +++ b/packages/docs/docusaurus.config.js @@ -44,7 +44,7 @@ module.exports = { }, { label: 'Tutorial', - to: 'docs/basic-tutorial', + to: 'docs/guides/basic-tutorial', }, { label: 'API Reference', From 91253fbefbb30e6c14d1982208133272ee12152a Mon Sep 17 00:00:00 2001 From: azreenashah Date: Sat, 11 Jan 2020 17:57:15 +0800 Subject: [PATCH 2/5] Update dev.md --- packages/docs/docs/dev.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/docs/docs/dev.md b/packages/docs/docs/dev.md index 2ef206fa1..740e3ee61 100644 --- a/packages/docs/docs/dev.md +++ b/packages/docs/docs/dev.md @@ -5,23 +5,23 @@ title: Craft.js - Build any page editor with React -You know a web application is fancy when it has a page editor. Without a doubt, they help boost user experience significantly. If you're a frontend developer though, and have been tasked to be build one before, then you know precisely the difficulty and challenges of building one. +You know a web application is fancy when it has a page editor. Without a doubt, a page editor helps boost user experience significantly. If you're a frontend developer and have been tasked to be build one before, then you know precisely the difficulty and challenges of building one. -Existing libraries such as Grape.js or react-page are great for a working out-of-the-box page editor solution. However, as soon as you need to customize the look and feel of the page editor itself, you will find yourself hacking in the library's code. +Existing libraries such as Grape.js or react-page are great for a working out-of-the-box page editor solution. However, as soon as you need to customise the look and feel of the page editor itself, you will find yourself hacking in the library's code. ## Introducing Craft.js -Craft.js is a React framework to build any type of page editor. Rather than providing a working page editor implementation with an user interface, Craft.js instead provides an abstraction for you to implement your own page editor upon. It comes backed-in with a extensible drag-n-drop system; handles the way React elements should be rendered/updated; and a cohesive API to interact with the editor which you can additionally implement your own features on top of. +Craft.js is a React framework to build any type of page editor. Instead of providing a working page editor implementation with a user interface, Craft.js provides an abstraction for you to implement your own page editor upon. It comes backed-in with an extensible drag-n-drop system which handles the way React elements should be rendered/updated, and a cohesive API to interact with the editor which you can additionally implement your own features on top of. ### TL;DR - Design your own user interface for your page editor - Write React components that end-user could edit - Govern drag-and-drop conditions for your components -- Control how your components should be edited. From simple text fields to content editables and drag to resize - if you can do it in React, then it's you can do it with Craft.js. +- Control how your components should be edited. From simple text fields to content editables and drag to resize; if you can do it in React, then you can do it with Craft.js. ## Editable React Components -Let's start with a simple Card component like so: +Let's start with a simple Card component like this: ```jsx const Card = ({title}) => { @@ -54,12 +54,12 @@ const Card = ({title}) => { } ``` -What's happening here ? -- We passed the `connect` connector to the root element of our component; this tells Craft.js that this element represents the `Card` component. Hence, the dimensions of the specified element will be taken into considerations during drag and drop events. -- Then, we also passed `drag` connector to the same root element; this adds the drag handlers to the DOM. If the component is rendered as child of a ``, then the user will be able to drag this element and it will move the entire Text component. +What's happening here? +- We passed the `connect` connector to the root element of our component; this tells Craft.js that this element represents the `Card` component. Hence, the dimensions of the specified element will be taken into consideration during drag and drop events. +- Then, we also passed `drag` connector to the same root element; this adds the drag handlers to the DOM. If the component is rendered as the child of a ``, the user will be able to drag this element and it will move the entire Text component. -Next, we might want to be able to control the drag-n-drop rules of our Card component. For example purposes, let's say we only want our Card component to be draggable as long as it's `title` prop is not "No Drag". We can achieve this easily like so: +Next, we might want to be able to control the drag-n-drop rules of our Card component. For example, let's say we only want our Card component to be draggable as long as its `title` prop is not "No Drag". We can achieve this easily as such: ```jsx const Card = () => {...} @@ -71,9 +71,9 @@ Card.craft = { ``` #### Droppable regions -Next, let's take a look at the `#p-only` element we specified in our Card component. What if we want this area to be droppable, where only `p` could be dropped ? +Next, let's take a look at the `#p-only` element we specified in our Card component. What if we want this area to be droppable where only `p` can be dropped? -This is where the`` component provided by Craft.js becomes useful. It defines a droppable region, where each of it's immediate child is draggable. +This is where the`` component provided by Craft.js becomes useful. It defines a droppable region where each of its immediate child is draggable. ```jsx @@ -91,7 +91,7 @@ const Card = ({title}) => { ) } ``` -Your next question might be how do we control the our newly created droppable region. The `` component accepts an `is` prop which can be either a HTML element or a React component (by default, it's a `div`). So, if we supplied a React component, we could essentially achieve the same design flexibility as we've with our Card component: +Your next question might be about how we control our newly created droppable region. The `` component accepts an `is` prop which can be either a HTML element or a React component (by default, it's a `div`). So, if we supply a React component, we can essentially achieve the same design flexibility as we have with our Card component: ```jsx import {useNode, Canvas} from "@craftjs/core"; @@ -124,12 +124,12 @@ const Card = ({title}) => { } ``` -Let's break this down a bit. Our `` component is being rendered as a droppable region - this means, all dropped elements will be rendered in the component's `children` prop. Next, we also specified the `connectors` just as we did previously. This time, we specified a `canMoveIn` rule where only elements with the `p` tag will be accepted into the component. +Let's break this down a bit. Our `` component is being rendered as a droppable region. This means, all dropped elements will be rendered in the component's `children` prop. Next, we also specified the `connectors` just as we did previously. This time, we specified a `canMoveIn` rule where only elements with the `p` tag will be accepted into the component. ## Control editing behaviours Of course, any page editor must allow the end-user to edit the elements that are rendered. With Craft.js, you are in control of this as well. -Let's implement make our `h2` element content editable so our users could visually edit the `title` prop: +Let's make our `h2` element content editable so our users could visually edit the `title` prop: ```jsx const Card = ({title}) => { @@ -168,7 +168,7 @@ Essentially, Craft.js exposes these few React components: - `Editor` creates the Editor context and sets everything up - `Frame` defines the editable area -As you may have notice, none of these are UI components, instead they are intended to be plugged into any user interface that you would like to implement for your page editor. +As you may have noticed, none of these are UI components. Instead, they are intended to be plugged into any user interface you would like to implement for your page editor. Let's take a look at a super simple interface that we could design: @@ -203,8 +203,8 @@ Your user interface will most likely need to display some information or perform Let's say we want to design a Toolbar component that does the following things: - Tells us the the type of the currently selected element - - A button to save the current editor state - - Another button to load the last saved editor state + - Has a button to save the current editor state + - Has another button to load the last saved editor state ```jsx import React, {useState} from 'react'; @@ -255,9 +255,9 @@ const Toolbar = () => { Let's break this down: - First, we access the editor's state to retrieve the type of the currently selected element -- Then, when our "Save Checkpoint" button is clicked, we use the `serialize` query which tells the editor to return its state in a serialised JSON form. We then save the JSON output in our component's state +- Then, when the "Save Checkpoint" button is clicked, we use the `serialize` query which tells the editor to return its state in a serialised JSON form. We then save the JSON output in our component's state - Once we have the JSON, we display the "Load from checkpoint" button. When this button is clicked, we simply call the `deserialize` editor action which essentially returns the editor to the state stored in the JSON output. ## Closing words -These has been a high-level overview of Craft.js and we've only covered some very basic examples. We've seen how we could easily control almost every aspect of the page editor experience. Hopefully, this article has given you an idea on the possibilities of what you can do with Craft.js. +This has been a high-level overview of Craft.js and we've only covered some very basic examples. We've seen how we could easily control almost every aspect of the page editor experience. Hopefully, this article has given you an idea on the possibilities of what you can do with Craft.js. From 552eda52b57e352b5230106f6ca0142a5417a3fd Mon Sep 17 00:00:00 2001 From: azreenashah Date: Sat, 11 Jan 2020 17:58:00 +0800 Subject: [PATCH 3/5] Update dev.md --- packages/docs/docs/dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/docs/dev.md b/packages/docs/docs/dev.md index 740e3ee61..956d8d711 100644 --- a/packages/docs/docs/dev.md +++ b/packages/docs/docs/dev.md @@ -5,7 +5,7 @@ title: Craft.js - Build any page editor with React -You know a web application is fancy when it has a page editor. Without a doubt, a page editor helps boost user experience significantly. If you're a frontend developer and have been tasked to be build one before, then you know precisely the difficulty and challenges of building one. +You know a web application is fancy when it has a page editor. Without a doubt, a page editor helps boost user experience significantly. If you're a frontend developer and have been tasked to be build one before, then you know precisely the difficulties and challenges of building one. Existing libraries such as Grape.js or react-page are great for a working out-of-the-box page editor solution. However, as soon as you need to customise the look and feel of the page editor itself, you will find yourself hacking in the library's code. From cd1d18d9f33e97980ea2f3792321bbfb3a3c35f7 Mon Sep 17 00:00:00 2001 From: Prev Wong Date: Sat, 11 Jan 2020 18:02:37 +0800 Subject: [PATCH 4/5] update demo gif --- packages/core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/README.md b/packages/core/README.md index 4492fdfd9..d2f297129 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -9,7 +9,7 @@
- +

From f7314118715b199ad9961347772601907e7bc4f7 Mon Sep 17 00:00:00 2001 From: azreenashah Date: Sat, 11 Jan 2020 18:06:54 +0800 Subject: [PATCH 5/5] Update CONTRIBUTING.md Update CONTRIBUTING.md Update CONTRIBUTING.md Update CONTRIBUTING.md update contributing fix url --- CONTRIBUTING.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 014f16565..578538c4e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,17 @@ # Contributing Thank you for considering to contribute to Craft.js! -There are many ways to contribute - from proofreading, writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests or writing code. +From proofreading, translating, writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests, or writing code, there are many ways to contribute. Upon contribution as per the [all-contributors](https://allcontributors.org/) specification, your profile will be recognised in our README's contributors section. To get started right away, have a look at our [project tracker](https://github.com/prevwong/craft.js/projects) to check out a list of things that we'd like to work on right now. -If you're interested in proposing a new feature, or found a bug that you'd like to fix - please first file a new [issue](https://github.com/prevwong/craft.js/issues) +If you are interested in proposing a new feature or have found a bug that you'd like to fix, please file a new [issue](https://github.com/prevwong/craft.js/issues). + # Setup 1. Fork this repository and create your branch from `master` ```bash -git clone https://github.com/your-name/craft.js.git +git clone https://github.com/your-name/craft.js cd craft.js ``` @@ -26,8 +27,8 @@ cd craft.js > yarn build # create production build for all craftjs packages > yarn lint # run tests across the monorepo ``` -4. Profit 😁 +4. Submit a [pull request](https://github.com/prevwong/craft.js/compare) to merge the changes from your fork :heart: # License -By contributing, you agree that your contributions will be licensed under its MIT License. +By contributing, you agree that your contributions will be licensed under MIT License.