diff --git a/.vscode/settings.json b/.vscode/settings.json index d3be7dea..44e7635b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -47,6 +47,7 @@ "stylelintrc": "jsonc", "*.json": "jsonc", "package.json": "json", + "*.mdc": "markdown", ".htmlhintrc": "jsonc", "htmlhintrc": "jsonc", "Procfile*": "shellscript", diff --git a/apps/docs/components/free-layout-simple/preview.tsx b/apps/docs/components/free-layout-simple/preview.tsx index de4c9117..5be86d7f 100644 --- a/apps/docs/components/free-layout-simple/preview.tsx +++ b/apps/docs/components/free-layout-simple/preview.tsx @@ -1,377 +1,14 @@ import { PreviewEditor } from '../preview-editor'; import { FreeLayoutSimple } from '.'; -const indexCode = { - code: `import { - EditorRenderer, - FreeLayoutEditorProvider, -} from '@flowgram.ai/free-layout-editor'; +import nodeRegistriesCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/node-registries.ts'; +import dataCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/initial-data.ts'; +import useEditorPropsCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/hooks/use-editor-props.tsx'; +import indexCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/editor.tsx'; +import toolsCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/components/tools.tsx'; +import nodeAddPanelCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/components/node-add-panel.tsx'; +import minimapCode from '!!raw-loader!@flowgram.ai/demo-free-layout-simple/src/components/minimap.tsx'; -import { NodeAddPanel } from './components/node-add-panel'; -import { Tools } from './components/tools' -import { Minimap } from './components/minimap' -import { useEditorProps } from './hooks/use-editor-props' -import '@flowgram.ai/free-layout-editor/index.css'; -import './index.css'; - -export const Editor = () => { - const editorProps = useEditorProps() - return ( - -
-
- - -
- - -
-
- ) -}; - `, - active: true, -}; - -const dataCode = `import { WorkflowJSON } from '@flowgram.ai/free-layout-editor'; - -export const initialData: WorkflowJSON = { - nodes: [ - { - id: 'start_0', - type: 'start', - meta: { - position: { x: 0, y: 0 }, - }, - data: { - title: 'Start', - content: 'Start content' - }, - }, - { - id: 'node_0', - type: 'custom', - meta: { - position: { x: 400, y: 0 }, - }, - data: { - title: 'Custom', - content: 'Custom node content' - }, - }, - { - id: 'end_0', - type: 'end', - meta: { - position: { x: 800, y: 0 }, - }, - data: { - title: 'End', - content: 'End content' - }, - }, - ], - edges: [ - { - sourceNodeID: 'start_0', - targetNodeID: 'node_0', - }, - { - sourceNodeID: 'node_0', - targetNodeID: 'end_0', - }, - ], -}; - - -`; - -const nodeAddPanelCode = `import React from 'react'; - -import { WorkflowDragService, useService } from '@flowgram.ai/free-layout-editor'; - -const cardkeys = ['Node1', 'Node2']; - -export const NodeAddPanel: React.FC = props => { - const startDragSerivce = useService(WorkflowDragService); - - return ( -
- {cardkeys.map(nodeType => ( -
startDragSerivce.startDragCard(nodeType, e, { - data: { - title: \`New \${nodeType}\`, - content: 'xxxx' - } - })} - > - {nodeType} -
- ))} -
- ); -}; -`; - -const useEditorPropsCode = `import { useMemo } from 'react'; - -import { - FreeLayoutProps, - WorkflowNodeProps, - WorkflowNodeRenderer, - Field, - useNodeRender -} from '@flowgram.ai/free-layout-editor'; -import { createMinimapPlugin } from '@flowgram.ai/minimap-plugin'; -import { createFreeSnapPlugin } from '@flowgram.ai/free-snap-plugin'; - -import { initialData } from '../initial-data'; -import { nodeRegistries } from '../node-registries' - -export const useEditorProps = () => useMemo( - () => ({ - /** - * Whether to enable the background - */ - background: true, - /** - * Whether it is read-only or not, the node cannot be dragged in read-only mode - */ - readonly: false, - /** - * Initial data - * 初始化数据 - */ - initialData, - /** - * Node registries - * 节点注册 - */ - nodeRegistries, - /** - * Get the default node registry, which will be merged with the 'nodeRegistries' - * 提供默认的节点注册,这个会和 nodeRegistries 做合并 - */ - getNodeDefaultRegistry(type) { - return { - type, - meta: { - defaultExpanded: true, - }, - formMeta: { - /** - * Render form - */ - render: () => <> - name="title"> - {({ field }) =>
{field.value}
} - -
- name="content"> - - -
- - } - }; - }, - materials: { - /** - * Render Node - */ - renderDefaultNode: (props: WorkflowNodeProps) => { - const { form } = useNodeRender() - return ( - - {form?.render()} - - ) - }, - }, - /** - * Content change - */ - onContentChange(ctx, event) { - // console.log('Auto Save: ', event, ctx.document.toJSON()); - }, - // /** - // * Node engine enable, you can configure formMeta in the FlowNodeRegistry - // */ - nodeEngine: { - enable: true, - }, - /** - * Redo/Undo enable - */ - history: { - enable: true, - enableChangeNode: true, // Listen Node engine data change - }, - /** - * Playground init - */ - onInit: ctx => {}, - /** - * Playground render - */ - onAllLayersRendered(ctx) { - // Fitview - ctx.document.fitView(false); - }, - /** - * Playground dispose - */ - onDispose() { - console.log('---- Playground Dispose ----'); - }, - plugins: () => [ - /** - * Minimap plugin - * 缩略图插件 - */ - createMinimapPlugin({ - disableLayer: true, - canvasStyle: { - canvasWidth: 182, - canvasHeight: 102, - canvasPadding: 50, - canvasBackground: 'rgba(245, 245, 245, 1)', - canvasBorderRadius: 10, - viewportBackground: 'rgba(235, 235, 235, 1)', - viewportBorderRadius: 4, - viewportBorderColor: 'rgba(201, 201, 201, 1)', - viewportBorderWidth: 1, - viewportBorderDashLength: 2, - nodeColor: 'rgba(255, 255, 255, 1)', - nodeBorderRadius: 2, - nodeBorderWidth: 0.145, - nodeBorderColor: 'rgba(6, 7, 9, 0.10)', - overlayColor: 'rgba(255, 255, 255, 0)', - }, - inactiveDebounceTime: 1, - }), - /** - * Snap plugin - * 自动对齐及辅助线插件 - */ - createFreeSnapPlugin({ - edgeColor: '#00B2B2', - alignColor: '#00B2B2', - edgeLineWidth: 1, - alignLineWidth: 1, - alignCrossWidth: 8, - }), - ] - }), - [], - ); - -`; - -const nodeRegistriesCode = `import { WorkflowNodeRegistry } from '@flowgram.ai/free-layout-editor'; - -/** - * You can customize your own node registry - * 你可以自定义节点的注册器 - */ -export const nodeRegistries: WorkflowNodeRegistry[] = [ - { - type: 'start', - meta: { - isStart: true, // Mark as start - deleteDisable: true, // The start node cannot be deleted - copyDisable: true, // The start node cannot be copied - defaultPorts: [{ type: 'output' }], // Used to define the input and output ports, the start node only has the output port - }, - }, - { - type: 'end', - meta: { - deleteDisable: true, - copyDisable: true, - defaultPorts: [{ type: 'input' }], - }, - }, - { - type: 'custom', - meta: { - }, - defaultPorts: [{ type: 'output' }, { type: 'input' }], // A normal node has two ports - }, -]; - -`; - -const toolsCode = `import { useEffect, useState } from 'react' -import { usePlaygroundTools, useClientContext } from '@flowgram.ai/free-layout-editor'; - -export function Tools() { - const { history } = useClientContext(); - const tools = usePlaygroundTools(); - const [canUndo, setCanUndo] = useState(false); - const [canRedo, setCanRedo] = useState(false); - - useEffect(() => { - const disposable = history.undoRedoService.onChange(() => { - setCanUndo(history.canUndo()); - setCanRedo(history.canRedo()); - }); - return () => disposable.dispose(); - }, [history]); - - return
- - - - - - - {Math.floor(tools.zoom * 100)}% -
-} -`; - -const minimapCode = `import { FlowMinimapService, MinimapRender } from '@flowgram.ai/minimap-plugin'; -import { useService } from '@flowgram.ai/free-layout-editor'; - - -export const Minimap = () => { - const minimapService = useService(FlowMinimapService); - return ( -
- -
- ); -}; - -`; export const FreeLayoutSimplePreview = () => { const files = { 'index.tsx': indexCode, diff --git a/apps/docs/package.json b/apps/docs/package.json index 774340cd..bdf1d13d 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -47,7 +47,9 @@ "devDependencies": { "@flowgram.ai/ts-config": "workspace:*", "@flowgram.ai/eslint-config": "workspace:*", + "webpack-merge": "^5.9.0", "@eslint/js": "^9.12.0", + "raw-loader": "^4.0.2", "@rspress/plugin-typedoc": "^1.38.0", "@types/node": "^18", "@types/lodash-es": "^4.17.12", diff --git a/apps/docs/rspress.config.ts b/apps/docs/rspress.config.ts index 04f48644..e15671f2 100644 --- a/apps/docs/rspress.config.ts +++ b/apps/docs/rspress.config.ts @@ -1,5 +1,6 @@ import * as path from 'node:path'; +import { merge } from 'webpack-merge'; import { defineConfig } from 'rspress/config'; export default defineConfig({ @@ -9,32 +10,46 @@ export default defineConfig({ globalStyles: path.join(__dirname, './global.less'), builderConfig: { tools: { - rspack: { - optimization: { - splitChunks: { - chunks: 'all', // 拆分所有模块,包括异步和同步 - minSize: 30 * 1024, // 30KB 以下不拆分 - maxSize: 500 * 1024, // 500KB 以上强制拆分 - minChunks: 1, // 最少被引用 1 次就可以拆分 - automaticNameDelimiter: '-', - cacheGroups: { - vendors: { - test: /[\\/]node_modules[\\/]/, - name: 'vendors', - chunks: 'all', - priority: -10, // 优先级 + rspack(options) { + return merge(options, { + module: { + rules: [ + { + test: /\.mdc$/, + type: 'asset/source', + }, + { + resourceQuery: /raw/, + type: 'asset/source', + }, + ], + }, + optimization: { + splitChunks: { + chunks: 'all', // 拆分所有模块,包括异步和同步 + minSize: 30 * 1024, // 30KB 以下不拆分 + maxSize: 500 * 1024, // 500KB 以上强制拆分 + minChunks: 1, // 最少被引用 1 次就可以拆分 + automaticNameDelimiter: '-', + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + name: 'vendors', + chunks: 'all', + priority: -10, // 优先级 + }, }, }, }, - }, - // 禁用 ES 模块输出(启用 CommonJS) - experiments: { - outputModule: false, - }, - // 允许省略文件扩展名 - resolve: { - fullySpecified: false, - }, + // 禁用 ES 模块输出(启用 CommonJS) + experiments: { + outputModule: false, + }, + // 允许省略文件扩展名 + resolve: { + fullySpecified: false, + }, + }); }, }, }, diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 6a7ddd75..1bde1617 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -494,12 +494,18 @@ importers: globals: specifier: ^15.11.0 version: 15.13.0 + raw-loader: + specifier: ^4.0.2 + version: 4.0.2(webpack@5.76.0) sucrase: specifier: 3.35.0 version: 3.35.0 typescript-eslint: specifier: ^8.8.1 version: 8.18.0(eslint@8.57.1)(typescript@5.0.4) + webpack-merge: + specifier: ^5.9.0 + version: 5.10.0 ../../config/eslint-config: dependencies: @@ -8001,6 +8007,15 @@ packages: engines: {node: '>= 12'} dev: false + /clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + dev: true + /clone-response@1.0.2: resolution: {integrity: sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==} dependencies: @@ -9479,6 +9494,11 @@ packages: keyv: 4.5.4 rimraf: 3.0.2 + /flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: true + /flatted@3.3.2: resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} @@ -10356,6 +10376,13 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + /is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: true + /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true @@ -10456,6 +10483,11 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + dev: true + /isomorphic-rslog@0.0.6: resolution: {integrity: sha512-HM0q6XqQ93psDlqvuViNs/Ea3hAyGDkIdVAHlrEocjjAwGrs1fZ+EdQjS9eUPacnYB7Y8SoDdSY3H8p3ce205A==} engines: {node: '>=14.17.6'} @@ -12585,6 +12617,17 @@ packages: dependencies: safe-buffer: 5.2.1 + /raw-loader@4.0.2(webpack@5.76.0): + resolution: {integrity: sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.76.0 + dev: true + /react-devtools-inline@4.4.0: resolution: {integrity: sha512-ES0GolSrKO8wsKbsEkVeiR/ZAaHQTY4zDh1UW8DImVmm8oaGLl3ijJDvSGe+qDRKPZdPRnDtWWnSvvrgxXdThQ==} dependencies: @@ -13524,6 +13567,13 @@ packages: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + /shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + dependencies: + kind-of: 6.0.3 + dev: true + /shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} @@ -14801,6 +14851,15 @@ packages: engines: {node: '>=12'} dev: true + /webpack-merge@5.10.0: + resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} + engines: {node: '>=10.0.0'} + dependencies: + clone-deep: 4.0.1 + flat: 5.0.2 + wildcard: 2.0.1 + dev: true + /webpack-sources@3.2.3: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} @@ -14936,6 +14995,10 @@ packages: stackback: 0.0.2 dev: true + /wildcard@2.0.1: + resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + dev: true + /word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'}