├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .github ├── assets │ ├── banne-bg-light.png │ ├── banner-bg-dark.png │ ├── banner-dark.png │ ├── banner-dark.svg │ ├── banner.png │ ├── banner.svg │ ├── logo- bg-light.png │ ├── logo-bg-dark.png │ ├── logo-dark.png │ ├── logo-dark.svg │ ├── logo.png │ └── logo.svg └── workflows │ ├── release.yml │ └── version.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc.json ├── .vscode └── settings.json ├── LICENSE ├── README-zh_CN.md ├── README.md ├── biome.json ├── commitlint.config.js ├── docs ├── .vitepress │ ├── cache │ │ └── deps │ │ │ ├── @vueuse_core.js │ │ │ ├── @vueuse_core.js.map │ │ │ ├── _metadata.json │ │ │ ├── chunk-6Y7CYOCB.js │ │ │ ├── chunk-6Y7CYOCB.js.map │ │ │ ├── chunk-LZXTVE33.js │ │ │ ├── chunk-LZXTVE33.js.map │ │ │ ├── package.json │ │ │ ├── vitepress___@vue_devtools-api.js │ │ │ ├── vitepress___@vue_devtools-api.js.map │ │ │ ├── vitepress___@vueuse_core.js │ │ │ ├── vitepress___@vueuse_core.js.map │ │ │ ├── vitepress___@vueuse_integrations_useFocusTrap.js │ │ │ ├── vitepress___@vueuse_integrations_useFocusTrap.js.map │ │ │ ├── vitepress___mark__js_src_vanilla__js.js │ │ │ ├── vitepress___mark__js_src_vanilla__js.js.map │ │ │ ├── vitepress___minisearch.js │ │ │ ├── vitepress___minisearch.js.map │ │ │ ├── vue.js │ │ │ └── vue.js.map │ ├── config │ │ ├── en.ts │ │ ├── index.ts │ │ ├── shared.ts │ │ └── zh.ts │ └── theme │ │ ├── Layout.vue │ │ ├── components │ │ ├── RainbowAnimationSwitcher.vue │ │ └── RainbowSwitcher.vue │ │ ├── index.ts │ │ ├── overrides.css │ │ ├── rainbow.css │ │ └── vars.css ├── components.d.ts ├── design │ ├── editor.md │ ├── overview.md │ ├── plugin.md │ ├── renderer.md │ ├── setter.md │ └── specs.md ├── en │ ├── design │ │ ├── editor.md │ │ ├── overview.md │ │ ├── plugin.md │ │ ├── renderer.md │ │ ├── setter.md │ │ └── specs.md │ ├── guide │ │ ├── core-concepts.md │ │ ├── extension │ │ │ ├── material.md │ │ │ ├── plugin.md │ │ │ └── setter.md │ │ ├── getting-started.md │ │ ├── renderer │ │ │ ├── custom.md │ │ │ ├── editor.md │ │ │ ├── index.md │ │ │ └── runtime.md │ │ ├── scenarios │ │ │ ├── dashboard │ │ │ │ ├── getting-started.md │ │ │ │ └── index.md │ │ │ └── form │ │ │ │ ├── getting-started.md │ │ │ │ └── index.md │ │ └── why.md │ ├── index.md │ └── reference │ │ ├── core │ │ └── index.md │ │ ├── overview.md │ │ ├── plugin │ │ └── index.md │ │ └── renderer │ │ └── index.md ├── guide │ ├── core-concepts.md │ ├── extension │ │ ├── material.md │ │ ├── plugin.md │ │ └── setter.md │ ├── getting-started.md │ ├── renderer │ │ ├── custom.md │ │ ├── editor.md │ │ ├── index.md │ │ └── runtime.md │ ├── scenarios │ │ ├── dashboard │ │ │ ├── getting-started.md │ │ │ └── index.md │ │ └── form │ │ │ ├── getting-started.md │ │ │ └── index.md │ └── why.md ├── index.md ├── package.json ├── public │ ├── favicon.svg │ ├── logo-dark.svg │ ├── logo.svg │ ├── relationship.png │ └── relationship_dark.png ├── reference │ ├── core │ │ └── index.md │ ├── overview.md │ ├── plugin │ │ └── index.md │ └── renderer │ │ └── index.md ├── uno.config.ts ├── vercel.json └── vite.config.ts ├── examples └── dashboard │ ├── .gitignore │ ├── README.md │ ├── eslint.config.js │ ├── index.html │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── components │ │ ├── Center.tsx │ │ ├── Header.tsx │ │ ├── Left.tsx │ │ └── Right.tsx │ ├── editor │ │ ├── const.ts │ │ ├── index.ts │ │ ├── materials │ │ │ ├── button │ │ │ │ ├── component.tsx │ │ │ │ ├── configure.ts │ │ │ │ ├── meta.ts │ │ │ │ └── snippets.ts │ │ │ ├── component.ts │ │ │ ├── group │ │ │ │ ├── component.tsx │ │ │ │ ├── configure.ts │ │ │ │ ├── index.ts │ │ │ │ └── meta.ts │ │ │ ├── input │ │ │ │ ├── component.tsx │ │ │ │ ├── configure.ts │ │ │ │ ├── meta.ts │ │ │ │ └── snippets.ts │ │ │ ├── meta.ts │ │ │ └── rootContainer │ │ │ │ ├── component.tsx │ │ │ │ ├── configure.ts │ │ │ │ └── meta.ts │ │ ├── plugins │ │ │ ├── index.ts │ │ │ └── plugin-example │ │ │ │ └── index.ts │ │ ├── setters │ │ │ ├── group-setter │ │ │ │ └── index.tsx │ │ │ ├── index.ts │ │ │ └── string-setter │ │ │ │ └── index.tsx │ │ └── utils.ts │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── uno.config.ts │ └── vite.config.ts ├── package.json ├── packages ├── core │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── config.ts │ │ ├── designer │ │ │ ├── active-tracker.ts │ │ │ ├── clipboard.ts │ │ │ ├── designer.ts │ │ │ ├── detecting.ts │ │ │ ├── dragon.ts │ │ │ ├── index.ts │ │ │ ├── location.ts │ │ │ ├── offset-observer.ts │ │ │ ├── scroller.ts │ │ │ ├── selection.ts │ │ │ ├── sensor.ts │ │ │ └── setting │ │ │ │ ├── index.ts │ │ │ │ ├── setting-entry.ts │ │ │ │ ├── setting-field.ts │ │ │ │ ├── setting-manager.ts │ │ │ │ ├── setting-prop-entry.ts │ │ │ │ └── setting-top-entry.ts │ │ ├── document │ │ │ ├── document.ts │ │ │ ├── history.ts │ │ │ ├── index.ts │ │ │ ├── node │ │ │ │ ├── node-children.ts │ │ │ │ └── node.ts │ │ │ └── prop │ │ │ │ ├── prop.ts │ │ │ │ ├── props.ts │ │ │ │ └── value-to-source.ts │ │ ├── engine │ │ │ ├── editor.ts │ │ │ ├── engine.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── materials │ │ │ ├── component-meta.ts │ │ │ ├── index.ts │ │ │ └── materials.ts │ │ ├── plugin │ │ │ ├── index.ts │ │ │ ├── plugin-context.ts │ │ │ ├── plugin-extend-mobx.ts │ │ │ ├── plugin-extend.ts │ │ │ ├── plugin-runtime.ts │ │ │ ├── plugins.ts │ │ │ └── sequencify.ts │ │ ├── project │ │ │ ├── index.ts │ │ │ └── project.ts │ │ ├── setters │ │ │ ├── index.ts │ │ │ └── setters.ts │ │ ├── simulator │ │ │ ├── index.ts │ │ │ ├── simulator-renderer.ts │ │ │ ├── simulator.ts │ │ │ └── viewport.ts │ │ ├── types │ │ │ ├── common.ts │ │ │ ├── component.ts │ │ │ ├── data-source.ts │ │ │ ├── editor.ts │ │ │ ├── event.ts │ │ │ ├── index.ts │ │ │ ├── meta.ts │ │ │ ├── schema.ts │ │ │ └── setter.ts │ │ └── utils │ │ │ ├── common.ts │ │ │ ├── event-bus.ts │ │ │ ├── event.ts │ │ │ ├── hotkey.ts │ │ │ ├── index.ts │ │ │ ├── is.ts │ │ │ ├── logger.ts │ │ │ └── unique-id.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── create-easy-editor │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── const.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── template │ │ └── dashboard │ │ │ └── react │ │ │ ├── .editorconfig │ │ │ ├── README.md │ │ │ ├── biome.json │ │ │ ├── components.json │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── public │ │ │ └── logo.svg │ │ │ ├── src │ │ │ ├── App.tsx │ │ │ ├── assets │ │ │ │ ├── banner.png │ │ │ │ ├── logo.svg │ │ │ │ └── react.svg │ │ │ ├── components │ │ │ │ ├── theme-provider.tsx │ │ │ │ ├── theme-toggle.tsx │ │ │ │ └── ui │ │ │ │ │ ├── accordion.tsx │ │ │ │ │ ├── button.tsx │ │ │ │ │ ├── card.tsx │ │ │ │ │ ├── chart.tsx │ │ │ │ │ ├── collapsible.tsx │ │ │ │ │ ├── context-menu.tsx │ │ │ │ │ ├── dropdown-menu.tsx │ │ │ │ │ ├── input.tsx │ │ │ │ │ ├── label.tsx │ │ │ │ │ ├── popover.tsx │ │ │ │ │ ├── progress.tsx │ │ │ │ │ ├── radio-group.tsx │ │ │ │ │ ├── select.tsx │ │ │ │ │ ├── separator.tsx │ │ │ │ │ ├── sheet.tsx │ │ │ │ │ ├── sidebar-extra.tsx │ │ │ │ │ ├── sidebar.tsx │ │ │ │ │ ├── skeleton.tsx │ │ │ │ │ ├── sonner.tsx │ │ │ │ │ ├── switch.tsx │ │ │ │ │ ├── tabs.tsx │ │ │ │ │ └── tooltip.tsx │ │ │ ├── editor │ │ │ │ ├── const.ts │ │ │ │ ├── index.ts │ │ │ │ ├── materials │ │ │ │ │ ├── basic │ │ │ │ │ │ ├── image │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ │ └── text │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ ├── chart │ │ │ │ │ │ ├── area-chart │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ │ ├── bar-chart │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ │ ├── line-chart │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ │ ├── pie-chart │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ │ ├── radar-chart │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ │ └── radial-chart │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ ├── meta.ts │ │ │ │ │ │ │ └── snippets.ts │ │ │ │ │ ├── component.ts │ │ │ │ │ ├── configure.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── inner │ │ │ │ │ │ └── group │ │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ │ └── meta.ts │ │ │ │ │ ├── meta.ts │ │ │ │ │ ├── root │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ ├── configure.ts │ │ │ │ │ │ └── meta.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── overrides.css │ │ │ │ ├── plugins │ │ │ │ │ ├── index.ts │ │ │ │ │ └── plugin-hotkey-move-node │ │ │ │ │ │ └── index.ts │ │ │ │ ├── setters │ │ │ │ │ ├── basic │ │ │ │ │ │ ├── color-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── id-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── number-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── rect-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── string-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── switch-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── upload-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── custom-field-item.tsx │ │ │ │ │ ├── group │ │ │ │ │ │ ├── collapse-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── tab-setter │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── type.ts │ │ │ │ └── utils.ts │ │ │ ├── hooks │ │ │ │ ├── useDebounceFn.ts │ │ │ │ └── useMobile.ts │ │ │ ├── lib │ │ │ │ ├── schema.ts │ │ │ │ └── utils.ts │ │ │ ├── main.tsx │ │ │ ├── pages │ │ │ │ ├── editor │ │ │ │ │ ├── ContextMenu.tsx │ │ │ │ │ ├── Header.tsx │ │ │ │ │ ├── Renderer.tsx │ │ │ │ │ ├── SettingRenderer.tsx │ │ │ │ │ ├── Sidebar │ │ │ │ │ │ ├── Components.tsx │ │ │ │ │ │ ├── Outline.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ └── preview │ │ │ │ │ └── index.tsx │ │ │ ├── styles │ │ │ │ └── global.css │ │ │ └── vite-env.d.ts │ │ │ ├── tailwind.config.js │ │ │ ├── tsconfig.app.json │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.mts │ └── tsconfig.json ├── plugin-dashboard │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── designer │ │ │ └── guideline.ts │ │ ├── index.ts │ │ ├── type.ts │ │ └── utils.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── plugin-datasource │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── core │ │ │ ├── RuntimeDataSourceItem.ts │ │ │ ├── adapter.ts │ │ │ ├── index.ts │ │ │ └── reloadDataSourceFactory.ts │ │ ├── handlers │ │ │ └── fetch.ts │ │ ├── helpers │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── interpret │ │ │ ├── DataSourceEngineFactory.ts │ │ │ └── index.ts │ │ ├── runtime │ │ │ ├── RuntimeDataSourceEngineFactory.ts │ │ │ └── index.ts │ │ ├── type.ts │ │ ├── types │ │ │ ├── data-source-handlers.ts │ │ │ ├── data-source-interpret.ts │ │ │ ├── data-source-runtime.ts │ │ │ ├── data-source.ts │ │ │ └── index.ts │ │ └── utils.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── plugin-hotkey │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── const.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── react-renderer-dashboard │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── css │ │ │ └── theme.css │ │ ├── index.ts │ │ ├── loading.css │ │ ├── renderer-core │ │ │ ├── hoc │ │ │ │ └── dashboard.tsx │ │ │ ├── index.tsx │ │ │ ├── renderer.ts │ │ │ └── renderer │ │ │ │ └── base.ts │ │ ├── renderer │ │ │ ├── index.css │ │ │ └── index.tsx │ │ ├── simulator-renderer │ │ │ ├── RendererView.tsx │ │ │ ├── SimulatorRenderer │ │ │ │ ├── BemTools │ │ │ │ │ ├── BorderDetecting.tsx │ │ │ │ │ ├── BorderResizing.tsx │ │ │ │ │ ├── BorderSelecting.tsx │ │ │ │ │ ├── GuideLine.tsx │ │ │ │ │ ├── drag-resize-engine.ts │ │ │ │ │ ├── index.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── tools.css │ │ │ │ │ └── utils.ts │ │ │ │ ├── DesignView.tsx │ │ │ │ ├── ProjectView.tsx │ │ │ │ ├── SimulatorView.tsx │ │ │ │ ├── css │ │ │ │ │ └── theme.css │ │ │ │ ├── hooks │ │ │ │ │ └── useResizeObserver.ts │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── loading.css │ │ │ ├── document-instance.ts │ │ │ ├── index.ts │ │ │ ├── simulator-renderer.ts │ │ │ └── utils.ts │ │ └── type.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── react-renderer │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── adapter │ │ │ └── index.ts │ │ ├── base.tsx │ │ ├── component.tsx │ │ ├── components │ │ │ ├── FaultComponent.tsx │ │ │ └── NotFoundComponent.tsx │ │ ├── context.ts │ │ ├── hoc │ │ │ ├── comp.tsx │ │ │ ├── index.ts │ │ │ └── leaf.tsx │ │ ├── index.ts │ │ ├── page.tsx │ │ ├── renderer.tsx │ │ ├── setting-renderer │ │ │ ├── SettingSetter.tsx │ │ │ ├── context.ts │ │ │ └── index.tsx │ │ ├── types.ts │ │ └── utils │ │ │ ├── hoc.ts │ │ │ ├── index.ts │ │ │ └── is.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json └── renderer-core │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ ├── index.ts │ ├── types │ │ ├── components.ts │ │ ├── index.ts │ │ ├── renderer.ts │ │ └── setting-renderer.ts │ └── utils │ │ ├── classnames.ts │ │ ├── common.ts │ │ ├── data-helper.ts │ │ ├── index.ts │ │ ├── logger.ts │ │ └── request.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── tsconfig.json ├── tsconfig.test.json └── turbo.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.4/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["example-dashboard"] 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.github/assets/banne-bg-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/banne-bg-light.png -------------------------------------------------------------------------------- /.github/assets/banner-bg-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/banner-bg-dark.png -------------------------------------------------------------------------------- /.github/assets/banner-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/banner-dark.png -------------------------------------------------------------------------------- /.github/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/banner.png -------------------------------------------------------------------------------- /.github/assets/logo- bg-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/logo- bg-light.png -------------------------------------------------------------------------------- /.github/assets/logo-bg-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/logo-bg-dark.png -------------------------------------------------------------------------------- /.github/assets/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/logo-dark.png -------------------------------------------------------------------------------- /.github/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/.github/assets/logo.png -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: write-all 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | node-version: [18] 18 | 19 | steps: 20 | - name: Checkout Branch 21 | uses: actions/checkout@v3 22 | 23 | - name: Install pnpm 24 | uses: pnpm/action-setup@v4 25 | 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | cache: 'pnpm' 31 | 32 | - name: Install Dependencies 33 | run: pnpm install 34 | 35 | - name: Setup 36 | run: pnpm run pub:build 37 | 38 | - name: Publish to npm 39 | id: changesets 40 | uses: changesets/action@v1 41 | with: 42 | version: pnpm run pub:version 43 | commit: 'chore: update versions' 44 | title: 'chore: update versions' 45 | publish: pnpm run pub:release 46 | createGithubReleases: true 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }} 49 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 50 | -------------------------------------------------------------------------------- /.github/workflows/version.yml: -------------------------------------------------------------------------------- 1 | name: Version 2 | 3 | on: 4 | push: 5 | branches: 6 | - release/** 7 | - release 8 | 9 | permissions: write-all 10 | 11 | jobs: 12 | version: 13 | name: Version 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [18] 19 | 20 | steps: 21 | - name: Checkout Branch 22 | uses: actions/checkout@v3 23 | 24 | - name: Install pnpm 25 | uses: pnpm/action-setup@v4 26 | 27 | - name: Use Node.js ${{ matrix.node-version }} 28 | uses: actions/setup-node@v3 29 | with: 30 | node-version: ${{ matrix.node-version }} 31 | cache: 'pnpm' 32 | 33 | - name: Install Dependencies 34 | run: pnpm install 35 | 36 | - name: Create Release Pull Request 37 | uses: changesets/action@v1 38 | with: 39 | version: pnpm run pub:version 40 | commit: 'chore: update versions' 41 | title: 'chore: update versions' 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }} 44 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | pnpm commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm lint-staged 2 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "*.{ts,tsx,js,jsx,json}": "biome format --write ." 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "biomejs.biome", 3 | "editor.codeActionsOnSave": { 4 | "source.organizeImports": "explicit", 5 | "quickfix.biome": "explicit" 6 | }, 7 | "editor.formatOnSave": true, 8 | "[javascript]": { 9 | "editor.defaultFormatter": "biomejs.biome" 10 | }, 11 | "[typescript]": { 12 | "editor.defaultFormatter": "biomejs.biome" 13 | }, 14 | "[javascriptreact]": { 15 | "editor.defaultFormatter": "biomejs.biome" 16 | }, 17 | "[typescriptreact]": { 18 | "editor.defaultFormatter": "biomejs.biome" 19 | }, 20 | "[json]": { 21 | "editor.defaultFormatter": "biomejs.biome" 22 | }, 23 | "cSpell.words": [ 24 | "autorun", 25 | "deactive", 26 | "easyeditor", 27 | "inited", 28 | "Metas" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2024-PRESENT JinSo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/config/index.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import { en } from './en' 3 | import { shared } from './shared' 4 | import { zh } from './zh' 5 | 6 | export default defineConfig({ 7 | ...shared, 8 | locales: { 9 | root: { label: '简体中文', ...zh }, 10 | en: { label: 'English', ...en }, 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /docs/.vitepress/config/shared.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons' 3 | 4 | const title = 'EasyEditor' 5 | 6 | export const shared = defineConfig({ 7 | lang: 'zh', 8 | title, 9 | titleTemplate: title, 10 | outDir: './dist', 11 | head: [ 12 | ['link', { rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' }], 13 | ['link', { rel: 'alternate icon', href: '/favicon.ico', type: 'image/png', sizes: '16x16' }], 14 | ['meta', { name: 'author', content: 'JinSo' }], 15 | [ 16 | 'link', 17 | { rel: 'search', type: 'application/opensearchdescription+xml', href: '/search.xml', title: 'EasyEditor' }, 18 | ], 19 | ], 20 | lastUpdated: true, 21 | cleanUrls: true, 22 | 23 | themeConfig: { 24 | logo: '/logo-dark.svg', 25 | search: { 26 | provider: 'local', 27 | }, 28 | outline: [2, 3], 29 | socialLinks: [{ icon: 'github', link: 'https://github.com/Easy-Editor/EasyEditor' }], 30 | footer: { 31 | message: 'Released under the MIT License.', 32 | copyright: 'Copyright © 2024-PRESENT JinSo', 33 | }, 34 | }, 35 | 36 | markdown: { 37 | // math: true, 38 | config(md) { 39 | md.use(groupIconMdPlugin) 40 | }, 41 | }, 42 | 43 | vite: { 44 | plugins: [groupIconVitePlugin()], 45 | }, 46 | }) 47 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/Layout.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/RainbowSwitcher.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 64 | -------------------------------------------------------------------------------- /docs/components.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | 3 | declare module 'vue' { 4 | export interface GlobalComponents { 5 | RainbowAnimationSwitcher: typeof import('./.vitepress/theme/components/RainbowAnimationSwitcher.vue')['default'] 6 | RainbowSwitcher: typeof import('./.vitepress/theme/components/RainbowSwitcher.vue')['default'] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/design/editor.md: -------------------------------------------------------------------------------- 1 | # 编排模块 2 | 3 | :::tip 4 | 我们正在编写 EasyEditor 特有的架构设计文档,敬请期待。 5 | ::: 6 | 7 | :::info 8 | EasyEditor 是基于 [lowcode-engine](https://github.com/alibaba/lowcode-engine) 进行修改和扩展的,大体功能上基本一致。 9 | 10 | 可以先参考 [lowcode-engine 的编排模块设计文档](https://lowcode-engine.cn/site/docs/guide/design/editor)。 11 | ::: 12 | -------------------------------------------------------------------------------- /docs/design/overview.md: -------------------------------------------------------------------------------- 1 | # 架构综述 2 | 3 | :::tip 4 | 我们正在编写 EasyEditor 特有的架构设计文档,敬请期待。 5 | ::: 6 | 7 | :::info 8 | EasyEditor 是基于 [lowcode-engine](https://github.com/alibaba/lowcode-engine) 进行修改和扩展的,大体功能上基本一致。 9 | 10 | 可以先参考 [lowcode-engine 的架构综述文档](https://lowcode-engine.cn/site/docs/guide/design/summary)。 11 | ::: 12 | -------------------------------------------------------------------------------- /docs/design/plugin.md: -------------------------------------------------------------------------------- 1 | # 插件系统 2 | 3 | :::tip 4 | 我们正在编写 EasyEditor 特有的架构设计文档,敬请期待。 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/design/renderer.md: -------------------------------------------------------------------------------- 1 | # 渲染模块 2 | 3 | :::tip 4 | 我们正在编写 EasyEditor 特有的架构设计文档,敬请期待。 5 | ::: 6 | 7 | :::info 8 | EasyEditor 是基于 [lowcode-engine](https://github.com/alibaba/lowcode-engine) 进行修改和扩展的,大体功能上基本一致。 9 | 10 | 可以先参考 [lowcode-engine 的渲染模块设计文档](https://lowcode-engine.cn/site/docs/guide/design/renderer)。 11 | ::: 12 | -------------------------------------------------------------------------------- /docs/design/setter.md: -------------------------------------------------------------------------------- 1 | # 设置器模块 2 | 3 | :::tip 4 | 我们正在编写 EasyEditor 特有的架构设计文档,敬请期待。 5 | ::: 6 | 7 | :::info 8 | EasyEditor 是基于 [lowcode-engine](https://github.com/alibaba/lowcode-engine) 进行修改和扩展的,大体功能上基本一致。 9 | 10 | 可以先参考 [lowcode-engine 的设置器设计文档](https://lowcode-engine.cn/site/docs/guide/design/setter)。 11 | ::: 12 | -------------------------------------------------------------------------------- /docs/design/specs.md: -------------------------------------------------------------------------------- 1 | # 协议栈简介 2 | 3 | :::tip 4 | 我们正在编写 EasyEditor 特有的架构设计文档,敬请期待。 5 | ::: 6 | 7 | :::info 8 | EasyEditor 是基于 [lowcode-engine](https://github.com/alibaba/lowcode-engine) 进行修改和扩展的,大体功能上基本一致。 9 | 10 | 可以先参考 [lowcode-engine 的协议栈简介文档](https://lowcode-engine.cn/site/docs/guide/design/specs)。 11 | ::: 12 | -------------------------------------------------------------------------------- /docs/en/design/editor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Editor Module 3 | description: Overview of EasyEditor's editor module 4 | --- 5 | 6 | # Editor Module 7 | 8 | ::: tip 9 | We are currently working on editor module documentation specific to EasyEditor. Stay tuned! 10 | ::: 11 | 12 | ::: info 13 | EasyEditor is based on [lowcode-engine](https://github.com/alibaba/lowcode-engine) with modifications and extensions, though the core functionality remains similar. 14 | 15 | You can refer to the [lowcode-engine editor module documentation](https://lowcode-engine.cn/site/docs/guide/design/editor) in the meantime. 16 | ::: 17 | 18 | ::: warning English Documentation Status 19 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 20 | ::: 21 | -------------------------------------------------------------------------------- /docs/en/design/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Architecture Overview 3 | description: Overview of EasyEditor's architecture 4 | --- 5 | 6 | # Architecture Overview 7 | 8 | ::: tip 9 | We are currently working on architecture design documentation specific to EasyEditor. Stay tuned! 10 | ::: 11 | 12 | ::: info 13 | EasyEditor is based on [lowcode-engine](https://github.com/alibaba/lowcode-engine) with modifications and extensions, though the core functionality remains similar. 14 | 15 | You can refer to the [lowcode-engine architecture overview documentation](https://lowcode-engine.cn/site/docs/guide/design/summary) in the meantime. 16 | ::: 17 | 18 | ::: warning English Documentation Status 19 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 20 | ::: 21 | -------------------------------------------------------------------------------- /docs/en/design/plugin.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Plugin System 3 | description: Overview of EasyEditor's plugin system 4 | --- 5 | 6 | # Plugin System 7 | 8 | ::: tip 9 | We are currently working on plugin system documentation specific to EasyEditor. Stay tuned! 10 | ::: 11 | 12 | ::: warning English Documentation Status 13 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 14 | ::: 15 | -------------------------------------------------------------------------------- /docs/en/design/renderer.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Renderer Module 3 | description: Overview of EasyEditor's renderer module 4 | --- 5 | 6 | # Renderer Module 7 | 8 | ::: tip 9 | We are currently working on renderer module documentation specific to EasyEditor. Stay tuned! 10 | ::: 11 | 12 | ::: info 13 | EasyEditor is based on [lowcode-engine](https://github.com/alibaba/lowcode-engine) with modifications and extensions, though the core functionality remains similar. 14 | 15 | You can refer to the [lowcode-engine renderer module documentation](https://lowcode-engine.cn/site/docs/guide/design/renderer) in the meantime. 16 | ::: 17 | 18 | ::: warning English Documentation Status 19 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 20 | ::: 21 | -------------------------------------------------------------------------------- /docs/en/design/setter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setter Module 3 | description: Overview of EasyEditor's setter module 4 | --- 5 | 6 | # Setter Module 7 | 8 | ::: tip 9 | We are currently working on setter module documentation specific to EasyEditor. Stay tuned! 10 | ::: 11 | 12 | ::: info 13 | EasyEditor is based on [lowcode-engine](https://github.com/alibaba/lowcode-engine) with modifications and extensions, though the core functionality remains similar. 14 | 15 | You can refer to the [lowcode-engine setter module documentation](https://lowcode-engine.cn/site/docs/guide/design/setter) in the meantime. 16 | ::: 17 | 18 | ::: warning English Documentation Status 19 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 20 | ::: 21 | -------------------------------------------------------------------------------- /docs/en/design/specs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Protocol Stack 3 | description: Introduction to EasyEditor's protocol stack 4 | --- 5 | 6 | # Protocol Stack 7 | 8 | ::: tip 9 | We are currently working on protocol stack documentation specific to EasyEditor. Stay tuned! 10 | ::: 11 | 12 | ::: info 13 | EasyEditor is based on [lowcode-engine](https://github.com/alibaba/lowcode-engine) with modifications and extensions, though the core functionality remains similar. 14 | 15 | You can refer to the [lowcode-engine protocol stack documentation](https://lowcode-engine.cn/site/docs/guide/design/specs) in the meantime. 16 | ::: 17 | 18 | ::: warning English Documentation Status 19 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 20 | ::: 21 | -------------------------------------------------------------------------------- /docs/en/guide/core-concepts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Core Concepts 3 | description: Understanding the core concepts of EasyEditor 4 | --- 5 | 6 | # Core Concepts 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/extension/material.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Material Extension 3 | description: Developing custom materials for EasyEditor 4 | --- 5 | 6 | # Material Extension 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/extension/plugin.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Plugin Extension 3 | description: Developing custom plugins for EasyEditor 4 | --- 5 | 6 | # Plugin Extension 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/extension/setter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setter Extension 3 | description: Developing custom setters for EasyEditor 4 | --- 5 | 6 | # Setter Extension 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | description: Get started with EasyEditor 4 | --- 5 | 6 | # Getting Started 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/renderer/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Renderer Customization 3 | description: Creating custom renderers for EasyEditor 4 | --- 5 | 6 | # Renderer Customization 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/renderer/editor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Design-time Renderer 3 | description: Working with EasyEditor's design-time renderer 4 | --- 5 | 6 | # Using Design-time Renderer 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/renderer/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Renderer Overview 3 | description: Understanding EasyEditor's rendering system 4 | --- 5 | 6 | # Renderer Overview 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/renderer/runtime.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Runtime Renderer 3 | description: Working with EasyEditor's runtime renderer 4 | --- 5 | 6 | # Using Runtime Renderer 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/scenarios/dashboard/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dashboard Design Getting Started 3 | description: Getting started with dashboard design in EasyEditor 4 | --- 5 | 6 | # Dashboard Design Getting Started 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/scenarios/dashboard/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dashboard Design Introduction 3 | description: Introduction to dashboard design with EasyEditor 4 | --- 5 | 6 | # Dashboard Design Introduction 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/scenarios/form/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Form Design Getting Started 3 | description: Getting started with form design in EasyEditor 4 | --- 5 | 6 | # Form Design Getting Started 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/scenarios/form/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Form Design Introduction 3 | description: Introduction to form design with EasyEditor 4 | --- 5 | 6 | # Form Design Introduction 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/guide/why.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Why EasyEditor? 3 | description: Core advantages and principles of EasyEditor 4 | --- 5 | 6 | # Why EasyEditor? 7 | 8 | ::: warning English Documentation Status 9 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 10 | ::: 11 | -------------------------------------------------------------------------------- /docs/en/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | title: "EasyEditor: Plugin-based cross-framework low-code engine for building visual application platforms" 4 | 5 | hero: 6 | name: EasyEditor 7 | text: Low-Code Engine 8 | tagline: Plugin-based cross-framework low-code engine for building visual application platforms 9 | image: 10 | light: /logo.svg 11 | dark: /logo-dark.svg 12 | alt: EasyEditor 13 | actions: 14 | - theme: brand 15 | text: What is EasyEditor? 16 | link: /guide/why 17 | - theme: alt 18 | text: Getting Started 19 | link: /guide/getting-started 20 | - theme: alt 21 | text: Reference 22 | link: /reference/overview 23 | 24 | features: 25 | - title: Decoupling Design 26 | icon: 🔌 27 | details: Engine core is framework-independent, supporting multiple framework rendering extensions 28 | - title: Plugin Architecture 29 | icon: 🧩 30 | details: Flexible plugin system design, lifecycle management, hotkey binding, class extension mechanism, dependency injection... 31 | - title: Renderer Engine 32 | icon: ⚡ 33 | details: Multi-framework support, real-time preview, Schema driven, component isolation sandbox 34 | - title: Visual Design 35 | icon: 🎨 36 | details: Complete implementation of the designer, drag-and-drop layout, snapping alignment, multi-device preview, undo/redo stack... 37 | - title: Enterprise-level Capabilities 38 | icon: 🏢 39 | details: Data source management, multi-language support, version control, online collaboration 40 | - title: Component Ecosystem 41 | icon: 📦 42 | details: Built-in material market, component packaging specifications, material development tools, component version management... 43 | --- 44 | 45 | -------------------------------------------------------------------------------- /docs/en/reference/core/index.md: -------------------------------------------------------------------------------- 1 | # Editor 2 | 3 | ::: warning English Documentation Status 4 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/en/reference/overview.md: -------------------------------------------------------------------------------- 1 | # API Overview 2 | 3 | ::: warning English Documentation Status 4 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/en/reference/plugin/index.md: -------------------------------------------------------------------------------- 1 | # Plugin 2 | 3 | ::: warning English Documentation Status 4 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/en/reference/renderer/index.md: -------------------------------------------------------------------------------- 1 | # Renderer 2 | 3 | ::: warning English Documentation Status 4 | This English documentation is currently under development. The content may be incomplete or subject to change. For the most complete and up-to-date information, please refer to the Chinese documentation. We appreciate your patience as we work to provide comprehensive English documentation. 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/guide/scenarios/dashboard/index.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | EasyEditor 的大屏设计场景是基于插件化架构实现的,通过 `@easy-editor/plugin-dashboard` 和 `@easy-editor/react-renderer-dashboard` 两个核心包,为开发者提供了完整的大屏设计能力。 4 | 5 | ## 核心价值 6 | 7 | 大屏设计场景致力于解决以下问题: 8 | 9 | 1. **开发效率** 10 | - 通过可视化拖拽快速构建大屏应用 11 | - 内置丰富的组件库,开箱即用 12 | - 支持组件复用和模板管理 13 | 14 | 2. **技术门槛** 15 | - 降低大屏开发的技术门槛 16 | - 无需深入掌握复杂的数据可视化技术 17 | - 提供友好的可视化配置界面 18 | 19 | 3. **维护成本** 20 | - 统一的组件管理机制 21 | - 标准化的数据接入方案 22 | - 可复用的主题配置系统 23 | 24 | ## 技术架构 25 | 26 | 大屏设计场景的核心是 `@easy-editor/plugin-dashboard` 插件,它扩展了 `@easy-editor/core` 的基础能力,提供了: 27 | 28 | - 大屏专用的设计器逻辑 29 | - 大屏组件物料体系 30 | - 大屏特有的布局系统 31 | - 分组功能 32 | - ... 33 | 34 | ### 渲染引擎 35 | 36 | `@easy-editor/react-renderer-dashboard` 是基于 React 的大屏渲染引擎,它扩展了 `@easy-editor/react-renderer` 的基础能力,提供了: 37 | 38 | - 大屏特有的布局系统 39 | - 多页面能力 40 | - 组件增强能力 41 | - 性能优化 42 | 43 | ## 应用场景 44 | 45 | 大屏设计场景适用于: 46 | 47 | - 数据可视化大屏 48 | - 监控中心 49 | - 指挥中心 50 | - 展示大屏 51 | - 数据看板 52 | 53 | ## 最佳实践 54 | 55 | 我们提供了一个完整的大屏设计案例 [EasyDashboard](https://github.com/Easy-Editor/EasyDashboard),展示了如何基于 EasyEditor 构建专业的大屏应用。该案例包含了: 56 | 57 | - 完整的大屏设计流程 58 | - 丰富的组件示例 59 | - 数据源接入示例 60 | - 主题配置示例 61 | - 性能优化实践 62 | -------------------------------------------------------------------------------- /docs/guide/scenarios/form/getting-started.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | 3 | :::info 开发中 4 | 表单设计场景的快速开始指南正在开发中,敬请期待! 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/guide/scenarios/form/index.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | :::info 开发中 4 | 表单设计场景功能正在积极开发中,敬请期待! 5 | ::: 6 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | title: "EasyEditor: 用于构建可视化应用平台的插件化跨框架低代码引擎" 4 | 5 | hero: 6 | name: EasyEditor 7 | text: 低代码引擎 8 | tagline: 用于构建可视化应用平台的插件化跨框架低代码引擎 9 | image: 10 | light: /logo.svg 11 | dark: /logo-dark.svg 12 | alt: EasyEditor 13 | actions: 14 | - theme: brand 15 | text: 什么是 EasyEditor? 16 | link: /guide/why 17 | - theme: alt 18 | text: 快速开始 19 | link: /guide/getting-started 20 | - theme: alt 21 | text: API 参考 22 | link: /reference/overview 23 | 24 | features: 25 | - title: 解耦设计 26 | icon: 🔌 27 | details: 引擎核心与框架无关,支持多种框架渲染扩展 28 | - title: 插件化架构 29 | icon: 🧩 30 | details: 灵活的插件系统设计,生命周期管理、热键绑定、类扩展机制、依赖注入... 31 | - title: 渲染引擎 32 | icon: ⚡ 33 | details: 多框架支持、实时预览、Schema 驱动、组件隔离沙箱 34 | - title: 可视化设计 35 | icon: 🎨 36 | details: 完整的设计器实现,拖拽布局、吸附对齐、多设备预览、撤销/重做栈... 37 | - title: 企业级能力 38 | icon: 🏢 39 | details: 数据源管理、多语言支持、版本控制、在线协作 40 | - title: 组件生态体系 41 | icon: 📦 42 | details: 内置物料市场、组件封装规范、物料开发工具、组件版本管理... 43 | --- 44 | 45 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "private": true, 6 | "scripts": { 7 | "docs:dev": "vitepress dev", 8 | "docs:build": "vitepress build", 9 | "docs:preview": "vitepress preview" 10 | }, 11 | "devDependencies": { 12 | "unocss": "^0.64.1", 13 | "vite": "^6.0.1", 14 | "vitepress": "^1.6.3" 15 | }, 16 | "dependencies": { 17 | "@vueuse/core": "^13.0.0", 18 | "vitepress-plugin-group-icons": "^1.4.1", 19 | "vue": "^3.5.13" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/public/relationship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/docs/public/relationship.png -------------------------------------------------------------------------------- /docs/public/relationship_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/docs/public/relationship_dark.png -------------------------------------------------------------------------------- /docs/reference/overview.md: -------------------------------------------------------------------------------- 1 | # API 总览 2 | 3 | :::warning 注意 4 | 目前 API 文档仅提供核心的 Editor、Plugin、Renderer 的 API 参考,其他 API 文档仍在开发中。我们会持续更新和完善文档内容,以提供更全面的开发指南。 5 | ::: 6 | 7 | 8 | EasyEditor 提供了一系列强大的 API,用于构建和扩展低代码编辑器。本节将概述 EasyEditor 的 API 体系结构,帮助您了解如何使用这些 API 构建自己的低代码应用。 9 | 10 | ## API 分类 11 | 12 | EasyEditor 的 API 主要分为以下几个部分: 13 | 14 | ### 核心 API(Core) 15 | 16 | 核心 API 是 EasyEditor 的基础,提供了编辑器的基本功能和数据结构。主要包括: 17 | 18 | - **项目管理**:`Project`、`Document` - 管理低代码项目和文档 19 | - **节点操作**:`Node`、`Props` - 处理组件树和属性 20 | - **编辑器设计**:`Designer`、`Selection`、`Dragon` - 设计器核心功能 21 | - **组件元数据**:`ComponentMeta`、`Setting` - 组件配置和设置 22 | - **模拟器**:`Simulator`、`SimulatorRenderer` - 页面渲染和预览 23 | 24 | [了解更多核心 API](./core/index) 25 | 26 | ### 插件 API(Plugin) 27 | 28 | 插件 API 允许开发者扩展 EasyEditor 的功能,创建自定义插件。包括: 29 | 30 | - **插件生命周期**:插件的注册、初始化和卸载 31 | - **插件上下文**:访问编辑器内部功能 32 | - **扩展点**:在特定位置扩展编辑器功能 33 | 34 | [了解更多插件 API](./plugin/index) 35 | 36 | ### 渲染器 API(Renderer) 37 | 38 | 渲染器 API 用于自定义组件的渲染方式,支持多框架渲染。包括: 39 | 40 | - **渲染引擎**:将 Schema 转换为实际 UI 41 | - **渲染适配器**:适配不同前端框架 42 | - **渲染钩子**:自定义渲染过程 43 | 44 | [了解更多渲染器 API](./renderer/index) 45 | 46 | ## 开始使用 47 | 48 | 根据您的需求,选择对应的 API 类别查看详细文档。每个 API 文档都提供了详细的接口说明和使用示例。 49 | 50 | - 查看编辑器核心功能?查看[核心 API](./core/index) 51 | - 查看插件开发指南?查看[插件 API](./plugin/index) 52 | - 查看渲染器配置?查看[渲染器 API](./renderer/index) 53 | -------------------------------------------------------------------------------- /docs/uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, presetAttributify, presetIcons, presetWind, transformerDirectives } from 'unocss' 2 | 3 | export default defineConfig({ 4 | theme: { 5 | animation: { 6 | keyframes: { 7 | custom: '{0%, 100% { transform: scale(0.5); } 50% { transform: scale(1); }}', 8 | }, 9 | durations: { 10 | custom: '2s', 11 | }, 12 | timingFns: { 13 | custom: 'cubic-bezier(0.4,0,.6,1)', 14 | }, 15 | properties: { 16 | custom: { 'transform-origin': 'center' }, 17 | }, 18 | counts: { 19 | custom: 'infinite', 20 | }, 21 | }, 22 | }, 23 | presets: [presetWind(), presetIcons(), presetAttributify()], 24 | transformers: [transformerDirectives()], 25 | }) 26 | -------------------------------------------------------------------------------- /docs/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "cleanUrls": true 3 | } -------------------------------------------------------------------------------- /docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import UnoCSS from 'unocss/vite' 2 | import { defineConfig } from 'vite' 3 | 4 | export default defineConfig({ 5 | plugins: [UnoCSS()], 6 | }) 7 | -------------------------------------------------------------------------------- /examples/dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/dashboard/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 23 | }, 24 | }, 25 | ) 26 | -------------------------------------------------------------------------------- /examples/dashboard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-dashboard", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@easy-editor/core": "workspace:*", 14 | "@easy-editor/plugin-datasource": "workspace:*", 15 | "@easy-editor/plugin-dashboard": "workspace:*", 16 | "@easy-editor/plugin-hotkey": "workspace:*", 17 | "@easy-editor/renderer-core": "workspace:*", 18 | "@easy-editor/react-renderer": "workspace:*", 19 | "@easy-editor/react-renderer-dashboard": "workspace:*", 20 | "mobx-react": "^9.2.0", 21 | "react": "^19.0.0", 22 | "react-dom": "^19.0.0", 23 | "react-scan": "^0.0.50" 24 | }, 25 | "devDependencies": { 26 | "@eslint/js": "^9.15.0", 27 | "@types/react": "^19.0.8", 28 | "@types/react-dom": "^19.0.3", 29 | "@vitejs/plugin-react": "^4.3.4", 30 | "eslint": "^9.15.0", 31 | "eslint-plugin-react-hooks": "^5.0.0", 32 | "eslint-plugin-react-refresh": "^0.4.14", 33 | "globals": "^15.12.0", 34 | "typescript": "~5.6.2", 35 | "typescript-eslint": "^8.15.0", 36 | "unocss": "^0.64.1", 37 | "vite": "^6.0.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/dashboard/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/dashboard/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Center from './components/Center' 2 | import Header from './components/Header' 3 | import Left from './components/Left' 4 | import Right from './components/Right' 5 | 6 | const App = () => { 7 | return ( 8 |
9 | {/* */} 17 |
18 |
19 | 20 |
21 | 22 |
23 |
24 | ) 25 | } 26 | 27 | export default App 28 | -------------------------------------------------------------------------------- /examples/dashboard/src/components/Center.tsx: -------------------------------------------------------------------------------- 1 | import { project } from '@easy-editor/core' 2 | import { SimulatorRenderer } from '@easy-editor/react-renderer-dashboard' 3 | import { observer } from 'mobx-react' 4 | 5 | const Center = observer(() => { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | }) 14 | 15 | export default Center 16 | -------------------------------------------------------------------------------- /examples/dashboard/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | const Header = () => { 2 | return ( 3 |
4 |
5 |
6 |

低代码平台

7 |
8 |
9 | 12 | 15 |
16 |
17 |
18 | ) 19 | } 20 | 21 | export default Header 22 | -------------------------------------------------------------------------------- /examples/dashboard/src/components/Left.tsx: -------------------------------------------------------------------------------- 1 | import { type Snippet as ISnippet, materials, project } from '@easy-editor/core' 2 | import { observer } from 'mobx-react' 3 | import { useEffect, useRef } from 'react' 4 | 5 | const Snippet = ({ snippet }: { snippet: ISnippet }) => { 6 | const ref = useRef(null) 7 | 8 | useEffect(() => { 9 | const unlink = project.simulator?.linkSnippet(ref.current!, snippet) 10 | return () => { 11 | unlink?.() 12 | } 13 | }, [snippet]) 14 | 15 | return ( 16 |
17 | {snippet?.title} 18 |
19 | ) 20 | } 21 | 22 | const Left = observer(() => { 23 | const snippets = materials.getComponentSnippets() 24 | 25 | return ( 26 |
27 |
28 |

组件库

29 |
30 |
31 |
32 | {snippets.map(snippet => ( 33 | 34 | ))} 35 |
36 |
37 |
38 | ) 39 | }) 40 | 41 | export default Left 42 | -------------------------------------------------------------------------------- /examples/dashboard/src/components/Right.tsx: -------------------------------------------------------------------------------- 1 | import { project } from '@easy-editor/core' 2 | import { SettingRenderer } from '@easy-editor/react-renderer' 3 | import { observer } from 'mobx-react' 4 | 5 | const Right = observer(() => { 6 | return ( 7 |
8 |
9 |

Property Setting

10 |
11 | 12 |
13 | ) 14 | }) 15 | 16 | export default Right 17 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/button/component.tsx: -------------------------------------------------------------------------------- 1 | import { type Ref, forwardRef } from 'react' 2 | 3 | interface ButtonProps { 4 | type?: 'primary' | 'default' 5 | text?: string 6 | onClick?: () => void 7 | } 8 | 9 | const Button = forwardRef((props: ButtonProps, ref: Ref) => { 10 | return ( 11 | 14 | ) 15 | }) 16 | 17 | export default Button 18 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/button/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import Button from './component' 3 | 4 | const configure: Configure = { 5 | props: [ 6 | { 7 | type: 'group', 8 | title: '功能', 9 | setter: 'GroupSetter', 10 | items: [ 11 | { 12 | type: 'field', 13 | name: 'text', 14 | title: '内容', 15 | setter: 'StringSetter', 16 | }, 17 | ], 18 | }, 19 | ], 20 | component: {}, 21 | supports: {}, 22 | advanced: { 23 | view: Button, 24 | }, 25 | } 26 | 27 | export default configure 28 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/button/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import configure from './configure' 3 | import snippets from './snippets' 4 | 5 | const meta: ComponentMetadata = { 6 | componentName: 'Button', 7 | title: '按钮', 8 | category: '通用', 9 | snippets, 10 | configure, 11 | } 12 | 13 | export default meta 14 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/button/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: '主按钮', 6 | // screenshot: require('./__screenshots__/button-1.png'), 7 | schema: { 8 | componentName: 'Button', 9 | props: { 10 | type: 'primary', 11 | text: '主按钮', 12 | }, 13 | // TODO: 这样写法是否奇怪 14 | $dashboard: { 15 | rect: { 16 | width: 100, 17 | height: 100, 18 | }, 19 | }, 20 | }, 21 | }, 22 | { 23 | title: '次按钮', 24 | // screenshot: require('./__screenshots__/button-1.png'), 25 | schema: { 26 | componentName: 'Button', 27 | props: { 28 | type: 'default', 29 | text: '次按钮', 30 | }, 31 | }, 32 | }, 33 | ] 34 | 35 | export default snippets 36 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/component.ts: -------------------------------------------------------------------------------- 1 | import Button from './button/component' 2 | import Input from './input/component' 3 | import RootContainer from './rootContainer/component' 4 | 5 | export { Button, Input, RootContainer } 6 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/group/component.tsx: -------------------------------------------------------------------------------- 1 | import { type PropsWithChildren, type Ref, forwardRef } from 'react' 2 | 3 | interface GroupProps extends PropsWithChildren {} 4 | 5 | const Group = forwardRef((props: GroupProps, ref: Ref) => { 6 | return ( 7 |
8 | {props?.children} 9 |
10 | ) 11 | }) 12 | 13 | export default Group 14 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/group/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import Group from './component' 3 | 4 | const configure: Configure = { 5 | props: [ 6 | // { 7 | // name: 'test', 8 | // title: '分组', 9 | // type: 'group', 10 | // items: [], 11 | // }, 12 | ], 13 | component: {}, 14 | supports: {}, 15 | advanced: { 16 | view: Group, 17 | }, 18 | } 19 | 20 | export default configure 21 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/group/index.ts: -------------------------------------------------------------------------------- 1 | import GroupComponent from './component' 2 | import GroupComponentMeta from './meta' 3 | 4 | export { GroupComponent, GroupComponentMeta } 5 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/group/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import configure from './configure' 3 | 4 | const meta: ComponentMetadata = { 5 | componentName: 'Group', 6 | title: '分组', 7 | category: '内置', 8 | configure, 9 | } 10 | 11 | export default meta 12 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/input/component.tsx: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'react' 2 | 3 | interface InputProps { 4 | ref: Ref 5 | value?: string 6 | placeholder?: string 7 | } 8 | 9 | const Input = (props: InputProps) => { 10 | return 11 | } 12 | 13 | export default Input 14 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/input/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import Input from './component' 3 | 4 | const configure: Configure = { 5 | props: [ 6 | { 7 | title: '功能', 8 | display: 'block', 9 | type: 'group', 10 | items: [ 11 | { 12 | name: 'value', 13 | title: '当前值', 14 | defaultValue: '', 15 | setter: 'StringSetter', 16 | }, 17 | { 18 | name: 'placeholder', 19 | title: '占位提示', 20 | defaultValue: '请输入', 21 | setter: 'StringSetter', 22 | }, 23 | ], 24 | }, 25 | ], 26 | component: {}, 27 | supports: {}, 28 | advanced: { 29 | view: Input, 30 | }, 31 | } 32 | 33 | export default configure 34 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/input/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import configure from './configure' 3 | import snippets from './snippets' 4 | 5 | const meta: ComponentMetadata = { 6 | componentName: 'Input', 7 | title: '输入框', 8 | category: '表单', 9 | snippets, 10 | configure, 11 | } 12 | 13 | export default meta 14 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/input/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: '输入框', 6 | // screenshot: require('./__screenshots__/button-1.png'), 7 | schema: { 8 | componentName: 'Input', 9 | props: { 10 | placeholder: '请输入', 11 | }, 12 | }, 13 | }, 14 | ] 15 | 16 | export default snippets 17 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/meta.ts: -------------------------------------------------------------------------------- 1 | import Button from './button/meta' 2 | import Group from './group/meta' 3 | import Input from './input/meta' 4 | import RootContainer from './rootContainer/meta' 5 | 6 | export { Button, Group, Input, RootContainer } 7 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/rootContainer/component.tsx: -------------------------------------------------------------------------------- 1 | import { type Ref, forwardRef } from 'react' 2 | 3 | interface RootContainerProps { 4 | backgroundColor?: string 5 | children?: React.ReactNode 6 | } 7 | 8 | const RootContainer = forwardRef((props: RootContainerProps, ref: Ref) => { 9 | return ( 10 |
11 | {props?.children} 12 |
13 | ) 14 | }) 15 | 16 | export default RootContainer 17 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/rootContainer/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import RootContainer from './component' 3 | 4 | const configure: Configure = { 5 | props: [ 6 | { 7 | type: 'group', 8 | title: '功能', 9 | setter: 'GroupSetter', 10 | items: [ 11 | { 12 | name: 'backgroundColor', 13 | title: '背景颜色', 14 | setter: 'StringSetter', 15 | }, 16 | ], 17 | }, 18 | ], 19 | component: {}, 20 | supports: {}, 21 | advanced: { 22 | view: RootContainer, 23 | }, 24 | } 25 | 26 | export default configure 27 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/materials/rootContainer/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import configure from './configure' 3 | 4 | const meta: ComponentMetadata = { 5 | componentName: 'RootContainer', 6 | title: '根容器', 7 | category: '通用', 8 | configure, 9 | } 10 | 11 | export default meta 12 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import ExamplePlugin from './plugin-example' 2 | 3 | export default [ExamplePlugin] 4 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/plugins/plugin-example/index.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from '@easy-editor/core' 2 | 3 | const ExamplePlugin: Plugin = ctx => { 4 | return { 5 | name: 'ExamplePlugin', 6 | deps: [], 7 | init() { 8 | ctx.logger.log('打个日志', ctx) 9 | 10 | ctx.project.set('example', { 11 | aaa: 'bbb', 12 | }) 13 | }, 14 | } 15 | } 16 | 17 | ExamplePlugin.pluginName = 'ExamplePlugin' 18 | 19 | export default ExamplePlugin 20 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/setters/group-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SetterProps } from '@easy-editor/core' 2 | import type { PropsWithChildren } from 'react' 3 | 4 | interface GroupSetterProps extends SetterProps, PropsWithChildren {} 5 | 6 | const GroupSetter = (props: GroupSetterProps) => { 7 | const { children } = props 8 | 9 | return
{children}
10 | } 11 | 12 | export default GroupSetter 13 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/setters/index.ts: -------------------------------------------------------------------------------- 1 | import GroupSetter from './group-setter' 2 | import StringSetter from './string-setter' 3 | 4 | export { GroupSetter, StringSetter } 5 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/setters/string-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SetterProps } from '@easy-editor/core' 2 | 3 | interface StringSetterProps extends SetterProps { 4 | placeholder: string 5 | } 6 | 7 | const StringSetter = (props: StringSetterProps) => { 8 | const { value, placeholder, onChange } = props 9 | 10 | return ( 11 | onChange(e.target.value)} 15 | style={{ width: '100%' }} 16 | /> 17 | ) 18 | } 19 | 20 | export default StringSetter 21 | -------------------------------------------------------------------------------- /examples/dashboard/src/editor/utils.ts: -------------------------------------------------------------------------------- 1 | export const formatMapFromESModule = (map: Record) => { 2 | return Object.keys(map).reduce>((result, key) => { 3 | result[key] = map[key] as T 4 | return result 5 | }, {}) 6 | } 7 | -------------------------------------------------------------------------------- /examples/dashboard/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | html, 8 | body, 9 | #root { 10 | width: 100%; 11 | height: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /examples/dashboard/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from 'react-dom/client' 2 | import { scan } from 'react-scan' 3 | import 'virtual:uno.css' 4 | import App from './App' 5 | import './editor' 6 | import './index.css' 7 | 8 | if (typeof window !== 'undefined') { 9 | scan({ 10 | enabled: true, 11 | log: false, // logs render info to console (default: false) 12 | }) 13 | } 14 | 15 | createRoot(document.getElementById('root')!).render() 16 | -------------------------------------------------------------------------------- /examples/dashboard/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/dashboard/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /examples/dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["src/*"], 11 | }, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/dashboard/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /examples/dashboard/uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, presetUno } from 'unocss' 2 | 3 | export default defineConfig({ 4 | content: { 5 | filesystem: ['./src/**/*.{html,js,ts,jsx,tsx}'], 6 | }, 7 | presets: [presetUno()], 8 | }) 9 | -------------------------------------------------------------------------------- /examples/dashboard/vite.config.ts: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import react from '@vitejs/plugin-react' 3 | import UnoCSS from 'unocss/vite' 4 | import { defineConfig } from 'vite' 5 | import ReactComponentName from 'react-scan/react-component-name/vite' 6 | 7 | // https://vite.dev/config/ 8 | export default defineConfig({ 9 | plugins: [ 10 | // TODO: 暂时需要 babel 插件,因为需要联调 @easy-editor/core 的代码,会用到装饰器内容 11 | babel({ 12 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 13 | exclude: 'node_modules/**', 14 | babelrc: false, 15 | babelHelpers: 'bundled', 16 | presets: ['@babel/preset-typescript'], 17 | plugins: [ 18 | [ 19 | '@babel/plugin-proposal-decorators', 20 | { 21 | version: '2023-11', 22 | }, 23 | ], 24 | ], 25 | }), 26 | react(), 27 | UnoCSS(), 28 | ReactComponentName({}), 29 | ], 30 | resolve: { 31 | alias: { 32 | '@': '/src', 33 | }, 34 | }, 35 | }) 36 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/core 2 | 3 | Core specification and type package for EasyEditor, a cross-framework low-code editor with a scalable architecture. 4 | 5 | ## Package Structure 6 | 7 | This package provides two main entry points: 8 | 9 | ### 1. Main Entry Point (`@easy-editor/core`) 10 | 11 | The main entry point provides specifications, interfaces, and types: 12 | - Core interfaces and abstract classes 13 | - Type definitions for all components and modules 14 | - Base structures for plugins, documents, and components 15 | - Standard events and constants 16 | - Utility functions and helpers 17 | 18 | ### 2. Engine Entry Point (`@easy-editor/core/engine`) 19 | 20 | The engine entry point provides the concrete implementation that users should import and use directly: 21 | - Ready-to-use editor instance 22 | - Fully configured plugin system 23 | - Initialized core modules 24 | - Export of common services (designer, project, etc.) 25 | - Lifecycle management (init, destroy) 26 | 27 | ## Features 28 | 29 | - **Framework Agnostic**: Core is designed to work with any frontend framework 30 | - **Plugin Architecture**: Extensible system for adding features and capabilities 31 | - **Visual Design**: Complete designer implementation with drag-and-drop, alignment, and undo/redo 32 | - **Component Model**: Structured component definition and management system 33 | - **Event System**: Powerful event bus for communication between modules 34 | - **Configuration System**: Centralized config management with plugin integration 35 | - **Project Management**: Handles documents, history, serialization, and more 36 | - **Type Safety**: Comprehensive TypeScript definitions for all components 37 | -------------------------------------------------------------------------------- /packages/core/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import nodeResolve from '@rollup/plugin-node-resolve' 3 | import replace from '@rollup/plugin-replace' 4 | import { createRequire } from 'node:module' 5 | import cleanup from 'rollup-plugin-cleanup' 6 | 7 | const require = createRequire(import.meta.url) 8 | const pkg = require('./package.json') 9 | 10 | const plugins = [ 11 | replace({ 12 | _EASY_EDITOR_VERSION_: pkg.version, 13 | preventAssignment: true, 14 | delimiters: ['', ''], 15 | }), 16 | nodeResolve({ 17 | extensions: ['.js', '.ts'], 18 | browser: true, 19 | }), 20 | babel({ 21 | extensions: ['.js', '.ts'], 22 | exclude: 'node_modules/**', 23 | babelrc: false, 24 | babelHelpers: 'bundled', 25 | presets: ['@babel/preset-typescript'], 26 | plugins: [ 27 | [ 28 | '@babel/plugin-proposal-decorators', 29 | { 30 | version: '2023-11', 31 | }, 32 | ], 33 | ], 34 | }), 35 | cleanup({ 36 | comments: ['some', /PURE/], 37 | extensions: ['.js', '.ts'], 38 | }), 39 | ] 40 | 41 | export default [ 42 | { 43 | input: 'src/index.ts', 44 | output: [ 45 | { 46 | file: 'dist/index.js', 47 | format: 'es', 48 | }, 49 | { 50 | file: 'dist/index.cjs', 51 | format: 'cjs', 52 | }, 53 | ], 54 | plugins, 55 | }, 56 | ] 57 | -------------------------------------------------------------------------------- /packages/core/src/designer/active-tracker.ts: -------------------------------------------------------------------------------- 1 | import { observable } from 'mobx' 2 | import { type Node, isNode } from '../document' 3 | import type { ComponentInstance } from '../types' 4 | import { createEventBus } from '../utils' 5 | import type { LocationDetail } from './location' 6 | 7 | export interface ActiveTarget { 8 | node: Node 9 | detail?: LocationDetail 10 | instance?: ComponentInstance 11 | } 12 | 13 | export class ActiveTracker { 14 | @observable.ref private accessor _target: ActiveTarget | Node 15 | 16 | private emitter = createEventBus('ActiveTracker') 17 | 18 | track(originalTarget: ActiveTarget | Node) { 19 | let target = originalTarget 20 | if (isNode(originalTarget)) { 21 | target = { node: originalTarget as Node } 22 | } 23 | this._target = target 24 | this.emitter.emit('change', target) 25 | } 26 | 27 | get currentNode() { 28 | return (this._target as ActiveTarget)?.node 29 | } 30 | 31 | get detail() { 32 | return (this._target as ActiveTarget)?.detail 33 | } 34 | 35 | get instance() { 36 | return (this._target as ActiveTarget)?.instance 37 | } 38 | 39 | onChange(fn: (target: ActiveTarget) => void): () => void { 40 | this.emitter.on('change', fn) 41 | return () => { 42 | this.emitter.off('change', fn) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/core/src/designer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clipboard' 2 | export * from './designer' 3 | export * from './detecting' 4 | export * from './dragon' 5 | export * from './location' 6 | export * from './offset-observer' 7 | export * from './selection' 8 | export * from './sensor' 9 | export * from './setting' 10 | -------------------------------------------------------------------------------- /packages/core/src/designer/sensor.ts: -------------------------------------------------------------------------------- 1 | import type { Node } from '../document' 2 | import type { ComponentInstance } from '../types' 3 | import type { NodeInstance } from './dragon' 4 | import type { DropLocation, LocateEvent } from './location' 5 | 6 | export interface Sensor { 7 | /** 8 | * whether the sensor is available 9 | */ 10 | readonly sensorAvailable: boolean 11 | 12 | /** 13 | * fix location event, add canvasX,canvasY 14 | */ 15 | fixEvent(e: LocateEvent): LocateEvent 16 | 17 | /** 18 | * locate and activate 19 | */ 20 | locate(e: LocateEvent): DropLocation | undefined | null 21 | 22 | /** 23 | * whether enter the sensitive area 24 | */ 25 | isEnter(e: LocateEvent): boolean 26 | 27 | /** 28 | * deactivate 29 | */ 30 | deactiveSensor(): void 31 | 32 | /** 33 | * get node instance from element 34 | */ 35 | getNodeInstanceFromElement?: (e: Element | null) => NodeInstance | null 36 | } 37 | -------------------------------------------------------------------------------- /packages/core/src/designer/setting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setting-entry' 2 | export * from './setting-field' 3 | export * from './setting-manager' 4 | export * from './setting-prop-entry' 5 | export * from './setting-top-entry' 6 | -------------------------------------------------------------------------------- /packages/core/src/designer/setting/setting-entry.ts: -------------------------------------------------------------------------------- 1 | import type { Editor, Node, Setters } from '../..' 2 | import type { Designer } from '../designer' 3 | import type { SettingField } from './setting-field' 4 | 5 | export interface SettingEntry { 6 | readonly designer: Designer | undefined 7 | 8 | readonly id: string 9 | 10 | /** 11 | * 同样类型的节点 12 | */ 13 | readonly isSameComponent: boolean 14 | 15 | /** 16 | * 一个 17 | */ 18 | readonly isSingle: boolean 19 | 20 | /** 21 | * 多个 22 | */ 23 | readonly isMultiple: boolean 24 | 25 | /** 26 | * 编辑器引用 27 | */ 28 | readonly editor: Editor 29 | 30 | readonly setters: Setters 31 | 32 | /** 33 | * 取得子项 34 | */ 35 | get: (propName: string | number) => SettingField | null 36 | 37 | readonly nodes: Node[] 38 | 39 | // @todo 补充 node 定义 40 | /** 41 | * 获取 node 中的第一项 42 | */ 43 | getNode: () => any 44 | } 45 | 46 | export interface SettingTarget { 47 | // 所设置的节点集,至少一个 48 | readonly nodes: Node[] 49 | 50 | // 所有属性值数据 51 | readonly props: object 52 | 53 | // 设置属性值 54 | setPropValue(propName: string, value: any): void 55 | 56 | // 获取属性值 57 | getPropValue(propName: string): any 58 | 59 | // 设置多个属性值,替换原有值 60 | setProps(data: object): void 61 | 62 | // 设置多个属性值,和原有值合并 63 | mergeProps(data: object): void 64 | 65 | // 绑定属性值发生变化时 66 | onPropsChange(fn: () => void): () => void 67 | } 68 | -------------------------------------------------------------------------------- /packages/core/src/document/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document' 2 | export * from './history' 3 | export * from './node/node' 4 | export * from './node/node-children' 5 | export * from './prop/prop' 6 | export * from './prop/props' 7 | -------------------------------------------------------------------------------- /packages/core/src/engine/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * TODO: 从 core 中抽离出来 3 | */ 4 | 5 | import { config } from '..' 6 | 7 | export * from './engine' 8 | 9 | export const version = '_EASY_EDITOR_VERSION_' 10 | config.set('VERSION', version) 11 | 12 | console.log( 13 | `%c EasyEditor %c v${version} `, 14 | 'padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #5584ff; font-weight: bold;', 15 | 'padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;', 16 | ) 17 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | // core 2 | export * from './config' 3 | export * from './designer' 4 | export * from './document' 5 | export * from './materials' 6 | export * from './plugin' 7 | export * from './project' 8 | export * from './setters' 9 | export * from './simulator' 10 | export * from './types' 11 | export * from './utils' 12 | 13 | // engine 14 | export * from './engine' 15 | -------------------------------------------------------------------------------- /packages/core/src/materials/index.ts: -------------------------------------------------------------------------------- 1 | export * from './component-meta' 2 | export * from './materials' 3 | -------------------------------------------------------------------------------- /packages/core/src/plugin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugin-context' 2 | export * from './plugin-extend' 3 | export * from './plugin-extend-mobx' 4 | export * from './plugin-runtime' 5 | export * from './plugins' 6 | -------------------------------------------------------------------------------- /packages/core/src/plugin/plugin-context.ts: -------------------------------------------------------------------------------- 1 | import type { Event, Materials, Project, Setters } from '..' 2 | import type { Config } from '../config' 3 | import { type EventBus, type Hotkey, type Logger, createEventBus } from '../utils' 4 | import type { PluginContextApiAssembler, PluginMeta, Plugins } from './plugins' 5 | 6 | export interface PluginContextOptions { 7 | pluginName: string 8 | meta?: PluginMeta 9 | } 10 | 11 | export class PluginContext { 12 | project: Project 13 | plugins: Plugins 14 | setters: Setters 15 | materials: Materials 16 | event: Event 17 | pluginEvent: EventBus 18 | hotkey: Hotkey 19 | config: Config 20 | logger: Logger 21 | 22 | constructor(options: PluginContextOptions, contextApiAssembler: PluginContextApiAssembler) { 23 | const { pluginName = 'anonymous', meta = {} } = options 24 | contextApiAssembler.assembleApis(this, pluginName, meta) 25 | this.pluginEvent = createEventBus(pluginName) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/core/src/project/index.ts: -------------------------------------------------------------------------------- 1 | export * from './project' 2 | -------------------------------------------------------------------------------- /packages/core/src/setters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setters' 2 | -------------------------------------------------------------------------------- /packages/core/src/simulator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './simulator' 2 | export * from './simulator-renderer' 3 | export * from './viewport' 4 | -------------------------------------------------------------------------------- /packages/core/src/simulator/simulator-renderer.ts: -------------------------------------------------------------------------------- 1 | import type { Component, ComponentInstance, Node } from '..' 2 | import type { NodeInstance } from '../designer' 3 | 4 | export interface SimulatorRenderer { 5 | readonly isSimulatorRenderer: true 6 | 7 | /** 8 | * 是否自动重绘节点 9 | */ 10 | autoRepaintNode?: boolean 11 | 12 | /** 13 | * 组件列表 14 | */ 15 | components: Record 16 | 17 | /** 18 | * 重新渲染 19 | */ 20 | rerender: () => void 21 | 22 | /** 23 | * 获取组件 24 | */ 25 | getComponent(componentName: string): Component 26 | 27 | /** 28 | * 获取最近的节点实例 29 | */ 30 | getClosestNodeInstance(from: ComponentInstance, nodeId?: string): NodeInstance | null 31 | 32 | /** 33 | * 获取组件的 DOM 节点 34 | */ 35 | findDOMNodes(instance: ComponentInstance): Array | null 36 | 37 | /** 38 | * 获取元素的 Rect 信息 39 | */ 40 | getClientRects(element: Element | Text): DOMRect[] 41 | 42 | /** 43 | * 关闭自动重绘节点 44 | */ 45 | stopAutoRepaintNode(): void 46 | 47 | /** 48 | * 开启自动重绘节点 49 | */ 50 | enableAutoRepaintNode(): void 51 | 52 | /** 53 | * 渲染器启动 54 | */ 55 | run(): void 56 | 57 | // TODO 58 | // load(asset: Asset): Promise; 59 | // loadAsyncLibrary(asyncMap: { [index: string]: any }): void 60 | } 61 | 62 | export const isSimulatorRenderer = (obj: any): obj is SimulatorRenderer => { 63 | return obj && obj.isSimulatorRenderer 64 | } 65 | -------------------------------------------------------------------------------- /packages/core/src/types/common.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * transform stage, use for export 3 | */ 4 | export enum TRANSFORM_STAGE { 5 | RENDER = 'render', 6 | SERIALIZE = 'serialize', 7 | SAVE = 'save', 8 | CLONE = 'clone', 9 | INIT = 'init', 10 | UPGRADE = 'upgrade', 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/types/component.ts: -------------------------------------------------------------------------------- 1 | // export type ComponentInstance = Element 2 | export type ComponentInstance = any 3 | 4 | // export type ComponentType = React.ComponentType 5 | export type ComponentType = any 6 | 7 | /** 8 | * component type 9 | */ 10 | export type Component = ComponentType | object 11 | 12 | export interface LowCodeComponent { 13 | /** 14 | * 研发模式 15 | */ 16 | devMode: 'lowCode' 17 | /** 18 | * 组件名称 19 | */ 20 | componentName: string 21 | } 22 | 23 | // export type ProCodeComponent = TypeNpmInfo; 24 | export interface ProCodeComponent { 25 | /** 26 | * 研发模式 27 | */ 28 | devMode: 'proCode' 29 | /** 30 | * 组件名称 31 | */ 32 | componentName: string 33 | } 34 | 35 | export type ComponentMap = ProCodeComponent | LowCodeComponent 36 | 37 | export type ComponentsMap = ComponentMap[] 38 | -------------------------------------------------------------------------------- /packages/core/src/types/data-source.ts: -------------------------------------------------------------------------------- 1 | import type { JSExpression, JSONObject } from '../document' 2 | 3 | export interface DataSourceItem { 4 | id: string 5 | isInit?: boolean | JSExpression 6 | type?: string 7 | options?: { 8 | uri: string | JSExpression 9 | params?: JSONObject | JSExpression 10 | method?: string | JSExpression 11 | shouldFetch?: string 12 | willFetch?: string 13 | fit?: string 14 | didFetch?: string 15 | } 16 | dataHandler?: JSExpression 17 | } 18 | 19 | export interface DataSource { 20 | list?: DataSourceItem[] 21 | dataHandler?: JSExpression 22 | } 23 | 24 | export interface DataSourceEngine { 25 | createDataSourceEngine: ( 26 | dataSource: DataSource, 27 | engine: any, 28 | ) => { 29 | dataSourceMap: Record 30 | reloadDataSource: () => Promise 31 | } 32 | 33 | [key: string]: any 34 | } 35 | -------------------------------------------------------------------------------- /packages/core/src/types/event.ts: -------------------------------------------------------------------------------- 1 | // import { DESIGNER_EVENT, DETECTING_EVENT, DRAGON_EVENT, SELECTION_EVENT } from '../designer' 2 | // import { DOCUMENT_EVENT, NODE_CHILDREN_EVENT, NODE_EVENT } from '../document' 3 | // import { EDITOR_EVENT } from '../editor' 4 | // import { PROJECT_EVENT } from '../project' 5 | 6 | export const GLOBAL_EVENT = { 7 | // EDITOR_EVENT, 8 | // DESIGNER_EVENT, 9 | // DRAGON_EVENT, 10 | // DETECTING_EVENT, 11 | // SELECTION_EVENT, 12 | // PROJECT_EVENT, 13 | // DOCUMENT_EVENT, 14 | // NODE_EVENT, 15 | // NODE_CHILDREN_EVENT, 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common' 2 | export * from './component' 3 | export * from './data-source' 4 | export * from './editor' 5 | export * from './event' 6 | export * from './meta' 7 | export * from './schema' 8 | export * from './setter' 9 | -------------------------------------------------------------------------------- /packages/core/src/types/setter.ts: -------------------------------------------------------------------------------- 1 | import type { SettingField, SettingPropEntry } from '../designer' 2 | import type { Component } from './component' 3 | 4 | // export type SetterType = SetterConfig | SetterConfig[] | string 5 | export type SetterType = SetterConfig | string 6 | 7 | export type DynamicSetterProps = (target: SettingField) => Record 8 | 9 | export interface SetterConfig { 10 | /** 11 | * the name of the setter 12 | */ 13 | componentName: string 14 | 15 | /** 16 | * the props pass to Setter Component 17 | */ 18 | props?: Record | DynamicSetterProps 19 | 20 | /** 21 | * is required 22 | */ 23 | isRequired?: boolean 24 | 25 | /** 26 | * Setter initial value 27 | */ 28 | // initialValue?: any | ((target: SettingField) => any) 29 | 30 | /** 31 | * Setter default value 32 | */ 33 | defaultValue?: any 34 | 35 | /** 36 | * judge which one to be selected 37 | */ 38 | // condition?: (target: SettingField) => boolean 39 | } 40 | 41 | export type DynamicSetter = (target: SettingPropEntry) => string | SetterConfig | Component 42 | -------------------------------------------------------------------------------- /packages/core/src/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { isPlainObject } from '..' 2 | 3 | export const cloneDeep = (src: any): any => { 4 | const type = typeof src 5 | 6 | let data: any 7 | if (src === null || src === undefined) { 8 | data = src 9 | } else if (Array.isArray(src)) { 10 | data = src.map(item => cloneDeep(item)) 11 | } else if (type === 'object' && isPlainObject(src)) { 12 | data = {} 13 | for (const key in src) { 14 | if (Object.prototype.hasOwnProperty.call(src, key)) { 15 | data[key] = cloneDeep(src[key]) 16 | } 17 | } 18 | } else { 19 | data = src 20 | } 21 | 22 | return data 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common' 2 | export * from './event' 3 | export * from './event-bus' 4 | export * from './hotkey' 5 | export * from './is' 6 | export * from './logger' 7 | export * from './unique-id' 8 | -------------------------------------------------------------------------------- /packages/core/src/utils/unique-id.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid' 2 | 3 | /** 4 | * generate a unique id 5 | * @param prefix a identifier prefix 6 | */ 7 | export const uniqueId = (prefix = '') => { 8 | return `${prefix}-${nanoid(12)}` 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist" 6 | }, 7 | "include": ["./src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/create-easy-editor/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/create 2 | 3 | ## 0.0.2 4 | 5 | ### Patch Changes 6 | 7 | - c9d74ac: fix: add shebang 8 | 9 | ## 0.0.1 10 | 11 | ### Patch Changes 12 | 13 | - 38be299: feat: add create-easy-editor cli 14 | -------------------------------------------------------------------------------- /packages/create-easy-editor/README.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/create 2 | -------------------------------------------------------------------------------- /packages/create-easy-editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@easy-editor/create", 3 | "version": "0.0.2", 4 | "description": "Create a new EasyEditor project", 5 | "type": "module", 6 | "main": "./src/index.ts", 7 | "exports": "./src/index.ts", 8 | "files": [ 9 | "dist", 10 | "template", 11 | "README.md" 12 | ], 13 | "bin": { 14 | "@easy-editor/create": "./dist/index.js" 15 | }, 16 | "publishConfig": { 17 | "access": "public", 18 | "main": "dist/index.js", 19 | "module": "dist/index.js", 20 | "exports": "./dist/index.js" 21 | }, 22 | "homepage": "https://github.com/Easy-Editor/EasyEditor", 23 | "license": "MIT", 24 | "author": "JinSo ", 25 | "keywords": [ 26 | "@easy-editor", 27 | "easyeditor", 28 | "low-code", 29 | "cli" 30 | ], 31 | "scripts": { 32 | "dev": "deno run --watch ./src/index.ts", 33 | "format": "biome format --write .", 34 | "lint": "biome check .", 35 | "build": "npm-run-all -nl build:*", 36 | "build:clean": "rimraf dist/", 37 | "build:js": "rollup -c" 38 | }, 39 | "devDependencies": { 40 | "@clack/prompts": "^0.11.0", 41 | "mri": "^1.2.0", 42 | "picocolors": "^1.1.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/create-easy-editor/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import resolve from '@rollup/plugin-node-resolve' 4 | 5 | const plugins = [ 6 | resolve({ 7 | extensions: ['.js', '.ts'], 8 | }), 9 | commonjs(), 10 | babel({ 11 | extensions: ['.js', '.ts'], 12 | exclude: 'node_modules/**', 13 | babelrc: false, 14 | babelHelpers: 'bundled', 15 | presets: ['@babel/preset-typescript'], 16 | }), 17 | ] 18 | 19 | export default [ 20 | { 21 | input: 'src/index.ts', 22 | output: [ 23 | { 24 | file: 'dist/index.js', 25 | format: 'es', 26 | banner: '#!/usr/bin/env node', 27 | }, 28 | { 29 | file: 'dist/index.cjs', 30 | format: 'cjs', 31 | banner: '#!/usr/bin/env node', 32 | }, 33 | ], 34 | plugins, 35 | }, 36 | ] 37 | -------------------------------------------------------------------------------- /packages/create-easy-editor/src/const.ts: -------------------------------------------------------------------------------- 1 | import colors from 'picocolors' 2 | 3 | const { blue, cyan, gray } = colors 4 | 5 | export const renameFiles: Record = { 6 | _gitignore: '.gitignore', 7 | } 8 | 9 | export const defaultTargetDir = 'easy-editor' 10 | 11 | export const helpMessage = `\ 12 | Usage: 13 | npm init @easy-editor [OPTION]... [DIRECTORY] 14 | npx @easy-editor/create [OPTION]... [DIRECTORY] 15 | 16 | Create a new Easy Editor project in JavaScript or TypeScript. 17 | With no arguments, start the CLI in interactive mode. 18 | 19 | Options: 20 | -s, --scenarios NAME use a specific scenario 21 | -t, --template NAME use a specific template 22 | -h, --help display this help message 23 | --overwrite overwrite target directory if it exists 24 | 25 | Available templates: 26 | ${cyan('react-dashboard')}` 27 | 28 | type ColorFunc = (str: string | number) => string 29 | 30 | type Variant = { 31 | name: string 32 | display: string 33 | color: ColorFunc 34 | } 35 | 36 | export const FRAMEWORKS: Variant[] = [ 37 | { 38 | name: 'react', 39 | display: 'React', 40 | color: blue, 41 | }, 42 | { 43 | name: 'vue', 44 | display: 'Vue (Developing)', 45 | color: gray, 46 | }, 47 | ] 48 | 49 | export const SCENARIOS: Variant[] = [ 50 | { 51 | name: 'dashboard', 52 | display: 'Dashboard', 53 | color: blue, 54 | }, 55 | { 56 | name: 'form', 57 | display: 'Form (Developing)', 58 | color: gray, 59 | }, 60 | ] 61 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/README.md: -------------------------------------------------------------------------------- 1 | # React + Dashboard 2 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/styles/global.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } 22 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | easy-editor-react-dashboard 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react' 2 | import { BrowserRouter, Navigate, Route, Routes } from 'react-router' 3 | import { ThemeProvider } from './components/theme-provider' 4 | 5 | const Preview = lazy(() => import('./pages/preview')) 6 | const Editor = lazy(() => import('./pages/editor')) 7 | 8 | function App() { 9 | return ( 10 | 11 | 12 | 13 | } /> 14 | } /> 15 | } /> 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | export default App 23 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Easy-Editor/EasyEditor/e8bedc68e237a1710ec30cb9e3ec6a34940c7ed1/packages/create-easy-editor/template/dashboard/react/src/assets/banner.png -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/theme-toggle.tsx: -------------------------------------------------------------------------------- 1 | import { Moon, Sun } from 'lucide-react' 2 | 3 | import { useTheme } from '@/components/theme-provider' 4 | import { Button } from '@/components/ui/button' 5 | import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' 6 | 7 | export const ThemeToggle = () => { 8 | const { setTheme } = useTheme() 9 | 10 | return ( 11 | 12 | 13 | 18 | 19 | 20 | setTheme('light')}>Light 21 | setTheme('dark')}>Dark 22 | setTheme('system')}>System 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import type * as React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | function Card({ className, ...props }: React.ComponentProps<'div'>) { 6 | return ( 7 |
12 | ) 13 | } 14 | 15 | function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { 16 | return
17 | } 18 | 19 | function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { 20 | return ( 21 |
22 | ) 23 | } 24 | 25 | function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { 26 | return
27 | } 28 | 29 | function CardContent({ className, ...props }: React.ComponentProps<'div'>) { 30 | return
31 | } 32 | 33 | function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { 34 | return
35 | } 36 | 37 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 38 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible' 2 | 3 | function Collapsible({ ...props }: React.ComponentProps) { 4 | return 5 | } 6 | 7 | function CollapsibleTrigger({ ...props }: React.ComponentProps) { 8 | return 9 | } 10 | 11 | function CollapsibleContent({ ...props }: React.ComponentProps) { 12 | return 13 | } 14 | 15 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 16 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import type * as React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | function Input({ className, type, ...props }: React.ComponentProps<'input'>) { 6 | return ( 7 | 16 | ) 17 | } 18 | 19 | export { Input } 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as LabelPrimitive from '@radix-ui/react-label' 2 | import type * as React from 'react' 3 | 4 | import { cn } from '@/lib/utils' 5 | 6 | function Label({ className, ...props }: React.ComponentProps) { 7 | return ( 8 | 16 | ) 17 | } 18 | 19 | export { Label } 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/progress.tsx: -------------------------------------------------------------------------------- 1 | import * as ProgressPrimitive from '@radix-ui/react-progress' 2 | import type * as React from 'react' 3 | 4 | import { cn } from '@/lib/utils' 5 | 6 | function Progress({ className, value, ...props }: React.ComponentProps) { 7 | return ( 8 | 13 | 18 | 19 | ) 20 | } 21 | 22 | export { Progress } 23 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/radio-group.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import * as RadioGroupPrimitive from '@radix-ui/react-radio-group' 3 | import { CircleIcon } from 'lucide-react' 4 | 5 | import { cn } from '@/lib/utils' 6 | 7 | function RadioGroup({ className, ...props }: React.ComponentProps) { 8 | return 9 | } 10 | 11 | function RadioGroupItem({ className, ...props }: React.ComponentProps) { 12 | return ( 13 | 21 | 25 | 26 | 27 | 28 | ) 29 | } 30 | 31 | export { RadioGroup, RadioGroupItem } 32 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import * as SeparatorPrimitive from '@radix-ui/react-separator' 3 | 4 | import { cn } from '@/lib/utils' 5 | 6 | function Separator({ 7 | className, 8 | orientation = 'horizontal', 9 | decorative = true, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 23 | ) 24 | } 25 | 26 | export { Separator } 27 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/sidebar-extra.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | import React from 'react' 3 | 4 | const SidebarMenuExtra = React.forwardRef>( 5 | ({ className, ...props }, ref) => ( 6 |
12 | ), 13 | ) 14 | SidebarMenuExtra.displayName = 'SidebarMenuExtra' 15 | 16 | const SidebarMenuExtraItem = React.forwardRef>( 17 | ({ className, ...props }, ref) => ( 18 |
svg]:size-4', 26 | className, 27 | )} 28 | {...props} 29 | /> 30 | ), 31 | ) 32 | SidebarMenuExtraItem.displayName = 'SidebarMenuExtraItem' 33 | 34 | export { SidebarMenuExtra, SidebarMenuExtraItem } 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) { 4 | return
5 | } 6 | 7 | export { Skeleton } 8 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from 'next-themes' 2 | import { Toaster as Sonner, type ToasterProps } from 'sonner' 3 | 4 | const Toaster = ({ ...props }: ToasterProps) => { 5 | const { theme = 'system' } = useTheme() 6 | 7 | return ( 8 | 22 | ) 23 | } 24 | 25 | export { Toaster } 26 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/components/ui/switch.tsx: -------------------------------------------------------------------------------- 1 | import * as SwitchPrimitive from '@radix-ui/react-switch' 2 | import type * as React from 'react' 3 | 4 | import { cn } from '@/lib/utils' 5 | 6 | function Switch({ className, ...props }: React.ComponentProps) { 7 | return ( 8 | 16 | 22 | 23 | ) 24 | } 25 | 26 | export { Switch } 27 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/const.ts: -------------------------------------------------------------------------------- 1 | import type { RootSchema } from '@easy-editor/core' 2 | 3 | export const defaultRootSchema: RootSchema = { 4 | fileName: 'home', 5 | fileDesc: '首页', 6 | componentName: 'Root', 7 | props: { 8 | backgroundColor: '#232630', 9 | className: 'page test', 10 | }, 11 | isRoot: true, 12 | $dashboard: { 13 | rect: { 14 | x: 0, 15 | y: 0, 16 | // TODO: 根节点需要动态调整 17 | width: 1920, 18 | height: 1080, 19 | }, 20 | }, 21 | children: [ 22 | { 23 | componentName: 'Image', 24 | $dashboard: { 25 | rect: { 26 | x: 600, 27 | y: 480, 28 | width: 740, 29 | height: 120, 30 | }, 31 | }, 32 | }, 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/image/component.tsx: -------------------------------------------------------------------------------- 1 | import Banner from '@/assets/banner.png' 2 | import type { Ref } from 'react' 3 | 4 | interface ImageProps { 5 | ref: Ref 6 | src?: string 7 | } 8 | 9 | const Image = (props: ImageProps) => { 10 | const { ref, src } = props 11 | 12 | return ( 13 |
14 | img e.preventDefault()} /> 15 |
16 | ) 17 | } 18 | 19 | export default Image 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/image/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'Image', 8 | title: 'Image', 9 | group: MaterialGroup.BASIC, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/image/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Image', 6 | screenshot: 'https://img.alicdn.com/imgextra/i3/O1CN01tnhXhk1GUIFhsXwzA_!!6000000000625-55-tps-56-56.svg', 7 | schema: { 8 | componentName: 'Image', 9 | props: {}, 10 | $dashboard: { 11 | rect: { 12 | width: 370, 13 | height: 60, 14 | }, 15 | }, 16 | }, 17 | }, 18 | ] 19 | 20 | export default snippets 21 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/text/component.tsx: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'react' 2 | 3 | interface TextProps { 4 | ref: Ref 5 | text?: string 6 | } 7 | 8 | const Text = (props: TextProps) => { 9 | const { ref, text, ...rest } = props 10 | 11 | return ( 12 |

13 | {text} 14 |

15 | ) 16 | } 17 | 18 | export default Text 19 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/text/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import Text from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: Text, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/text/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'Text', 8 | title: 'Text', 9 | group: MaterialGroup.BASIC, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/basic/text/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Text', 6 | screenshot: 'https://img.alicdn.com/imgextra/i3/O1CN01n5wpxc1bi862KuXFz_!!6000000003498-55-tps-50-50.svg', 7 | schema: { 8 | componentName: 'Text', 9 | props: { 10 | text: 'Text Text Text', 11 | }, 12 | $dashboard: { 13 | rect: { 14 | width: 120, 15 | height: 40, 16 | }, 17 | }, 18 | }, 19 | }, 20 | ] 21 | 22 | export default snippets 23 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/area-chart/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import MAreaChart from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: MAreaChart, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/area-chart/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'AreaChart', 8 | title: 'Area Chart', 9 | group: MaterialGroup.CHART, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/area-chart/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Area Chart', 6 | schema: { 7 | componentName: 'AreaChart', 8 | props: {}, 9 | $dashboard: { 10 | rect: { 11 | width: 400, 12 | height: 240, 13 | }, 14 | }, 15 | }, 16 | }, 17 | ] 18 | 19 | export default snippets 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/bar-chart/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import MBarChart from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: MBarChart, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/bar-chart/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'BarChart', 8 | title: 'Bar Chart', 9 | group: MaterialGroup.CHART, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/bar-chart/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Bar Chart', 6 | schema: { 7 | componentName: 'BarChart', 8 | props: {}, 9 | $dashboard: { 10 | rect: { 11 | width: 400, 12 | height: 240, 13 | }, 14 | }, 15 | }, 16 | }, 17 | ] 18 | 19 | export default snippets 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/line-chart/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import MLineChart from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: MLineChart, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/line-chart/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'LineChart', 8 | title: 'Lien Chart', 9 | group: MaterialGroup.CHART, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/line-chart/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Line Chart', 6 | schema: { 7 | componentName: 'LineChart', 8 | props: {}, 9 | $dashboard: { 10 | rect: { 11 | width: 400, 12 | height: 240, 13 | }, 14 | }, 15 | }, 16 | }, 17 | ] 18 | 19 | export default snippets 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/pie-chart/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import MPieChart from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: MPieChart, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/pie-chart/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'PieChart', 8 | title: 'Pie Chart', 9 | group: MaterialGroup.CHART, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/pie-chart/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Pie Chart', 6 | schema: { 7 | componentName: 'PieChart', 8 | props: {}, 9 | $dashboard: { 10 | rect: { 11 | width: 400, 12 | height: 240, 13 | }, 14 | }, 15 | }, 16 | }, 17 | ] 18 | 19 | export default snippets 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radar-chart/component.tsx: -------------------------------------------------------------------------------- 1 | import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' 2 | import type { Ref } from 'react' 3 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from 'recharts' 4 | 5 | const chartData = [ 6 | { month: 'January', desktop: 186 }, 7 | { month: 'February', desktop: 305 }, 8 | { month: 'March', desktop: 237 }, 9 | { month: 'April', desktop: 273 }, 10 | { month: 'May', desktop: 209 }, 11 | { month: 'June', desktop: 214 }, 12 | ] 13 | 14 | const chartConfig = { 15 | desktop: { 16 | label: 'Desktop', 17 | color: 'var(--chart-1)', 18 | }, 19 | } satisfies ChartConfig 20 | 21 | interface MRadarChartProps { 22 | ref: Ref 23 | } 24 | 25 | const MRadarChart = (props: MRadarChartProps) => { 26 | const { ref } = props 27 | 28 | return ( 29 | 30 | 31 | } /> 32 | 33 | 34 | 35 | 36 | 37 | ) 38 | } 39 | 40 | export default MRadarChart 41 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radar-chart/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import MRadarChart from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: MRadarChart, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radar-chart/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'RadarChart', 8 | title: 'Radar Chart', 9 | group: MaterialGroup.CHART, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radar-chart/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Radar Chart', 6 | schema: { 7 | componentName: 'RadarChart', 8 | props: {}, 9 | $dashboard: { 10 | rect: { 11 | width: 400, 12 | height: 240, 13 | }, 14 | }, 15 | }, 16 | }, 17 | ] 18 | 19 | export default snippets 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radial-chart/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import { generalAdvancedConfigure, generalBasicConfigure } from '../../configure' 3 | import MRadialChart from './component' 4 | 5 | const configure: Configure = { 6 | props: [ 7 | { 8 | type: 'group', 9 | title: '功能', 10 | setter: 'TabSetter', 11 | items: [ 12 | { 13 | type: 'group', 14 | key: 'basic', 15 | title: '基本', 16 | items: [...generalBasicConfigure], 17 | }, 18 | { 19 | type: 'group', 20 | key: 'advanced', 21 | title: '高级', 22 | items: [...generalAdvancedConfigure], 23 | }, 24 | ], 25 | }, 26 | ], 27 | component: {}, 28 | supports: {}, 29 | advanced: { 30 | view: MRadialChart, 31 | }, 32 | } 33 | 34 | export default configure 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radial-chart/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | import snippets from './snippets' 5 | 6 | const meta: ComponentMetadata = { 7 | componentName: 'RadialChart', 8 | title: 'Radial Chart', 9 | group: MaterialGroup.CHART, 10 | snippets, 11 | configure, 12 | } 13 | 14 | export default meta 15 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/chart/radial-chart/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { Snippet } from '@easy-editor/core' 2 | 3 | const snippets: Snippet[] = [ 4 | { 5 | title: 'Radial Chart', 6 | schema: { 7 | componentName: 'RadialChart', 8 | props: {}, 9 | $dashboard: { 10 | rect: { 11 | width: 400, 12 | height: 240, 13 | }, 14 | }, 15 | }, 16 | }, 17 | ] 18 | 19 | export default snippets 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/component.ts: -------------------------------------------------------------------------------- 1 | import Root from './root/component' 2 | 3 | // Basic 4 | import Image from './basic/image/component' 5 | import Text from './basic/text/component' 6 | // Inner 7 | import Group from './inner/group/component' 8 | 9 | // Chart 10 | import AreaChart from './chart/area-chart/component' 11 | import BarChart from './chart/bar-chart/component' 12 | import LineChart from './chart/line-chart/component' 13 | import PieChart from './chart/pie-chart/component' 14 | import RadarChart from './chart/radar-chart/component' 15 | import RadialChart from './chart/radial-chart/component' 16 | 17 | /** 18 | * 物料组件 19 | */ 20 | export const components = { 21 | AreaChart, 22 | BarChart, 23 | Image, 24 | LineChart, 25 | PieChart, 26 | RadarChart, 27 | RadialChart, 28 | Root, 29 | Text, 30 | Group, 31 | } 32 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/index.ts: -------------------------------------------------------------------------------- 1 | export * from './component' 2 | export * from './meta' 3 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/inner/group/component.tsx: -------------------------------------------------------------------------------- 1 | import { type PropsWithChildren, type Ref, forwardRef } from 'react' 2 | 3 | interface GroupProps extends PropsWithChildren {} 4 | 5 | const Group = forwardRef((props: GroupProps, ref: Ref) => { 6 | return ( 7 |
8 | {props?.children} 9 |
10 | ) 11 | }) 12 | 13 | export default Group 14 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/inner/group/configure.ts: -------------------------------------------------------------------------------- 1 | import type { Configure } from '@easy-editor/core' 2 | import Group from './component' 3 | 4 | const configure: Configure = { 5 | props: [ 6 | // { 7 | // name: 'test', 8 | // title: '分组', 9 | // type: 'group', 10 | // items: [], 11 | // }, 12 | ], 13 | component: {}, 14 | supports: {}, 15 | advanced: { 16 | view: Group, 17 | }, 18 | } 19 | 20 | export default configure 21 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/inner/group/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import { MaterialGroup } from '../../type' 3 | import configure from './configure' 4 | 5 | const meta: ComponentMetadata = { 6 | componentName: 'Group', 7 | title: 'Group', 8 | group: MaterialGroup.INNER, 9 | configure, 10 | } 11 | 12 | export default meta 13 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/meta.ts: -------------------------------------------------------------------------------- 1 | import Root from './root/meta' 2 | 3 | // Inner 4 | import Group from './inner/group/meta' 5 | export { Group } 6 | 7 | // Basic 8 | import Image from './basic/image/meta' 9 | import Text from './basic/text/meta' 10 | 11 | // Chart 12 | import AreaChart from './chart/area-chart/meta' 13 | import BarChart from './chart/bar-chart/meta' 14 | import LineChart from './chart/line-chart/meta' 15 | import PieChart from './chart/pie-chart/meta' 16 | import RadarChart from './chart/radar-chart/meta' 17 | import RadialChart from './chart/radial-chart/meta' 18 | 19 | /** 20 | * 物料元数据 21 | */ 22 | export const componentMetaMap = { 23 | AreaChart, 24 | BarChart, 25 | Image, 26 | LineChart, 27 | PieChart, 28 | RadarChart, 29 | RadialChart, 30 | Root, 31 | Text, 32 | } 33 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/root/component.tsx: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'react' 2 | 3 | interface RootProps { 4 | ref: Ref 5 | children?: React.ReactNode 6 | backgroundColor?: string 7 | backgroundImage?: string 8 | } 9 | 10 | const Root = (props: RootProps) => { 11 | const { ref, backgroundColor, children, backgroundImage } = props 12 | 13 | return ( 14 |
21 | {children} 22 |
23 | ) 24 | } 25 | 26 | export default Root 27 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/root/meta.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentMetadata } from '@easy-editor/core' 2 | import configure from './configure' 3 | 4 | const meta: ComponentMetadata = { 5 | componentName: 'Root', 6 | title: '根容器', 7 | category: '通用', 8 | configure, 9 | } 10 | 11 | export default meta 12 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/materials/type.ts: -------------------------------------------------------------------------------- 1 | export enum MaterialGroup { 2 | /** 内置 */ 3 | INNER = 'Inner', 4 | /** 基础 */ 5 | BASIC = 'Basic', 6 | /** 图表 */ 7 | CHART = 'Chart', 8 | /** 数据展示 */ 9 | DATA = 'Data', 10 | /** 交互 */ 11 | INTERACTION = 'Interaction', 12 | } 13 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/overrides.css: -------------------------------------------------------------------------------- 1 | .lc-project { 2 | .lc-simulator { 3 | background-color: unset !important; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import HotKeyMoveNodePlugin from './plugin-hotkey-move-node' 2 | 3 | /** 4 | * 插件 5 | */ 6 | export const pluginList = [HotKeyMoveNodePlugin()] 7 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/plugins/plugin-hotkey-move-node/index.ts: -------------------------------------------------------------------------------- 1 | import type { PluginCreator } from '@easy-editor/core' 2 | 3 | export const HOTKEY_MAP = { 4 | UP: ['up'], 5 | DOWN: ['down'], 6 | LEFT: ['left'], 7 | RIGHT: ['right'], 8 | } 9 | 10 | const HotKeyMoveNodePlugin: PluginCreator = () => { 11 | return { 12 | name: 'HotKeyMoveNodePlugin', 13 | deps: [], 14 | init(ctx) { 15 | const { hotkey, designer } = ctx 16 | 17 | const moveNode = (type: 'up' | 'down' | 'left' | 'right', step = 1) => { 18 | const selectedNodes = designer.selection.getTopNodes(false) 19 | if (selectedNodes.length === 0) return 20 | 21 | for (const node of selectedNodes) { 22 | let { x, y } = node.getDashboardRect() 23 | switch (type) { 24 | case 'up': 25 | y -= step 26 | break 27 | case 'down': 28 | y += step 29 | break 30 | case 'left': 31 | x -= step 32 | break 33 | case 'right': 34 | x += step 35 | break 36 | } 37 | node.updateDashboardRect({ 38 | x, 39 | y, 40 | }) 41 | } 42 | } 43 | 44 | hotkey.bind(HOTKEY_MAP.UP, () => moveNode('up')) 45 | hotkey.bind(HOTKEY_MAP.DOWN, () => moveNode('down')) 46 | hotkey.bind(HOTKEY_MAP.LEFT, () => moveNode('left')) 47 | hotkey.bind(HOTKEY_MAP.RIGHT, () => moveNode('right')) 48 | }, 49 | } 50 | } 51 | 52 | export default HotKeyMoveNodePlugin 53 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/basic/color-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@/components/ui/button' 2 | import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' 3 | import type { SetterProps } from '@easy-editor/core' 4 | import Sketch from '@uiw/react-color-sketch' 5 | 6 | interface ColorSetterProps extends SetterProps { 7 | disableAlpha?: boolean 8 | } 9 | 10 | const ColorSetter = (props: ColorSetterProps) => { 11 | const { value, initialValue, onChange, disableAlpha = false } = props 12 | 13 | return ( 14 | 15 | 16 | 28 | 29 | 30 | onChange(res.hexa)} disableAlpha={disableAlpha} presetColors={[]} /> 31 | 32 | 33 | ) 34 | } 35 | 36 | export default ColorSetter 37 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/basic/id-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SetterProps } from '@easy-editor/core' 2 | 3 | interface NodeIdSetterProps extends SetterProps {} 4 | 5 | const NodeIdSetter = (props: NodeIdSetterProps) => { 6 | const { selected } = props 7 | 8 | return ( 9 |
10 |

{selected.id}

11 |

{selected.componentMeta.title}

12 |
13 | ) 14 | } 15 | 16 | export default NodeIdSetter 17 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/basic/number-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import { Input } from '@/components/ui/input' 2 | import { cn } from '@/lib/utils' 3 | import type { SetterProps } from '@easy-editor/core' 4 | 5 | interface NumberSetterProps extends SetterProps { 6 | placeholder?: string 7 | suffix?: string 8 | } 9 | 10 | const NumberSetter = (props: NumberSetterProps) => { 11 | const { value, initialValue, placeholder, onChange, suffix } = props 12 | 13 | return ( 14 |
15 | onChange(+e.target.value)} 24 | /> 25 | {suffix && ( 26 | 30 | {suffix} 31 | 32 | )} 33 |
34 | ) 35 | } 36 | 37 | export default NumberSetter 38 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/basic/string-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import { Input } from '@/components/ui/input' 2 | import { cn } from '@/lib/utils' 3 | import type { SetterProps } from '@easy-editor/core' 4 | 5 | interface StringSetterProps extends SetterProps { 6 | placeholder?: string 7 | suffix?: string 8 | } 9 | 10 | const StringSetter = (props: StringSetterProps) => { 11 | const { value, initialValue, placeholder, onChange, suffix } = props 12 | 13 | return ( 14 |
15 | onChange(e.target.value)} 19 | className={cn('h-8 !text-xs px-2 py-[5px]', suffix && 'pr-8')} 20 | /> 21 | {suffix && ( 22 | 26 | {suffix} 27 | 28 | )} 29 |
30 | ) 31 | } 32 | 33 | export default StringSetter 34 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/basic/switch-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import { Switch } from '@/components/ui/switch' 2 | import type { SetterProps } from '@easy-editor/core' 3 | 4 | interface SwitchSetterProps extends SetterProps {} 5 | 6 | const SwitchSetter = (props: SwitchSetterProps) => { 7 | const { value, initialValue, onChange } = props 8 | 9 | return ( 10 |
11 | 12 |
13 | ) 14 | } 15 | 16 | export default SwitchSetter 17 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/custom-field-item.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from '@/components/ui/label' 2 | import { cn } from '@/lib/utils' 3 | import type { SettingField } from '@easy-editor/core' 4 | import type { ReactNode } from 'react' 5 | 6 | export const customFieldItem = (field: SettingField, setter: ReactNode) => { 7 | const { label = true, wrap = false } = field.config.extraProps || {} 8 | 9 | if (typeof label === 'boolean' && !label) { 10 | return
{setter}
11 | } 12 | 13 | return ( 14 |
15 | 18 |
19 |
{setter}
20 |
21 |
22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/group/collapse-setter/index.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@/components/ui/button' 2 | import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' 3 | import type { SetterProps } from '@easy-editor/core' 4 | import { ChevronsUpDown } from 'lucide-react' 5 | import type { PropsWithChildren } from 'react' 6 | import { useState } from 'react' 7 | 8 | interface CollapseSetterProps extends SetterProps, PropsWithChildren { 9 | icon?: boolean 10 | } 11 | 12 | const CollapseSetter = (props: CollapseSetterProps) => { 13 | const { field, children, initialValue, icon = true } = props 14 | const [isOpen, setIsOpen] = useState(initialValue ?? true) 15 | 16 | return ( 17 | 18 |
19 |

{field.title}

20 | {icon && ( 21 | 22 | 26 | 27 | )} 28 |
29 | {children} 30 |
31 | ) 32 | } 33 | 34 | export default CollapseSetter 35 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/setters/index.ts: -------------------------------------------------------------------------------- 1 | import ColorSetter from './basic/color-setter' 2 | import NodeIdSetter from './basic/id-setter' 3 | import NumberSetter from './basic/number-setter' 4 | import RectSetter from './basic/rect-setter' 5 | import StringSetter from './basic/string-setter' 6 | import SwitchSetter from './basic/switch-setter' 7 | import UploadSetter from './basic/upload-setter' 8 | 9 | import CollapseSetter from './group/collapse-setter' 10 | import TabSetter from './group/tab-setter' 11 | 12 | /** 13 | * 设置器 14 | */ 15 | export const setterMap = { 16 | CollapseSetter, 17 | ColorSetter, 18 | NodeIdSetter, 19 | NumberSetter, 20 | RectSetter, 21 | StringSetter, 22 | SwitchSetter, 23 | TabSetter, 24 | UploadSetter, 25 | } 26 | 27 | export * from './custom-field-item' 28 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/type.ts: -------------------------------------------------------------------------------- 1 | declare module '@easy-editor/core' { 2 | interface JSFunction { 3 | /** 4 | * 标识(TODO) 5 | */ 6 | key?: string 7 | 8 | /** 9 | * 方法名称(TODO) 10 | */ 11 | name?: string 12 | 13 | /** 14 | * 方法描述 15 | */ 16 | description?: string 17 | } 18 | 19 | interface JSExpression { 20 | /** 21 | * 标识(TODO) 22 | */ 23 | key?: string 24 | 25 | /** 26 | * 状态名称(TODO) 27 | */ 28 | name?: string 29 | 30 | /** 31 | * 状态描述 32 | */ 33 | description?: string 34 | } 35 | 36 | interface FieldExtraProps { 37 | /** 38 | * 是否显示 label 39 | * @default true 40 | */ 41 | label?: boolean 42 | 43 | /** 44 | * 是否换行 45 | * @default false 46 | */ 47 | wrap?: boolean 48 | 49 | /** 50 | * 是否支持变量绑定 51 | * @default false 52 | */ 53 | supportVariable?: boolean 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/editor/utils.ts: -------------------------------------------------------------------------------- 1 | export const formatMapFromESModule = (map: Record) => { 2 | return Object.keys(map).reduce>((result, key) => { 3 | result[key] = map[key] as T 4 | return result 5 | }, {}) 6 | } 7 | 8 | export const getSystemFonts = async () => { 9 | try { 10 | // @ts-ignore 11 | const availableFonts = await window.queryLocalFonts() 12 | return Array.from(new Set(availableFonts.map((font: any) => font.family))).map((font: any) => ({ 13 | label: font, 14 | value: font, 15 | })) 16 | } catch { 17 | console.error('浏览器不支持 queryLocalFonts API') 18 | return [] 19 | } 20 | } 21 | 22 | export const systemFonts = await getSystemFonts() 23 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/hooks/useDebounceFn.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef } from 'react' 2 | 3 | interface Options { 4 | wait: number 5 | } 6 | 7 | export function useDebounceFn any>(fn: T, options: Options = { wait: 400 }) { 8 | const timerRef = useRef | null>(null) 9 | const fnRef = useRef(fn) 10 | 11 | useEffect(() => { 12 | fnRef.current = fn 13 | }, [fn]) 14 | 15 | const cancel = useCallback(() => { 16 | if (timerRef.current) { 17 | clearTimeout(timerRef.current) 18 | timerRef.current = null 19 | } 20 | }, []) 21 | 22 | const run = useCallback( 23 | (...args: Parameters) => { 24 | cancel() 25 | timerRef.current = setTimeout(() => { 26 | fnRef.current(...args) 27 | }, options.wait) 28 | }, 29 | [cancel, options.wait], 30 | ) 31 | 32 | useEffect(() => { 33 | return cancel 34 | }, [cancel]) 35 | 36 | return { 37 | run, 38 | cancel, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/hooks/useMobile.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener('change', onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener('change', onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from 'react-dom/client' 2 | import App from './App' 3 | import './styles/global.css' 4 | 5 | createRoot(document.getElementById('root')!).render() 6 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/pages/editor/SettingRenderer.tsx: -------------------------------------------------------------------------------- 1 | import { Sidebar, SidebarContent, SidebarHeader } from '@/components/ui/sidebar' 2 | import { customFieldItem } from '@/editor/setters' 3 | import { project } from '@easy-editor/core' 4 | import { SettingRenderer } from '@easy-editor/react-renderer' 5 | import { observer } from 'mobx-react' 6 | 7 | export const SettingSidebar = observer(({ ...props }: React.ComponentProps) => { 8 | return ( 9 | 10 | 11 |
12 |
属性配置
13 |
14 |
15 | 16 | 17 | 18 |
19 | ) 20 | }) 21 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/pages/preview/index.tsx: -------------------------------------------------------------------------------- 1 | import { components } from '@/editor/materials' 2 | import { getPageInfoFromLocalStorage, getPageSchemaFromLocalStorage } from '@/lib/schema' 3 | import { Renderer } from '@easy-editor/react-renderer-dashboard' 4 | import { useEffect, useRef, useState } from 'react' 5 | 6 | const Preview = () => { 7 | const [schema, setSchema] = useState(null) 8 | const pageInfoRef = useRef(getPageInfoFromLocalStorage()) 9 | 10 | const navigate = (path?: string) => { 11 | const pageInfo = pageInfoRef.current 12 | if (pageInfo.length === 0) { 13 | console.warn('pageInfo is empty') 14 | return 15 | } 16 | 17 | const pageSchema = getPageSchemaFromLocalStorage(path || pageInfo[0].path) 18 | if (!pageSchema) { 19 | console.warn('pageSchema is empty') 20 | return 21 | } 22 | 23 | setSchema(pageSchema?.componentsTree[0]) 24 | console.log(pageInfo, pageSchema) 25 | } 26 | 27 | useEffect(() => { 28 | navigate() 29 | }, []) 30 | 31 | return ( 32 |
33 | {schema ? ( 34 | 35 | ) : ( 36 |
37 |
loading...
38 |
39 | )} 40 |
41 | ) 42 | } 43 | 44 | export default Preview 45 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ['class'], 4 | content: ['./index.html', './src/**/*.{ts,tsx,js,jsx}'], 5 | theme: { 6 | extend: { 7 | colors: { 8 | sidebar: { 9 | DEFAULT: 'hsl(var(--sidebar-background))', 10 | foreground: 'hsl(var(--sidebar-foreground))', 11 | primary: 'hsl(var(--sidebar-primary))', 12 | 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))', 13 | accent: 'hsl(var(--sidebar-accent))', 14 | 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))', 15 | border: 'hsl(var(--sidebar-border))', 16 | ring: 'hsl(var(--sidebar-ring))', 17 | }, 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } 23 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true, 24 | 25 | "baseUrl": ".", 26 | "paths": { 27 | "@/*": ["./src/*"] 28 | } 29 | }, 30 | "include": ["src"] 31 | } 32 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.mts"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/create-easy-editor/template/dashboard/react/vite.config.mts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite' 2 | import react from '@vitejs/plugin-react' 3 | import path from 'node:path' 4 | import { defineConfig } from 'vite' 5 | 6 | // https://vite.dev/config/ 7 | export default defineConfig({ 8 | plugins: [ 9 | react({ 10 | babel: { 11 | exclude: 'node_modules/**', 12 | babelrc: false, 13 | presets: [ 14 | [ 15 | '@babel/preset-typescript', 16 | { 17 | allowDeclareFields: true, 18 | }, 19 | ], 20 | ], 21 | plugins: [ 22 | [ 23 | '@babel/plugin-proposal-decorators', 24 | { 25 | version: '2023-11', 26 | }, 27 | ], 28 | ], 29 | }, 30 | }), 31 | tailwindcss(), 32 | ], 33 | resolve: { 34 | alias: { 35 | '@': path.resolve(__dirname, './src'), 36 | }, 37 | }, 38 | build: { 39 | target: 'esnext', 40 | }, 41 | }) 42 | -------------------------------------------------------------------------------- /packages/create-easy-editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "target": "ES2023", 5 | "module": "Preserve", 6 | "moduleResolution": "bundler", 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "declaration": false, 10 | "sourceMap": false, 11 | "noUnusedLocals": true, 12 | "esModuleInterop": true 13 | }, 14 | "include": ["src"], 15 | } 16 | -------------------------------------------------------------------------------- /packages/plugin-dashboard/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import nodeResolve from '@rollup/plugin-node-resolve' 3 | import cleanup from 'rollup-plugin-cleanup' 4 | import pkg from './package.json' assert { type: 'json' } 5 | 6 | const external = [...Object.keys(pkg.peerDependencies)] 7 | 8 | const plugins = [ 9 | nodeResolve({ 10 | extensions: ['.js', '.ts'], 11 | browser: true, 12 | }), 13 | babel({ 14 | extensions: ['.js', '.ts'], 15 | exclude: 'node_modules/**', 16 | babelrc: false, 17 | babelHelpers: 'bundled', 18 | presets: [['@babel/preset-typescript']], 19 | plugins: [ 20 | [ 21 | '@babel/plugin-proposal-decorators', 22 | { 23 | version: '2023-11', 24 | }, 25 | ], 26 | ], 27 | }), 28 | cleanup({ 29 | comments: ['some', /PURE/], 30 | extensions: ['.js', '.ts'], 31 | }), 32 | ] 33 | 34 | export default [ 35 | { 36 | input: 'src/index.ts', 37 | output: [ 38 | { 39 | file: 'dist/index.js', 40 | format: 'es', 41 | }, 42 | { 43 | file: 'dist/index.cjs', 44 | format: 'cjs', 45 | }, 46 | ], 47 | plugins, 48 | external, 49 | }, 50 | ] 51 | -------------------------------------------------------------------------------- /packages/plugin-dashboard/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { Node } from '@easy-editor/core' 2 | 3 | /** 4 | * 更新节点在 dashboard 中的位置 5 | * @param node 节点 6 | * @param offset 节点相对于画布的偏移量 7 | * @param groupOffset 节点相对于其父组节点的偏移量 8 | */ 9 | export const updateNodeRect = (node: Node, offset = { x: 0, y: 0 }) => { 10 | if (node.isGroup) { 11 | const nodeRect = node.getDashboardRect() 12 | const delta = { 13 | x: offset.x - nodeRect.x, 14 | y: offset.y - nodeRect.y, 15 | } 16 | 17 | for (const childNode of node.getAllNodesInGroup()) { 18 | const childRect = childNode.getDashboardRect() 19 | childNode.updateDashboardRect({ 20 | x: childRect.x + delta.x, 21 | y: childRect.y + delta.y, 22 | }) 23 | } 24 | } else { 25 | node.updateDashboardRect({ 26 | x: offset.x, 27 | y: offset.y, 28 | }) 29 | } 30 | } 31 | 32 | /** 33 | * 更新节点 DOM 在 dashboard 中的位置 34 | * @param node 节点 35 | * @param offset 节点相对于画布的偏移量 36 | * @param groupOffset 节点相对于其父组节点的偏移量 37 | */ 38 | export const updateNodeRectByDOM = (node: Node, offset = { x: 0, y: 0 }) => { 39 | const domNode = node.getDashboardContainer() 40 | if (!domNode) { 41 | return 42 | } 43 | 44 | domNode.style.left = `${offset.x}px` 45 | domNode.style.top = `${offset.y}px` 46 | } 47 | -------------------------------------------------------------------------------- /packages/plugin-dashboard/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist" 6 | }, 7 | "include": ["./src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"], 4 | } 5 | -------------------------------------------------------------------------------- /packages/plugin-dashboard/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test", "./web/test", "./store/test"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/plugin-datasource/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/plugin-datasource 2 | 3 | ## 1.0.2 4 | 5 | ### Patch Changes 6 | 7 | - 638425a: types: perform DataSource 8 | - Updated dependencies [638425a] 9 | - Updated dependencies [5afd68c] 10 | - @easy-editor/core@1.0.2 11 | 12 | ## 1.0.1 13 | 14 | ### Patch Changes 15 | 16 | - 8b51e73: perf: detach dataSource 17 | - 7ffae3c: perf: core provide DataSource interface 18 | - 90c6910: perf: plugin extend mobx 19 | - Updated dependencies [7ffae3c] 20 | - Updated dependencies [90c6910] 21 | - Updated dependencies [49ef13e] 22 | - @easy-editor/core@1.0.1 23 | 24 | ## 1.0.0 25 | 26 | ### Patch Changes 27 | 28 | - 262342d: V1.0.0 29 | 30 | - Core architecture refactoring, optimized plugin architecture, improved modularity and extensibility 31 | - Refactored renderer, extracted and added renderer core renderer-core 32 | - Added data source plugin plugin-datasource 33 | - Improved Dashboard plugin, supporting element positioning, grouping and guidelines 34 | - API changes: createEasyEditor → init, ComponentMetaManager → Materials, PluginManager → Plugins, SetterManager → Setters, ... 35 | - Other bug fixes... 36 | 37 | - Updated dependencies [262342d] 38 | - @easy-editor/core@1.0.0 39 | -------------------------------------------------------------------------------- /packages/plugin-datasource/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import nodeResolve from '@rollup/plugin-node-resolve' 4 | import cleanup from 'rollup-plugin-cleanup' 5 | import pkg from './package.json' assert { type: 'json' } 6 | 7 | const external = [...Object.keys(pkg.peerDependencies)] 8 | 9 | const plugins = [ 10 | nodeResolve({ 11 | extensions: ['.js', '.ts'], 12 | browser: true, 13 | }), 14 | commonjs(), 15 | babel({ 16 | extensions: ['.js', '.ts'], 17 | exclude: 'node_modules/**', 18 | babelrc: false, 19 | babelHelpers: 'bundled', 20 | presets: ['@babel/preset-typescript'], 21 | }), 22 | cleanup({ 23 | comments: ['some', /PURE/], 24 | extensions: ['.js', '.ts'], 25 | }), 26 | ] 27 | 28 | export default [ 29 | { 30 | input: 'src/index.ts', 31 | output: [ 32 | { 33 | file: 'dist/index.js', 34 | format: 'es', 35 | }, 36 | { 37 | file: 'dist/index.cjs', 38 | format: 'cjs', 39 | }, 40 | ], 41 | plugins, 42 | external, 43 | }, 44 | ] 45 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/core/index.ts: -------------------------------------------------------------------------------- 1 | export { RuntimeDataSourceItem } from './RuntimeDataSourceItem' 2 | export { adapt2Runtime } from './adapter' 3 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/handlers/fetch.ts: -------------------------------------------------------------------------------- 1 | import request from 'universal-request' 2 | import type { AsObject, RequestOptions } from 'universal-request/lib/types' 3 | import type { RuntimeOptionsConfig } from '../types' 4 | 5 | // config 留着扩展 6 | export function createFetchHandler(config?: Record) { 7 | return async (options: RuntimeOptionsConfig) => { 8 | const requestConfig: RequestOptions = { 9 | ...options, 10 | url: options.uri, 11 | method: options.method as RequestOptions['method'], 12 | data: options.params as AsObject, 13 | headers: options.headers as AsObject, 14 | ...config, 15 | } 16 | const response = await request(requestConfig) 17 | return response 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | DataHandler, 3 | RequestHandler, 4 | RequestHandlersMap, 5 | RuntimeDataSourceConfig, 6 | RuntimeOptionsConfig, 7 | UrlParamsHandler, 8 | WillFetch, 9 | } from '../types' 10 | 11 | // 默认的 dataSourceItem 的 dataHandler 12 | export const defaultDataHandler: DataHandler = async (response: { data: T }) => response.data 13 | 14 | // 默认的 dataSourceItem 的 willFetch 15 | export const defaultWillFetch: WillFetch = (options: RuntimeOptionsConfig) => options 16 | 17 | // 默认的 dataSourceItem 的 shouldFetch 18 | export const defaultShouldFetch = () => true 19 | 20 | type GetRequestHandler = ( 21 | ds: RuntimeDataSourceConfig, 22 | requestHandlersMap: RequestHandlersMap<{ data: T }>, 23 | ) => RequestHandler<{ data: T }> | UrlParamsHandler 24 | 25 | // 从当前 dataSourceItem 中获取 requestHandler 26 | export const getRequestHandler: GetRequestHandler = (ds, requestHandlersMap) => { 27 | if (ds.type === 'custom') { 28 | // 自定义类型处理 29 | return ds.requestHandler as unknown as RequestHandler<{ data: unknown }> // 理论上这里应该是能强转的,就算为空,应该在 request 请求的时候触发失败 30 | } 31 | // type 协议默认值 fetch 32 | return requestHandlersMap[ds.type || 'fetch'] 33 | } 34 | 35 | export const promiseSettled = 36 | (Promise.allSettled ? Promise.allSettled.bind(Promise) : null) || 37 | ((promises: Array>) => { 38 | return Promise.all( 39 | promises.map(p => { 40 | return p 41 | .then(v => ({ 42 | status: 'fulfilled', 43 | value: v, 44 | })) 45 | .catch(e => ({ 46 | status: 'rejected', 47 | reason: e, 48 | })) 49 | }), 50 | ) 51 | }) 52 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/interpret/DataSourceEngineFactory.ts: -------------------------------------------------------------------------------- 1 | import { RuntimeDataSourceItem } from '../core/RuntimeDataSourceItem' 2 | import { adapt2Runtime } from '../core/adapter' 3 | import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory' 4 | import { getRequestHandler } from '../helpers' 5 | import type { 6 | DataHandler, 7 | IDataSourceRuntimeContext, 8 | IRuntimeDataSource, 9 | InterpretDataSource, 10 | RequestHandlersMap, 11 | RuntimeDataSource, 12 | RuntimeDataSourceConfig, 13 | } from '../types' 14 | 15 | /** 16 | * @param dataSource 17 | * @param context 18 | * @param extraConfig: { requestHandlersMap } 19 | */ 20 | 21 | export default ( 22 | dataSource: InterpretDataSource, 23 | context: IDataSourceRuntimeContext, 24 | extraConfig: { 25 | requestHandlersMap: RequestHandlersMap<{ data: unknown }> 26 | defaultDataHandler?: DataHandler 27 | } = { requestHandlersMap: {} }, 28 | ) => { 29 | const { requestHandlersMap } = extraConfig 30 | 31 | const runtimeDataSource: RuntimeDataSource = adapt2Runtime(dataSource, context, { 32 | defaultDataHandler: extraConfig.defaultDataHandler, 33 | }) 34 | 35 | const dataSourceMap = runtimeDataSource.list.reduce( 36 | (prev: Record, current: RuntimeDataSourceConfig) => { 37 | prev[current.id] = new RuntimeDataSourceItem(current, getRequestHandler(current, requestHandlersMap), context) 38 | return prev 39 | }, 40 | {}, 41 | ) 42 | 43 | return { 44 | dataSourceMap, 45 | reloadDataSource: reloadDataSourceFactory(runtimeDataSource, dataSourceMap, runtimeDataSource.dataHandler), 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/interpret/index.ts: -------------------------------------------------------------------------------- 1 | import createInterpret from './DataSourceEngineFactory' 2 | export { createInterpret } 3 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/runtime/index.ts: -------------------------------------------------------------------------------- 1 | import createRuntime from './RuntimeDataSourceEngineFactory' 2 | export { createRuntime } 3 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/type.ts: -------------------------------------------------------------------------------- 1 | import type { InterpretDataSource } from './types' 2 | 3 | declare module '@easy-editor/core' { 4 | interface ProjectSchema { 5 | /** 6 | * 数据源配置 7 | */ 8 | // @ts-ignore 9 | dataSource?: InterpretDataSource 10 | } 11 | 12 | interface RootSchema { 13 | /** 14 | * 数据源配置 15 | */ 16 | // @ts-ignore 17 | dataSource?: InterpretDataSource 18 | } 19 | 20 | interface DataSourceEngine { 21 | // @ts-ignore 22 | createDataSourceEngine: ( 23 | dataSource: InterpretDataSource, 24 | engine: any, 25 | ) => { 26 | dataSourceMap: Record 27 | reloadDataSource: () => Promise 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/types/data-source-handlers.ts: -------------------------------------------------------------------------------- 1 | import type { IDataSourceRuntimeContext, RuntimeOptionsConfig } from './data-source-runtime' 2 | 3 | export type RequestHandler = ( 4 | options: RuntimeOptionsConfig, 5 | context?: IDataSourceRuntimeContext, 6 | ) => Promise 7 | 8 | export type UrlParamsHandler = (context?: IDataSourceRuntimeContext) => Promise 9 | 10 | export type RequestHandlersMap = Record> 11 | 12 | // 仅在 type=custom 的时候生效的 handler 13 | export type CustomRequestHandler = ( 14 | options: RuntimeOptionsConfig, 15 | context?: IDataSourceRuntimeContext, 16 | ) => Promise 17 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/types/data-source-interpret.ts: -------------------------------------------------------------------------------- 1 | import type { CompositeValue, JSExpression, JSFunction, JSONObject } from '@easy-editor/core' 2 | 3 | /** 4 | * 数据源对象 5 | * @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 6 | */ 7 | export interface InterpretDataSource { 8 | list: InterpretDataSourceConfig[] 9 | dataHandler?: JSFunction 10 | } 11 | 12 | /** 13 | * 数据源对象 14 | * @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 15 | */ 16 | export interface InterpretDataSourceConfig { 17 | id: string 18 | isInit?: boolean | JSExpression 19 | isSync?: boolean | JSExpression 20 | type?: string 21 | requestHandler?: JSFunction 22 | dataHandler?: JSFunction 23 | errorHandler?: JSFunction 24 | willFetch?: JSFunction 25 | shouldFetch?: JSFunction 26 | options?: { 27 | uri: string | JSExpression 28 | api?: string | JSExpression // 兼容 29 | params?: JSONObject | JSExpression 30 | method?: string | JSExpression 31 | isCors?: boolean | JSExpression 32 | timeout?: number | JSExpression 33 | headers?: JSONObject | JSExpression 34 | [option: string]: CompositeValue 35 | } 36 | [otherKey: string]: CompositeValue 37 | } 38 | -------------------------------------------------------------------------------- /packages/plugin-datasource/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { DataHandler } from './data-source-runtime' 2 | 3 | export * from './data-source' 4 | export * from './data-source-handlers' 5 | export * from './data-source-interpret' 6 | export * from './data-source-runtime' 7 | 8 | export interface ExtraConfig { 9 | defaultDataHandler?: DataHandler 10 | } 11 | -------------------------------------------------------------------------------- /packages/plugin-datasource/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist" 6 | }, 7 | "include": ["./src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-datasource/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"], 4 | } 5 | -------------------------------------------------------------------------------- /packages/plugin-datasource/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test", "./web/test", "./store/test"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/plugin-hotkey/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import nodeResolve from '@rollup/plugin-node-resolve' 4 | import cleanup from 'rollup-plugin-cleanup' 5 | import pkg from './package.json' assert { type: 'json' } 6 | 7 | const external = Object.keys(pkg.peerDependencies) 8 | 9 | const plugins = [ 10 | nodeResolve({ 11 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 12 | }), 13 | commonjs(), 14 | babel({ 15 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 16 | exclude: 'node_modules/**', 17 | babelrc: false, 18 | babelHelpers: 'bundled', 19 | presets: [ 20 | ['@babel/preset-react', { runtime: 'automatic' }], 21 | [ 22 | '@babel/preset-typescript', 23 | { 24 | allowDeclareFields: true, 25 | }, 26 | ], 27 | ], 28 | plugins: [ 29 | [ 30 | '@babel/plugin-proposal-decorators', 31 | { 32 | version: '2023-11', 33 | }, 34 | ], 35 | ], 36 | }), 37 | cleanup({ 38 | comments: ['some', /PURE/], 39 | extensions: ['.js', '.ts'], 40 | }), 41 | ] 42 | 43 | export default [ 44 | { 45 | input: 'src/index.ts', 46 | output: [ 47 | { 48 | file: 'dist/cjs/index.js', 49 | format: 'cjs', 50 | sourcemap: true, 51 | }, 52 | { 53 | file: 'dist/esm/index.js', 54 | format: 'es', 55 | sourcemap: true, 56 | }, 57 | { 58 | file: 'dist/index.js', 59 | format: 'es', 60 | }, 61 | ], 62 | plugins, 63 | external, 64 | }, 65 | ] 66 | -------------------------------------------------------------------------------- /packages/plugin-hotkey/src/const.ts: -------------------------------------------------------------------------------- 1 | export const HOTKEY_MAP = { 2 | /** 3 | * 历史记录回退 4 | */ 5 | HISTORY_UNDO: ['command+z', 'ctrl+z'], 6 | 7 | /** 8 | * 历史记录前进 9 | */ 10 | HISTORY_REDO: ['command+y', 'ctrl+y'], 11 | 12 | /** 13 | * 锁定/解锁 14 | */ 15 | LOCK_UNLOCK: ['command+shift+l', 'ctrl+shift+l'], 16 | 17 | /** 18 | * 显示/隐藏 19 | */ 20 | SHOW_HIDE: ['command+shift+h', 'ctrl+shift+h'], 21 | 22 | /** 23 | * 复制 24 | */ 25 | COPY: ['command+c', 'ctrl+c'], 26 | 27 | /** 28 | * 粘贴 29 | */ 30 | PASTE: ['command+v', 'ctrl+v'], 31 | 32 | /** 33 | * 剪切 34 | */ 35 | CUT: ['command+x', 'ctrl+x'], 36 | 37 | /** 38 | * 删除 39 | */ 40 | DELETE: ['backspace', 'del'], 41 | 42 | /** 43 | * 取消选中 44 | */ 45 | CLEAR_SELECTION: ['esc'], 46 | } 47 | -------------------------------------------------------------------------------- /packages/plugin-hotkey/src/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 检查事件是否由表单元素触发 3 | */ 4 | export const isFormEvent = (e: KeyboardEvent | MouseEvent) => { 5 | const t = e.target as HTMLFormElement 6 | if (!t) { 7 | return false 8 | } 9 | 10 | if (t.form || /^(INPUT|SELECT|TEXTAREA)$/.test(t.tagName)) { 11 | return true 12 | } 13 | if (t instanceof HTMLElement && /write/.test(window.getComputedStyle(t).getPropertyValue('-webkit-user-modify'))) { 14 | return true 15 | } 16 | return false 17 | } 18 | -------------------------------------------------------------------------------- /packages/plugin-hotkey/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist" 6 | }, 7 | "include": ["./src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-hotkey/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"], 4 | } 5 | -------------------------------------------------------------------------------- /packages/plugin-hotkey/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test", "./web/test", "./store/test"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/README.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/react-renderer-dashboard 2 | 3 | React renderer for EasyEditor in dashboard mode. This package provides specialized rendering capabilities for dashboard interfaces, extending the core react-renderer with dashboard-specific features for building visual editing experiences. 4 | 5 | ## Features 6 | 7 | - **Dashboard Layout Rendering**: Support for grid-based and absolute positioning layouts 8 | - **Component Overlays**: Visual indicators for component selection and editing 9 | - **Drag Handles**: Specialized interaction points for moving and resizing components 10 | - **Grid Snapping**: Alignment guidance for precise component positioning 11 | - **Visual Guidelines**: Smart guides for component alignment and distribution 12 | - **Multi-select Support**: Specialized rendering for multi-component selection 13 | - **Inline Editing**: Direct text and property editing within the dashboard view 14 | - **Lock/Visibility Controls**: Visual indicators for component lock and visibility state 15 | - **Z-index Management**: Visual representation of component stacking order 16 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/index.ts: -------------------------------------------------------------------------------- 1 | import Renderer from './renderer' 2 | import { LowCodeRenderer } from './renderer-core/renderer' 3 | import { SimulatorRenderer, simulatorRenderer } from './simulator-renderer' 4 | 5 | import './css/theme.css' 6 | 7 | export { 8 | /** 9 | * renderer: 用于 live 模式 10 | * @example 11 | * 12 | */ 13 | LowCodeRenderer, 14 | /** 15 | * Renderer: 用于 live 模式 16 | * @example 17 | * 18 | */ 19 | Renderer, 20 | /** 21 | * SimulatorRenderer: 用于 design 模式 22 | * @example 23 | * 24 | */ 25 | SimulatorRenderer, 26 | /** 27 | * simulator renderer: 用于 design 模式 28 | * @example 29 | * 30 | * simulatorRenderer.mount(simulator) 31 | * simulator.mountContentFrame(elem) 32 | */ 33 | simulatorRenderer, 34 | } 35 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/loading.css: -------------------------------------------------------------------------------- 1 | .loading-logo-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | gap: 15px; 7 | } 8 | 9 | .breathing-logo { 10 | width: 60px; 11 | height: 60px; 12 | animation: breathe 2s infinite ease-in-out; 13 | } 14 | 15 | @keyframes breathe { 16 | 0% { 17 | opacity: 0.4; 18 | transform: scale(0.95); 19 | } 20 | 50% { 21 | opacity: 1; 22 | transform: scale(1.05); 23 | } 24 | 100% { 25 | opacity: 0.4; 26 | transform: scale(0.95); 27 | } 28 | } 29 | 30 | .loading-text { 31 | color: #666; 32 | font-size: 14px; 33 | letter-spacing: 2px; 34 | animation: pulse 1.5s infinite; 35 | } 36 | 37 | @keyframes pulse { 38 | 0% { 39 | opacity: 0.5; 40 | } 41 | 50% { 42 | opacity: 1; 43 | } 44 | 100% { 45 | opacity: 0.5; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/renderer-core/index.tsx: -------------------------------------------------------------------------------- 1 | import type { RendererProps } from '@easy-editor/renderer-core' 2 | import { LowCodeRenderer as Renderer } from './renderer' 3 | 4 | const LowCodeRenderer = (props: RendererProps) => { 5 | return 6 | } 7 | 8 | export default LowCodeRenderer 9 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/renderer-core/renderer.ts: -------------------------------------------------------------------------------- 1 | import { adapter, componentRendererFactory, pageRendererFactory, rendererFactory } from '@easy-editor/react-renderer' 2 | import { dashboardBaseRendererFactory } from './renderer/base' 3 | 4 | // 抽离开单独设置,不然下面的 page 和 component 会走老的 5 | adapter.setBaseRenderer(dashboardBaseRendererFactory()) 6 | adapter.setRenderers({ 7 | PageRenderer: pageRendererFactory(), 8 | ComponentRenderer: componentRendererFactory(), 9 | }) 10 | 11 | export const LowCodeRenderer = rendererFactory() 12 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/renderer-core/renderer/base.ts: -------------------------------------------------------------------------------- 1 | import { type ComponentConstruct, baseRendererFactory, compWrapper, leafWrapper } from '@easy-editor/react-renderer' 2 | import { dashboardWrapper } from '../hoc/dashboard' 3 | 4 | export const dashboardBaseRendererFactory: () => any = () => { 5 | const OriginBase = baseRendererFactory() 6 | 7 | return class BaseRenderer extends OriginBase { 8 | get __componentHOCs(): ComponentConstruct[] { 9 | if (this.__designModeIsDesign) { 10 | return [dashboardWrapper, leafWrapper, compWrapper] 11 | } 12 | return [dashboardWrapper, compWrapper] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/renderer/index.css: -------------------------------------------------------------------------------- 1 | .lc-editor { 2 | position: relative; 3 | height: 100%; 4 | width: 100%; 5 | overflow: auto; 6 | 7 | .lc-editor-canvas { 8 | position: absolute; 9 | top: 0; 10 | bottom: 0; 11 | left: 0; 12 | width: 100%; 13 | overflow: hidden; 14 | 15 | .lc-editor-canvas-viewport { 16 | position: absolute; 17 | top: 0; 18 | bottom: 0; 19 | left: 0; 20 | width: 100%; 21 | 22 | left: 50%; 23 | top: 50%; 24 | transform-origin: 0px 0px; 25 | transform: scale(1) translate(-50%, -50%); 26 | } 27 | } 28 | 29 | .lc-editor-content { 30 | position: absolute; 31 | top: 0; 32 | bottom: 0; 33 | left: 0; 34 | overflow: hidden; 35 | height: 100%; 36 | width: 100%; 37 | 38 | .lc-editor-content-frame { 39 | border: none; 40 | transform-origin: 0 0; 41 | height: 100%; 42 | width: 100%; 43 | } 44 | } 45 | } 46 | 47 | .lc-component-container { 48 | position: absolute; 49 | border: none; 50 | user-select: none; 51 | touch-action: none; 52 | pointer-events: auto; 53 | 54 | &.mask { 55 | cursor: move !important; 56 | } 57 | 58 | .lc-component-mask { 59 | position: absolute; 60 | } 61 | 62 | .lc-component { 63 | &.mask { 64 | pointer-events: none; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/BemTools/GuideLine.tsx: -------------------------------------------------------------------------------- 1 | import type { Simulator } from '@easy-editor/core' 2 | import { observer } from 'mobx-react' 3 | 4 | interface GuideLineProps { 5 | host: Simulator 6 | } 7 | 8 | export const GuideLine: React.FC = observer(({ host }) => { 9 | const { guideline } = host.designer 10 | const { enabled, adsorptionLines } = guideline 11 | 12 | if (!enabled) { 13 | return <> 14 | } 15 | 16 | return ( 17 | <> 18 | {Array.from(adsorptionLines.verticalLines.values()).map(pos => ( 19 |
26 | ))} 27 | {Array.from(adsorptionLines.horizontalLines.values()).map(pos => ( 28 |
35 | ))} 36 | 37 | ) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/BemTools/index.css: -------------------------------------------------------------------------------- 1 | .lc-bem-tools { 2 | pointer-events: none; 3 | position: absolute; 4 | top: 0; 5 | left: 0; 6 | bottom: 0; 7 | right: 0; 8 | overflow: hidden; 9 | z-index: 1; 10 | } 11 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/BemTools/index.tsx: -------------------------------------------------------------------------------- 1 | import type { Simulator } from '@easy-editor/core' 2 | import { observer } from 'mobx-react' 3 | import { BorderDetecting } from './BorderDetecting' 4 | import { BorderResizing } from './BorderResizing' 5 | import { BorderSelecting } from './BorderSelecting' 6 | import { GuideLine } from './GuideLine' 7 | 8 | import './index.css' 9 | import './tools.css' 10 | 11 | interface BemToolsProps { 12 | host: Simulator 13 | } 14 | 15 | export const BemTools: React.FC = observer(({ host }) => { 16 | return ( 17 |
18 | 19 | 20 | 21 | 22 |
23 | ) 24 | }) 25 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/DesignView.tsx: -------------------------------------------------------------------------------- 1 | import { DESIGNER_EVENT, type Designer, type DesignerProps, clipboard } from '@easy-editor/core' 2 | import { classnames } from '@easy-editor/renderer-core' 3 | import { memo, useEffect, useState } from 'react' 4 | import { ProjectView } from './ProjectView' 5 | 6 | interface DesignerViewProps extends Omit { 7 | designer: Designer 8 | className?: string 9 | style?: React.CSSProperties 10 | 11 | [key: string]: any 12 | } 13 | 14 | export const DesignerView: React.FC = memo( 15 | props => { 16 | const { designer: propsDesigner, className, style, onMount, ...designerProps } = props 17 | 18 | const [designer] = useState(() => { 19 | propsDesigner.setProps(designerProps) 20 | return propsDesigner 21 | }) 22 | 23 | useEffect(() => { 24 | if (onMount) { 25 | onMount(designer) 26 | } 27 | 28 | clipboard.injectCopyPaster(document) 29 | designer.postEvent(DESIGNER_EVENT.MOUNT, designer) 30 | 31 | return () => { 32 | designer.purge() 33 | } 34 | }, []) 35 | 36 | return ( 37 |
38 | 39 |
40 | ) 41 | }, 42 | (prevProps, nextProps) => { 43 | nextProps.designer.setProps(nextProps) 44 | 45 | if (nextProps.className !== prevProps.className || nextProps.style !== prevProps.style) { 46 | return true 47 | } 48 | return false 49 | }, 50 | ) 51 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/hooks/useResizeObserver.ts: -------------------------------------------------------------------------------- 1 | import { throttle } from 'lodash-es' 2 | import { useEffect } from 'react' 3 | 4 | export const useResizeObserver = ({ 5 | elem, 6 | onResize, 7 | throttleTime = 300, 8 | }: { 9 | elem: React.RefObject 10 | onResize: (entries: ResizeObserverEntry[]) => void 11 | throttleTime?: number 12 | }) => { 13 | useEffect(() => { 14 | if (elem.current) { 15 | const observer = new ResizeObserver(throttle((entries: ResizeObserverEntry[]) => onResize(entries), throttleTime)) 16 | observer.observe(elem.current) 17 | return () => observer.disconnect() 18 | } 19 | }, [elem]) 20 | } 21 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/index.tsx: -------------------------------------------------------------------------------- 1 | import { DesignerView } from './DesignView' 2 | 3 | import './index.css' 4 | 5 | export { DesignerView as SimulatorRenderer } 6 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/SimulatorRenderer/loading.css: -------------------------------------------------------------------------------- 1 | .loading-logo-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | gap: 15px; 7 | } 8 | 9 | .breathing-logo { 10 | width: 60px; 11 | height: 60px; 12 | animation: breathe 2s infinite ease-in-out; 13 | } 14 | 15 | @keyframes breathe { 16 | 0%, 17 | 100% { 18 | opacity: 0.4; 19 | transform: scale(0.95); 20 | } 21 | 50% { 22 | opacity: 1; 23 | transform: scale(1.05); 24 | } 25 | } 26 | 27 | .loading-text { 28 | background: linear-gradient( 29 | 90deg, 30 | #000 0%, 31 | #444 10%, 32 | #fff 25%, 33 | #444 40%, 34 | #000 50%, 35 | #444 60%, 36 | #fff 75%, 37 | #444 90%, 38 | #000 100% 39 | ); 40 | background-size: 300% auto; 41 | background-clip: text; 42 | -webkit-background-clip: text; 43 | color: transparent; 44 | -webkit-text-fill-color: transparent; 45 | animation: gradient-move 5s linear infinite alternate; 46 | font-size: 14px; 47 | letter-spacing: 2px; 48 | } 49 | 50 | @keyframes gradient-move { 51 | 0% { 52 | background-position: 0% 50%; 53 | } 54 | 100% { 55 | background-position: 100% 50%; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/simulator-renderer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './simulator-renderer' 2 | export * from './SimulatorRenderer' 3 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/src/type.ts: -------------------------------------------------------------------------------- 1 | import '@easy-editor/plugin-dashboard' 2 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist", 6 | "skipLibCheck": true 7 | }, 8 | "include": ["./src"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"], 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-renderer-dashboard/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test", "./web/test", "./store/test"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/react-renderer/README.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/react-renderer 2 | 3 | React renderer implementation for EasyEditor. This package provides the React-specific implementation of the renderer-core interfaces, enabling schema-driven rendering using React components. 4 | 5 | ## Features 6 | 7 | - **React Component Rendering**: Converts EasyEditor schema into React component hierarchy 8 | - **React Context Integration**: Provides schema context to all rendered components 9 | - **Lifecycle Management**: Handles React component lifecycle methods based on schema 10 | - **Error Boundaries**: React-specific error handling with fallback components 11 | - **Ref Forwarding**: Automatic reference collection for component manipulation 12 | - **Dynamic Props**: Support for dynamic props and expressions within React components 13 | - **State Management**: Integration with React's state system 14 | - **Event Handling**: React-specific event binding from schema definitions 15 | 16 | -------------------------------------------------------------------------------- /packages/react-renderer/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import nodeResolve from '@rollup/plugin-node-resolve' 4 | import cleanup from 'rollup-plugin-cleanup' 5 | import pkg from './package.json' assert { type: 'json' } 6 | 7 | const external = [...Object.keys(pkg.peerDependencies), 'mobx-react-lite', 'mobx-react', 'mobx', 'react/jsx-runtime'] 8 | 9 | const plugins = [ 10 | nodeResolve({ 11 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 12 | }), 13 | commonjs(), 14 | babel({ 15 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 16 | exclude: 'node_modules/**', 17 | babelrc: false, 18 | babelHelpers: 'bundled', 19 | presets: [ 20 | ['@babel/preset-react', { runtime: 'automatic' }], 21 | [ 22 | '@babel/preset-typescript', 23 | { 24 | allowDeclareFields: true, 25 | }, 26 | ], 27 | ], 28 | plugins: [ 29 | [ 30 | '@babel/plugin-proposal-decorators', 31 | { 32 | version: '2023-11', 33 | }, 34 | ], 35 | ], 36 | }), 37 | cleanup({ 38 | comments: ['some', /PURE/], 39 | extensions: ['.js', '.ts'], 40 | }), 41 | ] 42 | 43 | export default [ 44 | { 45 | input: 'src/index.ts', 46 | output: [ 47 | { 48 | file: 'dist/index.js', 49 | format: 'es', 50 | }, 51 | { 52 | file: 'dist/index.cjs', 53 | format: 'cjs', 54 | }, 55 | ], 56 | plugins, 57 | external, 58 | }, 59 | ] 60 | -------------------------------------------------------------------------------- /packages/react-renderer/src/adapter/index.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentType } from '@easy-editor/core' 2 | import type { BaseRendererComponent } from '../types' 3 | 4 | export interface RendererModules { 5 | BaseRenderer?: BaseRendererComponent 6 | PageRenderer: BaseRendererComponent 7 | ComponentRenderer: BaseRendererComponent 8 | } 9 | 10 | class Adapter { 11 | // @ts-ignore 12 | renderers: RendererModules = {} 13 | 14 | setRenderers(renderers: RendererModules) { 15 | this.renderers = renderers 16 | } 17 | 18 | setBaseRenderer(BaseRenderer: BaseRendererComponent) { 19 | this.renderers.BaseRenderer = BaseRenderer 20 | } 21 | 22 | setPageRenderer(PageRenderer: BaseRendererComponent) { 23 | this.renderers.PageRenderer = PageRenderer 24 | } 25 | 26 | setComponentRenderer(ComponentRenderer: BaseRendererComponent) { 27 | this.renderers.ComponentRenderer = ComponentRenderer 28 | } 29 | 30 | getRenderers() { 31 | return (this.renderers || {}) as unknown as Record> 32 | } 33 | } 34 | 35 | export const adapter = new Adapter() 36 | -------------------------------------------------------------------------------- /packages/react-renderer/src/component.tsx: -------------------------------------------------------------------------------- 1 | import { type BaseRendererProps, logger } from '@easy-editor/renderer-core' 2 | import { baseRendererFactory } from './base' 3 | import type { BaseRendererComponent } from './types' 4 | 5 | export function componentRendererFactory(): BaseRendererComponent { 6 | const BaseRenderer = baseRendererFactory() 7 | return class CompRenderer extends BaseRenderer { 8 | static displayName = 'CompRenderer' 9 | 10 | __namespace = 'component' 11 | 12 | __afterInit(props: BaseRendererProps, ...rest: any[]) { 13 | this.__generateCtx({ 14 | component: this, 15 | }) 16 | const schema = props.__schema || {} 17 | this.state = this.__parseData(schema.state || {}) 18 | this.__initDataSource(props) 19 | this.__executeLifeCycleMethod('constructor', [props, ...rest]) 20 | } 21 | 22 | render() { 23 | const { __schema } = this.props 24 | if (this.__checkSchema(__schema)) { 25 | return '自定义组件 schema 结构异常!' 26 | } 27 | logger.log(`${CompRenderer.displayName} render - ${__schema.componentName}`) 28 | 29 | this.__generateCtx({ 30 | component: this, 31 | }) 32 | this.__render() 33 | 34 | const noContainer = this.__parseData(__schema.props?.noContainer) 35 | 36 | this.__bindCustomMethods(this.props) 37 | 38 | if (noContainer) { 39 | return this.__renderContextProvider({ compContext: this }) 40 | } 41 | 42 | const Comp = this.__getComponentView() 43 | 44 | if (!Comp) { 45 | return this.__renderContent(this.__renderContextProvider({ compContext: this })) 46 | } 47 | 48 | return this.__renderComp(Comp, { compContext: this }) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/react-renderer/src/components/FaultComponent.tsx: -------------------------------------------------------------------------------- 1 | import { type FaultComponentProps, logger } from '@easy-editor/renderer-core' 2 | import type { FC } from 'react' 3 | 4 | const FaultComponent: FC = ({ componentName = '', error }) => { 5 | logger.error(`${componentName} 组件渲染异常, 异常原因: ${(error as Error)?.message || error || '未知'}`) 6 | 7 | return ( 8 |
21 | {componentName} 组件渲染异常,请查看控制台日志 22 |
23 | ) 24 | } 25 | 26 | export default FaultComponent 27 | -------------------------------------------------------------------------------- /packages/react-renderer/src/components/NotFoundComponent.tsx: -------------------------------------------------------------------------------- 1 | import { type NotFoundComponentProps, logger } from '@easy-editor/renderer-core' 2 | import type { FC } from 'react' 3 | 4 | const NotFoundComponent: FC = ({ componentName = '', enableStrictNotFoundMode, children }) => { 5 | logger.warn(`Component ${componentName} not found`) 6 | 7 | if (enableStrictNotFoundMode) { 8 | return <>{`${componentName} Component Not Found`} 9 | } 10 | 11 | return ( 12 |
25 | {/* {children || `${componentName} Component Not Found`} */} 26 | {`${componentName} Component Not Found`} 27 |
28 | ) 29 | } 30 | 31 | export default NotFoundComponent 32 | -------------------------------------------------------------------------------- /packages/react-renderer/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react' 2 | 3 | export interface RendererContext { 4 | [extra: string]: any 5 | } 6 | 7 | export const RendererContext = createContext({} as RendererContext) 8 | 9 | export const useRendererContext = () => { 10 | try { 11 | return useContext(RendererContext) 12 | } catch (error) { 13 | console.warn('useRendererContext must be used within a RendererContextProvider') 14 | } 15 | return {} as RendererContext 16 | } 17 | 18 | export function contextFactory() { 19 | let context = (window as any).__appContext 20 | if (!context) { 21 | context = createContext({}) 22 | ;(window as any).__appContext = context 23 | } 24 | return context 25 | } 26 | -------------------------------------------------------------------------------- /packages/react-renderer/src/hoc/index.ts: -------------------------------------------------------------------------------- 1 | export * from './comp' 2 | export * from './leaf' 3 | -------------------------------------------------------------------------------- /packages/react-renderer/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './adapter' 2 | export * from './base' 3 | export * from './component' 4 | export * from './context' 5 | export * from './hoc' 6 | export * from './page' 7 | export * from './renderer' 8 | export * from './setting-renderer' 9 | export * from './types' 10 | export * from './utils' 11 | -------------------------------------------------------------------------------- /packages/react-renderer/src/setting-renderer/context.ts: -------------------------------------------------------------------------------- 1 | import type { Setters, SettingsManager } from '@easy-editor/core' 2 | import type { SettingRendererProps } from '@easy-editor/renderer-core' 3 | import { createContext, useContext } from 'react' 4 | 5 | export interface SettingRendererContext extends SettingRendererProps { 6 | setters: Setters 7 | settingsManager: SettingsManager 8 | } 9 | 10 | export const SettingRendererContext = createContext({} as SettingRendererContext) 11 | 12 | export const useSettingRendererContext = () => { 13 | try { 14 | return useContext(SettingRendererContext) 15 | } catch (error) { 16 | console.warn('useSettingRendererContext must be used within a SettingRendererContextProvider') 17 | } 18 | return {} as SettingRendererContext 19 | } 20 | -------------------------------------------------------------------------------- /packages/react-renderer/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | BaseRendererProps, 3 | BaseRendererComponent as IBaseRendererComponent, 4 | BaseRendererContext as IBaseRendererContext, 5 | BaseRendererInstance as IBaseRendererInstance, 6 | RendererComponent as IRendererComponent, 7 | RendererComponentInstance as IRendererComponentInstance, 8 | RendererProps, 9 | RendererState, 10 | } from '@easy-editor/renderer-core' 11 | import type { Component } from 'react' 12 | 13 | export type RendererComponent = IRendererComponent> 14 | 15 | export type RendererComponentInstance = IRendererComponentInstance> 16 | 17 | export type BaseRendererContext = IBaseRendererContext, any>> 18 | 19 | export type BaseRendererComponent = IBaseRendererComponent, any>> 20 | 21 | export type BaseRendererInstance = IBaseRendererInstance, any>> 22 | -------------------------------------------------------------------------------- /packages/react-renderer/src/utils/hoc.ts: -------------------------------------------------------------------------------- 1 | import { createElement } from 'react' 2 | 3 | import { forwardRef } from 'react' 4 | 5 | const excludePropertyNames = [ 6 | '$$typeof', 7 | 'render', 8 | 'defaultProps', 9 | 'props', 10 | 'length', 11 | 'prototype', 12 | 'name', 13 | 'caller', 14 | 'callee', 15 | 'arguments', 16 | ] 17 | 18 | export const cloneEnumerableProperty = (target: any, origin: any, excludes = excludePropertyNames) => { 19 | const compExtraPropertyNames = Object.keys(origin).filter(d => !excludes.includes(d)) 20 | 21 | compExtraPropertyNames.forEach((d: string) => { 22 | ;(target as any)[d] = origin[d] 23 | }) 24 | 25 | return target 26 | } 27 | 28 | export const createForwardRefHocElement = (Wrapper: any, Comp: any) => { 29 | const WrapperComponent = cloneEnumerableProperty( 30 | forwardRef((props: any, ref: any) => { 31 | return createElement(Wrapper, { ...props, forwardRef: ref }) 32 | }), 33 | Comp, 34 | ) 35 | WrapperComponent.displayName = Comp.displayName 36 | 37 | return WrapperComponent 38 | } 39 | -------------------------------------------------------------------------------- /packages/react-renderer/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hoc' 2 | export * from './is' 3 | -------------------------------------------------------------------------------- /packages/react-renderer/src/utils/is.ts: -------------------------------------------------------------------------------- 1 | import { Component, type ComponentClass, type ComponentType } from 'react' 2 | 3 | export const isReactClass = (obj: any): obj is ComponentClass => { 4 | return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component) 5 | } 6 | 7 | export const isReactComponent = (obj: any): obj is ComponentType => { 8 | return obj && (isReactClass(obj) || typeof obj === 'function') 9 | } 10 | -------------------------------------------------------------------------------- /packages/react-renderer/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist", 6 | "skipLibCheck": true 7 | }, 8 | "include": ["./src"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/react-renderer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"], 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-renderer/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test", "./web/test", "./store/test"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/renderer-core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @easy-editor/renderer-core 2 | 3 | ## 1.0.2 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [638425a] 8 | - Updated dependencies [5afd68c] 9 | - @easy-editor/core@1.0.2 10 | 11 | ## 1.0.1 12 | 13 | ### Patch Changes 14 | 15 | - Updated dependencies [7ffae3c] 16 | - Updated dependencies [90c6910] 17 | - Updated dependencies [49ef13e] 18 | - @easy-editor/core@1.0.1 19 | 20 | ## 1.0.0 21 | 22 | ### Major Changes 23 | 24 | - 262342d: V1.0.0 25 | 26 | - Core architecture refactoring, optimized plugin architecture, improved modularity and extensibility 27 | - Refactored renderer, extracted and added renderer core renderer-core 28 | - Added data source plugin plugin-datasource 29 | - Improved Dashboard plugin, supporting element positioning, grouping and guidelines 30 | - API changes: createEasyEditor → init, ComponentMetaManager → Materials, PluginManager → Plugins, SetterManager → Setters, ... 31 | - Other bug fixes... 32 | 33 | ### Patch Changes 34 | 35 | - Updated dependencies [262342d] 36 | - @easy-editor/core@1.0.0 37 | -------------------------------------------------------------------------------- /packages/renderer-core/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import nodeResolve from '@rollup/plugin-node-resolve' 4 | import cleanup from 'rollup-plugin-cleanup' 5 | import pkg from './package.json' assert { type: 'json' } 6 | 7 | const external = [...Object.keys(pkg.peerDependencies)] 8 | 9 | const plugins = [ 10 | nodeResolve({ 11 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 12 | }), 13 | commonjs(), 14 | babel({ 15 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 16 | exclude: 'node_modules/**', 17 | babelrc: false, 18 | babelHelpers: 'bundled', 19 | presets: [ 20 | ['@babel/preset-react', { runtime: 'automatic' }], 21 | [ 22 | '@babel/preset-typescript', 23 | { 24 | allowDeclareFields: true, 25 | }, 26 | ], 27 | ], 28 | plugins: [ 29 | [ 30 | '@babel/plugin-proposal-decorators', 31 | { 32 | version: '2023-11', 33 | }, 34 | ], 35 | ], 36 | }), 37 | cleanup({ 38 | comments: ['some', /PURE/], 39 | extensions: ['.js', '.ts'], 40 | }), 41 | ] 42 | 43 | export default [ 44 | { 45 | input: 'src/index.ts', 46 | output: [ 47 | { 48 | file: 'dist/index.js', 49 | format: 'es', 50 | }, 51 | { 52 | file: 'dist/index.cjs', 53 | format: 'cjs', 54 | }, 55 | ], 56 | plugins, 57 | external, 58 | }, 59 | ] 60 | -------------------------------------------------------------------------------- /packages/renderer-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | export * from './utils' 3 | -------------------------------------------------------------------------------- /packages/renderer-core/src/types/components.ts: -------------------------------------------------------------------------------- 1 | import type { NodeSchema } from '@easy-editor/core' 2 | 3 | /** 4 | * Minimal framework-agnostic component interface 5 | * Contains only essential shared properties across frameworks 6 | */ 7 | export interface GeneralComponent

, S = Record, SS = any> { 8 | readonly props: Readonly

& Readonly<{ children?: any | undefined }> 9 | state: Readonly 10 | refs: Record 11 | context: any 12 | setState( 13 | state: ((prevState: Readonly, props: Readonly

) => Pick | S | null) | (Pick | S | null), 14 | callback?: () => void, 15 | ): void 16 | forceUpdate(callback?: () => void): void 17 | render?(): any 18 | } 19 | 20 | export interface FaultComponentProps extends NodeSchema { 21 | error?: Error | string 22 | } 23 | 24 | export interface NotFoundComponentProps extends NodeSchema { 25 | enableStrictNotFoundMode?: boolean 26 | } 27 | -------------------------------------------------------------------------------- /packages/renderer-core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components' 2 | export * from './renderer' 3 | export * from './setting-renderer' 4 | -------------------------------------------------------------------------------- /packages/renderer-core/src/types/setting-renderer.ts: -------------------------------------------------------------------------------- 1 | import type { Component, Designer, SettingField } from '@easy-editor/core' 2 | 3 | export interface SettingRendererProps { 4 | designer: Designer 5 | 6 | /** 自定义渲染 Field Item */ 7 | customFieldItem?: (field: SettingField, setter: Component) => Component 8 | 9 | /** 自定义渲染 Field Group */ 10 | customFieldGroup?: (field: SettingField, setters: Component) => Component 11 | 12 | [extra: string]: any 13 | } 14 | -------------------------------------------------------------------------------- /packages/renderer-core/src/utils/classnames.ts: -------------------------------------------------------------------------------- 1 | export const classnames = (...args: any[]) => { 2 | return args.filter(Boolean).join(' ') 3 | } 4 | -------------------------------------------------------------------------------- /packages/renderer-core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './classnames' 2 | export * from './common' 3 | export * from './data-helper' 4 | export * from './logger' 5 | export * from './request' 6 | -------------------------------------------------------------------------------- /packages/renderer-core/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import { createLogger } from '@easy-editor/core' 2 | 3 | export const logger = createLogger('Renderer') 4 | -------------------------------------------------------------------------------- /packages/renderer-core/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "strictPropertyInitialization": false, 5 | "outDir": "./dist", 6 | "skipLibCheck": true 7 | }, 8 | "include": ["./src"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/renderer-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "include": ["./src", "./test"], 4 | } 5 | -------------------------------------------------------------------------------- /packages/renderer-core/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | }, 6 | "include": ["./test", "./web/test", "./store/test"] 7 | } 8 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - examples/* 4 | - docs 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDeclarationOnly": true, 4 | "declaration": true, 5 | "target": "ESNext", 6 | "newLine": "LF", 7 | "module": "ESNext", 8 | "moduleResolution": "Bundler", 9 | "strict": true, 10 | "jsx": "preserve" 11 | }, 12 | "exclude": ["node_modules", "dist"] 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "target": "ESNext", 5 | "module": "NodeNext", 6 | "moduleResolution": "NodeNext", 7 | "strict": true, 8 | "lib": ["dom", "esnext", "dom.iterable"], 9 | "jsx": "preserve", 10 | // Necessary due to picocolors using weird export syntax. 11 | // This can be removed if the following issue gets fixed: 12 | // https://github.com/alexeyraspopov/picocolors/issues/50 13 | "allowSyntheticDefaultImports": true, 14 | // Allows TS to see the Vitest globals 15 | "types": ["vitest/globals"] 16 | }, 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "ui": "tui", 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 8 | "outputs": ["dist/**", ".next/**", "!.next/cache/**"], 9 | "cache": false 10 | }, 11 | "dev": { 12 | "cache": false, 13 | "persistent": true 14 | }, 15 | "lint": { 16 | "dependsOn": ["^lint"] 17 | }, 18 | "format": { 19 | "dependsOn": ["^format"] 20 | }, 21 | "types": { 22 | "dependsOn": ["^types"], 23 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 24 | "outputs": ["dist/**", ".next/**", "!.next/cache/**"], 25 | "cache": false 26 | }, 27 | "test-types": { 28 | "dependsOn": ["^test-types"] 29 | }, 30 | "test": { 31 | "dependsOn": ["^test"] 32 | } 33 | } 34 | } 35 | --------------------------------------------------------------------------------