├── README.md ├── .prettierignore ├── examples ├── landing │ ├── seo │ │ ├── urllist.txt │ │ ├── googlee6ec608adf0c9ed0.html │ │ └── sitemap.xml │ ├── .babelrc │ ├── components │ │ ├── selectors │ │ │ ├── index.ts │ │ │ ├── Video │ │ │ │ ├── VideoSettings.tsx │ │ │ │ └── index.tsx │ │ │ ├── Custom1 │ │ │ │ └── index.tsx │ │ │ ├── Custom2 │ │ │ │ └── index.tsx │ │ │ ├── Custom3 │ │ │ │ └── index.tsx │ │ │ ├── Text │ │ │ │ └── index.tsx │ │ │ ├── Button │ │ │ │ ├── index.tsx │ │ │ │ └── ButtonSettings.tsx │ │ │ └── Container │ │ │ │ └── index.tsx │ │ └── editor │ │ │ ├── index.ts │ │ │ ├── Toolbar │ │ │ ├── ToolbarDropdown.tsx │ │ │ ├── index.tsx │ │ │ └── ToolbarRadio.tsx │ │ │ └── Viewport │ │ │ ├── Sidebar │ │ │ ├── index.tsx │ │ │ └── SidebarItem.tsx │ │ │ └── index.tsx │ ├── next-env.d.ts │ ├── public │ │ ├── favicon.ico │ │ └── icons │ │ │ ├── arrow-up.svg │ │ │ ├── toolbox │ │ │ ├── text-fill.svg │ │ │ ├── text.svg │ │ │ ├── link.svg │ │ │ ├── container.svg │ │ │ ├── video-fill.svg │ │ │ ├── video-line.svg │ │ │ ├── rectangle.svg │ │ │ ├── button.svg │ │ │ ├── redo.svg │ │ │ └── undo.svg │ │ │ ├── square.svg │ │ │ ├── type.svg │ │ │ ├── arrow.svg │ │ │ ├── button.svg │ │ │ ├── check.svg │ │ │ ├── youtube.svg │ │ │ ├── customize.svg │ │ │ ├── layers.svg │ │ │ ├── edit.svg │ │ │ ├── delete.svg │ │ │ └── move.svg │ ├── types │ │ └── svg.d.ts │ ├── postcss.config.js │ ├── next.config.js │ ├── utils │ │ ├── text.ts │ │ └── numToMeasurement.ts │ ├── README.md │ ├── .gitignore │ ├── tailwind.config.js │ ├── pages │ │ ├── _app.tsx │ │ └── _document.tsx │ ├── styles │ │ └── app.css │ ├── tsconfig.json │ └── package.json └── basic │ ├── .babelrc │ ├── next.config.js │ ├── styles │ └── main.css │ ├── .gitignore │ ├── README.md │ ├── src │ ├── theme.js │ ├── ProTip.js │ └── Link.js │ ├── package.json │ ├── pages │ ├── _app.js │ ├── about.js │ ├── _document.js │ └── index.js │ └── components │ ├── Header.js │ ├── user │ ├── Container.js │ ├── Text.js │ └── Card.js │ ├── SettingsPanel.js │ └── Toolbox.js ├── packages ├── core │ ├── src │ │ ├── render │ │ │ ├── index.tsx │ │ │ ├── SimpleElement.tsx │ │ │ ├── RenderNode.tsx │ │ │ ├── RenderPlaceholder.tsx │ │ │ ├── DefaultRender.tsx │ │ │ ├── tests │ │ │ │ └── Frame.test.tsx │ │ │ └── Frame.tsx │ │ ├── interfaces │ │ │ ├── index.ts │ │ │ ├── events.ts │ │ │ └── editor.ts │ │ ├── utils │ │ │ ├── isObject.ts │ │ │ ├── fromEntries.ts │ │ │ ├── removeNodeFromEvents.ts │ │ │ ├── mapChildrenToNodes.ts │ │ │ ├── resolveComponent.ts │ │ │ ├── createTestNode.ts │ │ │ ├── parseNodeFromJSX.tsx │ │ │ ├── mergeTrees.tsx │ │ │ ├── serializeNode.tsx │ │ │ └── tests │ │ │ │ └── parseNodeFromJSX.test.tsx │ │ ├── editor │ │ │ ├── index.tsx │ │ │ ├── EditorContext.tsx │ │ │ ├── tests │ │ │ │ └── Editor.test.tsx │ │ │ ├── useInternalEditor.ts │ │ │ └── Editor.tsx │ │ ├── nodes │ │ │ ├── index.ts │ │ │ ├── NodeElement.tsx │ │ │ ├── Canvas.tsx │ │ │ ├── NodeContext.tsx │ │ │ ├── useInternalNode.ts │ │ │ └── Element.tsx │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── legacy │ │ │ │ ├── connectNode.tsx │ │ │ │ └── connectEditor.tsx │ │ │ ├── tests │ │ │ │ ├── EditorContext.test.tsx │ │ │ │ └── useEditor.test.tsx │ │ │ └── useNode.ts │ │ ├── events │ │ │ ├── index.tsx │ │ │ ├── defineEventListener.ts │ │ │ ├── EventContext.ts │ │ │ ├── isEventBlockedByDescendant.ts │ │ │ ├── createShadow.ts │ │ │ ├── CoreEventHandlers.ts │ │ │ ├── movePlaceholder.ts │ │ │ └── findPosition.ts │ │ └── index.tsx │ ├── nodemon.json │ ├── .npmignore │ ├── rollup.config.js │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── LICENSE │ └── package.json ├── layers │ ├── .npmignore │ ├── src │ │ ├── manager │ │ │ ├── index.tsx │ │ │ ├── context.tsx │ │ │ ├── useLayerManager.tsx │ │ │ ├── LayerManagerProvider.tsx │ │ │ └── actions.tsx │ │ ├── layers │ │ │ ├── DefaultLayer │ │ │ │ ├── index.tsx │ │ │ │ ├── svg │ │ │ │ │ ├── corner-arrow.svg │ │ │ │ │ ├── eye.svg │ │ │ │ │ ├── arrow.svg │ │ │ │ │ └── linked.svg │ │ │ │ ├── EditableLayerName.tsx │ │ │ │ └── DefaultLayer.tsx │ │ │ ├── index.ts │ │ │ ├── LayerContext.tsx │ │ │ ├── LayerIndicator.tsx │ │ │ ├── LayerContextProvider.tsx │ │ │ ├── useLayer.tsx │ │ │ └── LayerNode.tsx │ │ ├── index.tsx │ │ ├── interfaces.tsx │ │ └── events │ │ │ └── index.tsx │ ├── svg.d.ts │ ├── rollup.config.js │ ├── tsconfig.json │ ├── LICENSE │ ├── package.json │ └── README.md └── utils │ ├── nodemon.json │ ├── .npmignore │ ├── rollup.config.js │ ├── src │ ├── useEffectOnce.tsx │ ├── EventHandlers │ │ ├── index.ts │ │ ├── isEventBlockedByDescendant.ts │ │ ├── interfaces.ts │ │ └── DerivedEventHandlers.ts │ ├── index.ts │ ├── utilityTypes.ts │ ├── getRandomId.ts │ ├── deprecate.ts │ ├── RenderIndicator.tsx │ ├── useCollector.tsx │ └── tests │ │ └── History.test.ts │ ├── README.md │ ├── .gitignore │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── package.json │ └── LICENSE ├── cypress.json ├── tsconfig.jest.json ├── .yarnrc.yml ├── .prettierrc ├── site ├── static │ └── img │ │ ├── layers.gif │ │ ├── logo.png │ │ ├── favicon.ico │ │ ├── heart-fill.png │ │ ├── hearts-fill.png │ │ ├── tutorial │ │ ├── dnd.gif │ │ ├── topbar.gif │ │ ├── interface.png │ │ ├── text-edit.gif │ │ ├── save-and-load.gif │ │ ├── settings-panel.gif │ │ ├── droppable-regions.gif │ │ └── text-edit-others.gif │ │ ├── arrow-down-s-line.png │ │ └── ChevronDownSmall.svg ├── src │ ├── components │ │ ├── index.js │ │ ├── Image.js │ │ ├── Badge.js │ │ └── API.js │ ├── theme │ │ ├── Footer │ │ │ └── styles.module.css │ │ └── Root.js │ └── pages │ │ ├── index.js │ │ └── styles.module.css ├── .gitignore ├── docs │ ├── acknowledgements.md │ ├── api │ │ ├── NodeTree.md │ │ └── EditorState.md │ └── concepts │ │ └── serializing.md ├── versioned_docs │ └── version-0.1.0-beta.17 │ │ ├── acknowledgements.md │ │ ├── api │ │ ├── NodeTree.md │ │ └── EditorState.md │ │ └── concepts │ │ └── serializing.md ├── package.json └── sidebars.js ├── lerna.json ├── cypress ├── plugins │ └── index.js ├── tsconfig.json └── support │ ├── commands.ts │ └── index.ts ├── .eslintignore ├── .github ├── ISSUE_TEMPLATE │ ├── improve-documentation.md │ ├── feature_request.md │ └── bug_report.md ├── .kodiak.toml └── workflows │ ├── release.yml │ ├── deploy-gh.yml │ └── pull-request.yml ├── jest └── setup.js ├── CODEOWNERS ├── .gitignore ├── scripts ├── dev.sh ├── yalc.sh ├── deploy.sh ├── build.sh └── publish.sh ├── tsconfig.base.json ├── tsconfig.json ├── .eslintrc.js ├── CHANGELOG.md ├── LICENSE ├── rollup.config.js └── CONTRIBUTING.md /README.md: -------------------------------------------------------------------------------- 1 | packages/core/README.md -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | .jest-cache 3 | *.md 4 | *.mdx -------------------------------------------------------------------------------- /examples/landing/seo/urllist.txt: -------------------------------------------------------------------------------- 1 | https://craft.js.org/ 2 | -------------------------------------------------------------------------------- /packages/core/src/render/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Frame'; 2 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3002" 3 | } 4 | -------------------------------------------------------------------------------- /examples/basic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/layers/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | rollup.config.js 3 | tsconfig.json -------------------------------------------------------------------------------- /tsconfig.jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ext": "js,jsx,json,ts,tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/utils/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ext": "js,jsx,json,ts,tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | rollup.config.js 3 | tsconfig.json 4 | nodemon.json -------------------------------------------------------------------------------- /packages/utils/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | rollup.config.js 3 | tsconfig.json 4 | nodemon.json -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: '.yarn/releases/yarn-berry.cjs' 2 | 3 | nodeLinker: node-modules 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /examples/landing/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"], 3 | "plugins": ["inline-react-svg"] 4 | } 5 | -------------------------------------------------------------------------------- /examples/landing/components/selectors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Container'; 2 | export * from './Text'; 3 | -------------------------------------------------------------------------------- /examples/landing/seo/googlee6ec608adf0c9ed0.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googlee6ec608adf0c9ed0.html 2 | -------------------------------------------------------------------------------- /packages/layers/src/manager/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './useLayerManager'; 2 | export * from './context'; 3 | -------------------------------------------------------------------------------- /site/static/img/layers.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/layers.gif -------------------------------------------------------------------------------- /site/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/logo.png -------------------------------------------------------------------------------- /examples/landing/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "yarn", 3 | "useWorkspaces": true, 4 | "version": "0.1.0-beta.20" 5 | } 6 | -------------------------------------------------------------------------------- /site/src/components/index.js: -------------------------------------------------------------------------------- 1 | export * from './API'; 2 | export * from './Badge'; 3 | export * from './Image'; 4 | -------------------------------------------------------------------------------- /site/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/favicon.ico -------------------------------------------------------------------------------- /packages/layers/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const value: string; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /site/static/img/heart-fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/heart-fill.png -------------------------------------------------------------------------------- /site/static/img/hearts-fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/hearts-fill.png -------------------------------------------------------------------------------- /site/static/img/tutorial/dnd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/dnd.gif -------------------------------------------------------------------------------- /examples/landing/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/examples/landing/public/favicon.ico -------------------------------------------------------------------------------- /examples/landing/types/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './nodes'; 2 | export * from './editor'; 3 | export * from './events'; 4 | -------------------------------------------------------------------------------- /site/static/img/tutorial/topbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/topbar.gif -------------------------------------------------------------------------------- /site/static/img/arrow-down-s-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/arrow-down-s-line.png -------------------------------------------------------------------------------- /site/static/img/tutorial/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/interface.png -------------------------------------------------------------------------------- /site/static/img/tutorial/text-edit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/text-edit.gif -------------------------------------------------------------------------------- /examples/basic/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | assetPrefix: process.env.NODE_ENV === 'production' ? '/examples/basic' : '', 3 | }; 4 | -------------------------------------------------------------------------------- /examples/landing/components/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toolbar'; 2 | export * from './RenderNode'; 3 | export * from './Viewport'; 4 | -------------------------------------------------------------------------------- /examples/landing/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /site/static/img/tutorial/save-and-load.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/save-and-load.gif -------------------------------------------------------------------------------- /site/static/img/tutorial/settings-panel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/settings-panel.gif -------------------------------------------------------------------------------- /examples/landing/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | assetPrefix: process.env.NODE_ENV === 'production' ? '/examples/landing' : '', 3 | }; 4 | -------------------------------------------------------------------------------- /packages/core/src/utils/isObject.ts: -------------------------------------------------------------------------------- 1 | export const isObject = (value) => 2 | value && typeof value === 'object' && value.constructor === Object; 3 | -------------------------------------------------------------------------------- /site/static/img/tutorial/droppable-regions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/droppable-regions.gif -------------------------------------------------------------------------------- /site/static/img/tutorial/text-edit-others.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/craft.js/develop/site/static/img/tutorial/text-edit-others.gif -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /** 4 | * @type {Cypress.PluginConfig} 5 | */ 6 | module.exports = () => {}; 7 | -------------------------------------------------------------------------------- /packages/core/rollup.config.js: -------------------------------------------------------------------------------- 1 | import config from '../../rollup.config'; 2 | 3 | export default { 4 | ...config, 5 | input: './src/index.tsx', 6 | }; 7 | -------------------------------------------------------------------------------- /packages/core/src/editor/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './store'; 3 | export * from './query'; 4 | export * from './NodeHelpers'; 5 | -------------------------------------------------------------------------------- /packages/utils/rollup.config.js: -------------------------------------------------------------------------------- 1 | import config from '../../rollup.config'; 2 | 3 | export default { 4 | ...config, 5 | input: './src/index.ts', 6 | }; 7 | -------------------------------------------------------------------------------- /packages/utils/src/useEffectOnce.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | export const useEffectOnce = (effect) => { 4 | useEffect(effect, []); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/layers/src/layers/DefaultLayer/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './DefaultLayerHeader'; 2 | export * from './DefaultLayer'; 3 | export * from './EditableLayerName'; 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | **/lib/ 3 | **/dist/ 4 | **/public/ 5 | **/static/ 6 | *-cache 7 | packages/docs 8 | packages/examples/landing 9 | site/ 10 | -------------------------------------------------------------------------------- /packages/layers/src/layers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LayerContext'; 2 | export * from './useLayer'; 3 | export * from './LayerNode'; 4 | export * from './DefaultLayer'; 5 | -------------------------------------------------------------------------------- /packages/core/src/nodes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Canvas'; 2 | export * from './Element'; 3 | export * from './NodeElement'; 4 | export { NodeProvider } from './NodeContext'; 5 | -------------------------------------------------------------------------------- /packages/utils/README.md: -------------------------------------------------------------------------------- 1 | # @craftjs/utils 2 | 3 | Internal package containing common utilities used across the [Craft.js](https://github.com/prevwong/craft.js) monorepo. 4 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es5", "dom"], 5 | "types": ["cypress"] 6 | }, 7 | "include": ["**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useEditor'; 2 | export * from './useNode'; 3 | export * from './legacy/connectEditor'; 4 | export * from './legacy/connectNode'; 5 | -------------------------------------------------------------------------------- /packages/utils/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | .cache 5 | .rts2_cache_cjs 6 | .rts2_cache_esm 7 | .rts2_cache_umd 8 | .rts2_cache_system 9 | dist 10 | -------------------------------------------------------------------------------- /examples/landing/public/icons/arrow-up.svg: -------------------------------------------------------------------------------- 1 | 2 | Arrow Up 3 | 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/improve-documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Improve Documentation 3 | about: Suggest improvements to the Documentation 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | -------------------------------------------------------------------------------- /packages/utils/src/EventHandlers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EventHandlers'; 2 | export * from './DerivedEventHandlers'; 3 | export * from './wrapConnectorHooks'; 4 | export * from './interfaces'; 5 | -------------------------------------------------------------------------------- /packages/core/src/events/index.tsx: -------------------------------------------------------------------------------- 1 | export { useEventHandler } from './EventContext'; 2 | export * from './CoreEventHandlers'; 3 | export * from './DefaultEventHandlers'; 4 | export { Events } from './Events'; 5 | -------------------------------------------------------------------------------- /packages/core/src/events/defineEventListener.ts: -------------------------------------------------------------------------------- 1 | export const defineEventListener = ( 2 | name: string, 3 | handler: (e: any, payload: any) => void, 4 | capture?: boolean 5 | ): any => [name, handler, capture]; 6 | -------------------------------------------------------------------------------- /jest/setup.js: -------------------------------------------------------------------------------- 1 | const Adapter = require('@wojtekmaj/enzyme-adapter-react-17'); 2 | const Enzyme = require('enzyme'); 3 | 4 | Enzyme.configure({ adapter: new Adapter() }); 5 | 6 | jest.spyOn(console, 'error').mockImplementation(() => {}); 7 | -------------------------------------------------------------------------------- /packages/core/src/editor/EditorContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | import { EditorStore } from './store'; 4 | 5 | export type EditorContext = EditorStore; 6 | export const EditorContext = createContext(null); 7 | -------------------------------------------------------------------------------- /packages/layers/rollup.config.js: -------------------------------------------------------------------------------- 1 | import image from '@svgr/rollup'; 2 | 3 | import config from '../../rollup.config'; 4 | 5 | export default { 6 | ...config, 7 | input: './src/index.tsx', 8 | plugins: [...config.plugins, image()], 9 | }; 10 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # @global-owner1 and @global-owner2 will be requested for 4 | # review when someone opens a pull request. 5 | * @prevwong 6 | -------------------------------------------------------------------------------- /examples/landing/utils/text.ts: -------------------------------------------------------------------------------- 1 | export const capitalize = (text: string) => 2 | text[0].toUpperCase() + text.substr(1, text.length); 3 | export const weightDescription = (weight: number) => 4 | weight === 400 ? 'Regular' : weight === 500 ? 'Medium' : 'Bold'; 5 | -------------------------------------------------------------------------------- /examples/basic/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #f3f3f3 !important; 3 | } 4 | 5 | p { 6 | margin: 2px 0; 7 | } 8 | 9 | fieldset.MuiFormControl-root { 10 | margin-bottom: 20px; 11 | } 12 | 13 | *[draggable] { 14 | cursor: move !important; 15 | } 16 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/text-fill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './nodes'; 2 | export * from './render'; 3 | export * from './interfaces'; 4 | export * from './hooks'; 5 | export * from './editor'; 6 | export * from './events'; 7 | export * from './utils/testHelpers'; 8 | export { ROOT_NODE } from '@craftjs/utils'; 9 | -------------------------------------------------------------------------------- /examples/landing/public/icons/square.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/utils/fromEntries.ts: -------------------------------------------------------------------------------- 1 | export const fromEntries = (pairs) => { 2 | if (Object.fromEntries) { 3 | return Object.fromEntries(pairs); 4 | } 5 | return pairs.reduce( 6 | (accum, [id, value]) => ({ 7 | ...accum, 8 | [id]: value, 9 | }), 10 | {} 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/events/EventContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react'; 2 | 3 | import { CoreEventHandlers } from './CoreEventHandlers'; 4 | 5 | export const EventHandlerContext = createContext(null); 6 | 7 | export const useEventHandler = () => useContext(EventHandlerContext); 8 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/container.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache 3 | *-cache 4 | out 5 | dist 6 | lib 7 | *-*.log 8 | .now 9 | .vscode 10 | .idea 11 | build 12 | 13 | .DS_Store 14 | cypress/videos/* 15 | cypress/screenshots/* 16 | 17 | .yarn/* 18 | !.yarn/patches 19 | !.yarn/releases 20 | !.yarn/plugins 21 | !.yarn/sdks 22 | !.yarn/versions 23 | .pnp.* -------------------------------------------------------------------------------- /packages/layers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": "./src", 5 | "outDir": "./lib", 6 | "allowSyntheticDefaultImports": true, 7 | "skipLibCheck": true, 8 | "jsx": "react" 9 | }, 10 | "include": ["src/index.tsx", "svg.d.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /examples/landing/README.md: -------------------------------------------------------------------------------- 1 | # Landing 2 | 3 | This is the source code for the landing page demo seen [here](https://craft.js.org/) 4 | 5 | > The code is admittedly a bit messy and is scheduled for a clean up. In the mean time, feel free to submit an issue if you encounter any confusing/weird/wtf bits ... or even better, submit a pull request! :clap: 6 | -------------------------------------------------------------------------------- /packages/layers/src/layers/DefaultLayer/svg/corner-arrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/utils/removeNodeFromEvents.ts: -------------------------------------------------------------------------------- 1 | import { EditorState, NodeId } from '../interfaces'; 2 | 3 | export const removeNodeFromEvents = (state: EditorState, nodeId: NodeId) => 4 | Object.keys(state.events).forEach((key) => { 5 | if (state.events[key] && state.events[key] === nodeId) { 6 | state.events[key] = null; 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /examples/basic/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # misc 7 | .DS_Store 8 | .env.local 9 | .env.development.local 10 | .env.test.local 11 | .env.production.local 12 | 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Next.js 18 | /.next 19 | -------------------------------------------------------------------------------- /packages/layers/src/layers/DefaultLayer/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npx lerna run clean --stream 4 | wait 5 | 6 | # build type definitons for utils 7 | npx tsc --p packages/utils --skipLibCheck --emitDeclarationOnly 8 | wait 9 | 10 | # build type definitons for core 11 | npx tsc --p packages/core --skipLibCheck --emitDeclarationOnly 12 | wait 13 | 14 | npx lerna run start --parallel --ignore docs -------------------------------------------------------------------------------- /examples/landing/public/icons/type.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": "./src", 5 | "outDir": "./lib", 6 | "allowSyntheticDefaultImports": true, 7 | "skipLibCheck": true, 8 | "jsx": "react", 9 | "declaration": true, 10 | "declarationDir": "./lib" 11 | }, 12 | "include": ["./src/index.tsx"] 13 | } 14 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": "./src", 5 | "outDir": "./lib", 6 | "allowSyntheticDefaultImports": true, 7 | "skipLibCheck": true, 8 | "jsx": "react", 9 | "declaration": true, 10 | "declarationDir": "./lib" 11 | }, 12 | "include": ["./src/index.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /scripts/yalc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | defaultRollupConfig=../../rollup.config.js 4 | if [ -f ./rollup.config.js ]; then 5 | defaultRollupConfig=rollup.config.js 6 | fi 7 | 8 | command=" 9 | npx tsc --skipLibCheck --emitDeclarationOnly & 10 | npx rollup -c ${defaultRollupConfig}; 11 | yalc push 12 | " 13 | 14 | echo $command 15 | 16 | nodemon --watch src -x "${command}" 17 | -------------------------------------------------------------------------------- /packages/core/src/render/SimpleElement.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { useNode } from '../hooks/useNode'; 4 | 5 | export const SimpleElement = ({ render }: any) => { 6 | const { 7 | connectors: { connect, drag }, 8 | } = useNode(); 9 | 10 | return typeof render.type === 'string' 11 | ? connect(drag(React.cloneElement(render))) 12 | : render; 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | rm -rf build 5 | yarn clean 6 | yarn build:all 7 | 8 | lerna run export --stream 9 | mv site/build build 10 | mkdir build/examples 11 | cp -r ./examples/basic/out/ build/examples/basic 12 | cp -r ./examples/landing/out/ build/examples/landing 13 | 14 | touch build/.nojekyll 15 | touch build/CNAME 16 | echo "craft.js.org" >> build/CNAME -------------------------------------------------------------------------------- /examples/landing/public/icons/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | ChevronDownMedium 3 | 4 | -------------------------------------------------------------------------------- /examples/landing/public/icons/button.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | args=() 4 | if [ $NODE_ENV == 'development' ] 5 | then 6 | args+=( '-w' ); 7 | fi 8 | 9 | 10 | defaultRollupConfig=../../rollup.config.js 11 | if [ -f ./rollup.config.js ] 12 | then 13 | defaultRollupConfig=rollup.config.js 14 | fi 15 | 16 | npx tsc --skipLibCheck --emitDeclarationOnly "${args[@]}" & 17 | npx rollup -c "${defaultRollupConfig}" "${args[@]}" -------------------------------------------------------------------------------- /site/src/theme/Footer/styles.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | .footerLogoLink { 9 | opacity: 0.5; 10 | transition: opacity 0.15s ease-in-out; 11 | } 12 | 13 | .footerLogoLink:hover { 14 | opacity: 1; 15 | } 16 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/video-fill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/layers/src/layers/DefaultLayer/svg/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | ChevronDownMedium 3 | 4 | -------------------------------------------------------------------------------- /examples/basic/README.md: -------------------------------------------------------------------------------- 1 | # Basic demo 2 | 3 | This example is the end result of the tutorial [guide](https://craft.js.org/r/docs/guides/basic-tutorial). 4 | 5 | Check out the live demo [here](https://craft.js.org/examples/basic/) 6 | 7 | ## Try it out 8 | 9 | ```bash 10 | > git clone https://github.com/prevwong/craft.js/ 11 | > cd craft.js/packages/examples/basic 12 | > npm install 13 | > npm dev 14 | ``` 15 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './useMethods'; 3 | export * from './getDOMInfo'; 4 | export * from './useCollector'; 5 | export * from './EventHandlers'; 6 | export * from './RenderIndicator'; 7 | export * from './useEffectOnce'; 8 | export * from './deprecate'; 9 | export * from './utilityTypes'; 10 | export * from './History'; 11 | export * from './getRandomId'; 12 | -------------------------------------------------------------------------------- /examples/landing/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .env* 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/video-line.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/landing/public/icons/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | S Checkmark 18 N 4 | 5 | -------------------------------------------------------------------------------- /.github/.kodiak.toml: -------------------------------------------------------------------------------- 1 | # .kodiak.toml 2 | version = 1 3 | 4 | [merge] 5 | blocking_labels = ["draft"] 6 | require_automerge_label = false 7 | method = "squash" 8 | delete_branch_on_merge = true 9 | prioritize_ready_to_merge = true 10 | notify_on_conflict = false 11 | 12 | [merge.message] 13 | title = "pull_request_title" 14 | body = "pull_request_body" 15 | include_pr_number = true 16 | body_type = "markdown" 17 | strip_html_comments = true -------------------------------------------------------------------------------- /packages/utils/src/utilityTypes.ts: -------------------------------------------------------------------------------- 1 | export type Overwrite = Pick> & U; 2 | export type Delete = Pick>; 3 | export type OverwriteFnReturnType void, R> = ( 4 | ...args: Parameters 5 | ) => Delete, R>; 6 | export type ConditionallyMergeRecordTypes< 7 | C, 8 | S extends Record 9 | > = C extends null ? S : C & S; 10 | -------------------------------------------------------------------------------- /site/static/img/ChevronDownSmall.svg: -------------------------------------------------------------------------------- 1 | 2 | ChevronDownSmall 3 | 4 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/rectangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | S Rectangle 18 N 10 | 11 | -------------------------------------------------------------------------------- /packages/core/src/hooks/legacy/connectNode.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Node } from '../../interfaces'; 4 | import { useNode } from '../useNode'; 5 | 6 | export function connectNode(collect?: (state: Node) => C) { 7 | return function (WrappedComponent: React.ElementType) { 8 | return (props: any) => { 9 | const node = useNode(collect); 10 | return ; 11 | }; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /packages/layers/src/manager/context.tsx: -------------------------------------------------------------------------------- 1 | import { SubscriberAndCallbacksFor } from '@craftjs/utils'; 2 | import { createContext } from 'react'; 3 | 4 | import { LayerMethods } from './actions'; 5 | 6 | export type LayerStore = SubscriberAndCallbacksFor; 7 | export type LayerManagerContext = { 8 | store: LayerStore; 9 | }; 10 | 11 | export const LayerManagerContext = createContext( 12 | {} as LayerManagerContext 13 | ); 14 | -------------------------------------------------------------------------------- /examples/landing/components/editor/Toolbar/ToolbarDropdown.tsx: -------------------------------------------------------------------------------- 1 | import { FormControl, InputLabel, Select } from '@material-ui/core'; 2 | import React from 'react'; 3 | 4 | export const ToolbarDropdown = ({ title, value, onChange, children }: any) => { 5 | return ( 6 | 7 | {title} 8 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/core/src/hooks/legacy/connectEditor.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { EditorState } from '../../interfaces'; 4 | import { useEditor } from '../useEditor'; 5 | 6 | export function connectEditor(collect?: (state: EditorState) => C) { 7 | return (WrappedComponent: React.ElementType) => { 8 | return (props: any) => { 9 | const Editor = collect ? useEditor(collect) : useEditor(); 10 | return ; 11 | }; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/utils/mapChildrenToNodes.ts: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | import { Node } from '../interfaces'; 4 | 5 | export function mapChildrenToNodes( 6 | children: ReactNode, 7 | cb: (JSX: React.ReactElement | string) => Node 8 | ): Node[] { 9 | return React.Children.toArray(children).reduce( 10 | (result: Node[], child: any) => { 11 | const node = cb(child); 12 | result.push(node); 13 | return result; 14 | }, 15 | [] 16 | ) as Node[]; 17 | } 18 | -------------------------------------------------------------------------------- /examples/basic/src/theme.js: -------------------------------------------------------------------------------- 1 | import { red } from '@material-ui/core/colors'; 2 | import { createMuiTheme } from '@material-ui/core/styles'; 3 | 4 | // Create a theme instance. 5 | const theme = createMuiTheme({ 6 | palette: { 7 | primary: { 8 | main: '#556cd6', 9 | }, 10 | secondary: { 11 | main: '#19857b', 12 | }, 13 | error: { 14 | main: red.A400, 15 | }, 16 | background: { 17 | default: '#fff', 18 | }, 19 | }, 20 | }); 21 | 22 | export default theme; 23 | -------------------------------------------------------------------------------- /examples/landing/components/selectors/Video/VideoSettings.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { ToolbarSection, ToolbarItem } from '../../editor'; 4 | 5 | export const VideoSettings = () => { 6 | return ( 7 | 8 | 9 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | S Button 18 N 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.1.0-beta.20](https://github.com/prevwong/craft.js/compare/v0.1.0-beta.19...v0.1.0-beta.20) (2021-08-02) 7 | 8 | 9 | ### Features 10 | 11 | * clear history ([#281](https://github.com/prevwong/craft.js/issues/281)) ([7524cb2](https://github.com/prevwong/craft.js/commit/7524cb2d59aa81470eadbeb9f1267451b1252bac)) 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release to NPM 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | env: 8 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 9 | 10 | jobs: 11 | release: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@master 15 | - run: git fetch --prune --unshallow 16 | 17 | - name: Use Node.js 10.x 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: 10.x 21 | 22 | - run: yarn install 23 | - run: yarn publish 24 | -------------------------------------------------------------------------------- /packages/utils/src/getRandomId.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid'; 2 | 3 | // By default nanoid generate an ID with 21 characters. To reduce the footprint, we default to 10 characters. 4 | // We have a higher probability for collisions, though 5 | 6 | /** 7 | * Generate a random ID. That ID can for example be used as a node ID. 8 | * 9 | * @param size The number of characters that are generated for the ID. Defaults to `10` 10 | * @returns A random id 11 | */ 12 | export const getRandomId = (size: number = 10) => nanoid(size); 13 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "skipLibCheck": true, 4 | "incremental": true, 5 | "target": "esnext", 6 | "module": "esnext", 7 | "moduleResolution": "node", 8 | "lib": ["esnext", "dom"], 9 | "strict": false, 10 | "experimentalDecorators": true, 11 | "noUnusedLocals": false, 12 | "jsx": "react", 13 | "forceConsistentCasingInFileNames": false, 14 | "declaration": true, 15 | "allowSyntheticDefaultImports": true 16 | }, 17 | "exclude": ["**/node_modules/**"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/layers/src/layers/LayerContext.tsx: -------------------------------------------------------------------------------- 1 | import { NodeId } from '@craftjs/core'; 2 | import { ChainableConnectors } from '@craftjs/utils'; 3 | import React from 'react'; 4 | 5 | import { LayerHandlers } from '../events/LayerHandlers'; 6 | 7 | export type LayerContext = { 8 | id: NodeId; 9 | depth: number; 10 | connectors: ChainableConnectors< 11 | LayerHandlers['connectors'], 12 | React.ReactElement 13 | >; 14 | }; 15 | 16 | export const LayerContext = React.createContext( 17 | {} as LayerContext 18 | ); 19 | -------------------------------------------------------------------------------- /packages/core/src/nodes/NodeElement.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { NodeProvider } from './NodeContext'; 4 | 5 | import { NodeId } from '../interfaces'; 6 | import { RenderNodeToElement } from '../render/RenderNode'; 7 | 8 | export type NodeElementProps = { 9 | id: NodeId; 10 | render?: React.ReactElement; 11 | }; 12 | 13 | export const NodeElement: React.FC = ({ id, render }) => { 14 | return ( 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea you'd like to see in Craft.js 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Additional context** 16 | Add any other context or screenshots about the feature request here. 17 | -------------------------------------------------------------------------------- /examples/landing/public/icons/youtube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/src/components/Image.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 3 | 4 | export const Image = ({ img }) => { 5 | const context = useDocusaurusContext(); 6 | const { 7 | siteConfig: { baseUrl }, 8 | } = context; 9 | 10 | return ( 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /examples/landing/seo/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | https://craft.js.org/ 9 | 2020-01-04T06:39:23+00:00 10 | 11 | 12 | 13 | https://craft.js.org/r/ 14 | 2020-01-04T06:39:23+00:00 15 | 16 | -------------------------------------------------------------------------------- /packages/layers/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { ROOT_NODE } from '@craftjs/utils'; 2 | import React from 'react'; 3 | 4 | import { LayerOptions } from './interfaces'; 5 | import { LayerContextProvider } from './layers/LayerContextProvider'; 6 | import { LayerManagerProvider } from './manager/LayerManagerProvider'; 7 | export { useLayer } from './layers'; 8 | 9 | export const Layers: React.FC> = ({ ...options }) => { 10 | return ( 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /examples/landing/public/icons/customize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | S Edit 18 N 5 | 6 | -------------------------------------------------------------------------------- /packages/core/src/nodes/Canvas.tsx: -------------------------------------------------------------------------------- 1 | import { deprecationWarning } from '@craftjs/utils'; 2 | import React, { useEffect } from 'react'; 3 | 4 | import { Element } from './Element'; 5 | 6 | export type Canvas = Element; 7 | 8 | export const deprecateCanvasComponent = () => 9 | deprecationWarning('', { 10 | suggest: '', 11 | }); 12 | 13 | export function Canvas({ ...props }: Canvas) { 14 | useEffect(() => deprecateCanvasComponent(), []); 15 | 16 | return ; 17 | } 18 | -------------------------------------------------------------------------------- /packages/utils/src/deprecate.ts: -------------------------------------------------------------------------------- 1 | type DeprecationPayload = Partial<{ 2 | suggest: string; 3 | doc: string; 4 | }>; 5 | 6 | export const deprecationWarning = (name, payload?: DeprecationPayload) => { 7 | let message = `Deprecation warning: ${name} will be deprecated in future relases.`; 8 | 9 | const { suggest, doc } = payload; 10 | 11 | if (suggest) { 12 | message += ` Please use ${suggest} instead.`; 13 | } 14 | 15 | // URL link to Documentation 16 | if (doc) { 17 | message += `(${doc})`; 18 | } 19 | 20 | // eslint-disable-next-line no-console 21 | console.warn(message); 22 | }; 23 | -------------------------------------------------------------------------------- /examples/landing/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'], 3 | theme: { 4 | extend: { 5 | colors: { 6 | primary: '#2680eb', 7 | 'dar-gray': '#4b4b4b', 8 | 'light-gray-0': '#eaeaea', 9 | 'light-gray-1': 'rgb(75,75,75)', 10 | 'light-gray-2': 'rgb(128,128,128)', 11 | 'renderer-gray': 'rgb(224, 224, 224)', 12 | red: '#e34850', 13 | 'green-400': '#2d9d78', 14 | 'green-500': '#268e6c', 15 | }, 16 | }, 17 | }, 18 | variants: {}, 19 | plugins: [], 20 | }; 21 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/redo.svg: -------------------------------------------------------------------------------- 1 | 2 | Redo 3 | 4 | -------------------------------------------------------------------------------- /examples/landing/public/icons/toolbox/undo.svg: -------------------------------------------------------------------------------- 1 | 2 | Undo 3 | 4 | -------------------------------------------------------------------------------- /site/src/components/Badge.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Badge = ({ type, title = true, noMargin = true }) => { 4 | let name; 5 | switch (type) { 6 | case 'hoc': 7 | name = 'Higher-Order Component'; 8 | break; 9 | default: 10 | name = type[0].toUpperCase() + type.substring(1); 11 | } 12 | 13 | return ( 14 |
15 | 20 | {name} 21 | 22 |
23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/core/src/events/isEventBlockedByDescendant.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if a specified event is blocked by a child 3 | * that's a descendant of the specified element 4 | */ 5 | export const isEventBlockedByDescendant = (e, eventName, el) => { 6 | // TODO: Update TS to use optional chaining 7 | const blockingElements = (e.craft && e.craft.blockedEvents[eventName]) || []; 8 | 9 | for (let i = 0; i < blockingElements.length; i++) { 10 | const blockingElement = blockingElements[i]; 11 | 12 | if (el !== blockingElement && el.contains(blockingElement)) { 13 | return true; 14 | } 15 | } 16 | 17 | return false; 18 | }; 19 | -------------------------------------------------------------------------------- /examples/landing/public/icons/layers.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | S Layers 18 N 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "allowSyntheticDefaultImports": true, 6 | "allowJs": true, 7 | "esModuleInterop": true, 8 | "paths": { 9 | "@craftjs/core": ["packages/core/src/index"], 10 | "@craftjs/*": ["packages/core/src/*"], 11 | "@craftjs/layers": ["packages/layers/src/index"], 12 | "@craftjs/utils": ["packages/utils/src/index"], 13 | "@craftjs/utils/*": ["packages/utils/src/*"], 14 | "@craftjs/slate": ["packages/slate/src/*"], 15 | "@craftjs/slate/*": ["packages/slate/src/*"] 16 | } 17 | }, 18 | "exclude": ["**/node_modules/**"] 19 | } 20 | -------------------------------------------------------------------------------- /cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | import './dnd'; 2 | 3 | declare global { 4 | // eslint-disable-next-line @typescript-eslint/no-namespace 5 | namespace Cypress { 6 | interface Chainable { 7 | getByTestId( 8 | selector: string, 9 | ...additionalArguments: any[] 10 | ): Chainable; 11 | } 12 | } 13 | } 14 | 15 | /** 16 | * Will select elements that have a data-cy=$test-id attribute 17 | * Usage: `cy.getByTestId('test-id')` 18 | * @example HTML:
Selector: cy.getByTestId('test-id') 19 | */ 20 | Cypress.Commands.add('getByTestId', (selector, ...args) => { 21 | return cy.get(`[data-cy="${selector}"]`, ...args); 22 | }); 23 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'prettier/@typescript-eslint', 4 | 'plugin:prettier/recommended', 5 | 'react-app', 6 | "plugin:import/typescript", 7 | ], 8 | rules: { 9 | 'no-console': 1, 10 | 'import/no-unresolved': 2, 11 | 'import/order': [ 12 | 'error', 13 | { 14 | alphabetize: { order: 'asc' }, 15 | 'newlines-between': 'always', 16 | groups: ['builtin', 'external', 'internal', 'sibling', 'index'], 17 | pathGroups: [{ pattern: '*', group: 'external' }], 18 | }, 19 | ], 20 | '@typescript-eslint/no-unused-expressions': 2, 21 | '@typescript-eslint/no-unused-vars': 2, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /.github/workflows/deploy-gh.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to gh-pages 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build-and-deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@master 13 | - name: Use Node.js 10.x 14 | uses: actions/setup-node@v1 15 | with: 16 | node-version: 10.x 17 | 18 | - run: yarn install 19 | - run: yarn deploy 20 | 21 | - name: Deploy 22 | uses: peaceiris/actions-gh-pages@v2 23 | env: 24 | ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }} 25 | PUBLISH_BRANCH: gh-pages 26 | PUBLISH_DIR: ./site 27 | -------------------------------------------------------------------------------- /packages/utils/src/RenderIndicator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | export const RenderIndicator: React.FC = ({ style, parentDom }) => { 5 | const indicator = ( 6 |
18 | ); 19 | 20 | if (parentDom && parentDom.ownerDocument !== document) { 21 | return ReactDOM.createPortal(indicator, parentDom.ownerDocument.body); 22 | } 23 | 24 | return indicator; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/layers/src/manager/useLayerManager.tsx: -------------------------------------------------------------------------------- 1 | import { useCollector, useCollectorReturnType } from '@craftjs/utils'; 2 | import { useContext } from 'react'; 3 | 4 | import { LayerManagerContext, LayerStore } from './context'; 5 | 6 | import { LayerState } from '../interfaces'; 7 | 8 | export function useLayerManager(): useCollectorReturnType; 9 | export function useLayerManager( 10 | collector?: (state: LayerState) => C 11 | ): useCollectorReturnType; 12 | export function useLayerManager( 13 | collector?: (state: LayerState) => C 14 | ): useCollectorReturnType { 15 | const { store } = useContext(LayerManagerContext); 16 | return useCollector(store, collector); 17 | } 18 | -------------------------------------------------------------------------------- /packages/core/src/utils/resolveComponent.ts: -------------------------------------------------------------------------------- 1 | import { Resolver } from '../interfaces'; 2 | import { Canvas } from '../nodes/Canvas'; 3 | 4 | export const resolveComponent = ( 5 | resolver: Resolver, 6 | comp: React.ElementType | string 7 | ) => { 8 | let Comp: string; 9 | const name = (comp as any).name || (comp as any).displayName; 10 | 11 | if (comp === Canvas) return 'Canvas'; 12 | 13 | if (resolver[name]) return name; 14 | 15 | for (let i = 0; i < Object.keys(resolver).length; i++) { 16 | const name = Object.keys(resolver)[i], 17 | fn = resolver[name]; 18 | if (fn === comp) { 19 | Comp = name; 20 | return Comp; 21 | } 22 | } 23 | 24 | if (typeof comp === 'string') return comp; 25 | }; 26 | -------------------------------------------------------------------------------- /examples/landing/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import '../styles/app.css'; 4 | 5 | function MyApp({ Component, pageProps }) { 6 | return ; 7 | } 8 | 9 | // Only uncomment this method if you have blocking data requirements for 10 | // every single page in your application. This disables the ability to 11 | // perform automatic static optimization, causing every page in your app to 12 | // be server-side rendered. 13 | // 14 | // MyApp.getInitialProps = async (appContext) => { 15 | // // calls page's `getInitialProps` and fills `appProps.pageProps` 16 | // const appProps = await App.getInitialProps(appContext); 17 | // 18 | // return { ...appProps } 19 | // } 20 | 21 | export default MyApp; 22 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/events.ts: -------------------------------------------------------------------------------- 1 | import { NodeId, Node } from './nodes'; 2 | 3 | export type NodeInfo = { 4 | id?: NodeId; 5 | } & DOMInfo; 6 | 7 | export type DOMInfo = Record< 8 | | 'x' 9 | | 'y' 10 | | 'top' 11 | | 'left' 12 | | 'bottom' 13 | | 'right' 14 | | 'width' 15 | | 'height' 16 | | 'outerWidth' 17 | | 'outerHeight', 18 | number 19 | > & { 20 | inFlow: boolean; 21 | margin: Record<'top' | 'left' | 'bottom' | 'right', number>; 22 | padding: Record<'top' | 'left' | 'bottom' | 'right', number>; 23 | }; 24 | 25 | export interface DropAction { 26 | parent: Node; 27 | index: number; 28 | where: string; 29 | } 30 | 31 | export type Placement = DropAction & { 32 | currentNode: Node | null; 33 | }; 34 | -------------------------------------------------------------------------------- /examples/landing/public/icons/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | S Edit 18 N 10 | 11 | -------------------------------------------------------------------------------- /packages/layers/src/layers/DefaultLayer/svg/linked.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | S LinkOut 18 N 10 | 11 | 12 | -------------------------------------------------------------------------------- /cypress/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /packages/core/src/utils/createTestNode.ts: -------------------------------------------------------------------------------- 1 | // TODO: deprecate in favor of testUtils 2 | export const createTestNode = (id, data = {}, config: any = {}) => { 3 | return { 4 | ...config, 5 | id, 6 | data: { 7 | props: {}, 8 | custom: {}, 9 | hidden: false, 10 | isCanvas: false, 11 | nodes: [], 12 | linkedNodes: {}, 13 | ...data, 14 | }, 15 | related: {}, 16 | events: { 17 | selected: false, 18 | dragged: false, 19 | hovered: false, 20 | ...(config.events || {}), 21 | }, 22 | rules: { 23 | canMoveIn: () => true, 24 | canMoveOut: () => true, 25 | canDrag: () => true, 26 | canDrop: () => true, 27 | ...(config.rules || {}), 28 | }, 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /examples/landing/public/icons/delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | S Delete 18 N 10 | 11 | -------------------------------------------------------------------------------- /examples/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-basic", 3 | "version": "0.1.0-beta.20", 4 | "private": true, 5 | "dependencies": { 6 | "@craftjs/core": "^0.1.0-beta.20", 7 | "@material-ui/core": "latest", 8 | "clsx": "latest", 9 | "copy-to-clipboard": "^3.2.0", 10 | "lzutf8": "^0.5.5", 11 | "material-ui-color-picker": "^3.2.0", 12 | "next": "^10.2.0", 13 | "prop-types": "latest", 14 | "react": "17.0.2", 15 | "react-contenteditable": "^3.3.3", 16 | "react-dom": "17.0.2" 17 | }, 18 | "scripts": { 19 | "start": "next dev -p 3002", 20 | "build": "next build", 21 | "export": "next export", 22 | "clean": "rimraf lib .next out dist" 23 | }, 24 | "devDependencies": { 25 | "cross-env": "^6.0.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/layers/src/interfaces.tsx: -------------------------------------------------------------------------------- 1 | import { NodeId, Indicator } from '@craftjs/core'; 2 | 3 | export type Layer = { 4 | id: NodeId; 5 | dom: HTMLElement; 6 | headingDom: HTMLElement; 7 | expanded: boolean; 8 | event: LayerRefEvents; 9 | }; 10 | 11 | export type LayerRefEvents = Record; 12 | 13 | export type LayerEvents = 'selected' | 'hovered'; 14 | 15 | export type LayerOptions = { 16 | expandRootOnLoad: boolean; 17 | renderLayer: React.ElementType; 18 | }; 19 | 20 | export type LayerIndicator = Indicator & { 21 | onCanvas: boolean; 22 | }; 23 | 24 | export type LayerState = { 25 | layers: Record; 26 | events: Record & { 27 | indicator: LayerIndicator; 28 | }; 29 | 30 | options: LayerOptions; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.1.0-beta.20](https://github.com/prevwong/craft.js/compare/v0.1.0-beta.19...v0.1.0-beta.20) (2021-08-02) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * readonly parent error ([#280](https://github.com/prevwong/craft.js/issues/280)) ([83fdc23](https://github.com/prevwong/craft.js/commit/83fdc232213b1b504679e50efb21cf708f23e069)) 12 | * sync props with state options ([#271](https://github.com/prevwong/craft.js/issues/271)) ([3156043](https://github.com/prevwong/craft.js/commit/3156043232b7e88f39e313b70f00bfb91ba830a3)), closes [prevwong/craft.js#149](https://github.com/prevwong/craft.js/issues/149) 13 | -------------------------------------------------------------------------------- /examples/landing/styles/app.css: -------------------------------------------------------------------------------- 1 | /* purgecss start ignore */ 2 | @tailwind base; 3 | @tailwind components; 4 | @import url('https://use.typekit.net/mpa1wkh.css'); 5 | html, 6 | body { 7 | font-family: 'acumin-pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 8 | 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 9 | 'Helvetica Neue', sans-serif; 10 | color: rgb(75, 75, 75); 11 | background: #e0e0e0; 12 | } 13 | /* purgecss end ignore */ 14 | 15 | @tailwind utilities; 16 | 17 | .component-selected { 18 | @apply relative; 19 | } 20 | .component-selected::after { 21 | content: ' '; 22 | @apply border-primary border border-dashed w-full h-full absolute left-0 top-0 pointer-events-none block; 23 | } 24 | 25 | .transition { 26 | transition: 0.4s cubic-bezier(0.19, 1, 0.22, 1); 27 | } 28 | -------------------------------------------------------------------------------- /site/docs/acknowledgements.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: acknowledgements 3 | title: Acknowledgements 4 | --- 5 | 6 | A huge thank you to the authors and contributors of the following libraries/frameworks: 7 | 8 | - **[react-dnd](https://github.com/react-dnd/react-dnd)** The React drag-n-drop library. 9 | Although it is not actually used here, many aspects of Craft.js are written with react-dnd as a reference along with some utilities and functions being borrowed. 10 | - **[Grape.js](https://github.com/artf/grapesjs)** The HTML web builder framework. This has served as an inspiration for Craft.js. The element positioning logic used in Craft.js is borrowed from Grape.js 11 | - **[use-methods](https://github.com/pelotom/use-methods)** A super handy hook when dealing with reducers. Craft.js uses a slightly modified version of `use-methods` to better fit our API. 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/utils/parseNodeFromJSX.tsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | 3 | import { createNode } from './createNode'; 4 | 5 | import { Node } from '../interfaces'; 6 | 7 | export function parseNodeFromJSX( 8 | jsx: React.ReactElement | string, 9 | normalize?: (node: Node, jsx: React.ReactElement) => void 10 | ) { 11 | let element = jsx as React.ReactElement; 12 | 13 | if (typeof element === 'string') { 14 | element = React.createElement(Fragment, {}, element) as React.ReactElement; 15 | } 16 | 17 | let actualType = element.type as any; 18 | 19 | return createNode( 20 | { 21 | data: { 22 | type: actualType, 23 | props: { ...element.props }, 24 | }, 25 | }, 26 | (node) => { 27 | if (normalize) { 28 | normalize(node, element); 29 | } 30 | } 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/layers/src/layers/LayerIndicator.tsx: -------------------------------------------------------------------------------- 1 | import { Indicator, useEditor } from '@craftjs/core'; 2 | import React from 'react'; 3 | 4 | export type Placeholder = { 5 | placeholder: Indicator; 6 | suggestedStyles: any; 7 | }; 8 | 9 | export const LayerIndicator: React.FC = ({ 10 | placeholder, 11 | suggestedStyles, 12 | }) => { 13 | const { indicator } = useEditor((state) => ({ 14 | indicator: state.options.indicator, 15 | })); 16 | 17 | return ( 18 |
30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /site/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import Layout from '@theme/Layout'; 10 | 11 | function Home() { 12 | return ( 13 | 19 |