├── .changelogrc.js ├── .commitlintrc.js ├── .dumirc.ts ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .fatherrc.ts ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── workflows │ ├── deploy.yml │ ├── preview.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .gitpod.yml ├── .husky ├── commit-msg └── pre-commit ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .releaserc.js ├── .stylelintrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README.zh-CN.md ├── docs ├── apiDocs │ ├── demos │ │ ├── css │ │ │ └── viewer.style.ts │ │ ├── data │ │ │ └── viewer.ts │ │ └── useFlowView.tsx │ ├── useFlowEditor.zh-CN.md │ └── useFlowViewer.zh-CN.md ├── caseShow │ ├── cicdPipeLine.md │ ├── dataFlow.md │ ├── demos │ │ ├── dataflow │ │ │ ├── data.tsx │ │ │ ├── helper.ts │ │ │ ├── index.tsx │ │ │ └── styled.ts │ │ ├── index.style.ts │ │ ├── pipeline │ │ │ ├── multiPipe │ │ │ │ ├── data.tsx │ │ │ │ ├── pipeNode.tsx │ │ │ │ └── pipelineDemo.tsx │ │ │ ├── taskPipeline │ │ │ │ ├── data.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── nodes │ │ │ │ │ ├── stageNode.tsx │ │ │ │ │ ├── styled.ts │ │ │ │ │ ├── taskContent.tsx │ │ │ │ │ └── taskNode.tsx │ │ │ │ └── styled.ts │ │ │ └── techPipe │ │ │ │ ├── data.ts │ │ │ │ ├── pipeNode.tsx │ │ │ │ ├── techPipeLine.style.ts │ │ │ │ └── techPipeline.tsx │ │ ├── pressureTest.tsx │ │ ├── tinaFlow │ │ │ ├── comp │ │ │ │ ├── box │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── comp │ │ │ │ │ └── index.tsx │ │ │ │ ├── ctx.tsx │ │ │ │ ├── group │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── icon │ │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ └── workflow │ │ │ ├── index.tsx │ │ │ ├── nodes │ │ │ ├── network.tsx │ │ │ └── textNode.tsx │ │ │ ├── sidebar.tsx │ │ │ └── styled.ts │ ├── pipeline.md │ ├── presureTest.md │ ├── techPileline.md │ └── workFlow.md ├── changelog.md ├── guide │ ├── autoLayout.zh-CN.md │ ├── baseIntro.zh-CN.md │ ├── briefIntro.zh-CN.md │ ├── customEdge.zh-CN.md │ ├── customNode.zh-CN.md │ ├── demos │ │ ├── autoLayout │ │ │ ├── data │ │ │ │ ├── demo1data.ts │ │ │ │ └── demo2data.ts │ │ │ ├── demo1.tsx │ │ │ ├── demo2.tsx │ │ │ └── index.style.ts │ │ ├── baseIntro │ │ │ ├── coreEdge.tsx │ │ │ ├── coreHandle.tsx │ │ │ ├── coreNode.tsx │ │ │ ├── css │ │ │ │ ├── customerNode.style.ts │ │ │ │ └── index.style.ts │ │ │ ├── customerNode.tsx │ │ │ └── data │ │ │ │ └── coreEdgeData.ts │ │ ├── customEdge │ │ │ ├── ButtonEdge.tsx │ │ │ ├── btn.style.ts │ │ │ ├── data.ts │ │ │ └── index.tsx │ │ ├── customNode │ │ │ ├── components │ │ │ │ ├── CustomNode.tsx │ │ │ │ └── custom.style.ts │ │ │ ├── css │ │ │ │ ├── index.style.ts │ │ │ │ └── multi.style.ts │ │ │ ├── data │ │ │ │ ├── index.ts │ │ │ │ └── multi.ts │ │ │ ├── index.tsx │ │ │ └── multiHandle.tsx │ │ ├── flowEditor │ │ │ ├── EditorNode.tsx │ │ │ ├── StringNode.tsx │ │ │ ├── base.tsx │ │ │ ├── btnGroup.tsx │ │ │ ├── css │ │ │ │ ├── dragAddNode.style.ts │ │ │ │ ├── index.style.ts │ │ │ │ ├── probase.style.ts │ │ │ │ └── sidebar.style.ts │ │ │ ├── dragAddNode.tsx │ │ │ ├── editFlowDemo.tsx │ │ │ ├── proBase.tsx │ │ │ └── sidebar.tsx │ │ ├── flowViewIntro │ │ │ ├── autoFlow.tsx │ │ │ ├── baseMiniMap.tsx │ │ │ ├── css │ │ │ │ └── index.style.ts │ │ │ ├── data │ │ │ │ ├── data.ts │ │ │ │ ├── data2.tsx │ │ │ │ └── data3.ts │ │ │ ├── dragableNode.tsx │ │ │ ├── groupNode.tsx │ │ │ ├── noAutoFlow.tsx │ │ │ └── noMiniMap.tsx │ │ └── quickUse │ │ │ ├── baseFlow.tsx │ │ │ ├── css │ │ │ └── index.style.ts │ │ │ ├── data.ts │ │ │ ├── emptyFLow.tsx │ │ │ └── selectFlow.tsx │ ├── flowEditor.zh-CN.md │ ├── flowViewIntro.zh-CN.md │ ├── installUse.zh-CN.md │ └── quickUse.zh-CN.md └── index.md ├── package.json ├── src ├── Background │ ├── components │ │ └── SwimBg.tsx │ ├── demos │ │ ├── double.tsx │ │ ├── index.tsx │ │ └── swim.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── BasicGroupNode │ ├── constants.ts │ ├── demos │ │ ├── data.ts │ │ └── index.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── styles.ts ├── BasicNode │ ├── demos │ │ ├── DataViewList.tsx │ │ └── default │ │ │ ├── data.tsx │ │ │ └── index.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── styles.ts ├── CanvasLoading │ ├── demos │ │ ├── _Content.tsx │ │ └── index.tsx │ ├── index.md │ └── index.tsx ├── ControlInput │ ├── demos │ │ └── index.tsx │ ├── index.tsx │ └── index.txt ├── EditNode │ ├── CollapseContext.tsx │ ├── demos │ │ ├── FieldCollapse.tsx │ │ ├── Preview.tsx │ │ └── PreviewField.tsx │ ├── index.md │ └── index.tsx ├── EditableText │ ├── demos │ │ └── index.tsx │ ├── index.tsx │ └── index.txt ├── FlowEditor │ ├── container │ │ ├── FlowEditor.tsx │ │ ├── FlowEditorProvider.tsx │ │ ├── StoreUpdater │ │ │ ├── Common.tsx │ │ │ └── index.tsx │ │ └── index.tsx │ ├── demos │ │ ├── index.style.ts │ │ └── index.tsx │ ├── features │ │ ├── ContextMenu │ │ │ ├── index.tsx │ │ │ └── useMenuAction.tsx │ │ └── ControlAction │ │ │ └── index.tsx │ ├── hooks │ │ ├── useFlowEditor.ts │ │ └── useHotkeyManager.ts │ ├── index.ts │ ├── index.zh-CN.md │ ├── store │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── initialState.ts │ │ ├── reducers │ │ │ ├── __snapshots__ │ │ │ │ └── edge.test.ts.snap │ │ │ ├── edge.test.ts │ │ │ ├── edge.ts │ │ │ ├── node.test.ts │ │ │ └── node.ts │ │ ├── selectors.ts │ │ └── slices │ │ │ ├── edgesSlice.ts │ │ │ ├── generalActionSlice.ts │ │ │ ├── index.ts │ │ │ └── nodesSlice.ts │ ├── types │ │ ├── index.ts │ │ ├── meta.ts │ │ └── node.ts │ └── utils │ │ ├── convertChange.ts │ │ ├── edge.test.ts │ │ ├── edge.ts │ │ ├── memoEqual.ts │ │ ├── merge.ts │ │ ├── nodeTree.ts │ │ ├── uuid.ts │ │ └── yjs.ts ├── FlowPanel │ ├── demos │ │ └── index.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── FlowStoreProvider │ ├── demos │ │ └── FlowStoreProvider.tsx │ ├── index.tsx │ └── index.txt ├── FlowView │ ├── FlowView.tsx │ ├── components │ │ └── DefaultNode.tsx │ ├── constants.tsx │ ├── demos │ │ ├── CustomerNode.tsx │ │ ├── ProFlowDemo.tsx │ │ ├── data.tsx │ │ └── index.style.ts │ ├── helper.tsx │ ├── hooks │ │ ├── useFlowState.ts │ │ └── useFlowView.ts │ ├── index.tsx │ ├── index.zh-CN.md │ ├── provider │ │ ├── FlowViewProvider.tsx │ │ └── provider.ts │ └── styles.tsx ├── Input │ ├── index.tsx │ └── style.ts ├── Inspector │ ├── demos │ │ └── index.tsx │ ├── index.style.ts │ ├── index.tsx │ └── index.zh-CN.md ├── MiniMap │ ├── demos │ │ └── FlowControllerDemo.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── NodeField │ ├── demos │ │ ├── actions.tsx │ │ └── index.tsx │ ├── index.tsx │ └── index.txt ├── RadiusEdge │ ├── demos │ │ └── index.tsx │ └── index.tsx ├── constants.tsx ├── index.ts └── utils │ └── index.ts ├── testDagre.js ├── tests └── test-setup.ts ├── tsconfig-check.json ├── tsconfig.json └── vitest.config.ts /.changelogrc.js: -------------------------------------------------------------------------------- 1 | // 详情配置查看 https://github.com/arvinxx/gitmoji-commit-workflow/tree/master/packages/changelog#readme 2 | module.exports = { 3 | displayTypes: ['feat', 'fix', 'styles', 'pref', 'build'], 4 | titleLanguage: 'zh-CN', 5 | showAuthor: true, 6 | showAuthorAvatar: true, 7 | showSummary: true, 8 | reduceHeadingLevel: true, 9 | newlineTimestamp: true, 10 | addBackToTop: true, 11 | }; 12 | -------------------------------------------------------------------------------- /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['gitmoji'], 3 | rules: { 4 | 'footer-leading-blank': [1, 'always'], 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /.dumirc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'dumi'; 2 | import { homepage } from './package.json'; 3 | 4 | const isProd = process.env.NODE_ENV === 'production'; 5 | 6 | // 不是预览模式 同时是生产环境 7 | const isProdSite = process.env.PREVIEW !== '1' && isProd; 8 | 9 | export default defineConfig({ 10 | outputPath: 'docs-dist', 11 | favicons: [ 12 | 'https://mdn.alipayobjects.com/huamei_d2ejos/afts/img/A*j10nRoiMh0MAAAAAAAAAAAAADvl6AQ/original', 13 | ], 14 | themeConfig: { 15 | name: 'ProFlow', 16 | logo: 'https://mdn.alipayobjects.com/huamei_d2ejos/afts/img/A*j10nRoiMh0MAAAAAAAAAAAAADvl6AQ/original', 17 | socialLinks: { 18 | github: homepage, 19 | }, 20 | footer: 'Made with ❤️ by 蚂蚁集团 - AFX & 数字科技', 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /lambda/mock/** 2 | /scripts 3 | /config 4 | /example 5 | _test_ 6 | __test__ 7 | 8 | /node_modules 9 | jest* 10 | /es 11 | /lib 12 | /docs 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@umijs/lint/dist/config/eslint'); 2 | -------------------------------------------------------------------------------- /.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | esm: { output: 'es' }, 5 | }); 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '报告Bug 🐛' 3 | about: 报告 pro-flow-editor 的 bug 4 | title: '🐛[BUG]' 5 | labels: '🐛 BUG' 6 | assignees: '' 7 | --- 8 | 9 | ### 🐛 bug 描述 10 | 11 | 14 | 15 | ### 📷 复现步骤 16 | 17 | 20 | 21 | ### 🏞 期望结果 22 | 23 | 26 | 27 | ### 💻 复现代码 28 | 29 | 33 | 34 | [可复现 demo](https://codesandbox.io/s/html2ksetch-demo-m53be?file=/src/Demo.tsx) 35 | 36 | ### © 版本信息 37 | 38 | - pro-flow-editor 版本: [e.g. 1.0.0] 39 | - 浏览器环境 40 | - 开发环境 [e.g. mac OS] 41 | 42 | ### 🚑 其他信息 43 | 44 | 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '功能需求 ✨' 3 | about: 对 pro-flow-editor 的需求或建议 4 | title: '👑 [需求]' 5 | labels: '👑 Feature' 6 | assignees: '' 7 | --- 8 | 9 | ### 🥰 需求描述 10 | 11 | 14 | 15 | ### 🧐 解决方案 16 | 17 | 20 | 21 | ### 🚑 其他信息 22 | 23 | 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '疑问或需要帮助 ❓' 3 | about: 对 pro-flow-editor 使用的疑问或需要帮助 4 | title: '🧐[问题]' 5 | labels: '🧐 Question' 6 | assignees: '' 7 | --- 8 | 9 | ### 🧐 问题描述 10 | 11 | 14 | 15 | ### 💻 示例代码 16 | 17 | 20 | 21 | ### 🚑 其他信息 22 | 23 | 26 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build-and-deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 🛎️ 13 | uses: actions/checkout@v3 14 | 15 | - name: Install pnpm 16 | uses: pnpm/action-setup@v2 17 | with: 18 | version: 8 19 | 20 | - name: Setup Node.js environment 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: '18' 24 | 25 | - name: Install and Build 🔧 26 | run: | 27 | pnpm i 28 | pnpm run lint 29 | pnpm run docs:build 30 | 31 | - name: Deploy 🚀 32 | uses: JamesIves/github-pages-deploy-action@v4 33 | with: 34 | token: ${{ secrets.GITHUB_TOKEN }} 35 | branch: gh-pages # The branch the action should deploy to. 36 | folder: docs-dist # The folder the action should deploy. 37 | clean: true # Automatically remove deleted files from the deploy branch 38 | -------------------------------------------------------------------------------- /.github/workflows/preview.yml: -------------------------------------------------------------------------------- 1 | name: Surge PR Preview 2 | 3 | on: 4 | pull_request: 5 | 6 | workflow_dispatch: 7 | 8 | jobs: 9 | preview: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - name: Install pnpm 15 | uses: pnpm/action-setup@v2 16 | with: 17 | version: 8 18 | 19 | - uses: afc163/surge-preview@v1 20 | id: preview_step 21 | with: 22 | surge_token: ${{ secrets.SURGE_TOKEN }} 23 | github_token: ${{ secrets.GITHUB_TOKEN }} 24 | build: | 25 | pnpm i 26 | pnpm run docs:preview 27 | dist: docs-dist 28 | 29 | - name: Get the preview_url 30 | run: echo "url => ${{ steps.preview_step.outputs.preview_url }}" 31 | 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - alpha 7 | - beta 8 | - rc 9 | 10 | jobs: 11 | test: 12 | name: Test 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Install pnpm 18 | uses: pnpm/action-setup@v2 19 | with: 20 | version: 8 21 | 22 | - name: Setup Node.js environment 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '18' 26 | 27 | - name: Install deps 28 | run: pnpm install 29 | 30 | - name: Test 31 | run: pnpm run test 32 | 33 | release: 34 | needs: test 35 | name: Release 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v3 39 | 40 | - name: Install pnpm 41 | uses: pnpm/action-setup@v2 42 | with: 43 | version: 8 44 | 45 | - name: Setup Node.js environment 46 | uses: actions/setup-node@v3 47 | with: 48 | node-version: '18' 49 | 50 | - name: Install deps 51 | run: pnpm install 52 | 53 | - name: build 54 | run: pnpm run build 55 | 56 | - name: release 57 | run: pnpm run release 58 | env: 59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 61 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test CI 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | 7 | steps: 8 | - uses: actions/checkout@v3 9 | 10 | - name: Install pnpm 11 | uses: pnpm/action-setup@v2 12 | with: 13 | version: 8 14 | 15 | - name: Setup Node.js environment 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: '18' 19 | 20 | - name: Install deps 21 | run: pnpm install 22 | 23 | - name: lint 24 | run: pnpm run ci 25 | 26 | - name: Test and coverage 27 | run: pnpm run test:coverage 28 | 29 | # - name: Upload coverage to Codecov 30 | # uses: codecov/codecov-action@v3 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | # roadhog-api-doc ignore 6 | /src/utils/request-temp.js 7 | _roadhog-api-doc 8 | 9 | # production 10 | **/dist 11 | /.vscode 12 | /es 13 | /lib 14 | 15 | # misc 16 | .DS_Store 17 | storybook-static 18 | npm-debug.log* 19 | yarn-error.log 20 | 21 | /coverage 22 | .idea 23 | package-lock.json 24 | *bak 25 | .vscode 26 | 27 | # visual studio code 28 | .history 29 | *.log 30 | functions/* 31 | lambda/mock/index.js 32 | .temp/** 33 | 34 | # umi 35 | .dumi/tmp* 36 | 37 | # screenshot 38 | screenshot 39 | .firebase 40 | example/.temp/* 41 | .eslintcache 42 | techUI* 43 | docs-dist 44 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: pnpm install 3 | command: pnpm run start 4 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit ${1} 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | lockfile=false 2 | resolution-mode=highest 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.svg 2 | .umi 3 | .umi-production 4 | /dist 5 | .dockerignore 6 | .DS_Store 7 | .eslintignore 8 | *.png 9 | *.toml 10 | docker 11 | .editorconfig 12 | Dockerfile* 13 | .gitignore 14 | .prettierignore 15 | LICENSE 16 | .eslintcache 17 | *.lock 18 | yarn-error.log 19 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pluginSearchDirs: false, 3 | plugins: [ 4 | require.resolve('prettier-plugin-organize-imports'), 5 | require.resolve('prettier-plugin-packagejson'), 6 | ], 7 | printWidth: 100, 8 | proseWrap: 'never', 9 | singleQuote: true, 10 | trailingComma: 'all', 11 | overrides: [ 12 | { 13 | files: '*.md', 14 | options: { 15 | proseWrap: 'preserve', 16 | }, 17 | }, 18 | ], 19 | }; 20 | -------------------------------------------------------------------------------- /.releaserc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['semantic-release-config-gitmoji'], 3 | }; 4 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@umijs/lint/dist/config/stylelint'); 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Arvin Xu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/apiDocs/demos/css/viewer.style.ts: -------------------------------------------------------------------------------- 1 | import { createStyles } from 'antd-style'; 2 | 3 | const useStyles = createStyles(() => { 4 | return { 5 | container: { 6 | width: '100%', 7 | height: '500px', 8 | }, 9 | }; 10 | }); 11 | export default useStyles; 12 | -------------------------------------------------------------------------------- /docs/apiDocs/demos/data/viewer.ts: -------------------------------------------------------------------------------- 1 | export const nodes = [ 2 | { 3 | id: 'a1', 4 | data: { 5 | title: 'a1 节点', 6 | logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', 7 | describe: 'XXX_XXX_XXX_API', 8 | }, 9 | }, 10 | { 11 | id: 'a2', 12 | data: { 13 | title: 'XXX_API_b4', 14 | logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', 15 | describe: 'XXX_XXX_XXX_API', 16 | }, 17 | }, 18 | { 19 | id: 'a3', 20 | data: { 21 | title: 'XXX_API_b4', 22 | logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', 23 | describe: 'XXX_XXX_XXX_API', 24 | }, 25 | }, 26 | ]; 27 | 28 | export const edges = [ 29 | { 30 | id: 'a1-a2', 31 | source: 'a1', 32 | target: 'a2', 33 | }, 34 | { 35 | id: 'a1-a3', 36 | source: 'a1', 37 | target: 'a3', 38 | type: 'radius', 39 | }, 40 | ]; 41 | -------------------------------------------------------------------------------- /docs/apiDocs/demos/useFlowView.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FlowPanel, 3 | FlowView, 4 | FlowViewProvider, 5 | SelectType, 6 | useFlowViewer, 7 | } from '@ant-design/pro-flow'; 8 | import { Button } from 'antd'; 9 | import useStyles from './css/viewer.style'; 10 | import { edges, nodes } from './data/viewer'; 11 | 12 | function App() { 13 | const { selectNode, selectEdges, selectNodes, zoomToNode, fullScreen } = useFlowViewer(); 14 | const { styles } = useStyles(); 15 | 16 | return ( 17 |
18 | { 20 | selectNodes(['a1', 'a2', 'a3'], SelectType.SUB_SELECT); 21 | selectNode(node.id, SelectType.SELECT); 22 | selectEdges(['a1-a2', 'a1-a3'], SelectType.SUB_SELECT); 23 | }} 24 | onPaneClick={() => { 25 | selectNodes(['a1', 'a2', 'a3'], SelectType.DEFAULT); 26 | selectEdges(['a1-a2', 'a1-a3'], SelectType.DEFAULT); 27 | }} 28 | nodes={nodes} 29 | edges={edges} 30 | > 31 | 32 |
33 | 40 | 47 | 54 | 61 |
62 |
63 |
64 |
65 | ); 66 | } 67 | 68 | function ProApp() { 69 | return ( 70 | 71 | 72 | 73 | ); 74 | } 75 | 76 | export default ProApp; 77 | -------------------------------------------------------------------------------- /docs/caseShow/cicdPipeLine.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav: 案例展示 3 | order: 100 4 | group: 5 | title: pipeLine 6 | order: 1 7 | title: CI/CD PipeLine 8 | description: 9 | --- 10 | 11 | ## Default 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/caseShow/dataFlow.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav: 3 | title: 案例展示 4 | order: 100 5 | group: 6 | title: 场景展示 7 | order: 1 8 | title: 数据流程图 9 | order: 1 10 | description: 11 | --- 12 | 13 | ## 数据流程图 14 | 15 | 案例特点: 16 | 17 | - 点击选中节点,自动高亮相关链路 18 | - 无级缩放的 label 19 | - 节点拖拽 20 | - Danger 节点链路高亮 21 | - 选中节点唤起抽屉 22 | - 点击画布或其他节点重置选中态 23 | - 初始化自动布局 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/caseShow/demos/dataflow/styled.ts: -------------------------------------------------------------------------------- 1 | import { createStyles } from 'antd-style'; 2 | 3 | const useStyles = createStyles(({ css }) => { 4 | return { 5 | dangerLogo: { 6 | width: '28px', 7 | height: '16px', 8 | background: '#ffeef1', 9 | borderRadius: '7px', 10 | marginTop: '3px', 11 | display: 'flex', 12 | justifyContent: 'center', 13 | alignItems: 'center', 14 | img: { width: '8px', height: '9px' }, 15 | }, 16 | container: css` 17 | width: 100%; 18 | height: 600px; 19 | .ant-progress-text { 20 | text-align: center !important; 21 | } 22 | `, 23 | CustomWrap: { 24 | width: '300px', 25 | height: '100px', 26 | backgroundColor: 'red', 27 | }, 28 | }; 29 | }); 30 | export default useStyles; 31 | -------------------------------------------------------------------------------- /docs/caseShow/demos/index.style.ts: -------------------------------------------------------------------------------- 1 | import { createStyles } from 'antd-style'; 2 | 3 | const useStyles = createStyles(() => { 4 | return { 5 | pipeNodeWrap: { 6 | width: '260px', 7 | minHeight: '100px', 8 | backgroundColor: 'white', 9 | padding: '16px', 10 | boxSizing: 'border-box', 11 | borderRadius: '8px', 12 | }, 13 | handle: { 14 | top: '0', 15 | }, 16 | stepTitle: { 17 | overflow: 'hidden', 18 | color: '#8c8c8c', 19 | whiteSpace: 'nowrap', 20 | textOverflow: 'ellipsis', 21 | }, 22 | pipeNode: { 23 | marginTop: '10px', 24 | width: '232px', 25 | boxSizing: 'border-box', 26 | border: '1px solid rgba(0, 0, 0, 0.08)', 27 | borderRadius: '8px', 28 | backgroundColor: 'white', 29 | }, 30 | mainBox: { 31 | width: '100%', 32 | padding: '12px', 33 | height: '70px', 34 | backgroundColor: 'white', 35 | display: 'flex', 36 | borderBottom: 'none', 37 | borderRadius: '8px', 38 | boxSizing: 'border-box', 39 | position: 'relative', 40 | }, 41 | logo: { 42 | img: { width: '16px', height: '16px', marginTop: '4px' }, 43 | }, 44 | wrap: { 45 | marginLeft: '8px', 46 | display: 'flex', 47 | flexDirection: 'column', 48 | }, 49 | title: { 50 | color: '#000', 51 | fontWeight: '500', 52 | fontSize: '14px', 53 | lineHeight: '22px', 54 | whiteSpace: 'nowrap', 55 | }, 56 | des: { 57 | marginTop: '8px', 58 | color: '#00000073', 59 | fontSize: '10px', 60 | }, 61 | children: { 62 | display: 'flex', 63 | flexDirection: 'column', 64 | alignItems: 'center', 65 | paddingBottom: '10px', 66 | }, 67 | childrenBox: { 68 | width: '200px', 69 | padding: '12px', 70 | height: '70px', 71 | backgroundColor: 'white', 72 | display: 'flex', 73 | border: '1px solid rgba(0, 0, 0, 0.08)', 74 | borderRadius: '8px', 75 | boxSizing: 'border-box', 76 | marginTop: '10px', 77 | }, 78 | container: { 79 | width: '100%', 80 | height: '600px', 81 | }, 82 | }; 83 | }); 84 | export default useStyles; 85 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/multiPipe/pipelineDemo.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | */ 4 | import { 5 | Background, 6 | FlowView, 7 | FlowViewProvider, 8 | useEdgesState, 9 | useFlowViewer, 10 | useNodesState, 11 | } from '@ant-design/pro-flow'; 12 | import { useCallback } from 'react'; 13 | import useStyles from '../../index.style'; 14 | import { edges, nodes } from './data'; 15 | import { PipeNode } from './pipeNode'; 16 | 17 | const nodeTypes = { pipeNode: PipeNode }; 18 | 19 | function App() { 20 | const flowViewer = useFlowViewer(); 21 | const { styles } = useStyles(); 22 | const [_nodes, , onNodesChange] = useNodesState([...nodes]); 23 | const [_edges, , onEdgesChange] = useEdgesState([...edges]); 24 | 25 | const handleClick = useCallback( 26 | (e, n) => { 27 | flowViewer?.zoomToNode(n.id, 1000); 28 | }, 29 | [flowViewer], 30 | ); 31 | 32 | return ( 33 |
34 | 43 | 44 | 45 |
46 | ); 47 | } 48 | 49 | function ProApp() { 50 | return ( 51 | 52 | 53 | 54 | ); 55 | } 56 | 57 | export default ProApp; 58 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/taskPipeline/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | */ 4 | 5 | import { Background, FlowView, applyEdgeChanges, applyNodeChanges } from '@ant-design/pro-flow'; 6 | import { useCallback, useState } from 'react'; 7 | import { edges, nodes } from './data'; 8 | import StageNode from './nodes/stageNode'; 9 | import TaskNode from './nodes/taskNode'; 10 | import useStyles from './styled'; 11 | 12 | const nodeTypes = { TaskNode, StageNode }; 13 | 14 | function App() { 15 | const { styles } = useStyles(); 16 | const [_nodes, setNodes] = useState(nodes); 17 | const [_edges, setEdges] = useState(edges); 18 | 19 | const onNodesChange = useCallback( 20 | (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), 21 | [setNodes], 22 | ); 23 | 24 | const onEdgesChange = useCallback( 25 | (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), 26 | [setEdges], 27 | ); 28 | 29 | return ( 30 |
31 | 42 | 43 | 44 |
45 | ); 46 | } 47 | 48 | function ProApp() { 49 | return ; 50 | } 51 | 52 | export default ProApp; 53 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/taskPipeline/nodes/stageNode.tsx: -------------------------------------------------------------------------------- 1 | import { FlowViewNode } from '@ant-design/pro-flow'; 2 | import { FC } from 'react'; 3 | import useStyles from './styled'; 4 | import TaskNode from './taskNode'; 5 | 6 | const StageNode: FC = (node) => { 7 | // const [open, setOpen] = useState(false); 8 | const { styles } = useStyles(); 9 | const { data } = node; 10 | const taskNodes = data.children; 11 | 12 | return ( 13 |
14 |
15 |
{data.title}
16 | {data.extra} 17 |
18 |
19 | {taskNodes.map((taskNode: any) => { 20 | return ; 21 | })} 22 |
23 |
24 | ); 25 | }; 26 | 27 | export default StageNode; 28 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/taskPipeline/nodes/styled.ts: -------------------------------------------------------------------------------- 1 | import { createStyles } from 'antd-style'; 2 | 3 | const useStyles = createStyles(() => { 4 | return { 5 | wrap: { 6 | width: '240px', 7 | backgroundColor: '#FAFAFA', 8 | marginBottom: '10px', 9 | borderRadius: '8px', 10 | position: 'relative', 11 | }, 12 | taskNode: { 13 | width: '240px', 14 | minHeight: '42px', 15 | backgroundColor: 'white', 16 | padding: '8px 12px', 17 | borderRadius: '8px', 18 | boxSizing: 'border-box', 19 | border: '1px solid #e8e8e8', 20 | display: 'flex', 21 | alignItems: 'center', 22 | justifyContent: 'space-between', 23 | '.title': { 24 | width: '100px', 25 | marginLeft: '10px', 26 | }, 27 | '.group': { 28 | width: '100px', 29 | display: 'flex', 30 | alignItems: 'center', 31 | justifyContent: 'space-between', 32 | 33 | '.extra': { 34 | width: '60px', 35 | }, 36 | 37 | '.span': { 38 | width: '20px', 39 | display: 'block', 40 | textAlign: 'center', 41 | }, 42 | }, 43 | }, 44 | 45 | stageNode: { 46 | width: '256px', 47 | height: ' 100%', 48 | backgroundColor: '#FAFAFA', 49 | display: 'flex', 50 | flexDirection: 'column', 51 | alignItems: 'center', 52 | borderRadius: '8px', 53 | 54 | '.wrap': { 55 | width: '100%', 56 | display: 'flex', 57 | flexWrap: 'nowrap', 58 | justifyContent: 'space-between', 59 | padding: '10px', 60 | }, 61 | 62 | '.title': { 63 | width: '100px', 64 | marginLeft: '10px', 65 | }, 66 | }, 67 | 68 | taskContent: { 69 | margin: '0', 70 | padding: '8px 12px', 71 | listStyle: 'none', 72 | border: '1px solid #f0f0f0', 73 | borderTop: 'none', 74 | '> li': { 75 | display: 'flex', 76 | alignItems: 'center', 77 | marginBottom: '8px', 78 | '> div': { 79 | marginLeft: '8px', 80 | display: 'flex', 81 | justifyContent: 'space-between', 82 | width: '100%', 83 | }, 84 | }, 85 | }, 86 | }; 87 | }); 88 | export default useStyles; 89 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/taskPipeline/nodes/taskContent.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCircleFilled, ClockCircleFilled, CloseCircleFilled } from '@ant-design/icons'; 2 | import useStyles from './styled'; 3 | 4 | export const TaskContent = () => { 5 | const { styles } = useStyles(); 6 | 7 | return ( 8 | 41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/taskPipeline/nodes/taskNode.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCircleFilled } from '@ant-design/icons'; 2 | import { Handle, Position } from '@ant-design/pro-flow'; 3 | import { useState } from 'react'; 4 | import useStyles from './styled'; 5 | 6 | export interface TaskNodeC { 7 | id: string; 8 | title: string; 9 | status: string; 10 | extra: React.JSX.Element; 11 | isOpen: boolean; 12 | children: React.JSX.Element; 13 | } 14 | 15 | const TaskNode = (props: { data: TaskNodeC }) => { 16 | const { data } = props; 17 | const [open, setOpen] = useState(data.isOpen); 18 | const { styles } = useStyles(); 19 | 20 | return ( 21 |
22 | 33 |
37 | 38 |
{data.title}
39 | {data.children && ( 40 |
44 | {data.extra &&
{data.extra}
} 45 | {data.extra && |} 46 |
setOpen(!open)}>{open ? 'on' : 'off'}
47 |
48 | )} 49 |
50 | {open && data.children} 51 | 62 |
63 | ); 64 | }; 65 | 66 | export default TaskNode; 67 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/taskPipeline/styled.ts: -------------------------------------------------------------------------------- 1 | import { createStyles } from 'antd-style'; 2 | 3 | const useStyles = createStyles(() => { 4 | return { 5 | techUIpipeNodeWrap: { 6 | width: '260px', 7 | minHeight: '100px', 8 | backgroundColor: '#f6f8fa', 9 | padding: '12px 6px', 10 | boxSizing: 'border-box', 11 | borderRadius: '8px', 12 | }, 13 | 14 | pipeNode: { 15 | width: '100%', 16 | borderRadius: '4px', 17 | backgroundColor: '#fff', 18 | paddingBottom: '12px', 19 | }, 20 | mainBox: { 21 | width: '100%', 22 | padding: '12px', 23 | height: '45px', 24 | backgroundColor: 'white', 25 | display: 'flex', 26 | borderBottom: 'none', 27 | borderRadius: '8px', 28 | boxSizing: 'border-box', 29 | position: 'relative', 30 | }, 31 | logo: { 32 | display: 'flex', 33 | alignItems: 'center', 34 | img: { width: '16px', height: '16px' }, 35 | }, 36 | title: { 37 | marginLeft: '8px', 38 | fontSize: '14px', 39 | fontWeight: '500', 40 | color: '#000', 41 | lineHeight: '22px', 42 | whiteSpace: 'nowrap', 43 | }, 44 | lineTitle: { 45 | marginLeft: '8px', 46 | fontSize: '14px', 47 | fontWeight: '500', 48 | color: '#000', 49 | lineHeight: '22px', 50 | whiteSpace: 'nowrap', 51 | }, 52 | subLogo: { 53 | position: 'absolute', 54 | right: '6px', 55 | top: '8px', 56 | img: { width: '80px', height: '25px' }, 57 | }, 58 | des: { 59 | marginTop: '16px', 60 | color: '#00000073', 61 | fontSize: '10px', 62 | }, 63 | children: { 64 | display: 'flex', 65 | flexDirection: 'column', 66 | alignItems: 'center', 67 | paddingBottom: '8px', 68 | }, 69 | childrenBox: { 70 | width: '220px', 71 | height: '30px', 72 | paddingLeft: '5px', 73 | backgroundColor: 'white', 74 | display: 'flex', 75 | alignItems: 'center', 76 | border: '1px solid #f1f1f1', 77 | borderRadius: '3px', 78 | boxSizing: 'border-box', 79 | marginTop: '3px', 80 | position: 'relative', 81 | }, 82 | wrap: { 83 | marginLeft: '8px', 84 | display: 'flex', 85 | flexDirection: 'column', 86 | }, 87 | container: { 88 | width: '100%', 89 | height: '600px', 90 | }, 91 | }; 92 | }); 93 | export default useStyles; 94 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/techPipe/pipeNode.tsx: -------------------------------------------------------------------------------- 1 | import { Handle, Position } from '@ant-design/pro-flow'; 2 | import useStyles from './techPipeLine.style'; 3 | 4 | interface PipeNodeChild { 5 | title: string; 6 | logo?: string; 7 | id: string; 8 | } 9 | 10 | interface PipeNode { 11 | title: string; 12 | logo: string; 13 | des?: string; 14 | children?: PipeNodeChild[]; 15 | } 16 | 17 | const PipeNode: FC<{ 18 | data: PipeNode; 19 | }> = ({ data }) => { 20 | const { title, des, logo, children = [] } = data; 21 | const { styles } = useStyles(); 22 | 23 | return ( 24 |
25 |
26 |
27 |
28 | 29 |
30 |
{title}
31 |
32 | 38 |
39 |
40 | 41 | {children.length > 0 && ( 42 |
43 | {children.map((item, index) => ( 44 |
45 |
46 | 54 | 55 | {item.logo && ( 56 |
57 | 58 |
59 | )} 60 | 61 |
62 |
{item.title}
63 |
64 | 72 |
73 |
74 | ))} 75 |
76 | )} 77 | 78 | {des &&
{des}
} 79 |
80 |
81 | ); 82 | }; 83 | 84 | export default PipeNode; 85 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/techPipe/techPipeLine.style.ts: -------------------------------------------------------------------------------- 1 | import { createStyles } from 'antd-style'; 2 | 3 | const useStyles = createStyles(() => { 4 | return { 5 | techUIpipeNodeWrap: { 6 | width: '260px', 7 | minHeight: '100px', 8 | backgroundColor: '#f6f8fa', 9 | padding: '12px 6px', 10 | boxSizing: 'border-box', 11 | borderRadius: '8px', 12 | }, 13 | 14 | pipeNode: { 15 | width: '100%', 16 | borderRadius: '4px', 17 | backgroundColor: '#fff', 18 | paddingBottom: '12px', 19 | }, 20 | mainBox: { 21 | width: '100%', 22 | padding: '12px', 23 | height: '45px', 24 | backgroundColor: 'white', 25 | display: 'flex', 26 | borderBottom: 'none', 27 | borderRadius: '8px', 28 | boxSizing: 'border-box', 29 | position: 'relative', 30 | }, 31 | logo: { 32 | display: 'flex', 33 | alignItems: 'center', 34 | img: { width: '16px', height: '16px' }, 35 | }, 36 | title: { 37 | marginLeft: '8px', 38 | fontSize: '14px', 39 | fontWeight: '500', 40 | color: '#000', 41 | lineHeight: '22px', 42 | whiteSpace: 'nowrap', 43 | }, 44 | lineTitle: { 45 | marginLeft: '8px', 46 | fontSize: '14px', 47 | fontWeight: '500', 48 | color: '#000', 49 | lineHeight: '22px', 50 | whiteSpace: 'nowrap', 51 | }, 52 | subLogo: { 53 | position: 'absolute', 54 | right: '6px', 55 | top: '8px', 56 | img: { width: '80px', height: '25px' }, 57 | }, 58 | des: { 59 | marginTop: '16px', 60 | color: '#00000073', 61 | fontSize: '10px', 62 | }, 63 | children: { 64 | display: 'flex', 65 | flexDirection: 'column', 66 | alignItems: 'center', 67 | paddingBottom: '8px', 68 | }, 69 | childrenBox: { 70 | width: '220px', 71 | height: '30px', 72 | paddingLeft: '5px', 73 | backgroundColor: 'white', 74 | display: 'flex', 75 | alignItems: 'center', 76 | border: '1px solid #f1f1f1', 77 | borderRadius: '3px', 78 | boxSizing: 'border-box', 79 | marginTop: '3px', 80 | position: 'relative', 81 | }, 82 | wrap: { 83 | marginLeft: '8px', 84 | display: 'flex', 85 | flexDirection: 'column', 86 | }, 87 | container: { 88 | width: '100%', 89 | height: '600px', 90 | }, 91 | }; 92 | }); 93 | export default useStyles; 94 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pipeline/techPipe/techPipeline.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | */ 4 | 5 | import { 6 | Background, 7 | FlowView, 8 | FlowViewProvider, 9 | useEdgesState, 10 | useFlowViewer, 11 | useNodesState, 12 | } from '@ant-design/pro-flow'; 13 | import { useCallback } from 'react'; 14 | import { edges, nodes } from './data'; 15 | import PipeNode from './pipeNode'; 16 | import useStyles from './techPipeLine.style'; 17 | 18 | const nodeTypes = { pipeNode: PipeNode }; 19 | 20 | function App() { 21 | const flowViewer = useFlowViewer(); 22 | const { styles } = useStyles(); 23 | const [_nodes, , onNodesChange] = useNodesState([...nodes]); 24 | const [_edges, , onEdgesChange] = useEdgesState([...edges]); 25 | 26 | const handleClick = useCallback( 27 | (e, n) => { 28 | flowViewer?.zoomToNode(n.id, 1000); 29 | }, 30 | [flowViewer], 31 | ); 32 | 33 | return ( 34 |
35 | 44 | 45 | 46 |
47 | ); 48 | } 49 | 50 | function ProApp() { 51 | return ( 52 | 53 | 54 | 55 | ); 56 | } 57 | 58 | export default ProApp; 59 | -------------------------------------------------------------------------------- /docs/caseShow/demos/pressureTest.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | * defaultShowCode: true 4 | */ 5 | import { FlowEdge, FlowNode, FlowView } from '@ant-design/pro-flow'; 6 | 7 | const nodes: FlowNode[] = []; 8 | const edges: FlowEdge[] = []; 9 | 10 | nodes.push({ 11 | id: `a${0}`, 12 | data: { 13 | title: `节点${0}`, 14 | logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', 15 | describe: 'XXX_XXX_XXX_API', 16 | }, 17 | }); 18 | 19 | for (let i = 1; i < 1000; i += 1) { 20 | nodes.push({ 21 | id: `a${i}`, 22 | data: { 23 | title: `节点${i}`, 24 | logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', 25 | describe: 'XXX_XXX_XXX_API', 26 | }, 27 | }); 28 | 29 | if ((i - 1) % 10 === 0) { 30 | edges.push({ 31 | id: `a${i}-${Math.random()}-${Date.now() * Math.random()}`, 32 | source: 'a0', 33 | target: `a${i}`, 34 | }); 35 | } else { 36 | edges.push({ 37 | id: `a${i}-${Math.random()}-${Date.now() * Math.random()}`, 38 | source: `a${i - 1}`, 39 | target: `a${i}`, 40 | }); 41 | } 42 | } 43 | 44 | function App() { 45 | return ( 46 |
52 | 53 |
54 | ); 55 | } 56 | 57 | export default App; 58 | -------------------------------------------------------------------------------- /docs/caseShow/demos/tinaFlow/comp/comp/index.tsx: -------------------------------------------------------------------------------- 1 | import { Handle, Position, useFlowViewer } from '@ant-design/pro-flow'; 2 | import { FC, useState } from 'react'; 3 | import { IconFont } from '../icon'; 4 | 5 | interface CompNodeProps { 6 | className?: string; 7 | } 8 | 9 | export const CompNode: FC = function CompNode(props) { 10 | const s = useState({ height: '100px', width: '200px' }); 11 | // const { updateNodeMeta } = useFlowEditor(); 12 | const { selectNode, selectEdges, selectNodes, zoomToNode, fullScreen, instance } = 13 | useFlowViewer(); 14 | 15 | // @ts-ignore 16 | window.instance = instance; 17 | return ( 18 |
19 | 27 | compcompcompcomp 28 | { 31 | if (s[0].width === '200px') { 32 | s[1]({ height: '200px', width: '250px' }); 33 | props?.data?.onResize(250, 200); 34 | } else { 35 | s[1]({ height: '100px', width: '200px' }); 36 | props?.data?.onResize(200, 100); 37 | } 38 | console.log('props: ', props); 39 | // updateNodeMeta(props.id, "height", 200); 40 | // updateNodeMeta(props.id, "width", 250); 41 | }} 42 | /> 43 |
44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /docs/caseShow/demos/tinaFlow/comp/ctx.tsx: -------------------------------------------------------------------------------- 1 | import { FlowViewEdge, FlowViewNode, useFlowViewer } from '@ant-design/pro-flow'; 2 | import { FC, createContext, useCallback, useContext, useState } from 'react'; 3 | 4 | interface ICtx { 5 | nodes: FlowViewNode[]; 6 | edges: FlowViewEdge[]; 7 | init: (nodes: FlowViewNode[], edges: FlowViewEdge[]) => void; 8 | updateNodes: ( 9 | items: [string, Partial | ((node: FlowViewNode) => FlowViewNode)][], 10 | ) => void; 11 | removeNodes: (ids: string[]) => void; 12 | } 13 | 14 | const Ctx = createContext({ 15 | nodes: [], 16 | edges: [], 17 | init: () => {}, 18 | updateNodes: () => {}, 19 | removeNodes: () => {}, 20 | }); 21 | 22 | export const MindProvider: FC<{ children: React.ReactNode }> = ({ children }) => { 23 | const nodesState = useState([]); 24 | const edgesState = useState([]); 25 | 26 | const updateNodes = useCallback((items) => { 27 | nodesState[1]((nodes) => { 28 | const _nodes = [...nodes]; 29 | items.forEach(([id, item]) => { 30 | const idx = _nodes.findIndex((n) => n.id === id); 31 | const node = _nodes[idx]; 32 | if (node) { 33 | if (typeof item === 'function') { 34 | _nodes[idx] = { ...node, ...item(node) }; 35 | } else { 36 | _nodes[idx] = { ...node, ...item }; 37 | } 38 | } 39 | }); 40 | // @ts-ignore 41 | window.nodes = _nodes; 42 | return _nodes; 43 | }); 44 | }, []); 45 | 46 | const removeNodes = useCallback((ids) => { 47 | nodesState[1]((nodes) => { 48 | return nodes.filter((node) => !ids.includes(node.id)); 49 | }); 50 | edgesState[1]((edges) => { 51 | return edges.filter((edge) => !ids.includes(edge.source) && !ids.includes(edge.target)); 52 | }); 53 | }, []); 54 | 55 | const init = useCallback((nodes, edges) => { 56 | nodesState[1](nodes); 57 | edgesState[1](edges); 58 | }, []); 59 | 60 | return ( 61 | 64 | {children} 65 | 66 | ); 67 | }; 68 | 69 | export function useMind() { 70 | const { selectNode, selectEdges, selectNodes, zoomToNode, fullScreen, instance } = 71 | useFlowViewer(); 72 | 73 | // @ts-ignore 74 | window.instance = instance; 75 | return useContext(Ctx); 76 | } 77 | -------------------------------------------------------------------------------- /docs/caseShow/demos/tinaFlow/comp/group/index.less: -------------------------------------------------------------------------------- 1 | @w: 155px; 2 | 3 | .group { 4 | background-color: #fff; 5 | border-radius: 8px; 6 | box-shadow: 0 4px 6px -2px rgba(25, 15, 15, 0.05), 0 0 1px 0 rgba(0, 0, 0, 0.08); 7 | padding: 0 12px 16px; 8 | width: @w * 2 + 8px + 12px * 2; 9 | box-sizing: border-box; 10 | .header { 11 | display: flex; 12 | padding: 8px 0; 13 | img { 14 | width: 16px; 15 | vertical-align: middle; 16 | margin-right: 8px; 17 | } 18 | .title { 19 | flex: 1 1 auto; 20 | } 21 | } 22 | 23 | .body { 24 | display: flex; 25 | flex-wrap: wrap; 26 | gap: 8px; 27 | .item { 28 | width: @w; 29 | border: 1px solid #eee; 30 | box-sizing: border-box; 31 | border-radius: 8px; 32 | box-shadow: 0 4px 6px -2px rgba(25, 15, 15, 0.05), 0 0 1px 0 rgba(0, 0, 0, 0.08); 33 | padding: 12px 8px; 34 | .itemTitle { 35 | font-size: 14px; 36 | } 37 | .itemDesc { 38 | color: #666; 39 | font-size: 12px; 40 | } 41 | } 42 | } 43 | } 44 | 45 | .handle { 46 | top: 41.5px; 47 | left: -9px; 48 | } 49 | -------------------------------------------------------------------------------- /docs/caseShow/demos/tinaFlow/comp/group/index.tsx: -------------------------------------------------------------------------------- 1 | import { Handle, NodeProps, Position } from '@ant-design/pro-flow'; 2 | import React, { FC, useEffect } from 'react'; 3 | 4 | import { useMind } from '../ctx'; 5 | import { IconFont } from '../icon'; 6 | import './index.less'; 7 | 8 | interface GroupProps extends NodeProps { 9 | className?: string; 10 | } 11 | 12 | export const Group: FC = function Group(props) { 13 | const { updateNodes } = useMind(); 14 | 15 | const [count, setCount] = React.useState(props.data?.count); 16 | 17 | useEffect(() => { 18 | const row = Math.ceil(count / 2); 19 | updateNodes([[props.id, { height: 38.5 + row * 63 + (row - 1) * 8 + 16, width: 342 }]]); 20 | }, [count]); 21 | 22 | return ( 23 |
24 | 30 | 31 |
32 | 36 |
bizData
37 |
38 | { 41 | setCount((count) => count + 1); 42 | }} 43 | /> 44 |
45 |
46 | 47 |
48 | {new Array(count).fill('').map((item, i) => ( 49 |
50 |
SaveMoneyContainer
51 |
直塞发奖弹窗
52 |
53 | ))} 54 |
55 |
56 | ); 57 | }; 58 | -------------------------------------------------------------------------------- /docs/caseShow/demos/tinaFlow/comp/icon/index.tsx: -------------------------------------------------------------------------------- 1 | import { createFromIconfontCN } from '@ant-design/icons'; 2 | 3 | // 使用你在 iconfont.cn 上的项目URL 4 | export const IconFont = createFromIconfontCN({ 5 | scriptUrl: '//at.alicdn.com/t/a/font_4664976_ncmcql8595.js', // 示例URL 6 | }); 7 | -------------------------------------------------------------------------------- /docs/caseShow/demos/workflow/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | * defaultShowCode: true 4 | */ 5 | import { 6 | BasicNode, 7 | EditNode, 8 | FlowEditor, 9 | FlowEditorProvider, 10 | useFlowEditor, 11 | } from '@ant-design/pro-flow'; 12 | import { useCallback, useEffect } from 'react'; 13 | import { StringRender } from '/docs/guide/demos/flowEditor/StringNode'; 14 | 15 | import TextNode from './nodes/textNode'; 16 | import Sidebar from './sidebar'; 17 | import useStyles from './styled'; 18 | 19 | let id = 0; 20 | const getId = () => `node_${id++}`; 21 | 22 | const nodeTypes = { 23 | TextNode: TextNode, 24 | StringNode: StringRender, 25 | BasicNode: BasicNode, 26 | EditNode: EditNode, 27 | }; 28 | const ProFlowDemo = () => { 29 | const editor = useFlowEditor(); 30 | const { styles } = useStyles(); 31 | 32 | const onDragOver = useCallback((event) => { 33 | event.preventDefault(); 34 | event.dataTransfer.dropEffect = 'move'; 35 | }, []); 36 | 37 | const onDrop = useCallback( 38 | (event) => { 39 | event.preventDefault(); 40 | if (!editor) return; 41 | 42 | const type = event.dataTransfer.getData('application/reactflow'); 43 | if (typeof type === 'undefined' || !type) { 44 | return; 45 | } 46 | 47 | const position = editor.screenToFlowPosition({ 48 | x: event.clientX, 49 | y: event.clientY, 50 | }); 51 | const newNode = { 52 | id: getId(), 53 | type, 54 | position, 55 | content: { 56 | a: '123', 57 | }, 58 | data: { 59 | title: `${type} node`, 60 | content: '123', 61 | }, 62 | }; 63 | 64 | editor.addNode(newNode); 65 | }, 66 | [editor], 67 | ); 68 | 69 | useEffect(() => { 70 | editor.addNode({ 71 | id: 'a1', 72 | type: 'TextNode', 73 | position: { x: 200, y: 100 }, 74 | data: { 75 | title: '123', 76 | aaa: '456', 77 | }, 78 | }); 79 | }, [editor]); 80 | 81 | return ( 82 |
83 | 92 | 93 | 94 |
95 | ); 96 | }; 97 | 98 | const FlowDemo = () => { 99 | return ( 100 | 101 | 102 | 103 | ); 104 | }; 105 | 106 | export default FlowDemo; 107 | -------------------------------------------------------------------------------- /docs/caseShow/demos/workflow/nodes/network.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from 'react'; 2 | import useStyles from '../styled'; 3 | 4 | interface NetworkNode { 5 | title: string; 6 | logo: string; 7 | des?: string; 8 | } 9 | 10 | const NetworkNode: FC<{ 11 | data: NetworkNode; 12 | }> = ({ data }) => { 13 | const { styles } = useStyles(); 14 | 15 | return
; 16 | }; 17 | 18 | export default NetworkNode; 19 | -------------------------------------------------------------------------------- /docs/caseShow/demos/workflow/nodes/textNode.tsx: -------------------------------------------------------------------------------- 1 | import { Handle, Position } from '@ant-design/pro-flow'; 2 | import useStyles from '../styled'; 3 | 4 | const TextNode = () => { 5 | const { styles } = useStyles(); 6 | 7 | return ( 8 |
9 |

文本节点

10 |