Showing preview only (7,702K chars total). Download the full file or copy to clipboard to get everything.
Repository: bytedance/flowgram.ai
Branch: main
Commit: 2511ff5cfd65
Files: 3381
Total size: 6.7 MB
Directory structure:
gitextract_ksplgn6_/
├── .claude/
│ ├── commands/
│ │ └── add-tests.md
│ └── skills/
│ ├── create-node/
│ │ ├── SKILL.md
│ │ └── templates/
│ │ ├── README.md
│ │ ├── complex-node/
│ │ │ ├── components/
│ │ │ │ └── custom-component.tsx
│ │ │ ├── form-meta.tsx
│ │ │ ├── index.tsx
│ │ │ └── types.tsx
│ │ └── simple-node/
│ │ └── index.ts
│ ├── material-component-dev/
│ │ └── SKILL.md
│ └── material-component-doc/
│ ├── SKILL.md
│ └── templates/
│ └── material.mdx
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ └── question.md
│ └── workflows/
│ ├── ci.yml
│ ├── common-pr-checks.yml
│ ├── deploy.yml
│ ├── e2e.yml
│ ├── publish-alpha.yml
│ ├── publish-app-to-version.yml
│ ├── publish-app.yml
│ ├── publish-minor.yml
│ ├── publish-to-version.yml
│ ├── publish.yml
│ └── sync-screenshot.yml
├── .gitignore
├── .vscode/
│ ├── extentions.json
│ └── settings.json
├── AGENTS.md
├── CHANGELOG.md
├── CLAUDE.md
├── CNAME
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── README_DE.md
├── README_ES.md
├── README_JA.md
├── README_PT.md
├── README_RU.md
├── README_ZH.md
├── apps/
│ ├── cli/
│ │ ├── .gitignore
│ │ ├── bin/
│ │ │ └── index.js
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── create-app/
│ │ │ │ └── index.ts
│ │ │ ├── find-materials/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── materials/
│ │ │ │ ├── copy.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── material.ts
│ │ │ │ ├── refresh-project-import.ts
│ │ │ │ ├── select.ts
│ │ │ │ └── types.ts
│ │ │ ├── update-version/
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── export.ts
│ │ │ ├── file.ts
│ │ │ ├── import.ts
│ │ │ ├── npm.ts
│ │ │ ├── project.ts
│ │ │ └── ts-file.ts
│ │ ├── tsconfig.json
│ │ └── tsup.config.js
│ ├── create-app/
│ │ ├── bin/
│ │ │ └── index.js
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── demo-fixed-layout/
│ │ ├── README.md
│ │ ├── README.zh_CN.md
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── assets/
│ │ │ │ ├── icon-mouse.tsx
│ │ │ │ └── icon-pad.tsx
│ │ │ ├── components/
│ │ │ │ ├── agent-adder/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── agent-label/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── base-node/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── branch-adder/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── drag-node/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── node-adder/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── node-list.tsx
│ │ │ │ ├── selector-box-popover/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── sidebar/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── sidebar-node-renderer.tsx
│ │ │ │ │ └── sidebar-renderer.tsx
│ │ │ │ └── tools/
│ │ │ │ ├── download.tsx
│ │ │ │ ├── fit-view.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── interactive.tsx
│ │ │ │ ├── minimap-switch.tsx
│ │ │ │ ├── minimap.tsx
│ │ │ │ ├── mouse-pad-selector.less
│ │ │ │ ├── mouse-pad-selector.tsx
│ │ │ │ ├── readonly.tsx
│ │ │ │ ├── run.tsx
│ │ │ │ ├── save.tsx
│ │ │ │ ├── styles.tsx
│ │ │ │ ├── switch-vertical.tsx
│ │ │ │ └── zoom-select.tsx
│ │ │ ├── context/
│ │ │ │ ├── index.ts
│ │ │ │ ├── node-render-context.ts
│ │ │ │ └── sidebar-context.ts
│ │ │ ├── editor.tsx
│ │ │ ├── form-components/
│ │ │ │ ├── feedback.tsx
│ │ │ │ ├── form-content/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── form-header/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ ├── title-input.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ │ ├── form-inputs/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── form-item/
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── form-outputs/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── properties-edit/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── property-edit.tsx
│ │ │ │ └── styles.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── index.ts
│ │ │ │ ├── use-editor-props.ts
│ │ │ │ ├── use-form-value.ts
│ │ │ │ ├── use-is-sidebar.ts
│ │ │ │ └── use-node-render-context.ts
│ │ │ ├── index.ts
│ │ │ ├── initial-data.ts
│ │ │ ├── nodes/
│ │ │ │ ├── agent/
│ │ │ │ │ ├── agent-llm.ts
│ │ │ │ │ ├── agent-memory.ts
│ │ │ │ │ ├── agent-tools.ts
│ │ │ │ │ ├── agent.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── memory.ts
│ │ │ │ │ └── tool.ts
│ │ │ │ ├── break-loop/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── case/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── case-default/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── catch-block/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── default-form-meta.tsx
│ │ │ │ ├── end/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── if/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── if-block/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── llm/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── loop/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── start/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── switch/
│ │ │ │ │ └── index.ts
│ │ │ │ └── trycatch/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ └── index.ts
│ │ │ ├── plugins/
│ │ │ │ ├── clipboard-plugin/
│ │ │ │ │ └── create-clipboard-plugin.ts
│ │ │ │ ├── group-plugin/
│ │ │ │ │ ├── group-box-header.tsx
│ │ │ │ │ ├── group-node.tsx
│ │ │ │ │ ├── group-note.tsx
│ │ │ │ │ ├── group-tools.tsx
│ │ │ │ │ ├── icons/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── multilang-textarea-editor/
│ │ │ │ │ ├── base-textarea.tsx
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── variable-panel-plugin/
│ │ │ │ ├── components/
│ │ │ │ │ ├── full-variable-list.tsx
│ │ │ │ │ ├── global-variable-editor.tsx
│ │ │ │ │ ├── index.module.less
│ │ │ │ │ └── variable-panel.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── variable-panel-layer.tsx
│ │ │ │ └── variable-panel-plugin.ts
│ │ │ ├── services/
│ │ │ │ ├── custom-service.ts
│ │ │ │ └── index.ts
│ │ │ ├── shortcuts/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── utils.ts
│ │ │ ├── type.d.ts
│ │ │ └── typings/
│ │ │ ├── index.ts
│ │ │ ├── json-schema.ts
│ │ │ └── node.ts
│ │ └── tsconfig.json
│ ├── demo-fixed-layout-animation/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── form-render/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── loading-dots/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── node-render/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── thinking-node/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── tools/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── minimap.tsx
│ │ │ │ └── update-schema/
│ │ │ │ ├── example-schemas.ts
│ │ │ │ ├── example.py
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── fields/
│ │ │ │ ├── content-field/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── thinking-text-field/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ └── title-field/
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── use-editor-props.tsx
│ │ │ │ └── use-node-loading.tsx
│ │ │ ├── nodes/
│ │ │ │ ├── condition/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── custom/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── thinking/
│ │ │ │ └── index.tsx
│ │ │ └── services/
│ │ │ ├── index.ts
│ │ │ └── load-schema-service/
│ │ │ ├── index.ts
│ │ │ ├── type.ts
│ │ │ └── utils.ts
│ │ └── tsconfig.json
│ ├── demo-fixed-layout-simple/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── base-node.tsx
│ │ │ │ ├── branch-adder.tsx
│ │ │ │ ├── flow-select.tsx
│ │ │ │ ├── minimap.tsx
│ │ │ │ ├── node-add-panel.tsx
│ │ │ │ ├── node-adder.tsx
│ │ │ │ ├── slot-adder.tsx
│ │ │ │ └── tools.tsx
│ │ │ ├── data/
│ │ │ │ ├── condition.ts
│ │ │ │ ├── dynamicSplit.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── loop.ts
│ │ │ │ ├── mindmap.ts
│ │ │ │ ├── multiInputs.ts
│ │ │ │ ├── multiOutputs.ts
│ │ │ │ ├── slot.ts
│ │ │ │ └── tryCatch.ts
│ │ │ ├── editor.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── use-add-node.tsx
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── index.css
│ │ │ ├── index.ts
│ │ │ ├── initial-data.ts
│ │ │ └── node-registries.ts
│ │ └── tsconfig.json
│ ├── demo-free-layout/
│ │ ├── README.md
│ │ ├── README.zh_CN.md
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── assets/
│ │ │ │ ├── icon-auto-layout.tsx
│ │ │ │ ├── icon-cancel.tsx
│ │ │ │ ├── icon-comment.tsx
│ │ │ │ ├── icon-minimap.tsx
│ │ │ │ ├── icon-mouse.tsx
│ │ │ │ ├── icon-pad.tsx
│ │ │ │ ├── icon-success.tsx
│ │ │ │ ├── icon-switch-line.tsx
│ │ │ │ └── icon-warning.tsx
│ │ │ ├── components/
│ │ │ │ ├── add-node/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── use-add-node.ts
│ │ │ │ ├── base-node/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── node-wrapper.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── comment/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── blank-area.tsx
│ │ │ │ │ │ ├── border-area.tsx
│ │ │ │ │ │ ├── container.tsx
│ │ │ │ │ │ ├── content-drag-area.tsx
│ │ │ │ │ │ ├── drag-area.tsx
│ │ │ │ │ │ ├── editor.tsx
│ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── more-button.tsx
│ │ │ │ │ │ ├── render.tsx
│ │ │ │ │ │ └── resize-area.tsx
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── use-model.ts
│ │ │ │ │ │ ├── use-overflow.ts
│ │ │ │ │ │ ├── use-placeholder.ts
│ │ │ │ │ │ └── use-size.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── model.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── group/
│ │ │ │ │ ├── color.ts
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── background.tsx
│ │ │ │ │ │ ├── color.tsx
│ │ │ │ │ │ ├── header.tsx
│ │ │ │ │ │ ├── icon-group.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── node-render.tsx
│ │ │ │ │ │ ├── tips/
│ │ │ │ │ │ │ ├── global-store.ts
│ │ │ │ │ │ │ ├── icon-close.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── is-mac-os.ts
│ │ │ │ │ │ │ ├── style.ts
│ │ │ │ │ │ │ └── use-control.ts
│ │ │ │ │ │ ├── title.tsx
│ │ │ │ │ │ ├── tools.tsx
│ │ │ │ │ │ └── ungroup.tsx
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── line-add-button/
│ │ │ │ │ ├── button.tsx
│ │ │ │ │ ├── index.less
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── use-visible.ts
│ │ │ │ ├── node-menu/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── node-panel/
│ │ │ │ │ ├── index.less
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── node-list.tsx
│ │ │ │ │ └── node-placeholder.tsx
│ │ │ │ ├── problem-panel/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── problem-panel.tsx
│ │ │ │ │ └── use-watch-validate.ts
│ │ │ │ ├── selector-box-popover/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── sidebar/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── node-form-panel.tsx
│ │ │ │ │ └── sidebar-node-renderer.tsx
│ │ │ │ ├── testrun/
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── use-fields.ts
│ │ │ │ │ │ ├── use-form-meta.ts
│ │ │ │ │ │ └── use-sync-default.ts
│ │ │ │ │ ├── json-value-editor/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── node-status-bar/
│ │ │ │ │ │ ├── group/
│ │ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── header/
│ │ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── render/
│ │ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── viewer/
│ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── testrun-button/
│ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── testrun-form/
│ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── type.ts
│ │ │ │ │ ├── testrun-json-input/
│ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── testrun-panel/
│ │ │ │ │ ├── index.module.less
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── test-run-panel.tsx
│ │ │ │ └── tools/
│ │ │ │ ├── auto-layout.tsx
│ │ │ │ ├── comment.tsx
│ │ │ │ ├── download.tsx
│ │ │ │ ├── fit-view.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── interactive.tsx
│ │ │ │ ├── minimap-switch.tsx
│ │ │ │ ├── minimap.tsx
│ │ │ │ ├── mouse-pad-selector.less
│ │ │ │ ├── mouse-pad-selector.tsx
│ │ │ │ ├── readonly.tsx
│ │ │ │ ├── save.tsx
│ │ │ │ ├── styles.tsx
│ │ │ │ ├── switch-line.tsx
│ │ │ │ └── zoom-select.tsx
│ │ │ ├── context/
│ │ │ │ ├── index.ts
│ │ │ │ ├── node-render-context.ts
│ │ │ │ └── sidebar-context.ts
│ │ │ ├── editor.tsx
│ │ │ ├── form-components/
│ │ │ │ ├── feedback.tsx
│ │ │ │ ├── form-content/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── form-header/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ ├── title-input.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ │ ├── form-inputs/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── form-item/
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── index.tsx
│ │ │ │ └── index.ts
│ │ │ ├── hooks/
│ │ │ │ ├── index.ts
│ │ │ │ ├── use-editor-props.tsx
│ │ │ │ ├── use-is-sidebar.ts
│ │ │ │ ├── use-node-render-context.ts
│ │ │ │ └── use-port-click.ts
│ │ │ ├── index.ts
│ │ │ ├── initial-data.ts
│ │ │ ├── nodes/
│ │ │ │ ├── block-end/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── block-start/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── break/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── code/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── code.tsx
│ │ │ │ │ │ ├── inputs.tsx
│ │ │ │ │ │ └── outputs.tsx
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.tsx
│ │ │ │ ├── comment/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── condition/
│ │ │ │ │ ├── condition-inputs/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── continue/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── default-form-meta.tsx
│ │ │ │ ├── end/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── group/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── http/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── api.tsx
│ │ │ │ │ │ ├── body.tsx
│ │ │ │ │ │ ├── headers.tsx
│ │ │ │ │ │ ├── params.tsx
│ │ │ │ │ │ └── timeout.tsx
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── llm/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── loop/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── multi-condition/
│ │ │ │ │ ├── condition-inputs/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── start/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ └── variable/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── types.tsx
│ │ │ ├── plugins/
│ │ │ │ ├── context-menu-plugin/
│ │ │ │ │ ├── context-menu-layer.tsx
│ │ │ │ │ ├── context-menu-plugin.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── panel-manager-plugin/
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── hooks.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── runtime-plugin/
│ │ │ │ │ ├── client/
│ │ │ │ │ │ ├── base-client.ts
│ │ │ │ │ │ ├── browser-client/
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── server-client/
│ │ │ │ │ │ ├── constant.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── type.ts
│ │ │ │ │ ├── create-runtime-plugin.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── runtime-service/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── type.ts
│ │ │ │ └── variable-panel-plugin/
│ │ │ │ ├── components/
│ │ │ │ │ ├── full-variable-list.tsx
│ │ │ │ │ ├── global-variable-editor.tsx
│ │ │ │ │ ├── index.module.less
│ │ │ │ │ └── variable-panel.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── variable-panel-layer.tsx
│ │ │ │ └── variable-panel-plugin.ts
│ │ │ ├── services/
│ │ │ │ ├── custom-service.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── validate-service.ts
│ │ │ ├── shortcuts/
│ │ │ │ ├── collapse/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── copy/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── delete/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── expand/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── paste/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── traverse.ts
│ │ │ │ │ └── unique-workflow.ts
│ │ │ │ ├── select-all/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── shortcuts.ts
│ │ │ │ ├── type.ts
│ │ │ │ ├── zoom-in/
│ │ │ │ │ └── index.ts
│ │ │ │ └── zoom-out/
│ │ │ │ └── index.ts
│ │ │ ├── styles/
│ │ │ │ └── index.css
│ │ │ ├── type.d.ts
│ │ │ ├── typings/
│ │ │ │ ├── index.ts
│ │ │ │ ├── json-schema.ts
│ │ │ │ └── node.ts
│ │ │ └── utils/
│ │ │ ├── can-contain-node.ts
│ │ │ ├── index.ts
│ │ │ ├── on-drag-line-end.ts
│ │ │ └── toggle-loop-expanded.ts
│ │ └── tsconfig.json
│ ├── demo-free-layout-simple/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── minimap.tsx
│ │ │ │ ├── node-add-panel.tsx
│ │ │ │ └── tools.tsx
│ │ │ ├── editor.tsx
│ │ │ ├── hooks/
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── initial-data.ts
│ │ │ └── nodes/
│ │ │ ├── batch/
│ │ │ │ └── index.ts
│ │ │ ├── batch-function/
│ │ │ │ ├── create-batch-function-json.ts
│ │ │ │ ├── create-batch-function-lines.ts
│ │ │ │ ├── create-batch-function.ts
│ │ │ │ ├── form-meta.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── registry.ts
│ │ │ │ └── relation.ts
│ │ │ ├── block-end/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ └── index.ts
│ │ │ ├── block-start/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ └── index.ts
│ │ │ ├── chain/
│ │ │ │ └── index.ts
│ │ │ ├── condition/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ └── index.ts
│ │ │ ├── custom/
│ │ │ │ └── index.ts
│ │ │ ├── end/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── loop/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ └── index.ts
│ │ │ ├── start/
│ │ │ │ └── index.ts
│ │ │ ├── tool/
│ │ │ │ └── index.ts
│ │ │ └── twoway/
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── demo-materials/
│ │ ├── .storybook/
│ │ │ └── main.ts
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── assets/
│ │ │ │ ├── icon-auto-layout.tsx
│ │ │ │ ├── icon-cancel.tsx
│ │ │ │ ├── icon-comment.tsx
│ │ │ │ ├── icon-minimap.tsx
│ │ │ │ ├── icon-mouse.tsx
│ │ │ │ ├── icon-pad.tsx
│ │ │ │ ├── icon-success.tsx
│ │ │ │ ├── icon-switch-line.tsx
│ │ │ │ └── icon-warning.tsx
│ │ │ ├── components/
│ │ │ │ ├── form-header/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ ├── title-input.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ │ ├── free-editor/
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ └── use-editor-props.tsx
│ │ │ │ │ ├── index.css
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── plugins/
│ │ │ │ │ └── debug-panel-plugin/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── debug-panel.tsx
│ │ │ │ │ │ ├── full-variable-list.tsx
│ │ │ │ │ │ └── workflow-json-editor.tsx
│ │ │ │ │ ├── debug-panel-layer.tsx
│ │ │ │ │ ├── debug-panel-plugin.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── free-form-meta-story-builder/
│ │ │ │ ├── constants.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── initial-data.tsx
│ │ │ │ └── utils.tsx
│ │ │ ├── index.tsx
│ │ │ ├── stories/
│ │ │ │ ├── components/
│ │ │ │ │ ├── blur-input.stories.tsx
│ │ │ │ │ ├── inputs-values-tree.stories.tsx
│ │ │ │ │ ├── json-schema-creator.stories.tsx
│ │ │ │ │ ├── sql-editor-with-variables.stories.tsx
│ │ │ │ │ └── variable-selector.stories.tsx
│ │ │ │ └── hello.stories.tsx
│ │ │ └── type.d.ts
│ │ └── tsconfig.json
│ ├── demo-nextjs/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── next.config.ts
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ ├── api/
│ │ │ │ │ └── runtime/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── globals.css
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── editor/
│ │ │ │ ├── components/
│ │ │ │ │ ├── editor-client.tsx
│ │ │ │ │ ├── editor.tsx
│ │ │ │ │ ├── form-render.tsx
│ │ │ │ │ ├── node-render.tsx
│ │ │ │ │ └── tools.tsx
│ │ │ │ ├── data/
│ │ │ │ │ ├── initial-data.ts
│ │ │ │ │ └── node-registries.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── use-editor-props.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── style/
│ │ │ │ ├── index.css
│ │ │ │ ├── theme.css
│ │ │ │ └── var.css
│ │ │ └── runtime/
│ │ │ ├── index.ts
│ │ │ ├── main.ts
│ │ │ └── models/
│ │ │ ├── index.ts
│ │ │ └── runtime/
│ │ │ ├── index.ts
│ │ │ ├── model.ts
│ │ │ └── type.ts
│ │ └── tsconfig.json
│ ├── demo-nextjs-antd/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── next-env.d.ts
│ │ ├── next.config.ts
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ ├── globals.css
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ └── editor/
│ │ │ ├── assets/
│ │ │ │ ├── icon-auto-layout.tsx
│ │ │ │ ├── icon-comment.tsx
│ │ │ │ ├── icon-minimap.tsx
│ │ │ │ ├── icon-mouse.tsx
│ │ │ │ ├── icon-pad.tsx
│ │ │ │ └── icon-switch-line.tsx
│ │ │ ├── components/
│ │ │ │ ├── base-node/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── node-wrapper.scss
│ │ │ │ │ ├── node-wrapper.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── editor-client.tsx
│ │ │ │ ├── editor.tsx
│ │ │ │ ├── form-render.tsx
│ │ │ │ ├── group/
│ │ │ │ │ ├── color.ts
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── background.tsx
│ │ │ │ │ │ ├── color.tsx
│ │ │ │ │ │ ├── header.tsx
│ │ │ │ │ │ ├── icon-group.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── node-render.tsx
│ │ │ │ │ │ ├── tips/
│ │ │ │ │ │ │ ├── global-store.ts
│ │ │ │ │ │ │ ├── icon-close.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── is-mac-os.ts
│ │ │ │ │ │ │ ├── style.ts
│ │ │ │ │ │ │ └── use-control.ts
│ │ │ │ │ │ ├── title.tsx
│ │ │ │ │ │ ├── tools.tsx
│ │ │ │ │ │ └── ungroup.tsx
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── line-add-button/
│ │ │ │ │ ├── button.tsx
│ │ │ │ │ ├── index.scss
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── use-visible.ts
│ │ │ │ ├── node-comment/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── blank-area.tsx
│ │ │ │ │ │ ├── border-area.tsx
│ │ │ │ │ │ ├── container.tsx
│ │ │ │ │ │ ├── content-drag-area.tsx
│ │ │ │ │ │ ├── drag-area.tsx
│ │ │ │ │ │ ├── editor.tsx
│ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── more-button.tsx
│ │ │ │ │ │ ├── render.tsx
│ │ │ │ │ │ └── resize-area.tsx
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── use-model.ts
│ │ │ │ │ │ ├── use-overflow.ts
│ │ │ │ │ │ └── use-size.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── model.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── node-menu/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── node-panel/
│ │ │ │ │ ├── index.scss
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── node-list.tsx
│ │ │ │ │ └── node-placeholder.tsx
│ │ │ │ ├── node-render.tsx
│ │ │ │ ├── selector-box-popover/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── sidebar/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── sidebar-node-renderer.tsx
│ │ │ │ │ ├── sidebar-provider.tsx
│ │ │ │ │ └── sidebar-renderer.tsx
│ │ │ │ └── tools.tsx
│ │ │ ├── context/
│ │ │ │ ├── index.ts
│ │ │ │ ├── node-render-context.ts
│ │ │ │ └── sidebar-context.ts
│ │ │ ├── data/
│ │ │ │ ├── initial-data.ts
│ │ │ │ └── node-registries.ts
│ │ │ ├── form-components/
│ │ │ │ ├── feedback.tsx
│ │ │ │ ├── form-content/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── form-header/
│ │ │ │ │ ├── index.scss
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ ├── title-input.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ │ ├── form-inputs/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── form-item/
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── form-outputs/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── properties-edit/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── property-edit.tsx
│ │ │ │ │ └── styles.tsx
│ │ │ │ ├── type-tag.tsx
│ │ │ │ └── value-display/
│ │ │ │ ├── index.tsx
│ │ │ │ └── styles.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── index.ts
│ │ │ │ ├── use-editor-props.tsx
│ │ │ │ ├── use-is-sidebar.ts
│ │ │ │ └── use-node-render-context.ts
│ │ │ ├── index.ts
│ │ │ ├── nodes/
│ │ │ │ ├── comment/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── condition/
│ │ │ │ │ ├── condition-inputs/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── default-form-meta.tsx
│ │ │ │ ├── end/
│ │ │ │ │ ├── form-meta.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── llm/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── loop/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── loop-form-render.tsx
│ │ │ │ └── start/
│ │ │ │ ├── form-meta.tsx
│ │ │ │ └── index.ts
│ │ │ ├── plugins/
│ │ │ │ ├── context-menu-plugin/
│ │ │ │ │ ├── context-menu-layer.tsx
│ │ │ │ │ ├── context-menu-plugin.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── index.ts
│ │ │ ├── shortcuts/
│ │ │ │ ├── collapse/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── copy/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── delete/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── expand/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── paste/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── traverse.ts
│ │ │ │ │ └── unique-workflow.ts
│ │ │ │ ├── select-all/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── shortcuts.ts
│ │ │ │ ├── type.ts
│ │ │ │ ├── zoom-in/
│ │ │ │ │ └── index.ts
│ │ │ │ └── zoom-out/
│ │ │ │ └── index.ts
│ │ │ ├── style/
│ │ │ │ ├── index.css
│ │ │ │ └── var.css
│ │ │ ├── typings/
│ │ │ │ ├── flow-value/
│ │ │ │ │ ├── config.json
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── json-schema/
│ │ │ │ │ ├── config.json
│ │ │ │ │ └── index.ts
│ │ │ │ └── node.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ └── on-drag-line-end.ts
│ │ └── tsconfig.json
│ ├── demo-node-form/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── field-title.tsx
│ │ │ │ ├── field-wrapper.css
│ │ │ │ ├── field-wrapper.tsx
│ │ │ │ └── index.ts
│ │ │ ├── constant.ts
│ │ │ ├── editor.tsx
│ │ │ ├── form-meta.tsx
│ │ │ ├── hooks/
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── initial-data.ts
│ │ │ └── node-registries.tsx
│ │ └── tsconfig.json
│ ├── demo-playground/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── card.tsx
│ │ │ │ └── playground-tools.tsx
│ │ │ ├── editor.tsx
│ │ │ └── index.tsx
│ │ └── tsconfig.json
│ ├── demo-react-16/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── rsbuild.config.ts
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── minimap.tsx
│ │ │ │ ├── node-add-panel.tsx
│ │ │ │ ├── node-form-panel/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── sidebar-renderer.tsx
│ │ │ │ └── tools.tsx
│ │ │ ├── editor.tsx
│ │ │ ├── hooks/
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── initial-data.ts
│ │ │ └── node-registries.ts
│ │ └── tsconfig.json
│ ├── demo-vite/
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── components/
│ │ │ │ ├── minimap.tsx
│ │ │ │ ├── node-add-panel.tsx
│ │ │ │ └── tools.tsx
│ │ │ ├── editor.tsx
│ │ │ ├── hooks/
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── initial-data.ts
│ │ │ └── node-registries.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.js
│ └── docs/
│ ├── .gitignore
│ ├── README.md
│ ├── components/
│ │ ├── code-preview/
│ │ │ └── index.tsx
│ │ ├── fixed-examples/
│ │ │ ├── step-1.tsx
│ │ │ ├── step-2.tsx
│ │ │ ├── step-3.tsx
│ │ │ ├── step-4.tsx
│ │ │ ├── step-5/
│ │ │ │ ├── adder.tsx
│ │ │ │ ├── app.tsx
│ │ │ │ ├── initial-data.ts
│ │ │ │ ├── node-registries.tsx
│ │ │ │ ├── node-render.tsx
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── step-6/
│ │ │ │ ├── adder.tsx
│ │ │ │ ├── app.tsx
│ │ │ │ ├── initial-data.ts
│ │ │ │ ├── node-registries.tsx
│ │ │ │ ├── node-render.tsx
│ │ │ │ └── use-editor-props.tsx
│ │ │ └── step-7/
│ │ │ ├── adder.tsx
│ │ │ ├── app.tsx
│ │ │ ├── initial-data.ts
│ │ │ ├── minimap.tsx
│ │ │ ├── node-registries.tsx
│ │ │ ├── node-render.tsx
│ │ │ ├── tools.tsx
│ │ │ └── use-editor-props.tsx
│ │ ├── fixed-feature-overview/
│ │ │ ├── index.less
│ │ │ └── index.tsx
│ │ ├── fixed-layout-simple/
│ │ │ ├── composite-nodes-preview.tsx
│ │ │ ├── fixed-layout-simple.tsx
│ │ │ ├── index.tsx
│ │ │ └── preview.tsx
│ │ ├── form-materials/
│ │ │ ├── common/
│ │ │ │ ├── disable-declaration-plugin.tsx
│ │ │ │ ├── json-schema-preset.css
│ │ │ │ └── json-schema-preset.tsx
│ │ │ ├── components/
│ │ │ │ ├── assign-row.tsx
│ │ │ │ ├── assign-rows.tsx
│ │ │ │ ├── batch-outputs.tsx
│ │ │ │ ├── batch-variable-selector.tsx
│ │ │ │ ├── blur-input.tsx
│ │ │ │ ├── code-editor.tsx
│ │ │ │ ├── condition-context.tsx
│ │ │ │ ├── condition-row.tsx
│ │ │ │ ├── constant-inputs.tsx
│ │ │ │ ├── db-condition-row.tsx
│ │ │ │ ├── display-flow-value.tsx
│ │ │ │ ├── display-inputs-values.tsx
│ │ │ │ ├── display-outputs.tsx
│ │ │ │ ├── display-schema-tag.tsx
│ │ │ │ ├── display-schema-tree.tsx
│ │ │ │ ├── dynamic-value-input.tsx
│ │ │ │ ├── inputs-values-tree.tsx
│ │ │ │ ├── inputs-values.tsx
│ │ │ │ ├── json-editor-with-variables.tsx
│ │ │ │ ├── json-schema-creator.tsx
│ │ │ │ ├── json-schema-editor.tsx
│ │ │ │ ├── prompt-editor-with-inputs.tsx
│ │ │ │ ├── prompt-editor-with-variables.tsx
│ │ │ │ ├── prompt-editor.tsx
│ │ │ │ ├── sql-editor-with-variables.tsx
│ │ │ │ ├── type-selector.tsx
│ │ │ │ └── variable-selector.tsx
│ │ │ ├── effects/
│ │ │ │ ├── auto-rename-ref.tsx
│ │ │ │ ├── listen-ref-schema-change.tsx
│ │ │ │ ├── listen-ref-value-change.tsx
│ │ │ │ ├── provide-batch-input.tsx
│ │ │ │ ├── provide-json-schema-output.tsx
│ │ │ │ ├── sync-variable-title.tsx
│ │ │ │ └── validate-when-variable-sync.tsx
│ │ │ ├── form-plugins/
│ │ │ │ ├── batch-outputs-plugin.tsx
│ │ │ │ ├── infer-assign-plugin.tsx
│ │ │ │ └── infer-inputs-plugin.tsx
│ │ │ └── validate/
│ │ │ └── validate-flow-value.tsx
│ │ ├── free-examples/
│ │ │ ├── step-1.tsx
│ │ │ ├── step-2.tsx
│ │ │ ├── step-3.tsx
│ │ │ ├── step-4.tsx
│ │ │ ├── step-5/
│ │ │ │ ├── app.tsx
│ │ │ │ ├── initial-data.ts
│ │ │ │ ├── node-registries.tsx
│ │ │ │ ├── node-render.tsx
│ │ │ │ └── use-editor-props.tsx
│ │ │ ├── step-6/
│ │ │ │ ├── app.tsx
│ │ │ │ ├── initial-data.ts
│ │ │ │ ├── node-registries.tsx
│ │ │ │ ├── node-render.tsx
│ │ │ │ └── use-editor-props.tsx
│ │ │ └── step-7/
│ │ │ ├── add-node.tsx
│ │ │ ├── app.tsx
│ │ │ ├── initial-data.ts
│ │ │ ├── minimap.tsx
│ │ │ ├── node-registries.tsx
│ │ │ ├── node-render.tsx
│ │ │ ├── tools.tsx
│ │ │ └── use-editor-props.tsx
│ │ ├── free-feature-overview/
│ │ │ ├── index.less
│ │ │ └── index.tsx
│ │ ├── free-form-meta-story-builder/
│ │ │ └── index.tsx
│ │ ├── free-layout-simple/
│ │ │ ├── index.less
│ │ │ ├── index.tsx
│ │ │ └── preview.tsx
│ │ ├── index.ts
│ │ ├── infinite-canvas/
│ │ │ ├── index.less
│ │ │ ├── index.tsx
│ │ │ ├── infinite-canvas.tsx
│ │ │ └── preview.tsx
│ │ ├── materials.tsx
│ │ ├── node-form/
│ │ │ ├── array/
│ │ │ │ ├── index.css
│ │ │ │ ├── node-registry.tsx
│ │ │ │ └── preview.tsx
│ │ │ ├── basic-preview.tsx
│ │ │ ├── dynamic/
│ │ │ │ ├── node-registry.tsx
│ │ │ │ └── preview.tsx
│ │ │ ├── editor.tsx
│ │ │ ├── effect/
│ │ │ │ ├── node-registry.tsx
│ │ │ │ └── preview.tsx
│ │ │ ├── index.css
│ │ │ └── index.ts
│ │ ├── preview-editor.tsx
│ │ └── tsx-editor.tsx
│ ├── eslint.config.js
│ ├── global.less
│ ├── package.json
│ ├── rspress.config.ts
│ ├── scripts/
│ │ ├── auto-generate.ts
│ │ ├── constants.ts
│ │ └── patch.ts
│ ├── src/
│ │ ├── en/
│ │ │ ├── _nav.json
│ │ │ ├── api/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── common-apis.mdx
│ │ │ │ ├── components/
│ │ │ │ │ ├── editor-renderer.mdx
│ │ │ │ │ ├── fixed-layout-editor-provider.mdx
│ │ │ │ │ ├── fixed-layout-editor.mdx
│ │ │ │ │ ├── free-layout-editor-provider.mdx
│ │ │ │ │ ├── free-layout-editor.mdx
│ │ │ │ │ └── workflow-node-renderer.mdx
│ │ │ │ ├── core/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── flow-document.mdx
│ │ │ │ │ ├── flow-node-entity.mdx
│ │ │ │ │ ├── playground.mdx
│ │ │ │ │ ├── workflow-document.mdx
│ │ │ │ │ ├── workflow-line-entity.mdx
│ │ │ │ │ └── workflow-lines-manager.mdx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-client-context.mdx
│ │ │ │ │ ├── use-node-render.mdx
│ │ │ │ │ ├── use-playground-tools.mdx
│ │ │ │ │ ├── use-refresh.mdx
│ │ │ │ │ └── use-service.mdx
│ │ │ │ ├── index.mdx
│ │ │ │ ├── plugins.mdx
│ │ │ │ ├── services/
│ │ │ │ │ ├── clipboard-service.mdx
│ │ │ │ │ ├── command-service.mdx
│ │ │ │ │ ├── flow-operation-service.mdx
│ │ │ │ │ ├── history-service.mdx
│ │ │ │ │ └── selection-service.mdx
│ │ │ │ └── utils/
│ │ │ │ ├── disposable-collection.mdx
│ │ │ │ ├── disposable.mdx
│ │ │ │ ├── emitter.mdx
│ │ │ │ └── get-node-form.mdx
│ │ │ ├── examples/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── fixed-layout/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── fixed-composite-nodes.mdx
│ │ │ │ │ ├── fixed-feature-overview.mdx
│ │ │ │ │ └── fixed-layout-simple.mdx
│ │ │ │ ├── free-layout/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── free-feature-overview.mdx
│ │ │ │ │ └── free-layout-simple.mdx
│ │ │ │ ├── index.mdx
│ │ │ │ ├── node-form/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── array.mdx
│ │ │ │ │ ├── basic.mdx
│ │ │ │ │ ├── dynamic.mdx
│ │ │ │ │ └── effect.mdx
│ │ │ │ └── playground.mdx
│ │ │ ├── guide/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── advanced/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── custom-layer.mdx
│ │ │ │ │ ├── custom-plugin.mdx
│ │ │ │ │ ├── custom-service.mdx
│ │ │ │ │ ├── history.mdx
│ │ │ │ │ ├── lines.mdx
│ │ │ │ │ ├── shortcuts.mdx
│ │ │ │ │ └── zoom-scroll.mdx
│ │ │ │ ├── concepts/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── canvas-engine.mdx
│ │ │ │ │ ├── ecs.mdx
│ │ │ │ │ ├── index.mdx
│ │ │ │ │ ├── ioc.mdx
│ │ │ │ │ ├── node-engine.mdx
│ │ │ │ │ └── reactflow.mdx
│ │ │ │ ├── contact-us.mdx
│ │ │ │ ├── contributing.mdx
│ │ │ │ ├── fixed-layout/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── composite-nodes.mdx
│ │ │ │ │ ├── load.mdx
│ │ │ │ │ └── node.mdx
│ │ │ │ ├── form/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── form-materials.mdx
│ │ │ │ │ ├── form.mdx
│ │ │ │ │ └── without-form.mdx
│ │ │ │ ├── free-layout/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── line.mdx
│ │ │ │ │ ├── load.mdx
│ │ │ │ │ ├── node.mdx
│ │ │ │ │ ├── port.mdx
│ │ │ │ │ └── sub-canvas.mdx
│ │ │ │ ├── getting-started/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── fixed-layout.mdx
│ │ │ │ │ ├── free-layout.mdx
│ │ │ │ │ ├── introduction.mdx
│ │ │ │ │ └── quick-start.mdx
│ │ │ │ ├── plugin/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── background-plugin.mdx
│ │ │ │ │ ├── export-plugin.mdx
│ │ │ │ │ ├── free-auto-layout-plugin.mdx
│ │ │ │ │ ├── free-stack-plugin.mdx
│ │ │ │ │ ├── minimap-plugin.mdx
│ │ │ │ │ └── panel-manager-plugin.mdx
│ │ │ │ ├── runtime/
│ │ │ │ │ ├── _meta.json
│ │ │ │ │ ├── api.mdx
│ │ │ │ │ ├── introduction.mdx
│ │ │ │ │ ├── node.mdx
│ │ │ │ │ ├── quick-start.mdx
│ │ │ │ │ ├── schema.mdx
│ │ │ │ │ └── source-code-guide.mdx
│ │ │ │ └── variable/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── basic.mdx
│ │ │ │ ├── concept.mdx
│ │ │ │ ├── custom-scope-chain.mdx
│ │ │ │ ├── variable-consume.mdx
│ │ │ │ └── variable-output.mdx
│ │ │ ├── index.md
│ │ │ └── materials/
│ │ │ ├── _meta.json
│ │ │ ├── cli.mdx
│ │ │ ├── common/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── disable-declaration-plugin.mdx
│ │ │ │ ├── flow-value.mdx
│ │ │ │ ├── inject-material.mdx
│ │ │ │ └── json-schema-preset.mdx
│ │ │ ├── components/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── assign-row.mdx
│ │ │ │ ├── assign-rows.mdx
│ │ │ │ ├── batch-outputs.mdx
│ │ │ │ ├── batch-variable-selector.mdx
│ │ │ │ ├── blur-input.mdx
│ │ │ │ ├── code-editor.mdx
│ │ │ │ ├── condition-context.mdx
│ │ │ │ ├── condition-row.mdx
│ │ │ │ ├── constant-input.mdx
│ │ │ │ ├── coze-editor-extensions.mdx
│ │ │ │ ├── db-condition-row.mdx
│ │ │ │ ├── display-flow-value.mdx
│ │ │ │ ├── display-inputs-values.mdx
│ │ │ │ ├── display-outputs.mdx
│ │ │ │ ├── display-schema-tag.mdx
│ │ │ │ ├── display-schema-tree.mdx
│ │ │ │ ├── dynamic-value-input.mdx
│ │ │ │ ├── inputs-values-tree.mdx
│ │ │ │ ├── inputs-values.mdx
│ │ │ │ ├── json-editor-with-variables.mdx
│ │ │ │ ├── json-schema-creator.mdx
│ │ │ │ ├── json-schema-editor.mdx
│ │ │ │ ├── prompt-editor-with-inputs.mdx
│ │ │ │ ├── prompt-editor-with-variables.mdx
│ │ │ │ ├── prompt-editor.mdx
│ │ │ │ ├── sql-editor-with-variables.mdx
│ │ │ │ ├── type-selector.mdx
│ │ │ │ └── variable-selector.mdx
│ │ │ ├── effects/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── auto-rename-ref.mdx
│ │ │ │ ├── listen-ref-schema-change.mdx
│ │ │ │ ├── listen-ref-value-change.mdx
│ │ │ │ ├── provide-batch-input.mdx
│ │ │ │ ├── provide-json-schema-outputs.mdx
│ │ │ │ ├── sync-variable-title.mdx
│ │ │ │ └── validate-when-variable-sync.mdx
│ │ │ ├── form-plugins/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── batch-outputs-plugin.mdx
│ │ │ │ ├── infer-assign-plugin.mdx
│ │ │ │ └── infer-inputs-plugin.mdx
│ │ │ ├── introduction.mdx
│ │ │ └── validate/
│ │ │ ├── _meta.json
│ │ │ └── validate-flow-value.mdx
│ │ ├── global.d.ts
│ │ └── zh/
│ │ ├── _nav.json
│ │ ├── api/
│ │ │ ├── _meta.json
│ │ │ ├── common-apis.mdx
│ │ │ ├── components/
│ │ │ │ ├── editor-renderer.mdx
│ │ │ │ ├── fixed-layout-editor-provider.mdx
│ │ │ │ ├── fixed-layout-editor.mdx
│ │ │ │ ├── free-layout-editor-provider.mdx
│ │ │ │ ├── free-layout-editor.mdx
│ │ │ │ └── workflow-node-renderer.mdx
│ │ │ ├── core/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── flow-document.mdx
│ │ │ │ ├── flow-node-entity.mdx
│ │ │ │ ├── playground.mdx
│ │ │ │ ├── workflow-document.mdx
│ │ │ │ ├── workflow-line-entity.mdx
│ │ │ │ └── workflow-lines-manager.mdx
│ │ │ ├── hooks/
│ │ │ │ ├── use-client-context.mdx
│ │ │ │ ├── use-node-render.mdx
│ │ │ │ ├── use-playground-tools.mdx
│ │ │ │ ├── use-refresh.mdx
│ │ │ │ └── use-service.mdx
│ │ │ ├── index.mdx
│ │ │ ├── plugins.mdx
│ │ │ ├── services/
│ │ │ │ ├── clipboard-service.mdx
│ │ │ │ ├── command-service.mdx
│ │ │ │ ├── flow-operation-service.mdx
│ │ │ │ ├── history-service.mdx
│ │ │ │ └── selection-service.mdx
│ │ │ └── utils/
│ │ │ ├── disposable-collection.mdx
│ │ │ ├── disposable.mdx
│ │ │ ├── emitter.mdx
│ │ │ └── get-node-form.mdx
│ │ ├── examples/
│ │ │ ├── _meta.json
│ │ │ ├── fixed-layout/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── fixed-composite-nodes.mdx
│ │ │ │ ├── fixed-feature-overview.mdx
│ │ │ │ └── fixed-layout-simple.mdx
│ │ │ ├── free-layout/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── free-feature-overview.mdx
│ │ │ │ └── free-layout-simple.mdx
│ │ │ ├── index.mdx
│ │ │ ├── node-form/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── array.mdx
│ │ │ │ ├── basic.mdx
│ │ │ │ ├── dynamic.mdx
│ │ │ │ └── effect.mdx
│ │ │ └── playground.mdx
│ │ ├── guide/
│ │ │ ├── _meta.json
│ │ │ ├── advanced/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── custom-layer.mdx
│ │ │ │ ├── custom-plugin.mdx
│ │ │ │ ├── custom-service.mdx
│ │ │ │ ├── history.mdx
│ │ │ │ ├── shortcuts.mdx
│ │ │ │ └── zoom-scroll.mdx
│ │ │ ├── concepts/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── canvas-engine.mdx
│ │ │ │ ├── ecs.mdx
│ │ │ │ ├── index.mdx
│ │ │ │ ├── ioc.mdx
│ │ │ │ ├── node-engine.mdx
│ │ │ │ └── reactflow.mdx
│ │ │ ├── contact-us.mdx
│ │ │ ├── contributing.mdx
│ │ │ ├── fixed-layout/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── composite-nodes.mdx
│ │ │ │ ├── load.mdx
│ │ │ │ └── node.mdx
│ │ │ ├── form/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── form-materials.mdx
│ │ │ │ ├── form.mdx
│ │ │ │ └── without-form.mdx
│ │ │ ├── free-layout/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── line.mdx
│ │ │ │ ├── load.mdx
│ │ │ │ ├── node.mdx
│ │ │ │ ├── port.mdx
│ │ │ │ └── sub-canvas.mdx
│ │ │ ├── getting-started/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── fixed-layout.mdx
│ │ │ │ ├── free-layout.mdx
│ │ │ │ ├── introduction.mdx
│ │ │ │ └── quick-start.mdx
│ │ │ ├── plugin/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── background-plugin.mdx
│ │ │ │ ├── export-plugin.mdx
│ │ │ │ ├── free-auto-layout-plugin.mdx
│ │ │ │ ├── free-stack-plugin.mdx
│ │ │ │ ├── minimap-plugin.mdx
│ │ │ │ └── panel-manager-plugin.mdx
│ │ │ ├── question.mdx
│ │ │ ├── runtime/
│ │ │ │ ├── _meta.json
│ │ │ │ ├── api.mdx
│ │ │ │ ├── introduction.mdx
│ │ │ │ ├── node.mdx
│ │ │ │ ├── quick-start.mdx
│ │ │ │ ├── schema.mdx
│ │ │ │ └── source-code-guide.mdx
│ │ │ └── variable/
│ │ │ ├── _meta.json
│ │ │ ├── basic.mdx
│ │ │ ├── cases/
│ │ │ │ ├── _meta.json
│ │ │ │ └── case-batch-variable.mdx
│ │ │ ├── concept.mdx
│ │ │ ├── core-api.mdx
│ │ │ ├── core-ast.mdx
│ │ │ ├── custom-scope-chain.mdx
│ │ │ ├── variable-consume.mdx
│ │ │ └── variable-output.mdx
│ │ ├── index.md
│ │ └── materials/
│ │ ├── _meta.json
│ │ ├── cli.mdx
│ │ ├── common/
│ │ │ ├── _meta.json
│ │ │ ├── disable-declaration-plugin.mdx
│ │ │ ├── flow-value.mdx
│ │ │ ├── inject-material.mdx
│ │ │ └── json-schema-preset.mdx
│ │ ├── components/
│ │ │ ├── _meta.json
│ │ │ ├── assign-row.mdx
│ │ │ ├── assign-rows.mdx
│ │ │ ├── batch-outputs.mdx
│ │ │ ├── batch-variable-selector.mdx
│ │ │ ├── blur-input.mdx
│ │ │ ├── code-editor.mdx
│ │ │ ├── condition-context.mdx
│ │ │ ├── condition-row.mdx
│ │ │ ├── constant-input.mdx
│ │ │ ├── coze-editor-extensions.mdx
│ │ │ ├── db-condition-row.mdx
│ │ │ ├── display-flow-value.mdx
│ │ │ ├── display-inputs-values.mdx
│ │ │ ├── display-outputs.mdx
│ │ │ ├── display-schema-tag.mdx
│ │ │ ├── display-schema-tree.mdx
│ │ │ ├── dynamic-value-input.mdx
│ │ │ ├── inputs-values-tree.mdx
│ │ │ ├── inputs-values.mdx
│ │ │ ├── json-editor-with-variables.mdx
│ │ │ ├── json-schema-creator.mdx
│ │ │ ├── json-schema-editor.mdx
│ │ │ ├── prompt-editor-with-inputs.mdx
│ │ │ ├── prompt-editor-with-variables.mdx
│ │ │ ├── prompt-editor.mdx
│ │ │ ├── sql-editor-with-variables.mdx
│ │ │ ├── type-selector.mdx
│ │ │ └── variable-selector.mdx
│ │ ├── effects/
│ │ │ ├── _meta.json
│ │ │ ├── auto-rename-ref.mdx
│ │ │ ├── listen-ref-schema-change.mdx
│ │ │ ├── listen-ref-value-change.mdx
│ │ │ ├── provide-batch-input.mdx
│ │ │ ├── provide-json-schema-outputs.mdx
│ │ │ ├── sync-variable-title.mdx
│ │ │ └── validate-when-variable-sync.mdx
│ │ ├── form-plugins/
│ │ │ ├── _meta.json
│ │ │ ├── batch-outputs-plugin.mdx
│ │ │ ├── infer-assign-plugin.mdx
│ │ │ └── infer-inputs-plugin.mdx
│ │ ├── introduction.mdx
│ │ └── validate/
│ │ ├── _meta.json
│ │ └── validate-flow-value.mdx
│ ├── theme/
│ │ ├── components/
│ │ │ ├── background/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ └── logo/
│ │ │ ├── index.less
│ │ │ ├── index.tsx
│ │ │ ├── initial-data.ts
│ │ │ ├── musk.tsx
│ │ │ ├── node-color.ts
│ │ │ ├── node-registries.tsx
│ │ │ ├── node-render.tsx
│ │ │ ├── port.tsx
│ │ │ ├── position-groups.ts
│ │ │ ├── update-position.ts
│ │ │ └── use-editor-props.tsx
│ │ ├── index.tsx
│ │ ├── theme.css
│ │ └── use-is-mobile.ts
│ └── tsconfig.json
├── common/
│ ├── autoinstallers/
│ │ ├── dep-check/
│ │ │ ├── dep-check.ts
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── license-header/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── rush-commands/
│ │ │ ├── check-circular-dependency.mjs
│ │ │ └── package.json
│ │ ├── rush-commitlint/
│ │ │ ├── .cz-config.js
│ │ │ ├── commitlint.config.js
│ │ │ ├── package.json
│ │ │ └── utils.js
│ │ └── rush-lint-staged/
│ │ ├── .lintstagedrc.js
│ │ ├── package.json
│ │ └── utils.js
│ ├── config/
│ │ └── rush/
│ │ ├── .npmrc
│ │ ├── .npmrc-publish
│ │ ├── .pnpmfile.cjs
│ │ ├── artifactory.json
│ │ ├── build-cache.json
│ │ ├── cobuild.json
│ │ ├── command-line.json
│ │ ├── common-versions.json
│ │ ├── custom-tips.json
│ │ ├── experiments.json
│ │ ├── pnpm-config.json
│ │ ├── repo-state.json
│ │ ├── rush-plugins.json
│ │ ├── subspaces.json
│ │ └── version-policies.json
│ ├── git-hooks/
│ │ ├── commit-msg
│ │ ├── post-checkout
│ │ └── pre-commit
│ └── scripts/
│ ├── install-run-rush-pnpm.js
│ ├── install-run-rush.js
│ ├── install-run-rushx.js
│ └── install-run.js
├── config/
│ ├── eslint-config/
│ │ ├── CHANGELOG.json
│ │ ├── CHANGELOG.md
│ │ ├── eslint.base.config.js
│ │ ├── eslint.config.js
│ │ ├── eslint.node.config.js
│ │ ├── eslint.web.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── defineFlatConfig.js
│ │ │ ├── defineFlatConfig.ts
│ │ │ └── index.js
│ │ └── tsconfig.json
│ └── ts-config/
│ ├── eslint.config.js
│ ├── global.d.ts
│ ├── package.json
│ ├── tsconfig.base.json
│ ├── tsconfig.flow.base.json
│ ├── tsconfig.flow.path.json
│ ├── tsconfig.infra.base.json
│ ├── tsconfig.infra.node.json
│ └── tsconfig.node.json
├── cspell.json
├── doc_build.sh
├── e2e/
│ ├── fixed-layout/
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── playwright.config.ts
│ │ ├── tests/
│ │ │ ├── drag.spec.ts
│ │ │ ├── drawer.spec.ts
│ │ │ ├── layout.spec.ts
│ │ │ ├── models/
│ │ │ │ └── index.ts
│ │ │ ├── node.spec.ts
│ │ │ ├── testrun.spec.ts
│ │ │ ├── typings/
│ │ │ │ ├── drag.ts
│ │ │ │ └── index.ts
│ │ │ ├── validate.spec.ts
│ │ │ └── variable.spec.ts
│ │ ├── tsconfig.json
│ │ └── utils/
│ │ └── index.ts
│ └── free-layout/
│ ├── eslint.config.js
│ ├── package.json
│ ├── playwright.config.ts
│ ├── tests/
│ │ ├── layout.spec.ts
│ │ ├── models/
│ │ │ └── index.ts
│ │ └── node.spec.ts
│ └── tsconfig.json
├── packages/
│ ├── canvas-engine/
│ │ ├── core/
│ │ │ ├── __mocks__/
│ │ │ │ ├── create-entity.mock.ts
│ │ │ │ ├── layers.mock.tsx
│ │ │ │ └── playground-container.mock.ts
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── pipeline.spec.tsx.snap
│ │ │ │ │ └── playground.test.ts.snap
│ │ │ │ ├── core/
│ │ │ │ │ └── layer/
│ │ │ │ │ ├── config/
│ │ │ │ │ │ ├── editor-state-config-entity.spec.ts
│ │ │ │ │ │ └── payground-config-entity.spec.ts
│ │ │ │ │ └── playground-layer.spec.tsx
│ │ │ │ ├── entity.spec.ts
│ │ │ │ ├── layer.spec.tsx
│ │ │ │ ├── pipeline.spec.tsx
│ │ │ │ ├── playground-contribution.spec.tsx
│ │ │ │ ├── playground-mock-tools.spec.ts
│ │ │ │ ├── playground-react.spec.tsx
│ │ │ │ ├── playground.test.ts
│ │ │ │ ├── plugin.test.ts
│ │ │ │ ├── react-hooks.spec.tsx
│ │ │ │ ├── schema.spec.ts
│ │ │ │ ├── selection.spec.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── clipboard-service.spec.ts
│ │ │ │ │ └── storage-service.spec.ts
│ │ │ │ ├── transform-schema.spec.ts
│ │ │ │ └── utils.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── common/
│ │ │ │ │ ├── config-entity.ts
│ │ │ │ │ ├── entity-data.ts
│ │ │ │ │ ├── entity-manager-contribution.ts
│ │ │ │ │ ├── entity-manager.ts
│ │ │ │ │ ├── entity.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── playground-context.ts
│ │ │ │ │ ├── playground-decorator-helper.ts
│ │ │ │ │ ├── playground-decorators.ts
│ │ │ │ │ ├── playground-schedule.ts
│ │ │ │ │ ├── protect-wheel-area.ts
│ │ │ │ │ ├── schema/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── node.ts
│ │ │ │ │ │ ├── opacity-schema.ts
│ │ │ │ │ │ ├── origin-schema.ts
│ │ │ │ │ │ ├── position-schema.ts
│ │ │ │ │ │ ├── rotation-schema.ts
│ │ │ │ │ │ ├── scale-schema.ts
│ │ │ │ │ │ ├── size-schema.ts
│ │ │ │ │ │ ├── skew-schema.ts
│ │ │ │ │ │ └── transform-schema.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── bounds.spec.ts
│ │ │ │ │ ├── bounds.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── core/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── layer/
│ │ │ │ │ │ ├── config/
│ │ │ │ │ │ │ ├── editor-state-config-entity.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── playground-config-entity.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── layer.ts
│ │ │ │ │ │ └── playground-layer.ts
│ │ │ │ │ ├── pipeline/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── pipeline-entities-selector.ts
│ │ │ │ │ │ ├── pipeline-entities.ts
│ │ │ │ │ │ ├── pipeline-registry.ts
│ │ │ │ │ │ ├── pipeline-renderer.tsx
│ │ │ │ │ │ ├── pipeline.ts
│ │ │ │ │ │ └── pipline-react-utils.tsx
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── inject-provider-decorators.ts
│ │ │ │ │ ├── lazy-inject-decorators.ts
│ │ │ │ │ ├── mouse-touch-event.ts
│ │ │ │ │ ├── playground-drag.ts
│ │ │ │ │ ├── playground-gesture.spec.ts
│ │ │ │ │ ├── playground-gesture.ts
│ │ │ │ │ ├── tween.ts
│ │ │ │ │ └── use-gesture/
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── Controller.ts
│ │ │ │ │ │ ├── EventStore.ts
│ │ │ │ │ │ ├── TimeoutStore.ts
│ │ │ │ │ │ ├── actions.ts
│ │ │ │ │ │ ├── config/
│ │ │ │ │ │ │ ├── commonConfigResolver.ts
│ │ │ │ │ │ │ ├── coordinatesConfigResolver.ts
│ │ │ │ │ │ │ ├── dragConfigResolver.ts
│ │ │ │ │ │ │ ├── hoverConfigResolver.ts
│ │ │ │ │ │ │ ├── moveConfigResolver.ts
│ │ │ │ │ │ │ ├── pinchConfigResolver.ts
│ │ │ │ │ │ │ ├── resolver.ts
│ │ │ │ │ │ │ ├── scrollConfigResolver.ts
│ │ │ │ │ │ │ ├── sharedConfigResolver.ts
│ │ │ │ │ │ │ ├── support.ts
│ │ │ │ │ │ │ └── wheelConfigResolver.ts
│ │ │ │ │ │ ├── engines/
│ │ │ │ │ │ │ ├── CoordinatesEngine.ts
│ │ │ │ │ │ │ ├── DragEngine.ts
│ │ │ │ │ │ │ ├── Engine.ts
│ │ │ │ │ │ │ ├── HoverEngine.ts
│ │ │ │ │ │ │ ├── MoveEngine.ts
│ │ │ │ │ │ │ ├── PinchEngine.ts
│ │ │ │ │ │ │ ├── ScrollEngine.ts
│ │ │ │ │ │ │ └── WheelEngine.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── parser.ts
│ │ │ │ │ │ ├── types/
│ │ │ │ │ │ │ ├── action.ts
│ │ │ │ │ │ │ ├── config.ts
│ │ │ │ │ │ │ ├── handlers.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── internalConfig.ts
│ │ │ │ │ │ │ ├── state.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ ├── utils/
│ │ │ │ │ │ │ ├── events.ts
│ │ │ │ │ │ │ ├── fn.ts
│ │ │ │ │ │ │ ├── maths.ts
│ │ │ │ │ │ │ └── state.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── vanilla/
│ │ │ │ │ ├── DragGesture.ts
│ │ │ │ │ ├── Gesture.ts
│ │ │ │ │ ├── HoverGesture.ts
│ │ │ │ │ ├── MoveGesture.ts
│ │ │ │ │ ├── PinchGesture.ts
│ │ │ │ │ ├── Recognizer.ts
│ │ │ │ │ ├── ScrollGesture.ts
│ │ │ │ │ ├── WheelGesture.ts
│ │ │ │ │ ├── createGesture.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── playground-config.ts
│ │ │ │ ├── playground-container.ts
│ │ │ │ ├── playground-contribution.ts
│ │ │ │ ├── playground-mock-tools.ts
│ │ │ │ ├── playground.ts
│ │ │ │ ├── plugin/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── plugin.ts
│ │ │ │ ├── react/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── playground-react-context.ts
│ │ │ │ │ ├── playground-react-provider.tsx
│ │ │ │ │ └── playground-react-renderer.tsx
│ │ │ │ ├── react-hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── use-config-entity.ts
│ │ │ │ │ ├── use-entities.ts
│ │ │ │ │ ├── use-entity-data-from-context.ts
│ │ │ │ │ ├── use-entity-from-context.ts
│ │ │ │ │ ├── use-listen-events.ts
│ │ │ │ │ ├── use-playground-container.ts
│ │ │ │ │ ├── use-playground-context.ts
│ │ │ │ │ ├── use-playground-drag.ts
│ │ │ │ │ ├── use-playground.ts
│ │ │ │ │ ├── use-refresh.ts
│ │ │ │ │ └── use-service.ts
│ │ │ │ └── services/
│ │ │ │ ├── clipboard-service.ts
│ │ │ │ ├── context-menu-service.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── logger-service.ts
│ │ │ │ ├── selection-service.ts
│ │ │ │ └── storage-service.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── document/
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── flow-document.test.ts.snap
│ │ │ │ ├── datas/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── flow-node-transition-data.spec.ts.snap
│ │ │ │ │ ├── flow-node-render-data.spec.ts
│ │ │ │ │ └── flow-node-transition-data.spec.ts
│ │ │ │ ├── flow-document-container.mock.ts
│ │ │ │ ├── flow-document-transformer.test.ts
│ │ │ │ ├── flow-document.test.ts
│ │ │ │ ├── flow-node-entity.spec.ts
│ │ │ │ ├── flow-node-registry.spec.ts
│ │ │ │ ├── flow-render-tree.spec.ts
│ │ │ │ ├── flow-virtual-tree.spec.ts
│ │ │ │ ├── flow.mock.ts
│ │ │ │ └── services/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── flow-operation-base-service.test.ts.snap
│ │ │ │ └── flow-operation-base-service.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── datas/
│ │ │ │ │ ├── flow-node-render-data.ts
│ │ │ │ │ ├── flow-node-transform-data.ts
│ │ │ │ │ ├── flow-node-transition-data.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── entities/
│ │ │ │ │ ├── flow-document-transformer-entity.ts
│ │ │ │ │ ├── flow-node-entity.ts
│ │ │ │ │ ├── flow-renderer-state-entity.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── flow-document-config.ts
│ │ │ │ ├── flow-document-container-module.ts
│ │ │ │ ├── flow-document-contribution.ts
│ │ │ │ ├── flow-document-options.ts
│ │ │ │ ├── flow-document.ts
│ │ │ │ ├── flow-render-tree.ts
│ │ │ │ ├── flow-virtual-tree.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layout/
│ │ │ │ │ ├── horizontal-fixed-layout.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── vertical-fixed-layout.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── flow-drag-service.ts
│ │ │ │ │ ├── flow-group-service/
│ │ │ │ │ │ ├── flow-group-controller.ts
│ │ │ │ │ │ ├── flow-group-service.ts
│ │ │ │ │ │ ├── flow-group-utils.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── flow-operation-base-service.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── typings/
│ │ │ │ │ ├── flow-group.ts
│ │ │ │ │ ├── flow-layout.ts
│ │ │ │ │ ├── flow-node-register.ts
│ │ │ │ │ ├── flow-operation.ts
│ │ │ │ │ ├── flow-transition.ts
│ │ │ │ │ ├── flow.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── utils/
│ │ │ │ ├── get-default-spacing.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── fixed-layout-core/
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── flow-activities.spec.ts.snap
│ │ │ │ ├── flow-activities.mock.ts
│ │ │ │ └── flow-activities.spec.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── activities/
│ │ │ │ │ ├── block-icon.ts
│ │ │ │ │ ├── block-order-icon.ts
│ │ │ │ │ ├── block.ts
│ │ │ │ │ ├── break.ts
│ │ │ │ │ ├── dynamic-split.ts
│ │ │ │ │ ├── empty.ts
│ │ │ │ │ ├── end.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── inline-blocks.ts
│ │ │ │ │ ├── input.ts
│ │ │ │ │ ├── loop-extends/
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── loop-empty-branch.ts
│ │ │ │ │ │ ├── loop-inline-blocks.ts
│ │ │ │ │ │ ├── loop-left-empty-block.ts
│ │ │ │ │ │ └── loop-right-empty-block.ts
│ │ │ │ │ ├── loop.ts
│ │ │ │ │ ├── multi-inputs.ts
│ │ │ │ │ ├── multi-outputs.ts
│ │ │ │ │ ├── output.ts
│ │ │ │ │ ├── root.ts
│ │ │ │ │ ├── simple-split.ts
│ │ │ │ │ ├── slot/
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── extends/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── slot-block.ts
│ │ │ │ │ │ │ ├── slot-icon.ts
│ │ │ │ │ │ │ └── slot-inline-blocks.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── slot.ts
│ │ │ │ │ │ ├── typings.ts
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── create.ts
│ │ │ │ │ │ ├── layout.ts
│ │ │ │ │ │ ├── node.ts
│ │ │ │ │ │ └── transition.ts
│ │ │ │ │ ├── start.ts
│ │ │ │ │ ├── static-split.ts
│ │ │ │ │ ├── try-catch-extends/
│ │ │ │ │ │ ├── catch-block.ts
│ │ │ │ │ │ ├── catch-inline-blocks.ts
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── main-inline-blocks.ts
│ │ │ │ │ │ ├── try-block.ts
│ │ │ │ │ │ └── try-slot.ts
│ │ │ │ │ └── try-catch.ts
│ │ │ │ ├── fixed-layout-container-module.ts
│ │ │ │ ├── flow-registers.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-layout-core/
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── workflow-lines-manager.test.ts.snap
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-current-dom-node.test.ts
│ │ │ │ │ ├── use-current-entity.test.ts
│ │ │ │ │ ├── use-node-render.test.tsx
│ │ │ │ │ ├── use-playground-readonly-state.test.ts
│ │ │ │ │ └── use-workflow-document.test.ts
│ │ │ │ ├── mocks/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── service/
│ │ │ │ │ ├── workflow-drag-service.test.ts
│ │ │ │ │ ├── workflow-hover-service.test.ts
│ │ │ │ │ └── workflow-select-service.test.ts
│ │ │ │ ├── simple-line.ts
│ │ │ │ ├── utils/
│ │ │ │ │ └── location-config-to-point.test.ts
│ │ │ │ ├── workflow-document.test.ts
│ │ │ │ └── workflow-lines-manager.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── entities/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── workflow-line-entity.ts
│ │ │ │ │ ├── workflow-node-entity.ts
│ │ │ │ │ └── workflow-port-entity.ts
│ │ │ │ ├── entity-datas/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── workflow-line-render-data.ts
│ │ │ │ │ ├── workflow-node-lines-data.ts
│ │ │ │ │ └── workflow-node-ports-data.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── typings.ts
│ │ │ │ │ ├── use-current-dom-node.ts
│ │ │ │ │ ├── use-current-entity.ts
│ │ │ │ │ ├── use-node-render-context.ts
│ │ │ │ │ ├── use-node-render.tsx
│ │ │ │ │ ├── use-playground-readonly-state.ts
│ │ │ │ │ └── use-workflow-document.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layout/
│ │ │ │ │ ├── free-layout.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── service/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── workflow-drag-service.ts
│ │ │ │ │ ├── workflow-hover-service.ts
│ │ │ │ │ ├── workflow-operation-base-service.ts
│ │ │ │ │ ├── workflow-reset-layout-service.ts
│ │ │ │ │ └── workflow-select-service.ts
│ │ │ │ ├── typings/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── workflow-drag.ts
│ │ │ │ │ ├── workflow-edge.ts
│ │ │ │ │ ├── workflow-json.ts
│ │ │ │ │ ├── workflow-line.ts
│ │ │ │ │ ├── workflow-node.ts
│ │ │ │ │ ├── workflow-operation.ts
│ │ │ │ │ ├── workflow-registry.ts
│ │ │ │ │ └── workflow-sub-canvas.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── build-group-json.ts
│ │ │ │ │ ├── compose.ts
│ │ │ │ │ ├── fit-view.ts
│ │ │ │ │ ├── flow-node-form-data.ts
│ │ │ │ │ ├── get-anti-overlap-position.ts
│ │ │ │ │ ├── get-line-center.ts
│ │ │ │ │ ├── get-url-params.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── layout-to-positions.ts
│ │ │ │ │ ├── location-config-to-point.ts
│ │ │ │ │ ├── nanoid.ts
│ │ │ │ │ └── statics.ts
│ │ │ │ ├── workflow-commands.ts
│ │ │ │ ├── workflow-document-container-module.ts
│ │ │ │ ├── workflow-document-contribution.ts
│ │ │ │ ├── workflow-document-option.ts
│ │ │ │ ├── workflow-document.ts
│ │ │ │ └── workflow-lines-manager.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ └── renderer/
│ │ ├── __mocks__/
│ │ │ ├── flow-document-container.mock.ts
│ │ │ ├── flow-drag-entity.ts
│ │ │ ├── flow-json.mock.ts
│ │ │ ├── flow-labels-mock-register.ts
│ │ │ ├── flow-mock-node-json.ts
│ │ │ ├── flow-selected-nodes.mock.ts
│ │ │ ├── mock-lines.ts
│ │ │ ├── renderer.mock.ts
│ │ │ └── setup-file.ts
│ │ ├── __tests__/
│ │ │ ├── components/
│ │ │ │ ├── Adder.test.tsx
│ │ │ │ └── rounded-turning-line.test.tsx
│ │ │ ├── entities/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── flow-drag-entities.test.ts.snap
│ │ │ │ ├── flow-drag-entities.test.ts
│ │ │ │ └── flow-select-config-entity.test.ts
│ │ │ ├── flow-renderer.tsx
│ │ │ ├── layers/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── flow-drag-layer.test.ts.snap
│ │ │ │ │ ├── flow-label-layer.test.tsx.snap
│ │ │ │ │ └── flow-selector-box-layer.test.tsx.snap
│ │ │ │ ├── flow-drag-layer.test.ts
│ │ │ │ ├── flow-label-layer.test.tsx
│ │ │ │ ├── flow-lines-layer.test.ts
│ │ │ │ ├── flow-selector-box-layer.test.tsx
│ │ │ │ └── flow-transform-layer.test.tsx
│ │ │ └── utils/
│ │ │ ├── element.test.ts
│ │ │ ├── find-selected-nodes.test.ts
│ │ │ ├── get-vertices.test.ts
│ │ │ └── scroll-limit.test.ts
│ │ ├── eslint.config.js
│ │ ├── index.module.less
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── Adder.tsx
│ │ │ │ ├── BranchDraggableRenderer.tsx
│ │ │ │ ├── Collapse.tsx
│ │ │ │ ├── CollapseAdder.tsx
│ │ │ │ ├── CustomLine.tsx
│ │ │ │ ├── LabelsRenderer.tsx
│ │ │ │ ├── LinesRenderer.tsx
│ │ │ │ ├── MarkerActivatedArrow.tsx
│ │ │ │ ├── MarkerArrow.tsx
│ │ │ │ ├── RoundedTurningLine.tsx
│ │ │ │ ├── StraightLine.tsx
│ │ │ │ └── utils.tsx
│ │ │ ├── entities/
│ │ │ │ ├── README.md
│ │ │ │ ├── flow-drag-entity.tsx
│ │ │ │ ├── flow-select-config-entity.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── selector-box-config-entity.ts
│ │ │ ├── flow-renderer-container-module.ts
│ │ │ ├── flow-renderer-contribution.ts
│ │ │ ├── flow-renderer-registry.ts
│ │ │ ├── flow-renderer-resize-observer.ts
│ │ │ ├── hooks/
│ │ │ │ └── use-base-color.ts
│ │ │ ├── index.ts
│ │ │ ├── layers/
│ │ │ │ ├── flow-context-menu-layer.tsx
│ │ │ │ ├── flow-debug-layer.tsx
│ │ │ │ ├── flow-drag-layer.tsx
│ │ │ │ ├── flow-labels-layer.tsx
│ │ │ │ ├── flow-lines-layer.tsx
│ │ │ │ ├── flow-nodes-content-layer.tsx
│ │ │ │ ├── flow-nodes-transform-layer.tsx
│ │ │ │ ├── flow-scroll-bar-layer.tsx
│ │ │ │ ├── flow-scroll-limit-layer.tsx
│ │ │ │ ├── flow-selector-bounds-layer.tsx
│ │ │ │ ├── flow-selector-box-layer.tsx
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── element.ts
│ │ │ ├── find-selected-nodes.ts
│ │ │ ├── index.ts
│ │ │ ├── scroll-bar-events.tsx
│ │ │ └── scroll-limit.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── client/
│ │ ├── editor/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── clients/
│ │ │ │ │ ├── flow-editor-client-plugins.ts
│ │ │ │ │ ├── flow-editor-client.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── node-client/
│ │ │ │ │ ├── create-node-client-plugins.ts
│ │ │ │ │ ├── highlight/
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── create-node-highlight-plugin.ts
│ │ │ │ │ │ ├── highlight-form-item.ts
│ │ │ │ │ │ ├── highlight-style.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── use-highlight.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── node-client.ts
│ │ │ │ │ └── node-focus-service.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── editor-provider.tsx
│ │ │ │ │ ├── editor-renderer.tsx
│ │ │ │ │ ├── editor.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── use-flow-editor.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── preset/
│ │ │ │ ├── editor-default-preset.ts
│ │ │ │ ├── editor-props.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── fixed-layout-editor/
│ │ │ ├── __mocks__/
│ │ │ │ ├── flow.mock.ts
│ │ │ │ └── form.mock.tsx
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── fixed-layout-preset.test.ts.snap
│ │ │ │ ├── create-container.ts
│ │ │ │ ├── fixed-layout-preset.test.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── flow-operation-service.test.ts
│ │ │ │ │ └── history-operation-service/
│ │ │ │ │ ├── add-block.test.ts
│ │ │ │ │ ├── add-from-node.test.ts
│ │ │ │ │ ├── add-node.test.ts
│ │ │ │ │ ├── apply.test.ts
│ │ │ │ │ ├── create-group.test.ts
│ │ │ │ │ ├── delete-node.test.ts
│ │ │ │ │ ├── delete-nodes.test.ts
│ │ │ │ │ ├── move-node.test.ts
│ │ │ │ │ ├── set-form-value.test.tsx
│ │ │ │ │ ├── transact.test.ts
│ │ │ │ │ └── ungroup.test.ts
│ │ │ │ └── utils.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── index.css
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── fixed-layout-editor-provider.tsx
│ │ │ │ │ ├── fixed-layout-editor.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-client-context.ts
│ │ │ │ │ ├── use-node-render.tsx
│ │ │ │ │ └── use-playground-tools.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ └── create-operation-plugin.ts
│ │ │ │ ├── preset/
│ │ │ │ │ ├── fixed-layout-preset.ts
│ │ │ │ │ ├── fixed-layout-props.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── node-serialize.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── flow-operation-service.ts
│ │ │ │ │ └── history-operation-service.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils/
│ │ │ │ └── compose.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-layout-editor/
│ │ │ ├── __mocks__/
│ │ │ │ └── flow.mocks.ts
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── free-layout-preset.test.ts.snap
│ │ │ │ ├── create-editor.ts
│ │ │ │ ├── free-layout-preset.test.ts
│ │ │ │ ├── history.test.ts
│ │ │ │ ├── use-playground-tools.test.ts
│ │ │ │ └── utils.mock.tsx
│ │ │ ├── eslint.config.js
│ │ │ ├── index.css
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── free-layout-editor-provider.tsx
│ │ │ │ │ ├── free-layout-editor.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── workflow-node-renderer.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── use-auto-layout.ts
│ │ │ │ │ ├── use-client-context.ts
│ │ │ │ │ └── use-playground-tools.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ └── create-operation-plugin.ts
│ │ │ │ ├── preset/
│ │ │ │ │ ├── free-layout-preset.ts
│ │ │ │ │ ├── free-layout-props.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── node-serialize.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── flow-operation-service.ts
│ │ │ │ │ └── history-operation-service.ts
│ │ │ │ ├── tools/
│ │ │ │ │ ├── auto-layout.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ └── playground-react/
│ │ ├── eslint.config.js
│ │ ├── index.css
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── index.ts
│ │ │ │ ├── playground-react-content.tsx
│ │ │ │ └── playground-react.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── index.ts
│ │ │ │ └── use-playground-tools.ts
│ │ │ ├── index.ts
│ │ │ ├── layers/
│ │ │ │ └── playground-content-layer.tsx
│ │ │ └── preset/
│ │ │ ├── index.ts
│ │ │ ├── playground-react-preset.ts
│ │ │ └── playground-react-props.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── common/
│ │ ├── command/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── command-container-module.ts
│ │ │ │ ├── command-service.ts
│ │ │ │ ├── command.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── history/
│ │ │ ├── __mocks__/
│ │ │ │ ├── editor.mock.ts
│ │ │ │ └── history-container.mock.ts
│ │ │ ├── __tests__/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── history-manager.test.ts.snap
│ │ │ │ │ ├── history-service.test.ts.snap
│ │ │ │ │ └── undo-redo-service.test.ts.snap
│ │ │ │ ├── history-manager.test.ts
│ │ │ │ ├── history-service.test.ts
│ │ │ │ ├── operation-registry.test.ts
│ │ │ │ ├── operation-service.test.ts
│ │ │ │ └── undo-redo-service.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-history-plugin.ts
│ │ │ │ ├── history/
│ │ │ │ │ ├── history-manager.ts
│ │ │ │ │ ├── history-service.ts
│ │ │ │ │ ├── history-stack.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── stack-operation.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── undo-redo-service.ts
│ │ │ │ ├── history-config.ts
│ │ │ │ ├── history-container-module.ts
│ │ │ │ ├── history-context.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── operation/
│ │ │ │ ├── index.ts
│ │ │ │ ├── operation-contribution.ts
│ │ │ │ ├── operation-registry.ts
│ │ │ │ ├── operation-service.ts
│ │ │ │ └── types.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── history-storage/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── history-database.test.ts
│ │ │ │ ├── create-history-storage-plugin.ts
│ │ │ │ ├── history-database.ts
│ │ │ │ ├── history-storage-container-module.ts
│ │ │ │ ├── history-storage-manager.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── use-storage-hisotry-items.tsx
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── i18n/
│ │ │ ├── __tests__/
│ │ │ │ └── i18n.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── i18n/
│ │ │ │ │ ├── en-US.ts
│ │ │ │ │ └── zh-CN.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vitest.config.ts
│ │ ├── reactive/
│ │ │ ├── README.md
│ │ │ ├── __tests__/
│ │ │ │ ├── hooks.test.tsx
│ │ │ │ ├── observe.test.tsx
│ │ │ │ ├── reactive-base-state.test.ts
│ │ │ │ ├── reactive-state.test.ts
│ │ │ │ └── tracker.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── core/
│ │ │ │ │ ├── reactive-base-state.ts
│ │ │ │ │ ├── reactive-state.ts
│ │ │ │ │ └── tracker.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-observe.ts
│ │ │ │ │ ├── use-reactive-state.ts
│ │ │ │ │ └── use-readonly-reactive-state.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── react/
│ │ │ │ │ └── observe.tsx
│ │ │ │ └── utils/
│ │ │ │ └── create-proxy.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vitest.config.ts
│ │ └── utils/
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── add-event-listener.ts
│ │ │ ├── array.spec.ts
│ │ │ ├── array.ts
│ │ │ ├── cache.spec.ts
│ │ │ ├── cache.ts
│ │ │ ├── cancellation.spec.ts
│ │ │ ├── cancellation.ts
│ │ │ ├── compare.spec.ts
│ │ │ ├── compare.ts
│ │ │ ├── compose.ts
│ │ │ ├── contribution-provider.ts
│ │ │ ├── decoration-style.ts
│ │ │ ├── disposable-collection.ts
│ │ │ ├── disposable.spec.ts
│ │ │ ├── disposable.ts
│ │ │ ├── dom-utils.spec.ts
│ │ │ ├── dom-utils.ts
│ │ │ ├── event.spec.ts
│ │ │ ├── event.ts
│ │ │ ├── hooks/
│ │ │ │ ├── use-refresh.spec.tsx
│ │ │ │ └── use-refresh.ts
│ │ │ ├── id.spec.ts
│ │ │ ├── id.ts
│ │ │ ├── index.spec.ts
│ │ │ ├── index.ts
│ │ │ ├── inversify-utils.ts
│ │ │ ├── logger.spec.ts
│ │ │ ├── logger.ts
│ │ │ ├── math/
│ │ │ │ ├── IPoint.spec.ts
│ │ │ │ ├── IPoint.ts
│ │ │ │ ├── Matrix.spec.ts
│ │ │ │ ├── Matrix.ts
│ │ │ │ ├── ObservablePoint.spec.ts
│ │ │ │ ├── ObservablePoint.ts
│ │ │ │ ├── Point.spec.ts
│ │ │ │ ├── Point.ts
│ │ │ │ ├── Transform.spec.ts
│ │ │ │ ├── Transform.ts
│ │ │ │ ├── Vector2.spec.ts
│ │ │ │ ├── Vector2.ts
│ │ │ │ ├── angle.spec.ts
│ │ │ │ ├── angle.ts
│ │ │ │ ├── const.spec.ts
│ │ │ │ ├── const.ts
│ │ │ │ ├── index.spec.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── shapes/
│ │ │ │ │ ├── Circle.spec.ts
│ │ │ │ │ ├── Circle.ts
│ │ │ │ │ ├── Rectangle.spec.ts
│ │ │ │ │ ├── Rectangle.ts
│ │ │ │ │ ├── index.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── wrap.spec.ts
│ │ │ │ └── wrap.ts
│ │ │ ├── objects.spec.ts
│ │ │ ├── objects.ts
│ │ │ ├── promise-util.spec.ts
│ │ │ ├── promise-util.ts
│ │ │ ├── request-with-memo.spec.ts
│ │ │ ├── request-with-memo.ts
│ │ │ ├── schema/
│ │ │ │ ├── index.spec.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── schema-base.ts
│ │ │ │ ├── schema-transform.ts
│ │ │ │ ├── schema.spec.ts
│ │ │ │ └── schema.ts
│ │ │ ├── types.spec.ts
│ │ │ └── types.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── materials/
│ │ ├── coze-editor/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── rslib.config.ts
│ │ │ ├── scripts/
│ │ │ │ └── gen.js
│ │ │ ├── src/
│ │ │ │ ├── index.ts
│ │ │ │ ├── language-json.ts
│ │ │ │ ├── language-python.ts
│ │ │ │ ├── language-shell.ts
│ │ │ │ ├── language-sql.ts
│ │ │ │ ├── language-typescript/
│ │ │ │ │ └── worker.ts
│ │ │ │ ├── language-typescript.ts
│ │ │ │ ├── preset-code.ts
│ │ │ │ ├── preset-expression.ts
│ │ │ │ ├── preset-none.ts
│ │ │ │ ├── preset-prompt.ts
│ │ │ │ ├── preset-universal.ts
│ │ │ │ ├── preset-variable.ts
│ │ │ │ ├── react-merge.ts
│ │ │ │ ├── react.ts
│ │ │ │ └── vscode.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── fixed-semi-materials/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── assets/
│ │ │ │ │ ├── ellipsis.tsx
│ │ │ │ │ ├── icons.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── adder/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── branch-adder/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── collapse/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── constants.tsx
│ │ │ │ │ ├── drag-highlight-adder/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── drag-node/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── dragging-adder/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── metadata.tsx
│ │ │ │ │ ├── nodes/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── slot-adder.tsx
│ │ │ │ │ ├── slot-collapse.tsx
│ │ │ │ │ ├── tools.tsx
│ │ │ │ │ └── try-catch-collapse.tsx
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── form-antd-materials/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── batch-variable-selector/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── condition-row/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ ├── styles.tsx
│ │ │ │ │ │ │ ├── useOp.tsx
│ │ │ │ │ │ │ └── useRule.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.tsx
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── constant-input/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.tsx
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── dynamic-value-input/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── json-schema-editor/
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ └── blur-input.tsx
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── default-value.tsx
│ │ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.tsx
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── type-selector/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── constants.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── variable-selector/
│ │ │ │ │ ├── config.json
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.tsx
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── use-variable-tree.tsx
│ │ │ │ ├── effects/
│ │ │ │ │ ├── auto-rename-ref/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── provide-batch-input/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── provide-batch-outputs/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── provide-json-schema-outputs/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── sync-variable-title/
│ │ │ │ │ ├── config.json
│ │ │ │ │ └── index.ts
│ │ │ │ ├── form-plugins/
│ │ │ │ │ ├── batch-outputs-plugin/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── typings/
│ │ │ │ │ ├── flow-value/
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── json-schema/
│ │ │ │ │ ├── config.json
│ │ │ │ │ └── index.ts
│ │ │ │ └── utils/
│ │ │ │ ├── format-legacy-refs/
│ │ │ │ │ ├── config.json
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── readme.md
│ │ │ │ ├── index.ts
│ │ │ │ ├── json-schema/
│ │ │ │ │ ├── config.json
│ │ │ │ │ └── index.ts
│ │ │ │ └── svg-icon/
│ │ │ │ └── index.tsx
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── form-materials/
│ │ │ ├── bin/
│ │ │ │ └── run.sh
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── rslib.config.ts
│ │ │ ├── scripts/
│ │ │ │ └── name-export.js
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── assign-row/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── assign-rows/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── batch-outputs/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── batch-variable-selector/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── blur-input/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── code-editor/
│ │ │ │ │ │ ├── editor-all.tsx
│ │ │ │ │ │ ├── editor-json.tsx
│ │ │ │ │ │ ├── editor-python.tsx
│ │ │ │ │ │ ├── editor-shell.tsx
│ │ │ │ │ │ ├── editor-sql.tsx
│ │ │ │ │ │ ├── editor-ts.tsx
│ │ │ │ │ │ ├── editor.tsx
│ │ │ │ │ │ ├── factory.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ ├── theme/
│ │ │ │ │ │ │ ├── dark.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── light.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── code-editor-mini/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── condition-context/
│ │ │ │ │ │ ├── context.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ └── use-condition.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── op.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── condition-row/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── constant-input/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── coze-editor-extensions/
│ │ │ │ │ │ ├── extensions/
│ │ │ │ │ │ │ ├── inputs-tree.tsx
│ │ │ │ │ │ │ ├── variable-tag.tsx
│ │ │ │ │ │ │ └── variable-tree.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.css
│ │ │ │ │ ├── db-condition-row/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── display-flow-value/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── display-inputs-values/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.css
│ │ │ │ │ ├── display-outputs/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.css
│ │ │ │ │ ├── display-schema-tag/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.css
│ │ │ │ │ ├── display-schema-tree/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.css
│ │ │ │ │ ├── dynamic-value-input/
│ │ │ │ │ │ ├── hooks.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.css
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── inputs-values/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── inputs-values-tree/
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ └── use-child-list.tsx
│ │ │ │ │ │ ├── icon.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── row.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── json-editor-with-variables/
│ │ │ │ │ │ ├── editor.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── json-schema-creator/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── json-input-modal.tsx
│ │ │ │ │ │ ├── json-schema-creator.tsx
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ └── json-to-schema.ts
│ │ │ │ │ ├── json-schema-editor/
│ │ │ │ │ │ ├── default-value.tsx
│ │ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ │ ├── icon.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── prompt-editor/
│ │ │ │ │ │ ├── editor.tsx
│ │ │ │ │ │ ├── extensions/
│ │ │ │ │ │ │ ├── jinja.tsx
│ │ │ │ │ │ │ ├── language-support.tsx
│ │ │ │ │ │ │ └── markdown.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.css
│ │ │ │ │ │ └── types.tsx
│ │ │ │ │ ├── prompt-editor-with-inputs/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── prompt-editor-with-variables/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── sql-editor-with-variables/
│ │ │ │ │ │ ├── editor.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── type-selector/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── variable-selector/
│ │ │ │ │ ├── context.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.css
│ │ │ │ │ └── use-variable-tree.tsx
│ │ │ │ ├── effects/
│ │ │ │ │ ├── auto-rename-ref/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── listen-ref-schema-change/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── listen-ref-value-change/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── provide-batch-input/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── provide-json-schema-outputs/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── sync-variable-title/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── validate-when-variable-sync/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── form-plugins/
│ │ │ │ │ ├── batch-outputs-plugin/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── infer-assign-plugin/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── infer-inputs-plugin/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── use-object-list/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ ├── disable-declaration-plugin/
│ │ │ │ │ │ ├── create-disable-declaration-plugin.ts
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── json-schema-preset/
│ │ │ │ │ ├── create-type-preset-plugin.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── react.tsx
│ │ │ │ │ ├── type-definition/
│ │ │ │ │ │ ├── array.tsx
│ │ │ │ │ │ ├── boolean.tsx
│ │ │ │ │ │ ├── date-time.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── integer.tsx
│ │ │ │ │ │ ├── map.tsx
│ │ │ │ │ │ ├── number.tsx
│ │ │ │ │ │ ├── object.tsx
│ │ │ │ │ │ └── string.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ ├── shared/
│ │ │ │ │ ├── flow-value/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── schema.ts
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── format-legacy-refs/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── readme.md
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── inject-material/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── lazy-suspense/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── polyfill-create-root/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── validate/
│ │ │ │ ├── index.ts
│ │ │ │ └── validate-flow-value/
│ │ │ │ └── index.tsx
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ └── type-editor/
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── feedback/
│ │ │ │ │ ├── feedback.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── style.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── type-editor/
│ │ │ │ │ ├── body.tsx
│ │ │ │ │ ├── cell.tsx
│ │ │ │ │ ├── columns/
│ │ │ │ │ │ ├── default.tsx
│ │ │ │ │ │ ├── description.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── key.tsx
│ │ │ │ │ │ ├── operate.tsx
│ │ │ │ │ │ ├── private.tsx
│ │ │ │ │ │ ├── required.tsx
│ │ │ │ │ │ ├── style.ts
│ │ │ │ │ │ ├── type.tsx
│ │ │ │ │ │ └── value.tsx
│ │ │ │ │ ├── common.ts
│ │ │ │ │ ├── drop-tip.tsx
│ │ │ │ │ ├── error.tsx
│ │ │ │ │ ├── formatter/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── active-pos.ts
│ │ │ │ │ │ ├── blink.ts
│ │ │ │ │ │ ├── disabled.ts
│ │ │ │ │ │ ├── drag-drop.ts
│ │ │ │ │ │ ├── editor-listener.tsx
│ │ │ │ │ │ ├── error-cell.ts
│ │ │ │ │ │ ├── formatter-value.ts
│ │ │ │ │ │ ├── hot-key.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── key-visible.tsx
│ │ │ │ │ │ ├── paste-data.ts
│ │ │ │ │ │ └── type-edit.ts
│ │ │ │ │ ├── indent.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── mode/
│ │ │ │ │ │ ├── declare-assign.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── type-definition.ts
│ │ │ │ │ ├── style.ts
│ │ │ │ │ ├── table.tsx
│ │ │ │ │ ├── tool-bar.tsx
│ │ │ │ │ ├── tools/
│ │ │ │ │ │ ├── create-by-data.tsx
│ │ │ │ │ │ ├── index.module.less
│ │ │ │ │ │ ├── style.ts
│ │ │ │ │ │ └── undo-redo.tsx
│ │ │ │ │ ├── type-editor.tsx
│ │ │ │ │ ├── type.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ └── type-selector/
│ │ │ │ ├── cascader-v2/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── style.ts
│ │ │ │ │ ├── trigger.tsx
│ │ │ │ │ ├── type-cascader.tsx
│ │ │ │ │ └── type-search.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── focus-item.ts
│ │ │ │ │ ├── hot-key.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── option-value.ts
│ │ │ │ │ ├── root-types.ts
│ │ │ │ │ └── use-hight-light.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── type.ts
│ │ │ │ └── utils/
│ │ │ │ └── index.tsx
│ │ │ ├── contexts/
│ │ │ │ └── index.tsx
│ │ │ ├── index.ts
│ │ │ ├── preset/
│ │ │ │ ├── index.tsx
│ │ │ │ └── object-type-editor/
│ │ │ │ └── index.tsx
│ │ │ ├── services/
│ │ │ │ ├── clipboard-service.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── shortcut-service.ts
│ │ │ │ ├── type-editor-service.ts
│ │ │ │ ├── type-operation-service.ts
│ │ │ │ ├── type-registry-manager.ts
│ │ │ │ └── utils.ts
│ │ │ ├── type-registry/
│ │ │ │ ├── array.tsx
│ │ │ │ ├── boolean.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── integer.tsx
│ │ │ │ ├── number.tsx
│ │ │ │ ├── object.tsx
│ │ │ │ └── string.tsx
│ │ │ ├── types/
│ │ │ │ ├── index.ts
│ │ │ │ ├── registry.ts
│ │ │ │ └── type-editor.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ ├── monitor-data/
│ │ │ │ ├── index.ts
│ │ │ │ ├── monitor-data.ts
│ │ │ │ └── use-monitor-data.ts
│ │ │ └── registry-adapter.tsx
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── node-engine/
│ │ ├── form/
│ │ │ ├── __tests__/
│ │ │ │ ├── create-form.test.ts
│ │ │ │ ├── field-array-model.test.ts
│ │ │ │ ├── field-model.test.ts
│ │ │ │ ├── form-model.test.ts
│ │ │ │ ├── glob.test.ts
│ │ │ │ ├── object.test.ts
│ │ │ │ ├── path.test.ts
│ │ │ │ ├── to-field-array.test.ts
│ │ │ │ ├── to-field.test.ts
│ │ │ │ ├── to-form.test.ts
│ │ │ │ ├── utils.test.ts
│ │ │ │ └── validate.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── core/
│ │ │ │ │ ├── create-form.ts
│ │ │ │ │ ├── field-array-model.ts
│ │ │ │ │ ├── field-model.ts
│ │ │ │ │ ├── form-model.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── path.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── to-field-array.ts
│ │ │ │ │ ├── to-field.ts
│ │ │ │ │ ├── to-form.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── react/
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── field-array.tsx
│ │ │ │ │ ├── field.tsx
│ │ │ │ │ ├── form.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── use-current-field-state.ts
│ │ │ │ │ ├── use-current-field.ts
│ │ │ │ │ ├── use-field-validate.ts
│ │ │ │ │ ├── use-field.ts
│ │ │ │ │ ├── use-form-state.ts
│ │ │ │ │ ├── use-form.ts
│ │ │ │ │ ├── use-watch.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── types/
│ │ │ │ │ ├── common.ts
│ │ │ │ │ ├── field.ts
│ │ │ │ │ ├── form.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── validate.ts
│ │ │ │ └── utils/
│ │ │ │ ├── dom.ts
│ │ │ │ ├── event.ts
│ │ │ │ ├── glob.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── object.ts
│ │ │ │ └── validate.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vitest.config.ts
│ │ ├── form-core/
│ │ │ ├── __tests__/
│ │ │ │ ├── form-path-service.test.ts
│ │ │ │ └── form.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── client/
│ │ │ │ │ ├── create-node-container-modules.ts
│ │ │ │ │ ├── create-node-entity-datas.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── node-material-client.ts
│ │ │ │ │ └── node-render.tsx
│ │ │ │ ├── error/
│ │ │ │ │ ├── client.ts
│ │ │ │ │ ├── error-container-module.ts
│ │ │ │ │ ├── error-node-contribution.ts
│ │ │ │ │ ├── flow-node-error-data.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── renders/
│ │ │ │ │ │ ├── default-error-render.tsx
│ │ │ │ │ │ ├── error-render.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── form/
│ │ │ │ │ ├── abilities/
│ │ │ │ │ │ ├── decorator-ability/
│ │ │ │ │ │ │ ├── decorator-ability.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ ├── default-ability/
│ │ │ │ │ │ │ ├── default-ability.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ ├── effect-ability/
│ │ │ │ │ │ │ ├── effect-ability.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── setter-ability/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── setter-ability.ts
│ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ ├── validation-ability/
│ │ │ │ │ │ │ ├── form-validate.types.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ └── validation-ability.ts
│ │ │ │ │ │ └── visibility-ability/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── visibility-ability.ts
│ │ │ │ │ ├── client/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── flow-node-form-data.ts
│ │ │ │ │ ├── form-contribution.ts
│ │ │ │ │ ├── form-core-container-module.ts
│ │ │ │ │ ├── form-node-contribution.ts
│ │ │ │ │ ├── form-render.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── models/
│ │ │ │ │ │ ├── form-ability-extension-registry.ts
│ │ │ │ │ │ ├── form-item-ability.ts
│ │ │ │ │ │ ├── form-item-material-context.ts
│ │ │ │ │ │ ├── form-item.ts
│ │ │ │ │ │ ├── form-meta.ts
│ │ │ │ │ │ ├── form-model.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── services/
│ │ │ │ │ │ ├── form-context-maker.ts
│ │ │ │ │ │ ├── form-manager.ts
│ │ │ │ │ │ ├── form-path-service.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── types/
│ │ │ │ │ ├── form-ability.types.ts
│ │ │ │ │ ├── form-meta.types.ts
│ │ │ │ │ ├── form-model.types.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── node/
│ │ │ │ │ ├── core-materials.ts
│ │ │ │ │ ├── core-plugins.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── node-container-module.ts
│ │ │ │ │ ├── node-contribution.ts
│ │ │ │ │ ├── node-engine-context.ts
│ │ │ │ │ ├── node-engine.ts
│ │ │ │ │ ├── node-manager.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── node-react/
│ │ │ │ ├── context/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── node-engine-react-context.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── use-form-Item.ts
│ │ │ │ │ └── use-node-engine-context.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ └── node/
│ │ ├── __tests__/
│ │ │ ├── form-effects.test.ts
│ │ │ ├── form-model-v2.test.ts
│ │ │ ├── form-plugins.test.ts
│ │ │ └── glob.test.ts
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── form-model-v2.ts
│ │ │ ├── form-plugin.ts
│ │ │ ├── form-render.tsx
│ │ │ ├── get-node-form.tsx
│ │ │ ├── helpers.ts
│ │ │ ├── hooks.ts
│ │ │ ├── index.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── plugins/
│ │ ├── background-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── background-layer.tsx
│ │ │ │ ├── create-background-plugin.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── export-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constant.ts
│ │ │ │ ├── create-plugin.ts
│ │ │ │ ├── download-service/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── service.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── export-image-service/
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── service.ts
│ │ │ │ │ ├── type.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── type.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── fixed-drag-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-fixed-drag-plugin.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ └── use-start-drag-node.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── fixed-history-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-fixed-history-plugin.ts
│ │ │ │ ├── fixed-history-config.ts
│ │ │ │ ├── fixed-history-registers.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── operation-metas/
│ │ │ │ │ ├── add-block.ts
│ │ │ │ │ ├── add-child-node.ts
│ │ │ │ │ ├── add-from-node.ts
│ │ │ │ │ ├── add-node.ts
│ │ │ │ │ ├── add-nodes.ts
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── create-group.ts
│ │ │ │ │ ├── delete-block.ts
│ │ │ │ │ ├── delete-child-node.ts
│ │ │ │ │ ├── delete-from-node.ts
│ │ │ │ │ ├── delete-node.ts
│ │ │ │ │ ├── delete-nodes.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── move-block.ts
│ │ │ │ │ ├── move-child-nodes.ts
│ │ │ │ │ ├── move-nodes.ts
│ │ │ │ │ └── ungroup.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── fixed-history-form-data-service.ts
│ │ │ │ │ ├── fixed-history-operation-service.ts
│ │ │ │ │ ├── fixed-history-service.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-auto-layout-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-auto-layout-plugin.tsx
│ │ │ │ ├── dagre-layout/
│ │ │ │ │ ├── acyclic.ts
│ │ │ │ │ ├── graph.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── layout.ts
│ │ │ │ │ ├── order.ts
│ │ │ │ │ ├── rank/
│ │ │ │ │ │ ├── feasible-tree.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── longest-path.ts
│ │ │ │ │ │ ├── network-simplex.ts
│ │ │ │ │ │ └── normalize-ranks.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── dagre-lib/
│ │ │ │ │ ├── acyclic.js
│ │ │ │ │ ├── add-border-segments.js
│ │ │ │ │ ├── coordinate-system.js
│ │ │ │ │ ├── data/
│ │ │ │ │ │ └── list.js
│ │ │ │ │ ├── debug.js
│ │ │ │ │ ├── greedy-fas.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── layout.js
│ │ │ │ │ ├── nesting-graph.js
│ │ │ │ │ ├── normalize.js
│ │ │ │ │ ├── order/
│ │ │ │ │ │ ├── add-subgraph-constraints.js
│ │ │ │ │ │ ├── barycenter.js
│ │ │ │ │ │ ├── build-layer-graph.js
│ │ │ │ │ │ ├── cross-count.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── init-order.js
│ │ │ │ │ │ ├── resolve-conflicts.js
│ │ │ │ │ │ ├── sort-subgraph.js
│ │ │ │ │ │ └── sort.js
│ │ │ │ │ ├── parent-dummy-chains.js
│ │ │ │ │ ├── position/
│ │ │ │ │ │ ├── bk.js
│ │ │ │ │ │ └── index.js
│ │ │ │ │ ├── rank/
│ │ │ │ │ │ ├── feasible-tree.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── network-simplex.js
│ │ │ │ │ │ └── util.js
│ │ │ │ │ ├── util.js
│ │ │ │ │ └── version.js
│ │ │ │ ├── index.ts
│ │ │ │ ├── layout/
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── dagre.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── layout.ts
│ │ │ │ │ ├── position.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── services.ts
│ │ │ │ └── type.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-container-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.ts
│ │ │ │ ├── node-into-container/
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── plugin.tsx
│ │ │ │ │ ├── service.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── sub-canvas/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── background/
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── style.ts
│ │ │ │ │ │ ├── border/
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── style.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── render/
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── style.ts
│ │ │ │ │ │ └── tips/
│ │ │ │ │ │ ├── global-store.ts
│ │ │ │ │ │ ├── icon-close.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── is-mac-os.ts
│ │ │ │ │ │ ├── style.ts
│ │ │ │ │ │ └── use-control.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── use-node-size.ts
│ │ │ │ │ │ └── use-sync-node-render-size.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── utils/
│ │ │ │ ├── adjust-sub-node-position.ts
│ │ │ │ ├── get-collision-transform.ts
│ │ │ │ ├── get-container-transforms.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── is-container.ts
│ │ │ │ ├── is-point-in-rect.ts
│ │ │ │ ├── is-rect-intersects.ts
│ │ │ │ └── next-frame.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-group-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constant.ts
│ │ │ │ ├── create-free-group-plugin.tsx
│ │ │ │ ├── group-node.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── shortcuts/
│ │ │ │ │ ├── group.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── ungroup.ts
│ │ │ │ ├── type.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── workflow-group-service.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-history-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── changes/
│ │ │ │ │ ├── add-line-change.ts
│ │ │ │ │ ├── add-node-change.ts
│ │ │ │ │ ├── change-line-data.ts
│ │ │ │ │ ├── delete-line-change.ts
│ │ │ │ │ ├── delete-node-change.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── create-free-history-plugin.ts
│ │ │ │ ├── free-history-config.ts
│ │ │ │ ├── free-history-manager.ts
│ │ │ │ ├── free-history-registers.ts
│ │ │ │ ├── handlers/
│ │ │ │ │ ├── change-content-handler.ts
│ │ │ │ │ └── drag-nodes-handler.ts
│ │ │ │ ├── history-entity-manager.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── use-undo-redo.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── operation-metas/
│ │ │ │ │ ├── add-line.ts
│ │ │ │ │ ├── add-node.ts
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── change-line-data.ts
│ │ │ │ │ ├── delete-line.ts
│ │ │ │ │ ├── delete-node.ts
│ │ │ │ │ ├── drag-nodes.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── move-child-nodes.ts
│ │ │ │ │ └── reset-layout.ts
│ │ │ │ └── types.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-hover-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-free-hover-plugin.ts
│ │ │ │ ├── hover-layer.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── selection-utils.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-lines-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── bezier-controls.spec.ts.snap
│ │ │ │ │ └── bezier-controls.spec.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── workflow-line-render/
│ │ │ │ │ │ ├── arrow.tsx
│ │ │ │ │ │ ├── index.style.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── line-svg.tsx
│ │ │ │ │ └── workflow-port-render/
│ │ │ │ │ ├── cross-hair.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.ts
│ │ │ │ ├── constants/
│ │ │ │ │ ├── lines.ts
│ │ │ │ │ └── points.ts
│ │ │ │ ├── contributions/
│ │ │ │ │ ├── bezier/
│ │ │ │ │ │ ├── bezier-controls.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── fold/
│ │ │ │ │ │ ├── fold-line.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── straight/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── point-on-line.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── create-free-lines-plugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layer/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── workflow-lines-layer.tsx
│ │ │ │ ├── type.ts
│ │ │ │ └── types/
│ │ │ │ └── arrow-renderer.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-node-panel-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── component.tsx
│ │ │ │ ├── create-plugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layer.tsx
│ │ │ │ ├── service.ts
│ │ │ │ ├── type.ts
│ │ │ │ └── utils/
│ │ │ │ ├── adjust-node-position.ts
│ │ │ │ ├── build-line.ts
│ │ │ │ ├── get-container-node.ts
│ │ │ │ ├── get-port-box.ts
│ │ │ │ ├── get-sub-nodes.ts
│ │ │ │ ├── greater-or-less.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── is-container.ts
│ │ │ │ ├── rect-distance.ts
│ │ │ │ ├── sub-nodes-auto-offset.ts
│ │ │ │ ├── sub-position-offset.ts
│ │ │ │ ├── update-sub-nodes-position.ts
│ │ │ │ └── wait-node-render.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-snap-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constant.ts
│ │ │ │ ├── create-plugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layer.tsx
│ │ │ │ ├── service.ts
│ │ │ │ ├── type.ts
│ │ │ │ └── utils.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── free-stack-plugin/
│ │ │ ├── __tests__/
│ │ │ │ ├── computing.test.ts
│ │ │ │ ├── manager.test.ts
│ │ │ │ ├── type.mock.ts
│ │ │ │ └── utils.mock.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── constant.ts
│ │ │ │ ├── create-free-stack-plugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── manager.ts
│ │ │ │ ├── stacking-computing.ts
│ │ │ │ └── type.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── group-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── group-box.tsx
│ │ │ │ │ ├── group-render.tsx
│ │ │ │ │ ├── hooks.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── constant.ts
│ │ │ │ ├── create-group-plugin.tsx
│ │ │ │ ├── group-node-register.tsx
│ │ │ │ ├── groups-layer.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── registers/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── register-clean-groups.ts
│ │ │ │ │ ├── register-group-node.ts
│ │ │ │ │ ├── register-layer.ts
│ │ │ │ │ └── register-render.tsx
│ │ │ │ └── type.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── history-node-plugin/
│ │ │ ├── __tests__/
│ │ │ │ ├── create-container.ts
│ │ │ │ └── form.test.ts
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-history-node-plugin.ts
│ │ │ │ ├── history-node-registers.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── operation-metas/
│ │ │ │ │ ├── change-form-values.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils/
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── i18n-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-i18n-plugin.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── materials-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-materials-plugin.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── minimap-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── component.tsx
│ │ │ │ ├── constant.ts
│ │ │ │ ├── create-plugin.ts
│ │ │ │ ├── draw.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layer.tsx
│ │ │ │ ├── service.ts
│ │ │ │ └── type.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── node-core-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-node-core-plugin.ts
│ │ │ │ ├── form-node-contribution.ts
│ │ │ │ ├── form-render.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── node-variable-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── PrivateScopeProvider.tsx
│ │ │ │ │ └── PublicScopeProvider.tsx
│ │ │ │ ├── create-node-variable-plugin.ts
│ │ │ │ ├── form-v2/
│ │ │ │ │ ├── create-provider-effect.ts
│ │ │ │ │ └── create-variable-provider-plugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── with-node-variables.tsx
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── panel-manager-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── components/
│ │ │ │ │ ├── panel-layer/
│ │ │ │ │ │ ├── css.ts
│ │ │ │ │ │ ├── docked-panel-layer.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── panel-layer.tsx
│ │ │ │ │ │ └── panel.tsx
│ │ │ │ │ └── resize-bar/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── contexts.ts
│ │ │ │ ├── create-panel-manager-plugin.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-global-css.ts
│ │ │ │ │ ├── use-panel-manager.ts
│ │ │ │ │ └── use-panel.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── panel-config.ts
│ │ │ │ │ ├── panel-factory.ts
│ │ │ │ │ ├── panel-layer.ts
│ │ │ │ │ ├── panel-manager.ts
│ │ │ │ │ └── panel-restore.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils.ts
│ │ │ └── tsconfig.json
│ │ ├── redux-devtool-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── connectors/
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── ecs-connector.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── variable-connector.ts
│ │ │ │ ├── create-redux-devtool-plugin.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── select-box-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-select-box-plugin.ts
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── shortcuts-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-shortcuts-plugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layers/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── shortcuts-layer.tsx
│ │ │ │ ├── shortcuts-contribution.ts
│ │ │ │ └── shortcuts-utils.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── vitest.config.ts
│ │ │ └── vitest.setup.ts
│ │ ├── test-run-plugin/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── create-test-run-plugin.ts
│ │ │ │ ├── form-engine/
│ │ │ │ │ ├── contexts.ts
│ │ │ │ │ ├── fields/
│ │ │ │ │ │ ├── create-field.tsx
│ │ │ │ │ │ ├── general-field.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── object-field.tsx
│ │ │ │ │ │ ├── reactive-field.tsx
│ │ │ │ │ │ ├── recursion-field.tsx
│ │ │ │ │ │ └── schema-field.tsx
│ │ │ │ │ ├── form/
│ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── use-create-form.ts
│ │ │ │ │ │ ├── use-field.ts
│ │ │ │ │ │ └── use-form.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── model/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── reactive/
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── use-create-form.ts
│ │ │ │ │ │ └── use-test-run-service.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── form/
│ │ │ │ │ │ ├── factory.ts
│ │ │ │ │ │ ├── form.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── manager.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── pipeline/
│ │ │ │ │ │ ├── factory.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── pipeline.ts
│ │ │ │ │ │ ├── plugin.ts
│ │ │ │ │ │ └── tap.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── test-run.ts
│ │ │ │ └── types.ts
│ │ │ └── tsconfig.json
│ │ └── variable-plugin/
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── create-variable-plugin.ts
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── runtime/
│ │ ├── interface/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── api/
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── define.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── schema.ts
│ │ │ │ │ ├── server-info/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task-cancel/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task-report/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task-result/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task-run/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task-validate/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── client/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── node/
│ │ │ │ │ ├── break/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── code/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── condition/
│ │ │ │ │ │ ├── constant.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── constant.ts
│ │ │ │ │ ├── continue/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── end/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── http/
│ │ │ │ │ │ ├── constant.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── llm/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── loop/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── start/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── runtime/
│ │ │ │ │ ├── base/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── inputs-outputs.ts
│ │ │ │ │ │ ├── invoke.ts
│ │ │ │ │ │ └── value-object.ts
│ │ │ │ │ ├── cache/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── container/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── context/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── document/
│ │ │ │ │ │ ├── document.ts
│ │ │ │ │ │ ├── edge.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── node.ts
│ │ │ │ │ │ └── port.ts
│ │ │ │ │ ├── engine/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── executor/
│ │ │ │ │ │ ├── executor.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── node-executor.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── io-center/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── message/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── reporter/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── snapshot/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── snapshot-center.ts
│ │ │ │ │ │ └── snapshot.ts
│ │ │ │ │ ├── state/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── status/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── validation/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── variable/
│ │ │ │ │ └── index.ts
│ │ │ │ └── schema/
│ │ │ │ ├── constant.ts
│ │ │ │ ├── edge.ts
│ │ │ │ ├── group.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── json-schema.ts
│ │ │ │ ├── node-meta.ts
│ │ │ │ ├── node.ts
│ │ │ │ ├── value.ts
│ │ │ │ ├── workflow.ts
│ │ │ │ └── xy.ts
│ │ │ └── tsconfig.json
│ │ ├── js-core/
│ │ │ ├── eslint.config.js
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── api/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── task-cancel.ts
│ │ │ │ │ ├── task-report.ts
│ │ │ │ │ ├── task-result.ts
│ │ │ │ │ ├── task-run.ts
│ │ │ │ │ └── task-validate.ts
│ │ │ │ ├── application/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── workflow.ts
│ │ │ │ ├── domain/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── config.ts
│ │ │ │ │ │ ├── executor/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── llm.ts
│ │ │ │ │ │ ├── schemas/
│ │ │ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ │ │ ├── basic.ts
│ │ │ │ │ │ │ ├── branch-two-layers.test.ts
│ │ │ │ │ │ │ ├── branch-two-layers.ts
│ │ │ │ │ │ │ ├── branch.test.ts
│ │ │ │ │ │ │ ├── branch.ts
│ │ │ │ │ │ │ ├── code.test.ts
│ │ │ │ │ │ │ ├── code.ts
│ │ │ │ │ │ │ ├── end-constant.test.ts
│ │ │ │ │ │ │ ├── end-constant.ts
│ │ │ │ │ │ │ ├── global-variable.test.ts
│ │ │ │ │ │ │ ├── global-variable.ts
│ │ │ │ │ │ │ ├── http-real.test.ts
│ │ │ │ │ │ │ ├── http.test.ts
│ │ │ │ │ │ │ ├── http.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── llm-real.test.ts
│ │ │ │ │ │ │ ├── llm-real.ts
│ │ │ │ │ │ │ ├── loop-break-continue.test.ts
│ │ │ │ │ │ │ ├── loop-break-continue.ts
│ │ │ │ │ │ │ ├── loop.test.ts
│ │ │ │ │ │ │ ├── loop.ts
│ │ │ │ │ │ │ ├── start-default.test.ts
│ │ │ │ │ │ │ ├── start-default.ts
│ │ │ │ │ │ │ ├── two-llm.ts
│ │ │ │ │ │ │ ├── validate-inputs.test.ts
│ │ │ │ │ │ │ └── validate-inputs.ts
│ │ │ │ │ │ ├── setup.ts
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── array-vo-data.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── snapshot.ts
│ │ │ │ │ ├── cache/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── container/
│ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── context/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── document/
│ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ ├── create-store.test.ts
│ │ │ │ │ │ │ ├── create-store.ts
│ │ │ │ │ │ │ ├── flat-schema.test.ts
│ │ │ │ │ │ │ ├── flat-schema.ts
│ │ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── entity/
│ │ │ │ │ │ │ ├── edge/
│ │ │ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── node/
│ │ │ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ └── port/
│ │ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── engine/
│ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── executor/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── io-center/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── message/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── message-center/
│ │ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── message-value-object/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── report/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── report-value-object/
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── reporter/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── snapshot/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── snapshot-center/
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── snapshot-entity/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── state/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── status/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── status-center/
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── status-entity/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── task/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── validation/
│ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── validators/
│ │ │ │ │ │ ├── cycle-detection.test.ts
│ │ │ │ │ │ ├── cycle-detection.ts
│ │ │ │ │ │ ├── edge-source-target-exist.test.ts
│ │ │ │ │ │ ├── edge-source-target-exist.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── schema-format.test.ts
│ │ │ │ │ │ ├── schema-format.ts
│ │ │ │ │ │ ├── start-end-node.test.ts
│ │ │ │ │ │ └── start-end-node.ts
│ │ │ │ │ └── variable/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── variable-store/
│ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── variable-value-object/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── infrastructure/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── compare-node-groups.test.ts
│ │ │ │ │ ├── compare-node-groups.ts
│ │ │ │ │ ├── delay.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── json-schema-validator.test.ts
│ │ │ │ │ ├── json-schema-validator.ts
│ │ │ │ │ ├── runtime-type.test.ts
│ │ │ │ │ ├── runtime-type.ts
│ │ │ │ │ ├── traverse-nodes.test.ts
│ │ │ │ │ ├── traverse-nodes.ts
│ │ │ │ │ └── uuid.ts
│ │ │ │ └── nodes/
│ │ │ │ ├── break/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── code/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── condition/
│ │ │ │ │ ├── handlers/
│ │ │ │ │ │ ├── array.ts
│ │ │ │ │ │ ├── boolean.ts
│ │ │ │ │ │ ├── datetime.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── map.ts
│ │ │ │ │ │ ├── null.ts
│ │ │ │ │ │ ├── number.ts
│ │ │ │ │ │ ├── object.ts
│ │ │ │ │ │ └── string.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── rules.ts
│ │ │ │ │ └── type.ts
│ │ │ │ ├── continue/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── empty/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── end/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── http/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── llm/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── loop/
│ │ │ │ │ └── index.ts
│ │ │ │ └── start/
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vitest.config.ts
│ │ └── nodejs/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── api/
│ │ │ │ ├── create-api.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── trpc.ts
│ │ │ │ └── type.ts
│ │ │ ├── config/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ └── server/
│ │ │ ├── context.ts
│ │ │ ├── docs.ts
│ │ │ ├── index.ts
│ │ │ └── type.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ └── variable-engine/
│ ├── json-schema/
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ ├── base-type-manager.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── container-module.tsx
│ │ │ ├── context.tsx
│ │ │ ├── index.ts
│ │ │ └── json-schema/
│ │ │ ├── index.ts
│ │ │ ├── json-schema-type-manager.tsx
│ │ │ ├── type-definition/
│ │ │ │ ├── array.tsx
│ │ │ │ ├── boolean.tsx
│ │ │ │ ├── date-time.tsx
│ │ │ │ ├── default.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── integer.tsx
│ │ │ │ ├── map.tsx
│ │ │ │ ├── number.tsx
│ │ │ │ ├── object.tsx
│ │ │ │ ├── string.tsx
│ │ │ │ └── unknown.tsx
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── variable-core/
│ │ ├── __mocks__/
│ │ │ ├── container.ts
│ │ │ ├── mock-chain.ts
│ │ │ └── variables.ts
│ │ ├── __tests__/
│ │ │ ├── ast/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── key-path-expression-v2.test.ts.snap
│ │ │ │ │ ├── variable-declaration.test.ts.snap
│ │ │ │ │ └── variable-with-initializer.test.ts.snap
│ │ │ │ ├── ast-decorators.test.ts
│ │ │ │ ├── key-path-expression-v2.test.ts
│ │ │ │ ├── variable-declaration.test.ts
│ │ │ │ ├── variable-match.test.ts
│ │ │ │ ├── variable-throw-errors.test.ts
│ │ │ │ ├── variable-type-equal.test.ts
│ │ │ │ └── variable-with-initializer.test.ts
│ │ │ ├── case-run-down/
│ │ │ │ ├── blockwise-python-expression.test.ts
│ │ │ │ └── variable-rename-listener.test.ts
│ │ │ └── scope/
│ │ │ └── variable-engine.test.ts
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── ast/
│ │ │ │ ├── ast-node.ts
│ │ │ │ ├── ast-registers.ts
│ │ │ │ ├── common/
│ │ │ │ │ ├── data-node.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── list-node.ts
│ │ │ │ │ └── map-node.ts
│ │ │ │ ├── declaration/
│ │ │ │ │ ├── base-variable-field.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── property.ts
│ │ │ │ │ ├── variable-declaration-list.ts
│ │ │ │ │ └── variable-declaration.ts
│ │ │ │ ├── expression/
│ │ │ │ │ ├── base-expression.ts
│ │ │ │ │ ├── enumerate-expression.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── keypath-expression.ts
│ │ │ │ │ ├── legacy-keypath-expression.ts
│ │ │ │ │ └── wrap-array-expression.ts
│ │ │ │ ├── factory.ts
│ │ │ │ ├── flags.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── match.ts
│ │ │ │ ├── type/
│ │ │ │ │ ├── array.ts
│ │ │ │ │ ├── base-type.ts
│ │ │ │ │ ├── boolean.ts
│ │ │ │ │ ├── custom-type.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── integer.ts
│ │ │ │ │ ├── map.ts
│ │ │ │ │ ├── number.ts
│ │ │ │ │ ├── object.ts
│ │ │ │ │ ├── string.ts
│ │ │ │ │ └── union.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils/
│ │ │ │ ├── expression.ts
│ │ │ │ ├── helpers.ts
│ │ │ │ ├── inversify.ts
│ │ │ │ ├── observable.ts
│ │ │ │ └── variable-field.ts
│ │ │ ├── index.ts
│ │ │ ├── providers.ts
│ │ │ ├── react/
│ │ │ │ ├── context.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-available-variables.ts
│ │ │ │ │ ├── use-output-variables.ts
│ │ │ │ │ └── use-scope-available.ts
│ │ │ │ └── index.tsx
│ │ │ ├── scope/
│ │ │ │ ├── datas/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── scope-available-data.ts
│ │ │ │ │ ├── scope-event-data.ts
│ │ │ │ │ └── scope-output-data.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── scope-chain.ts
│ │ │ │ ├── scope.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── variable-table.ts
│ │ │ ├── services/
│ │ │ │ ├── index.ts
│ │ │ │ └── variable-field-key-rename-service.ts
│ │ │ ├── utils/
│ │ │ │ ├── memo.ts
│ │ │ │ └── toDisposable.tsx
│ │ │ ├── variable-container-module.ts
│ │ │ └── variable-engine.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ └── variable-layout/
│ ├── __mocks__/
│ │ ├── container.ts
│ │ ├── fixed-layout-specs.ts
│ │ ├── free-layout-specs.ts
│ │ ├── run-fixed-layout-test.ts
│ │ └── run-free-layout-test.ts
│ ├── __tests__/
│ │ ├── __snapshots__/
│ │ │ ├── variable-fix-enable-global-scope.test.ts.snap
│ │ │ ├── variable-fix-layout-filter-start-end.test.ts.snap
│ │ │ ├── variable-fix-layout-group.test.ts.snap
│ │ │ ├── variable-fix-layout-no-config.test.ts.snap
│ │ │ ├── variable-fix-layout-transform-empty.test.ts.snap
│ │ │ ├── variable-fix-layout.test.ts.snap
│ │ │ ├── variable-free-enable-global-scope.test.ts.snap
│ │ │ ├── variable-free-is-node-children-private.test.ts.snap
│ │ │ ├── variable-free-layout-transform-empty.test.ts.snap
│ │ │ └── variable-free-layout.test.ts.snap
│ │ ├── variable-fix-enable-global-scope.test.ts
│ │ ├── variable-fix-layout-filter-start-end.test.ts
│ │ ├── variable-fix-layout-group.test.ts
│ │ ├── variable-fix-layout-no-config.test.ts
│ │ ├── variable-fix-layout-transform-empty.test.ts
│ │ ├── variable-fix-layout.test.ts
│ │ ├── variable-free-enable-global-scope.test.ts
│ │ ├── variable-free-is-node-children-private.test.ts
│ │ ├── variable-free-layout-transform-empty.test.ts
│ │ └── variable-free-layout.test.ts
│ ├── eslint.config.js
│ ├── package.json
│ ├── src/
│ │ ├── chains/
│ │ │ ├── fixed-layout-scope-chain.ts
│ │ │ └── free-layout-scope-chain.ts
│ │ ├── flow-node-variable-data.ts
│ │ ├── index.ts
│ │ ├── scopes/
│ │ │ └── global-scope.ts
│ │ ├── services/
│ │ │ └── scope-chain-transform-service.ts
│ │ ├── types.ts
│ │ ├── utils.ts
│ │ └── variable-chain-config.ts
│ ├── tsconfig.json
│ ├── vitest.config.ts
│ └── vitest.setup.ts
└── rush.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .claude/commands/add-tests.md
================================================
---
description: 为代码添加单元测试(支持增量和存量代码测试补齐)
---
# 单元测试生成
## 用法
- `/add-tests [dir]` - 为指定模块或文件添加单元测试
- `[dir]` 可选参数:包名(以 @ 开头)、文件路径或目录路径
- 不指定 `[dir]` 则默认为全代码库(会提示用户确认)
- 执行后会询问用户选择:增量代码测试(基于 git diff)或存量代码测试补齐
## 命令说明
此命令用于自动生成和补充单元测试,确保代码质量。FlowGram 使用 **Vitest** 作为测试框架。
### 测试覆盖率目标
根据包的类型和重要性,测试覆盖率要求如下:
- **核心引擎层**(canvas-engine、node-engine、variable-engine、runtime)
- 覆盖率目标:≥ 85%
- 包括:@flowgram.ai/core、@flowgram.ai/form、@flowgram.ai/variable-core、@flowgram.ai/runtime-js 等
- **插件和客户端层**(plugins、client)
- 覆盖率目标:≥ 60%
- 包括:@flowgram.ai/editor、各类 plugin 包、@flowgram.ai/fixed-layout-editor 等
- **工具和示例**(common、apps)
- 覆盖率目标:尽可能覆盖关键逻辑
- 包括:@flowgram.ai/utils、demo 应用等
### 测试文件组织
- 测试文件位置:
- `__tests__/` 目录(推荐)
- 或与源文件同级的 `*.test.ts`/`*.test.tsx` 文件
- 命名规范:
- 对于 `src/core/utils.ts`,测试文件为 `__tests__/core/utils.test.ts` 或 `src/core/utils.test.ts`
## 测试生成流程
### 0. 命令执行和用户确认
1. **确认范围**:
- 如果未指定 `[dir]`,询问用户是否要对全代码库操作,还是指定具体目录
- 全代码库操作工作量巨大,需要用户明确确认
2. **选择模式**:
- 询问用户选择测试模式:
- **增量代码测试**:仅为 git diff 中的新增/修改代码添加测试
- **存量代码测试补齐**:扫描所有代码,补齐缺失或覆盖率不足的测试
### 1. 识别待测代码
**增量代码模式**:
```bash
# 检查 git diff 获取所有修改的文件
git diff --name-only
git diff <file> # 查看具体变更
```
**存量代码模式**:
- 扫描指定目录下所有源文件(排除已有完整测试的文件)
- 查找缺少测试或覆盖率不足的文件
- 优先处理核心引擎层的文件
### 2. 确定包信息和覆盖率目标
1. 从最近的 `package.json` 获取包名
2. 使用包名在 `rush.json` 中查找包的分类(projectFolder)
3. 根据包所在目录确定覆盖率目标:
- `packages/canvas-engine/`、`packages/node-engine/`、`packages/variable-engine/`、`packages/runtime/` → 85%
- `packages/plugins/`、`packages/client/` → 60%
- `packages/common/`、`apps/` → 尽可能覆盖
### 3. 生成测试代码
**测试重点**:
- 新增或修改的函数、方法、类
- 分支逻辑(if/else、switch/case)
- 边界条件和异常处理
- 依赖注入容器(inversify)的模拟
- 响应式状态(ReactiveState)的行为验证
**Vitest 最佳实践**:
```typescript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen } from '@testing-library/react';
describe('ModuleName', () => {
beforeEach(() => {
// 初始化
});
it('should handle specific case', () => {
// 测试逻辑
expect(result).toBe(expected);
});
});
```
**React 组件测试**:
- 使用 `@testing-library/react` 进行组件测试
- 为关键元素添加 `data-testid` 属性
- 测试用户交互和状态变化
**依赖注入测试**:
- 使用 `vi.mock()` 模拟依赖
- 创建测试容器来验证服务注册
### 4. 执行测试验证
**单包测试**:
```bash
cd packages/canvas-engine/core
rushx test # 运行测试
rushx test:cov # 生成覆盖率报告
```
**全局测试**:
```bash
rush test # 运行所有包的测试
rush test:cov # 生成所有包的覆盖率报告
```
**每次添加测试后**:
1. 立即运行测试确保通过
2. 检查覆盖率是否达到目标
3. 修复失败的测试或调整测试用例
4. 继续处理下一个文件
### 5. 输出测试文件
- 将测试文件保存到 `__tests__/` 目录(优先)或源文件同级
- 保持目录结构与源代码一致
- 添加必要的导入和类型声明
## 示例命令
```bash
# 为某个包添加测试(执行后会询问增量或存量)
/add_tests @flowgram.ai/core
# 为特定目录添加测试
/add_tests packages/node-engine/form
# 为单个文件添加测试
/add_tests packages/canvas-engine/core/src/core/utils.ts
# 全代码库测试(会先确认范围,再询问增量或存量)
/add_tests
```
### 典型使用场景
**场景 1:为新功能添加测试**
```bash
/add_tests packages/plugins/my-new-plugin
# 选择:增量代码测试
# 结果:仅为 git diff 中的新代码生成测试
```
**场景 2:提升现有包的测试覆盖率**
```bash
/add_tests @flowgram.ai/variable-core
# 选择:存量代码测试补齐
# 结果:扫描所有代码,补齐缺失的测试,目标 85% 覆盖率
```
**场景 3:全面测试检查**
```bash
/add_tests
# 确认:选择要处理的目录或全代码库
# 选择:存量代码测试补齐
# 结果:系统性地补齐整个项目的测试
```
## 注意事项
1. **优先级**:优先为核心引擎层包编写高质量测试
2. **隔离性**:每个测试应该独立,不依赖其他测试的执行顺序
3. **可读性**:测试用例命名应清晰描述测试场景(使用中文或英文皆可)
4. **Mock 策略**:
- 外部依赖(网络请求、文件系统)必须 mock
- 内部复杂模块可以考虑 mock
- 简单工具函数可以直接使用
5. **快照测试**:谨慎使用快照测试,仅用于稳定的 UI 或数据结构
6. **异步测试**:使用 async/await 处理异步操作,确保 Promise 正确解决
## 工作流程总结
1. **接收命令**:用户执行 `/add_tests [dir]`
2. **确认范围**:如果未指定 dir,询问用户要处理全代码库还是指定目录
3. **选择模式**:询问用户选择增量代码测试或存量代码测试补齐
4. **分析代码**:根据选择的模式识别待测代码
5. **确定目标**:根据包的分类确定覆盖率目标
6. **生成测试**:逐文件生成测试用例
7. **运行验证**:每生成一批测试后立即运行验证
8. **修复问题**:修复失败的测试或调整测试用例
9. **检查覆盖率**:查看覆盖率报告是否达标
10. **继续迭代**:直到达到目标覆盖率或所有文件都有测试
开始生成测试吧!
================================================
FILE: .claude/skills/create-node/SKILL.md
================================================
---
skill_name: create-node
description: 用于在 FlowGram demo-free-layout 中创建新的自定义节点,支持简单节点(自动表单)和复杂节点(自定义 UI)
version: 1.0.0
tags: [flowgram, node, workflow, custom-node]
---
# FlowGram Custom Node Development
## 概述
本 SKILL 用于指导在 FlowGram 项目的 `apps/demo-free-layout/src/nodes` 目录下创建新的自定义工作流节点。
## 核心概念
### 节点数据结构
节点数据在保存时会存储到后端,基本结构如下:
```typescript
{
id: 'node_xxxxx', // 节点 ID
type: 'node_type', // 节点类型
data: {
title: 'Node Title', // 节点标题
inputsValues: { ... }, // 节点表单字段的初始值(实际的值)
inputs: { ... }, // 节点表单的 JSON Schema(定义表单结构)
outputs: { ... }, // 节点输出的 JSON Schema(工作流执行时的输出)
// ... 其他自定义字段
}
}
```
### 三个核心字段
#### 1. `data.inputsValues` - 节点表单字段的初始值
存储表单中各个字段的实际值,每个字段值包含 `type` 和 `content` 两个属性:
```typescript
inputsValues: {
url: {
type: 'constant', // 常量类型
content: 'https://...', // 实际的值
},
prompt: {
type: 'template', // 模板类型(支持变量引用)
content: 'Hello {var}', // 可以引用变量
},
}
```
**`type` 的可选值**:
- `'constant'`:常量值,不支持变量引用
- `'template'`:模板值,支持 `{variableName}` 语法引用变量
- `'variable'`:变量引用
#### 2. `data.inputs` - 节点表单的 JSON Schema
使用 JSON Schema 定义表单的结构,系统会根据这个 Schema 自动生成表单界面:
```typescript
inputs: {
type: 'object',
required: ['url'], // 必填字段
properties: {
url: {
type: 'string',
},
timeout: {
type: 'number',
minimum: 0,
maximum: 60000,
},
prompt: {
type: 'string',
extra: {
formComponent: 'prompt-editor', // 指定自定义组件
},
},
},
}
```
#### 3. `data.outputs` - 节点输出的 JSON Schema
定义节点在工作流执行时的输出数据结构,供下游节点使用:
```typescript
outputs: {
type: 'object',
properties: {
body: { type: 'string' },
statusCode: { type: 'number' },
headers: { type: 'object' },
},
}
```
### 三者的关系
```
inputs (JSON Schema) → 定义表单结构
inputsValues (实际值) → 存储表单数据
[节点执行]
outputs (JSON Schema) → 定义输出结构
```
### 字段类型与自动组件映射
在简单节点中,字段类型会自动匹配对应的表单组件:
| 字段类型 | `extra.formComponent` | 默认组件 |
|---------|---------------------|---------|
| `string` | - | Input |
| `string` | `'prompt-editor'` | PromptEditorWithVariables |
| `number` | - | InputNumber |
| `boolean` | - | Switch |
| `object` | - | JsonCodeEditor |
| `array` | - | JsonCodeEditor |
## 节点开发模式
### 1. 简单节点(自动表单模式)
- **适用场景**:节点配置较为简单,不需要复杂的自定义 UI
- **特点**:根据 `inputs` Schema 自动生成表单
- **示例**:LLM 节点
- **文件结构**:只需要 `index.ts` 文件
- **模板位置**:`./templates/simple-node/index.ts`
### 2. 复杂节点(自定义 UI 模式)
- **适用场景**:需要自定义表单布局、特殊交互或复杂的 UI 组件
- **特点**:完全控制表单渲染和交互逻辑
- **示例**:HTTP 节点
- **文件结构**:
```
{节点名}/
├── index.tsx # 节点注册配置
├── form-meta.tsx # 自定义表单渲染
├── types.tsx # TypeScript 类型定义
└── components/ # 自定义组件
└── *.tsx
```
- **模板位置**:`./templates/complex-node/`
## 开发流程
### Step 1: 规划节点
确定节点的核心信息:
- **节点类型 ID**:唯一标识,如 `database`、`webhook`
- **节点功能**:明确节点要做什么
- **输入参数**:节点需要哪些配置项
- **输出数据**:节点执行后返回什么数据
- **UI 复杂度**:是否需要自定义 UI
### Step 2: 选择开发模式
```
是否需要自定义 UI?
├─ 否 → 使用简单节点模式(复制 templates/simple-node/)
└─ 是 → 使用复杂节点模式(复制 templates/complex-node/)
```
### Step 3: 复制模板并修改
#### 简单节点
```bash
# 复制模板
cp .claude/skills/create-node/templates/simple-node/index.ts \
apps/demo-free-layout/src/nodes/{节点名}/index.ts
# 修改模板中的 TODO 标记
# - {NODE_NAME} → 节点名(PascalCase)
# - {NODE_TYPE} → 节点类型枚举值
# - {node_name} → 节点名(kebab-case)
# - {node_type} → 节点类型(小写)
```
#### 复杂节点
```bash
# 复制模板目录
cp -r .claude/skills/create-node/templates/complex-node \
apps/demo-free-layout/src/nodes/{节点名}
# 修改所有文件中的 TODO 标记
```
### Step 4: 添加节点类型常量
编辑 `apps/demo-free-layout/src/nodes/constants.ts`:
```typescript
export enum WorkflowNodeType {
// ... 现有节点
{节点类型} = '{节点类型}',
}
```
### Step 5: 注册节点
编辑 `apps/demo-free-layout/src/nodes/index.ts`:
```typescript
// 导入节点
export { {节点名}NodeRegistry } from './{节点名}';
// 添加到注册列表
export const nodeRegistries: FlowNodeRegistry[] = [
// ... 现有节点
{节点名}NodeRegistry,
];
```
### Step 6: 准备节点图标
在 `apps/demo-free-layout/src/assets/` 目录下添加节点图标(SVG 或 JPG 格式):
```
apps/demo-free-layout/src/assets/icon-{节点名}.svg
```
### Step 7: 测试验证
```bash
# 启动开发服务器
rush dev:demo-free-layout
# 在浏览器中测试节点功能
```
## 常用组件和工具
### FlowGram 组件
从 `@flowgram.ai/form-materials` 导入:
```typescript
import {
PromptEditorWithVariables, // 带变量的提示词编辑器
VariableSelector, // 变量选择器
JsonCodeEditor, // JSON 代码编辑器
CodeEditor, // 代码编辑器
DisplayOutputs, // 输出字段展示
DynamicValueInput, // 动态值输入
createInferInputsPlugin, // 输入推断插件
} from '@flowgram.ai/form-materials';
```
### Semi UI 组件
从 `@douyinfe/semi-ui` 导入:
```typescript
import {
Input,
InputNumber,
Select,
Switch,
Button,
Divider,
} from '@douyinfe/semi-ui';
```
### 表单工具
```typescript
import { Field } from '@flowgram.ai/free-layout-editor';
import { FormItem, FormHeader, FormContent } from '../../form-components';
import { useNodeRenderContext } from '../../hooks';
```
## 最佳实践
### 1. 节点设计
- **单一职责**:一个节点只做一件事
- **清晰的 Schema**:明确定义 inputs 和 outputs
- **合理的默认值**:提供有意义的初始配置
- **友好的描述**:为节点和字段提供清晰的描述
### 2. Schema 设计
```typescript
// ✅ 好的做法:清晰的 Schema
inputs: {
type: 'object',
required: ['url', 'method'],
properties: {
url: {
type: 'string',
description: 'API endpoint URL',
},
method: {
type: 'string',
enum: ['GET', 'POST', 'PUT', 'DELETE'],
},
},
}
// ❌ 不好的做法:缺少约束
inputs: {
type: 'object',
properties: {
url: { type: 'string' },
method: { type: 'string' },
},
}
```
### 3. 表单组件使用
```typescript
// ✅ 好的做法:使用 Field 绑定表单状态
<Field<string> name="api.url">
{({ field }) => (
<Input
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
// ❌ 不好的做法:手动管理状态
const [url, setUrl] = useState('');
<Input value={url} onChange={setUrl} />
```
### 4. 只读状态处理
```typescript
export function CustomComponent() {
const { readonly } = useNodeRenderContext();
return (
<Input disabled={readonly} {...props} />
);
}
```
## 常见问题
### Q1: 如何选择简单节点还是复杂节点?
**判断标准**:
- 字段简单 + 默认布局满足需求 → 简单节点
- 需要自定义布局/特殊交互 → 复杂节点
### Q2: 如何使用变量功能?
在 `inputs` Schema 中使用 `formComponent: 'prompt-editor'`,并在 `inputsValues` 中使用 `type: 'template'`。
### Q3: 如何定义必填字段?
在 `inputs` Schema 的 `required` 数组中列出必填字段名。
### Q4: `inputsValues` 和 `inputs` 必须一致吗?
是的。`inputsValues` 中的字段必须在 `inputs.properties` 中有对应的定义。
### Q5: 节点图标支持什么格式?
支持 SVG、JPG、PNG 格式,推荐使用 SVG。
### Q6: 如何调试节点?
1. 使用浏览器开发者工具查看 console.log
2. 在 FormRender 组件中添加 `console.log(form.getValues())`
3. 使用 React DevTools 查看组件状态
## 参考资源
### 代码示例
- **简单节点**: `apps/demo-free-layout/src/nodes/llm/`
- **复杂节点**: `apps/demo-free-layout/src/nodes/http/`
- **表单组件**: `apps/demo-free-layout/src/form-components/`
- **默认表单**: `apps/demo-free-layout/src/nodes/default-form-meta.tsx`
### 模板文件
- **简单节点模板**: `.claude/skills/create-node/templates/simple-node/`
- **复杂节点模板**: `.claude/skills/create-node/templates/complex-node/`
### 相关文档
- FlowGram 官方文档: https://flowgram.ai
- JSON Schema 规范: https://json-schema.org/
- Semi UI 组件库: https://semi.design/
### 开发命令
```bash
# 启动开发服务器
rush dev:demo-free-layout
# 构建项目
rush build
# 类型检查
rush ts-check
# 代码检查
rush lint
```
## 快速开始检查清单
创建新节点时,按照此检查清单执行:
- [ ] 规划节点功能和数据结构
- [ ] 选择开发模式(简单 vs 复杂)
- [ ] 复制对应的模板文件
- [ ] 修改模板中的 TODO 标记
- [ ] 在 `constants.ts` 中添加节点类型
- [ ] 在 `index.ts` 中注册节点
- [ ] 准备节点图标文件
- [ ] 启动开发服务器测试
- [ ] 验证节点功能正常
================================================
FILE: .claude/skills/create-node/templates/README.md
================================================
# Node Templates
这些是创建新节点的模板文件,使用时需要替换其中的占位符。
## 占位符说明
在使用模板时,需要将以下占位符替换为实际值:
| 占位符 | 说明 | 示例 |
|-------|------|------|
| `{NODE_NAME}` | 节点名称(PascalCase) | `Database`, `Webhook`, `EmailSender` |
| `{NODE_TYPE}` | 节点类型枚举值(SCREAMING_SNAKE_CASE) | `DATABASE`, `WEBHOOK`, `EMAIL_SENDER` |
| `{node_name}` | 节点名称(kebab-case,用于 ID 前缀) | `database`, `webhook`, `email_sender` |
| `{node_type}` | 节点类型(小写,用于 type 字段) | `database`, `webhook`, `email_sender` |
| `{节点功能描述}` | 节点的功能描述(中文) | `发送邮件`, `查询数据库`, `调用 Webhook` |
## 使用方法
### 简单节点
```bash
# 1. 复制模板
cp .claude/skills/create-node/templates/simple-node/index.ts \
apps/demo-free-layout/src/nodes/database/index.ts
# 2. 替换占位符
# {NODE_NAME} → Database
# {NODE_TYPE} → DATABASE
# {node_name} → database
# {node_type} → database
# {节点功能描述} → 查询数据库
```
### 复杂节点
```bash
# 1. 复制模板目录
cp -r .claude/skills/create-node/templates/complex-node \
apps/demo-free-layout/src/nodes/webhook
# 2. 替换所有文件中的占位符
# {NODE_NAME} → Webhook
# {NODE_TYPE} → WEBHOOK
# {node_name} → webhook
# {node_type} → webhook
# {节点功能描述} → 调用 Webhook
```
## 快速替换脚本(可选)
如果需要批量替换,可以使用以下命令(macOS/Linux):
```bash
# 设置变量
NODE_NAME="Database"
NODE_TYPE="DATABASE"
node_name="database"
node_type="database"
description="查询数据库"
# 批量替换
find apps/demo-free-layout/src/nodes/database -type f -name "*.ts*" -exec sed -i '' \
-e "s/{NODE_NAME}/$NODE_NAME/g" \
-e "s/{NODE_TYPE}/$NODE_TYPE/g" \
-e "s/{node_name}/$node_name/g" \
-e "s/{node_type}/$node_type/g" \
-e "s/{节点功能描述}/$description/g" \
{} +
```
================================================
FILE: .claude/skills/create-node/templates/complex-node/components/custom-component.tsx
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { Field } from '@flowgram.ai/free-layout-editor';
import { Input, Select } from '@douyinfe/semi-ui';
import { useNodeRenderContext } from '../../../hooks';
import { FormItem } from '../../../form-components';
/**
* 自定义表单组件
*/
export function CustomComponent() {
const { readonly } = useNodeRenderContext();
return (
<div>
<FormItem name="配置项名称" required vertical type="string">
<Field<string> name="customConfig.key" defaultValue="">
{({ field }) => (
<Input
value={field.value}
onChange={(value) => field.onChange(value)}
disabled={readonly}
placeholder="请输入..."
/>
)}
</Field>
</FormItem>
{/* TODO: 添加更多表单字段 */}
<FormItem name="选择器示例" vertical type="string">
<Field<string> name="customConfig.option" defaultValue="option1">
{({ field }) => (
<Select
value={field.value}
onChange={(value) => field.onChange(value as string)}
disabled={readonly}
style={{ width: '100%' }}
optionList={[
{ label: '选项 1', value: 'option1' },
{ label: '选项 2', value: 'option2' },
{ label: '选项 3', value: 'option3' },
]}
/>
)}
</Field>
</FormItem>
</div>
);
}
================================================
FILE: .claude/skills/create-node/templates/complex-node/form-meta.tsx
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { FormMeta, FormRenderProps } from '@flowgram.ai/free-layout-editor';
import { DisplayOutputs } from '@flowgram.ai/form-materials';
import { Divider } from '@douyinfe/semi-ui';
import { FormHeader, FormContent } from '../../form-components';
import { {NODE_NAME}NodeJSON } from './types';
import { CustomComponent } from './components/custom-component';
import { defaultFormMeta } from '../default-form-meta';
/**
* 表单渲染组件
*/
export const FormRender = ({ form }: FormRenderProps<{NODE_NAME}NodeJSON>) => (
<>
<FormHeader />
<FormContent>
{/* TODO: 添加自定义组件 */}
<CustomComponent />
<Divider />
{/* 显示节点输出 */}
<DisplayOutputs displayFromScope />
</FormContent>
</>
);
/**
* 表单配置
*/
export const formMeta: FormMeta = {
render: (props) => <FormRender {...props} />,
effect: defaultFormMeta.effect,
plugins: [
// TODO: 根据需要添加插件
// createInferInputsPlugin({ sourceKey: 'xxxValues', targetKey: 'xxx' }),
],
};
================================================
FILE: .claude/skills/create-node/templates/complex-node/index.tsx
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { nanoid } from 'nanoid';
import { WorkflowNodeType } from '../constants';
import { FlowNodeRegistry } from '../../typings';
import iconNode from '../../assets/icon-{NODE_NAME}.svg'; // TODO: 准备图标文件
import { formMeta } from './form-meta';
let index = 0;
export const {NODE_NAME}NodeRegistry: FlowNodeRegistry = {
type: WorkflowNodeType.{NODE_TYPE}, // TODO: 在 constants.ts 中定义
info: {
icon: iconNode,
description: '{节点功能描述}', // TODO: 修改描述
},
meta: {
size: {
width: 360,
height: 390,
},
},
onAdd() {
return {
id: `{node_name}_${nanoid(5)}`, // TODO: 修改前缀
type: '{node_type}', // TODO: 与 WorkflowNodeType 保持一致
data: {
title: `{NODE_NAME}_${++index}`, // TODO: 修改标题前缀
// TODO: 根据实际需求定义自定义字段
customConfig: {
key: 'value',
},
// 节点输出数据的 JSON Schema
outputs: {
type: 'object',
properties: {
// TODO: 定义节点执行后的输出结构
result: { type: 'string' },
status: { type: 'number' },
},
},
},
};
},
formMeta: formMeta, // 引入自定义表单
};
================================================
FILE: .claude/skills/create-node/templates/complex-node/types.tsx
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { FlowNodeJSON } from '../../typings';
/**
* 节点数据类型定义
*/
export interface {NODE_NAME}NodeJSON extends FlowNodeJSON {
data: FlowNodeJSON['data'] & {
// TODO: 根据实际需求定义自定义字段类型
customConfig?: {
key: string;
// 其他自定义字段
};
};
}
================================================
FILE: .claude/skills/create-node/templates/simple-node/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { nanoid } from 'nanoid';
import { WorkflowNodeType } from '../constants';
import { FlowNodeRegistry } from '../../typings';
import iconNode from '../../assets/icon-{NODE_NAME}.svg'; // TODO: 准备图标文件
let index = 0;
export const {NODE_NAME}NodeRegistry: FlowNodeRegistry = {
type: WorkflowNodeType.{NODE_TYPE}, // TODO: 在 constants.ts 中定义
info: {
icon: iconNode,
description: '{节点功能描述}', // TODO: 修改描述
},
meta: {
size: {
width: 360,
height: 390,
},
},
onAdd() {
// 返回节点的初始数据,这些数据会被保存到后端
return {
id: `{node_name}_${nanoid(5)}`, // TODO: 修改前缀
type: '{node_type}', // TODO: 与 WorkflowNodeType 保持一致
data: {
title: `{NODE_NAME}_${++index}`, // TODO: 修改标题前缀
// 节点表单字段的初始值
inputsValues: {
// TODO: 根据实际需求定义字段初始值
field1: {
type: 'constant', // 常量类型
content: '默认值', // 字段的初始值
},
field2: {
type: 'constant',
content: 100,
},
promptField: {
type: 'template', // 支持变量的模板类型
content: '',
},
},
// 节点表单的 JSON Schema(定义表单结构)
inputs: {
type: 'object',
required: ['field1'], // TODO: 定义必填字段
properties: {
// TODO: 根据实际需求定义字段 Schema
field1: {
type: 'string',
// 使用默认 Input 组件
},
field2: {
type: 'number',
minimum: 0,
maximum: 100,
},
promptField: {
type: 'string',
// 使用 PromptEditorWithVariables 组件
extra: {
formComponent: 'prompt-editor',
},
},
booleanField: {
type: 'boolean',
// 使用 Switch 组件
},
objectField: {
type: 'object',
// 使用 JsonCodeEditor 组件
},
},
},
// 节点输出数据的 JSON Schema(工作流执行时的输出)
outputs: {
type: 'object',
properties: {
// TODO: 定义节点执行后的输出结构
result: { type: 'string' },
status: { type: 'number' },
},
},
},
};
},
};
================================================
FILE: .claude/skills/material-component-dev/SKILL.md
================================================
---
skill_name: material-component-dev
description: FlowGram 物料组件开发指南 - 用于在 form-materials 包中创建新的物料组件
version: 1.0.0
tags: [flowgram, material, component, development]
---
# FlowGram Material Component Development
## 概述
本 SKILL 用于指导在 FlowGram 项目的 `@flowgram.ai/form-materials` 包中创建新的物料组件。
## 核心原则
### 1. 组件位置
- ✅ **在现有包中创建**:直接在 `packages/materials/form-materials/src/components/` 下创建组件目录
- ❌ **不要单独拆包**:不创建新的 npm 包,保持简洁
### 2. 代码质量
- ✅ **使用 named export**:所有导出使用 named export 提高 tree shake 性能
- ❌ **不写单元测试**:通过 Storybook 进行手动测试
- ✅ **通过类型检查**:必须通过 `yarn ts-check`
- ✅ **符合代码规范**:遵循项目 ESLint 规则
### 3. 物料设计
- ✅ **保持精简**:只保留必要的 props,不添加非核心功能配置项
- ✅ **功能单一**:一个物料只做一件事
- ✅ **使用内部依赖**:优先使用 FlowGram 内部的组件和类型
### 4. 技术栈
- **UI 组件库**:`@douyinfe/semi-ui`
- **代码编辑器**:`JsonCodeEditor`, `CodeEditor` 等来自 `../code-editor`
- **类型定义**:`IJsonSchema` 来自 `@flowgram.ai/json-schema`(不使用外部的 `json-schema` 包)
- **React**:必须显式 `import React` 避免 UMD 全局引用错误
## 开发流程
### Step 1: 规划组件结构
确定组件的:
- **功能**:组件要解决什么问题
- **Props 接口**:只保留核心必需的 props
- **命名**:使用 PascalCase,清晰描述功能
### Step 2: 创建目录结构
```bash
mkdir -p packages/materials/form-materials/src/components/{组件名}/utils
```
典型结构:
```
packages/materials/form-materials/src/components/{组件名}/
├── index.tsx # 导出文件 (named export)
├── {组件名}.tsx # 主组件
├── {辅助组件}.tsx # 可选的辅助组件
└── utils/ # 可选的工具函数
└── *.ts
```
### Step 3: 实现组件
#### 3.1 工具函数(如需要)
```typescript
// utils/helper.ts
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
export function helperFunction(input: string): Output {
// 实现逻辑
}
```
#### 3.2 辅助组件(如需要)
```typescript
// modal.tsx
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React, { useState } from 'react';
import { Modal, Typography } from '@douyinfe/semi-ui';
interface ModalProps {
visible: boolean;
onClose: () => void;
onConfirm: (data: SomeType) => void;
}
export function MyModal({ visible, onClose, onConfirm }: ModalProps) {
// 实现
}
```
#### 3.3 主组件
```typescript
// my-component.tsx
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React, { useState } from 'react';
import { Button } from '@douyinfe/semi-ui';
import type { IJsonSchema } from '@flowgram.ai/json-schema';
export interface MyComponentProps {
/** 核心功能的回调 */
onSomething?: (data: SomeType) => void;
}
// 使用 named export,不使用 default export
export function MyComponent({ onSomething }: MyComponentProps) {
const [visible, setVisible] = useState(false);
return (
<>
<Button onClick={() => setVisible(true)}>
操作文本
</Button>
{/* 其他组件 */}
</>
);
}
```
**关键点**:
- ✅ 显式 `import React`
- ✅ 使用 Semi UI 组件
- ✅ 使用 function 声明而非 React.FC
- ✅ Props 精简,只保留核心功能
- ✅ Named export
#### 3.4 导出文件
```typescript
// index.tsx
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
export { MyComponent } from './my-component';
export type { MyComponentProps } from './my-component';
```
### Step 4: 在 form-materials 主入口导出
编辑 `packages/materials/form-materials/src/components/index.ts`:
```typescript
export {
// ... 其他组件按字母序
MyComponent,
// ... 继续其他组件
type MyComponentProps,
// ... 继续其他类型
} from './components';
```
然后编辑 `packages/materials/form-materials/src/index.ts`,确保新组件在主导出列表中:
```typescript
export {
// ... 其他组件按字母序
MyComponent,
// ...
type MyComponentProps,
// ...
} from './components';
```
### Step 5: 创建 Storybook Story
在 `apps/demo-materials/src/stories/components/` 创建 Story:
```typescript
// my-component.stories.tsx
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React, { useState } from 'react';
import type { Meta, StoryObj } from 'storybook-react-rsbuild';
import { MyComponent } from '@flowgram.ai/form-materials';
import type { SomeType } from '@flowgram.ai/json-schema';
const MyComponentDemo: React.FC = () => {
const [result, setResult] = useState<SomeType | null>(null);
return (
<div style={{ padding: '20px' }}>
<h2>My Component Demo</h2>
<MyComponent
onSomething={(data) => {
console.log('Generated data:', data);
setResult(data);
}}
/>
{result && (
<div style={{ marginTop: '20px' }}>
<h3>结果:</h3>
<pre style={{
background: '#f5f5f5',
padding: '16px',
borderRadius: '4px',
overflow: 'auto'
}}>
{JSON.stringify(result, null, 2)}
</pre>
</div>
)}
</div>
);
};
const meta: Meta<typeof MyComponentDemo> = {
title: 'Form Components/MyComponent',
component: MyComponentDemo,
parameters: {
layout: 'centered',
docs: {
description: {
component: '组件功能描述',
},
},
},
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
```
### Step 6: 运行类型检查
```bash
cd packages/materials/form-materials
yarn ts-check
```
确保通过所有类型检查。
### Step 7: 启动开发环境测试
开启两个 Terminal:
**Terminal 1 - 监听包编译:**
```bash
rush build:watch
```
**Terminal 2 - 启动 Storybook:**
```bash
cd apps/demo-materials
yarn dev
```
访问 http://localhost:6006/,找到你的组件进行测试。
## 常见问题
### Q1: React 引用错误
**错误信息**:
```
error TS2686: 'React' refers to a UMD global, but the current file is a module.
```
**解决方案**:
在文件顶部添加:
```typescript
import React from 'react';
```
### Q2: 组件未导出
**错误信息**:
```
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
```
**解决方案**:
检查以下文件的导出:
1. `components/{组件名}/index.tsx`
2. `components/index.ts`
3. `src/index.ts`
### Q3: 类型找不到
**错误信息**:
```
Cannot find module '@flowgram.ai/json-schema' or its corresponding type declarations.
```
**解决方案**:
- 使用 `type IJsonSchema` 而非 `type JSONSchema7`
- 从 `@flowgram.ai/json-schema` 导入而非 `json-schema`
### Q4: CodeEditor 没有 height 属性
**错误信息**:
```
Property 'height' does not exist on type 'CodeEditorPropsType'.
```
**解决方案**:
使用外层 div 设置高度:
```tsx
<div style={{ minHeight: 300 }}>
<JsonCodeEditor value={value} onChange={onChange} />
</div>
```
## 验收标准
- [ ] 组件在 `packages/materials/form-materials/src/components/` 下创建
- [ ] 使用 named export
- [ ] 通过 `yarn ts-check` 类型检查
- [ ] Props 精简,只保留核心功能
- [ ] 在 Storybook 中可以正常显示和使用
- [ ] 功能正常,无明显 bug
- [ ] 代码符合 FlowGram 代码规范
## 最佳实践
### 1. 组件设计
- **单一职责**:一个组件只做一件事
- **Props 精简**:避免过度配置
- **命名清晰**:组件名和 Props 名要清晰易懂
### 2. 代码风格
- **使用 TypeScript**:充分利用类型系统
- **显式导入**:明确导入所需的依赖
- **注释适度**:关键逻辑添加注释
### 3. UI 一致性
- **使用 Semi UI**:保持 UI 风格一致
- **响应式设计**:考虑不同屏幕尺寸
- **错误处理**:友好的错误提示
### 4. 性能优化
- **Named export**:支持 tree shaking
- **按需加载**:避免不必要的依赖
- **合理使用 memo**:必要时使用 React.memo
## 示例参考
完整示例请参考:
- `packages/materials/form-materials/src/components/json-schema-creator/`
- `apps/demo-materials/src/stories/components/json-schema-creator.stories.tsx`
================================================
FILE: .claude/skills/material-component-doc/SKILL.md
================================================
---
name: material-component-doc
description: 用于 FlowGram 物料库组件文档撰写的专用技能,提供组件文档生成、Story 创建、翻译等功能的指导和自动化支持
metadata:
version: "1.1.0"
category: "documentation"
language: "zh-CN"
framework: "FlowGram"
---
# FlowGram 文档的组织结构
- **英文文档**: `apps/docs/src/en`
- **中文文档**: `apps/docs/src/zh`
- **Story 组件**: `apps/docs/components/form-materials/components`
- **物料源码**: `packages/materials/form-materials/src/components`
- **文档模板**: `./templates/material.mdx`
# 组件物料文档撰写流程
## 1. 源码定位
在 `packages/materials/form-materials/src/components` 目录下确认物料源代码地址。
**操作**:
- 使用 Glob 工具搜索物料文件
- 确认目录结构(是否有 hooks.ts, context.tsx 等)
- 记录导出名称和文件路径
## 2. 需求收集
向用户询问物料使用实例和具体需求。
**收集信息**:
- 主要使用场景
- 典型代码示例(1-2 个)
- 特殊配置或高级用法
- 是否需要配图
## 3. 功能分析
深入阅读源代码,理解物料功能。
**分析要点**:
- Props 接口(类型、默认值、描述)
- 核心功能和实现方式
- 依赖关系(FlowGram API、其他物料、第三方库)
- Hooks 和 Context
- 特殊逻辑(条件渲染、副作用等)
## 4. Story 创建
在 `apps/docs/components/form-materials/components` 下创建 Story 组件(详见下方 Story 规范)。
## 5. 文档撰写
基于模板 `./templates/material.mdx` 撰写完整文档。
**文档位置**:
- 中文:`apps/docs/src/zh/materials/components/{物料名称}.mdx`
- 英文:`apps/docs/src/en/materials/components/{物料名称}.mdx`(翻译后)
## 6. 质量检查
**检查清单**:
- [ ] Story 组件能正常运行
- [ ] 代码示例准确无误
- [ ] API 表格完整
- [ ] 依赖链接正确可访问
- [ ] 图片路径正确
- [ ] Mermaid 流程图语法正确
- [ ] CLI 命令路径准确
**用户确认中文文档的撰写后,再执行翻译**。
**用户确认中文文档的撰写后,再执行翻译**。
**用户确认中文文档的撰写后,再执行翻译**。
---
# Story 组件规范
> **参考示例**: `apps/docs/components/form-materials/components/variable-selector.tsx`
## 命名规范
**文件命名**: kebab-case,与物料名称一致
- ✅ `variable-selector.tsx`
- ✅ `dynamic-value-input.tsx`
- ❌ `VariableSelector.tsx`
**Story 导出命名**: PascalCase + "Story" 后缀
- `BasicStory` - 基础使用(必需)
- `WithSchemaStory` - 带 Schema 约束
- `DisabledStory` - 禁用状态
- `CustomFilterStory` - 自定义过滤
- 根据物料特性命名,见名知意
## 代码要求
### 1. 懒加载导入
```tsx
// ✅ 正确
const VariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelector,
}))
);
// ❌ 错误
import { VariableSelector } from '@flowgram.ai/form-materials';
```
### 2. 包装组件
```tsx
// ✅ 正确
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string[]> name="variable_selector">
{({ field }) => (
<VariableSelector
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</>
),
}}
/>
);
// ❌ 错误:缺少包装
export const BasicStory = () => (
<VariableSelector value={[]} onChange={() => {}} />
);
```
### 3. 类型标注
```tsx
// ✅ 正确
<Field<string[] | undefined> name="variable_selector">
// ❌ 错误
<Field<any> name="variable_selector">
```
### 4. 语言规范
代码和注释只使用英文,无中文。
## 完整示例
```tsx
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const VariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelector,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string[] | undefined> name="variable_selector">
{({ field }) => (
<VariableSelector
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</>
),
}}
/>
);
export const FilterSchemaStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string[] | undefined> name="variable_selector">
{({ field }) => (
<VariableSelector
value={field.value}
onChange={(value) => field.onChange(value)}
includeSchema={{ type: 'string' }}
/>
)}
</Field>
</>
),
}}
/>
);
```
---
# 物料文档格式
## 使用模板
**模板文件**: `./templates/material.mdx`
文档必须严格按照模板格式编写,包含以下章节:
1. Import 语句
2. 标题和简介(带可选配图)
3. 案例演示(基本使用 + 高级用法)
4. API 参考(Props 表格)
5. 源码导读(目录结构、核心实现、流程图、依赖梳理)
## 参考示例
- [`dynamic-value-input.mdx`](apps/docs/src/zh/materials/components/dynamic-value-input.mdx) - 完整的流程图和依赖说明
- [`variable-selector.mdx`](apps/docs/src/zh/materials/components/variable-selector.mdx) - 多个 API 表格和警告提示
## 关键注意事项
**API 表格要求**:
- 必须包含所有公开的 Props
- 类型使用反引号(如 \`string\`)
- 描述清晰简洁
- 多个相关类型分开列表
**源码导读要求**:
- 目录结构:展示文件列表及说明
- 核心实现:用代码片段说明关键逻辑
- 整体流程:Mermaid 流程图(推荐)
- 依赖梳理:分类列出 FlowGram API、其他物料、第三方库
---
# 图片处理指南
## 截图要求
1. **时机**: Story 组件完成后,运行 docs 站点截图
2. **内容**: 捕获物料的典型使用状态,清晰可见
3. **格式**: PNG,适当压缩
## 命名和存储
- **命名**: `{物料名称}.png`(kebab-case)
- **存储**: `apps/docs/src/public/materials/{物料名称}.png`
- **引用**: `/materials/{物料名称}.png`
## 在文档中使用
```mdx
<br />
<div>
<img loading="lazy" src="/materials/{物料名称}.png" alt="{物料名称} 组件" style={{ width: '50%' }} />
</div>
```
---
# 翻译流程
## 翻译时机
- ✅ 用户明确要求翻译
- ✅ 中文文档已经用户审核确认
- ❌ 文档还在修改中
- ❌ 用户未确认最终版本
## 翻译原则
**术语一致性**:
- ComponentName → ComponentName(组件名不翻译)
- Props、Hook、Schema 等术语保持原文
**代码不翻译**:
- 所有代码块、命令、路径保持原样
**链接处理**:
- 内部链接:`/zh/` → `/en/`
- 外部链接和 GitHub 链接:保持不变
**格式保持**:
- Markdown 格式、缩进、空行完全一致
## 翻译检查清单
- [ ] 标题和描述已翻译
- [ ] 代码示例未被翻译
- [ ] 命令和路径保持原样
- [ ] 内部文档链接已更新
- [ ] API 表格描述列已翻译
- [ ] Mermaid 图中文节点已翻译
- [ ] 术语使用一致
---
# 最佳实践
## Props 提取技巧
1. 查找 `interface` 或 `type` 定义
2. 检查组件函数参数类型
3. 查找 `defaultProps` 确认默认值
4. 阅读 JSDoc 提取描述
## 依赖分析方法
1. 查看 import 语句(直接依赖)
2. 分析 Hook 调用(FlowGram API)
3. 查找组件引用(其他物料)
4. 检查 package.json(第三方库)
## Mermaid 流程图建议
1. 简洁明了,关注核心流程
2. 使用时序图绘制
## 常见错误避免
❌ 直接导入物料而不使用 `React.lazy`
❌ API 表格遗漏 Props
❌ 依赖链接失效
❌ 中英文混用
❌ 路径格式错误
✅ 参考优秀示例
✅ 仔细阅读源码
✅ 验证所有链接
✅ 保持语言和格式一致
✅ 使用项目约定的路径格式
---
# 相关工具和资源
## 开发命令
```bash
# 启动文档站点
rush dev:docs
# 查看修改
git diff
git diff --cached
```
## 关键目录
| 目录 | 说明 |
|------|------|
| `packages/materials/form-materials/src/components` | 物料源码 |
| `apps/docs/src/zh/materials/components` | 中文文档 |
| `apps/docs/src/en/materials/components` | 英文文档 |
| `apps/docs/components/form-materials/components` | Story 组件 |
| `apps/docs/src/public/materials` | 图片资源 |
| `./templates` | 文档模板 |
================================================
FILE: .claude/skills/material-component-doc/templates/material.mdx
================================================
import { SourceCode } from '@theme';
import { BasicStory, WithSchemaStory } from 'components/form-materials/components/{物料名称}';
# ComponentName
ComponentName 是一个用于...的组件,它支持...功能。[用 1-2 段文字描述物料的核心功能、使用场景和主要特性]
<br />
<div>
<img loading="lazy" src="/materials/{物料名称}.png" alt="ComponentName 组件" style={{ width: '50%' }} />
</div>
## 案例演示
### 基本使用
<BasicStory />
```tsx pure title="form-meta.tsx"
import { ComponentName } from '@flowgram.ai/form-materials';
const formMeta = {
render: () => (
<>
<FormHeader />
<Field<ValueType> name="field_name">
{({ field }) => (
<ComponentName
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</>
),
}
```
### 高级用法示例(根据物料特性添加)
<WithSchemaStory />
```tsx pure title="form-meta.tsx"
import { ComponentName } from '@flowgram.ai/form-materials';
const formMeta = {
render: () => (
<>
<FormHeader />
<Field<ValueType> name="field_name">
{({ field }) => (
<ComponentName
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'string' }}
// 其他高级配置...
/>
)}
</Field>
</>
),
}
```
## API 参考
### ComponentName Props
| 属性名 | 类型 | 默认值 | 描述 |
|--------|------|--------|------|
| `value` | `ValueType` | - | 组件的值 |
| `onChange` | `(value: ValueType) => void` | - | 值变化时的回调函数 |
| `readonly` | `boolean` | `false` | 是否为只读模式 |
| `hasError` | `boolean` | `false` | 是否显示错误状态 |
| `style` | `React.CSSProperties` | - | 自定义样式 |
### RelatedConfigType(如果有相关的配置类型)
| 属性名 | 类型 | 默认值 | 描述 |
|--------|------|--------|------|
| `property1` | `string` | - | 属性说明 |
| `property2` | `boolean` | `false` | 属性说明 |
### RelatedProviderProps(如果有 Provider 组件)
| 属性名 | 类型 | 默认值 | 描述 |
|--------|------|--------|------|
| `children` | `React.ReactNode` | - | 子组件 |
| `config` | `ConfigType` | - | 配置对象 |
## 源码导读
<SourceCode
href="https://github.com/bytedance/flowgram.ai/tree/main/packages/materials/form-materials/src/components/{物料路径}"
/>
使用 CLI 命令可以复制源代码到本地:
```bash
npx @flowgram.ai/cli@latest materials components/{物料路径}
```
### 目录结构讲解
```
{物料名称}/
├── index.tsx # 主组件实现,包含 ComponentName 核心逻辑
├── hooks.ts # 自定义 Hooks,处理... [如果有]
├── context.tsx # Context Provider,提供... [如果有]
├── utils.ts # 工具函数,用于... [如果有]
└── styles.css # 样式文件
```
### 核心实现说明
#### 功能点1
[用简洁的文字描述实现原理]
```typescript
// 展示关键代码片段
const result = useHookName(props);
```
#### 功能点2
[描述另一个关键功能的实现方式]
```typescript
// 展示关键逻辑
if (condition) {
return <ComponentA />;
} else {
return <ComponentB />;
}
```
### 整体流程
```mermaid
graph TD
A[组件初始化] --> B{判断条件}
B -->|条件1| C[执行分支A]
B -->|条件2| D[执行分支B]
C --> E[处理用户交互]
D --> F[处理数据变化]
E --> G[触发 onChange 回调]
F --> G
```
### 使用到的 FlowGram API
[**@flowgram.ai/package-name**](https://github.com/bytedance/flowgram.ai/tree/main/packages/path)
- [`ApiName`](https://flowgram.ai/auto-docs/package/type/ApiName): API 的功能说明
- [`HookName`](https://flowgram.ai/auto-docs/package/functions/HookName): Hook 的功能说明
[**@flowgram.ai/another-package**](https://github.com/bytedance/flowgram.ai/tree/main/packages/another-path)
- [`TypeName`](https://flowgram.ai/auto-docs/package/interfaces/TypeName): 类型定义说明
### 依赖的其他物料
[**DependentMaterial**](./dependent-material) 物料的简要说明
- `ExportedComponent`: 导出组件的用途
- `ExportedHook`: 导出 Hook 的用途
[**AnotherMaterial**](./another-material) 物料的简要说明
### 使用的第三方库
[**library-name**](https://library-url.com) 库的说明
- `ImportedComponent`: 组件的用途
- `importedFunction`: 函数的用途
================================================
FILE: .gitattributes
================================================
# Don't allow people to merge changes to these generated files, because the result
# may be invalid. You need to run "rush update" again.
pnpm-lock.yaml merge=ours
shrinkwrap.yaml merge=binary
npm-shrinkwrap.json merge=binary
yarn.lock merge=binary
# Rush's JSON config files use JavaScript-style code comments. The rule below prevents pedantic
# syntax highlighters such as GitHub's from highlighting these comments as errors. Your text editor
# may also require a special configuration to allow comments in JSON.
#
# For more information, see this issue: https://github.com/microsoft/rushstack/issues/1088
#
*.json linguist-language=JSON-with-Comments
================================================
FILE: .github/CODEOWNERS
================================================
# 文件路径与代码负责人分配
# 对整个仓库设置代码负责人
* @xiamidaxia @luics @dragooncjw @YuanHeDx @sanmaopep @louisyoungx
# 对特定目录设置代码负责人
/apps/docs/ @xiamidaxia @dragooncjw @YuanHeDx @sanmaopep @louisyoungx
/apps/demo-node-form/ @xiamidaxia @dragooncjw @YuanHeDx
/packages/node-engine/ @xiamidaxia @dragooncjw @YuanHeDx
/packages/variable-engine/ @xiamidaxia @dragooncjw @sanmaopep
/packages/plugins/variable-plugin/ @xiamidaxia @dragooncjw @sanmaopep
/packages/plugins/node-variable-plugin/ @xiamidaxia @dragooncjw @sanmaopep
/packages/plugins/node-core-plugin/ @xiamidaxia @dragooncjw @YuanHeDx
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug Report
about: Report Bug
title: "[Bug] "
labels: [bug]
---
## 🙋 SDK Version
Please input version of SDK.
## 📌 Layout
Free layout or Fixed layout?
## 💻 Environment
- Operation System: (e.g. Windows 11 / macOs 14.3)
- Node.js:
- Other:
## 📝 Question Description
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question Report
about: Report Question
title: "[Question] "
labels: [question]
---
## 🙋 SDK Version
Please input version of SDK.
## 📌 Layout
Free layout or Fixed layout?
## 💻 Environment
- Operation System: (e.g. Windows 11 / macOs 14.3)
- Node.js:
- Other:
## 📝 Question Description
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
merge_group:
branches: ["main"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
- name: For Debug
run: |
echo "Listing files in the root directory:"
ls -alh
- uses: actions/setup-node@v3
with:
node-version: 18
# - name: Verify Change Logs
# run: node common/scripts/install-run-rush.js change --verify
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
- name: Check Lint
run: node common/scripts/install-run-rush.js lint --verbose
- name: Check TS
run: node common/scripts/install-run-rush.js ts-check
- name: Test (coverage)
run: node common/scripts/install-run-rush.js test:cov
================================================
FILE: .github/workflows/common-pr-checks.yml
================================================
name: PR Common Checks
on:
pull_request:
types: [opened, edited, synchronize, reopened]
jobs:
common-checks:
name: PR Common Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 1
- name: Config Git User
run: |
git config --local user.name "tecvan"
git config --local user.email "fanwenjie.fe@bytedance.com"
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Dependencies
run: node common/scripts/install-run-rush.js install
# PR Title Format Check
- name: Check PR Title Format
if: ${{ !contains(github.event.pull_request.title, 'WIP') && !contains(github.event.pull_request.title, 'wip') }}
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
node common/scripts/install-run-rush.js update-autoinstaller --name rush-commitlint && \
pushd common/autoinstallers/rush-commitlint && \
echo "$PR_TITLE" | npx commitlint --config commitlint.config.js && \
popd
# Add more common checks here
# For example: file size checks, specific file format validations, etc.
================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy With Actions
on: workflow_dispatch
concurrency:
group: "main-deploy-branch-workflow"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
pages: write
id-token: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
persist-credentials: true
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install -t @flowgram.ai/docs
- name: Rush build
run: node common/scripts/install-run-rush.js build -t @flowgram.ai/docs
- name: Generate docs
run: |
cd apps/docs
npm run docs
- name: Copy auto-docs to en
run: cp -r apps/docs/src/zh/auto-docs apps/docs/src/en/auto-docs
- name: Build Doc site
run: |
cd apps/docs
npm run build
- name: Replace docs
run: |
rm -rf docs
mv apps/docs/doc_build docs
# 🔥 新增步骤:在 docs 目录下生成 vercel.json
- name: Create vercel.json
run: |
cat > docs/vercel.json <<EOF
{
"version": 2,
"buildCommand": "",
"outputDirectory": ".",
"cleanUrls": true,
"trailingSlash": false
}
EOF
# 🔥 推送到 gh-pages 分支
- name: Push to gh-pages branch
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
publish_branch: gh-pages
force: true
================================================
FILE: .github/workflows/e2e.yml
================================================
name: E2E Tests
on:
pull_request:
branches: ["main"]
merge_group:
branches: ["main"]
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# 缓存 Playwright 浏览器
- name: Cache Playwright browsers
uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('e2e/fixed-layout/package.json') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Browsers
run: pushd e2e/fixed-layout && npx playwright install --with-deps --only-shell chromium && popd
- name: Run E2E tests
run: node common/scripts/install-run-rush.js e2e:test --verbose
================================================
FILE: .github/workflows/publish-alpha.yml
================================================
name: Publish Alpha Version
on: workflow_dispatch
concurrency:
group: "main-branch-alpha-publish-workflow" # 唯一标识符,确保只运行一个实例
cancel-in-progress: false # 不取消正在运行的实例,后续触发需要等待当前实例完成
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up npm token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
- name: Debug Auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
npm whoami
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
- name: Get alpha latest npm version
id: get_version
run: |
LATEST_VERSION=$(npm view @flowgram.ai/core version --tag=alpha latest 2>/dev/null || true)
if [ -n "$LATEST_VERSION" ]; then
echo "Using existing version: $LATEST_VERSION"
else
LATEST_VERSION="0.1.0-alpha.1"
echo "Version not found, using default: $LATEST_VERSION"
fi
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- name: Echo version
run: |
echo "The package version is : $LATEST_VERSION"
echo "The package output version is ${{ steps.get_version.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# version bump 之前保证是远端最新的,这样无需 commit package.json version
- name: Sync versions
run: |
echo "[
{
\"policyName\": \"publishPolicy\",
\"definitionName\": \"lockStepVersion\",
\"version\": \"$LATEST_VERSION\",
\"nextBump\": \"prerelease\"
}
]" > common/config/rush/version-policies.json
- name: replace with alpha version
run: node common/scripts/install-run-rush.js version --ensure-version-policy --override-version=$LATEST_VERSION --version-policy=publishPolicy
- name: Version Bump
run: node common/scripts/install-run-rush.js version --bump --version-policy publishPolicy
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: node common/scripts/install-run-rush.js publish --include-all -p --tag alpha
- name: Get new Version
id: get_new_version
run: |
NEW_VERSION=$(npm view @flowgram.ai/core version --tag=alpha latest)
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Create tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v$NEW_VERSION"
git push origin "v$NEW_VERSION"
================================================
FILE: .github/workflows/publish-app-to-version.yml
================================================
name: Publish App To Version
on:
workflow_dispatch:
inputs:
sdk-version:
description: "要升级到的 SDK 版本(e.g. 1.0.0)"
required: true
default: ""
concurrency:
group: "main-branch-workflow" # 唯一标识符,确保只运行一个实例
cancel-in-progress: false # 不取消正在运行的实例,后续触发需要等待当前实例完成
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up npm token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
- name: Debug Auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
npm whoami
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- name: Echo version
run: |
LATEST_VERSION=${{ github.event.inputs.sdk-version }}
echo "The package input version is ${{ github.event.inputs.sdk-version }}"
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# version bump 之前保证是远端最新的,这样无需 commit package.json version
- name: Sync versions
run: |
echo "[
{
\"policyName\": \"appPolicy\",
\"definitionName\": \"lockStepVersion\",
\"version\": \"$LATEST_VERSION\"
}
]" > common/config/rush/version-policies.json
- name: Version Bump
run: node common/scripts/install-run-rush.js version --ensure-version-policy --override-version=$LATEST_VERSION --version-policy appPolicy
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: node common/scripts/install-run-rush.js publish --include-all -p --tag latest
- name: Get new Version
id: get_new_version
run: |
NEW_VERSION=$(npm view @flowgram.ai/core version --tag=latest latest)
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Create tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v$NEW_VERSION"
git push origin "v$NEW_VERSION"
================================================
FILE: .github/workflows/publish-app.yml
================================================
name: Publish-Apps
on: workflow_dispatch
concurrency:
group: "main-branch-workflow" # 唯一标识符,确保只运行一个实例
cancel-in-progress: false # 不取消正在运行的实例,后续触发需要等待当前实例完成
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up npm token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
- name: Debug Auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
npm whoami
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
- name: Get latest npm version
id: get_version
run: |
LATEST_VERSION=$(npm view @flowgram.ai/demo-fixed-layout version --tag=latest latest)
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- name: Echo version
run: |
echo "The package version is : $LATEST_VERSION"
echo "The package output version is ${{ steps.get_version.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# version bump 之前保证是远端最新的,这样无需 commit package.json version
- name: Sync versions
run: |
echo "[
{
\"policyName\": \"appPolicy\",
\"definitionName\": \"lockStepVersion\",
\"version\": \"$LATEST_VERSION\",
\"nextBump\": \"patch\"
}
]" > common/config/rush/version-policies.json
- name: Version Bump
run: node common/scripts/install-run-rush.js version --bump --version-policy appPolicy
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: node common/scripts/install-run-rush.js publish --include-all -p --tag latest
================================================
FILE: .github/workflows/publish-minor.yml
================================================
name: Publish-Minor
on: workflow_dispatch
concurrency:
group: "main-branch-workflow" # 唯一标识符,确保只运行一个实例
cancel-in-progress: false # 不取消正在运行的实例,后续触发需要等待当前实例完成
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up npm token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
- name: Debug Auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
npm whoami
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
- name: Get latest npm version
id: get_version
run: |
LATEST_VERSION=$(npm view @flowgram.ai/core version --tag=latest latest)
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- name: Echo version
run: |
echo "The package version is : $LATEST_VERSION"
echo "The package output version is ${{ steps.get_version.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# version bump 之前保证是远端最新的,这样无需 commit package.json version
- name: Sync versions
run: |
echo "[
{
\"policyName\": \"publishPolicy\",
\"definitionName\": \"lockStepVersion\",
\"version\": \"$LATEST_VERSION\",
\"nextBump\": \"minor\"
}
]" > common/config/rush/version-policies.json
- name: Version Bump
run: node common/scripts/install-run-rush.js version --bump --version-policy publishPolicy
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: node common/scripts/install-run-rush.js publish --include-all -p --tag latest
- name: Get new Version
id: get_new_version
run: |
NEW_VERSION=$(npm view @flowgram.ai/core version --tag=latest latest)
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Create tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v$NEW_VERSION"
git push origin "v$NEW_VERSION"
================================================
FILE: .github/workflows/publish-to-version.yml
================================================
name: Publish To Version
on:
workflow_dispatch:
inputs:
sdk-version:
description: "要升级到的 SDK 版本(e.g. 1.0.0)"
required: true
default: ""
concurrency:
group: "main-branch-workflow" # 唯一标识符,确保只运行一个实例
cancel-in-progress: false # 不取消正在运行的实例,后续触发需要等待当前实例完成
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up npm token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
- name: Debug Auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
npm whoami
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- name: Echo version
run: |
LATEST_VERSION=${{ github.event.inputs.sdk-version }}
echo "The package input version is ${{ github.event.inputs.sdk-version }}"
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# version bump 之前保证是远端最新的,这样无需 commit package.json version
- name: Sync versions
run: |
echo "[
{
\"policyName\": \"publishPolicy\",
\"definitionName\": \"lockStepVersion\",
\"version\": \"$LATEST_VERSION\"
}
]" > common/config/rush/version-policies.json
- name: Version Bump
run: node common/scripts/install-run-rush.js version --ensure-version-policy --override-version=$LATEST_VERSION --version-policy publishPolicy
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: node common/scripts/install-run-rush.js publish --include-all -p --tag latest
- name: Get new Version
id: get_new_version
run: |
NEW_VERSION=$(npm view @flowgram.ai/core version --tag=latest latest)
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Create tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v$NEW_VERSION"
git push origin "v$NEW_VERSION"
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish
on: workflow_dispatch
concurrency:
group: "main-branch-workflow" # 唯一标识符,确保只运行一个实例
cancel-in-progress: false # 不取消正在运行的实例,后续触发需要等待当前实例完成
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up npm token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
- name: Debug Auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
npm whoami
- name: Config Git User
run: |
git config --local user.name "dragooncjw"
git config --local user.email "289056872@qq.com"
- name: Get latest npm version
id: get_version
run: |
LATEST_VERSION=$(npm view @flowgram.ai/core version --tag=latest latest)
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- name: Echo version
run: |
echo "The package version is : $LATEST_VERSION"
echo "The package output version is ${{ steps.get_version.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org/"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
# version bump 之前保证是远端最新的,这样无需 commit package.json version
- name: Sync versions
run: |
echo "[
{
\"policyName\": \"publishPolicy\",
\"definitionName\": \"lockStepVersion\",
\"version\": \"$LATEST_VERSION\",
\"nextBump\": \"patch\"
}
]" > common/config/rush/version-policies.json
- name: Version Bump
run: node common/scripts/install-run-rush.js version --bump --version-policy publishPolicy
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: node common/scripts/install-run-rush.js publish --include-all -p --tag latest
- name: Get new Version
id: get_new_version
run: |
NEW_VERSION=$(npm view @flowgram.ai/core version --tag=latest latest)
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Create tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v$NEW_VERSION"
git push origin "v$NEW_VERSION"
================================================
FILE: .github/workflows/sync-screenshot.yml
================================================
name: Sync Screenshot
on: workflow_dispatch
concurrency:
group: "manual-sync-screenshot"
cancel-in-progress: false
jobs:
e2e:
# can not update screenshot run on main.
if: github.ref_name != 'main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Set Git user.name and user.email from trigger actor
run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush build
run: node common/scripts/install-run-rush.js build
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run E2E tests
run: node common/scripts/install-run-rush.js e2e:update-screenshot --verbose
- name: Commit and push changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git add .
if git diff-index --quiet HEAD; then
echo "No changes to commit"
else
git commit -m "chore: sync screenshot"
git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }} HEAD:${{ github.ref_name }}
fi
================================================
FILE: .gitignore
================================================
# e2e results
test-results/
doc_build/
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov/
# Coverage directory used by tools like istanbul
coverage/
# nyc test coverage
.nyc_output/
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt/
# Bower dependency directory (https://bower.io/)
bower_components/
# node-waf configuration
.lock-wscript/
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release/
# Dependency directories
node_modules/
jspm_packages/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm/
# Optional eslint cache
.eslintcache/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# next.js build output
.next/
# Docusaurus cache and generated files
.docusaurus/
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# yarn v2
.yarn/cache/
.yarn/unplugged/
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# OS X temporary files
.DS_Store
# IntelliJ IDEA project files; if you want to commit IntelliJ settings, this recipe may be helpful:
# https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
.idea/
*.iml
# Visual Studio Code
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
# Rush temporary files
common/deploy/
common/temp/
common/autoinstallers/*/.npmrc
**/.rush/temp/
*.lock
# Common toolchain intermediate files
temp/
lib/
lib-amd/
lib-es6/
lib-esnext/
lib-commonjs/
lib-shim/
dist/
dist-storybook/
*.tsbuildinfo
# Heft temporary files
.cache/
.heft/
# rush standard files
.eslintcache
# eslint cache for v9
.lintcache/
================================================
FILE: .vscode/extentions.json
================================================
{
"recommendations": [
"styled-components.vscode-styled-components",
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"streetsidesoftware.code-spell-checker",
"codezombiech.gitignore",
"aaron-bond.better-comments"
],
"unwantedRecommendations": [
"nucllear.vscode-extension-auto-import",
"steoates.autoimport"
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"eslint.nodePath": "config/eslint-config/node_modules/eslint",
"prettier.prettierPath": "config/eslint-config/node_modules/prettier",
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.formatOnSave": true,
"editor.formatOnType": false,
"editor.formatOnPaste": false,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.fixAll.eslint": "explicit"
},
"search.followSymlinks": false,
"search.exclude": {
"**/node_modules": true,
"**/.nyc_output": true,
"**/.rush": true,
"**/pnpm-lock.yaml": true,
"**/CHANGELOG.json": true,
"**/CHANGELOG.md": true,
"common/changes": true,
"**/output": true,
"**/lib": true,
"**/dist": true,
"**/coverage": true,
"common/temp": true
},
"eslint.workingDirectories": [
{
"mode": "auto"
}
],
"files.defaultLanguage": "plaintext",
"files.associations": {
".code-workspace": "jsonc",
".babelrc": "json",
".eslintrc": "jsonc",
".eslintrc*.json": "jsonc",
".stylelintrc": "jsonc",
"stylelintrc": "jsonc",
"*.json": "jsonc",
"package.json": "json",
".htmlhintrc": "jsonc",
"htmlhintrc": "jsonc",
"Procfile*": "shellscript",
"README": "markdown",
"**/coverage/**/*.*": "plaintext",
"OWNERS": "yaml",
"**/pnpm-lock.yaml": "plaintext",
"**/dist/**": "plaintext",
"**/dist_*/**": "plaintext",
"*.map": "plaintext",
"*.log": "plaintext"
},
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/.rush": true
},
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/*/**": true
},
"search.useIgnoreFiles": true,
//
"editor.rulers": [
80,
120
],
"files.eol": "\n",
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"cSpell.diagnosticLevel": "Warning",
"eslint.probe": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"eslint.format.enable": true,
"eslint.lintTask.enable": true,
"javascript.validate.enable": false,
"typescript.validate.enable": true,
"typescript.tsdk": "config/ts-config/node_modules/typescript/lib",
"typescript.tsserver.maxTsServerMemory": 8192,
// "typescript.tsserver.experimental.enableProjectDiagnostics": true,
"typescript.tsserver.watchOptions": {
"fallbackPolling": "dynamicPriorityPolling",
"synchronousWatchDirectory": false,
"watchDirectory": "dynamicPriorityPolling",
"watchFile": "useFsEventsOnParentDirectory"
},
"css.validate": false,
"scss.validate": false,
"less.validate": false,
"emmet.triggerExpansionOnTab": true,
"[yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[less]": {
"editor.defaultFormatter": "vscode.css-language-features"
},
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[javascriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[ignore]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[shellscript]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[dotenv]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[svg]": {
"editor.defaultFormatter": "jock.svg"
},
"[mdx]": {
"editor.defaultFormatter": "unifiedjs.vscode-mdx"
},
"cSpell.words": [
"Twoway"
]
}
================================================
FILE: AGENTS.md
================================================
# Repository Guidelines
## Project Structure & Module Organization
FlowGram is a Rush-managed monorepo. Production-ready libraries live under `packages/*` (canvas engine, node engine, runtime, plugins). Demo UIs and docs sit inside `apps/*` (for example `apps/demo-free-layout`, `apps/docs`). Shared tooling, config, and scripts live under `common/` and `config/`. End-to-end Playwright suites are isolated in `e2e/<scenario>` so they can be installed and run independently. New code should land in the closest existing package; create additional Rush projects only when a module needs its own version and publish cycle.
## Build, Test, and Development Commands
Use Node.js 18 LTS with pnpm 10.6.5 (Rush enforces versions). Install dependencies via `rush install`. Run `rush build` to compile every registered project. Use `rush dev:docs` or `rush dev:demo-free-layout` for hot-reload docs and demos. `rush lint`, `rush lint:fix`, and `rush ts-check` keep lint/TS diagnostics consistent. `rush test` aggregates unit tests; `rush e2e:test` runs Playwright suites, while `rush e2e:update-screenshot` refreshes snapshots.
## Coding Style & Naming Conventions
We write TypeScript with React, sharing configs from `config/eslint-config`. ESLint enforces 2-space indentation, semicolons, and import order; run `rush lint:fix` before committing. Use `PascalCase` for React components and classes, `camelCase` for variables/functions, and `SCREAMING_SNAKE_CASE` only for constants exported from config files. File names follow kebab-case (e.g., `flow-node-form.tsx`). Keep public API surfaces documented via barrel files such as `packages/canvas-engine/core/src/index.ts`.
## Testing Guidelines
Unit tests use Vitest and live beside source in `__tests__` folders or `*.test.ts` files; prefer descriptive names like `node-service.test.ts`. Ensure new logic is covered by `rush test`, and include data fixtures where possible. Playwright specs under `e2e/*/tests` cover critical workflows—coordinate UI changes with updated snapshots and run `rush e2e:test --to <package>` to scope failures.
## Commit & Pull Request Guidelines
Follow conventional commits (`type(scope): subject`) as seen in history (`fix(auto-layout): ...`). Keep subjects imperative and ≤72 characters, with optional bodies for context. PRs must describe the change, link GitHub issues, and attach before/after screenshots for UI updates. Confirm CI status, note any follow-ups, and request reviewers from the owning package tags (see `rush.json`).
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## [Unreleased]
### Added
- Add `flowing` field to `LineColor` interface for configuring flowing line colors
- Added `flowing: string` field to `LineColor` interface
- Added `LineColors.FLOWING` enum value with default color
- Updated `WorkflowLinesManager.getLineColor()` to support flowing state
- Updated demo configurations to include flowing color examples
- Added comprehensive test coverage for flowing line functionality
### Features
- Lines can now be colored differently when in flowing state (e.g., during workflow execution)
- Priority order: hidden > error > highlight > drawing > hovered > selected > flowing > default
- Backward compatible with existing line color configurations
### Demo Updates
- Updated `apps/demo-free-layout` to include flowing color configuration
- Added CSS variable support: `var(--g-workflow-line-color-flowing,#4d53e8)`
### Tests
- Added test cases for flowing line color functionality
- Verified priority ordering with other line states
- Ensured backward compatibility
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repository Overview
FlowGram is a composable, visual workflow development framework built as a Rush-managed monorepo. It provides tools for building AI workflow platforms, including a flow canvas, node configuration forms, variable scope chains, and pre-built materials (LLM, Condition, Code Editor, etc.).
## Build System & Package Management
This monorepo uses **Rush 5.150.0** with **pnpm 10.6.5** as the package manager. Node.js version must be >=18.20.3 <19.0.0 || >=20.14.0 <23.0.0.
### Essential Commands
```bash
# Install dependencies (required first step)
rush install
# Build all packages
rush build
# Build specific package and its dependencies
rush build --to @flowgram.ai/core
# Lint all packages
rush lint
# Fix lint issues
rush lint:fix
# TypeScript type checking
rush ts-check
# Run unit tests
rush test
# Run tests with coverage
rush test:cov
# Build packages in watch mode (for development)
rush build:watch
# E2E tests with Playwright
rush e2e:test
# Update E2E screenshots
rush e2e:update-screenshot
```
### Development Commands for Demos
```bash
# Run docs site with hot reload
rush dev:docs
# Run specific demo apps with hot reload
rush dev:demo-free-layout
rush dev:demo-fixed-layout
rush dev:demo-fixed-layout-simple
rush dev:demo-free-layout-simple
rush dev:demo-nextjs
rush dev:demo-nextjs-antd
```
These commands use `concurrently` to run `rush build:watch` for dependencies alongside the demo's dev server.
### Single Package Development
To work on a single package in isolation:
```bash
cd packages/canvas-engine/core
rushx build # Runs the build script for this package only
rushx test # Runs tests for this package only
rushx ts-check # Type checks this package only
```
## Monorepo Structure
### Core Organization
- **`packages/`** - Production libraries organized by functional area:
- `canvas-engine/` - Canvas rendering and layout systems (core, document, renderer, fixed-layout-core, free-layout-core)
- `node-engine/` - Node data and form management (node, form, form-core)
- `variable-engine/` - Variable scoping and type inference (variable-core, variable-layout, json-schema)
- `runtime/` - Workflow execution engines (interface, js-core, nodejs)
- `plugins/` - Extensibility modules (23+ plugins for features like history, drag, snap, minimap, etc.)
- `client/` - High-level React components (editor, fixed-layout-editor, free-layout-editor, playground-react)
- `materials/` - Pre-built node materials (form-materials, form-antd-materials, fixed-semi-materials, coze-editor, type-editor)
- `common/` - Shared utilities (utils, reactive, command, history, history-storage, i18n)
- **`apps/`** - Demos and documentation:
- `docs/` - Main documentation site
- `demo-*/` - Example applications (free-layout, fixed-layout, nextjs, vite, playground, etc.)
- `create-app/`, `cli/` - CLI tools for scaffolding
- **`e2e/`** - End-to-end test suites (fixed-layout, free-layout)
- **`config/`** - Shared configuration (eslint-config, ts-config)
- **`common/`** - Rush tooling and scripts
### Architectural Layers
FlowGram is architected in distinct layers:
1. **Canvas Engine Layer** (`@flowgram.ai/core`, `@flowgram.ai/document`, `@flowgram.ai/renderer`)
- Core abstractions for canvas rendering, document model, and viewport management
- Supports two layout modes: free-layout (drag-anywhere) and fixed-layout (structured positioning)
- Plugin-based architecture using dependency injection (inversify)
2. **Node Engine Layer** (`@flowgram.ai/node`, `@flowgram.ai/form`, `@flowgram.ai/form-core`)
- Manages node data structures and lifecycle
- Form engine with validation, side effects, linkage, and error capture
- Uses `FormModelV2` (exported as `FormModel` from `@flowgram.ai/editor`)
3. **Variable Engine Layer** (`@flowgram.ai/variable-core`, `@flowgram.ai/json-schema`)
- Provides variable scoping, structure inspection, and type inference
- Manages data flow constraints across workflow nodes
- Scope chain mechanism for variable resolution
4. **Runtime Layer** (`@flowgram.ai/runtime-js`, `@flowgram.ai/runtime-nodejs`, `@flowgram.ai/runtime-interface`)
- Executes workflows in JavaScript/Node.js environments
- Interface package defines runtime contracts
- Separate implementations for browser and server
5. **Client/Editor Layer** (`@flowgram.ai/editor`, `@flowgram.ai/fixed-layout-editor`, `@flowgram.ai/free-layout-editor`)
- High-level React components that integrate all subsystems
- `@flowgram.ai/editor` is the main barrel export for fixed-layout workflows
- Re-exports from core, form, variable, and plugin packages
6. **Plugin Ecosystem**
- 20+ plugins providing features like drag-and-drop, history/undo, snap-to-grid, minimap, auto-layout, etc.
- Plugins are registered via dependency injection containers
- Naming convention: `free-*-plugin` for free-layout, `fixed-*-plugin` for fixed-layout, or generic plugins
## Key Design Patterns
### Dependency Injection
The codebase heavily uses **inversify** for dependency injection. Services are decorated with `@injectable()` and injected via `@inject()`. Container modules organize related services.
### Reactive State Management
Uses a custom reactive system (`@flowgram.ai/reactive`) with React hooks:
- `ReactiveState` and `ReactiveBaseState` for observable state
- `useReactiveState`, `useReadonlyReactiveState`, `useObserve` hooks
- `Tracker` for dependency tracking
### Command Pattern
`@flowgram.ai/command` provides a command/command registry system for undo/redo operations. Re-exported by `@flowgram.ai/core`.
### Plugin Architecture
Plugins extend functionality via:
- `Plugin` interface from `@flowgram.ai/core`
- Registration through container modules
- Lifecycle hooks (`onInit`, `onDestroy`, etc.)
## Testing
- **Unit tests**: Use Vitest, located in `__tests__/` folders or `*.test.ts` files
- **E2E tests**: Use Playwright, located in `e2e/*/tests/` directories
- Run all tests: `rush test`
- Run E2E tests for specific package: `rush e2e:test --to @flowgram.ai/e2e-free-layout`
- Update Playwright snapshots: `rush e2e:update-screenshot`
## Code Quality
### Linting & Type Checking
- ESLint configuration in `config/eslint-config` enforces 2-space indentation, semicolons, and import order
- TypeScript config in `config/ts-config`
- Always run `rush lint:fix` before committing
- Run `rush ts-check` to validate TypeScript across all packages
### Naming Conventions
- **React components/classes**: PascalCase
- **Variables/functions**: camelCase
- **Constants**: SCREAMING_SNAKE_CASE (only for exported config)
- **File names**: kebab-case (e.g., `flow-node-form.tsx`)
### Pre-commit Hooks
- `rush lint-staged` - Runs linting on staged files
- `rush commitlint` - Validates commit message format (conventional commits)
### Dependency Checks
- `rush check-circular-dependency` - Detects circular dependencies
- `rush dep-check` - Validates dependency consistency
## Commit & Pull Request Standards
Follow **conventional commits** format: `type(scope): subject`
Examples from recent history:
- `fix(auto-layout): rankdir top to bottom`
- `feat(landing): hover logo node glowing`
- `docs(variable): optimize variable docs by codex`
Keep commit subjects imperative, ≤72 characters. Reference GitHub issues in PR descriptions.
## Working with Packages
### Adding a New Package
1. Create folder under appropriate category (`packages/<category>/<package-name>`)
2. Add entry to `rush.json` "projects" array with:
- `packageName`: `@flowgram.ai/<package-name>`
- `projectFolder`: relative path
- `versionPolicyName`: typically "publishPolicy" for libraries, "appPolicy" for apps
- `tags`: for categorization
3. Run `rush update` to link the package
### Publishing Workflow
Packages with `versionPolicyName: "publishPolicy"` are publishable to npm. Apps use `"appPolicy"`.
### Inter-package Dependencies
Use `workspace:^x.x.x` protocol in package.json for internal dependencies. Rush will link them locally during development.
## Common Issues
### Build Failures
- Ensure `rush install` was run after pulling changes
- Check Node.js version matches `nodeSupportedVersionRange` in rush.json
- Clear incremental build cache: delete `common/temp` and rebuild
### Type Errors in Editor Packages
The main editor packages (`@flowgram.ai/editor`, `@flowgram.ai/fixed-layout-editor`, `@flowgram.ai/free-layout-editor`) re-export many types. Look for type definitions in their upstream dependencies (@flowgram.ai/form, @flowgram.ai/core, @flowgram.ai/node).
### Plugin Registration
Plugins must be registered in a dependency injection container. Check demo apps for examples of container module setup.
### Rush Command Not Found
Ensure Rush is installed globally: `npm install -g @microsoft/rush`
Or use the install-run script: `node common/scripts/install-run-rush.js <command>`
## Additional Resources
- Documentation: https://flowgram.ai
- Issues: https://github.com/bytedance/flowgram.ai/issues
- Contributing: See CONTRIBUTING.md
================================================
FILE: CNAME
================================================
flowgram.ai
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to flowgram.ai
## Quick Start
### Prerequisites
- Node.js 18+ (LTS/Hydrogen recommended)
- pnpm 10.6.5
- Rush 5.150.0
### Installation
1. **Install Node.js 18+**
``` bash
nvm install lts/hydrogen
nvm alias default lts/hydrogen # set default node version
nvm use lts/hydrogen
```
2. **Clone the repository**
``` bash
git clone git@github.com:bytedance/flowgram.ai.git
```
3. **Install required global dependencies**
``` bash
npm i -g pnpm@10.6.5 @microsoft/rush@5.150.0
```
4. **Install project dependencies**
``` bash
rush install
```
5. **Build the project**
``` bash
rush build
```
6. **Run docs or demo**
``` bash
rush dev:docs # docs
rush dev:demo-fixed-layout
rush dev:demo-free-layout
```
After that, you can start to develop projects inside this repository.
## Submitting Changes
1. Create a new branch from `main` using the format:
- `feat/description` for features
- `fix/description` for bug fixes
- `docs/description` for documentation
- `chore/description` for maintenance
2. Write code and tests
- Follow our coding standards
- Add/update tests for changes
- Update documentation if needed
3. Ensure quality
- Run `cd path/to/packageName && npm test` for all tests
- Run `rush lint` for code style
- Run `rush build` to verify build
4. Create Pull Request
- Use the PR template
- Link related issues
- Provide clear description of changes
5. Review Process
- Maintainers will review your PR
- Address review feedback if any
- Changes must pass CI checks
6. Commit Message Format
```
type(scope): subject
body
```
Types: feat, fix, docs, style, refactor, test, chore
## Reporting Bugs
Report bugs via [GitHub Issues](https://github.com/bytedance/flowgram.ai/issues/new/choose). Please include:
- Issue description
- Steps to reproduce
- Expected behavior
- Actual behavior
- Code examples (if applicable)
## Documentation
- Update API documentation for interface changes
- Update README.md if usage is affected
## License
This project is under the [MIT License](http://choosealicense.com/licenses/mit/). By submitting code, you agree to these terms.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
================================================
FILE: README.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram|Workflow development framework
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGram is a composable, visual, easy-to-integrate, and extensible workflow development framework & toolkit.
Our goal is to help developers build AI workflow platforms **faster** and **simpler**.
FlowGram comes with a suite of built-in tools for workflow development: flow canvas, node configuration form, variable scope chain, and ready-to-use materials (LLM, Condition, Code Editor etc). It’s not a ready-made workflow platform; it’s the framework and toolkit to build yours.
Learn more at [FlowGram.AI 🌐](https://flowgram.ai)
## 🎬 Demo
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
Open in [CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main) or [StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo)
In this demo, we iterate through a list of cities, fetch real-time weather via HTTP, parse temperatures with a Code node, generate outfit suggestions with an LLM, gate by a Condition, aggregate results across the loop, and finally use an Advisor LLM to pick the most comfortable city before sending the result to the End node.
## 🚀 Quick Start
1. Create a new FlowGram project:
```sh
npx @flowgram.ai/create-app@latest
```
> We recommend choosing the `Free Layout Demo ⭐️` template.
2. Start the project:
```sh
cd demo-free-layout
npm install
npm start
```
3. Open [http://localhost:3000](http://localhost:3000) in your browser.
## ✨ Features
| Feature | Description | Demo |
| -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [Free Layout Canvas](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | Free layout canvas where nodes can be placed anywhere and connected using free-form lines. |  |
| [Fixed Layout Canvas](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | Fixed layout canvas where nodes can be dragged to specified positions, with support for compound nodes like branches and loops. |  |
| [Form](https://flowgram.ai/examples/node-form/basic.html) | The form engine manages the CRUD operations of node data and provides rendering, validation, side effects, linkage, and error-capturing capabilities, simplifying the development of node configurations. |  |
| [Variable](https://flowgram.ai/guide/variable/basic.html) | The variable engine supports scope constraints, variable structure inspection, and type inference, making it easy to manage data flow within the workflow. |  |
## 📖 Documentation
You can find the FlowGram documentation [on the website](https://flowgram.ai).
The documentation is divided into several sections:
- [Quick Start](https://flowgram.ai/guide/getting-started/introduction.html)
- [Canvas](https://flowgram.ai/guide/free-layout/load.html)
- [Form](https://flowgram.ai/guide/form/form.html)
- [Variable](https://flowgram.ai/guide/variable/basic.html)
- [Material](https://flowgram.ai/materials/introduction.html)
- [Runtime](https://flowgram.ai/guide/runtime/introduction.html)
- [Advanced Guides](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [API Reference](https://flowgram.ai/api/index.html)
- [Where to get Support](https://flowgram.ai/guide/contact-us.html)
- [Contributing Guide](https://flowgram.ai/guide/contributing.html)
## 🙌 Contributors
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 Adoption
- [Coze Studio](https://github.com/coze-dev/coze-studio) is an all-in-one AI agent development tool. Providing the latest large models and tools, various development modes and frameworks, Coze Studio offers the most convenient AI agent development environment, from development to deployment.
- [NNDeploy](https://github.com/NNDeploy/nndeploy) is a workflow-based multi-platform ai deployment tool.
- [Certimate](https://github.com/certimate-go/certimate) is an open-source SSL certificate management tool that helps you automatically apply for and deploy SSL certificates with a visual workflow. It is one of the ACME client options listed in the official documentation of Let's Encrypt.
## 📬 Contact us
- Issues: [Issues](https://github.com/bytedance/flowgram.ai/issues)
- Lark: Scan the QR code below with [Register Feishu](https://www.feishu.cn/en/) to join our FlowGram user group.
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: README_DE.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram | Workflow-Entwicklungs-Framework
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGram ist ein zusammensetzbares, visuelles, einfach zu integrierendes und erweiterbares Workflow-Entwicklungs-Framework & Toolkit.
Unser Ziel ist es, Entwicklern zu helfen, KI-Workflow-Plattformen **schneller** und **einfacher** zu erstellen.
FlowGram wird mit einer Reihe von integrierten Werkzeugen für die Workflow-Entwicklung geliefert: eine visuelle Flow-Canvas, Node-Konfigurationsformulare, eine Variablen-Scope-Chain und sofort einsatzbereite Materialien (LLM, Bedingung, Code-Editor usw.). Es ist keine fertige Workflow-Plattform; es ist das Framework und Toolkit, um Ihre zu erstellen.
Erfahren Sie mehr unter [FlowGram.AI 🌐](https://flowgram.ai)
## 🎬 Demo
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
Öffnen Sie in [CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main) oder [StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo)
In dieser Demo durchlaufen wir eine Liste von Städten, rufen das Echtzeit-Wetter über HTTP ab, parsen die Temperaturen mit einem Code-Knoten, generieren Outfit-Vorschläge mit einem LLM, steuern durch eine Bedingung, aggregieren die Ergebnisse über die Schleife und verwenden schließlich einen Berater-LLM, um die komfortabelste Stadt auszuwählen, bevor das Ergebnis an den Endknoten gesendet wird.
## 🚀 Schnellstart
1. Erstellen Sie ein neues FlowGram-Projekt:
```sh
npx @flowgram.ai/create-app@latest
```
> Wir empfehlen, die Vorlage `Free Layout Demo ⭐️` zu wählen.
2. Starten Sie das Projekt:
```sh
cd demo-free-layout
npm install
npm start
```
3. Öffnen Sie [http://localhost:3000](http://localhost:3000) in Ihrem Browser.
## ✨ Funktionen
| Funktion | Beschreibung | Demo |
| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [Free Layout Canvas](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | Freie Layout-Canvas, auf der Knoten beliebig platziert und mit Freiformlinien verbunden werden können. |  |
| [Fixed Layout Canvas](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | Feste Layout-Canvas, auf der Knoten an bestimmte Positionen gezogen werden können, mit Unterstützung für zusammengesetzte Knoten wie Verzweigungen und Schleifen. |  |
| [Formular](https://flowgram.ai/examples/node-form/basic.html) | Die Formular-Engine verwaltet CRUD-Operationen von Knotendaten und bietet Rendering-, Validierungs-, Nebeneffekt-, Verknüpfungs- und Fehlererfassungsfunktionen, wodurch die Entwicklung von Knotenkonfigurationen vereinfacht wird. |  |
| [Variable](https://flowgram.ai/guide/variable/basic.html) | Die Variablen-Engine unterstützt Bereichsbeschränkungen, Variablenstrukturinspektion und Typinferenz, wodurch der Datenfluss im Workflow einfach verwaltet werden kann. |  |
## 📖 Dokumentation
Sie finden die FlowGram-Dokumentation [auf der Website](https://flowgram.ai).
Die Dokumentation ist in mehrere Abschnitte unterteilt:
- [Schnellstart](https://flowgram.ai/guide/getting-started/introduction.html)
- [Canvas](https://flowgram.ai/guide/free-layout/load.html)
- [Formular](https://flowgram.ai/guide/form/form.html)
- [Variable](https://flowgram.ai/guide/variable/basic.html)
- [Material](https://flowgram.ai/materials/introduction.html)
- [Laufzeit](https://flowgram.ai/guide/runtime/introduction.html)
- [Erweiterte Anleitungen](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [API-Referenz](https://flowgram.ai/api/index.html)
- [Wo Sie Unterstützung erhalten](https://flowgram.ai/guide/contact-us.html)
- [Leitfaden für Beiträge](https://flowgram.ai/guide/contributing.html)
## 🙌 Mitwirkende
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 Einführung
- [Coze Studio](https://github.com/coze-dev/coze-studio) ist ein All-in-One-KI-Agenten-Entwicklungstool. Coze Studio bietet die neuesten großen Modelle und Werkzeuge, verschiedene Entwicklungsmodi und Frameworks und bietet die bequemste KI-Agenten-Entwicklungsumgebung, von der Entwicklung bis zur Bereitstellung.
- [NNDeploy](https://github.com/NNDeploy/nndeploy) ist ein Workflow-basiertes Multi-Plattform-KI-Bereitstellungstool.
- [Certimate](https://github.com/certimate-go/certimate) ist ein Open-Source-SSL-Zertifikatsverwaltungstool, mit dem Sie SSL-Zertifikate automatisch mit einem visuellen Workflow beantragen und bereitstellen können. Es ist eine der ACME-Client-Optionen, die in der offiziellen Dokumentation von Let's Encrypt aufgeführt sind.
## 📬 Kontaktieren Sie uns
- Probleme: [Probleme](https://github.com/bytedance/flowgram.ai/issues)
- Lark: Scannen Sie den QR-Code unten mit [Register Feishu](https://www.feishu.cn/en/), um unserer FlowGram-Benutzergruppe beizutreten.
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: README_ES.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram | Marco de desarrollo de flujos de trabajo
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGram es un marco y conjunto de herramientas de desarrollo de flujos de trabajo componible, visual, fácil de integrar y extensible.
Nuestro objetivo es ayudar a los desarrolladores a crear plataformas de flujo de trabajo de IA de forma **más rápida** y **sencilla**.
FlowGram viene con un conjunto de herramientas integradas para el desarrollo de flujos de trabajo: un lienzo de flujo visual, formularios de configuración de nodos, una cadena de alcance de variables y materiales listos para usar (LLM, Condición, Editor de código, etc.). No es una plataforma de flujo de trabajo ya hecha; es el marco y el conjunto de herramientas para crear la suya.
Obtenga más información en [FlowGram.AI 🌐](https://flowgram.ai)
## 🎬 Demostración
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
Abra en [CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main) o [StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo)
En esta demostración, iteramos a través de una lista de ciudades, obtenemos el clima en tiempo real a través de HTTP, analizamos las temperaturas con un nodo de código, generamos sugerencias de atuendos con un LLM, controlamos mediante una condición, agregamos los resultados a lo largo del bucle y, finalmente, usamos un LLM asesor para elegir la ciudad más cómoda antes de enviar el resultado al nodo final.
## 🚀 Inicio rápido
1. Cree un nuevo proyecto de FlowGram:
```sh
npx @flowgram.ai/create-app@latest
```
> Le recomendamos que elija la plantilla `Free Layout Demo ⭐️`.
2. Inicie el proyecto:
```sh
cd demo-free-layout
npm install
npm start
```
3. Abra [http://localhost:3000](http://localhost:3000) en su navegador.
## ✨ Características
| Característica | Descripción | Demostración |
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| [Lienzo de diseño libre](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | Lienzo de diseño libre donde los nodos se pueden colocar en cualquier lugar y conectar mediante líneas de forma libre. |  |
| [Lienzo de diseño fijo](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | Lienzo de diseño fijo donde los nodos se pueden arrastrar a posiciones específicas, con soporte para nodos compuestos como ramas y bucles. |  |
| [Formulario](https://flowgram.ai/examples/node-form/basic.html) | El motor de formularios gestiona las operaciones CRUD de datos de nodos y proporciona capacidades de renderizado, validación, efectos secundarios, vinculación y captura de errores, simplificando el desarrollo de configuraciones de nodos. |  |
| [Variable](https://flowgram.ai/guide/variable/basic.html) | El motor de variables admite restricciones de ámbito, inspección de estructura de variables e inferencia de tipos, facilitando la gestión del flujo de datos dentro del flujo de trabajo. |  |
## 📖 Documentación
Puede encontrar la documentación de FlowGram [en el sitio web](https://flowgram.ai).
La documentación se divide en varias secciones:
- [Inicio rápido](https://flowgram.ai/guide/getting-started/introduction.html)
- [Lienzo](https://flowgram.ai/guide/free-layout/load.html)
- [Formulario](https://flowgram.ai/guide/form/form.html)
- [Variable](https://flowgram.ai/guide/variable/basic.html)
- [Material](https://flowgram.ai/materials/introduction.html)
- [Tiempo de ejecución](https://flowgram.ai/guide/runtime/introduction.html)
- [Guías avanzadas](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [Referencia de la API](https://flowgram.ai/api/index.html)
- [Dónde obtener soporte](https://flowgram.ai/guide/contact-us.html)
- [Guía de contribución](https://flowgram.ai/guide/contributing.html)
## 🙌 Colaboradores
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 Adopción
- [Coze Studio](https://github.com/coze-dev/coze-studio) es una herramienta de desarrollo de agentes de IA todo en uno. Coze Studio, que proporciona los últimos modelos y herramientas grandes, varios modos y marcos de desarrollo, ofrece el entorno de desarrollo de agentes de IA más conveniente, desde el desarrollo hasta la implementación.
- [NNDeploy](https://github.com/NNDeploy/nndeploy) es una herramienta de implementación de IA multiplataforma basada en flujos de trabajo.
- [Certimate](https://github.com/certimate-go/certimate) es una herramienta de gestión de certificados SSL de código abierto que le ayuda a solicitar e implementar automáticamente certificados SSL con un flujo de trabajo visual. Es una de las opciones de cliente ACME que se enumeran en la documentación oficial de Let's Encrypt.
## 📬 Contáctenos
- Problemas: [Problemas](https://github.com/bytedance/flowgram.ai/issues)
- Lark: Escanee el código QR a continuación con [Registrar Feishu](https://www.feishu.cn/en/) para unirse a nuestro grupo de usuarios de FlowGram.
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: README_JA.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram|ワークフロー開発フレームワーク
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGramは、構成可能で、視覚的で、統合しやすく、拡張可能なワークフロー開発フレームワーク&ツールキットです。
私たちの目標は、開発者がAIワークフロープラットフォームを**より速く**、**よりシンプルに**構築できるよう支援することです。
FlowGramには、ワークフロー開発用の組み込みツール一式が付属しています。視覚的なフローキャンバス、ノード構成フォーム、変数スコープチェーン、すぐに使えるマテリアル(LLM、条件、コードエディターなど)です。これは既製のワークフロープラットフォームではありません。あなたのワークフロープラットフォームを構築するためのフレームワークとツールキットです。
詳細は[FlowGram.AI 🌐](https://flowgram.ai)をご覧ください。
## 🎬 デモ
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
[CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main)または[StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo)で開く
このデモでは、都市のリストを反復処理し、HTTP経由でリアルタイムの天気を取得し、コードノードで気温を解析し、LLMで服装の提案を生成し、条件でゲートし、ループ全体で結果を集計し、最後にアドバイザーLLMを使用して最も快適な都市を選択してから、結果を終了ノードに送信します。
## 🚀 クイックスタート
1. 新しいFlowGramプロジェクトを作成します:
```sh
npx @flowgram.ai/create-app@latest
```
> `Free Layout Demo ⭐️` テンプレートを選択することをお勧めします。
2. プロジェクトを開始します:
```sh
cd demo-free-layout
npm install
npm start
```
3. ブラウザで[http://localhost:3000](http://localhost:3000)を開きます。
## ✨ 機能
| 機能 | 説明 | デモ |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [フリーレイアウトキャンバス](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | ノードをどこにでも配置し、自由形式の線で接続できるフリーレイアウトキャンバス。 |  |
| [固定レイアウトキャンバス](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | 分岐やループなどの複合ノードをサポートし、ノードを指定した位置にドラッグできる固定レイアウトキャンバス。 |  |
| [フォーム](https://flowgram.ai/examples/node-form/basic.html) | フォームエンジンはノードデータのCRUD操作を管理し、レンダリング、検証、副作用、連動、エラー処理機能を提供し、ノード設定の開発を簡素化します。 |  |
| [変数](https://flowgram.ai/guide/variable/basic.html) | 変数エンジンはスコープ制約、変数構造検査、型推論をサポートし、ワークフロー内のデータフローの管理を容易にします。 |  |
## 📖 ドキュメント
FlowGramのドキュメントは[ウェブサイト](https://flowgram.ai)でご覧いただけます。
ドキュメントはいくつかのセクションに分かれています。
- [クイックスタート](https://flowgram.ai/guide/getting-started/introduction.html)
- [キャンバス](https://flowgram.ai/guide/free-layout/load.html)
- [フォーム](https://flowgram.ai/guide/form/form.html)
- [変数](https://flowgram.ai/guide/variable/basic.html)
- [マテリアル](https://flowgram.ai/materials/introduction.html)
- [ランタイム](https://flowgram.ai/guide/runtime/introduction.html)
- [高度なガイド](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [APIリファレンス](https://flowgram.ai/api/index.html)
- [サポートの入手先](https://flowgram.ai/guide/contact-us.html)
- [貢献ガイド](https://flowgram.ai/guide/contributing.html)
## 🙌 貢献者
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 採用
- [Coze Studio](https://github.com/coze-dev/coze-studio)は、オールインワンのAIエージェント開発ツールです。最新の主要モデルとツール、さまざまな開発モードとフレームワークを提供するCoze Studioは、開発から展開まで、最も便利なAIエージェント開発環境を提供します。
- [NNDeploy](https://github.com/NNDeploy/nndeploy)は、ワークフローベースのマルチプラットフォームAI展開ツールです。
- [Certimate](https://github.com/certimate-go/certimate)は、視覚的なワークフローでSSL証明書を自動的に申請および展開するのに役立つオープンソースのSSL証明書管理ツールです。これは、Let's Encryptの公式ドキュメントに記載されているACMEクライアントオプションの1つです。
## 📬 お問い合わせ
- 問題:[問題](https://github.com/bytedance/flowgram.ai/issues)
- Lark:[Register Feishu](https://www.feishu.cn/en/)で以下のQRコードをスキャンして、FlowGramユーザーグループに参加してください。
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: README_PT.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram | Estrutura de desenvolvimento de fluxo de trabalho
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGram é uma estrutura e kit de ferramentas de desenvolvimento de fluxo de trabalho componível, visual, fácil de integrar e extensível.
Nosso objetivo é ajudar os desenvolvedores a criar plataformas de fluxo de trabalho de IA de forma **mais rápida** e **simples**.
O FlowGram vem com um conjunto de ferramentas integradas para o desenvolvimento de fluxo de trabalho: uma tela de fluxo visual, formulários de configuração de nós, uma cadeia de escopo de variáveis e materiais prontos para uso (LLM, Condição, Editor de Código, etc.). Não é uma plataforma de fluxo de trabalho pronta; é a estrutura e o kit de ferramentas para construir a sua.
Saiba mais em [FlowGram.AI 🌐](https://flowgram.ai)
## 🎬 Demonstração
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
Abra no [CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main) ou [StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo)
Nesta demonstração, iteramos por uma lista de cidades, buscamos o clima em tempo real via HTTP, analisamos as temperaturas com um nó de Código, geramos sugestões de roupas com um LLM, controlamos por uma Condição, agregamos os resultados ao longo do loop e, finalmente, usamos um LLM Conselheiro para escolher a cidade mais confortável antes de enviar o resultado para o nó Final.
## 🚀 Início rápido
1. Crie um novo projeto FlowGram:
```sh
npx @flowgram.ai/create-app@latest
```
> Recomendamos escolher o template `Free Layout Demo ⭐️`.
2. Inicie o projeto:
```sh
cd demo-free-layout
npm install
npm start
```
3. Abra [http://localhost:3000](http://localhost:3000) no seu navegador.
## ✨ Recursos
| Recurso | Descrição | Demonstração |
| -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| [Tela de Layout Livre](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | Tela de layout livre onde os nós podem ser colocados em qualquer lugar e conectados usando linhas de forma livre. |  |
| [Tela de Layout Fixo](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | Tela de layout fixo onde os nós podem ser arrastados para posições especificadas, com suporte para nós compostos como ramificações e loops. |  |
| [Formulário](https://flowgram.ai/examples/node-form/basic.html) | O mecanismo de formulário gerencia as operações CRUD de dados do nó e fornece recursos de renderização, validação, efeitos colaterais, vinculação e captura de erros, simplificando o desenvolvimento de configurações de nó. |  |
| [Variável](https://flowgram.ai/guide/variable/basic.html) | O mecanismo de variáveis suporta restrições de escopo, inspeção de estrutura de variáveis e inferência de tipos, facilitando o gerenciamento do fluxo de dados dentro do fluxo de trabalho. |  |
## 📖 Documentação
Você pode encontrar a documentação do FlowGram [no site](https://flowgram.ai).
A documentação está dividida em várias seções:
- [Início Rápido](https://flowgram.ai/guide/getting-started/introduction.html)
- [Tela](https://flowgram.ai/guide/free-layout/load.html)
- [Formulário](https://flowgram.ai/guide/form/form.html)
- [Variável](https://flowgram.ai/guide/variable/basic.html)
- [Material](https://flowgram.ai/materials/introduction.html)
- [Tempo de Execução](https://flowgram.ai/guide/runtime/introduction.html)
- [Guias Avançados](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [Referência da API](https://flowgram.ai/api/index.html)
- [Onde obter suporte](https://flowgram.ai/guide/contact-us.html)
- [Guia de contribuição](https://flowgram.ai/guide/contributing.html)
## 🙌 Colaboradores
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 Adoção
- [Coze Studio](https://github.com/coze-dev/coze-studio) é uma ferramenta de desenvolvimento de agente de IA tudo-em-um. Fornecendo os modelos e ferramentas mais recentes, vários modos e estruturas de desenvolvimento, o Coze Studio oferece o ambiente de desenvolvimento de agente de IA mais conveniente, do desenvolvimento à implantação.
- [NNDeploy](https://github.com/NNDeploy/nndeploy) é uma ferramenta de implantação de IA multiplataforma baseada em fluxo de trabalho.
- [Certimate](https://github.com/certimate-go/certimate) é uma ferramenta de gerenciamento de certificados SSL de código aberto que ajuda você a solicitar e implantar certificados SSL automaticamente com um fluxo de trabalho visual. É uma das opções de cliente ACME listadas na documentação oficial do Let's Encrypt.
## 📬 Contate-nos
- Problemas: [Problemas](https://github.com/bytedance/flowgram.ai/issues)
- Lark: Digitalize o código QR abaixo com [Registrar Feishu](https://www.feishu.cn/en/) para se juntar ao nosso grupo de usuários FlowGram.
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: README_RU.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram | Фреймворк для разработки рабочих процессов
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGram — это компонуемый, визуальный, легко интегрируемый и расширяемый фреймворк и набор инструментов для разработки рабочих процессов.
Наша цель — помочь разработчикам создавать платформы для рабочих процессов ИИ **быстрее** и **проще**.
FlowGram поставляется со встроенным набором инструментов для разработки рабочих процессов: визуальным холстом потока, формами конфигурации узлов, цепочкой области видимости переменных и готовыми к использованию материалами (LLM, Условие, Редактор кода и т. д.). Это не готовая платформа для рабочих процессов; это фреймворк и набор инструментов для создания вашей собственной.
Узнайте больше на [FlowGram.AI 🌐](https://flowgram.ai)
## 🎬 Демо
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
Откройте в [CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main) или [StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo)
В этом демо мы перебираем список городов, получаем погоду в реальном времени по HTTP, анализируем температуру с помощью узла «Код», генерируем предложения по одежде с помощью LLM, управляем с помощью «Условия», агрегируем результаты по циклу и, наконец, используем LLM-советника, чтобы выбрать самый комфортный город, прежде чем отправить результат в конечный узел.
## 🚀 Быстрый старт
1. Создайте новый проект FlowGram:
```sh
npx @flowgram.ai/create-app@latest
```
> Мы рекомендуем выбрать шаблон `Free Layout Demo ⭐️`.
2. Запустите проект:
```sh
cd demo-free-layout
npm install
npm start
```
3. Откройте [http://localhost:3000](http://localhost:3000) в вашем браузере.
## ✨ Особенности
| Особенность | Описание | Демо |
| ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [Холст со свободной компоновкой](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | Холст со свободной компоновкой, где узлы можно размещать где угодно и соединять линиями произвольной формы. |  |
| [Холст с фиксированной компоновкой](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | Холст с фиксированной компоновкой, где узлы можно перетаскивать в указанные позиции, с поддержкой составных узлов, таких как ветви и циклы. |  |
| [Форма](https://flowgram.ai/examples/node-form/basic.html) | Движок форм управляет операциями CRUD данных узлов и предоставляет возможности рендеринга, валидации, побочных эффектов, связывания и обработки ошибок, упрощая разработку конфигураций узлов. |  |
| [Переменная](https://flowgram.ai/guide/variable/basic.html) | Движок переменных поддерживает ограничения области видимости, инспекцию структуры переменных и вывод типов, облегчая управление потоком данных в рабочем процессе. |  |
## 📖 Документация
Вы можете найти документацию FlowGram [на веб-сайте](https://flowgram.ai).
Документация разделена на несколько разделов:
- [Быстрый старт](https://flowgram.ai/guide/getting-started/introduction.html)
- [Холст](https://flowgram.ai/guide/free-layout/load.html)
- [Форма](https://flowgram.ai/guide/form/form.html)
- [Переменная](https://flowgram.ai/guide/variable/basic.html)
- [Материал](https://flowgram.ai/materials/introduction.html)
- [Среда выполнения](https://flowgram.ai/guide/runtime/introduction.html)
- [Расширенные руководства](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [Справочник по API](https://flowgram.ai/api/index.html)
- [Где получить поддержку](https://flowgram.ai/guide/contact-us.html)
- [Руководство по вкладу](https://flowgram.ai/guide/contributing.html)
## 🙌 Участники
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 Внедрение
- [Coze Studio](https://github.com/coze-dev/coze-studio) — это универсальный инструмент для разработки агентов ИИ. Предоставляя новейшие большие модели и инструменты, различные режимы и фреймворки разработки, Coze Studio предлагает наиболее удобную среду разработки агентов ИИ, от разработки до развертывания.
- [NNDeploy](https://github.com/NNDeploy/nndeploy) — это мультиплатформенный инструмент развертывания ИИ на основе рабочих процессов.
- [Certimate](https://github.com/certimate-go/certimate) — это инструмент управления SSL-сертификатами с открытым исходным кодом, который помогает автоматически подавать заявки и развертывать SSL-сертификаты с помощью визуального рабочего процесса. Это один из вариантов клиента ACME, перечисленных в официальной документации Let's Encrypt.
## 📬 Свяжитесь с нами
- Проблемы: [Проблемы](https://github.com/bytedance/flowgram.ai/issues)
- Lark: отсканируйте QR-код ниже с помощью [Register Feishu](https://www.feishu.cn/en/), чтобы присоединиться к нашей группе пользователей FlowGram.
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: README_ZH.md
================================================

<div align="center">
[](https://github.com/bytedance/flowgram.ai/blob/main/LICENSE) [](https://www.npmjs.com/package/@flowgram.ai/editor) [](https://deepwiki.com/bytedance/flowgram.ai) [](https://juejin.cn/column/7479814468601315362)
[](https://trendshift.io/repositories/13877)
</div>
# FlowGram.AI|工作流开发框架
[English](README.md) | [中文](README_ZH.md) | [Español](README_ES.md) | [Русский](README_RU.md) | [Português](README_PT.md) | [Deutsch](README_DE.md) | [日本語](README_JA.md)
FlowGram 是一个可组合、可视化、易于集成且可扩展的工作流开发框架与工具集。
我们的目标是帮助开发者以更快、更简单的方式搭建 AI 工作流平台。
FlowGram 内置开箱开箱即用的工作流开发能力:可视化流程画布、节点配置表单、变量作用域链,以及开箱即用的物料(LLM、条件、代码编辑器等)。这并非一个现成的工作流平台,而是帮助你构建平台的框架与工具。
了解更多 [FlowGram.AI 🌐](https://flowgram.ai)
## 🎬 演示
<https://github.com/user-attachments/assets/fee87890-ceec-4c07-b659-08afc4dedc26>
在 [CodeSandbox 🌐](https://codesandbox.io/p/github/louisyoungx/flowgram-demo/main) 或 [StackBlitz 🌐](https://stackblitz.com/~/github.com/louisyoungx/flowgram-demo) 中打开
在该演示中,我们遍历一组城市,通过 HTTP 获取实时天气,用 Code 节点解析温度,借助 LLM 生成穿搭建议,经由 Condition 进行筛选,在循环中汇总结果,最后使用 Advisor LLM 选出最舒适的城市,并将结果发送至 End 节点。
## 🚀 快速上手
1. 创建一个新的 FlowGram 项目:
```sh
npx @flowgram.ai/create-app@latest
```
> 我们推荐选择 `Free Layout Demo ⭐️` 模板。
2. 启动项目:
```sh
cd demo-free-layout
npm install
npm start
```
3. 在浏览器中打开 [http://localhost:3000](http://localhost:3000)。
## ✨ 特性
| 特性 | 说明 | 演示 |
| -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [Free Layout Canvas](https://flowgram.ai/examples/free-layout/free-feature-overview.html) | 自由布局画布,节点可任意摆放,可在节点间创建边进行链接。 |  |
| [Fixed Layout Canvas](https://flowgram.ai/examples/fixed-layout/fixed-feature-overview.html) | 固定布局画布,节点可拖拽至指定位置,支持复合节点(如分支与循环)。 |  |
| [Form](https://flowgram.ai/examples/node-form/basic.html) | 表单引擎管理节点数据的增删改查操作,并提供渲染、验证、副作用、联动和错误捕获等功能,简化节点配置的开发。 |  |
| [Variable](https://flowgram.ai/guide/variable/basic.html) | 变量引擎支持作用域约束、变量结构检查和类型推断等功能,便于管理工作流中的数据流。 |  |
## 📖 文档
你可以在官网查阅完整文档:[FlowGram 文档](https://flowgram.ai)。
文档分为以下章节:
- [快速入门](https://flowgram.ai/guide/getting-started/introduction.html)
- [自由画布](https://flowgram.ai/guide/free-layout/load.html)
- [固定画布](https://flowgram.ai/guide/fixed-layout/load.html)
- [表单](https://flowgram.ai/guide/form/form.html)
- [变量](https://flowgram.ai/guide/variable/basic.html)
- [素材](https://flowgram.ai/materials/introduction.html)
- [运行时](https://flowgram.ai/guide/runtime/introduction.html)
- [进阶指南](https://flowgram.ai/guide/advanced/zoom-scroll.html)
- [API 参考](https://flowgram.ai/api/index.html)
- [获取支持](https://flowgram.ai/guide/contact-us.html)
- [贡献指南](https://flowgram.ai/guide/contributing.html)
## 🙌 贡献者
[](https://github.com/bytedance/flowgram.ai/graphs/contributors)
## 🌍 被这些项目采用
- [Coze Studio](https://github.com/coze-dev/coze-studio) 是一体化的 AI Agent 开发工具,提供最新的大模型与工具、多样的开发模式与框架,并在从开发到部署的全流程中,提供最便捷的 Agent 开发体验。
- [NNDeploy](https://github.com/NNDeploy/nndeploy) 是一个基于工作流的多平台 AI 部署工具。
- [Certimate](https://github.com/certimate-go/certimate) 是开源的 SSL 证书管理工具,借助可视化工作流帮助你自动申请与部署证书;它也是官方文档列出的 Let's Encrypt ACME 客户端选项之一。
## 📬 联系我们
- 问题反馈: [Issues](https://github.com/bytedance/flowgram.ai/issues)
- 飞书:使用 [Register Feishu](https://www.feishu.cn/en/) 扫码下方二维码,加入 FlowGram 用户群。
<img src="./apps/docs/src/public/lark-group.png" width="200"/>
================================================
FILE: apps/cli/.gitignore
================================================
.download
================================================
FILE: apps/cli/bin/index.js
================================================
#!/usr/bin/env node
import '../dist/index.js';
================================================
FILE: apps/cli/eslint.config.js
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { defineFlatConfig } from '@flowgram.ai/eslint-config';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default defineFlatConfig({
preset: 'web',
packageRoot: __dirname,
rules: {
'no-console': 'off',
},
settings: {
react: {
version: '18',
},
},
});
================================================
FILE: apps/cli/package.json
================================================
{
"name": "@flowgram.ai/cli",
"version": "0.1.8",
"description": "A CLI tool to create demo projects or sync materials",
"bin": {
"flowgram-cli": "./bin/index.js"
},
"type": "module",
"files": [
"bin",
"src",
"dist"
],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts --out-dir dist",
"watch": "tsup src/index.ts --format esm,cjs --out-dir dist --watch",
"start": "node bin/index.js",
"lint": "eslint ./src --cache",
"lint:fix": "eslint ./src --fix"
},
"dependencies": {
"fs-extra": "^9.1.0",
"commander": "^11.0.0",
"chalk": "^5.3.0",
"tar": "7.4.3",
"inquirer": "^12.9.4",
"ignore": "~7.0.5"
},
"devDependencies": {
"@flowgram.ai/eslint-config": "workspace:*",
"@types/download": "8.0.5",
"@types/fs-extra": "11.0.4",
"@types/node": "^18",
"@types/inquirer": "^9.0.9",
"tsup": "^8.0.1",
"eslint": "^9.0.0",
"@typescript-eslint/parser": "^8.0.0",
"typescript": "^5.8.3"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}
}
================================================
FILE: apps/cli/src/create-app/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import https from 'https';
import { execSync } from 'child_process';
import * as tar from 'tar';
import inquirer from 'inquirer';
import fs from 'fs-extra';
import chalk from 'chalk';
const updateFlowGramVersions = (dependencies: any[], latestVersion: string) => {
for (const packageName in dependencies) {
if (packageName.startsWith('@flowgram.ai')) {
dependencies[packageName] = latestVersion;
}
}
};
// 使用 https 下载文件
function downloadFile(url: string, dest: string): Promise<void> {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
https
.get(url, (response) => {
if (response.statusCode !== 200) {
reject(new Error(`Download failed: ${response.statusCode}`));
return;
}
response.pipe(file);
file.on('finish', () => {
file.close();
resolve();
});
})
.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
file.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
});
}
export const createApp = async (projectName?: string) => {
console.log(chalk.green('Welcome to @flowgram.ai/create-app CLI!'));
const latest = execSync('npm view @flowgram.ai/demo-fixed-layout version --tag=latest latest')
.toString()
.trim();
let folderName = '';
if (!projectName) {
// 询问用户选择 demo 项目
const { repo } = await inquirer.prompt([
{
type: 'list',
name: 'repo',
message: 'Select a demo to create:',
choices: [
{ name: 'Fixed Layout Demo', value: 'demo-fixed-layout' },
{ name: 'Free Layout Demo', value: 'demo-free-layout' },
{ name: 'Fixed Layout Demo Simple', value: 'demo-fixed-layout-simple' },
{ name: 'Free Layout Demo Simple', value: 'demo-free-layout-simple' },
{ name: 'Free Layout Nextjs Demo', value: 'demo-nextjs' },
{ name: 'Free Layout Vite Demo Simple', value: 'demo-vite' },
{ name: 'Demo Playground for infinite canvas', value: 'demo-playground' },
],
},
]);
folderName = repo;
} else {
if (
[
'fixed-layout',
'free-layout',
'fixed-layout-simple',
'free-layout-simple',
'playground',
'nextjs',
].includes(projectName)
) {
folderName = `demo-${projectName}`;
} else {
console.error('Invalid projectName. Please run "npx create-app" to choose demo.');
return;
}
}
try {
const targetDir = path.join(process.cwd());
// 下载 npm 包的 tarball
const downloadPackage = async () => {
try {
const url = `https://registry.npmjs.org/@flowgram.ai/${folderName}/-/${folderName}-${latest}.tgz`;
const tempTarballPath = path.join(process.cwd(), `${folderName}.tgz`);
console.log(chalk.blue(`Downloading ${url} ...`));
await downloadFile(url, tempTarballPath);
fs.ensureDirSync(targetDir);
await tar.x({
file: tempTarballPath,
C: targetDir,
});
fs.renameSync(path.join(targetDir, 'package'), path.join(targetDir, folderName));
fs.unlinkSync(tempTarballPath);
return true;
} catch (error) {
console.error(`Error downloading or extracting package`);
console.error(error);
return false;
}
};
const res = await downloadPackage();
// 替换 package.json 内部的 @flowgram.ai 包版本为 latest
const pkgJsonPath = path.join(targetDir, folderName, 'package.json');
const data = fs.readFileSync(pkgJsonPath, 'utf-8');
const packageLatestVersion = execSync('npm view @flowgram.ai/core version --tag=latest latest')
.toString()
.trim();
const jsonData = JSON.parse(data);
if (jsonData.dependencies) {
updateFlowGramVersions(jsonData.dependencies, packageLatestVersion);
}
if (jsonData.devDependencies) {
updateFlowGramVersions(jsonData.devDependencies, packageLatestVersion);
}
fs.writeFileSync(pkgJsonPath, JSON.stringify(jsonData, null, 2), 'utf-8');
if (res) {
console.log(chalk.green(`${folderName} Demo project created successfully!`));
console.log(chalk.yellow('Run the following commands to start:'));
console.log(chalk.cyan(` cd ${folderName}`));
console.log(chalk.cyan(' npm install'));
console.log(chalk.cyan(' npm start'));
} else {
console.log(chalk.red('Download failed'));
}
} catch (error) {
console.error('Error downloading repo:', error);
return;
}
};
================================================
FILE: apps/cli/src/find-materials/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import chalk from 'chalk';
import { traverseRecursiveTsFiles } from '../utils/ts-file';
import { Project } from '../utils/project';
import { loadNpm } from '../utils/npm';
import { Material } from '../materials/material';
export async function findUsedMaterials() {
// materialName can be undefined
console.log(chalk.bold('🚀 Welcome to @flowgram.ai form-materials CLI!'));
const project = await Project.getSingleton();
project.printInfo();
const formMaterialPkg = await loadNpm('@flowgram.ai/form-materials');
const materials: Material[] = Material.listAll(formMaterialPkg);
const allUsedMaterials = new Set<Material>();
const exportName2Material = new Map<string, Material>();
for (const material of materials) {
if (!material.indexFile) {
console.warn(`Material ${material.name} not found`);
return;
}
console.log(`👀 The exports of ${material.name} is ${material.allExportNames.join(',')}`);
material.allExportNames.forEach((exportName) => {
exportName2Material.set(exportName, material);
});
}
for (const tsFile of traverseRecursiveTsFiles(project.srcPath)) {
const fileMaterials = new Set<Material>();
let fileImportPrinted = false;
for (const importDeclaration of tsFile.imports) {
if (
!importDeclaration.source.startsWith('@flowgram.ai/form-materials') ||
!importDeclaration.namedImports?.length
) {
continue;
}
if (!fileImportPrinted) {
fileImportPrinted = true;
console.log(chalk.bold(`\n👀 Searching ${tsFile.path}`));
}
console.log(`🔍 ${importDeclaration.statement}`);
if (importDeclaration.namedImports) {
importDeclaration.namedImports.forEach((namedImport) => {
const material = exportName2Material.get(namedImport.imported);
if (material) {
fileMaterials.add(material);
allUsedMaterials.add(material);
console.log(`import ${chalk.bold(material.fullName)} by ${namedImport.imported}`);
}
});
}
}
}
console.log(chalk.bold('\n📦 All used materials:'));
console.log([...allUsedMaterials].map((_material) => _material.fullName).join(','));
}
================================================
FILE: apps/cli/src/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import { Command } from 'commander';
import { updateFlowgramVersion } from './update-version';
import { syncMaterial } from './materials';
import { findUsedMaterials } from './find-materials';
import { createApp } from './create-app';
const program = new Command();
program.name('flowgram-cli').version('1.0.0').description('Flowgram CLI');
program
.command('create-app')
.description('Create a new flowgram project')
.argument('[string]', 'Project name')
.action(async (projectName) => {
await createApp(projectName);
});
program
.command('materials')
.description('Sync materials to the project')
.argument(
'[string]',
'Material name or names\nExample 1: components/variable-selector \nExample2: components/variable-selector,effect/provideJsonSchemaOutputs'
)
.option('--refresh-project-imports', 'Refresh project imports to copied materials', false)
.option('--target-material-root-dir <string>', 'Target directory to copy materials')
.option('--select-multiple', 'Select multiple materials', false)
.action(async (materialName, options) => {
await syncMaterial({
materialName,
refreshProjectImports: options.refreshProjectImports,
targetMaterialRootDir: options.targetMaterialRootDir
? path.join(process.cwd(), options.targetMaterialRootDir)
: undefined,
selectMultiple: options.selectMultiple,
});
});
program
.command('find-used-materials')
.description('Find used materials in the project')
.action(async () => {
await findUsedMaterials();
});
program
.command('update-version')
.description('Update flowgram version in the project')
.argument('[string]', 'Flowgram version')
.action(async (version) => {
await updateFlowgramVersion(version);
});
program.parse(process.argv);
================================================
FILE: apps/cli/src/materials/copy.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import fs from 'fs';
import { traverseRecursiveTsFiles } from '../utils/ts-file';
import { SyncMaterialContext } from './types';
interface CopyMaterialReturn {
packagesToInstall: string[];
}
export const copyMaterials = (ctx: SyncMaterialContext): CopyMaterialReturn => {
const { selectedMaterials, project, formMaterialPkg, targetFormMaterialRoot } = ctx;
const formMaterialDependencies = formMaterialPkg.dependencies;
const packagesToInstall: Set<string> = new Set();
for (const material of selectedMaterials) {
const sourceDir: string = material.sourceDir;
const targetDir: string = path.join(targetFormMaterialRoot, material.type, material.name);
fs.cpSync(sourceDir, targetDir, { recursive: true });
for (const file of traverseRecursiveTsFiles(targetDir)) {
for (const importDeclaration of file.imports) {
const { source } = importDeclaration;
if (source.startsWith('@/')) {
// is inner import
console.log(`Replace Import from ${source} to @flowgram.ai/form-materials`);
file.replaceImport(
[importDeclaration],
[{ ...importDeclaration, source: '@flowgram.ai/form-materials' }]
);
packagesToInstall.add(`@flowgram.ai/form-materials@${project.flowgramVersion}`);
} else if (!source.startsWith('.') && !source.startsWith('react')) {
// check if is in form material dependencies
const [dep, version] =
Object.entries(formMaterialDependencies).find(([_key]) => source.startsWith(_key)) ||
[];
if (!dep) {
continue;
}
if (dep.startsWith('@flowgram.ai/')) {
packagesToInstall.add(`${dep}@${project.flowgramVersion}`);
} else {
packagesToInstall.add(`${dep}@${version}`);
}
}
}
}
}
return {
packagesToInstall: [...packagesToInstall],
};
};
================================================
FILE: apps/cli/src/materials/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import chalk from 'chalk';
import { Project } from '../utils/project';
import { loadNpm } from '../utils/npm';
import { MaterialCliOptions, SyncMaterialContext } from './types';
import { getSelectedMaterials } from './select';
import { executeRefreshProjectImport } from './refresh-project-import';
import { Material } from './material';
import { copyMaterials } from './copy';
export async function syncMaterial(cliOpts: MaterialCliOptions) {
const { refreshProjectImports, targetMaterialRootDir } = cliOpts;
// materialName can be undefined
console.log(chalk.bold('🚀 Welcome to @flowgram.ai form-materials CLI!'));
const project = await Project.getSingleton();
project.printInfo();
// where to place all material in target project
const targetFormMaterialRoot =
targetMaterialRootDir || path.join(project.projectPath, 'src', 'form-materials');
console.log(chalk.black(` - Target material root: ${targetFormMaterialRoot}`));
if (!project.flowgramVersion) {
throw new Error(
chalk.red(
'❌ Please install @flowgram.ai/fixed-layout-editor or @flowgram.ai/free-layout-editor'
)
);
}
const formMaterialPkg = await loadNpm('@flowgram.ai/form-materials');
let selectedMaterials: Material[] = await getSelectedMaterials(cliOpts, formMaterialPkg);
// Ensure material is defined before proceeding
if (!selectedMaterials.length) {
console.error(chalk.red('No material selected. Exiting.'));
process.exit(1);
}
const context: SyncMaterialContext = {
selectedMaterials: selectedMaterials,
project,
formMaterialPkg,
cliOpts,
targetFormMaterialRoot,
};
// Copy the materials to the project
console.log(chalk.bold('🚀 The following materials will be added to your project'));
console.log(selectedMaterials.map((material) => `📦 ${material.fullName}`).join('\n'));
console.log('\n');
let { packagesToInstall } = copyMaterials(context);
// Refresh project imports
if (refreshProjectImports) {
console.log(chalk.bold('🚀 Refresh imports in your project'));
executeRefreshProjectImport(context);
}
// Install the dependencies
await project.addDependencies(packagesToInstall);
console.log(chalk.bold('\n✅ These npm dependencies is added to your package.json'));
packagesToInstall.forEach((_package) => {
console.log(`- ${_package}`);
});
console.log(chalk.bold(chalk.bold('\n➡️ Please run npm install to install dependencies\n')));
}
================================================
FILE: apps/cli/src/materials/material.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import { readdirSync } from 'fs';
import { getIndexTsFile } from '../utils/ts-file';
import { LoadedNpmPkg } from '../utils/npm';
export class Material {
protected static _all_materials_cache: Material[] = [];
static ALL_TYPES = [
'components',
'effects',
'plugins',
'shared',
'validate',
'form-plugins',
'hooks',
];
constructor(public type: string, public name: string, public formMaterialPkg: LoadedNpmPkg) {}
get fullName() {
return `${this.type}/${this.name}`;
}
get sourceDir() {
return path.join(this.formMaterialPkg.srcPath, this.type, this.name);
}
get indexFile() {
return getIndexTsFile(this.sourceDir);
}
get allExportNames() {
return this.indexFile?.allExportNames || [];
}
static listAll(formMaterialPkg: LoadedNpmPkg): Material[] {
if (!this._all_materials_cache.length) {
this._all_materials_cache = Material.ALL_TYPES.map((type) => {
const materialsPath: string = path.join(formMaterialPkg.srcPath, type);
return readdirSync(materialsPath)
.map((_path: string) => {
if (_path === 'index.ts') {
return null;
}
return new Material(type, _path, formMaterialPkg);
})
.filter((material): material is Material => material !== null);
}).flat();
}
return this._all_materials_cache;
}
}
================================================
FILE: apps/cli/src/materials/refresh-project-import.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import chalk from 'chalk';
import { traverseRecursiveTsFiles } from '../utils/ts-file';
import { ImportDeclaration, NamedImport } from '../utils/import';
import { SyncMaterialContext } from './types';
import { Material } from './material';
export function executeRefreshProjectImport(context: SyncMaterialContext) {
const { selectedMaterials, project, targetFormMaterialRoot } = context;
const exportName2Material = new Map<string, Material>();
const targetModule = `@/${path.relative(project.srcPath, targetFormMaterialRoot)}`;
for (const material of selectedMaterials) {
if (!material.indexFile) {
console.warn(`Material ${material.name} not found`);
return;
}
console.log(`👀 The exports of ${material.name} is ${material.allExportNames.join(',')}`);
material.allExportNames.forEach((exportName) => {
exportName2Material.set(exportName, material);
});
}
for (const tsFile of traverseRecursiveTsFiles(project.srcPath)) {
for (const importDeclaration of tsFile.imports) {
if (importDeclaration.source.startsWith('@flowgram.ai/form-materials')) {
// Import Module and its related named Imported
const restImports: NamedImport[] = [];
const importMap: Record<string, NamedImport[]> = {};
if (!importDeclaration.namedImports) {
continue;
}
for (const nameImport of importDeclaration.namedImports) {
const material = exportName2Material.get(nameImport.imported);
if (material) {
const importModule = `${targetModule}/${material.fullName}`;
importMap[importModule] = importMap[importModule] || [];
importMap[importModule].push(nameImport);
} else {
restImports.push(nameImport);
}
}
if (Object.keys(importMap).length === 0) {
continue;
}
const nextImports: ImportDeclaration[] = Object.entries(importMap).map(
([importModule, namedImports]) => ({
...importDeclaration,
namedImports,
source: importModule,
})
);
if (restImports?.length) {
nextImports.unshift({
...importDeclaration,
namedImports: restImports,
});
}
tsFile.replaceImport([importDeclaration], nextImports);
console.log(chalk.green(`🔄 Refresh Imports In: ${tsFile.path}`));
console.log(
`From:\n${importDeclaration.statement}\nTo:\n${nextImports
.map((item) => item.statement)
.join('\n')}`
);
}
}
}
}
================================================
FILE: apps/cli/src/materials/select.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import inquirer from 'inquirer';
import chalk from 'chalk';
import { LoadedNpmPkg } from '../utils/npm';
import { MaterialCliOptions } from './types';
import { Material } from './material';
export const getSelectedMaterials = async (
cliOpts: MaterialCliOptions,
formMaterialPkg: LoadedNpmPkg
) => {
const { materialName, selectMultiple } = cliOpts;
const materials: Material[] = Material.listAll(formMaterialPkg);
let selectedMaterials: Material[] = [];
// 1. Check if materialName is provided and exists in materials
if (materialName) {
selectedMaterials = materialName
.split(',')
.map((_name) => materials.find((_m) => _m.fullName === _name.trim())!)
.filter(Boolean);
}
// 2. If material not found or materialName not provided, prompt user to select
if (!selectedMaterials.length) {
console.log(chalk.yellow(`Material "${materialName}" not found. Please select from the list:`));
const choices = materials.map((_material) => ({
name: _material.fullName,
value: _material,
}));
if (selectMultiple) {
// User select one component
const result = await inquirer.prompt<{
material: Material[]; // Specify type for prompt result
}>([
{
type: 'checkbox',
name: 'material',
message: 'Select multiple materials to add:',
choices: choices,
},
]);
selectedMaterials = result.material;
} else {
// User select one component
const result = await inquirer.prompt<{
material: Material; // Specify type for prompt result
}>([
{
type: 'list',
name: 'material',
message: 'Select one material to add:',
choices: choices,
},
]);
selectedMaterials = [result.material];
}
}
return selectedMaterials;
};
================================================
FILE: apps/cli/src/materials/types.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { Project } from '../utils/project';
import { LoadedNpmPkg } from '../utils/npm';
import { Material } from './material';
export interface MaterialCliOptions {
materialName?: string;
refreshProjectImports?: boolean;
targetMaterialRootDir?: string;
selectMultiple?: boolean;
}
export interface SyncMaterialContext {
selectedMaterials: Material[];
project: Project;
formMaterialPkg: LoadedNpmPkg;
cliOpts: MaterialCliOptions;
targetFormMaterialRoot: string;
}
================================================
FILE: apps/cli/src/update-version/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import chalk from 'chalk';
import { getLatestVersion } from '../utils/npm';
import { traverseRecursiveFiles } from '../utils/file';
export async function updateFlowgramVersion(inputVersion?: string) {
console.log(chalk.bold('🚀 Welcome to @flowgram.ai update-version helper'));
// Get latest version
const latestVersion = await getLatestVersion('@flowgram.ai/editor');
const currentPath = process.cwd();
console.log('- Latest flowgram version: ', latestVersion);
console.log('- Current Path: ', currentPath);
// User Input flowgram version, default is latestVersion
const flowgramVersion: string = inputVersion || latestVersion;
for (const file of traverseRecursiveFiles(currentPath)) {
if (file.path.endsWith('package.json')) {
console.log('👀 Find package.json: ', file.path);
let updated = false;
const json = JSON.parse(file.content);
if (json.dependencies) {
for (const key in json.dependencies) {
if (key.startsWith('@flowgram.ai/')) {
updated = true;
json.dependencies[key] = flowgramVersion;
console.log(`- Update ${key} to ${flowgramVersion}`);
}
}
}
if (json.devDependencies) {
for (const key in json.devDependencies) {
if (key.startsWith('@flowgram.ai/')) {
updated = true;
json.devDependencies[key] = flowgramVersion;
console.log(`- Update ${key} to ${flowgramVersion}`);
}
}
}
if (updated) {
file.write(JSON.stringify(json, null, 2));
console.log(`✅ ${file.path} Updated`);
}
}
}
}
================================================
FILE: apps/cli/src/utils/export.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
export function extractNamedExports(content: string) {
const valueExports = [];
const typeExports = [];
// Collect all type definition names
const typeDefinitions = new Set();
const typePatterns = [/\b(?:type|interface)\s+(\w+)/g, /\bexport\s+(?:type|interface)\s+(\w+)/g];
let match;
for (const pattern of typePatterns) {
while ((match = pattern.exec(content)) !== null) {
typeDefinitions.add(match[1]);
}
}
// Match various export patterns
const exportPatterns = [
// export const/var/let/function/class/type/interface
/\bexport\s+(const|var|let|function|class|type|interface)\s+(\w+)/g,
// export { name1, name2 }
/\bexport\s*\{([^}]+)\}/g,
// export { name as alias }
/\bexport\s*\{[^}]*\b(\w+)\s+as\s+(\w+)[^}]*\}/g,
// export default function name()
/\bexport\s+default\s+(?:function|class)\s+(\w+)/g,
// export type { Type1, Type2 }
/\bexport\s+type\s*\{([^}]+)\}/g,
// export type { Original as Alias }
/\bexport\s+type\s*\{[^}]*\b(\w+)\s+as\s+(\w+)[^}]*\}/g,
];
// Handle first pattern: export const/var/let/function/class/type/interface
exportPatterns[0].lastIndex = 0;
while ((match = exportPatterns[0].exec(content)) !== null) {
const [, kind, name] = match;
if (kind === 'type' || kind === 'interface' || typeDefinitions.has(name)) {
typeExports.push(name);
} else {
valueExports.push(name);
}
}
// Handle second pattern: export { name1, name2 }
exportPatterns[1].lastIndex = 0;
while ((match = exportPatterns[1].exec(content)) !== null) {
const exportsList = match[1]
.split(',')
.map((item) => item.trim())
.filter((item) => item && !item.includes(' as '));
for (const name of exportsList) {
if (name.startsWith('type ')) {
typeExports.push(name.replace('type ', '').trim());
} else if (typeDefinitions.has(name)) {
typeExports.push(name);
} else {
valueExports.push(name);
}
}
}
// Handle third pattern: export { name as alias }
exportPatterns[2].lastIndex = 0;
while ((match = exportPatterns[2].exec(content)) !== null) {
const [, original, alias] = match;
if (typeDefinitions.has(original)) {
typeExports.push(alias);
} else {
valueExports.push(alias);
}
}
// Handle fourth pattern: export default function name()
exportPatterns[3].lastIndex = 0;
while ((match = exportPatterns[3].exec(content)) !== null) {
const name = match[1];
if (typeDefinitions.has(name)) {
typeExports.push(name);
} else {
valueExports.push(name);
}
}
// Handle fifth pattern: export type { Type1, Type2 }
exportPatterns[4].lastIndex = 0;
while ((match = exportPatterns[4].exec(content)) !== null) {
const exportsList = match[1]
.split(',')
.map((item) => item.trim())
.filter((item) => item && !item.includes(' as '));
for (const name of exportsList) {
typeExports.push(name);
}
}
// Handle sixth pattern: export type { Original as Alias }
exportPatterns[5].lastIndex = 0;
while ((match = exportPatterns[5].exec(content)) !== null) {
const [, original, alias] = match;
typeExports.push(alias);
}
// Deduplicate and sort
return {
values: [...new Set(valueExports)].sort(),
types: [...new Set(typeExports)].sort(),
};
}
================================================
FILE: apps/cli/src/utils/file.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import fs from 'fs';
import ignore, { Ignore } from 'ignore';
export class File {
content: string;
isUtf8: boolean;
relativePath: string;
path: string;
suffix: string;
constructor(filePath: string, public root: string = '/') {
this.path = filePath;
this.relativePath = path.relative(this.root, this.path);
this.suffix = path.extname(this.path);
// Check if exists
if (!fs.existsSync(this.path)) {
throw Error(`File ${path} Not Exists`);
}
// If no utf-8, skip
try {
this.content = fs.readFileSync(this.path, 'utf-8');
this.isUtf8 = true;
} catch (e) {
this.isUtf8 = false;
return;
}
}
replace(updater: (content: string) => string) {
if (!this.isUtf8) {
console.warn('Not UTF-8 file skipped: ', this.path);
return;
}
this.content = updater(this.content);
fs.writeFileSync(this.path, this.content, 'utf-8');
}
write(nextContent: string) {
this.content = nextContent;
fs.writeFileSync(this.path, this.content, 'utf-8');
}
}
export function* traverseRecursiveFilePaths(
folder: string,
ig: Ignore = ignore().add('.git'),
root: string = folder
): Generator<string> {
const files = fs.readdirSync(folder);
// add .gitignore to ignore if exists
if (fs.existsSync(path.join(folder, '.gitignore'))) {
ig.add(fs.readFileSync(path.join(folder, '.gitignore'), 'utf-8'));
}
for (const file of files) {
const filePath = path.join(folder, file);
if (ig.ignores(path.relative(root, filePath))) {
continue;
}
if (fs.statSync(filePath).isDirectory()) {
yield* traverseRecursiveFilePaths(filePath, ig, root);
} else {
yield filePath;
}
}
}
export function* traverseRecursiveFiles(folder: string): Generator<File> {
for (const filePath of traverseRecursiveFilePaths(folder)) {
yield new File(filePath, folder);
}
}
================================================
FILE: apps/cli/src/utils/import.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
export interface NamedImport {
local?: string;
imported: string;
typeOnly?: boolean;
}
/**
* Cases
* import { A, B } from 'module';
* import A from 'module';
* import * as C from 'module';
* import D, { type E, F } from 'module';
* import A, { B as B1 } from 'module';
*/
export interface ImportDeclaration {
// origin statement
statement: string;
// import { A, B } from 'module';
namedImports?: NamedImport[];
// import A from 'module';
defaultImport?: string;
// import * as C from 'module';
namespaceImport?: string;
source: string;
}
export function assembleImport(declaration: ImportDeclaration): string {
const { namedImports, defaultImport, namespaceImport, source } = declaration;
const importClauses = [];
if (namedImports) {
importClauses.push(
`{ ${namedImports
.map(
({ local, imported, typeOnly }) =>
`${typeOnly ? 'type ' : ''}${imported}${local ? ` as ${local}` : ''}`
)
.join(', ')} }`
);
}
if (defaultImport) {
importClauses.push(defaultImport);
}
if (namespaceImport) {
importClauses.push(`* as ${namespaceImport}`);
}
return `import ${importClauses.join(', ')} from '${source}';`;
}
export function replaceImport(
fileContent: string,
origin: ImportDeclaration,
replaceTo: ImportDeclaration[]
): string {
const replaceImportStatements = replaceTo.map(assembleImport);
// replace origin statement
return fileContent.replace(origin.statement, replaceImportStatements.join('\n'));
}
export function* traverseFileImports(fileContent: string): Generator<ImportDeclaration> {
// 匹配所有 import 语句的正则表达式
const importRegex =
/import\s+([^{}*,]*?)?(?:\s*\*\s*as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,?)?(?:\s*\{([^}]*)\}\s*,?)?(?:\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,?)?\s*from\s*['"`]([^'"`]+)['"`]\;?/g;
let match;
while ((match = importRegex.exec(fileContent)) !== null) {
const [fullMatch, defaultPart, namespacePart, namedPart, defaultPart2, source] = match;
const declaration: ImportDeclaration = {
statement: fullMatch,
source: source,
};
// 处理默认导入
const defaultImport = defaultPart?.trim() || defaultPart2?.trim();
if (defaultImport && !namespacePart && !namedPart) {
declaration.defaultImport = defaultImport;
} else if (defaultImport && (namespacePart || namedPart)) {
declaration.defaultImport = defaultImport;
}
// 处理命名空间导入 (* as)
if (namespacePart) {
declaration.namespaceImport = namespacePart.trim();
}
// 处理命名导入
if (namedPart) {
const namedImports = [];
const namedItems = namedPart
.split(',')
.map((item) => item.trim())
.filter(Boolean);
for (const item of namedItems) {
const typeOnly = item.startsWith('type ');
const cleanItem = typeOnly ? item.slice(5).trim() : item;
if (cleanItem.includes(' as ')) {
const [imported, local] = cleanItem.split(' as ').map((s) => s.trim());
namedImports.push({
imported,
local,
typeOnly,
});
} else {
namedImports.push({
imported: cleanItem,
typeOnly,
});
}
}
if (namedImports.length > 0) {
declaration.namedImports = namedImports;
}
}
yield declaration;
}
}
================================================
FILE: apps/cli/src/utils/npm.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import https from 'https';
import { existsSync, readFileSync } from 'fs';
import { execSync } from 'child_process';
import * as tar from 'tar';
import fs from 'fs-extra';
export class LoadedNpmPkg {
constructor(public name: string, public version: string, public path: string) {}
get srcPath() {
return path.join(this.path, 'src');
}
get distPath() {
return path.join(this.path, 'dist');
}
protected _packageJson: Record<string, any>;
get packageJson() {
if (!this._packageJson) {
this._packageJson = JSON.parse(readFileSync(path.join(this.path, 'package.json'), 'utf8'));
}
return this._packageJson;
}
get dependencies(): Record<string, string> {
return this.packageJson.dependencies;
}
}
// 使用 https 下载文件
function downloadFile(url: string, dest: string): Promise<void> {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
https
.get(url, (response) => {
if (response.statusCode !== 200) {
reject(new Error(`Download failed: ${response.statusCode}`));
return;
}
response.pipe(file);
file.on('finish', () => {
file.close();
resolve();
});
})
.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
file.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
});
}
export async function getLatestVersion(packageName: string): Promise<string> {
return execSync(`npm view ${packageName} version --tag=latest`).toString().trim();
}
export async function loadNpm(packageName: string): Promise<LoadedNpmPkg> {
const packageLatestVersion = await getLatestVersion(packageName);
const packagePath = path.join(__dirname, `./.download/${packageName}-${packageLatestVersion}`);
if (existsSync(packagePath)) {
return new LoadedNpmPkg(packageName, packageLatestVersion, packagePath);
}
try {
// 获取 tarball 地址
const tarballUrl = execSync(`npm view ${packageName}@${packageLatestVersion} dist.tarball`)
.toString()
.trim();
// 临时 tarball 路径
const tempTarballPath = path.join(
__dirname,
`./.download/${packageName}-${packageLatestVersion}.tgz`
);
// 确保目录存在
fs.ensureDirSync(path.dirname(tempTarballPath));
// 下载 tarball
await downloadFile(tarballUrl, tempTarballPath);
fs.ensureDirSync(packagePath);
// 解压到目标目录
await tar.x({
file: tempTarballPath,
cwd: packagePath,
strip: 1,
});
// 删除临时文件
fs.unlinkSync(tempTarballPath);
return new LoadedNpmPkg(packageName, packageLatestVersion, packagePath);
} catch (error) {
console.error(`Error downloading or extracting package`);
console.error(error);
throw error;
}
}
================================================
FILE: apps/cli/src/utils/project.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import chalk from 'chalk';
import { getLatestVersion } from './npm';
interface PackageJson {
dependencies: { [key: string]: string };
devDependencies?: { [key: string]: string };
peerDependencies?: { [key: string]: string };
[key: string]: any;
}
export class Project {
flowgramVersion?: string;
projectPath: string;
packageJsonPath: string;
packageJson: PackageJson;
srcPath: string;
protected constructor() {}
async init() {
// get nearest package.json
let projectPath: string = process.cwd();
while (projectPath !== '/' && !existsSync(path.join(projectPath, 'package.json'))) {
projectPath = path.join(projectPath, '..');
}
if (projectPath === '/') {
throw new Error('Please run this command in a valid project');
}
this.projectPath = projectPath;
this.srcPath = path.join(projectPath, 'src');
this.packageJsonPath = path.join(projectPath, 'package.json');
this.packageJson = JSON.parse(readFileSync(this.packageJsonPath, 'utf8'));
this.flowgramVersion =
this.packageJson.dependencies['@flowgram.ai/fixed-layout-editor'] ||
this.packageJson.dependencies['@flowgram.ai/free-layout-editor'] ||
this.packageJson.dependencies['@flowgram.ai/editor'];
}
async addDependency(dependency: string) {
let name: string;
let version: string;
// 处理作用域包(如 @types/react@1.0.0)
const lastAtIndex = dependency.lastIndexOf('@');
if (lastAtIndex <= 0) {
// 没有@符号 或者@在开头(如 @types/react)
name = dependency;
version = await getLatestVersion(name);
} else {
// 正常分割包名和版本
name = dependency.substring(0, lastAtIndex);
version = dependency.substring(lastAtIndex + 1);
// 如果版本部分为空,获取最新版本
if (!version.trim()) {
version = await getLatestVersion(name);
}
}
this.packageJson.dependencies[name] = version;
writeFileSync(this.packageJsonPath, JSON.stringify(this.packageJson, null, 2));
}
async addDependencies(dependencies: string[]) {
for (const dependency of dependencies) {
await this.addDependency(dependency);
}
}
writeToPackageJsonFile() {
writeFileSync(this.packageJsonPath, JSON.stringify(this.packageJson, null, 2));
}
printInfo() {
console.log(chalk.bold('Project Info:'));
console.log(chalk.black(` - Flowgram Version: ${this.flowgramVersion}`));
console.log(chalk.black(` - Project Path: ${this.projectPath}`));
}
static async getSingleton() {
const info = new Project();
await info.init();
return info;
}
}
================================================
FILE: apps/cli/src/utils/ts-file.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path, { join } from 'path';
import fs from 'fs';
import { assembleImport, ImportDeclaration, traverseFileImports } from './import';
import { File, traverseRecursiveFilePaths } from './file';
import { extractNamedExports } from './export';
class TsFile extends File {
exports: {
values: string[];
types: string[];
} = {
values: [],
types: [],
};
imports: ImportDeclaration[] = [];
get allExportNames() {
return [...this.exports.values, ...this.exports.types];
}
constructor(filePath: string, root?: string) {
super(filePath, root);
this.exports = extractNamedExports(fs.readFileSync(filePath, 'utf-8'));
this.imports = Array.from(traverseFileImports(fs.readFileSync(filePath, 'utf-8')));
}
addImport(importDeclarations: ImportDeclaration[]) {
importDeclarations.forEach((importDeclaration) => {
importDeclaration.statement = assembleImport(importDeclaration);
});
// add in last import statement
this.replace((content) => {
const lastImportStatement = this.imports[this.imports.length - 1];
return content.replace(
lastImportStatement.statement,
`${lastImportStatement?.statement}\n${importDeclarations.map((item) => item.statement)}\n`
);
});
this.imports.push(...importDeclarations);
}
removeImport(importDeclarations: ImportDeclaration[]) {
this.replace((content) =>
importDeclarations.reduce((prev, cur) => prev.replace(cur.statement, ''), content)
);
this.imports = this.imports.filter((item) => !importDeclarations.includes(item));
}
replaceImport(oldImports: ImportDeclaration[], newImports: ImportDeclaration[]) {
newImports.forEach((importDeclaration) => {
importDeclaration.statement = assembleImport(importDeclaration);
});
this.replace((content) => {
oldImports.forEach((oldImport, idx) => {
const replaceTo = newImports[idx];
if (replaceTo) {
content = content.replace(oldImport.statement, replaceTo.statement);
this.imports.map((_import) => {
if (_import.statement === oldImport.statement) {
_import = replaceTo;
}
});
} else {
content = content.replace(oldImport.statement, '');
this.imports = this.imports.filter(
(_import) => _import.statement !== oldImport.statement
);
}
});
const restNewImports = newImports.slice(oldImports.length);
if (restNewImports.length > 0) {
const lastImportStatement = newImports[oldImports.length - 1].statement;
content = content.replace(
lastImportStatement,
`${lastImportStatement}
${restNewImports.map((item) => item.statement).join('\n')}
`
);
}
this.imports.push(...restNewImports);
return content;
});
}
}
export function* traverseRecursiveTsFiles(folder: string): Generator<TsFile> {
for (const filePath of traverseRecursiveFilePaths(folder)) {
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
yield new TsFile(filePath, folder);
}
}
}
export function getIndexTsFile(folder: string): TsFile | undefined {
// ts or tsx
const files = fs.readdirSync(folder);
for (const file of files) {
if (file === 'index.ts' || file === 'index.tsx') {
return new TsFile(path.join(folder, file), folder);
}
}
return undefined;
}
================================================
FILE: apps/cli/tsconfig.json
================================================
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "es2020",
"module": "esnext",
"strictPropertyInitialization": false,
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"skipLibCheck": true,
"noUnusedLocals": true,
"noImplicitAny": true,
"allowJs": true,
"resolveJsonModule": true,
"types": ["node"],
"jsx": "react-jsx",
"lib": ["es6", "dom", "es2020", "es2019.Array"]
},
"include": ["./src"],
}
================================================
FILE: apps/cli/tsup.config.js
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { defineConfig } from "tsup";
export default defineConfig({
shims: true,
})
================================================
FILE: apps/create-app/bin/index.js
================================================
#!/usr/bin/env node
import '../dist/index.js';
================================================
FILE: apps/create-app/eslint.config.js
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { defineFlatConfig } from '@flowgram.ai/eslint-config';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default defineFlatConfig({
preset: 'node',
packageRoot: __dirname,
ignore: [
'**/*.d.ts',
'**/__mocks__',
'**/node_modules',
'**/build',
'**/dist',
'**/es',
'**/lib',
'**/.codebase',
'**/.changeset',
'**/config',
'**/common/scripts',
'**/output',
'error-log-str.js',
'*.bundle.js',
'*.min.js',
'*.js.map',
'**/*.log',
'**/tsconfig.tsbuildinfo',
'**/vitest.config.ts',
'package.json',
'*.json',
],
rules: {
'no-console': 'off',
'import/prefer-default-export': 'off',
'lines-between-class-members': 'warn',
'no-unused-vars': 'off',
'no-redeclare': 'off',
'no-empty-function': 'off',
'prefer-destructuring': 'off',
'no-underscore-dangle': 'off',
'no-multi-assign': 'off',
'arrow-body-style': 'warn',
'no-useless-constructor': 'off',
'no-param-reassign': 'off',
'max-classes-per-file': 'off',
'grouped-accessor-pairs': 'off',
'no-plusplus': 'off',
'no-restricted-syntax': 'off',
'import/extensions': 'off',
'consistent-return': 'off',
'no-use-before-define': 'off',
'no-bitwise': 'off',
'no-case-declarations': 'off',
'no-dupe-class-members': 'off',
'class-methods-use-this': 'off',
'default-param-last': 'off',
},
});
================================================
FILE: apps/create-app/package.json
================================================
{
"name": "@flowgram.ai/create-app",
"version": "0.1.8",
"description": "A CLI tool to create demo projects",
"bin": {
"create-app": "./bin/index.js"
},
"type": "module",
"files": [
"bin",
"src",
"dist"
],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts --out-dir dist",
"start": "node bin/index.js",
"lint": "eslint ./src --cache",
"lint:fix": "eslint ./src --fix"
},
"dependencies": {
"fs-extra": "^9.1.0",
"commander": "^11.0.0",
"chalk": "^5.3.0",
"tar": "7.4.3",
"inquirer": "^12.9.4"
},
"devDependencies": {
"@flowgram.ai/eslint-config": "workspace:*",
"@types/fs-extra": "11.0.4",
"@types/node": "^18",
"@types/inquirer": "^9.0.9",
"tsup": "^8.0.1",
"eslint": "^9.0.0",
"@typescript-eslint/parser": "^8.0.0",
"typescript": "^5.8.3"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}
}
================================================
FILE: apps/create-app/src/index.ts
================================================
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import https from 'https';
import http from 'http';
import { execSync } from 'child_process';
import * as tar from 'tar';
import inquirer from 'inquirer';
import fs from 'fs-extra';
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
const args = process.argv.slice(2);
const updateFlowGramVersions = (dependencies: any[], latestVersion: string) => {
for (const packageName in dependencies) {
if (packageName.startsWith('@flowgram.ai')) {
dependencies[packageName] = latestVersion;
}
}
};
// 使用 http/https 下载文件
function downloadFile(url: string, dest: string): Promise<void> {
return new Promise((resolve, reject) => {
const lib = url.startsWith('https') ? https : http;
const file = fs.createWriteStream(dest);
const request = lib.get(url, (response) => {
if (response.statusCode !== 200) {
reject(new Error(`Download failed: ${response.statusCode}`));
return;
}
response.pipe(file);
file.on('finish', () => {
file.close();
resolve();
});
});
request.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
file.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
});
}
const main = async () => {
console.log(chalk.green('Welcome to @flowgram.ai/create-app CLI!123123'));
const latest = execSync('npm view @flowgram.ai/demo-fixed-layout version --tag=latest latest')
.toString()
.trim();
let folderName = '';
if (!args?.length) {
const { repo } = await inquirer.prompt([
{
type: 'list',
name: 'repo',
message: 'Select a demo to create:',
choices: [
{ name: 'Fixed Layout Demo', value: 'demo-fixed-layout' },
{ name: 'Free Layout Demo', value: 'demo-free-layout' },
{ name: 'Fixed Layout Demo Simple', value: 'demo-fixed-layout-simple' },
{ name: 'Free Layout Demo Simple', value: 'demo-free-layout-simple' },
{ name: 'Free Layout Nextjs Demo', value: 'demo-nextjs' },
{ name: 'Free Layout Vite Demo Simple', value: 'demo-vite' },
{ name: 'Demo Playground for infinite canvas', value: 'demo-playground' },
],
},
]);
folderName = repo;
} else {
if (
[
'fixed-layout',
'free-layout',
'fixed-layout-simple',
'free-layout-simple',
'playground',
'nextjs',
].includes(args[0])
) {
folderName = `demo-${args[0]}`;
} else {
console.error('Invalid argument. Please run "npx create-app" to choose demo.');
return;
}
}
try {
const targetDir = path.join(process.cwd());
const downloadPackage = async () => {
try {
const tempTarballPath = path.join(process.cwd(), `${folderName}.tgz`);
const url = `https://registry.npmjs.org/@flowgram.ai/${folderName}/-/${folderName}-${latest}.tgz`;
console.log(chalk.blue(`Downloading ${url} ...`));
await downloadFile(url, tempTarballPath);
fs.ensureDirSync(targetDir);
await tar.x({
file: tempTarballPath,
C: targetDir,
});
fs.renameSync(path.join(targetDir, 'package'), path.join(targetDir, folderName));
fs.unlinkSync(tempTarballPath);
return true;
} catch (error) {
console.error(`Error downloading or extracting package`);
console.error(error);
return false;
}
};
const res = await downloadPackage();
const pkgJsonPath = path.join(targetDir, folderName, 'package.json');
const data = fs.readFileSync(pkgJsonPath, 'utf-8');
const packageLatestVersion = execSync('npm view @flowgram.ai/core version --tag=latest latest')
.toString()
.trim();
const jsonData = JSON.parse(data);
if (jsonData.dependencies) {
updateFlowGramVersions(jsonData.dependencies, packageLatestVersion);
}
if (jsonData.devDependencies) {
updateFlowGramVersions(jsonData.devDependencies, packageLatestVersion);
}
fs.writeFileSync(pkgJsonPath, JSON.stringify(jsonData, null, 2), 'utf-8');
if (res) {
console.log(chalk.green(`${folderName} Demo project created successfully!`));
console.log(chalk.yellow('Run the following commands to start:'));
console.log(chalk.cyan(` cd ${folderName}`));
console.log(chalk.cyan(' npm install'));
console.log(chalk.cyan(' npm start'));
} else {
console.log(chalk.red('Download failed'));
}
} catch (error) {
console.error('Error downloading repo:', error);
return;
}
};
program.version('1.0.0').description('Create a demo project');
program.parse(process.argv);
main();
================================================
FILE: apps/create-app/tsconfig.json
================================================
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "es2020",
"module": "esnext",
"strictPropertyInitialization": false,
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"skipLibCheck": true,
"noUnusedLocals": true,
"noImplicitAny": true,
"allowJs": true,
"resolveJsonModule": true,
"types": ["node"],
"jsx": "react-jsx",
"lib": ["es6", "dom", "es2020", "es2019.Array"]
},
"include": ["./src"],
}
================================================
FILE: apps/demo-fixed-layout/README.md
================================================
# FlowGram.AI - Demo Fixed Layout
Best practices demo for fixed layout
## Installation
```shell
npx @flowgram.ai/create-app@latest fixed-layout
```
## Project Overview
### Core Tech Stack
- Frontend Framework: React 18 + TypeScript
- Build Tool: Rsbuild (a modern build tool based on Rspack)
- Styling: Less + Styled Components + CSS Variables
- UI Component Library: Semi Design (@douyinfe/semi-ui)
- State Management: Editor framework developed in-house by Flowgram
- Dependency Injection: Inversify
### Core Dependencies
- @flowgram.ai/fixed-layout-editor: Core dependency for the fixed-layout editor
- @flowgram.ai/fixed-semi-materials: Semi Design materials library
- @flowgram.ai/form-materials: Form materials library
- @flowgram.ai/group-plugin: Group plugin
- @flowgram.ai/minimap-plugin: Minimap plugin
- @flowgram.ai/export-plugin: Download/export plugin
## Code Overview
```
src/
├── app.tsx # Application entry component
├── editor.tsx # Main editor component
├── index.ts # Module export entry
├── initial-data.ts # Initial data configuration
├── type.d.ts # Global type declarations
│
├── assets/ # Static assets
│ ├── icon-mouse.tsx # Mouse icon component
│ └── icon-pad.tsx # Trackpad icon component
│
├── components/ # Common components library
│ ├── index.ts # Components export entry
│ ├── node-list.tsx # Node list component
│ │
│ ├── agent-adder/ # Agent adder component
│ │ └── index.tsx
│ ├── agent-label/ # Agent label component
│ │ └── index.tsx
│ ├── base-node/ # Base node component
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── branch-adder/ # Branch adder component
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── drag-node/ # Draggable node component
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── node-adder/ # Node adder component
│ │ ├── index.tsx
│ │ ├── styles.tsx
│ │ └── utils.ts
│ ├── selector-box-popover/ # Selection box popover component
│ │ └── index.tsx
│ ├── sidebar/ # Sidebar components
│ │ ├── index.tsx
│ │ ├── sidebar-node-renderer.tsx
│ │ ├── sidebar-provider.tsx
│ │ └── sidebar-renderer.tsx
│ └── tools/ # Toolbar components
│ ├── index.tsx
│ ├── styles.tsx
│ ├── fit-view.tsx # Fit view tool
│ ├── minimap-switch.tsx # Minimap toggle
│ ├── minimap.tsx # Minimap component
│ ├── readonly.tsx # Readonly mode toggle
│ ├── run.tsx # Run tool
│ ├── save.tsx # Save tool
│ ├── switch-vertical.tsx # Vertical layout toggle
│ └── zoom-select.tsx # Zoom selector
│
├── context/ # React Context state management
│ ├── index.ts # Context export entry
│ ├── node-render-context.ts # Node render context
│ └── sidebar-context.ts # Sidebar context
│
├── form-components/ # Form components library
│ ├── index.ts # Export entry for form components
│ ├── feedback.tsx # Feedback component
│ │
│ ├── form-content/ # Form content components
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── form-header/ # Form header components
│ │ ├── index.tsx
│ │ ├── styles.tsx
│ │ ├── title-input.tsx
│ │ └── utils.tsx
│ ├── form-inputs/ # Form input components
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── form-item/ # Form item component
│ │ ├── index.css
│ │ └── index.tsx
│ ├── form-outputs/ # Form output components
│ │ ├── index.tsx
│ │ └── styles.tsx
│ └── properties-edit/ # Property editing components
│ ├── index.tsx
│ ├── property-edit.tsx
│ └── styles.tsx
│
├── hooks/ # Custom React hooks
│ ├── index.ts # Hooks export entry
│ ├── use-editor-props.ts # Hook for editor properties
│ ├── use-is-sidebar.ts # Hook for sidebar state
│ └── use-node-render-context.ts # Hook for node render context
│
├── nodes/ # Flow node definitions
│ ├── index.ts # Node registry
│ ├── default-form-meta.tsx # Default form metadata
│ │
│ ├── agent/ # Agent node type
│ │ ├── index.ts
│ │ ├── agent.ts
│ │ ├── agent-llm.ts
│ │ ├── agent-memory.ts
│ │ ├── agent-tools.ts
│ │ ├── memory.ts
│ │ └── tool.ts
│ ├── break-loop/ # Break loop node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── case/ # Case branch node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── case-default/ # Default case node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── catch-block/ # Exception catch block node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── end/ # End node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── if/ # Conditional node
│ │ └── index.ts
│ ├── if-block/ # Conditional block node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── llm/ # LLM node
│ │ └── index.ts
│ ├── loop/ # Loop node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── start/ # Start node
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── switch/ # Switch branch node
│ │ └── index.ts
│ └── trycatch/ # Try-Catch node
│ ├── index.ts
│ └── form-meta.tsx
│
├── plugins/ # Plugin system
│ ├── index.ts # Plugins export entry
│ │
│ ├── clipboard-plugin/ # Clipboard plugin
│ │ └── create-clipboard-plugin.ts
│ ├── group-plugin/ # Group plugin
│ │ ├── index.ts
│ │ ├── group-box-header.tsx
│ │ ├── group-node.tsx
│ │ ├── group-note.tsx
│ │ ├── group-tools.tsx
│ │ ├── icons/
│ │ │ └── index.tsx
│ │ └── multilang-textarea-editor/ # Multi-language textarea editor
│ │ ├── index.css
│ │ ├── index.tsx
│ │ └── base-textarea.tsx
│ └── variable-panel-plugin/ # Variable panel plugin
│ ├── index.ts
│ ├── variable-panel-layer.tsx
│ ├── variable-panel-plugin.ts
│ └── components/
│ ├── full-variable-list.tsx
│ ├── global-variable-editor.tsx
│ └── variable-panel.tsx
│
├── services/ # Services layer
│ ├── index.ts
│ └── custom-service.ts # Custom service
│
├── shortcuts/ # Shortcuts system
│ ├── index.ts
│ ├── constants.ts # Shortcut constants
│ └── utils.ts # Shortcut utilities
│
└── typings/ # Type definitions
├── index.ts # Types export entry
├── json-schema.ts # JSON Schema types
└── node.ts # Node type definitions
```
## Architecture Design Analysis
### Overall Architecture Pattern
This project adopts a layered architecture combined with modular design:
1. Presentation Layer
- Component layer: responsible for UI rendering and user interactions
- Tools layer: provides editor tool features
2. Business Logic Layer
- Node system: defines the behavior and properties of various flow nodes
- Plugin system: provides extensible functional modules
- Services layer: handles business logic and data operations
3. Data Layer
- Context state management: manages global application state
- Type system: ensures consistency of data structures
### Key Design Patterns
#### 1. Provider Pattern
```typescript
// The main editor component uses multiple nested Providers
<FixedLayoutEditorProvider {...editorProps}>
<SidebarProvider>
<EditorRenderer />
<DemoTools />
<SidebarRenderer />
</SidebarProvider>
</FixedLayoutEditorProvider>
```
Use cases:
- `FixedLayoutEditorProvider`: provides core editor features and state
- `SidebarProvider`: manages sidebar visibility and the selected node
#### 2. Registry Pattern
```typescript
export const FlowNodeRegistries: FlowNodeRegistry[] = [
StartNodeRegistry,
EndNodeRegistry,
SwitchNodeRegistry,
LLMNodeRegistry,
// ... more node types
];
```
Advantages:
- Supports dynamic registration of node types
- Easy to extend with new node types
- Decouples node type definitions
#### 3. Plugin Pattern
```typescript
plugins: () => [
createMinimapPlugin({...}),
createGroupPlugin({...}),
createClipboardPlugin(),
createVariablePanelPlugin({}),
]
```
Plugin system highlights:
- Minimap plugin: provides a canvas minimap
- Group plugin: supports node grouping and management
- Clipboard plugin: enables copy and paste
- Variable panel plugin: provides a UI for variable management
#### 4. Factory Pattern
Widely used in node creation and configuration:
```typescript
getNodeDefaultRegistry(type) {
return {
type,
meta: {
defaultExpanded: true,
},
};
}
```
#### 5. Observer Pattern
Implemented via the history system:
```typescript
history: {
enable: true,
enableChangeNode: true,
onApply: debounce((ctx, opt) => {
console.log('auto save: ', ctx.document.toJSON());
}, 100),
}
```
#### 6. Strategy Pattern
Reflected in the materials system:
```typescript
materials: {
components: {
...defaultFixedSemiMaterials,
[FlowRendererKey.ADDER]: NodeAdder,
[FlowRendererKey.BRANCH_ADDER]: BranchAdder,
// Different render strategies can be swapped by key
}
}
```
### State Management Architecture
#### Context System Design
The project uses multiple dedicated Contexts to manage different domains of state:
1. SidebarContext: manages sidebar state
```typescript
export const SidebarContext = React.createContext<{
visible: boolean;
nodeId?: string;
setNodeId: (node: string | undefined) => void;
}>({ visible: false, setNodeId: () => {} });
```
2. NodeRenderContext: manages state related to node rendering
3. IsSidebarContext: simple boolean state
#### Custom Hooks
- `useEditorProps`: centralizes all editor configuration props
- `useIsSidebar`: determines whether the current environment is the sidebar
- `useNodeRenderContext`: gets the node render context
### Component Architecture
#### Component Layering
1. Base components
- `BaseNode`: base rendering component for all nodes
- `DragNode`: node component in drag state
2. Functional components
- Adders: `NodeAdder`, `BranchAdder`, `AgentAdder`
- Tools: zoom, save, run, and other utilities
3. Container components
- `Sidebar`: sidebar container and its subcomponents
- `Tools`: toolbar container
### Data Flow Architecture
#### Initial Data Structure
The project defines a comp
gitextract_ksplgn6_/ ├── .claude/ │ ├── commands/ │ │ └── add-tests.md │ └── skills/ │ ├── create-node/ │ │ ├── SKILL.md │ │ └── templates/ │ │ ├── README.md │ │ ├── complex-node/ │ │ │ ├── components/ │ │ │ │ └── custom-component.tsx │ │ │ ├── form-meta.tsx │ │ │ ├── index.tsx │ │ │ └── types.tsx │ │ └── simple-node/ │ │ └── index.ts │ ├── material-component-dev/ │ │ └── SKILL.md │ └── material-component-doc/ │ ├── SKILL.md │ └── templates/ │ └── material.mdx ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.md │ │ └── question.md │ └── workflows/ │ ├── ci.yml │ ├── common-pr-checks.yml │ ├── deploy.yml │ ├── e2e.yml │ ├── publish-alpha.yml │ ├── publish-app-to-version.yml │ ├── publish-app.yml │ ├── publish-minor.yml │ ├── publish-to-version.yml │ ├── publish.yml │ └── sync-screenshot.yml ├── .gitignore ├── .vscode/ │ ├── extentions.json │ └── settings.json ├── AGENTS.md ├── CHANGELOG.md ├── CLAUDE.md ├── CNAME ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README_DE.md ├── README_ES.md ├── README_JA.md ├── README_PT.md ├── README_RU.md ├── README_ZH.md ├── apps/ │ ├── cli/ │ │ ├── .gitignore │ │ ├── bin/ │ │ │ └── index.js │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── create-app/ │ │ │ │ └── index.ts │ │ │ ├── find-materials/ │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── materials/ │ │ │ │ ├── copy.ts │ │ │ │ ├── index.ts │ │ │ │ ├── material.ts │ │ │ │ ├── refresh-project-import.ts │ │ │ │ ├── select.ts │ │ │ │ └── types.ts │ │ │ ├── update-version/ │ │ │ │ └── index.ts │ │ │ └── utils/ │ │ │ ├── export.ts │ │ │ ├── file.ts │ │ │ ├── import.ts │ │ │ ├── npm.ts │ │ │ ├── project.ts │ │ │ └── ts-file.ts │ │ ├── tsconfig.json │ │ └── tsup.config.js │ ├── create-app/ │ │ ├── bin/ │ │ │ └── index.js │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── demo-fixed-layout/ │ │ ├── README.md │ │ ├── README.zh_CN.md │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── assets/ │ │ │ │ ├── icon-mouse.tsx │ │ │ │ └── icon-pad.tsx │ │ │ ├── components/ │ │ │ │ ├── agent-adder/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── agent-label/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── base-node/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── branch-adder/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── drag-node/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── node-adder/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ └── utils.ts │ │ │ │ ├── node-list.tsx │ │ │ │ ├── selector-box-popover/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── sidebar/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── sidebar-node-renderer.tsx │ │ │ │ │ └── sidebar-renderer.tsx │ │ │ │ └── tools/ │ │ │ │ ├── download.tsx │ │ │ │ ├── fit-view.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── interactive.tsx │ │ │ │ ├── minimap-switch.tsx │ │ │ │ ├── minimap.tsx │ │ │ │ ├── mouse-pad-selector.less │ │ │ │ ├── mouse-pad-selector.tsx │ │ │ │ ├── readonly.tsx │ │ │ │ ├── run.tsx │ │ │ │ ├── save.tsx │ │ │ │ ├── styles.tsx │ │ │ │ ├── switch-vertical.tsx │ │ │ │ └── zoom-select.tsx │ │ │ ├── context/ │ │ │ │ ├── index.ts │ │ │ │ ├── node-render-context.ts │ │ │ │ └── sidebar-context.ts │ │ │ ├── editor.tsx │ │ │ ├── form-components/ │ │ │ │ ├── feedback.tsx │ │ │ │ ├── form-content/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── form-header/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ ├── title-input.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ ├── form-inputs/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── form-item/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── form-outputs/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── index.ts │ │ │ │ └── properties-edit/ │ │ │ │ ├── index.tsx │ │ │ │ ├── property-edit.tsx │ │ │ │ └── styles.tsx │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ ├── use-editor-props.ts │ │ │ │ ├── use-form-value.ts │ │ │ │ ├── use-is-sidebar.ts │ │ │ │ └── use-node-render-context.ts │ │ │ ├── index.ts │ │ │ ├── initial-data.ts │ │ │ ├── nodes/ │ │ │ │ ├── agent/ │ │ │ │ │ ├── agent-llm.ts │ │ │ │ │ ├── agent-memory.ts │ │ │ │ │ ├── agent-tools.ts │ │ │ │ │ ├── agent.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── memory.ts │ │ │ │ │ └── tool.ts │ │ │ │ ├── break-loop/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── case/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── case-default/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── catch-block/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── default-form-meta.tsx │ │ │ │ ├── end/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── if/ │ │ │ │ │ └── index.ts │ │ │ │ ├── if-block/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── llm/ │ │ │ │ │ └── index.ts │ │ │ │ ├── loop/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── start/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── switch/ │ │ │ │ │ └── index.ts │ │ │ │ └── trycatch/ │ │ │ │ ├── form-meta.tsx │ │ │ │ └── index.ts │ │ │ ├── plugins/ │ │ │ │ ├── clipboard-plugin/ │ │ │ │ │ └── create-clipboard-plugin.ts │ │ │ │ ├── group-plugin/ │ │ │ │ │ ├── group-box-header.tsx │ │ │ │ │ ├── group-node.tsx │ │ │ │ │ ├── group-note.tsx │ │ │ │ │ ├── group-tools.tsx │ │ │ │ │ ├── icons/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── multilang-textarea-editor/ │ │ │ │ │ ├── base-textarea.tsx │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.ts │ │ │ │ └── variable-panel-plugin/ │ │ │ │ ├── components/ │ │ │ │ │ ├── full-variable-list.tsx │ │ │ │ │ ├── global-variable-editor.tsx │ │ │ │ │ ├── index.module.less │ │ │ │ │ └── variable-panel.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── variable-panel-layer.tsx │ │ │ │ └── variable-panel-plugin.ts │ │ │ ├── services/ │ │ │ │ ├── custom-service.ts │ │ │ │ └── index.ts │ │ │ ├── shortcuts/ │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ ├── type.d.ts │ │ │ └── typings/ │ │ │ ├── index.ts │ │ │ ├── json-schema.ts │ │ │ └── node.ts │ │ └── tsconfig.json │ ├── demo-fixed-layout-animation/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── form-render/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── loading-dots/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── node-render/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── thinking-node/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── tools/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── minimap.tsx │ │ │ │ └── update-schema/ │ │ │ │ ├── example-schemas.ts │ │ │ │ ├── example.py │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── fields/ │ │ │ │ ├── content-field/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── thinking-text-field/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── title-field/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── hooks/ │ │ │ │ ├── use-editor-props.tsx │ │ │ │ └── use-node-loading.tsx │ │ │ ├── nodes/ │ │ │ │ ├── condition/ │ │ │ │ │ └── index.ts │ │ │ │ ├── custom/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── thinking/ │ │ │ │ └── index.tsx │ │ │ └── services/ │ │ │ ├── index.ts │ │ │ └── load-schema-service/ │ │ │ ├── index.ts │ │ │ ├── type.ts │ │ │ └── utils.ts │ │ └── tsconfig.json │ ├── demo-fixed-layout-simple/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── base-node.tsx │ │ │ │ ├── branch-adder.tsx │ │ │ │ ├── flow-select.tsx │ │ │ │ ├── minimap.tsx │ │ │ │ ├── node-add-panel.tsx │ │ │ │ ├── node-adder.tsx │ │ │ │ ├── slot-adder.tsx │ │ │ │ └── tools.tsx │ │ │ ├── data/ │ │ │ │ ├── condition.ts │ │ │ │ ├── dynamicSplit.ts │ │ │ │ ├── index.ts │ │ │ │ ├── loop.ts │ │ │ │ ├── mindmap.ts │ │ │ │ ├── multiInputs.ts │ │ │ │ ├── multiOutputs.ts │ │ │ │ ├── slot.ts │ │ │ │ └── tryCatch.ts │ │ │ ├── editor.tsx │ │ │ ├── hooks/ │ │ │ │ ├── use-add-node.tsx │ │ │ │ └── use-editor-props.tsx │ │ │ ├── index.css │ │ │ ├── index.ts │ │ │ ├── initial-data.ts │ │ │ └── node-registries.ts │ │ └── tsconfig.json │ ├── demo-free-layout/ │ │ ├── README.md │ │ ├── README.zh_CN.md │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── assets/ │ │ │ │ ├── icon-auto-layout.tsx │ │ │ │ ├── icon-cancel.tsx │ │ │ │ ├── icon-comment.tsx │ │ │ │ ├── icon-minimap.tsx │ │ │ │ ├── icon-mouse.tsx │ │ │ │ ├── icon-pad.tsx │ │ │ │ ├── icon-success.tsx │ │ │ │ ├── icon-switch-line.tsx │ │ │ │ └── icon-warning.tsx │ │ │ ├── components/ │ │ │ │ ├── add-node/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── use-add-node.ts │ │ │ │ ├── base-node/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── node-wrapper.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ └── utils.ts │ │ │ │ ├── comment/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── blank-area.tsx │ │ │ │ │ │ ├── border-area.tsx │ │ │ │ │ │ ├── container.tsx │ │ │ │ │ │ ├── content-drag-area.tsx │ │ │ │ │ │ ├── drag-area.tsx │ │ │ │ │ │ ├── editor.tsx │ │ │ │ │ │ ├── index.css │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── more-button.tsx │ │ │ │ │ │ ├── render.tsx │ │ │ │ │ │ └── resize-area.tsx │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── use-model.ts │ │ │ │ │ │ ├── use-overflow.ts │ │ │ │ │ │ ├── use-placeholder.ts │ │ │ │ │ │ └── use-size.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── model.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── group/ │ │ │ │ │ ├── color.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── background.tsx │ │ │ │ │ │ ├── color.tsx │ │ │ │ │ │ ├── header.tsx │ │ │ │ │ │ ├── icon-group.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── node-render.tsx │ │ │ │ │ │ ├── tips/ │ │ │ │ │ │ │ ├── global-store.ts │ │ │ │ │ │ │ ├── icon-close.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── is-mac-os.ts │ │ │ │ │ │ │ ├── style.ts │ │ │ │ │ │ │ └── use-control.ts │ │ │ │ │ │ ├── title.tsx │ │ │ │ │ │ ├── tools.tsx │ │ │ │ │ │ └── ungroup.tsx │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── line-add-button/ │ │ │ │ │ ├── button.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── use-visible.ts │ │ │ │ ├── node-menu/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── node-panel/ │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── node-list.tsx │ │ │ │ │ └── node-placeholder.tsx │ │ │ │ ├── problem-panel/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── problem-panel.tsx │ │ │ │ │ └── use-watch-validate.ts │ │ │ │ ├── selector-box-popover/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── sidebar/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── node-form-panel.tsx │ │ │ │ │ └── sidebar-node-renderer.tsx │ │ │ │ ├── testrun/ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── use-fields.ts │ │ │ │ │ │ ├── use-form-meta.ts │ │ │ │ │ │ └── use-sync-default.ts │ │ │ │ │ ├── json-value-editor/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── node-status-bar/ │ │ │ │ │ │ ├── group/ │ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── header/ │ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── render/ │ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── viewer/ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── testrun-button/ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── testrun-form/ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── type.ts │ │ │ │ │ ├── testrun-json-input/ │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── testrun-panel/ │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── test-run-panel.tsx │ │ │ │ └── tools/ │ │ │ │ ├── auto-layout.tsx │ │ │ │ ├── comment.tsx │ │ │ │ ├── download.tsx │ │ │ │ ├── fit-view.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── interactive.tsx │ │ │ │ ├── minimap-switch.tsx │ │ │ │ ├── minimap.tsx │ │ │ │ ├── mouse-pad-selector.less │ │ │ │ ├── mouse-pad-selector.tsx │ │ │ │ ├── readonly.tsx │ │ │ │ ├── save.tsx │ │ │ │ ├── styles.tsx │ │ │ │ ├── switch-line.tsx │ │ │ │ └── zoom-select.tsx │ │ │ ├── context/ │ │ │ │ ├── index.ts │ │ │ │ ├── node-render-context.ts │ │ │ │ └── sidebar-context.ts │ │ │ ├── editor.tsx │ │ │ ├── form-components/ │ │ │ │ ├── feedback.tsx │ │ │ │ ├── form-content/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── form-header/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ ├── title-input.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ ├── form-inputs/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── form-item/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ ├── use-editor-props.tsx │ │ │ │ ├── use-is-sidebar.ts │ │ │ │ ├── use-node-render-context.ts │ │ │ │ └── use-port-click.ts │ │ │ ├── index.ts │ │ │ ├── initial-data.ts │ │ │ ├── nodes/ │ │ │ │ ├── block-end/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── block-start/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── break/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── code/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── code.tsx │ │ │ │ │ │ ├── inputs.tsx │ │ │ │ │ │ └── outputs.tsx │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.tsx │ │ │ │ ├── comment/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── condition/ │ │ │ │ │ ├── condition-inputs/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── continue/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── default-form-meta.tsx │ │ │ │ ├── end/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── group/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── http/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── api.tsx │ │ │ │ │ │ ├── body.tsx │ │ │ │ │ │ ├── headers.tsx │ │ │ │ │ │ ├── params.tsx │ │ │ │ │ │ └── timeout.tsx │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── llm/ │ │ │ │ │ └── index.ts │ │ │ │ ├── loop/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── multi-condition/ │ │ │ │ │ ├── condition-inputs/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── start/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ └── variable/ │ │ │ │ ├── form-meta.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── types.tsx │ │ │ ├── plugins/ │ │ │ │ ├── context-menu-plugin/ │ │ │ │ │ ├── context-menu-layer.tsx │ │ │ │ │ ├── context-menu-plugin.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── panel-manager-plugin/ │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── hooks.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── runtime-plugin/ │ │ │ │ │ ├── client/ │ │ │ │ │ │ ├── base-client.ts │ │ │ │ │ │ ├── browser-client/ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── server-client/ │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── type.ts │ │ │ │ │ ├── create-runtime-plugin.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── runtime-service/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── type.ts │ │ │ │ └── variable-panel-plugin/ │ │ │ │ ├── components/ │ │ │ │ │ ├── full-variable-list.tsx │ │ │ │ │ ├── global-variable-editor.tsx │ │ │ │ │ ├── index.module.less │ │ │ │ │ └── variable-panel.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── variable-panel-layer.tsx │ │ │ │ └── variable-panel-plugin.ts │ │ │ ├── services/ │ │ │ │ ├── custom-service.ts │ │ │ │ ├── index.ts │ │ │ │ └── validate-service.ts │ │ │ ├── shortcuts/ │ │ │ │ ├── collapse/ │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── copy/ │ │ │ │ │ └── index.ts │ │ │ │ ├── delete/ │ │ │ │ │ └── index.ts │ │ │ │ ├── expand/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── paste/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── traverse.ts │ │ │ │ │ └── unique-workflow.ts │ │ │ │ ├── select-all/ │ │ │ │ │ └── index.ts │ │ │ │ ├── shortcuts.ts │ │ │ │ ├── type.ts │ │ │ │ ├── zoom-in/ │ │ │ │ │ └── index.ts │ │ │ │ └── zoom-out/ │ │ │ │ └── index.ts │ │ │ ├── styles/ │ │ │ │ └── index.css │ │ │ ├── type.d.ts │ │ │ ├── typings/ │ │ │ │ ├── index.ts │ │ │ │ ├── json-schema.ts │ │ │ │ └── node.ts │ │ │ └── utils/ │ │ │ ├── can-contain-node.ts │ │ │ ├── index.ts │ │ │ ├── on-drag-line-end.ts │ │ │ └── toggle-loop-expanded.ts │ │ └── tsconfig.json │ ├── demo-free-layout-simple/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── minimap.tsx │ │ │ │ ├── node-add-panel.tsx │ │ │ │ └── tools.tsx │ │ │ ├── editor.tsx │ │ │ ├── hooks/ │ │ │ │ └── use-editor-props.tsx │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ ├── initial-data.ts │ │ │ └── nodes/ │ │ │ ├── batch/ │ │ │ │ └── index.ts │ │ │ ├── batch-function/ │ │ │ │ ├── create-batch-function-json.ts │ │ │ │ ├── create-batch-function-lines.ts │ │ │ │ ├── create-batch-function.ts │ │ │ │ ├── form-meta.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── registry.ts │ │ │ │ └── relation.ts │ │ │ ├── block-end/ │ │ │ │ ├── form-meta.tsx │ │ │ │ └── index.ts │ │ │ ├── block-start/ │ │ │ │ ├── form-meta.tsx │ │ │ │ └── index.ts │ │ │ ├── chain/ │ │ │ │ └── index.ts │ │ │ ├── condition/ │ │ │ │ ├── form-meta.tsx │ │ │ │ └── index.ts │ │ │ ├── custom/ │ │ │ │ └── index.ts │ │ │ ├── end/ │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── loop/ │ │ │ │ ├── form-meta.tsx │ │ │ │ └── index.ts │ │ │ ├── start/ │ │ │ │ └── index.ts │ │ │ ├── tool/ │ │ │ │ └── index.ts │ │ │ └── twoway/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── demo-materials/ │ │ ├── .storybook/ │ │ │ └── main.ts │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── assets/ │ │ │ │ ├── icon-auto-layout.tsx │ │ │ │ ├── icon-cancel.tsx │ │ │ │ ├── icon-comment.tsx │ │ │ │ ├── icon-minimap.tsx │ │ │ │ ├── icon-mouse.tsx │ │ │ │ ├── icon-pad.tsx │ │ │ │ ├── icon-success.tsx │ │ │ │ ├── icon-switch-line.tsx │ │ │ │ └── icon-warning.tsx │ │ │ ├── components/ │ │ │ │ ├── form-header/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ ├── title-input.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ ├── free-editor/ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ └── use-editor-props.tsx │ │ │ │ │ ├── index.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── plugins/ │ │ │ │ │ └── debug-panel-plugin/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── debug-panel.tsx │ │ │ │ │ │ ├── full-variable-list.tsx │ │ │ │ │ │ └── workflow-json-editor.tsx │ │ │ │ │ ├── debug-panel-layer.tsx │ │ │ │ │ ├── debug-panel-plugin.ts │ │ │ │ │ └── index.ts │ │ │ │ └── free-form-meta-story-builder/ │ │ │ │ ├── constants.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── initial-data.tsx │ │ │ │ └── utils.tsx │ │ │ ├── index.tsx │ │ │ ├── stories/ │ │ │ │ ├── components/ │ │ │ │ │ ├── blur-input.stories.tsx │ │ │ │ │ ├── inputs-values-tree.stories.tsx │ │ │ │ │ ├── json-schema-creator.stories.tsx │ │ │ │ │ ├── sql-editor-with-variables.stories.tsx │ │ │ │ │ └── variable-selector.stories.tsx │ │ │ │ └── hello.stories.tsx │ │ │ └── type.d.ts │ │ └── tsconfig.json │ ├── demo-nextjs/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ ├── api/ │ │ │ │ │ └── runtime/ │ │ │ │ │ └── route.ts │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── editor/ │ │ │ │ ├── components/ │ │ │ │ │ ├── editor-client.tsx │ │ │ │ │ ├── editor.tsx │ │ │ │ │ ├── form-render.tsx │ │ │ │ │ ├── node-render.tsx │ │ │ │ │ └── tools.tsx │ │ │ │ ├── data/ │ │ │ │ │ ├── initial-data.ts │ │ │ │ │ └── node-registries.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── use-editor-props.tsx │ │ │ │ ├── index.ts │ │ │ │ └── style/ │ │ │ │ ├── index.css │ │ │ │ ├── theme.css │ │ │ │ └── var.css │ │ │ └── runtime/ │ │ │ ├── index.ts │ │ │ ├── main.ts │ │ │ └── models/ │ │ │ ├── index.ts │ │ │ └── runtime/ │ │ │ ├── index.ts │ │ │ ├── model.ts │ │ │ └── type.ts │ │ └── tsconfig.json │ ├── demo-nextjs-antd/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── next-env.d.ts │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ └── editor/ │ │ │ ├── assets/ │ │ │ │ ├── icon-auto-layout.tsx │ │ │ │ ├── icon-comment.tsx │ │ │ │ ├── icon-minimap.tsx │ │ │ │ ├── icon-mouse.tsx │ │ │ │ ├── icon-pad.tsx │ │ │ │ └── icon-switch-line.tsx │ │ │ ├── components/ │ │ │ │ ├── base-node/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── node-wrapper.scss │ │ │ │ │ ├── node-wrapper.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ └── utils.ts │ │ │ │ ├── editor-client.tsx │ │ │ │ ├── editor.tsx │ │ │ │ ├── form-render.tsx │ │ │ │ ├── group/ │ │ │ │ │ ├── color.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── background.tsx │ │ │ │ │ │ ├── color.tsx │ │ │ │ │ │ ├── header.tsx │ │ │ │ │ │ ├── icon-group.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── node-render.tsx │ │ │ │ │ │ ├── tips/ │ │ │ │ │ │ │ ├── global-store.ts │ │ │ │ │ │ │ ├── icon-close.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── is-mac-os.ts │ │ │ │ │ │ │ ├── style.ts │ │ │ │ │ │ │ └── use-control.ts │ │ │ │ │ │ ├── title.tsx │ │ │ │ │ │ ├── tools.tsx │ │ │ │ │ │ └── ungroup.tsx │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── line-add-button/ │ │ │ │ │ ├── button.tsx │ │ │ │ │ ├── index.scss │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── use-visible.ts │ │ │ │ ├── node-comment/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── blank-area.tsx │ │ │ │ │ │ ├── border-area.tsx │ │ │ │ │ │ ├── container.tsx │ │ │ │ │ │ ├── content-drag-area.tsx │ │ │ │ │ │ ├── drag-area.tsx │ │ │ │ │ │ ├── editor.tsx │ │ │ │ │ │ ├── index.css │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── more-button.tsx │ │ │ │ │ │ ├── render.tsx │ │ │ │ │ │ └── resize-area.tsx │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── use-model.ts │ │ │ │ │ │ ├── use-overflow.ts │ │ │ │ │ │ └── use-size.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── model.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── node-menu/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── node-panel/ │ │ │ │ │ ├── index.scss │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── node-list.tsx │ │ │ │ │ └── node-placeholder.tsx │ │ │ │ ├── node-render.tsx │ │ │ │ ├── selector-box-popover/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── sidebar/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── sidebar-node-renderer.tsx │ │ │ │ │ ├── sidebar-provider.tsx │ │ │ │ │ └── sidebar-renderer.tsx │ │ │ │ └── tools.tsx │ │ │ ├── context/ │ │ │ │ ├── index.ts │ │ │ │ ├── node-render-context.ts │ │ │ │ └── sidebar-context.ts │ │ │ ├── data/ │ │ │ │ ├── initial-data.ts │ │ │ │ └── node-registries.ts │ │ │ ├── form-components/ │ │ │ │ ├── feedback.tsx │ │ │ │ ├── form-content/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── form-header/ │ │ │ │ │ ├── index.scss │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ ├── title-input.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ ├── form-inputs/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── form-item/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── form-outputs/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── properties-edit/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── property-edit.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── type-tag.tsx │ │ │ │ └── value-display/ │ │ │ │ ├── index.tsx │ │ │ │ └── styles.tsx │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ ├── use-editor-props.tsx │ │ │ │ ├── use-is-sidebar.ts │ │ │ │ └── use-node-render-context.ts │ │ │ ├── index.ts │ │ │ ├── nodes/ │ │ │ │ ├── comment/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── condition/ │ │ │ │ │ ├── condition-inputs/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── default-form-meta.tsx │ │ │ │ ├── end/ │ │ │ │ │ ├── form-meta.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── llm/ │ │ │ │ │ └── index.ts │ │ │ │ ├── loop/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── loop-form-render.tsx │ │ │ │ └── start/ │ │ │ │ ├── form-meta.tsx │ │ │ │ └── index.ts │ │ │ ├── plugins/ │ │ │ │ ├── context-menu-plugin/ │ │ │ │ │ ├── context-menu-layer.tsx │ │ │ │ │ ├── context-menu-plugin.ts │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── shortcuts/ │ │ │ │ ├── collapse/ │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── copy/ │ │ │ │ │ └── index.ts │ │ │ │ ├── delete/ │ │ │ │ │ └── index.ts │ │ │ │ ├── expand/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── paste/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── traverse.ts │ │ │ │ │ └── unique-workflow.ts │ │ │ │ ├── select-all/ │ │ │ │ │ └── index.ts │ │ │ │ ├── shortcuts.ts │ │ │ │ ├── type.ts │ │ │ │ ├── zoom-in/ │ │ │ │ │ └── index.ts │ │ │ │ └── zoom-out/ │ │ │ │ └── index.ts │ │ │ ├── style/ │ │ │ │ ├── index.css │ │ │ │ └── var.css │ │ │ ├── typings/ │ │ │ │ ├── flow-value/ │ │ │ │ │ ├── config.json │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── json-schema/ │ │ │ │ │ ├── config.json │ │ │ │ │ └── index.ts │ │ │ │ └── node.ts │ │ │ └── utils/ │ │ │ ├── index.ts │ │ │ └── on-drag-line-end.ts │ │ └── tsconfig.json │ ├── demo-node-form/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── field-title.tsx │ │ │ │ ├── field-wrapper.css │ │ │ │ ├── field-wrapper.tsx │ │ │ │ └── index.ts │ │ │ ├── constant.ts │ │ │ ├── editor.tsx │ │ │ ├── form-meta.tsx │ │ │ ├── hooks/ │ │ │ │ └── use-editor-props.tsx │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ ├── initial-data.ts │ │ │ └── node-registries.tsx │ │ └── tsconfig.json │ ├── demo-playground/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── card.tsx │ │ │ │ └── playground-tools.tsx │ │ │ ├── editor.tsx │ │ │ └── index.tsx │ │ └── tsconfig.json │ ├── demo-react-16/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── rsbuild.config.ts │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── minimap.tsx │ │ │ │ ├── node-add-panel.tsx │ │ │ │ ├── node-form-panel/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── sidebar-renderer.tsx │ │ │ │ └── tools.tsx │ │ │ ├── editor.tsx │ │ │ ├── hooks/ │ │ │ │ └── use-editor-props.tsx │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ ├── initial-data.ts │ │ │ └── node-registries.ts │ │ └── tsconfig.json │ ├── demo-vite/ │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── components/ │ │ │ │ ├── minimap.tsx │ │ │ │ ├── node-add-panel.tsx │ │ │ │ └── tools.tsx │ │ │ ├── editor.tsx │ │ │ ├── hooks/ │ │ │ │ └── use-editor-props.tsx │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ ├── initial-data.ts │ │ │ └── node-registries.ts │ │ ├── tsconfig.json │ │ └── vite.config.js │ └── docs/ │ ├── .gitignore │ ├── README.md │ ├── components/ │ │ ├── code-preview/ │ │ │ └── index.tsx │ │ ├── fixed-examples/ │ │ │ ├── step-1.tsx │ │ │ ├── step-2.tsx │ │ │ ├── step-3.tsx │ │ │ ├── step-4.tsx │ │ │ ├── step-5/ │ │ │ │ ├── adder.tsx │ │ │ │ ├── app.tsx │ │ │ │ ├── initial-data.ts │ │ │ │ ├── node-registries.tsx │ │ │ │ ├── node-render.tsx │ │ │ │ └── use-editor-props.tsx │ │ │ ├── step-6/ │ │ │ │ ├── adder.tsx │ │ │ │ ├── app.tsx │ │ │ │ ├── initial-data.ts │ │ │ │ ├── node-registries.tsx │ │ │ │ ├── node-render.tsx │ │ │ │ └── use-editor-props.tsx │ │ │ └── step-7/ │ │ │ ├── adder.tsx │ │ │ ├── app.tsx │ │ │ ├── initial-data.ts │ │ │ ├── minimap.tsx │ │ │ ├── node-registries.tsx │ │ │ ├── node-render.tsx │ │ │ ├── tools.tsx │ │ │ └── use-editor-props.tsx │ │ ├── fixed-feature-overview/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── fixed-layout-simple/ │ │ │ ├── composite-nodes-preview.tsx │ │ │ ├── fixed-layout-simple.tsx │ │ │ ├── index.tsx │ │ │ └── preview.tsx │ │ ├── form-materials/ │ │ │ ├── common/ │ │ │ │ ├── disable-declaration-plugin.tsx │ │ │ │ ├── json-schema-preset.css │ │ │ │ └── json-schema-preset.tsx │ │ │ ├── components/ │ │ │ │ ├── assign-row.tsx │ │ │ │ ├── assign-rows.tsx │ │ │ │ ├── batch-outputs.tsx │ │ │ │ ├── batch-variable-selector.tsx │ │ │ │ ├── blur-input.tsx │ │ │ │ ├── code-editor.tsx │ │ │ │ ├── condition-context.tsx │ │ │ │ ├── condition-row.tsx │ │ │ │ ├── constant-inputs.tsx │ │ │ │ ├── db-condition-row.tsx │ │ │ │ ├── display-flow-value.tsx │ │ │ │ ├── display-inputs-values.tsx │ │ │ │ ├── display-outputs.tsx │ │ │ │ ├── display-schema-tag.tsx │ │ │ │ ├── display-schema-tree.tsx │ │ │ │ ├── dynamic-value-input.tsx │ │ │ │ ├── inputs-values-tree.tsx │ │ │ │ ├── inputs-values.tsx │ │ │ │ ├── json-editor-with-variables.tsx │ │ │ │ ├── json-schema-creator.tsx │ │ │ │ ├── json-schema-editor.tsx │ │ │ │ ├── prompt-editor-with-inputs.tsx │ │ │ │ ├── prompt-editor-with-variables.tsx │ │ │ │ ├── prompt-editor.tsx │ │ │ │ ├── sql-editor-with-variables.tsx │ │ │ │ ├── type-selector.tsx │ │ │ │ └── variable-selector.tsx │ │ │ ├── effects/ │ │ │ │ ├── auto-rename-ref.tsx │ │ │ │ ├── listen-ref-schema-change.tsx │ │ │ │ ├── listen-ref-value-change.tsx │ │ │ │ ├── provide-batch-input.tsx │ │ │ │ ├── provide-json-schema-output.tsx │ │ │ │ ├── sync-variable-title.tsx │ │ │ │ └── validate-when-variable-sync.tsx │ │ │ ├── form-plugins/ │ │ │ │ ├── batch-outputs-plugin.tsx │ │ │ │ ├── infer-assign-plugin.tsx │ │ │ │ └── infer-inputs-plugin.tsx │ │ │ └── validate/ │ │ │ └── validate-flow-value.tsx │ │ ├── free-examples/ │ │ │ ├── step-1.tsx │ │ │ ├── step-2.tsx │ │ │ ├── step-3.tsx │ │ │ ├── step-4.tsx │ │ │ ├── step-5/ │ │ │ │ ├── app.tsx │ │ │ │ ├── initial-data.ts │ │ │ │ ├── node-registries.tsx │ │ │ │ ├── node-render.tsx │ │ │ │ └── use-editor-props.tsx │ │ │ ├── step-6/ │ │ │ │ ├── app.tsx │ │ │ │ ├── initial-data.ts │ │ │ │ ├── node-registries.tsx │ │ │ │ ├── node-render.tsx │ │ │ │ └── use-editor-props.tsx │ │ │ └── step-7/ │ │ │ ├── add-node.tsx │ │ │ ├── app.tsx │ │ │ ├── initial-data.ts │ │ │ ├── minimap.tsx │ │ │ ├── node-registries.tsx │ │ │ ├── node-render.tsx │ │ │ ├── tools.tsx │ │ │ └── use-editor-props.tsx │ │ ├── free-feature-overview/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── free-form-meta-story-builder/ │ │ │ └── index.tsx │ │ ├── free-layout-simple/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── preview.tsx │ │ ├── index.ts │ │ ├── infinite-canvas/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── infinite-canvas.tsx │ │ │ └── preview.tsx │ │ ├── materials.tsx │ │ ├── node-form/ │ │ │ ├── array/ │ │ │ │ ├── index.css │ │ │ │ ├── node-registry.tsx │ │ │ │ └── preview.tsx │ │ │ ├── basic-preview.tsx │ │ │ ├── dynamic/ │ │ │ │ ├── node-registry.tsx │ │ │ │ └── preview.tsx │ │ │ ├── editor.tsx │ │ │ ├── effect/ │ │ │ │ ├── node-registry.tsx │ │ │ │ └── preview.tsx │ │ │ ├── index.css │ │ │ └── index.ts │ │ ├── preview-editor.tsx │ │ └── tsx-editor.tsx │ ├── eslint.config.js │ ├── global.less │ ├── package.json │ ├── rspress.config.ts │ ├── scripts/ │ │ ├── auto-generate.ts │ │ ├── constants.ts │ │ └── patch.ts │ ├── src/ │ │ ├── en/ │ │ │ ├── _nav.json │ │ │ ├── api/ │ │ │ │ ├── _meta.json │ │ │ │ ├── common-apis.mdx │ │ │ │ ├── components/ │ │ │ │ │ ├── editor-renderer.mdx │ │ │ │ │ ├── fixed-layout-editor-provider.mdx │ │ │ │ │ ├── fixed-layout-editor.mdx │ │ │ │ │ ├── free-layout-editor-provider.mdx │ │ │ │ │ ├── free-layout-editor.mdx │ │ │ │ │ └── workflow-node-renderer.mdx │ │ │ │ ├── core/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── flow-document.mdx │ │ │ │ │ ├── flow-node-entity.mdx │ │ │ │ │ ├── playground.mdx │ │ │ │ │ ├── workflow-document.mdx │ │ │ │ │ ├── workflow-line-entity.mdx │ │ │ │ │ └── workflow-lines-manager.mdx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-client-context.mdx │ │ │ │ │ ├── use-node-render.mdx │ │ │ │ │ ├── use-playground-tools.mdx │ │ │ │ │ ├── use-refresh.mdx │ │ │ │ │ └── use-service.mdx │ │ │ │ ├── index.mdx │ │ │ │ ├── plugins.mdx │ │ │ │ ├── services/ │ │ │ │ │ ├── clipboard-service.mdx │ │ │ │ │ ├── command-service.mdx │ │ │ │ │ ├── flow-operation-service.mdx │ │ │ │ │ ├── history-service.mdx │ │ │ │ │ └── selection-service.mdx │ │ │ │ └── utils/ │ │ │ │ ├── disposable-collection.mdx │ │ │ │ ├── disposable.mdx │ │ │ │ ├── emitter.mdx │ │ │ │ └── get-node-form.mdx │ │ │ ├── examples/ │ │ │ │ ├── _meta.json │ │ │ │ ├── fixed-layout/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── fixed-composite-nodes.mdx │ │ │ │ │ ├── fixed-feature-overview.mdx │ │ │ │ │ └── fixed-layout-simple.mdx │ │ │ │ ├── free-layout/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── free-feature-overview.mdx │ │ │ │ │ └── free-layout-simple.mdx │ │ │ │ ├── index.mdx │ │ │ │ ├── node-form/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── array.mdx │ │ │ │ │ ├── basic.mdx │ │ │ │ │ ├── dynamic.mdx │ │ │ │ │ └── effect.mdx │ │ │ │ └── playground.mdx │ │ │ ├── guide/ │ │ │ │ ├── _meta.json │ │ │ │ ├── advanced/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── custom-layer.mdx │ │ │ │ │ ├── custom-plugin.mdx │ │ │ │ │ ├── custom-service.mdx │ │ │ │ │ ├── history.mdx │ │ │ │ │ ├── lines.mdx │ │ │ │ │ ├── shortcuts.mdx │ │ │ │ │ └── zoom-scroll.mdx │ │ │ │ ├── concepts/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── canvas-engine.mdx │ │ │ │ │ ├── ecs.mdx │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── ioc.mdx │ │ │ │ │ ├── node-engine.mdx │ │ │ │ │ └── reactflow.mdx │ │ │ │ ├── contact-us.mdx │ │ │ │ ├── contributing.mdx │ │ │ │ ├── fixed-layout/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── composite-nodes.mdx │ │ │ │ │ ├── load.mdx │ │ │ │ │ └── node.mdx │ │ │ │ ├── form/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── form-materials.mdx │ │ │ │ │ ├── form.mdx │ │ │ │ │ └── without-form.mdx │ │ │ │ ├── free-layout/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── line.mdx │ │ │ │ │ ├── load.mdx │ │ │ │ │ ├── node.mdx │ │ │ │ │ ├── port.mdx │ │ │ │ │ └── sub-canvas.mdx │ │ │ │ ├── getting-started/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── fixed-layout.mdx │ │ │ │ │ ├── free-layout.mdx │ │ │ │ │ ├── introduction.mdx │ │ │ │ │ └── quick-start.mdx │ │ │ │ ├── plugin/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── background-plugin.mdx │ │ │ │ │ ├── export-plugin.mdx │ │ │ │ │ ├── free-auto-layout-plugin.mdx │ │ │ │ │ ├── free-stack-plugin.mdx │ │ │ │ │ ├── minimap-plugin.mdx │ │ │ │ │ └── panel-manager-plugin.mdx │ │ │ │ ├── runtime/ │ │ │ │ │ ├── _meta.json │ │ │ │ │ ├── api.mdx │ │ │ │ │ ├── introduction.mdx │ │ │ │ │ ├── node.mdx │ │ │ │ │ ├── quick-start.mdx │ │ │ │ │ ├── schema.mdx │ │ │ │ │ └── source-code-guide.mdx │ │ │ │ └── variable/ │ │ │ │ ├── _meta.json │ │ │ │ ├── basic.mdx │ │ │ │ ├── concept.mdx │ │ │ │ ├── custom-scope-chain.mdx │ │ │ │ ├── variable-consume.mdx │ │ │ │ └── variable-output.mdx │ │ │ ├── index.md │ │ │ └── materials/ │ │ │ ├── _meta.json │ │ │ ├── cli.mdx │ │ │ ├── common/ │ │ │ │ ├── _meta.json │ │ │ │ ├── disable-declaration-plugin.mdx │ │ │ │ ├── flow-value.mdx │ │ │ │ ├── inject-material.mdx │ │ │ │ └── json-schema-preset.mdx │ │ │ ├── components/ │ │ │ │ ├── _meta.json │ │ │ │ ├── assign-row.mdx │ │ │ │ ├── assign-rows.mdx │ │ │ │ ├── batch-outputs.mdx │ │ │ │ ├── batch-variable-selector.mdx │ │ │ │ ├── blur-input.mdx │ │ │ │ ├── code-editor.mdx │ │ │ │ ├── condition-context.mdx │ │ │ │ ├── condition-row.mdx │ │ │ │ ├── constant-input.mdx │ │ │ │ ├── coze-editor-extensions.mdx │ │ │ │ ├── db-condition-row.mdx │ │ │ │ ├── display-flow-value.mdx │ │ │ │ ├── display-inputs-values.mdx │ │ │ │ ├── display-outputs.mdx │ │ │ │ ├── display-schema-tag.mdx │ │ │ │ ├── display-schema-tree.mdx │ │ │ │ ├── dynamic-value-input.mdx │ │ │ │ ├── inputs-values-tree.mdx │ │ │ │ ├── inputs-values.mdx │ │ │ │ ├── json-editor-with-variables.mdx │ │ │ │ ├── json-schema-creator.mdx │ │ │ │ ├── json-schema-editor.mdx │ │ │ │ ├── prompt-editor-with-inputs.mdx │ │ │ │ ├── prompt-editor-with-variables.mdx │ │ │ │ ├── prompt-editor.mdx │ │ │ │ ├── sql-editor-with-variables.mdx │ │ │ │ ├── type-selector.mdx │ │ │ │ └── variable-selector.mdx │ │ │ ├── effects/ │ │ │ │ ├── _meta.json │ │ │ │ ├── auto-rename-ref.mdx │ │ │ │ ├── listen-ref-schema-change.mdx │ │ │ │ ├── listen-ref-value-change.mdx │ │ │ │ ├── provide-batch-input.mdx │ │ │ │ ├── provide-json-schema-outputs.mdx │ │ │ │ ├── sync-variable-title.mdx │ │ │ │ └── validate-when-variable-sync.mdx │ │ │ ├── form-plugins/ │ │ │ │ ├── _meta.json │ │ │ │ ├── batch-outputs-plugin.mdx │ │ │ │ ├── infer-assign-plugin.mdx │ │ │ │ └── infer-inputs-plugin.mdx │ │ │ ├── introduction.mdx │ │ │ └── validate/ │ │ │ ├── _meta.json │ │ │ └── validate-flow-value.mdx │ │ ├── global.d.ts │ │ └── zh/ │ │ ├── _nav.json │ │ ├── api/ │ │ │ ├── _meta.json │ │ │ ├── common-apis.mdx │ │ │ ├── components/ │ │ │ │ ├── editor-renderer.mdx │ │ │ │ ├── fixed-layout-editor-provider.mdx │ │ │ │ ├── fixed-layout-editor.mdx │ │ │ │ ├── free-layout-editor-provider.mdx │ │ │ │ ├── free-layout-editor.mdx │ │ │ │ └── workflow-node-renderer.mdx │ │ │ ├── core/ │ │ │ │ ├── _meta.json │ │ │ │ ├── flow-document.mdx │ │ │ │ ├── flow-node-entity.mdx │ │ │ │ ├── playground.mdx │ │ │ │ ├── workflow-document.mdx │ │ │ │ ├── workflow-line-entity.mdx │ │ │ │ └── workflow-lines-manager.mdx │ │ │ ├── hooks/ │ │ │ │ ├── use-client-context.mdx │ │ │ │ ├── use-node-render.mdx │ │ │ │ ├── use-playground-tools.mdx │ │ │ │ ├── use-refresh.mdx │ │ │ │ └── use-service.mdx │ │ │ ├── index.mdx │ │ │ ├── plugins.mdx │ │ │ ├── services/ │ │ │ │ ├── clipboard-service.mdx │ │ │ │ ├── command-service.mdx │ │ │ │ ├── flow-operation-service.mdx │ │ │ │ ├── history-service.mdx │ │ │ │ └── selection-service.mdx │ │ │ └── utils/ │ │ │ ├── disposable-collection.mdx │ │ │ ├── disposable.mdx │ │ │ ├── emitter.mdx │ │ │ └── get-node-form.mdx │ │ ├── examples/ │ │ │ ├── _meta.json │ │ │ ├── fixed-layout/ │ │ │ │ ├── _meta.json │ │ │ │ ├── fixed-composite-nodes.mdx │ │ │ │ ├── fixed-feature-overview.mdx │ │ │ │ └── fixed-layout-simple.mdx │ │ │ ├── free-layout/ │ │ │ │ ├── _meta.json │ │ │ │ ├── free-feature-overview.mdx │ │ │ │ └── free-layout-simple.mdx │ │ │ ├── index.mdx │ │ │ ├── node-form/ │ │ │ │ ├── _meta.json │ │ │ │ ├── array.mdx │ │ │ │ ├── basic.mdx │ │ │ │ ├── dynamic.mdx │ │ │ │ └── effect.mdx │ │ │ └── playground.mdx │ │ ├── guide/ │ │ │ ├── _meta.json │ │ │ ├── advanced/ │ │ │ │ ├── _meta.json │ │ │ │ ├── custom-layer.mdx │ │ │ │ ├── custom-plugin.mdx │ │ │ │ ├── custom-service.mdx │ │ │ │ ├── history.mdx │ │ │ │ ├── shortcuts.mdx │ │ │ │ └── zoom-scroll.mdx │ │ │ ├── concepts/ │ │ │ │ ├── _meta.json │ │ │ │ ├── canvas-engine.mdx │ │ │ │ ├── ecs.mdx │ │ │ │ ├── index.mdx │ │ │ │ ├── ioc.mdx │ │ │ │ ├── node-engine.mdx │ │ │ │ └── reactflow.mdx │ │ │ ├── contact-us.mdx │ │ │ ├── contributing.mdx │ │ │ ├── fixed-layout/ │ │ │ │ ├── _meta.json │ │ │ │ ├── composite-nodes.mdx │ │ │ │ ├── load.mdx │ │ │ │ └── node.mdx │ │ │ ├── form/ │ │ │ │ ├── _meta.json │ │ │ │ ├── form-materials.mdx │ │ │ │ ├── form.mdx │ │ │ │ └── without-form.mdx │ │ │ ├── free-layout/ │ │ │ │ ├── _meta.json │ │ │ │ ├── line.mdx │ │ │ │ ├── load.mdx │ │ │ │ ├── node.mdx │ │ │ │ ├── port.mdx │ │ │ │ └── sub-canvas.mdx │ │ │ ├── getting-started/ │ │ │ │ ├── _meta.json │ │ │ │ ├── fixed-layout.mdx │ │ │ │ ├── free-layout.mdx │ │ │ │ ├── introduction.mdx │ │ │ │ └── quick-start.mdx │ │ │ ├── plugin/ │ │ │ │ ├── _meta.json │ │ │ │ ├── background-plugin.mdx │ │ │ │ ├── export-plugin.mdx │ │ │ │ ├── free-auto-layout-plugin.mdx │ │ │ │ ├── free-stack-plugin.mdx │ │ │ │ ├── minimap-plugin.mdx │ │ │ │ └── panel-manager-plugin.mdx │ │ │ ├── question.mdx │ │ │ ├── runtime/ │ │ │ │ ├── _meta.json │ │ │ │ ├── api.mdx │ │ │ │ ├── introduction.mdx │ │ │ │ ├── node.mdx │ │ │ │ ├── quick-start.mdx │ │ │ │ ├── schema.mdx │ │ │ │ └── source-code-guide.mdx │ │ │ └── variable/ │ │ │ ├── _meta.json │ │ │ ├── basic.mdx │ │ │ ├── cases/ │ │ │ │ ├── _meta.json │ │ │ │ └── case-batch-variable.mdx │ │ │ ├── concept.mdx │ │ │ ├── core-api.mdx │ │ │ ├── core-ast.mdx │ │ │ ├── custom-scope-chain.mdx │ │ │ ├── variable-consume.mdx │ │ │ └── variable-output.mdx │ │ ├── index.md │ │ └── materials/ │ │ ├── _meta.json │ │ ├── cli.mdx │ │ ├── common/ │ │ │ ├── _meta.json │ │ │ ├── disable-declaration-plugin.mdx │ │ │ ├── flow-value.mdx │ │ │ ├── inject-material.mdx │ │ │ └── json-schema-preset.mdx │ │ ├── components/ │ │ │ ├── _meta.json │ │ │ ├── assign-row.mdx │ │ │ ├── assign-rows.mdx │ │ │ ├── batch-outputs.mdx │ │ │ ├── batch-variable-selector.mdx │ │ │ ├── blur-input.mdx │ │ │ ├── code-editor.mdx │ │ │ ├── condition-context.mdx │ │ │ ├── condition-row.mdx │ │ │ ├── constant-input.mdx │ │ │ ├── coze-editor-extensions.mdx │ │ │ ├── db-condition-row.mdx │ │ │ ├── display-flow-value.mdx │ │ │ ├── display-inputs-values.mdx │ │ │ ├── display-outputs.mdx │ │ │ ├── display-schema-tag.mdx │ │ │ ├── display-schema-tree.mdx │ │ │ ├── dynamic-value-input.mdx │ │ │ ├── inputs-values-tree.mdx │ │ │ ├── inputs-values.mdx │ │ │ ├── json-editor-with-variables.mdx │ │ │ ├── json-schema-creator.mdx │ │ │ ├── json-schema-editor.mdx │ │ │ ├── prompt-editor-with-inputs.mdx │ │ │ ├── prompt-editor-with-variables.mdx │ │ │ ├── prompt-editor.mdx │ │ │ ├── sql-editor-with-variables.mdx │ │ │ ├── type-selector.mdx │ │ │ └── variable-selector.mdx │ │ ├── effects/ │ │ │ ├── _meta.json │ │ │ ├── auto-rename-ref.mdx │ │ │ ├── listen-ref-schema-change.mdx │ │ │ ├── listen-ref-value-change.mdx │ │ │ ├── provide-batch-input.mdx │ │ │ ├── provide-json-schema-outputs.mdx │ │ │ ├── sync-variable-title.mdx │ │ │ └── validate-when-variable-sync.mdx │ │ ├── form-plugins/ │ │ │ ├── _meta.json │ │ │ ├── batch-outputs-plugin.mdx │ │ │ ├── infer-assign-plugin.mdx │ │ │ └── infer-inputs-plugin.mdx │ │ ├── introduction.mdx │ │ └── validate/ │ │ ├── _meta.json │ │ └── validate-flow-value.mdx │ ├── theme/ │ │ ├── components/ │ │ │ ├── background/ │ │ │ │ ├── index.css │ │ │ │ └── index.tsx │ │ │ └── logo/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── initial-data.ts │ │ │ ├── musk.tsx │ │ │ ├── node-color.ts │ │ │ ├── node-registries.tsx │ │ │ ├── node-render.tsx │ │ │ ├── port.tsx │ │ │ ├── position-groups.ts │ │ │ ├── update-position.ts │ │ │ └── use-editor-props.tsx │ │ ├── index.tsx │ │ ├── theme.css │ │ └── use-is-mobile.ts │ └── tsconfig.json ├── common/ │ ├── autoinstallers/ │ │ ├── dep-check/ │ │ │ ├── dep-check.ts │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── license-header/ │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── rush-commands/ │ │ │ ├── check-circular-dependency.mjs │ │ │ └── package.json │ │ ├── rush-commitlint/ │ │ │ ├── .cz-config.js │ │ │ ├── commitlint.config.js │ │ │ ├── package.json │ │ │ └── utils.js │ │ └── rush-lint-staged/ │ │ ├── .lintstagedrc.js │ │ ├── package.json │ │ └── utils.js │ ├── config/ │ │ └── rush/ │ │ ├── .npmrc │ │ ├── .npmrc-publish │ │ ├── .pnpmfile.cjs │ │ ├── artifactory.json │ │ ├── build-cache.json │ │ ├── cobuild.json │ │ ├── command-line.json │ │ ├── common-versions.json │ │ ├── custom-tips.json │ │ ├── experiments.json │ │ ├── pnpm-config.json │ │ ├── repo-state.json │ │ ├── rush-plugins.json │ │ ├── subspaces.json │ │ └── version-policies.json │ ├── git-hooks/ │ │ ├── commit-msg │ │ ├── post-checkout │ │ └── pre-commit │ └── scripts/ │ ├── install-run-rush-pnpm.js │ ├── install-run-rush.js │ ├── install-run-rushx.js │ └── install-run.js ├── config/ │ ├── eslint-config/ │ │ ├── CHANGELOG.json │ │ ├── CHANGELOG.md │ │ ├── eslint.base.config.js │ │ ├── eslint.config.js │ │ ├── eslint.node.config.js │ │ ├── eslint.web.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── defineFlatConfig.js │ │ │ ├── defineFlatConfig.ts │ │ │ └── index.js │ │ └── tsconfig.json │ └── ts-config/ │ ├── eslint.config.js │ ├── global.d.ts │ ├── package.json │ ├── tsconfig.base.json │ ├── tsconfig.flow.base.json │ ├── tsconfig.flow.path.json │ ├── tsconfig.infra.base.json │ ├── tsconfig.infra.node.json │ └── tsconfig.node.json ├── cspell.json ├── doc_build.sh ├── e2e/ │ ├── fixed-layout/ │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── playwright.config.ts │ │ ├── tests/ │ │ │ ├── drag.spec.ts │ │ │ ├── drawer.spec.ts │ │ │ ├── layout.spec.ts │ │ │ ├── models/ │ │ │ │ └── index.ts │ │ │ ├── node.spec.ts │ │ │ ├── testrun.spec.ts │ │ │ ├── typings/ │ │ │ │ ├── drag.ts │ │ │ │ └── index.ts │ │ │ ├── validate.spec.ts │ │ │ └── variable.spec.ts │ │ ├── tsconfig.json │ │ └── utils/ │ │ └── index.ts │ └── free-layout/ │ ├── eslint.config.js │ ├── package.json │ ├── playwright.config.ts │ ├── tests/ │ │ ├── layout.spec.ts │ │ ├── models/ │ │ │ └── index.ts │ │ └── node.spec.ts │ └── tsconfig.json ├── packages/ │ ├── canvas-engine/ │ │ ├── core/ │ │ │ ├── __mocks__/ │ │ │ │ ├── create-entity.mock.ts │ │ │ │ ├── layers.mock.tsx │ │ │ │ └── playground-container.mock.ts │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── pipeline.spec.tsx.snap │ │ │ │ │ └── playground.test.ts.snap │ │ │ │ ├── core/ │ │ │ │ │ └── layer/ │ │ │ │ │ ├── config/ │ │ │ │ │ │ ├── editor-state-config-entity.spec.ts │ │ │ │ │ │ └── payground-config-entity.spec.ts │ │ │ │ │ └── playground-layer.spec.tsx │ │ │ │ ├── entity.spec.ts │ │ │ │ ├── layer.spec.tsx │ │ │ │ ├── pipeline.spec.tsx │ │ │ │ ├── playground-contribution.spec.tsx │ │ │ │ ├── playground-mock-tools.spec.ts │ │ │ │ ├── playground-react.spec.tsx │ │ │ │ ├── playground.test.ts │ │ │ │ ├── plugin.test.ts │ │ │ │ ├── react-hooks.spec.tsx │ │ │ │ ├── schema.spec.ts │ │ │ │ ├── selection.spec.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── clipboard-service.spec.ts │ │ │ │ │ └── storage-service.spec.ts │ │ │ │ ├── transform-schema.spec.ts │ │ │ │ └── utils.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── common/ │ │ │ │ │ ├── config-entity.ts │ │ │ │ │ ├── entity-data.ts │ │ │ │ │ ├── entity-manager-contribution.ts │ │ │ │ │ ├── entity-manager.ts │ │ │ │ │ ├── entity.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── playground-context.ts │ │ │ │ │ ├── playground-decorator-helper.ts │ │ │ │ │ ├── playground-decorators.ts │ │ │ │ │ ├── playground-schedule.ts │ │ │ │ │ ├── protect-wheel-area.ts │ │ │ │ │ ├── schema/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── node.ts │ │ │ │ │ │ ├── opacity-schema.ts │ │ │ │ │ │ ├── origin-schema.ts │ │ │ │ │ │ ├── position-schema.ts │ │ │ │ │ │ ├── rotation-schema.ts │ │ │ │ │ │ ├── scale-schema.ts │ │ │ │ │ │ ├── size-schema.ts │ │ │ │ │ │ ├── skew-schema.ts │ │ │ │ │ │ └── transform-schema.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── bounds.spec.ts │ │ │ │ │ ├── bounds.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── core/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── layer/ │ │ │ │ │ │ ├── config/ │ │ │ │ │ │ │ ├── editor-state-config-entity.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── playground-config-entity.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── layer.ts │ │ │ │ │ │ └── playground-layer.ts │ │ │ │ │ ├── pipeline/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── pipeline-entities-selector.ts │ │ │ │ │ │ ├── pipeline-entities.ts │ │ │ │ │ │ ├── pipeline-registry.ts │ │ │ │ │ │ ├── pipeline-renderer.tsx │ │ │ │ │ │ ├── pipeline.ts │ │ │ │ │ │ └── pipline-react-utils.tsx │ │ │ │ │ └── utils/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── inject-provider-decorators.ts │ │ │ │ │ ├── lazy-inject-decorators.ts │ │ │ │ │ ├── mouse-touch-event.ts │ │ │ │ │ ├── playground-drag.ts │ │ │ │ │ ├── playground-gesture.spec.ts │ │ │ │ │ ├── playground-gesture.ts │ │ │ │ │ ├── tween.ts │ │ │ │ │ └── use-gesture/ │ │ │ │ │ ├── core/ │ │ │ │ │ │ ├── Controller.ts │ │ │ │ │ │ ├── EventStore.ts │ │ │ │ │ │ ├── TimeoutStore.ts │ │ │ │ │ │ ├── actions.ts │ │ │ │ │ │ ├── config/ │ │ │ │ │ │ │ ├── commonConfigResolver.ts │ │ │ │ │ │ │ ├── coordinatesConfigResolver.ts │ │ │ │ │ │ │ ├── dragConfigResolver.ts │ │ │ │ │ │ │ ├── hoverConfigResolver.ts │ │ │ │ │ │ │ ├── moveConfigResolver.ts │ │ │ │ │ │ │ ├── pinchConfigResolver.ts │ │ │ │ │ │ │ ├── resolver.ts │ │ │ │ │ │ │ ├── scrollConfigResolver.ts │ │ │ │ │ │ │ ├── sharedConfigResolver.ts │ │ │ │ │ │ │ ├── support.ts │ │ │ │ │ │ │ └── wheelConfigResolver.ts │ │ │ │ │ │ ├── engines/ │ │ │ │ │ │ │ ├── CoordinatesEngine.ts │ │ │ │ │ │ │ ├── DragEngine.ts │ │ │ │ │ │ │ ├── Engine.ts │ │ │ │ │ │ │ ├── HoverEngine.ts │ │ │ │ │ │ │ ├── MoveEngine.ts │ │ │ │ │ │ │ ├── PinchEngine.ts │ │ │ │ │ │ │ ├── ScrollEngine.ts │ │ │ │ │ │ │ └── WheelEngine.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── parser.ts │ │ │ │ │ │ ├── types/ │ │ │ │ │ │ │ ├── action.ts │ │ │ │ │ │ │ ├── config.ts │ │ │ │ │ │ │ ├── handlers.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── internalConfig.ts │ │ │ │ │ │ │ ├── state.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ ├── utils/ │ │ │ │ │ │ │ ├── events.ts │ │ │ │ │ │ │ ├── fn.ts │ │ │ │ │ │ │ ├── maths.ts │ │ │ │ │ │ │ └── state.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── vanilla/ │ │ │ │ │ ├── DragGesture.ts │ │ │ │ │ ├── Gesture.ts │ │ │ │ │ ├── HoverGesture.ts │ │ │ │ │ ├── MoveGesture.ts │ │ │ │ │ ├── PinchGesture.ts │ │ │ │ │ ├── Recognizer.ts │ │ │ │ │ ├── ScrollGesture.ts │ │ │ │ │ ├── WheelGesture.ts │ │ │ │ │ ├── createGesture.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── playground-config.ts │ │ │ │ ├── playground-container.ts │ │ │ │ ├── playground-contribution.ts │ │ │ │ ├── playground-mock-tools.ts │ │ │ │ ├── playground.ts │ │ │ │ ├── plugin/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── plugin.ts │ │ │ │ ├── react/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── playground-react-context.ts │ │ │ │ │ ├── playground-react-provider.tsx │ │ │ │ │ └── playground-react-renderer.tsx │ │ │ │ ├── react-hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-config-entity.ts │ │ │ │ │ ├── use-entities.ts │ │ │ │ │ ├── use-entity-data-from-context.ts │ │ │ │ │ ├── use-entity-from-context.ts │ │ │ │ │ ├── use-listen-events.ts │ │ │ │ │ ├── use-playground-container.ts │ │ │ │ │ ├── use-playground-context.ts │ │ │ │ │ ├── use-playground-drag.ts │ │ │ │ │ ├── use-playground.ts │ │ │ │ │ ├── use-refresh.ts │ │ │ │ │ └── use-service.ts │ │ │ │ └── services/ │ │ │ │ ├── clipboard-service.ts │ │ │ │ ├── context-menu-service.ts │ │ │ │ ├── index.ts │ │ │ │ ├── logger-service.ts │ │ │ │ ├── selection-service.ts │ │ │ │ └── storage-service.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── document/ │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── flow-document.test.ts.snap │ │ │ │ ├── datas/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── flow-node-transition-data.spec.ts.snap │ │ │ │ │ ├── flow-node-render-data.spec.ts │ │ │ │ │ └── flow-node-transition-data.spec.ts │ │ │ │ ├── flow-document-container.mock.ts │ │ │ │ ├── flow-document-transformer.test.ts │ │ │ │ ├── flow-document.test.ts │ │ │ │ ├── flow-node-entity.spec.ts │ │ │ │ ├── flow-node-registry.spec.ts │ │ │ │ ├── flow-render-tree.spec.ts │ │ │ │ ├── flow-virtual-tree.spec.ts │ │ │ │ ├── flow.mock.ts │ │ │ │ └── services/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── flow-operation-base-service.test.ts.snap │ │ │ │ └── flow-operation-base-service.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── datas/ │ │ │ │ │ ├── flow-node-render-data.ts │ │ │ │ │ ├── flow-node-transform-data.ts │ │ │ │ │ ├── flow-node-transition-data.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── entities/ │ │ │ │ │ ├── flow-document-transformer-entity.ts │ │ │ │ │ ├── flow-node-entity.ts │ │ │ │ │ ├── flow-renderer-state-entity.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── flow-document-config.ts │ │ │ │ ├── flow-document-container-module.ts │ │ │ │ ├── flow-document-contribution.ts │ │ │ │ ├── flow-document-options.ts │ │ │ │ ├── flow-document.ts │ │ │ │ ├── flow-render-tree.ts │ │ │ │ ├── flow-virtual-tree.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layout/ │ │ │ │ │ ├── horizontal-fixed-layout.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── vertical-fixed-layout.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── flow-drag-service.ts │ │ │ │ │ ├── flow-group-service/ │ │ │ │ │ │ ├── flow-group-controller.ts │ │ │ │ │ │ ├── flow-group-service.ts │ │ │ │ │ │ ├── flow-group-utils.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── flow-operation-base-service.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── typings/ │ │ │ │ │ ├── flow-group.ts │ │ │ │ │ ├── flow-layout.ts │ │ │ │ │ ├── flow-node-register.ts │ │ │ │ │ ├── flow-operation.ts │ │ │ │ │ ├── flow-transition.ts │ │ │ │ │ ├── flow.ts │ │ │ │ │ └── index.ts │ │ │ │ └── utils/ │ │ │ │ ├── get-default-spacing.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── fixed-layout-core/ │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── flow-activities.spec.ts.snap │ │ │ │ ├── flow-activities.mock.ts │ │ │ │ └── flow-activities.spec.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── activities/ │ │ │ │ │ ├── block-icon.ts │ │ │ │ │ ├── block-order-icon.ts │ │ │ │ │ ├── block.ts │ │ │ │ │ ├── break.ts │ │ │ │ │ ├── dynamic-split.ts │ │ │ │ │ ├── empty.ts │ │ │ │ │ ├── end.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── inline-blocks.ts │ │ │ │ │ ├── input.ts │ │ │ │ │ ├── loop-extends/ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── loop-empty-branch.ts │ │ │ │ │ │ ├── loop-inline-blocks.ts │ │ │ │ │ │ ├── loop-left-empty-block.ts │ │ │ │ │ │ └── loop-right-empty-block.ts │ │ │ │ │ ├── loop.ts │ │ │ │ │ ├── multi-inputs.ts │ │ │ │ │ ├── multi-outputs.ts │ │ │ │ │ ├── output.ts │ │ │ │ │ ├── root.ts │ │ │ │ │ ├── simple-split.ts │ │ │ │ │ ├── slot/ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── extends/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── slot-block.ts │ │ │ │ │ │ │ ├── slot-icon.ts │ │ │ │ │ │ │ └── slot-inline-blocks.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── slot.ts │ │ │ │ │ │ ├── typings.ts │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ ├── create.ts │ │ │ │ │ │ ├── layout.ts │ │ │ │ │ │ ├── node.ts │ │ │ │ │ │ └── transition.ts │ │ │ │ │ ├── start.ts │ │ │ │ │ ├── static-split.ts │ │ │ │ │ ├── try-catch-extends/ │ │ │ │ │ │ ├── catch-block.ts │ │ │ │ │ │ ├── catch-inline-blocks.ts │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── main-inline-blocks.ts │ │ │ │ │ │ ├── try-block.ts │ │ │ │ │ │ └── try-slot.ts │ │ │ │ │ └── try-catch.ts │ │ │ │ ├── fixed-layout-container-module.ts │ │ │ │ ├── flow-registers.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-layout-core/ │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── workflow-lines-manager.test.ts.snap │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-current-dom-node.test.ts │ │ │ │ │ ├── use-current-entity.test.ts │ │ │ │ │ ├── use-node-render.test.tsx │ │ │ │ │ ├── use-playground-readonly-state.test.ts │ │ │ │ │ └── use-workflow-document.test.ts │ │ │ │ ├── mocks/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── service/ │ │ │ │ │ ├── workflow-drag-service.test.ts │ │ │ │ │ ├── workflow-hover-service.test.ts │ │ │ │ │ └── workflow-select-service.test.ts │ │ │ │ ├── simple-line.ts │ │ │ │ ├── utils/ │ │ │ │ │ └── location-config-to-point.test.ts │ │ │ │ ├── workflow-document.test.ts │ │ │ │ └── workflow-lines-manager.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constants.ts │ │ │ │ ├── entities/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── workflow-line-entity.ts │ │ │ │ │ ├── workflow-node-entity.ts │ │ │ │ │ └── workflow-port-entity.ts │ │ │ │ ├── entity-datas/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── workflow-line-render-data.ts │ │ │ │ │ ├── workflow-node-lines-data.ts │ │ │ │ │ └── workflow-node-ports-data.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── typings.ts │ │ │ │ │ ├── use-current-dom-node.ts │ │ │ │ │ ├── use-current-entity.ts │ │ │ │ │ ├── use-node-render-context.ts │ │ │ │ │ ├── use-node-render.tsx │ │ │ │ │ ├── use-playground-readonly-state.ts │ │ │ │ │ └── use-workflow-document.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layout/ │ │ │ │ │ ├── free-layout.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── service/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── workflow-drag-service.ts │ │ │ │ │ ├── workflow-hover-service.ts │ │ │ │ │ ├── workflow-operation-base-service.ts │ │ │ │ │ ├── workflow-reset-layout-service.ts │ │ │ │ │ └── workflow-select-service.ts │ │ │ │ ├── typings/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── workflow-drag.ts │ │ │ │ │ ├── workflow-edge.ts │ │ │ │ │ ├── workflow-json.ts │ │ │ │ │ ├── workflow-line.ts │ │ │ │ │ ├── workflow-node.ts │ │ │ │ │ ├── workflow-operation.ts │ │ │ │ │ ├── workflow-registry.ts │ │ │ │ │ └── workflow-sub-canvas.ts │ │ │ │ ├── utils/ │ │ │ │ │ ├── build-group-json.ts │ │ │ │ │ ├── compose.ts │ │ │ │ │ ├── fit-view.ts │ │ │ │ │ ├── flow-node-form-data.ts │ │ │ │ │ ├── get-anti-overlap-position.ts │ │ │ │ │ ├── get-line-center.ts │ │ │ │ │ ├── get-url-params.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── layout-to-positions.ts │ │ │ │ │ ├── location-config-to-point.ts │ │ │ │ │ ├── nanoid.ts │ │ │ │ │ └── statics.ts │ │ │ │ ├── workflow-commands.ts │ │ │ │ ├── workflow-document-container-module.ts │ │ │ │ ├── workflow-document-contribution.ts │ │ │ │ ├── workflow-document-option.ts │ │ │ │ ├── workflow-document.ts │ │ │ │ └── workflow-lines-manager.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ └── renderer/ │ │ ├── __mocks__/ │ │ │ ├── flow-document-container.mock.ts │ │ │ ├── flow-drag-entity.ts │ │ │ ├── flow-json.mock.ts │ │ │ ├── flow-labels-mock-register.ts │ │ │ ├── flow-mock-node-json.ts │ │ │ ├── flow-selected-nodes.mock.ts │ │ │ ├── mock-lines.ts │ │ │ ├── renderer.mock.ts │ │ │ └── setup-file.ts │ │ ├── __tests__/ │ │ │ ├── components/ │ │ │ │ ├── Adder.test.tsx │ │ │ │ └── rounded-turning-line.test.tsx │ │ │ ├── entities/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── flow-drag-entities.test.ts.snap │ │ │ │ ├── flow-drag-entities.test.ts │ │ │ │ └── flow-select-config-entity.test.ts │ │ │ ├── flow-renderer.tsx │ │ │ ├── layers/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── flow-drag-layer.test.ts.snap │ │ │ │ │ ├── flow-label-layer.test.tsx.snap │ │ │ │ │ └── flow-selector-box-layer.test.tsx.snap │ │ │ │ ├── flow-drag-layer.test.ts │ │ │ │ ├── flow-label-layer.test.tsx │ │ │ │ ├── flow-lines-layer.test.ts │ │ │ │ ├── flow-selector-box-layer.test.tsx │ │ │ │ └── flow-transform-layer.test.tsx │ │ │ └── utils/ │ │ │ ├── element.test.ts │ │ │ ├── find-selected-nodes.test.ts │ │ │ ├── get-vertices.test.ts │ │ │ └── scroll-limit.test.ts │ │ ├── eslint.config.js │ │ ├── index.module.less │ │ ├── package.json │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── Adder.tsx │ │ │ │ ├── BranchDraggableRenderer.tsx │ │ │ │ ├── Collapse.tsx │ │ │ │ ├── CollapseAdder.tsx │ │ │ │ ├── CustomLine.tsx │ │ │ │ ├── LabelsRenderer.tsx │ │ │ │ ├── LinesRenderer.tsx │ │ │ │ ├── MarkerActivatedArrow.tsx │ │ │ │ ├── MarkerArrow.tsx │ │ │ │ ├── RoundedTurningLine.tsx │ │ │ │ ├── StraightLine.tsx │ │ │ │ └── utils.tsx │ │ │ ├── entities/ │ │ │ │ ├── README.md │ │ │ │ ├── flow-drag-entity.tsx │ │ │ │ ├── flow-select-config-entity.tsx │ │ │ │ ├── index.ts │ │ │ │ └── selector-box-config-entity.ts │ │ │ ├── flow-renderer-container-module.ts │ │ │ ├── flow-renderer-contribution.ts │ │ │ ├── flow-renderer-registry.ts │ │ │ ├── flow-renderer-resize-observer.ts │ │ │ ├── hooks/ │ │ │ │ └── use-base-color.ts │ │ │ ├── index.ts │ │ │ ├── layers/ │ │ │ │ ├── flow-context-menu-layer.tsx │ │ │ │ ├── flow-debug-layer.tsx │ │ │ │ ├── flow-drag-layer.tsx │ │ │ │ ├── flow-labels-layer.tsx │ │ │ │ ├── flow-lines-layer.tsx │ │ │ │ ├── flow-nodes-content-layer.tsx │ │ │ │ ├── flow-nodes-transform-layer.tsx │ │ │ │ ├── flow-scroll-bar-layer.tsx │ │ │ │ ├── flow-scroll-limit-layer.tsx │ │ │ │ ├── flow-selector-bounds-layer.tsx │ │ │ │ ├── flow-selector-box-layer.tsx │ │ │ │ └── index.ts │ │ │ └── utils/ │ │ │ ├── element.ts │ │ │ ├── find-selected-nodes.ts │ │ │ ├── index.ts │ │ │ ├── scroll-bar-events.tsx │ │ │ └── scroll-limit.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── client/ │ │ ├── editor/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── clients/ │ │ │ │ │ ├── flow-editor-client-plugins.ts │ │ │ │ │ ├── flow-editor-client.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── node-client/ │ │ │ │ │ ├── create-node-client-plugins.ts │ │ │ │ │ ├── highlight/ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── create-node-highlight-plugin.ts │ │ │ │ │ │ ├── highlight-form-item.ts │ │ │ │ │ │ ├── highlight-style.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── use-highlight.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── node-client.ts │ │ │ │ │ └── node-focus-service.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── editor-provider.tsx │ │ │ │ │ ├── editor-renderer.tsx │ │ │ │ │ ├── editor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── use-flow-editor.ts │ │ │ │ ├── index.ts │ │ │ │ └── preset/ │ │ │ │ ├── editor-default-preset.ts │ │ │ │ ├── editor-props.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── fixed-layout-editor/ │ │ │ ├── __mocks__/ │ │ │ │ ├── flow.mock.ts │ │ │ │ └── form.mock.tsx │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── fixed-layout-preset.test.ts.snap │ │ │ │ ├── create-container.ts │ │ │ │ ├── fixed-layout-preset.test.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── flow-operation-service.test.ts │ │ │ │ │ └── history-operation-service/ │ │ │ │ │ ├── add-block.test.ts │ │ │ │ │ ├── add-from-node.test.ts │ │ │ │ │ ├── add-node.test.ts │ │ │ │ │ ├── apply.test.ts │ │ │ │ │ ├── create-group.test.ts │ │ │ │ │ ├── delete-node.test.ts │ │ │ │ │ ├── delete-nodes.test.ts │ │ │ │ │ ├── move-node.test.ts │ │ │ │ │ ├── set-form-value.test.tsx │ │ │ │ │ ├── transact.test.ts │ │ │ │ │ └── ungroup.test.ts │ │ │ │ └── utils.ts │ │ │ ├── eslint.config.js │ │ │ ├── index.css │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── fixed-layout-editor-provider.tsx │ │ │ │ │ ├── fixed-layout-editor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-client-context.ts │ │ │ │ │ ├── use-node-render.tsx │ │ │ │ │ └── use-playground-tools.ts │ │ │ │ ├── index.ts │ │ │ │ ├── plugins/ │ │ │ │ │ └── create-operation-plugin.ts │ │ │ │ ├── preset/ │ │ │ │ │ ├── fixed-layout-preset.ts │ │ │ │ │ ├── fixed-layout-props.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── node-serialize.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── flow-operation-service.ts │ │ │ │ │ └── history-operation-service.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils/ │ │ │ │ └── compose.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-layout-editor/ │ │ │ ├── __mocks__/ │ │ │ │ └── flow.mocks.ts │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── free-layout-preset.test.ts.snap │ │ │ │ ├── create-editor.ts │ │ │ │ ├── free-layout-preset.test.ts │ │ │ │ ├── history.test.ts │ │ │ │ ├── use-playground-tools.test.ts │ │ │ │ └── utils.mock.tsx │ │ │ ├── eslint.config.js │ │ │ ├── index.css │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── free-layout-editor-provider.tsx │ │ │ │ │ ├── free-layout-editor.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── workflow-node-renderer.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-auto-layout.ts │ │ │ │ │ ├── use-client-context.ts │ │ │ │ │ └── use-playground-tools.ts │ │ │ │ ├── index.ts │ │ │ │ ├── plugins/ │ │ │ │ │ └── create-operation-plugin.ts │ │ │ │ ├── preset/ │ │ │ │ │ ├── free-layout-preset.ts │ │ │ │ │ ├── free-layout-props.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── node-serialize.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── flow-operation-service.ts │ │ │ │ │ └── history-operation-service.ts │ │ │ │ ├── tools/ │ │ │ │ │ ├── auto-layout.ts │ │ │ │ │ └── index.ts │ │ │ │ └── types.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ └── playground-react/ │ │ ├── eslint.config.js │ │ ├── index.css │ │ ├── package.json │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── index.ts │ │ │ │ ├── playground-react-content.tsx │ │ │ │ └── playground-react.tsx │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ └── use-playground-tools.ts │ │ │ ├── index.ts │ │ │ ├── layers/ │ │ │ │ └── playground-content-layer.tsx │ │ │ └── preset/ │ │ │ ├── index.ts │ │ │ ├── playground-react-preset.ts │ │ │ └── playground-react-props.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── common/ │ │ ├── command/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── command-container-module.ts │ │ │ │ ├── command-service.ts │ │ │ │ ├── command.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── history/ │ │ │ ├── __mocks__/ │ │ │ │ ├── editor.mock.ts │ │ │ │ └── history-container.mock.ts │ │ │ ├── __tests__/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── history-manager.test.ts.snap │ │ │ │ │ ├── history-service.test.ts.snap │ │ │ │ │ └── undo-redo-service.test.ts.snap │ │ │ │ ├── history-manager.test.ts │ │ │ │ ├── history-service.test.ts │ │ │ │ ├── operation-registry.test.ts │ │ │ │ ├── operation-service.test.ts │ │ │ │ └── undo-redo-service.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-history-plugin.ts │ │ │ │ ├── history/ │ │ │ │ │ ├── history-manager.ts │ │ │ │ │ ├── history-service.ts │ │ │ │ │ ├── history-stack.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stack-operation.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── undo-redo-service.ts │ │ │ │ ├── history-config.ts │ │ │ │ ├── history-container-module.ts │ │ │ │ ├── history-context.ts │ │ │ │ ├── index.ts │ │ │ │ └── operation/ │ │ │ │ ├── index.ts │ │ │ │ ├── operation-contribution.ts │ │ │ │ ├── operation-registry.ts │ │ │ │ ├── operation-service.ts │ │ │ │ └── types.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── history-storage/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── index.ts │ │ │ │ ├── __tests__/ │ │ │ │ │ └── history-database.test.ts │ │ │ │ ├── create-history-storage-plugin.ts │ │ │ │ ├── history-database.ts │ │ │ │ ├── history-storage-container-module.ts │ │ │ │ ├── history-storage-manager.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── use-storage-hisotry-items.tsx │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── i18n/ │ │ │ ├── __tests__/ │ │ │ │ └── i18n.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── i18n/ │ │ │ │ │ ├── en-US.ts │ │ │ │ │ └── zh-CN.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ └── vitest.config.ts │ │ ├── reactive/ │ │ │ ├── README.md │ │ │ ├── __tests__/ │ │ │ │ ├── hooks.test.tsx │ │ │ │ ├── observe.test.tsx │ │ │ │ ├── reactive-base-state.test.ts │ │ │ │ ├── reactive-state.test.ts │ │ │ │ └── tracker.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── core/ │ │ │ │ │ ├── reactive-base-state.ts │ │ │ │ │ ├── reactive-state.ts │ │ │ │ │ └── tracker.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-observe.ts │ │ │ │ │ ├── use-reactive-state.ts │ │ │ │ │ └── use-readonly-reactive-state.ts │ │ │ │ ├── index.ts │ │ │ │ ├── react/ │ │ │ │ │ └── observe.tsx │ │ │ │ └── utils/ │ │ │ │ └── create-proxy.ts │ │ │ ├── tsconfig.json │ │ │ └── vitest.config.ts │ │ └── utils/ │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── add-event-listener.ts │ │ │ ├── array.spec.ts │ │ │ ├── array.ts │ │ │ ├── cache.spec.ts │ │ │ ├── cache.ts │ │ │ ├── cancellation.spec.ts │ │ │ ├── cancellation.ts │ │ │ ├── compare.spec.ts │ │ │ ├── compare.ts │ │ │ ├── compose.ts │ │ │ ├── contribution-provider.ts │ │ │ ├── decoration-style.ts │ │ │ ├── disposable-collection.ts │ │ │ ├── disposable.spec.ts │ │ │ ├── disposable.ts │ │ │ ├── dom-utils.spec.ts │ │ │ ├── dom-utils.ts │ │ │ ├── event.spec.ts │ │ │ ├── event.ts │ │ │ ├── hooks/ │ │ │ │ ├── use-refresh.spec.tsx │ │ │ │ └── use-refresh.ts │ │ │ ├── id.spec.ts │ │ │ ├── id.ts │ │ │ ├── index.spec.ts │ │ │ ├── index.ts │ │ │ ├── inversify-utils.ts │ │ │ ├── logger.spec.ts │ │ │ ├── logger.ts │ │ │ ├── math/ │ │ │ │ ├── IPoint.spec.ts │ │ │ │ ├── IPoint.ts │ │ │ │ ├── Matrix.spec.ts │ │ │ │ ├── Matrix.ts │ │ │ │ ├── ObservablePoint.spec.ts │ │ │ │ ├── ObservablePoint.ts │ │ │ │ ├── Point.spec.ts │ │ │ │ ├── Point.ts │ │ │ │ ├── Transform.spec.ts │ │ │ │ ├── Transform.ts │ │ │ │ ├── Vector2.spec.ts │ │ │ │ ├── Vector2.ts │ │ │ │ ├── angle.spec.ts │ │ │ │ ├── angle.ts │ │ │ │ ├── const.spec.ts │ │ │ │ ├── const.ts │ │ │ │ ├── index.spec.ts │ │ │ │ ├── index.ts │ │ │ │ ├── shapes/ │ │ │ │ │ ├── Circle.spec.ts │ │ │ │ │ ├── Circle.ts │ │ │ │ │ ├── Rectangle.spec.ts │ │ │ │ │ ├── Rectangle.ts │ │ │ │ │ ├── index.spec.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── wrap.spec.ts │ │ │ │ └── wrap.ts │ │ │ ├── objects.spec.ts │ │ │ ├── objects.ts │ │ │ ├── promise-util.spec.ts │ │ │ ├── promise-util.ts │ │ │ ├── request-with-memo.spec.ts │ │ │ ├── request-with-memo.ts │ │ │ ├── schema/ │ │ │ │ ├── index.spec.ts │ │ │ │ ├── index.ts │ │ │ │ ├── schema-base.ts │ │ │ │ ├── schema-transform.ts │ │ │ │ ├── schema.spec.ts │ │ │ │ └── schema.ts │ │ │ ├── types.spec.ts │ │ │ └── types.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── materials/ │ │ ├── coze-editor/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── rslib.config.ts │ │ │ ├── scripts/ │ │ │ │ └── gen.js │ │ │ ├── src/ │ │ │ │ ├── index.ts │ │ │ │ ├── language-json.ts │ │ │ │ ├── language-python.ts │ │ │ │ ├── language-shell.ts │ │ │ │ ├── language-sql.ts │ │ │ │ ├── language-typescript/ │ │ │ │ │ └── worker.ts │ │ │ │ ├── language-typescript.ts │ │ │ │ ├── preset-code.ts │ │ │ │ ├── preset-expression.ts │ │ │ │ ├── preset-none.ts │ │ │ │ ├── preset-prompt.ts │ │ │ │ ├── preset-universal.ts │ │ │ │ ├── preset-variable.ts │ │ │ │ ├── react-merge.ts │ │ │ │ ├── react.ts │ │ │ │ └── vscode.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── fixed-semi-materials/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── assets/ │ │ │ │ │ ├── ellipsis.tsx │ │ │ │ │ ├── icons.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── adder/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── branch-adder/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── collapse/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── constants.tsx │ │ │ │ │ ├── drag-highlight-adder/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── drag-node/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── dragging-adder/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── metadata.tsx │ │ │ │ │ ├── nodes/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── slot-adder.tsx │ │ │ │ │ ├── slot-collapse.tsx │ │ │ │ │ ├── tools.tsx │ │ │ │ │ └── try-catch-collapse.tsx │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── form-antd-materials/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── batch-variable-selector/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── condition-row/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ ├── styles.tsx │ │ │ │ │ │ │ ├── useOp.tsx │ │ │ │ │ │ │ └── useRule.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.tsx │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── constant-input/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.tsx │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── dynamic-value-input/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── json-schema-editor/ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ └── blur-input.tsx │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ ├── default-value.tsx │ │ │ │ │ │ ├── hooks.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── type-selector/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── variable-selector/ │ │ │ │ │ ├── config.json │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ └── use-variable-tree.tsx │ │ │ │ ├── effects/ │ │ │ │ │ ├── auto-rename-ref/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── provide-batch-input/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── provide-batch-outputs/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── provide-json-schema-outputs/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── sync-variable-title/ │ │ │ │ │ ├── config.json │ │ │ │ │ └── index.ts │ │ │ │ ├── form-plugins/ │ │ │ │ │ ├── batch-outputs-plugin/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── typings/ │ │ │ │ │ ├── flow-value/ │ │ │ │ │ │ ├── config.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── json-schema/ │ │ │ │ │ ├── config.json │ │ │ │ │ └── index.ts │ │ │ │ └── utils/ │ │ │ │ ├── format-legacy-refs/ │ │ │ │ │ ├── config.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── readme.md │ │ │ │ ├── index.ts │ │ │ │ ├── json-schema/ │ │ │ │ │ ├── config.json │ │ │ │ │ └── index.ts │ │ │ │ └── svg-icon/ │ │ │ │ └── index.tsx │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── form-materials/ │ │ │ ├── bin/ │ │ │ │ └── run.sh │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── rslib.config.ts │ │ │ ├── scripts/ │ │ │ │ └── name-export.js │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── assign-row/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── assign-rows/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── batch-outputs/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── batch-variable-selector/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── blur-input/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── code-editor/ │ │ │ │ │ │ ├── editor-all.tsx │ │ │ │ │ │ ├── editor-json.tsx │ │ │ │ │ │ ├── editor-python.tsx │ │ │ │ │ │ ├── editor-shell.tsx │ │ │ │ │ │ ├── editor-sql.tsx │ │ │ │ │ │ ├── editor-ts.tsx │ │ │ │ │ │ ├── editor.tsx │ │ │ │ │ │ ├── factory.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ ├── theme/ │ │ │ │ │ │ │ ├── dark.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── light.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── code-editor-mini/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── condition-context/ │ │ │ │ │ │ ├── context.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ └── use-condition.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── op.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── condition-row/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── constant-input/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── coze-editor-extensions/ │ │ │ │ │ │ ├── extensions/ │ │ │ │ │ │ │ ├── inputs-tree.tsx │ │ │ │ │ │ │ ├── variable-tag.tsx │ │ │ │ │ │ │ └── variable-tree.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.css │ │ │ │ │ ├── db-condition-row/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── display-flow-value/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── display-inputs-values/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.css │ │ │ │ │ ├── display-outputs/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.css │ │ │ │ │ ├── display-schema-tag/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.css │ │ │ │ │ ├── display-schema-tree/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.css │ │ │ │ │ ├── dynamic-value-input/ │ │ │ │ │ │ ├── hooks.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.css │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── inputs-values/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── inputs-values-tree/ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ └── use-child-list.tsx │ │ │ │ │ │ ├── icon.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── row.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── json-editor-with-variables/ │ │ │ │ │ │ ├── editor.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── json-schema-creator/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── json-input-modal.tsx │ │ │ │ │ │ ├── json-schema-creator.tsx │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ └── json-to-schema.ts │ │ │ │ │ ├── json-schema-editor/ │ │ │ │ │ │ ├── default-value.tsx │ │ │ │ │ │ ├── hooks.tsx │ │ │ │ │ │ ├── icon.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── prompt-editor/ │ │ │ │ │ │ ├── editor.tsx │ │ │ │ │ │ ├── extensions/ │ │ │ │ │ │ │ ├── jinja.tsx │ │ │ │ │ │ │ ├── language-support.tsx │ │ │ │ │ │ │ └── markdown.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ └── types.tsx │ │ │ │ │ ├── prompt-editor-with-inputs/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── prompt-editor-with-variables/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── sql-editor-with-variables/ │ │ │ │ │ │ ├── editor.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── type-selector/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── variable-selector/ │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.css │ │ │ │ │ └── use-variable-tree.tsx │ │ │ │ ├── effects/ │ │ │ │ │ ├── auto-rename-ref/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── listen-ref-schema-change/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── listen-ref-value-change/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── provide-batch-input/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── provide-json-schema-outputs/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── sync-variable-title/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── validate-when-variable-sync/ │ │ │ │ │ └── index.ts │ │ │ │ ├── form-plugins/ │ │ │ │ │ ├── batch-outputs-plugin/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── infer-assign-plugin/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── infer-inputs-plugin/ │ │ │ │ │ └── index.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── use-object-list/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── plugins/ │ │ │ │ │ ├── disable-declaration-plugin/ │ │ │ │ │ │ ├── create-disable-declaration-plugin.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── json-schema-preset/ │ │ │ │ │ ├── create-type-preset-plugin.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── react.tsx │ │ │ │ │ ├── type-definition/ │ │ │ │ │ │ ├── array.tsx │ │ │ │ │ │ ├── boolean.tsx │ │ │ │ │ │ ├── date-time.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── integer.tsx │ │ │ │ │ │ ├── map.tsx │ │ │ │ │ │ ├── number.tsx │ │ │ │ │ │ ├── object.tsx │ │ │ │ │ │ └── string.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── shared/ │ │ │ │ │ ├── flow-value/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── schema.ts │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── format-legacy-refs/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── readme.md │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── inject-material/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── lazy-suspense/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── polyfill-create-root/ │ │ │ │ │ └── index.tsx │ │ │ │ └── validate/ │ │ │ │ ├── index.ts │ │ │ │ └── validate-flow-value/ │ │ │ │ └── index.tsx │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ └── type-editor/ │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── feedback/ │ │ │ │ │ ├── feedback.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── style.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── type-editor/ │ │ │ │ │ ├── body.tsx │ │ │ │ │ ├── cell.tsx │ │ │ │ │ ├── columns/ │ │ │ │ │ │ ├── default.tsx │ │ │ │ │ │ ├── description.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── key.tsx │ │ │ │ │ │ ├── operate.tsx │ │ │ │ │ │ ├── private.tsx │ │ │ │ │ │ ├── required.tsx │ │ │ │ │ │ ├── style.ts │ │ │ │ │ │ ├── type.tsx │ │ │ │ │ │ └── value.tsx │ │ │ │ │ ├── common.ts │ │ │ │ │ ├── drop-tip.tsx │ │ │ │ │ ├── error.tsx │ │ │ │ │ ├── formatter/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── header.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── active-pos.ts │ │ │ │ │ │ ├── blink.ts │ │ │ │ │ │ ├── disabled.ts │ │ │ │ │ │ ├── drag-drop.ts │ │ │ │ │ │ ├── editor-listener.tsx │ │ │ │ │ │ ├── error-cell.ts │ │ │ │ │ │ ├── formatter-value.ts │ │ │ │ │ │ ├── hot-key.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── key-visible.tsx │ │ │ │ │ │ ├── paste-data.ts │ │ │ │ │ │ └── type-edit.ts │ │ │ │ │ ├── indent.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── mode/ │ │ │ │ │ │ ├── declare-assign.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── type-definition.ts │ │ │ │ │ ├── style.ts │ │ │ │ │ ├── table.tsx │ │ │ │ │ ├── tool-bar.tsx │ │ │ │ │ ├── tools/ │ │ │ │ │ │ ├── create-by-data.tsx │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ ├── style.ts │ │ │ │ │ │ └── undo-redo.tsx │ │ │ │ │ ├── type-editor.tsx │ │ │ │ │ ├── type.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── type-selector/ │ │ │ │ ├── cascader-v2/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── style.ts │ │ │ │ │ ├── trigger.tsx │ │ │ │ │ ├── type-cascader.tsx │ │ │ │ │ └── type-search.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── focus-item.ts │ │ │ │ │ ├── hot-key.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── option-value.ts │ │ │ │ │ ├── root-types.ts │ │ │ │ │ └── use-hight-light.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── type.ts │ │ │ │ └── utils/ │ │ │ │ └── index.tsx │ │ │ ├── contexts/ │ │ │ │ └── index.tsx │ │ │ ├── index.ts │ │ │ ├── preset/ │ │ │ │ ├── index.tsx │ │ │ │ └── object-type-editor/ │ │ │ │ └── index.tsx │ │ │ ├── services/ │ │ │ │ ├── clipboard-service.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── shortcut-service.ts │ │ │ │ ├── type-editor-service.ts │ │ │ │ ├── type-operation-service.ts │ │ │ │ ├── type-registry-manager.ts │ │ │ │ └── utils.ts │ │ │ ├── type-registry/ │ │ │ │ ├── array.tsx │ │ │ │ ├── boolean.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── integer.tsx │ │ │ │ ├── number.tsx │ │ │ │ ├── object.tsx │ │ │ │ └── string.tsx │ │ │ ├── types/ │ │ │ │ ├── index.ts │ │ │ │ ├── registry.ts │ │ │ │ └── type-editor.ts │ │ │ └── utils/ │ │ │ ├── index.ts │ │ │ ├── monitor-data/ │ │ │ │ ├── index.ts │ │ │ │ ├── monitor-data.ts │ │ │ │ └── use-monitor-data.ts │ │ │ └── registry-adapter.tsx │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── node-engine/ │ │ ├── form/ │ │ │ ├── __tests__/ │ │ │ │ ├── create-form.test.ts │ │ │ │ ├── field-array-model.test.ts │ │ │ │ ├── field-model.test.ts │ │ │ │ ├── form-model.test.ts │ │ │ │ ├── glob.test.ts │ │ │ │ ├── object.test.ts │ │ │ │ ├── path.test.ts │ │ │ │ ├── to-field-array.test.ts │ │ │ │ ├── to-field.test.ts │ │ │ │ ├── to-form.test.ts │ │ │ │ ├── utils.test.ts │ │ │ │ └── validate.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constants.ts │ │ │ │ ├── core/ │ │ │ │ │ ├── create-form.ts │ │ │ │ │ ├── field-array-model.ts │ │ │ │ │ ├── field-model.ts │ │ │ │ │ ├── form-model.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── path.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── to-field-array.ts │ │ │ │ │ ├── to-field.ts │ │ │ │ │ ├── to-form.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── index.ts │ │ │ │ ├── react/ │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── field-array.tsx │ │ │ │ │ ├── field.tsx │ │ │ │ │ ├── form.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-current-field-state.ts │ │ │ │ │ ├── use-current-field.ts │ │ │ │ │ ├── use-field-validate.ts │ │ │ │ │ ├── use-field.ts │ │ │ │ │ ├── use-form-state.ts │ │ │ │ │ ├── use-form.ts │ │ │ │ │ ├── use-watch.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── types/ │ │ │ │ │ ├── common.ts │ │ │ │ │ ├── field.ts │ │ │ │ │ ├── form.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── validate.ts │ │ │ │ └── utils/ │ │ │ │ ├── dom.ts │ │ │ │ ├── event.ts │ │ │ │ ├── glob.ts │ │ │ │ ├── index.ts │ │ │ │ ├── object.ts │ │ │ │ └── validate.ts │ │ │ ├── tsconfig.json │ │ │ └── vitest.config.ts │ │ ├── form-core/ │ │ │ ├── __tests__/ │ │ │ │ ├── form-path-service.test.ts │ │ │ │ └── form.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── client/ │ │ │ │ │ ├── create-node-container-modules.ts │ │ │ │ │ ├── create-node-entity-datas.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── node-material-client.ts │ │ │ │ │ └── node-render.tsx │ │ │ │ ├── error/ │ │ │ │ │ ├── client.ts │ │ │ │ │ ├── error-container-module.ts │ │ │ │ │ ├── error-node-contribution.ts │ │ │ │ │ ├── flow-node-error-data.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── renders/ │ │ │ │ │ │ ├── default-error-render.tsx │ │ │ │ │ │ ├── error-render.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── form/ │ │ │ │ │ ├── abilities/ │ │ │ │ │ │ ├── decorator-ability/ │ │ │ │ │ │ │ ├── decorator-ability.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── default-ability/ │ │ │ │ │ │ │ ├── default-ability.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── effect-ability/ │ │ │ │ │ │ │ ├── effect-ability.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── setter-ability/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── setter-ability.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── validation-ability/ │ │ │ │ │ │ │ ├── form-validate.types.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── validation-ability.ts │ │ │ │ │ │ └── visibility-ability/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── visibility-ability.ts │ │ │ │ │ ├── client/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── flow-node-form-data.ts │ │ │ │ │ ├── form-contribution.ts │ │ │ │ │ ├── form-core-container-module.ts │ │ │ │ │ ├── form-node-contribution.ts │ │ │ │ │ ├── form-render.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── models/ │ │ │ │ │ │ ├── form-ability-extension-registry.ts │ │ │ │ │ │ ├── form-item-ability.ts │ │ │ │ │ │ ├── form-item-material-context.ts │ │ │ │ │ │ ├── form-item.ts │ │ │ │ │ │ ├── form-meta.ts │ │ │ │ │ │ ├── form-model.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── form-context-maker.ts │ │ │ │ │ │ ├── form-manager.ts │ │ │ │ │ │ ├── form-path-service.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── types/ │ │ │ │ │ ├── form-ability.types.ts │ │ │ │ │ ├── form-meta.types.ts │ │ │ │ │ ├── form-model.types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── node/ │ │ │ │ │ ├── core-materials.ts │ │ │ │ │ ├── core-plugins.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── node-container-module.ts │ │ │ │ │ ├── node-contribution.ts │ │ │ │ │ ├── node-engine-context.ts │ │ │ │ │ ├── node-engine.ts │ │ │ │ │ ├── node-manager.ts │ │ │ │ │ └── types.ts │ │ │ │ └── node-react/ │ │ │ │ ├── context/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── node-engine-react-context.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-form-Item.ts │ │ │ │ │ └── use-node-engine-context.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ └── node/ │ │ ├── __tests__/ │ │ │ ├── form-effects.test.ts │ │ │ ├── form-model-v2.test.ts │ │ │ ├── form-plugins.test.ts │ │ │ └── glob.test.ts │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── form-model-v2.ts │ │ │ ├── form-plugin.ts │ │ │ ├── form-render.tsx │ │ │ ├── get-node-form.tsx │ │ │ ├── helpers.ts │ │ │ ├── hooks.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── plugins/ │ │ ├── background-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── background-layer.tsx │ │ │ │ ├── create-background-plugin.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── export-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constant.ts │ │ │ │ ├── create-plugin.ts │ │ │ │ ├── download-service/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── service.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── export-image-service/ │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── service.ts │ │ │ │ │ ├── type.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── index.ts │ │ │ │ └── type.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── fixed-drag-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-fixed-drag-plugin.ts │ │ │ │ ├── hooks/ │ │ │ │ │ └── use-start-drag-node.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── fixed-history-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-fixed-history-plugin.ts │ │ │ │ ├── fixed-history-config.ts │ │ │ │ ├── fixed-history-registers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── operation-metas/ │ │ │ │ │ ├── add-block.ts │ │ │ │ │ ├── add-child-node.ts │ │ │ │ │ ├── add-from-node.ts │ │ │ │ │ ├── add-node.ts │ │ │ │ │ ├── add-nodes.ts │ │ │ │ │ ├── base.ts │ │ │ │ │ ├── create-group.ts │ │ │ │ │ ├── delete-block.ts │ │ │ │ │ ├── delete-child-node.ts │ │ │ │ │ ├── delete-from-node.ts │ │ │ │ │ ├── delete-node.ts │ │ │ │ │ ├── delete-nodes.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── move-block.ts │ │ │ │ │ ├── move-child-nodes.ts │ │ │ │ │ ├── move-nodes.ts │ │ │ │ │ └── ungroup.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── fixed-history-form-data-service.ts │ │ │ │ │ ├── fixed-history-operation-service.ts │ │ │ │ │ ├── fixed-history-service.ts │ │ │ │ │ └── index.ts │ │ │ │ └── types.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-auto-layout-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-auto-layout-plugin.tsx │ │ │ │ ├── dagre-layout/ │ │ │ │ │ ├── acyclic.ts │ │ │ │ │ ├── graph.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── layout.ts │ │ │ │ │ ├── order.ts │ │ │ │ │ ├── rank/ │ │ │ │ │ │ ├── feasible-tree.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── longest-path.ts │ │ │ │ │ │ ├── network-simplex.ts │ │ │ │ │ │ └── normalize-ranks.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── dagre-lib/ │ │ │ │ │ ├── acyclic.js │ │ │ │ │ ├── add-border-segments.js │ │ │ │ │ ├── coordinate-system.js │ │ │ │ │ ├── data/ │ │ │ │ │ │ └── list.js │ │ │ │ │ ├── debug.js │ │ │ │ │ ├── greedy-fas.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── layout.js │ │ │ │ │ ├── nesting-graph.js │ │ │ │ │ ├── normalize.js │ │ │ │ │ ├── order/ │ │ │ │ │ │ ├── add-subgraph-constraints.js │ │ │ │ │ │ ├── barycenter.js │ │ │ │ │ │ ├── build-layer-graph.js │ │ │ │ │ │ ├── cross-count.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── init-order.js │ │ │ │ │ │ ├── resolve-conflicts.js │ │ │ │ │ │ ├── sort-subgraph.js │ │ │ │ │ │ └── sort.js │ │ │ │ │ ├── parent-dummy-chains.js │ │ │ │ │ ├── position/ │ │ │ │ │ │ ├── bk.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── rank/ │ │ │ │ │ │ ├── feasible-tree.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── network-simplex.js │ │ │ │ │ │ └── util.js │ │ │ │ │ ├── util.js │ │ │ │ │ └── version.js │ │ │ │ ├── index.ts │ │ │ │ ├── layout/ │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── dagre.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── layout.ts │ │ │ │ │ ├── position.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── services.ts │ │ │ │ └── type.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-container-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.ts │ │ │ │ ├── node-into-container/ │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── plugin.tsx │ │ │ │ │ ├── service.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── sub-canvas/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── background/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── style.ts │ │ │ │ │ │ ├── border/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── style.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── render/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── style.ts │ │ │ │ │ │ └── tips/ │ │ │ │ │ │ ├── global-store.ts │ │ │ │ │ │ ├── icon-close.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── is-mac-os.ts │ │ │ │ │ │ ├── style.ts │ │ │ │ │ │ └── use-control.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── use-node-size.ts │ │ │ │ │ │ └── use-sync-node-render-size.ts │ │ │ │ │ └── index.ts │ │ │ │ └── utils/ │ │ │ │ ├── adjust-sub-node-position.ts │ │ │ │ ├── get-collision-transform.ts │ │ │ │ ├── get-container-transforms.ts │ │ │ │ ├── index.ts │ │ │ │ ├── is-container.ts │ │ │ │ ├── is-point-in-rect.ts │ │ │ │ ├── is-rect-intersects.ts │ │ │ │ └── next-frame.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-group-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constant.ts │ │ │ │ ├── create-free-group-plugin.tsx │ │ │ │ ├── group-node.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── shortcuts/ │ │ │ │ │ ├── group.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ungroup.ts │ │ │ │ ├── type.ts │ │ │ │ ├── utils.ts │ │ │ │ └── workflow-group-service.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-history-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── changes/ │ │ │ │ │ ├── add-line-change.ts │ │ │ │ │ ├── add-node-change.ts │ │ │ │ │ ├── change-line-data.ts │ │ │ │ │ ├── delete-line-change.ts │ │ │ │ │ ├── delete-node-change.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── create-free-history-plugin.ts │ │ │ │ ├── free-history-config.ts │ │ │ │ ├── free-history-manager.ts │ │ │ │ ├── free-history-registers.ts │ │ │ │ ├── handlers/ │ │ │ │ │ ├── change-content-handler.ts │ │ │ │ │ └── drag-nodes-handler.ts │ │ │ │ ├── history-entity-manager.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── use-undo-redo.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── operation-metas/ │ │ │ │ │ ├── add-line.ts │ │ │ │ │ ├── add-node.ts │ │ │ │ │ ├── base.ts │ │ │ │ │ ├── change-line-data.ts │ │ │ │ │ ├── delete-line.ts │ │ │ │ │ ├── delete-node.ts │ │ │ │ │ ├── drag-nodes.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── move-child-nodes.ts │ │ │ │ │ └── reset-layout.ts │ │ │ │ └── types.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-hover-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-free-hover-plugin.ts │ │ │ │ ├── hover-layer.tsx │ │ │ │ ├── index.ts │ │ │ │ └── selection-utils.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-lines-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── bezier-controls.spec.ts.snap │ │ │ │ │ └── bezier-controls.spec.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── workflow-line-render/ │ │ │ │ │ │ ├── arrow.tsx │ │ │ │ │ │ ├── index.style.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── line-svg.tsx │ │ │ │ │ └── workflow-port-render/ │ │ │ │ │ ├── cross-hair.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.ts │ │ │ │ ├── constants/ │ │ │ │ │ ├── lines.ts │ │ │ │ │ └── points.ts │ │ │ │ ├── contributions/ │ │ │ │ │ ├── bezier/ │ │ │ │ │ │ ├── bezier-controls.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── fold/ │ │ │ │ │ │ ├── fold-line.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── straight/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── point-on-line.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── create-free-lines-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── workflow-lines-layer.tsx │ │ │ │ ├── type.ts │ │ │ │ └── types/ │ │ │ │ └── arrow-renderer.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-node-panel-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── component.tsx │ │ │ │ ├── create-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ ├── service.ts │ │ │ │ ├── type.ts │ │ │ │ └── utils/ │ │ │ │ ├── adjust-node-position.ts │ │ │ │ ├── build-line.ts │ │ │ │ ├── get-container-node.ts │ │ │ │ ├── get-port-box.ts │ │ │ │ ├── get-sub-nodes.ts │ │ │ │ ├── greater-or-less.ts │ │ │ │ ├── index.ts │ │ │ │ ├── is-container.ts │ │ │ │ ├── rect-distance.ts │ │ │ │ ├── sub-nodes-auto-offset.ts │ │ │ │ ├── sub-position-offset.ts │ │ │ │ ├── update-sub-nodes-position.ts │ │ │ │ └── wait-node-render.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-snap-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constant.ts │ │ │ │ ├── create-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ ├── service.ts │ │ │ │ ├── type.ts │ │ │ │ └── utils.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── free-stack-plugin/ │ │ │ ├── __tests__/ │ │ │ │ ├── computing.test.ts │ │ │ │ ├── manager.test.ts │ │ │ │ ├── type.mock.ts │ │ │ │ └── utils.mock.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── constant.ts │ │ │ │ ├── create-free-stack-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── manager.ts │ │ │ │ ├── stacking-computing.ts │ │ │ │ └── type.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── group-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── group-box.tsx │ │ │ │ │ ├── group-render.tsx │ │ │ │ │ ├── hooks.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── constant.ts │ │ │ │ ├── create-group-plugin.tsx │ │ │ │ ├── group-node-register.tsx │ │ │ │ ├── groups-layer.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── registers/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── register-clean-groups.ts │ │ │ │ │ ├── register-group-node.ts │ │ │ │ │ ├── register-layer.ts │ │ │ │ │ └── register-render.tsx │ │ │ │ └── type.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── history-node-plugin/ │ │ │ ├── __tests__/ │ │ │ │ ├── create-container.ts │ │ │ │ └── form.test.ts │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-history-node-plugin.ts │ │ │ │ ├── history-node-registers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── operation-metas/ │ │ │ │ │ ├── change-form-values.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils/ │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── i18n-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-i18n-plugin.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── materials-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-materials-plugin.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── minimap-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── component.tsx │ │ │ │ ├── constant.ts │ │ │ │ ├── create-plugin.ts │ │ │ │ ├── draw.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ ├── service.ts │ │ │ │ └── type.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── node-core-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-node-core-plugin.ts │ │ │ │ ├── form-node-contribution.ts │ │ │ │ ├── form-render.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── node-variable-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── PrivateScopeProvider.tsx │ │ │ │ │ └── PublicScopeProvider.tsx │ │ │ │ ├── create-node-variable-plugin.ts │ │ │ │ ├── form-v2/ │ │ │ │ │ ├── create-provider-effect.ts │ │ │ │ │ └── create-variable-provider-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── with-node-variables.tsx │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── panel-manager-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── panel-layer/ │ │ │ │ │ │ ├── css.ts │ │ │ │ │ │ ├── docked-panel-layer.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── panel-layer.tsx │ │ │ │ │ │ └── panel.tsx │ │ │ │ │ └── resize-bar/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── contexts.ts │ │ │ │ ├── create-panel-manager-plugin.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-global-css.ts │ │ │ │ │ ├── use-panel-manager.ts │ │ │ │ │ └── use-panel.ts │ │ │ │ ├── index.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── panel-config.ts │ │ │ │ │ ├── panel-factory.ts │ │ │ │ │ ├── panel-layer.ts │ │ │ │ │ ├── panel-manager.ts │ │ │ │ │ └── panel-restore.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ └── tsconfig.json │ │ ├── redux-devtool-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── connectors/ │ │ │ │ │ ├── base.ts │ │ │ │ │ ├── ecs-connector.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── variable-connector.ts │ │ │ │ ├── create-redux-devtool-plugin.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── select-box-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-select-box-plugin.ts │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── shortcuts-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-shortcuts-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layers/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── shortcuts-layer.tsx │ │ │ │ ├── shortcuts-contribution.ts │ │ │ │ └── shortcuts-utils.ts │ │ │ ├── tsconfig.json │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ ├── test-run-plugin/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── create-test-run-plugin.ts │ │ │ │ ├── form-engine/ │ │ │ │ │ ├── contexts.ts │ │ │ │ │ ├── fields/ │ │ │ │ │ │ ├── create-field.tsx │ │ │ │ │ │ ├── general-field.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── object-field.tsx │ │ │ │ │ │ ├── reactive-field.tsx │ │ │ │ │ │ ├── recursion-field.tsx │ │ │ │ │ │ └── schema-field.tsx │ │ │ │ │ ├── form/ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── use-create-form.ts │ │ │ │ │ │ ├── use-field.ts │ │ │ │ │ │ └── use-form.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── model/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── index.ts │ │ │ │ ├── reactive/ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── use-create-form.ts │ │ │ │ │ │ └── use-test-run-service.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── config.ts │ │ │ │ │ ├── form/ │ │ │ │ │ │ ├── factory.ts │ │ │ │ │ │ ├── form.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── manager.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── pipeline/ │ │ │ │ │ │ ├── factory.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── pipeline.ts │ │ │ │ │ │ ├── plugin.ts │ │ │ │ │ │ └── tap.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── test-run.ts │ │ │ │ └── types.ts │ │ │ └── tsconfig.json │ │ └── variable-plugin/ │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── create-variable-plugin.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── runtime/ │ │ ├── interface/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── api/ │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── define.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ ├── server-info/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task-cancel/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task-report/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task-result/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task-run/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task-validate/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── client/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── node/ │ │ │ │ │ ├── break/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── code/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── condition/ │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── continue/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── end/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── http/ │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── llm/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── loop/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── start/ │ │ │ │ │ └── index.ts │ │ │ │ ├── runtime/ │ │ │ │ │ ├── base/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── inputs-outputs.ts │ │ │ │ │ │ ├── invoke.ts │ │ │ │ │ │ └── value-object.ts │ │ │ │ │ ├── cache/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── container/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── context/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── document/ │ │ │ │ │ │ ├── document.ts │ │ │ │ │ │ ├── edge.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── node.ts │ │ │ │ │ │ └── port.ts │ │ │ │ │ ├── engine/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── executor/ │ │ │ │ │ │ ├── executor.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── node-executor.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── io-center/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── message/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── reporter/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── snapshot/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── snapshot-center.ts │ │ │ │ │ │ └── snapshot.ts │ │ │ │ │ ├── state/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── status/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── validation/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── variable/ │ │ │ │ │ └── index.ts │ │ │ │ └── schema/ │ │ │ │ ├── constant.ts │ │ │ │ ├── edge.ts │ │ │ │ ├── group.ts │ │ │ │ ├── index.ts │ │ │ │ ├── json-schema.ts │ │ │ │ ├── node-meta.ts │ │ │ │ ├── node.ts │ │ │ │ ├── value.ts │ │ │ │ ├── workflow.ts │ │ │ │ └── xy.ts │ │ │ └── tsconfig.json │ │ ├── js-core/ │ │ │ ├── eslint.config.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── api/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── task-cancel.ts │ │ │ │ │ ├── task-report.ts │ │ │ │ │ ├── task-result.ts │ │ │ │ │ ├── task-run.ts │ │ │ │ │ └── task-validate.ts │ │ │ │ ├── application/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── workflow.ts │ │ │ │ ├── domain/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── config.ts │ │ │ │ │ │ ├── executor/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── llm.ts │ │ │ │ │ │ ├── schemas/ │ │ │ │ │ │ │ ├── basic.test.ts │ │ │ │ │ │ │ ├── basic.ts │ │ │ │ │ │ │ ├── branch-two-layers.test.ts │ │ │ │ │ │ │ ├── branch-two-layers.ts │ │ │ │ │ │ │ ├── branch.test.ts │ │ │ │ │ │ │ ├── branch.ts │ │ │ │ │ │ │ ├── code.test.ts │ │ │ │ │ │ │ ├── code.ts │ │ │ │ │ │ │ ├── end-constant.test.ts │ │ │ │ │ │ │ ├── end-constant.ts │ │ │ │ │ │ │ ├── global-variable.test.ts │ │ │ │ │ │ │ ├── global-variable.ts │ │ │ │ │ │ │ ├── http-real.test.ts │ │ │ │ │ │ │ ├── http.test.ts │ │ │ │ │ │ │ ├── http.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── llm-real.test.ts │ │ │ │ │ │ │ ├── llm-real.ts │ │ │ │ │ │ │ ├── loop-break-continue.test.ts │ │ │ │ │ │ │ ├── loop-break-continue.ts │ │ │ │ │ │ │ ├── loop.test.ts │ │ │ │ │ │ │ ├── loop.ts │ │ │ │ │ │ │ ├── start-default.test.ts │ │ │ │ │ │ │ ├── start-default.ts │ │ │ │ │ │ │ ├── two-llm.ts │ │ │ │ │ │ │ ├── validate-inputs.test.ts │ │ │ │ │ │ │ └── validate-inputs.ts │ │ │ │ │ │ ├── setup.ts │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ ├── array-vo-data.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── snapshot.ts │ │ │ │ │ ├── cache/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── container/ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── context/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── document/ │ │ │ │ │ │ ├── document/ │ │ │ │ │ │ │ ├── create-store.test.ts │ │ │ │ │ │ │ ├── create-store.ts │ │ │ │ │ │ │ ├── flat-schema.test.ts │ │ │ │ │ │ │ ├── flat-schema.ts │ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── entity/ │ │ │ │ │ │ │ ├── edge/ │ │ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── node/ │ │ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── port/ │ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── engine/ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── executor/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── io-center/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── message/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── message-center/ │ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── message-value-object/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── report/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── report-value-object/ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── reporter/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── snapshot/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── snapshot-center/ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── snapshot-entity/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── state/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── status/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── status-center/ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── status-entity/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── task/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── validation/ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── validators/ │ │ │ │ │ │ ├── cycle-detection.test.ts │ │ │ │ │ │ ├── cycle-detection.ts │ │ │ │ │ │ ├── edge-source-target-exist.test.ts │ │ │ │ │ │ ├── edge-source-target-exist.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── schema-format.test.ts │ │ │ │ │ │ ├── schema-format.ts │ │ │ │ │ │ ├── start-end-node.test.ts │ │ │ │ │ │ └── start-end-node.ts │ │ │ │ │ └── variable/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── variable-store/ │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── variable-value-object/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── infrastructure/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── compare-node-groups.test.ts │ │ │ │ │ ├── compare-node-groups.ts │ │ │ │ │ ├── delay.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── json-schema-validator.test.ts │ │ │ │ │ ├── json-schema-validator.ts │ │ │ │ │ ├── runtime-type.test.ts │ │ │ │ │ ├── runtime-type.ts │ │ │ │ │ ├── traverse-nodes.test.ts │ │ │ │ │ ├── traverse-nodes.ts │ │ │ │ │ └── uuid.ts │ │ │ │ └── nodes/ │ │ │ │ ├── break/ │ │ │ │ │ └── index.ts │ │ │ │ ├── code/ │ │ │ │ │ └── index.ts │ │ │ │ ├── condition/ │ │ │ │ │ ├── handlers/ │ │ │ │ │ │ ├── array.ts │ │ │ │ │ │ ├── boolean.ts │ │ │ │ │ │ ├── datetime.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── map.ts │ │ │ │ │ │ ├── null.ts │ │ │ │ │ │ ├── number.ts │ │ │ │ │ │ ├── object.ts │ │ │ │ │ │ └── string.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── rules.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── continue/ │ │ │ │ │ └── index.ts │ │ │ │ ├── empty/ │ │ │ │ │ └── index.ts │ │ │ │ ├── end/ │ │ │ │ │ └── index.ts │ │ │ │ ├── http/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── llm/ │ │ │ │ │ └── index.ts │ │ │ │ ├── loop/ │ │ │ │ │ └── index.ts │ │ │ │ └── start/ │ │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ └── vitest.config.ts │ │ └── nodejs/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── api/ │ │ │ │ ├── create-api.ts │ │ │ │ ├── index.ts │ │ │ │ ├── trpc.ts │ │ │ │ └── type.ts │ │ │ ├── config/ │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── server/ │ │ │ ├── context.ts │ │ │ ├── docs.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ └── variable-engine/ │ ├── json-schema/ │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── base/ │ │ │ │ ├── base-type-manager.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── container-module.tsx │ │ │ ├── context.tsx │ │ │ ├── index.ts │ │ │ └── json-schema/ │ │ │ ├── index.ts │ │ │ ├── json-schema-type-manager.tsx │ │ │ ├── type-definition/ │ │ │ │ ├── array.tsx │ │ │ │ ├── boolean.tsx │ │ │ │ ├── date-time.tsx │ │ │ │ ├── default.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── integer.tsx │ │ │ │ ├── map.tsx │ │ │ │ ├── number.tsx │ │ │ │ ├── object.tsx │ │ │ │ ├── string.tsx │ │ │ │ └── unknown.tsx │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── variable-core/ │ │ ├── __mocks__/ │ │ │ ├── container.ts │ │ │ ├── mock-chain.ts │ │ │ └── variables.ts │ │ ├── __tests__/ │ │ │ ├── ast/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── key-path-expression-v2.test.ts.snap │ │ │ │ │ ├── variable-declaration.test.ts.snap │ │ │ │ │ └── variable-with-initializer.test.ts.snap │ │ │ │ ├── ast-decorators.test.ts │ │ │ │ ├── key-path-expression-v2.test.ts │ │ │ │ ├── variable-declaration.test.ts │ │ │ │ ├── variable-match.test.ts │ │ │ │ ├── variable-throw-errors.test.ts │ │ │ │ ├── variable-type-equal.test.ts │ │ │ │ └── variable-with-initializer.test.ts │ │ │ ├── case-run-down/ │ │ │ │ ├── blockwise-python-expression.test.ts │ │ │ │ └── variable-rename-listener.test.ts │ │ │ └── scope/ │ │ │ └── variable-engine.test.ts │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── ast/ │ │ │ │ ├── ast-node.ts │ │ │ │ ├── ast-registers.ts │ │ │ │ ├── common/ │ │ │ │ │ ├── data-node.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── list-node.ts │ │ │ │ │ └── map-node.ts │ │ │ │ ├── declaration/ │ │ │ │ │ ├── base-variable-field.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── property.ts │ │ │ │ │ ├── variable-declaration-list.ts │ │ │ │ │ └── variable-declaration.ts │ │ │ │ ├── expression/ │ │ │ │ │ ├── base-expression.ts │ │ │ │ │ ├── enumerate-expression.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── keypath-expression.ts │ │ │ │ │ ├── legacy-keypath-expression.ts │ │ │ │ │ └── wrap-array-expression.ts │ │ │ │ ├── factory.ts │ │ │ │ ├── flags.ts │ │ │ │ ├── index.ts │ │ │ │ ├── match.ts │ │ │ │ ├── type/ │ │ │ │ │ ├── array.ts │ │ │ │ │ ├── base-type.ts │ │ │ │ │ ├── boolean.ts │ │ │ │ │ ├── custom-type.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── integer.ts │ │ │ │ │ ├── map.ts │ │ │ │ │ ├── number.ts │ │ │ │ │ ├── object.ts │ │ │ │ │ ├── string.ts │ │ │ │ │ └── union.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils/ │ │ │ │ ├── expression.ts │ │ │ │ ├── helpers.ts │ │ │ │ ├── inversify.ts │ │ │ │ ├── observable.ts │ │ │ │ └── variable-field.ts │ │ │ ├── index.ts │ │ │ ├── providers.ts │ │ │ ├── react/ │ │ │ │ ├── context.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-available-variables.ts │ │ │ │ │ ├── use-output-variables.ts │ │ │ │ │ └── use-scope-available.ts │ │ │ │ └── index.tsx │ │ │ ├── scope/ │ │ │ │ ├── datas/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── scope-available-data.ts │ │ │ │ │ ├── scope-event-data.ts │ │ │ │ │ └── scope-output-data.ts │ │ │ │ ├── index.ts │ │ │ │ ├── scope-chain.ts │ │ │ │ ├── scope.ts │ │ │ │ ├── types.ts │ │ │ │ └── variable-table.ts │ │ │ ├── services/ │ │ │ │ ├── index.ts │ │ │ │ └── variable-field-key-rename-service.ts │ │ │ ├── utils/ │ │ │ │ ├── memo.ts │ │ │ │ └── toDisposable.tsx │ │ │ ├── variable-container-module.ts │ │ │ └── variable-engine.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ └── variable-layout/ │ ├── __mocks__/ │ │ ├── container.ts │ │ ├── fixed-layout-specs.ts │ │ ├── free-layout-specs.ts │ │ ├── run-fixed-layout-test.ts │ │ └── run-free-layout-test.ts │ ├── __tests__/ │ │ ├── __snapshots__/ │ │ │ ├── variable-fix-enable-global-scope.test.ts.snap │ │ │ ├── variable-fix-layout-filter-start-end.test.ts.snap │ │ │ ├── variable-fix-layout-group.test.ts.snap │ │ │ ├── variable-fix-layout-no-config.test.ts.snap │ │ │ ├── variable-fix-layout-transform-empty.test.ts.snap │ │ │ ├── variable-fix-layout.test.ts.snap │ │ │ ├── variable-free-enable-global-scope.test.ts.snap │ │ │ ├── variable-free-is-node-children-private.test.ts.snap │ │ │ ├── variable-free-layout-transform-empty.test.ts.snap │ │ │ └── variable-free-layout.test.ts.snap │ │ ├── variable-fix-enable-global-scope.test.ts │ │ ├── variable-fix-layout-filter-start-end.test.ts │ │ ├── variable-fix-layout-group.test.ts │ │ ├── variable-fix-layout-no-config.test.ts │ │ ├── variable-fix-layout-transform-empty.test.ts │ │ ├── variable-fix-layout.test.ts │ │ ├── variable-free-enable-global-scope.test.ts │ │ ├── variable-free-is-node-children-private.test.ts │ │ ├── variable-free-layout-transform-empty.test.ts │ │ └── variable-free-layout.test.ts │ ├── eslint.config.js │ ├── package.json │ ├── src/ │ │ ├── chains/ │ │ │ ├── fixed-layout-scope-chain.ts │ │ │ └── free-layout-scope-chain.ts │ │ ├── flow-node-variable-data.ts │ │ ├── index.ts │ │ ├── scopes/ │ │ │ └── global-scope.ts │ │ ├── services/ │ │ │ └── scope-chain-transform-service.ts │ │ ├── types.ts │ │ ├── utils.ts │ │ └── variable-chain-config.ts │ ├── tsconfig.json │ ├── vitest.config.ts │ └── vitest.setup.ts └── rush.json
Showing preview only (545K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5937 symbols across 1355 files)
FILE: .claude/skills/create-node/templates/complex-node/components/custom-component.tsx
function CustomComponent (line 15) | function CustomComponent() {
FILE: apps/cli/src/create-app/index.ts
function downloadFile (line 24) | function downloadFile(url: string, dest: string): Promise<void> {
FILE: apps/cli/src/find-materials/index.ts
function findUsedMaterials (line 13) | async function findUsedMaterials() {
FILE: apps/cli/src/materials/copy.ts
type CopyMaterialReturn (line 12) | interface CopyMaterialReturn {
FILE: apps/cli/src/materials/index.ts
function syncMaterial (line 18) | async function syncMaterial(cliOpts: MaterialCliOptions) {
FILE: apps/cli/src/materials/material.ts
class Material (line 12) | class Material {
method constructor (line 25) | constructor(public type: string, public name: string, public formMater...
method fullName (line 27) | get fullName() {
method sourceDir (line 31) | get sourceDir() {
method indexFile (line 35) | get indexFile() {
method allExportNames (line 39) | get allExportNames() {
method listAll (line 43) | static listAll(formMaterialPkg: LoadedNpmPkg): Material[] {
FILE: apps/cli/src/materials/refresh-project-import.ts
function executeRefreshProjectImport (line 15) | function executeRefreshProjectImport(context: SyncMaterialContext) {
FILE: apps/cli/src/materials/types.ts
type MaterialCliOptions (line 10) | interface MaterialCliOptions {
type SyncMaterialContext (line 17) | interface SyncMaterialContext {
FILE: apps/cli/src/update-version/index.ts
function updateFlowgramVersion (line 11) | async function updateFlowgramVersion(inputVersion?: string) {
FILE: apps/cli/src/utils/export.ts
function extractNamedExports (line 6) | function extractNamedExports(content: string) {
FILE: apps/cli/src/utils/file.ts
class File (line 11) | class File {
method constructor (line 22) | constructor(filePath: string, public root: string = '/') {
method replace (line 42) | replace(updater: (content: string) => string) {
method write (line 51) | write(nextContent: string) {
FILE: apps/cli/src/utils/import.ts
type NamedImport (line 6) | interface NamedImport {
type ImportDeclaration (line 20) | interface ImportDeclaration {
function assembleImport (line 36) | function assembleImport(declaration: ImportDeclaration): string {
function replaceImport (line 58) | function replaceImport(
FILE: apps/cli/src/utils/npm.ts
class LoadedNpmPkg (line 14) | class LoadedNpmPkg {
method constructor (line 15) | constructor(public name: string, public version: string, public path: ...
method srcPath (line 17) | get srcPath() {
method distPath (line 21) | get distPath() {
method packageJson (line 27) | get packageJson() {
method dependencies (line 34) | get dependencies(): Record<string, string> {
function downloadFile (line 40) | function downloadFile(url: string, dest: string): Promise<void> {
function getLatestVersion (line 68) | async function getLatestVersion(packageName: string): Promise<string> {
function loadNpm (line 72) | async function loadNpm(packageName: string): Promise<LoadedNpmPkg> {
FILE: apps/cli/src/utils/project.ts
type PackageJson (line 13) | interface PackageJson {
class Project (line 20) | class Project {
method constructor (line 31) | protected constructor() {}
method init (line 33) | async init() {
method addDependency (line 56) | async addDependency(dependency: string) {
method addDependencies (line 82) | async addDependencies(dependencies: string[]) {
method writeToPackageJsonFile (line 88) | writeToPackageJsonFile() {
method printInfo (line 92) | printInfo() {
method getSingleton (line 98) | static async getSingleton() {
FILE: apps/cli/src/utils/ts-file.ts
class TsFile (line 13) | class TsFile extends File {
method allExportNames (line 24) | get allExportNames() {
method constructor (line 28) | constructor(filePath: string, root?: string) {
method addImport (line 35) | addImport(importDeclarations: ImportDeclaration[]) {
method removeImport (line 50) | removeImport(importDeclarations: ImportDeclaration[]) {
method replaceImport (line 57) | replaceImport(oldImports: ImportDeclaration[], newImports: ImportDecla...
function getIndexTsFile (line 104) | function getIndexTsFile(folder: string): TsFile | undefined {
FILE: apps/create-app/src/index.ts
function downloadFile (line 34) | function downloadFile(url: string, dest: string): Promise<void> {
FILE: apps/demo-fixed-layout-animation/src/components/update-schema/example.py
class WorkflowState (line 19) | class WorkflowState(TypedDict):
class WeatherInfo (line 32) | class WeatherInfo:
class WeatherClothingAdvisor (line 41) | class WeatherClothingAdvisor:
method __init__ (line 44) | def __init__(self, openai_api_key: Optional[str] = None):
method validate_city_input (line 62) | def validate_city_input(self, state: WorkflowState) -> WorkflowState:
method fetch_weather_data (line 94) | def fetch_weather_data(self, state: WorkflowState) -> WorkflowState:
method generate_clothing_suggestion (line 153) | def generate_clothing_suggestion(self, state: WorkflowState) -> Workfl...
method _get_rule_based_suggestion (line 212) | def _get_rule_based_suggestion(self, temperature: float, weather_condi...
method format_final_response (line 265) | def format_final_response(self, state: WorkflowState) -> WorkflowState:
method create_workflow (line 304) | def create_workflow(self) -> StateGraph:
method get_clothing_advice (line 343) | def get_clothing_advice(self, city_name: str) -> str:
function main (line 376) | def main():
FILE: apps/demo-fixed-layout-animation/src/fields/thinking-text-field/index.tsx
type ThinkingTextProps (line 11) | interface ThinkingTextProps {
FILE: apps/demo-fixed-layout-animation/src/hooks/use-editor-props.tsx
function useEditorProps (line 20) | function useEditorProps(): FixedLayoutProps {
FILE: apps/demo-fixed-layout-animation/src/hooks/use-node-loading.tsx
type NodeStatus (line 10) | interface NodeStatus {
FILE: apps/demo-fixed-layout-animation/src/nodes/condition/index.ts
method onBlockChildCreate (line 17) | onBlockChildCreate(
FILE: apps/demo-fixed-layout-animation/src/services/load-schema-service/index.ts
class WorkflowLoadSchemaService (line 25) | class WorkflowLoadSchemaService {
method load (line 42) | public async load(schema: FlowDocumentJSON): Promise<void> {
method forceLoad (line 52) | public forceLoad(schema: FlowDocumentJSON): void {
method applySchemaPatch (line 57) | private async applySchemaPatch(schemaPatch: SchemaPatch): Promise<void> {
method applyCreatePatch (line 64) | private async applyCreatePatch(createSchemaPatchData: SchemaPatchData[...
method createNode (line 94) | private createNode(patchData: SchemaPatchData): FlowNodeEntity {
method getNode (line 110) | private getNode(id?: string): FlowNodeEntity | undefined {
method createNodeMotion (line 117) | private async createNodeMotion(node: FlowNodeEntity): Promise<void> {
method removeNodeMotion (line 137) | private async removeNodeMotion(node: FlowNodeEntity): Promise<void> {
method applyRemovePatch (line 144) | private async applyRemovePatch(removeNodeIDs: string[]): Promise<void> {
method setNodeStatus (line 160) | private setNodeStatus(
FILE: apps/demo-fixed-layout-animation/src/services/load-schema-service/type.ts
type SchemaPatchData (line 8) | interface SchemaPatchData {
type SchemaPatch (line 16) | interface SchemaPatch {
FILE: apps/demo-fixed-layout-simple/src/components/branch-adder.tsx
type PropsType (line 10) | interface PropsType {
function BranchAdder (line 15) | function BranchAdder(props: PropsType) {
FILE: apps/demo-fixed-layout-simple/src/components/flow-select.tsx
function FlowSelect (line 14) | function FlowSelect() {
FILE: apps/demo-fixed-layout-simple/src/components/slot-adder.tsx
type PropsType (line 16) | interface PropsType {
function SlotAdder (line 20) | function SlotAdder(props: PropsType) {
FILE: apps/demo-fixed-layout-simple/src/components/tools.tsx
function Tools (line 12) | function Tools() {
FILE: apps/demo-fixed-layout-simple/src/data/index.ts
constant FLOW_LIST (line 17) | const FLOW_LIST: Record<string, FlowDocumentJSON & { defaultLayout?: Flo...
FILE: apps/demo-fixed-layout-simple/src/hooks/use-editor-props.tsx
function useEditorProps (line 26) | function useEditorProps(
FILE: apps/demo-fixed-layout-simple/src/node-registries.ts
method onAdd (line 41) | onAdd() {
method onAdd (line 70) | onAdd() {
FILE: apps/demo-fixed-layout/src/assets/icon-mouse.tsx
function IconMouse (line 6) | function IconMouse(props: { width?: number; height?: number }) {
FILE: apps/demo-fixed-layout/src/assets/icon-pad.tsx
function IconPad (line 6) | function IconPad(props: { width?: number; height?: number }) {
FILE: apps/demo-fixed-layout/src/components/agent-adder/index.tsx
type PropsType (line 15) | interface PropsType {
function AgentAdder (line 19) | function AgentAdder(props: PropsType) {
FILE: apps/demo-fixed-layout/src/components/agent-label/index.tsx
type PropsType (line 9) | interface PropsType {
function AgentLabel (line 15) | function AgentLabel(props: PropsType) {
FILE: apps/demo-fixed-layout/src/components/branch-adder/index.tsx
type PropsType (line 13) | interface PropsType {
function BranchAdder (line 18) | function BranchAdder(props: PropsType) {
FILE: apps/demo-fixed-layout/src/components/drag-node/index.tsx
type PropsType (line 12) | type PropsType = Xor<
function DragNode (line 23) | function DragNode(props: PropsType): JSX.Element {
FILE: apps/demo-fixed-layout/src/components/node-adder/index.tsx
function Adder (line 33) | function Adder(props: {
FILE: apps/demo-fixed-layout/src/components/node-list.tsx
function Node (line 35) | function Node(props: { label: string; icon: JSX.Element; onClick: () => ...
function NodeList (line 55) | function NodeList(props: { onSelect: (meta: any) => void; from: FlowNode...
FILE: apps/demo-fixed-layout/src/components/selector-box-popover/index.tsx
constant BUTTON_HEIGHT (line 28) | const BUTTON_HEIGHT = 24;
FILE: apps/demo-fixed-layout/src/components/sidebar/sidebar-node-renderer.tsx
function SidebarNodeRenderer (line 14) | function SidebarNodeRenderer(props: { node: FlowNodeEntity }) {
FILE: apps/demo-fixed-layout/src/components/sidebar/sidebar-renderer.tsx
type NodeFormPanelProps (line 19) | interface NodeFormPanelProps {
FILE: apps/demo-fixed-layout/src/components/tools/interactive.tsx
constant CACHE_KEY (line 13) | const CACHE_KEY = 'workflow_prefer_interactive_type';
constant IS_MAC_OS (line 14) | const IS_MAC_OS = /(Macintosh|MacIntel|MacPPC|Mac68K|iPad)/.test(navigat...
type InteractiveType (line 28) | enum InteractiveType {
FILE: apps/demo-fixed-layout/src/components/tools/mouse-pad-selector.tsx
type InteractiveType (line 17) | enum InteractiveType {
type MousePadSelectorProps (line 22) | interface MousePadSelectorProps {
FILE: apps/demo-fixed-layout/src/components/tools/run.tsx
constant RUNNING_COLOR (line 18) | const RUNNING_COLOR = 'rgb(78, 64, 229)';
constant RUNNING_INTERVAL (line 19) | const RUNNING_INTERVAL = 1000;
function getRunningNodes (line 21) | function getRunningNodes(targetNode?: FlowNodeEntity | undefined, addChi...
function clear (line 43) | function clear() {
function runningNode (line 47) | function runningNode(ctx: FixedLayoutPluginContext, nodeId: string) {
function Run (line 90) | function Run() {
FILE: apps/demo-fixed-layout/src/components/tools/save.tsx
function Save (line 11) | function Save(props: { disabled: boolean }) {
FILE: apps/demo-fixed-layout/src/form-components/feedback.tsx
type StatePanelProps (line 9) | interface StatePanelProps {
FILE: apps/demo-fixed-layout/src/form-components/form-content/index.tsx
function FormContent (line 17) | function FormContent(props: { children?: React.ReactNode }) {
FILE: apps/demo-fixed-layout/src/form-components/form-header/index.tsx
function DropdownContent (line 23) | function DropdownContent(props: { updateTitleEdit: (editing: boolean) =>...
function FormHeader (line 69) | function FormHeader() {
FILE: apps/demo-fixed-layout/src/form-components/form-header/title-input.tsx
function TitleInput (line 15) | function TitleInput(props: {
FILE: apps/demo-fixed-layout/src/form-components/form-inputs/index.tsx
function FormInputs (line 14) | function FormInputs() {
FILE: apps/demo-fixed-layout/src/form-components/form-item/index.tsx
type FormItemProps (line 15) | interface FormItemProps {
function FormItem (line 24) | function FormItem({
FILE: apps/demo-fixed-layout/src/form-components/form-outputs/index.tsx
function FormOutputs (line 10) | function FormOutputs() {
FILE: apps/demo-fixed-layout/src/form-components/properties-edit/index.tsx
type PropertiesEditProps (line 15) | interface PropertiesEditProps {
FILE: apps/demo-fixed-layout/src/form-components/properties-edit/property-edit.tsx
type PropertyEditProps (line 15) | interface PropertyEditProps {
FILE: apps/demo-fixed-layout/src/hooks/use-editor-props.ts
function useEditorProps (line 36) | function useEditorProps(
FILE: apps/demo-fixed-layout/src/hooks/use-is-sidebar.ts
function useIsSidebar (line 10) | function useIsSidebar() {
FILE: apps/demo-fixed-layout/src/hooks/use-node-render-context.ts
function useNodeRenderContext (line 10) | function useNodeRenderContext() {
FILE: apps/demo-fixed-layout/src/nodes/agent/agent-tools.ts
method onAdd (line 23) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/agent/agent.ts
method onAdd (line 25) | onAdd(ctx, from) {
FILE: apps/demo-fixed-layout/src/nodes/agent/memory.ts
method onAdd (line 27) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/agent/tool.ts
method onAdd (line 26) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/break-loop/index.ts
method canAdd (line 31) | canAdd(ctx, from) {
method onAdd (line 38) | onAdd(ctx, from) {
FILE: apps/demo-fixed-layout/src/nodes/case/index.ts
method onAdd (line 29) | onAdd(ctx, from) {
FILE: apps/demo-fixed-layout/src/nodes/catch-block/index.ts
method onAdd (line 25) | onAdd(ctx, from) {
FILE: apps/demo-fixed-layout/src/nodes/end/index.ts
method canAdd (line 30) | canAdd(ctx, from) {
method canDelete (line 61) | canDelete(ctx, node) {
method onAdd (line 64) | onAdd(ctx, from) {
FILE: apps/demo-fixed-layout/src/nodes/if/index.ts
method onAdd (line 24) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/llm/index.ts
method canDelete (line 25) | canDelete(ctx, node) {
method onAdd (line 28) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/loop/form-meta.tsx
type LoopNodeJSON (line 16) | interface LoopNodeJSON extends FlowNodeJSON {
FILE: apps/demo-fixed-layout/src/nodes/loop/index.ts
method onAdd (line 23) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/switch/index.ts
method onAdd (line 25) | onAdd() {
FILE: apps/demo-fixed-layout/src/nodes/trycatch/index.ts
method onAdd (line 22) | onAdd() {
FILE: apps/demo-fixed-layout/src/plugins/clipboard-plugin/create-clipboard-plugin.ts
method onInit (line 18) | async onInit(ctx) {
FILE: apps/demo-fixed-layout/src/plugins/group-plugin/group-note.tsx
type GroupNoteProps (line 19) | interface GroupNoteProps {
FILE: apps/demo-fixed-layout/src/plugins/group-plugin/group-tools.tsx
type GroupToolsProps (line 28) | interface GroupToolsProps {
constant BUTTON_HEIGHT (line 35) | const BUTTON_HEIGHT = 24;
FILE: apps/demo-fixed-layout/src/plugins/group-plugin/multilang-textarea-editor/base-textarea.tsx
type Props (line 11) | interface Props {
FILE: apps/demo-fixed-layout/src/plugins/group-plugin/multilang-textarea-editor/index.tsx
type Props (line 19) | interface Props {
FILE: apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/full-variable-list.tsx
function FullVariableList (line 9) | function FullVariableList() {
FILE: apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/global-variable-editor.tsx
function GlobalVariableEditor (line 16) | function GlobalVariableEditor() {
FILE: apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/variable-panel.tsx
function VariablePanel (line 17) | function VariablePanel() {
FILE: apps/demo-fixed-layout/src/plugins/variable-panel-plugin/variable-panel-layer.tsx
class VariablePanelLayer (line 11) | class VariablePanelLayer extends Layer {
method onReady (line 12) | onReady(): void {
method render (line 24) | render(): JSX.Element {
FILE: apps/demo-fixed-layout/src/plugins/variable-panel-plugin/variable-panel-plugin.ts
method onInit (line 23) | onInit(ctx) {
FILE: apps/demo-fixed-layout/src/services/custom-service.ts
class CustomService (line 35) | class CustomService {
method save (line 44) | save() {
FILE: apps/demo-fixed-layout/src/shortcuts/constants.ts
type FlowCommandId (line 6) | enum FlowCommandId {
FILE: apps/demo-fixed-layout/src/shortcuts/index.ts
type ShortcutGetter (line 21) | type ShortcutGetter = (
FILE: apps/demo-fixed-layout/src/typings/json-schema.ts
type BasicType (line 8) | type BasicType = JsonSchemaBasicType;
type JsonSchema (line 9) | type JsonSchema = IJsonSchema;
FILE: apps/demo-fixed-layout/src/typings/node.ts
type FlowNodeJSON (line 21) | interface FlowNodeJSON extends FlowNodeJSONDefault {
type FlowNodeMeta (line 50) | interface FlowNodeMeta extends FlowNodeMetaDefault {
type FlowNodeRegistry (line 58) | interface FlowNodeRegistry extends FlowNodeRegistryDefault {
type FlowDocumentJSON (line 69) | type FlowDocumentJSON = {
FILE: apps/demo-free-layout-simple/src/components/tools.tsx
function Tools (line 12) | function Tools() {
FILE: apps/demo-free-layout-simple/src/hooks/use-editor-props.tsx
method fromNodeJSON (line 50) | fromNodeJSON(node, json) {
method toNodeJSON (line 59) | toNodeJSON(node, json) {
method getNodeDefaultRegistry (line 66) | getNodeDefaultRegistry(type) {
method onContentChange (line 112) | onContentChange(ctx, event) {
method isHideArrowLine (line 121) | isHideArrowLine(ctx, line) {
method onAllLayersRendered (line 147) | onAllLayersRendered(ctx) {
method onDispose (line 154) | onDispose() {
FILE: apps/demo-free-layout-simple/src/nodes/batch-function/registry.ts
method selectable (line 59) | selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {
method onCreate (line 75) | onCreate(node, json) {
FILE: apps/demo-free-layout-simple/src/nodes/batch/index.ts
method onCreate (line 23) | onCreate(node, json) {
FILE: apps/demo-free-layout-simple/src/nodes/block-end/index.ts
method canAdd (line 37) | canAdd() {
FILE: apps/demo-free-layout-simple/src/nodes/block-start/index.ts
method canAdd (line 37) | canAdd() {
FILE: apps/demo-free-layout-simple/src/nodes/condition/form-meta.tsx
constant CONDITION_ITEM_HEIGHT (line 14) | const CONDITION_ITEM_HEIGHT = 35;
FILE: apps/demo-free-layout-simple/src/nodes/loop/index.ts
method selectable (line 58) | selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {
method onAdd (line 73) | onAdd() {
FILE: apps/demo-free-layout/src/assets/icon-cancel.tsx
type Props (line 6) | interface Props {
FILE: apps/demo-free-layout/src/assets/icon-comment.tsx
type IconCommentProps (line 8) | interface IconCommentProps {
FILE: apps/demo-free-layout/src/assets/icon-mouse.tsx
function IconMouse (line 6) | function IconMouse(props: { width?: number; height?: number }) {
FILE: apps/demo-free-layout/src/assets/icon-pad.tsx
function IconPad (line 6) | function IconPad(props: { width?: number; height?: number }) {
FILE: apps/demo-free-layout/src/assets/icon-success.tsx
type Props (line 6) | interface Props {
FILE: apps/demo-free-layout/src/assets/icon-warning.tsx
type Props (line 6) | interface Props {
FILE: apps/demo-free-layout/src/components/base-node/node-wrapper.tsx
type NodeWrapperProps (line 17) | interface NodeWrapperProps {
FILE: apps/demo-free-layout/src/components/base-node/utils.ts
function scrollToView (line 8) | function scrollToView(
FILE: apps/demo-free-layout/src/components/comment/components/blank-area.tsx
type IBlankArea (line 13) | interface IBlankArea {
FILE: apps/demo-free-layout/src/components/comment/components/border-area.tsx
type IBorderArea (line 12) | interface IBorderArea {
FILE: apps/demo-free-layout/src/components/comment/components/container.tsx
type ICommentContainer (line 8) | interface ICommentContainer {
FILE: apps/demo-free-layout/src/components/comment/components/content-drag-area.tsx
type IContentDragArea (line 13) | interface IContentDragArea {
FILE: apps/demo-free-layout/src/components/comment/components/drag-area.tsx
type IDragArea (line 12) | interface IDragArea {
FILE: apps/demo-free-layout/src/components/comment/components/editor.tsx
type ICommentEditor (line 14) | interface ICommentEditor {
FILE: apps/demo-free-layout/src/components/comment/components/more-button.tsx
type IMoreButton (line 12) | interface IMoreButton {
FILE: apps/demo-free-layout/src/components/comment/components/resize-area.tsx
type IResizeArea (line 12) | interface IResizeArea {
FILE: apps/demo-free-layout/src/components/comment/constant.ts
type CommentEditorFormField (line 8) | enum CommentEditorFormField {
type CommentEditorEvent (line 14) | enum CommentEditorEvent {
FILE: apps/demo-free-layout/src/components/comment/model.ts
class CommentEditorModel (line 11) | class CommentEditorModel {
method value (line 22) | public get value(): string {
method setValue (line 27) | public setValue(value: string = CommentEditorDefaultValue): void {
method setInitValue (line 43) | public setInitValue(value: string = CommentEditorDefaultValue): void {
method element (line 58) | public set element(el: HTMLTextAreaElement) {
method element (line 66) | public get element(): HTMLTextAreaElement {
method setFocus (line 71) | public setFocus(focused: boolean): void {
method selectEnd (line 87) | public selectEnd(): void {
method focused (line 98) | public get focused(): boolean {
method deselect (line 103) | private deselect(): void {
method initialized (line 113) | private get initialized(): boolean {
method syncEditorValue (line 121) | private syncEditorValue(): void {
FILE: apps/demo-free-layout/src/components/comment/type.ts
type CommentEditorChangeEvent (line 8) | interface CommentEditorChangeEvent {
type CommentEditorMultiSelectEvent (line 13) | interface CommentEditorMultiSelectEvent {
type CommentEditorSelectEvent (line 17) | interface CommentEditorSelectEvent {
type CommentEditorBlurEvent (line 21) | interface CommentEditorBlurEvent {
type CommentEditorInitEvent (line 25) | interface CommentEditorInitEvent {
type CommentEditorEventParams (line 30) | type CommentEditorEventParams =
FILE: apps/demo-free-layout/src/components/group/color.ts
type GroupColor (line 6) | type GroupColor = {
FILE: apps/demo-free-layout/src/components/group/components/background.tsx
type GroupBackgroundProps (line 13) | interface GroupBackgroundProps {
FILE: apps/demo-free-layout/src/components/group/components/header.tsx
type GroupHeaderProps (line 13) | interface GroupHeaderProps {
FILE: apps/demo-free-layout/src/components/group/components/icon-group.tsx
type IconGroupProps (line 8) | interface IconGroupProps {
FILE: apps/demo-free-layout/src/components/group/components/tips/global-store.ts
constant STORAGE_KEY (line 8) | const STORAGE_KEY = 'workflow-move-into-group-tip-visible';
constant STORAGE_VALUE (line 9) | const STORAGE_VALUE = 'false';
class TipsGlobalStore (line 11) | class TipsGlobalStore {
method instance (line 14) | public static get instance(): TipsGlobalStore {
method isClosed (line 23) | public isClosed(): boolean {
method close (line 27) | public close(): void {
method isCloseForever (line 31) | public isCloseForever(): boolean {
method closeForever (line 35) | public closeForever(): void {
FILE: apps/demo-free-layout/src/components/group/components/ungroup.tsx
type UngroupButtonProps (line 14) | interface UngroupButtonProps {
FILE: apps/demo-free-layout/src/components/group/constant.ts
constant HEADER_HEIGHT (line 6) | const HEADER_HEIGHT = 30;
constant HEADER_PADDING (line 7) | const HEADER_PADDING = 5;
type GroupField (line 9) | enum GroupField {
FILE: apps/demo-free-layout/src/components/node-menu/index.tsx
type NodeMenuProps (line 25) | interface NodeMenuProps {
FILE: apps/demo-free-layout/src/components/node-panel/index.tsx
type NodePanelRenderProps (line 16) | interface NodePanelRenderProps extends NodePanelRenderPropsDefault {
FILE: apps/demo-free-layout/src/components/node-panel/node-list.tsx
type NodeProps (line 40) | interface NodeProps {
function Node (line 47) | function Node(props: NodeProps) {
type NodeListProps (line 68) | interface NodeListProps {
FILE: apps/demo-free-layout/src/components/problem-panel/use-watch-validate.ts
constant DEBOUNCE_TIME (line 13) | const DEBOUNCE_TIME = 1000;
FILE: apps/demo-free-layout/src/components/selector-box-popover/index.tsx
constant BUTTON_HEIGHT (line 16) | const BUTTON_HEIGHT = 24;
FILE: apps/demo-free-layout/src/components/sidebar/node-form-panel.tsx
type NodeFormPanelProps (line 19) | interface NodeFormPanelProps {
FILE: apps/demo-free-layout/src/components/sidebar/sidebar-node-renderer.tsx
function SidebarNodeRenderer (line 10) | function SidebarNodeRenderer(props: { node: FlowNodeEntity }) {
FILE: apps/demo-free-layout/src/components/testrun/hooks/use-form-meta.ts
constant DEFAULT_DECLARE (line 14) | const DEFAULT_DECLARE: IJsonSchema = {
FILE: apps/demo-free-layout/src/components/testrun/json-value-editor/index.tsx
function JsonValueEditor (line 10) | function JsonValueEditor({
FILE: apps/demo-free-layout/src/components/testrun/node-status-bar/group/index.tsx
type NodeStatusGroupProps (line 16) | interface NodeStatusGroupProps {
FILE: apps/demo-free-layout/src/components/testrun/node-status-bar/header/index.tsx
type NodeStatusBarProps (line 15) | interface NodeStatusBarProps {
FILE: apps/demo-free-layout/src/components/testrun/node-status-bar/render/index.tsx
type NodeStatusRenderProps (line 20) | interface NodeStatusRenderProps {
FILE: apps/demo-free-layout/src/components/testrun/node-status-bar/viewer/index.tsx
type DataStructureViewerProps (line 13) | interface DataStructureViewerProps {
type TreeNodeProps (line 18) | interface TreeNodeProps {
FILE: apps/demo-free-layout/src/components/testrun/testrun-button/index.tsx
function TestRunButton (line 16) | function TestRunButton(props: { disabled: boolean }) {
FILE: apps/demo-free-layout/src/components/testrun/testrun-form/index.tsx
type TestRunFormProps (line 19) | interface TestRunFormProps {
FILE: apps/demo-free-layout/src/components/testrun/testrun-form/type.ts
type TestRunFormMetaItem (line 8) | interface TestRunFormMetaItem {
type TestRunFormMeta (line 16) | type TestRunFormMeta = TestRunFormMetaItem[];
type TestRunFormField (line 18) | interface TestRunFormField extends TestRunFormMetaItem {
FILE: apps/demo-free-layout/src/components/testrun/testrun-json-input/index.tsx
type TestRunJsonInputProps (line 13) | interface TestRunJsonInputProps {
FILE: apps/demo-free-layout/src/components/testrun/testrun-panel/test-run-panel.tsx
type TestRunSidePanelProps (line 23) | interface TestRunSidePanelProps {}
FILE: apps/demo-free-layout/src/components/tools/interactive.tsx
constant CACHE_KEY (line 16) | const CACHE_KEY = 'workflow_prefer_interactive_type';
constant IS_MAC_OS (line 17) | const IS_MAC_OS = /(Macintosh|MacIntel|MacPPC|Mac68K|iPad)/.test(navigat...
type InteractiveType (line 31) | enum InteractiveType {
FILE: apps/demo-free-layout/src/components/tools/mouse-pad-selector.tsx
type InteractiveType (line 17) | enum InteractiveType {
type MousePadSelectorProps (line 22) | interface MousePadSelectorProps {
FILE: apps/demo-free-layout/src/components/tools/save.tsx
function Save (line 11) | function Save(props: { disabled: boolean }) {
FILE: apps/demo-free-layout/src/context/node-render-context.ts
type INodeRenderContext (line 10) | interface INodeRenderContext extends NodeRenderReturnType {}
FILE: apps/demo-free-layout/src/form-components/feedback.tsx
type StatePanelProps (line 9) | interface StatePanelProps {
FILE: apps/demo-free-layout/src/form-components/form-content/index.tsx
function FormContent (line 17) | function FormContent(props: { children?: React.ReactNode }) {
FILE: apps/demo-free-layout/src/form-components/form-header/index.tsx
function FormHeader (line 21) | function FormHeader() {
FILE: apps/demo-free-layout/src/form-components/form-header/title-input.tsx
function TitleInput (line 15) | function TitleInput(props: {
FILE: apps/demo-free-layout/src/form-components/form-inputs/index.tsx
function FormInputs (line 14) | function FormInputs() {
FILE: apps/demo-free-layout/src/form-components/form-item/index.tsx
type FormItemProps (line 15) | interface FormItemProps {
function FormItem (line 26) | function FormItem({
FILE: apps/demo-free-layout/src/hooks/use-editor-props.tsx
function useEditorProps (line 41) | function useEditorProps(
FILE: apps/demo-free-layout/src/hooks/use-is-sidebar.ts
function useIsSidebar (line 10) | function useIsSidebar() {
FILE: apps/demo-free-layout/src/hooks/use-node-render-context.ts
function useNodeRenderContext (line 10) | function useNodeRenderContext() {
FILE: apps/demo-free-layout/src/nodes/block-end/index.ts
method canAdd (line 43) | canAdd() {
FILE: apps/demo-free-layout/src/nodes/block-start/index.ts
method canAdd (line 43) | canAdd() {
FILE: apps/demo-free-layout/src/nodes/break/index.ts
method onAdd (line 35) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/code/components/code.tsx
function Code (line 12) | function Code() {
FILE: apps/demo-free-layout/src/nodes/code/components/inputs.tsx
function Inputs (line 12) | function Inputs() {
FILE: apps/demo-free-layout/src/nodes/code/components/outputs.tsx
function Outputs (line 13) | function Outputs() {
FILE: apps/demo-free-layout/src/nodes/code/index.tsx
method onAdd (line 47) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/code/types.tsx
type CodeNodeJSON (line 9) | interface CodeNodeJSON extends FlowNodeJSON {
FILE: apps/demo-free-layout/src/nodes/condition/condition-inputs/index.tsx
type ConditionValue (line 19) | interface ConditionValue {
function ConditionInputs (line 24) | function ConditionInputs() {
FILE: apps/demo-free-layout/src/nodes/condition/index.ts
method onAdd (line 31) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/constants.ts
type WorkflowNodeType (line 11) | enum WorkflowNodeType {
FILE: apps/demo-free-layout/src/nodes/continue/index.ts
method onAdd (line 35) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/end/index.ts
method canAdd (line 35) | canAdd() {
FILE: apps/demo-free-layout/src/nodes/group/index.tsx
method selectable (line 33) | selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {
method onAdd (line 50) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/http/components/api.tsx
function Api (line 13) | function Api() {
FILE: apps/demo-free-layout/src/nodes/http/components/body.tsx
constant BODY_TYPE_OPTIONS (line 17) | const BODY_TYPE_OPTIONS = [
function Body (line 32) | function Body() {
FILE: apps/demo-free-layout/src/nodes/http/components/headers.tsx
function Headers (line 12) | function Headers() {
FILE: apps/demo-free-layout/src/nodes/http/components/params.tsx
function Params (line 12) | function Params() {
FILE: apps/demo-free-layout/src/nodes/http/components/timeout.tsx
function Timeout (line 12) | function Timeout() {
FILE: apps/demo-free-layout/src/nodes/http/index.tsx
method onAdd (line 27) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/http/types.tsx
type HTTPNodeJSON (line 10) | interface HTTPNodeJSON extends FlowNodeJSON {
FILE: apps/demo-free-layout/src/nodes/llm/index.ts
method onAdd (line 26) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/loop/form-meta.tsx
type LoopNodeJSON (line 21) | interface LoopNodeJSON extends FlowNodeJSON {
FILE: apps/demo-free-layout/src/nodes/loop/index.ts
method selectable (line 65) | selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {
method onAdd (line 80) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/multi-condition/condition-inputs/index.tsx
type ConditionValue (line 18) | interface ConditionValue {
type BranchItem (line 23) | interface BranchItem {
function ConditionInputs (line 28) | function ConditionInputs() {
FILE: apps/demo-free-layout/src/nodes/multi-condition/index.ts
method onAdd (line 37) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/start/index.ts
method canAdd (line 36) | canAdd() {
FILE: apps/demo-free-layout/src/nodes/variable/index.tsx
method onAdd (line 27) | onAdd() {
FILE: apps/demo-free-layout/src/nodes/variable/types.tsx
type VariableNodeJSON (line 9) | interface VariableNodeJSON extends FlowNodeJSON {
FILE: apps/demo-free-layout/src/plugins/context-menu-plugin/context-menu-layer.tsx
class ContextMenuLayer (line 23) | class ContextMenuLayer extends Layer {
method onReady (line 36) | onReady() {
method openNodePanel (line 45) | openNodePanel(e: MouseEvent) {
method getContainerNode (line 74) | private getContainerNode(mousePos: PositionSchema): WorkflowNodeEntity...
FILE: apps/demo-free-layout/src/plugins/context-menu-plugin/context-menu-plugin.ts
type ContextMenuPluginOptions (line 14) | interface ContextMenuPluginOptions {}
method onInit (line 25) | onInit(ctx, options) {
FILE: apps/demo-free-layout/src/plugins/panel-manager-plugin/constants.ts
type PanelType (line 6) | enum PanelType {
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/client/base-client.ts
class WorkflowRuntimeClient (line 10) | class WorkflowRuntimeClient implements IRuntimeClient {
method constructor (line 11) | constructor() {}
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/client/browser-client/index.ts
class WorkflowRuntimeBrowserClient (line 11) | class WorkflowRuntimeBrowserClient implements IRuntimeClient {
method constructor (line 12) | constructor() {}
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/client/server-client/constant.ts
constant DEFAULT_SERVER_CONFIG (line 8) | const DEFAULT_SERVER_CONFIG: ServerConfig = {
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/client/server-client/index.ts
class WorkflowRuntimeServerClient (line 32) | class WorkflowRuntimeServerClient implements IRuntimeClient {
method constructor (line 35) | constructor() {}
method init (line 37) | public init(config: ServerConfig) {
method request (line 90) | private async request<T>(
method url (line 130) | private url(path: string, queryParams?: Record<string, string>): string {
method isError (line 140) | private isError(output: unknown | undefined): output is ServerError {
method getURL (line 144) | private getURL(path: string): string {
method [FlowGramAPIName.TaskRun] (line 41) | public async [FlowGramAPIName.TaskRun](input: TaskRunInput): Promise<Tas...
method [FlowGramAPIName.TaskReport] (line 48) | public async [FlowGramAPIName.TaskReport](
method [FlowGramAPIName.TaskResult] (line 57) | public async [FlowGramAPIName.TaskResult](
method [FlowGramAPIName.TaskCancel] (line 67) | public async [FlowGramAPIName.TaskCancel](input: TaskCancelInput): Promi...
method [FlowGramAPIName.TaskValidate] (line 80) | public async [FlowGramAPIName.TaskValidate](
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/client/server-client/type.ts
type ServerError (line 6) | interface ServerError {
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/create-runtime-plugin.ts
method onBind (line 17) | onBind({ bind, rebind }, options) {
method onInit (line 28) | onInit(ctx, options) {
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/runtime-service/index.ts
constant SYNC_TASK_REPORT_INTERVAL (line 27) | const SYNC_TASK_REPORT_INTERVAL = 500;
type NodeRunningStatus (line 29) | interface NodeRunningStatus {
class WorkflowRuntimeService (line 36) | class WorkflowRuntimeService {
method isFlowingLine (line 71) | public isFlowingLine(line: WorkflowLineEntity) {
method taskRun (line 75) | public async taskRun(inputs: WorkflowInputs): Promise<string | undefin...
method taskCancel (line 128) | public async taskCancel(): Promise<void> {
method validateForm (line 137) | private async validateForm(): Promise<boolean> {
method reset (line 145) | private reset(): void {
method syncTaskReport (line 155) | private async syncTaskReport(): Promise<void> {
method updateReport (line 183) | private updateReport(report: IReport): void {
FILE: apps/demo-free-layout/src/plugins/runtime-plugin/type.ts
type RuntimeBrowserOptions (line 6) | interface RuntimeBrowserOptions {
type RuntimeServerOptions (line 10) | interface RuntimeServerOptions {
type RuntimePluginOptions (line 15) | type RuntimePluginOptions = RuntimeBrowserOptions | RuntimeServerOptions;
type ServerConfig (line 17) | interface ServerConfig {
FILE: apps/demo-free-layout/src/plugins/variable-panel-plugin/components/full-variable-list.tsx
function FullVariableList (line 9) | function FullVariableList() {
FILE: apps/demo-free-layout/src/plugins/variable-panel-plugin/components/global-variable-editor.tsx
function GlobalVariableEditor (line 16) | function GlobalVariableEditor() {
FILE: apps/demo-free-layout/src/plugins/variable-panel-plugin/components/variable-panel.tsx
function VariablePanel (line 17) | function VariablePanel() {
FILE: apps/demo-free-layout/src/plugins/variable-panel-plugin/variable-panel-layer.tsx
class VariablePanelLayer (line 11) | class VariablePanelLayer extends Layer {
method onReady (line 12) | onReady(): void {
method render (line 24) | render(): JSX.Element {
FILE: apps/demo-free-layout/src/plugins/variable-panel-plugin/variable-panel-plugin.ts
type GetGlobalVariableSchema (line 27) | type GetGlobalVariableSchema = () => IJsonSchema;
method onBind (line 31) | onBind({ bind }) {
method onInit (line 37) | onInit(ctx, opts) {
FILE: apps/demo-free-layout/src/services/custom-service.ts
class CustomService (line 35) | class CustomService {
method save (line 44) | save() {
FILE: apps/demo-free-layout/src/services/validate-service.ts
type ValidateResult (line 16) | interface ValidateResult {
class ValidateService (line 22) | class ValidateService {
method validateLines (line 28) | validateLines() {
method validateNode (line 33) | async validateNode(node: FlowNodeEntity) {
method validateNodes (line 41) | async validateNodes(): Promise<ValidateResult[]> {
FILE: apps/demo-free-layout/src/shortcuts/collapse/index.ts
class CollapseShortcut (line 14) | class CollapseShortcut implements ShortcutsHandler {
method constructor (line 25) | constructor(context: FreeLayoutPluginContext) {
method execute (line 30) | public async execute(): Promise<void> {
FILE: apps/demo-free-layout/src/shortcuts/constants.ts
type FlowCommandId (line 8) | enum FlowCommandId {
FILE: apps/demo-free-layout/src/shortcuts/copy/index.ts
class CopyShortcut (line 32) | class CopyShortcut implements ShortcutsHandler {
method constructor (line 43) | constructor(context: FreeLayoutPluginContext) {
method execute (line 53) | public async execute(): Promise<void> {
method toClipboardData (line 67) | public toClipboardData(nodes?: WorkflowNodeEntity[]): WorkflowClipboar...
method readonly (line 83) | private get readonly(): boolean {
method hasSelectedText (line 90) | private async hasSelectedText(): Promise<boolean> {
method selectedNodes (line 104) | private get selectedNodes(): WorkflowNodeEntity[] {
method isValid (line 113) | private isValid(nodes: WorkflowNodeEntity[]): boolean {
method getValidNodes (line 126) | private getValidNodes(nodes: WorkflowNodeEntity[]): WorkflowNodeEntity...
method toSource (line 143) | private toSource(): WorkflowClipboardSource {
method toJSON (line 152) | private toJSON(nodes: WorkflowNodeEntity[]): WorkflowJSON {
method getNodeJSONs (line 164) | private getNodeJSONs(nodes: WorkflowNodeEntity[]): WorkflowNodeJSON[] {
method getGroupNodeJSON (line 176) | private getGroupNodeJSON(node: WorkflowNodeEntity): WorkflowNodeJSON {
method getEdgeJSONs (line 187) | private getEdgeJSONs(nodes: WorkflowNodeEntity[]): WorkflowEdgeJSON[] {
method expandGroupNodes (line 211) | private expandGroupNodes(nodes: WorkflowNodeEntity[]): WorkflowNodeEnt...
method getEntireBounds (line 223) | private getEntireBounds(nodes: WorkflowNodeEntity[]): WorkflowClipboar...
method write (line 237) | private async write(data: WorkflowClipboardData): Promise<void> {
method notifySuccess (line 249) | private notifySuccess(): void {
FILE: apps/demo-free-layout/src/shortcuts/delete/index.ts
class DeleteShortcut (line 22) | class DeleteShortcut implements ShortcutsHandler {
method constructor (line 38) | constructor(context: FreeLayoutPluginContext) {
method execute (line 49) | public async execute(nodes?: WorkflowNodeEntity[]): Promise<void> {
method readonly (line 81) | private get readonly(): boolean {
method isValid (line 88) | private isValid(nodes: WorkflowNodeEntity[]): boolean {
method removeNode (line 105) | private removeNode(node: WorkflowNodeEntity): void {
method removeLine (line 121) | private removeLine(line: WorkflowLineEntity): void {
FILE: apps/demo-free-layout/src/shortcuts/expand/index.ts
class ExpandShortcut (line 14) | class ExpandShortcut implements ShortcutsHandler {
method constructor (line 25) | constructor(context: FreeLayoutPluginContext) {
method execute (line 30) | public async execute(): Promise<void> {
FILE: apps/demo-free-layout/src/shortcuts/paste/index.ts
class PasteShortcut (line 31) | class PasteShortcut implements ShortcutsHandler {
method constructor (line 53) | constructor(context: FreeLayoutPluginContext) {
method execute (line 67) | public async execute(): Promise<WorkflowNodeEntity[] | undefined> {
method apply (line 93) | public apply(data: WorkflowClipboardData): WorkflowNodeEntity[] {
method readonly (line 121) | private get readonly(): boolean {
method isValidData (line 125) | private isValidData(data?: WorkflowClipboardData): boolean {
method tryReadClipboard (line 158) | private async tryReadClipboard(): Promise<WorkflowClipboardData | unde...
method calcPasteOffset (line 171) | private calcPasteOffset(boundsData: WorkflowClipboardRect): IPoint {
method applyOffset (line 186) | private applyOffset(params: {
method getSelectedContainer (line 213) | private getSelectedContainer(): WorkflowNodeEntity | undefined {
method selectNodes (line 219) | private selectNodes(nodes: WorkflowNodeEntity[]): void {
method scrollNodesToView (line 224) | private async scrollNodesToView(nodes: WorkflowNodeEntity[]): Promise<...
method nextTick (line 232) | private async nextTick(): Promise<void> {
FILE: apps/demo-free-layout/src/shortcuts/paste/traverse.ts
type TraverseValue (line 7) | type TraverseValue = any;
type TraverseNode (line 10) | interface TraverseNode {
type TraverseContext (line 19) | interface TraverseContext {
type TraverseHandler (line 29) | type TraverseHandler = (context: TraverseContext) => void;
FILE: apps/demo-free-layout/src/shortcuts/select-all/index.ts
class SelectAllShortcut (line 15) | class SelectAllShortcut implements ShortcutsHandler {
method constructor (line 24) | constructor(context: FreeLayoutPluginContext) {
method execute (line 30) | public async execute(): Promise<void> {
FILE: apps/demo-free-layout/src/shortcuts/shortcuts.ts
function shortcuts (line 17) | function shortcuts(shortcutsRegistry: ShortcutsRegistry, ctx: FreeLayout...
FILE: apps/demo-free-layout/src/shortcuts/type.ts
type WorkflowClipboardSource (line 10) | interface WorkflowClipboardSource {
type WorkflowClipboardRect (line 15) | interface WorkflowClipboardRect {
type WorkflowClipboardData (line 22) | interface WorkflowClipboardData {
FILE: apps/demo-free-layout/src/shortcuts/zoom-in/index.ts
class ZoomInShortcut (line 14) | class ZoomInShortcut implements ShortcutsHandler {
method constructor (line 21) | constructor(context: FreeLayoutPluginContext) {
method execute (line 26) | public async execute(): Promise<void> {
FILE: apps/demo-free-layout/src/shortcuts/zoom-out/index.ts
class ZoomOutShortcut (line 14) | class ZoomOutShortcut implements ShortcutsHandler {
method constructor (line 21) | constructor(context: FreeLayoutPluginContext) {
method execute (line 26) | public async execute(): Promise<void> {
FILE: apps/demo-free-layout/src/typings/json-schema.ts
type BasicType (line 8) | type BasicType = JsonSchemaBasicType;
type JsonSchema (line 9) | type JsonSchema = IJsonSchema;
FILE: apps/demo-free-layout/src/typings/node.ts
type FlowNodeJSON (line 23) | interface FlowNodeJSON extends FlowNodeJSONDefault {
type FlowNodeMeta (line 52) | interface FlowNodeMeta extends WorkflowNodeMeta {
type FlowNodeRegistry (line 63) | interface FlowNodeRegistry extends FlowNodeRegistryDefault {
type FlowDocumentJSON (line 74) | interface FlowDocumentJSON {
FILE: apps/demo-free-layout/src/utils/can-contain-node.ts
function canContainNode (line 16) | function canContainNode(
FILE: apps/demo-free-layout/src/utils/toggle-loop-expanded.ts
function toggleLoopExpanded (line 11) | function toggleLoopExpanded(
FILE: apps/demo-materials/src/assets/icon-cancel.tsx
type Props (line 6) | interface Props {
FILE: apps/demo-materials/src/assets/icon-comment.tsx
type IconCommentProps (line 8) | interface IconCommentProps {
FILE: apps/demo-materials/src/assets/icon-mouse.tsx
function IconMouse (line 6) | function IconMouse(props: { width?: number; height?: number }) {
FILE: apps/demo-materials/src/assets/icon-pad.tsx
function IconPad (line 6) | function IconPad(props: { width?: number; height?: number }) {
FILE: apps/demo-materials/src/assets/icon-success.tsx
type Props (line 6) | interface Props {
FILE: apps/demo-materials/src/assets/icon-warning.tsx
type Props (line 6) | interface Props {
FILE: apps/demo-materials/src/components/form-header/index.tsx
function FormHeader (line 12) | function FormHeader() {
FILE: apps/demo-materials/src/components/form-header/title-input.tsx
function TitleInput (line 16) | function TitleInput(): JSX.Element {
FILE: apps/demo-materials/src/components/free-editor/hooks/use-editor-props.tsx
type EditorProps (line 20) | interface EditorProps {
function passthrough (line 28) | function passthrough<T>(a: T) {
method getNodeDefaultRegistry (line 71) | getNodeDefaultRegistry(type) {
method onContentChange (line 105) | onContentChange(ctx, event) {
method onAllLayersRendered (line 129) | onAllLayersRendered(ctx) {
method onDispose (line 138) | onDispose() {
FILE: apps/demo-materials/src/components/free-editor/index.tsx
type EditorProps (line 17) | interface EditorProps {
FILE: apps/demo-materials/src/components/free-editor/plugins/debug-panel-plugin/components/debug-panel.tsx
function DebugPanel (line 30) | function DebugPanel() {
FILE: apps/demo-materials/src/components/free-editor/plugins/debug-panel-plugin/components/full-variable-list.tsx
function FullVariableList (line 9) | function FullVariableList() {
FILE: apps/demo-materials/src/components/free-editor/plugins/debug-panel-plugin/components/workflow-json-editor.tsx
function WorkflowJsonEditor (line 12) | function WorkflowJsonEditor() {
FILE: apps/demo-materials/src/components/free-editor/plugins/debug-panel-plugin/debug-panel-layer.tsx
class DebugPanelLayer (line 11) | class DebugPanelLayer extends Layer {
method onReady (line 12) | onReady(): void {
method render (line 25) | render(): JSX.Element {
FILE: apps/demo-materials/src/components/free-editor/plugins/debug-panel-plugin/debug-panel-plugin.ts
method onInit (line 11) | onInit(ctx, opts) {
FILE: apps/demo-materials/src/components/free-form-meta-story-builder/constants.tsx
constant DEFAULT_FORM_META (line 29) | const DEFAULT_FORM_META = {
constant START_REGISTRY (line 38) | const START_REGISTRY: FlowNodeRegistry<FlowNodeMeta> = {
method canAdd (line 55) | canAdd() {
constant END_REGISTRY (line 81) | const END_REGISTRY: FlowNodeRegistry<FlowNodeMeta> = {
method canAdd (line 98) | canAdd() {
constant BLOCK_START_REGISTRY (line 118) | const BLOCK_START_REGISTRY: FlowNodeRegistry<FlowNodeMeta> = {
constant BLOCK_END_REGISTRY (line 143) | const BLOCK_END_REGISTRY: FlowNodeRegistry<FlowNodeMeta> = {
constant VARIABLE_REGISTRY (line 168) | const VARIABLE_REGISTRY: FlowNodeRegistry<FlowNodeMeta> = {
constant CUSTOM_REGISTRY (line 198) | const CUSTOM_REGISTRY: FlowNodeRegistry<FlowNodeMeta> = {
method canAdd (line 214) | canAdd() {
FILE: apps/demo-materials/src/components/free-form-meta-story-builder/index.tsx
type NodeId (line 29) | type NodeId = string;
type PropsType (line 30) | interface PropsType {
function FreeFormMetaStoryBuilder (line 42) | function FreeFormMetaStoryBuilder(props: PropsType) {
FILE: apps/demo-materials/src/components/free-form-meta-story-builder/initial-data.tsx
constant INITIAL_DATA (line 8) | const INITIAL_DATA: WorkflowJSON = {
FILE: apps/demo-materials/src/stories/components/blur-input.stories.tsx
type Story (line 23) | type Story = StoryObj<typeof meta>;
FILE: apps/demo-materials/src/stories/components/inputs-values-tree.stories.tsx
type Story (line 23) | type Story = StoryObj<typeof meta>;
FILE: apps/demo-materials/src/stories/components/json-schema-creator.stories.tsx
type Story (line 58) | type Story = StoryObj<typeof meta>;
FILE: apps/demo-materials/src/stories/components/sql-editor-with-variables.stories.tsx
type Story (line 23) | type Story = StoryObj<typeof meta>;
FILE: apps/demo-materials/src/stories/components/variable-selector.stories.tsx
type Story (line 23) | type Story = StoryObj<typeof meta>;
FILE: apps/demo-materials/src/stories/hello.stories.tsx
type HelloWorldProps (line 10) | interface HelloWorldProps {
type Story (line 94) | type Story = StoryObj<typeof meta>;
FILE: apps/demo-nextjs-antd/src/app/layout.tsx
function RootLayout (line 25) | function RootLayout({
FILE: apps/demo-nextjs-antd/src/app/page.tsx
function Home (line 9) | function Home() {
FILE: apps/demo-nextjs-antd/src/editor/assets/icon-comment.tsx
type IconCommentProps (line 8) | interface IconCommentProps {
FILE: apps/demo-nextjs-antd/src/editor/assets/icon-mouse.tsx
function IconMouse (line 6) | function IconMouse(props: { width?: number; height?: number }) {
FILE: apps/demo-nextjs-antd/src/editor/assets/icon-pad.tsx
function IconPad (line 6) | function IconPad(props: { width?: number; height?: number }) {
FILE: apps/demo-nextjs-antd/src/editor/components/base-node/node-wrapper.tsx
type NodeWrapperProps (line 17) | interface NodeWrapperProps {
FILE: apps/demo-nextjs-antd/src/editor/components/base-node/utils.ts
function scrollToView (line 8) | function scrollToView(
FILE: apps/demo-nextjs-antd/src/editor/components/group/color.ts
type GroupColor (line 6) | type GroupColor = {
FILE: apps/demo-nextjs-antd/src/editor/components/group/components/background.tsx
type GroupBackgroundProps (line 13) | interface GroupBackgroundProps {
FILE: apps/demo-nextjs-antd/src/editor/components/group/components/header.tsx
type GroupHeaderProps (line 13) | interface GroupHeaderProps {
FILE: apps/demo-nextjs-antd/src/editor/components/group/components/icon-group.tsx
type IconGroupProps (line 8) | interface IconGroupProps {
FILE: apps/demo-nextjs-antd/src/editor/components/group/components/tips/global-store.ts
constant STORAGE_KEY (line 6) | const STORAGE_KEY = 'workflow-move-into-group-tip-visible';
constant STORAGE_VALUE (line 7) | const STORAGE_VALUE = 'false';
class TipsGlobalStore (line 9) | class TipsGlobalStore {
method instance (line 12) | public static get instance(): TipsGlobalStore {
method isClosed (line 21) | public isClosed(): boolean {
method close (line 25) | public close(): void {
method isCloseForever (line 29) | public isCloseForever(): boolean {
method closeForever (line 33) | public closeForever(): void {
FILE: apps/demo-nextjs-antd/src/editor/components/group/components/ungroup.tsx
type UngroupButtonProps (line 14) | interface UngroupButtonProps {
FILE: apps/demo-nextjs-antd/src/editor/components/group/constant.ts
constant HEADER_HEIGHT (line 6) | const HEADER_HEIGHT = 30;
constant HEADER_PADDING (line 7) | const HEADER_PADDING = 5;
type GroupField (line 9) | enum GroupField {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/blank-area.tsx
type IBlankArea (line 13) | interface IBlankArea {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/border-area.tsx
type IBorderArea (line 12) | interface IBorderArea {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/container.tsx
type ICommentContainer (line 8) | interface ICommentContainer {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/content-drag-area.tsx
type IContentDragArea (line 13) | interface IContentDragArea {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/drag-area.tsx
type IDragArea (line 12) | interface IDragArea {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/editor.tsx
type ICommentEditor (line 13) | interface ICommentEditor {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/more-button.tsx
type IMoreButton (line 14) | interface IMoreButton {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/components/resize-area.tsx
type IResizeArea (line 12) | interface IResizeArea {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/constant.ts
type CommentEditorFormField (line 6) | enum CommentEditorFormField {
type CommentEditorEvent (line 12) | enum CommentEditorEvent {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/model.ts
class CommentEditorModel (line 11) | class CommentEditorModel {
method value (line 22) | public get value(): string {
method setValue (line 27) | public setValue(value: string = CommentEditorDefaultValue): void {
method element (line 42) | public set element(el: HTMLTextAreaElement) {
method element (line 50) | public get element(): HTMLTextAreaElement {
method setFocus (line 55) | public setFocus(focused: boolean): void {
method selectEnd (line 71) | public selectEnd(): void {
method focused (line 82) | public get focused(): boolean {
method deselect (line 87) | private deselect(): void {
method initialized (line 97) | private get initialized(): boolean {
method syncEditorValue (line 105) | private syncEditorValue(): void {
FILE: apps/demo-nextjs-antd/src/editor/components/node-comment/type.ts
type CommentEditorChangeEvent (line 8) | interface CommentEditorChangeEvent {
type CommentEditorMultiSelectEvent (line 13) | interface CommentEditorMultiSelectEvent {
type CommentEditorSelectEvent (line 17) | interface CommentEditorSelectEvent {
type CommentEditorBlurEvent (line 21) | interface CommentEditorBlurEvent {
type CommentEditorEventParams (line 25) | type CommentEditorEventParams =
FILE: apps/demo-nextjs-antd/src/editor/components/node-menu/index.tsx
type NodeMenuProps (line 24) | interface NodeMenuProps {
FILE: apps/demo-nextjs-antd/src/editor/components/node-panel/node-list.tsx
type NodeProps (line 36) | interface NodeProps {
function Node (line 43) | function Node(props: NodeProps) {
type NodeListProps (line 64) | interface NodeListProps {
FILE: apps/demo-nextjs-antd/src/editor/components/selector-box-popover/index.tsx
constant BUTTON_HEIGHT (line 16) | const BUTTON_HEIGHT = 24;
FILE: apps/demo-nextjs-antd/src/editor/components/sidebar/sidebar-node-renderer.tsx
function SidebarNodeRenderer (line 10) | function SidebarNodeRenderer(props: { node: FlowNodeEntity }) {
FILE: apps/demo-nextjs-antd/src/editor/components/sidebar/sidebar-provider.tsx
function SidebarProvider (line 10) | function SidebarProvider({ children }: { children: React.ReactNode }) {
FILE: apps/demo-nextjs-antd/src/editor/context/node-render-context.ts
type INodeRenderContext (line 10) | interface INodeRenderContext extends NodeRenderReturnType {}
FILE: apps/demo-nextjs-antd/src/editor/form-components/feedback.tsx
type StatePanelProps (line 9) | interface StatePanelProps {
FILE: apps/demo-nextjs-antd/src/editor/form-components/form-content/index.tsx
function FormContent (line 19) | function FormContent(props: { children?: React.ReactNode }) {
FILE: apps/demo-nextjs-antd/src/editor/form-components/form-header/index.tsx
function FormHeader (line 22) | function FormHeader() {
FILE: apps/demo-nextjs-antd/src/editor/form-components/form-header/title-input.tsx
function TitleInput (line 16) | function TitleInput(props: {
FILE: apps/demo-nextjs-antd/src/editor/form-components/form-inputs/index.tsx
function FormInputs (line 14) | function FormInputs() {
FILE: apps/demo-nextjs-antd/src/editor/form-components/form-item/index.tsx
type FormItemProps (line 16) | interface FormItemProps {
function FormItem (line 24) | function FormItem({
FILE: apps/demo-nextjs-antd/src/editor/form-components/form-outputs/index.tsx
function FormOutputs (line 13) | function FormOutputs() {
FILE: apps/demo-nextjs-antd/src/editor/form-components/properties-edit/index.tsx
type PropertiesEditProps (line 15) | interface PropertiesEditProps {
FILE: apps/demo-nextjs-antd/src/editor/form-components/properties-edit/property-edit.tsx
type PropertyEditProps (line 15) | interface PropertyEditProps {
FILE: apps/demo-nextjs-antd/src/editor/form-components/type-tag.tsx
type PropsType (line 10) | interface PropsType {
function TypeTag (line 24) | function TypeTag({ name, type, isArray, className }: PropsType) {
FILE: apps/demo-nextjs-antd/src/editor/form-components/value-display/index.tsx
type ValueDisplayProps (line 9) | interface ValueDisplayProps {
FILE: apps/demo-nextjs-antd/src/editor/hooks/use-editor-props.tsx
method getNodeDefaultRegistry (line 58) | getNodeDefaultRegistry(type) {
method onContentChange (line 87) | onContentChange(ctx, event) {
method onAllLayersRendered (line 116) | onAllLayersRendered(ctx) {
method onDispose (line 123) | onDispose() {
FILE: apps/demo-nextjs-antd/src/editor/hooks/use-is-sidebar.ts
function useIsSidebar (line 10) | function useIsSidebar() {
FILE: apps/demo-nextjs-antd/src/editor/hooks/use-node-render-context.ts
function useNodeRenderContext (line 10) | function useNodeRenderContext() {
FILE: apps/demo-nextjs-antd/src/editor/nodes/condition/condition-inputs/index.tsx
type ConditionValue (line 23) | interface ConditionValue {
function ConditionInputs (line 28) | function ConditionInputs() {
FILE: apps/demo-nextjs-antd/src/editor/nodes/condition/index.ts
method onAdd (line 27) | onAdd() {
FILE: apps/demo-nextjs-antd/src/editor/nodes/constants.ts
type WorkflowNodeType (line 6) | enum WorkflowNodeType {
FILE: apps/demo-nextjs-antd/src/editor/nodes/end/index.ts
method canAdd (line 34) | canAdd() {
FILE: apps/demo-nextjs-antd/src/editor/nodes/llm/index.ts
method onAdd (line 26) | onAdd() {
FILE: apps/demo-nextjs-antd/src/editor/nodes/loop/index.ts
method selectable (line 56) | selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {
method onAdd (line 66) | onAdd() {
FILE: apps/demo-nextjs-antd/src/editor/nodes/loop/loop-form-render.tsx
type LoopNodeJSON (line 13) | interface LoopNodeJSON extends FlowNodeJSON {
FILE: apps/demo-nextjs-antd/src/editor/nodes/start/index.ts
method canAdd (line 37) | canAdd() {
FILE: apps/demo-nextjs-antd/src/editor/plugins/context-menu-plugin/context-menu-layer.tsx
class ContextMenuLayer (line 18) | class ContextMenuLayer extends Layer {
method onReady (line 25) | onReady() {
method openNodePanel (line 33) | openNodePanel(e: MouseEvent) {
FILE: apps/demo-nextjs-antd/src/editor/plugins/context-menu-plugin/context-menu-plugin.ts
type ContextMenuPluginOptions (line 14) | interface ContextMenuPluginOptions {}
method onInit (line 25) | onInit(ctx, options) {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/collapse/index.ts
class CollapseShortcut (line 14) | class CollapseShortcut implements ShortcutsHandler {
method constructor (line 25) | constructor(context: FreeLayoutPluginContext) {
method execute (line 30) | public async execute(): Promise<void> {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/constants.ts
type FlowCommandId (line 8) | enum FlowCommandId {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/copy/index.ts
class CopyShortcut (line 30) | class CopyShortcut implements ShortcutsHandler {
method constructor (line 39) | constructor(context: FreeLayoutPluginContext) {
method execute (line 48) | public async execute(): Promise<void> {
method hasSelectedText (line 62) | private async hasSelectedText(): Promise<boolean> {
method selectedNodes (line 76) | private get selectedNodes(): WorkflowNodeEntity[] {
method isValid (line 85) | private isValid(nodes: WorkflowNodeEntity[]): boolean {
method toClipboardData (line 98) | toClipboardData(nodes?: WorkflowNodeEntity[]): WorkflowClipboardData {
method getValidNodes (line 114) | private getValidNodes(nodes: WorkflowNodeEntity[]): WorkflowNodeEntity...
method toSource (line 131) | private toSource(): WorkflowClipboardSource {
method toJSON (line 140) | private toJSON(nodes: WorkflowNodeEntity[]): WorkflowJSON {
method getNodeJSONs (line 152) | private getNodeJSONs(nodes: WorkflowNodeEntity[]): WorkflowNodeJSON[] {
method getEdgeJSONs (line 172) | private getEdgeJSONs(nodes: WorkflowNodeEntity[]): WorkflowEdgeJSON[] {
method getEntireBounds (line 195) | private getEntireBounds(nodes: WorkflowNodeEntity[]): WorkflowClipboar...
method write (line 209) | private async write(data: WorkflowClipboardData): Promise<void> {
method notifySuccess (line 221) | private notifySuccess(): void {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/delete/index.ts
class DeleteShortcut (line 21) | class DeleteShortcut implements ShortcutsHandler {
method constructor (line 35) | constructor(context: FreeLayoutPluginContext) {
method execute (line 45) | public async execute(nodes?: WorkflowNodeEntity[]): Promise<void> {
method isValid (line 74) | private isValid(nodes: WorkflowNodeEntity[]): boolean {
method removeNode (line 91) | private removeNode(node: WorkflowNodeEntity): void {
method removeLine (line 107) | private removeLine(line: WorkflowLineEntity): void {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/expand/index.ts
class ExpandShortcut (line 14) | class ExpandShortcut implements ShortcutsHandler {
method constructor (line 25) | constructor(context: FreeLayoutPluginContext) {
method execute (line 30) | public async execute(): Promise<void> {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/paste/index.ts
class PasteShortcut (line 28) | class PasteShortcut implements ShortcutsHandler {
method constructor (line 46) | constructor(context: FreeLayoutPluginContext) {
method execute (line 58) | public async execute(): Promise<WorkflowNodeEntity[] | undefined> {
method apply (line 81) | public apply(data: WorkflowClipboardData): WorkflowNodeEntity[] {
method isValidData (line 99) | private isValidData(data?: WorkflowClipboardData): boolean {
method tryReadClipboard (line 117) | private async tryReadClipboard(): Promise<WorkflowClipboardData | unde...
method calcPasteOffset (line 130) | private calcPasteOffset(boundsData: WorkflowClipboardRect): IPoint {
method applyOffset (line 145) | private applyOffset(params: {
method getSelectedContainer (line 172) | private getSelectedContainer(): WorkflowNodeEntity | undefined {
method selectNodes (line 178) | private selectNodes(nodes: WorkflowNodeEntity[]): void {
method scrollNodesToView (line 183) | private async scrollNodesToView(nodes: WorkflowNodeEntity[]): Promise<...
method nextTick (line 191) | private async nextTick(): Promise<void> {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/paste/traverse.ts
type TraverseValue (line 7) | type TraverseValue = any;
type TraverseNode (line 10) | interface TraverseNode {
type TraverseContext (line 19) | interface TraverseContext {
type TraverseHandler (line 29) | type TraverseHandler = (context: TraverseContext) => void;
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/select-all/index.ts
class SelectAllShortcut (line 15) | class SelectAllShortcut implements ShortcutsHandler {
method constructor (line 24) | constructor(context: FreeLayoutPluginContext) {
method execute (line 30) | public async execute(): Promise<void> {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/shortcuts.ts
function shortcuts (line 17) | function shortcuts(shortcutsRegistry: ShortcutsRegistry, ctx: FreeLayout...
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/type.ts
type WorkflowClipboardSource (line 10) | interface WorkflowClipboardSource {
type WorkflowClipboardRect (line 15) | interface WorkflowClipboardRect {
type WorkflowClipboardData (line 22) | interface WorkflowClipboardData {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/zoom-in/index.ts
class ZoomInShortcut (line 14) | class ZoomInShortcut implements ShortcutsHandler {
method constructor (line 21) | constructor(context: FreeLayoutPluginContext) {
method execute (line 26) | public async execute(): Promise<void> {
FILE: apps/demo-nextjs-antd/src/editor/shortcuts/zoom-out/index.ts
class ZoomOutShortcut (line 14) | class ZoomOutShortcut implements ShortcutsHandler {
method constructor (line 21) | constructor(context: FreeLayoutPluginContext) {
method execute (line 26) | public async execute(): Promise<void> {
FILE: apps/demo-nextjs-antd/src/editor/typings/flow-value/index.ts
type IFlowConstantValue (line 6) | interface IFlowConstantValue {
type IFlowRefValue (line 11) | interface IFlowRefValue {
type IFlowExpressionValue (line 16) | interface IFlowExpressionValue {
type IFlowTemplateValue (line 21) | interface IFlowTemplateValue {
type IFlowValue (line 26) | type IFlowValue =
type IFlowConstantRefValue (line 32) | type IFlowConstantRefValue = IFlowConstantValue | IFlowRefValue;
FILE: apps/demo-nextjs-antd/src/editor/typings/json-schema/index.ts
type BasicType (line 8) | type BasicType = IBasicJsonSchema;
type JsonSchema (line 9) | type JsonSchema = IJsonSchema;
FILE: apps/demo-nextjs-antd/src/editor/typings/node.ts
type FlowNodeJSON (line 23) | interface FlowNodeJSON extends FlowNodeJSONDefault {
type FlowNodeMeta (line 52) | interface FlowNodeMeta extends WorkflowNodeMeta {
type FlowNodeRegistry (line 60) | interface FlowNodeRegistry extends FlowNodeRegistryDefault {
type FlowDocumentJSON (line 71) | interface FlowDocumentJSON {
FILE: apps/demo-nextjs/src/app/api/runtime/route.ts
function POST (line 10) | async function POST(request: Request) {
function GET (line 26) | async function GET() {
FILE: apps/demo-nextjs/src/app/layout.tsx
function RootLayout (line 25) | function RootLayout({
FILE: apps/demo-nextjs/src/app/page.tsx
function Home (line 9) | function Home() {
FILE: apps/demo-nextjs/src/editor/hooks/use-editor-props.tsx
method getNodeDefaultRegistry (line 42) | getNodeDefaultRegistry(type) {
method onContentChange (line 69) | onContentChange(ctx, event) {
method onAllLayersRendered (line 92) | onAllLayersRendered(ctx) {
method onDispose (line 99) | onDispose() {
FILE: apps/demo-nextjs/src/runtime/models/runtime/model.ts
class WorkflowRuntimeModel (line 8) | class WorkflowRuntimeModel implements IWorkflowRuntimeModel {
method instance (line 11) | public static get instance(): WorkflowRuntimeModel {
method run (line 18) | public async run(): Promise<void> {}
FILE: apps/demo-nextjs/src/runtime/models/runtime/type.ts
type IWorkflowRuntimeModel (line 6) | interface IWorkflowRuntimeModel {
FILE: apps/demo-node-form/src/components/field-wrapper.tsx
type FieldWrapperProps (line 10) | interface FieldWrapperProps {
FILE: apps/demo-node-form/src/editor.tsx
type EditorProps (line 16) | interface EditorProps {
FILE: apps/demo-node-form/src/form-meta.tsx
constant DEFAULT_FORM_META (line 56) | const DEFAULT_FORM_META = formMeta;
FILE: apps/demo-node-form/src/hooks/use-editor-props.tsx
type EditorProps (line 23) | interface EditorProps {
method getNodeDefaultRegistry (line 56) | getNodeDefaultRegistry(type) {
method onContentChange (line 97) | onContentChange(ctx, event) {
method onAllLayersRendered (line 120) | onAllLayersRendered(ctx) {
method onDispose (line 127) | onDispose() {
FILE: apps/demo-node-form/src/initial-data.ts
constant DEFAULT_INITIAL_DATA (line 8) | const DEFAULT_INITIAL_DATA: WorkflowJSON = {
FILE: apps/demo-node-form/src/node-registries.tsx
constant DEFAULT_DEMO_REGISTRY (line 10) | const DEFAULT_DEMO_REGISTRY: WorkflowNodeRegistry = {
FILE: apps/demo-playground/src/components/card.tsx
function StaticCard (line 10) | function StaticCard() {
function DragableCard (line 32) | function DragableCard() {
FILE: apps/demo-playground/src/editor.tsx
function PlaygroundEditor (line 24) | function PlaygroundEditor(props: { className?: string }) {
FILE: apps/demo-react-16/src/components/node-form-panel/sidebar-renderer.tsx
type NodeFormPanelProps (line 11) | interface NodeFormPanelProps {
FILE: apps/demo-react-16/src/components/tools.tsx
function Tools (line 10) | function Tools() {
FILE: apps/demo-react-16/src/hooks/use-editor-props.tsx
method getNodeDefaultRegistry (line 48) | getNodeDefaultRegistry(type) {
method onContentChange (line 99) | onContentChange(ctx, event) {
method onAllLayersRendered (line 122) | onAllLayersRendered(ctx) {
method onDispose (line 129) | onDispose() {
FILE: apps/demo-vite/src/components/tools.tsx
function Tools (line 10) | function Tools() {
FILE: apps/demo-vite/src/hooks/use-editor-props.tsx
method getNodeDefaultRegistry (line 46) | getNodeDefaultRegistry(type) {
method onContentChange (line 88) | onContentChange(ctx, event) {
method onAllLayersRendered (line 111) | onAllLayersRendered(ctx) {
method onDispose (line 118) | onDispose() {
FILE: apps/docs/components/code-preview/index.tsx
type CodePreviewProps (line 11) | interface CodePreviewProps {
FILE: apps/docs/components/fixed-examples/step-5/use-editor-props.tsx
function useEditorProps (line 14) | function useEditorProps(): FixedLayoutProps {
FILE: apps/docs/components/fixed-examples/step-6/node-registries.tsx
method onAdd (line 39) | onAdd() {
method onAdd (line 68) | onAdd() {
FILE: apps/docs/components/fixed-examples/step-6/use-editor-props.tsx
function useEditorProps (line 14) | function useEditorProps(): FixedLayoutProps {
FILE: apps/docs/components/fixed-examples/step-7/node-registries.tsx
method onAdd (line 39) | onAdd() {
method onAdd (line 68) | onAdd() {
FILE: apps/docs/components/fixed-examples/step-7/use-editor-props.tsx
function useEditorProps (line 14) | function useEditorProps(): FixedLayoutProps {
FILE: apps/docs/components/fixed-layout-simple/composite-nodes-preview.tsx
function CompositeNodesPreview (line 18) | function CompositeNodesPreview(props: { cellHeight?: number }) {
FILE: apps/docs/components/form-materials/components/batch-outputs.tsx
type BatchOutputsValueType (line 31) | type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
FILE: apps/docs/components/form-materials/components/condition-context.tsx
constant OPS (line 31) | const OPS: ConditionOpConfigs = {
constant RULES (line 38) | const RULES: Record<string, IConditionRule> = {
FILE: apps/docs/components/form-materials/components/prompt-editor-with-variables.tsx
constant STRING_ONLY_SCHEMA (line 55) | const STRING_ONLY_SCHEMA = { type: 'string' };
FILE: apps/docs/components/form-materials/effects/provide-batch-input.tsx
type BatchOutputsValueType (line 37) | type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
FILE: apps/docs/components/form-materials/form-plugins/batch-outputs-plugin.tsx
type BatchOutputsValueType (line 31) | type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
FILE: apps/docs/components/free-examples/step-6/use-editor-props.tsx
method getNodeDefaultRegistry (line 38) | getNodeDefaultRegistry(type) {
FILE: apps/docs/components/free-examples/step-7/use-editor-props.tsx
method getNodeDefaultRegistry (line 48) | getNodeDefaultRegistry(type) {
FILE: apps/docs/components/materials.tsx
function MaterialDisplay (line 10) | function MaterialDisplay(props: any) {
FILE: apps/docs/components/node-form/array/node-registry.tsx
type FormData (line 84) | interface FormData {
FILE: apps/docs/components/node-form/dynamic/node-registry.tsx
type FormData (line 17) | interface FormData {
FILE: apps/docs/components/node-form/effect/node-registry.tsx
type FormData (line 53) | interface FormData {
FILE: apps/docs/rspress.config.ts
method rspack (line 38) | rspack(options, { mergeConfig }) {
FILE: apps/docs/scripts/auto-generate.ts
function generateDocs (line 20) | async function generateDocs() {
function fileExists (line 150) | async function fileExists(path: string): Promise<boolean> {
FILE: apps/docs/scripts/patch.ts
function patchLinks (line 11) | async function patchLinks(outputDir: string) {
function patchGeneratedApiDocs (line 61) | async function patchGeneratedApiDocs(absoluteApiDir: string) {
FILE: apps/docs/theme/components/background/index.tsx
type PerformanceConfig (line 12) | interface PerformanceConfig {
type TrailParticle (line 101) | interface TrailParticle {
type MeteorParticle (line 114) | interface MeteorParticle {
class Trail (line 144) | class Trail {
method constructor (line 149) | constructor(parent: MeteorParticle) {
FILE: apps/docs/theme/components/logo/port.tsx
type WorkflowPortRenderProps (line 17) | interface WorkflowPortRenderProps {
FILE: apps/docs/theme/components/logo/position-groups.ts
type PositionGroup (line 8) | interface PositionGroup {
FILE: apps/docs/theme/components/logo/use-editor-props.tsx
method getNodeDefaultRegistry (line 56) | getNodeDefaultRegistry(type) {
FILE: apps/docs/theme/index.tsx
function getCustomMDXComponent (line 19) | function getCustomMDXComponent() {
function HomeLayout (line 37) | function HomeLayout(props: Parameters<typeof BaseHomeLayout>[0]) {
FILE: common/autoinstallers/dep-check/dep-check.ts
function runCheckDep (line 59) | async function runCheckDep(): Promise<void> {
FILE: common/autoinstallers/license-header/index.js
function addLicenseHeader (line 43) | function addLicenseHeader(targetDir, licenseContent, options = {}) {
FILE: common/autoinstallers/rush-commands/check-circular-dependency.mjs
function getPackageDependencies (line 10) | function getPackageDependencies(packageName, depsMap) {
function main (line 24) | function main() {
FILE: common/autoinstallers/rush-commitlint/utils.js
function getChangedPackages (line 18) | function getChangedPackages(changedFiles) {
FILE: common/autoinstallers/rush-lint-staged/utils.js
function withProjectFolder (line 22) | function withProjectFolder(changedFiles) {
function excludeIgnoredFiles (line 51) | async function excludeIgnoredFiles(changedFiles) {
function getChangedProjects (line 81) | function getChangedProjects(changedFiles) {
FILE: common/config/rush/.pnpmfile.cjs
function readPackage (line 34) | function readPackage(packageJson, context) {
FILE: common/scripts/install-run-rush.js
function __webpack_require__ (line 45) | function __webpack_require__(moduleId) {
function _getRushVersion (line 127) | function _getRushVersion(logger) {
function _getBin (line 148) | function _getBin(scriptName) {
function _run (line 158) | function _run() {
FILE: common/scripts/install-run.js
function _trimNpmrcFile (line 49) | function _trimNpmrcFile(options) {
function trimNpmrcFileLines (line 79) | function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSy...
function _copyAndTrimNpmrcFile (line 146) | function _copyAndTrimNpmrcFile(options) {
function syncNpmrc (line 154) | function syncNpmrc(options) {
function isVariableSetInNpmrcFile (line 183) | function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, suppor...
function __webpack_require__ (line 243) | function __webpack_require__(moduleId) {
function _parsePackageSpecifier (line 345) | function _parsePackageSpecifier(rawPackageSpecifier) {
function getNpmPath (line 371) | function getNpmPath() {
function _ensureFolder (line 397) | function _ensureFolder(folderPath) {
function _ensureAndJoinPath (line 410) | function _ensureAndJoinPath(baseFolder, ...pathSegments) {
function _getRushTempFolder (line 426) | function _getRushTempFolder(rushCommonFolder) {
function _compareVersionStrings (line 442) | function _compareVersionStrings(a, b) {
function _resolvePackageVersion (line 456) | function _resolvePackageVersion(logger, rushCommonFolder, { name, versio...
function findRushJsonFolder (line 530) | function findRushJsonFolder() {
function _isPackageAlreadyInstalled (line 553) | function _isPackageAlreadyInstalled(packageInstallFolder) {
function _deleteFile (line 569) | function _deleteFile(file) {
function _cleanInstallFolder (line 585) | function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockF...
function _createPackageJson (line 607) | function _createPackageJson(packageInstallFolder, name, version) {
function _installPackage (line 629) | function _installPackage(logger, packageInstallFolder, name, version, co...
function _getBinPath (line 652) | function _getBinPath(packageInstallFolder, binName) {
function _getPlatformPath (line 660) | function _getPlatformPath(platformPath) {
function _isWindows (line 663) | function _isWindows() {
function _writeFlagFile (line 669) | function _writeFlagFile(packageInstallFolder) {
function installAndRun (line 678) | function installAndRun(logger, packageName, packageVersion, packageBinNa...
function runWithErrorAndStatusCode (line 730) | function runWithErrorAndStatusCode(logger, fn) {
function _run (line 740) | function _run() {
FILE: config/eslint-config/src/defineFlatConfig.js
function defineFlatConfig (line 8) | function defineFlatConfig(config) {
FILE: config/eslint-config/src/defineFlatConfig.ts
type ESLintConfigMode (line 10) | type ESLintConfigMode = 'web' | 'node' | 'base';
type EnhanceESLintConfig (line 12) | interface EnhanceESLintConfig extends ESLintConfig {
FILE: e2e/fixed-layout/tests/drag.spec.ts
constant OFFSET (line 11) | const OFFSET = 10;
FILE: e2e/fixed-layout/tests/models/index.ts
type InsertEdgeOptions (line 10) | type InsertEdgeOptions = {
class FixedLayoutModel (line 15) | class FixedLayoutModel {
method constructor (line 18) | constructor(page: Page) {
method getNodeCount (line 22) | public async getNodeCount() {
method isStartNodeExist (line 26) | public async isStartNodeExist() {
method isEndNodeExist (line 30) | public async isEndNodeExist() {
method isConditionNodeExist (line 34) | public async isConditionNodeExist() {
method drag (line 38) | public async drag(from: DragPosition, to: DragPosition) {
method insert (line 45) | public async insert(searchText: string, { from, to }: InsertEdgeOption...
FILE: e2e/fixed-layout/tests/typings/drag.ts
type DragPosition (line 6) | interface DragPosition {
FILE: e2e/fixed-layout/utils/index.ts
function getOffsetByLocator (line 11) | async function getOffsetByLocator(locator: Locator) {
function cssEscape (line 32) | function cssEscape(str: string) {
FILE: e2e/free-layout/tests/models/index.ts
class FreeLayoutModel (line 8) | class FreeLayoutModel {
method constructor (line 11) | constructor(page: Page) {
method getNodeCount (line 16) | async getNodeCount() {
method isStartNodeExist (line 22) | public async isStartNodeExist() {
method isEndNodeExist (line 26) | public async isEndNodeExist() {
method isConditionNodeExist (line 30) | public async isConditionNodeExist() {
method addConditionNode (line 34) | async addConditionNode() {
FILE: packages/canvas-engine/core/__mocks__/create-entity.mock.ts
function createContainer (line 15) | function createContainer(): Container {
class TestEntity (line 26) | class TestEntity extends Entity {
function createEntity (line 30) | function createEntity<T extends Entity>(t = TestEntity, opts: any = {}):...
FILE: packages/canvas-engine/core/__mocks__/layers.mock.tsx
class MockEntityDataRegistry (line 11) | class MockEntityDataRegistry extends EntityData {
method getDefaultData (line 12) | getDefaultData() {
class TestUtilsLayer (line 19) | class TestUtilsLayer extends Layer {
method setRenderWithReactMemo (line 24) | setRenderWithReactMemo(status: boolean) {
class _TestEntity (line 29) | class _TestEntity extends Entity {
class TestRenderLayer1 (line 33) | class TestRenderLayer1 extends Layer {
class TestRenderLayer2 (line 37) | class TestRenderLayer2 extends Layer {
class TestRenderLayer3 (line 45) | class TestRenderLayer3 extends Layer {
FILE: packages/canvas-engine/core/__mocks__/playground-container.mock.ts
function createPlayground (line 8) | function createPlayground(): Playground {
FILE: packages/canvas-engine/core/__tests__/core/layer/config/editor-state-config-entity.spec.ts
method getDataInjector (line 13) | getDataInjector() {
method getDataInjector (line 30) | getDataInjector() {
FILE: packages/canvas-engine/core/__tests__/core/layer/config/payground-config-entity.spec.ts
method getDataInjector (line 13) | getDataInjector() {
FILE: packages/canvas-engine/core/__tests__/entity.spec.ts
function createContainer (line 22) | function createContainer(): Container {
function createEntity (line 37) | function createEntity<T extends Entity>(t = TestEntity, opts: any = {}):...
type TestSchema (line 41) | interface TestSchema {
class TestData (line 46) | class TestData extends EntityData<TestSchema> {
method getDefaultData (line 49) | getDefaultData(): TestSchema {
type Test1Schema (line 54) | interface Test1Schema {
class Test1Data (line 58) | class Test1Data extends EntityData<Test1Schema> {
method getDefaultData (line 61) | getDefaultData(): Test1Schema {
class SingleValueData (line 66) | class SingleValueData extends EntityData<string> {
method getDefaultData (line 69) | getDefaultData(): string {
class TestEntity (line 74) | class TestEntity extends Entity {
class _TestData (line 102) | class _TestData extends EntityData<string> {
method getDefaultData (line 105) | getDefaultData(): string {
class A (line 178) | class A {}
class B (line 180) | class B extends A {}
class C (line 182) | class C extends B {}
class _TestEntity (line 205) | class _TestEntity extends Entity {
method getDefaultDataRegistries (line 237) | getDefaultDataRegistries(): EntityDataRegistry[] {
class _TestEntity (line 230) | class _TestEntity extends Entity {
method getDefaultDataRegistries (line 237) | getDefaultDataRegistries(): EntityDataRegistry[] {
type TestConfigEntityData (line 325) | interface TestConfigEntityData {
class TestConfigEntity (line 329) | class TestConfigEntity extends ConfigEntity<TestConfigEntityData> {
method getDefaultConfig (line 332) | getDefaultConfig(): TestConfigEntityData {
method toDataJSON (line 336) | toDataJSON(): TestConfigEntityData {
class _TestEntity (line 507) | class _TestEntity extends Entity {
method getDefaultDataRegistries (line 237) | getDefaultDataRegistries(): EntityDataRegistry[] {
class _Test1Entity (line 513) | class _Test1Entity extends Entity {
class _TestEntityData (line 527) | class _TestEntityData extends EntityData {
method getDefaultData (line 528) | getDefaultData() {
FILE: packages/canvas-engine/core/__tests__/pipeline.spec.tsx
class TestConfigEntity (line 28) | class TestConfigEntity extends ConfigEntity<any> {
FILE: packages/canvas-engine/core/__tests__/playground-contribution.spec.tsx
class Layer1 (line 20) | class Layer1 extends Layer {
class Layer2 (line 29) | class Layer2 extends Layer {
method onInit (line 43) | onInit(playground: Playground) {
method onReady (line 51) | onReady(playground: Playground) {
method onAllLayersRendered (line 55) | onAllLayersRendered(playground: Playground) {
method onDispose (line 60) | onDispose(playground: Playground) {
method onInit (line 87) | onInit(ctx) {
method onReady (line 92) | onReady(ctx) {
method onAllLayersRendered (line 96) | onAllLayersRendered(ctx) {
method onDispose (line 101) | onDispose() {
FILE: packages/canvas-engine/core/__tests__/playground-mock-tools.spec.ts
class MockLayer (line 29) | class MockLayer extends Layer<any> {
method onReady (line 30) | onReady() {}
method onResize (line 32) | onResize() {}
method onFocus (line 34) | onFocus() {}
method onBlur (line 36) | onBlur() {}
method onZoom (line 38) | onZoom() {}
method onScroll (line 40) | onScroll() {}
method onViewportChange (line 42) | onViewportChange() {}
method onReadonlyOrDisabledChange (line 44) | onReadonlyOrDisabledChange() {}
method autorun (line 46) | autorun() {}
FILE: packages/canvas-engine/core/__tests__/playground-react.spec.tsx
function PlaygroundDemo (line 15) | function PlaygroundDemo() {
FILE: packages/canvas-engine/core/__tests__/plugin.test.ts
method onBind (line 32) | onBind({ bind }) {
method onInit (line 35) | onInit(ctx) {
method onReady (line 39) | onReady(ctx) {
method onDispose (line 43) | onDispose(ctx) {
method onInit (line 79) | onInit(ctx, opts) {
method onReady (line 84) | onReady(ctx, opts) {
method onDispose (line 89) | onDispose(ctx, opts) {
method onInit (line 123) | onInit(ctx, opts) {
method onInit (line 139) | onInit(ctx, opts) {
method onInit (line 160) | onInit(ctx) {
FILE: packages/canvas-engine/core/__tests__/react-hooks.spec.tsx
class MockEntity (line 36) | class MockEntity extends ConfigEntity {
method change (line 39) | change() {
class MockService (line 44) | @injectable()
method setInvoked (line 48) | setInvoked() {
FILE: packages/canvas-engine/core/__tests__/schema.spec.ts
function createContainer (line 29) | function createContainer(): Container {
function createEntity (line 43) | function createEntity() {
FILE: packages/canvas-engine/core/__tests__/transform-schema.spec.ts
function createContainer (line 19) | function createContainer(): Container {
function createEntity (line 29) | function createEntity(): Entity {
function createTransform (line 33) | function createTransform(entity?: Entity): TransformData {
function getIds (line 37) | function getIds(transform: TransformData): { localID: number; worldID: n...
function expectRectangle (line 44) | function expectRectangle(target: Rectangle, arr: number[]): void {
function expectSize (line 51) | function expectSize(target: SizeSchema, arr: number[]): void {
function expectIPoint (line 56) | function expectIPoint(target: IPoint, arr: number[]): void {
FILE: packages/canvas-engine/core/__tests__/utils.test.ts
type Config (line 16) | interface Config {
type PinchConfig (line 26) | interface PinchConfig {
class MockGesture (line 34) | class MockGesture {
method constructor (line 37) | constructor(target: HTMLElement, config: Config, pinchConfig: PinchCon...
FILE: packages/canvas-engine/core/src/common/config-entity.ts
type ConfigEntityProps (line 12) | interface ConfigEntityProps {}
function createConfigDataRegistry (line 16) | function createConfigDataRegistry<P>(entity: ConfigEntity<any>): EntityD...
class ConfigEntity (line 42) | class ConfigEntity<
method constructor (line 50) | constructor(opts: O) {
method getDefaultConfig (line 58) | getDefaultConfig(): P {
method checkChanged (line 65) | checkChanged(oldData: P, newData: Partial<P>): boolean {
method config (line 69) | get config(): P {
method updateConfig (line 73) | updateConfig(props: Partial<P>): void {
method onConfigChanged (line 77) | onConfigChanged(fn: (data: P) => void): Disposable {
FILE: packages/canvas-engine/core/src/common/entity-data.ts
method constructor (line 46) | constructor(entity: Entity, readonly opts?: OPTS) {
method type (line 57) | get type(): string {
method data (line 67) | get data(): DATA {
method update (line 74) | update(props: Partial<DATA> | keyof DATA | DATA, value?: any): void {
method fullyUpdate (line 96) | fullyUpdate(props: DATA): void {
method checkChanged (line 109) | checkChanged(newProps: Partial<DATA> | DATA): boolean {
method toJSON (line 116) | toJSON(): any {
method fromJSON (line 123) | fromJSON(data: object): void {
method changeLocked (line 127) | get changeLocked(): boolean {
method changeLocked (line 131) | set changeLocked(p) {
method fireWillChange (line 135) | fireWillChange(): void {
method fireChange (line 139) | fireChange(): void {
method bindChange (line 149) | protected bindChange(data: EntityData, fn?: () => void): void {
method version (line 158) | get version() {
type EntityDataProps (line 163) | type EntityDataProps<E extends EntityData> = E['data'];
type EntityDataRegistry (line 165) | interface EntityDataRegistry<E extends EntityData = EntityData> {
type EntityDataInjector (line 171) | type EntityDataInjector = <OPTS extends {} = {}>() => OPTS;
FILE: packages/canvas-engine/core/src/common/entity-manager-contribution.ts
type EntityManagerContribution (line 10) | interface EntityManagerContribution {
FILE: packages/canvas-engine/core/src/common/entity-manager.ts
function bindConfigEntity (line 40) | function bindConfigEntity(bind: interfaces.Bind, entityRegistry: EntityR...
class EntityManager (line 54) | class EntityManager implements Disposable {
method constructor (line 141) | constructor() {
method init (line 146) | init() {
method createEntity (line 153) | createEntity<T extends Entity>(
method isConfigEntity (line 177) | isConfigEntity(type: string): boolean {
method removeEntities (line 184) | removeEntities(Registry: EntityRegistry): void {
method removeEntityById (line 190) | removeEntityById(id: string): boolean {
method resetEntities (line 203) | resetEntities(registry: EntityRegistry): void {
method resetEntity (line 210) | resetEntity(registry: EntityRegistry, autoCreate?: boolean): void {
method updateConfigEntity (line 215) | updateConfigEntity<E extends ConfigEntity>(
method getRegistryByType (line 228) | getRegistryByType(type: string): EntityRegistry | undefined {
method registerEntity (line 232) | registerEntity(Registry: EntityRegistry): void {
method registerEntityData (line 244) | registerEntityData(Registry: EntityDataRegistry, injector?: EntityData...
method getDataRegistryByType (line 261) | getDataRegistryByType(type: string): EntityDataRegistry | undefined {
method getEntityById (line 265) | getEntityById<T extends Entity>(id: string): T | undefined {
method getEntity (line 272) | getEntity<T extends Entity>(registry: EntityRegistry, autoCreate?: boo...
method getEntities (line 280) | getEntities<T extends Entity>(registry: EntityRegistry): T[] {
method getEntityDatas (line 297) | getEntityDatas<T extends EntityData>(
method hasEntity (line 306) | hasEntity(registry: EntityRegistry): boolean {
method storeState (line 313) | storeState({ configOnly = true }: { configOnly?: boolean } = {}): Enti...
method restoreState (line 328) | restoreState(data: EntityJSON[]): void {
method saveEntity (line 347) | protected saveEntity(entity: Entity): void {
method removeEntity (line 385) | protected removeEntity(entity: Entity): void {
method reset (line 408) | reset(): void {
method getEntityVersion (line 454) | getEntityVersion(registry: EntityRegistry | string): number {
method getEntityDataVersion (line 458) | getEntityDataVersion(registry: EntityDataRegistry | string): number {
method dispose (line 464) | dispose(): void {
method getDataInjector (line 468) | getDataInjector(registry: EntityDataRegistry | string) {
method getService (line 472) | getService<T>(identifier: interfaces.ServiceIdentifier<T>): T {
FILE: packages/canvas-engine/core/src/common/entity.ts
type EntityRegistry (line 20) | interface EntityRegistry<E extends Entity = Entity> {
type EntityJSON (line 29) | interface EntityJSON {
type EntityDataChangedEvent (line 39) | interface EntityDataChangedEvent<T extends Entity = Entity> {
type EntityOpts (line 45) | interface EntityOpts {
class Entity (line 55) | class Entity<OPTS extends EntityOpts = EntityOpts> implements Disposable {
method getDefaultDataRegistries (line 120) | getDefaultDataRegistries(): EntityDataRegistry[] {
method changeLocked (line 140) | protected get changeLocked(): boolean {
method changeLocked (line 144) | protected set changeLocked(changeLocked) {
method type (line 156) | get type(): string {
method context (line 168) | get context(): PlaygroundContext {
method constructor (line 172) | constructor(opts: OPTS) {
method addInitializeData (line 202) | addInitializeData(datas: EntityDataRegistry[], dataConfig?: any) {
method version (line 211) | get version(): number {
method toJSON (line 218) | toJSON(): EntityJSON | any {
method fromJSON (line 237) | fromJSON(data?: EntityJSON | any): void {
method id (line 257) | get id(): string {
method dispose (line 264) | dispose(): void {
method disposed (line 269) | get disposed(): boolean {
method reset (line 276) | reset(): void {
method onDispose (line 292) | get onDispose(): Event<void> {
method fireChange (line 300) | protected fireChange(): void {
method addData (line 313) | addData<D extends EntityData>(
method savedInManager (line 371) | get savedInManager(): boolean {
method updateData (line 378) | updateData<D extends EntityData>(
method getData (line 391) | getData<D extends EntityData>(Registry: EntityDataRegistry<D>): D {
method hasData (line 398) | hasData(Registry: EntityDataRegistry): boolean {
method removeData (line 405) | removeData<D extends EntityData>(Registry: EntityDataRegistry<D>): void {
method getService (line 418) | getService<T>(identifier: interfaces.ServiceIdentifier<T>): T {
method register (line 449) | protected register(): void {
function getType (line 460) | function getType(registry: EntityRegistry): string {
function checkDataChanged (line 467) | function checkDataChanged(oldProps: any, newProps: any): boolean {
function isRegistryOf (line 471) | function isRegistryOf(target: any, Registry: any): boolean {
FILE: packages/canvas-engine/core/src/common/playground-context.ts
type PlaygroundContext (line 15) | type PlaygroundContext = any;
type PlaygroundContextProvider (line 18) | type PlaygroundContextProvider = () => any;
type PlaygroundContainerFactory (line 31) | interface PlaygroundContainerFactory {
FILE: packages/canvas-engine/core/src/common/playground-decorator-helper.ts
constant ENTITIES_DECO_KEY (line 15) | const ENTITIES_DECO_KEY = Symbol('EntitiesDecorator');
constant ENTITIES_BY_DATA_DECO_KEY (line 18) | const ENTITIES_BY_DATA_DECO_KEY = Symbol('EntitiesByDataDecorator');
constant PROPERTEIS_INJECTED (line 20) | const PROPERTEIS_INJECTED = Symbol('PropertiesInjected');
type RegistryValueGetter (line 22) | interface RegistryValueGetter<T> {
type RegistryInit (line 26) | interface RegistryInit {
function getRegistryMetadata (line 30) | function getRegistryMetadata(target: any, key: symbol): any[] {
function getRegistryInjectedProperties (line 34) | function getRegistryInjectedProperties(target: any): string[] {
function definePropertiesMetadata (line 38) | function definePropertiesMetadata(target: any, property: string): void {
function removeInjectedProperties (line 48) | function removeInjectedProperties(instance: any): void {
function createRegistryDecorator (line 60) | function createRegistryDecorator(
function getEntityMetadata (line 98) | function getEntityMetadata(layer: any): EntityRegistry[] {
function getEntityDatasMetadata (line 101) | function getEntityDatasMetadata(
FILE: packages/canvas-engine/core/src/common/playground-decorators.ts
function observeEntity (line 34) | function observeEntity(registry: EntityRegistry): any {
function observeEntities (line 44) | function observeEntities(registry: EntityRegistry): any {
function observeEntityDatas (line 74) | function observeEntityDatas(
FILE: packages/canvas-engine/core/src/common/playground-schedule.ts
class PlaygroundSchedule (line 10) | class PlaygroundSchedule implements Disposable {
method push (line 13) | push(key: any, fn: () => void): void {
method dispose (line 27) | dispose(): void {
FILE: packages/canvas-engine/core/src/common/protect-wheel-area.ts
type ProtectWheelArea (line 11) | type ProtectWheelArea = (dom: Element) => boolean;
FILE: packages/canvas-engine/core/src/common/schema/node.ts
type NodeSchema (line 8) | interface NodeSchema {
type TransformNodeSchema (line 13) | interface TransformNodeSchema extends NodeSchema {
FILE: packages/canvas-engine/core/src/common/schema/opacity-schema.ts
class OpacityData (line 13) | class OpacityData extends EntityData<OpacitySchema> {
method getDefaultData (line 16) | getDefaultData(): OpacitySchema {
FILE: packages/canvas-engine/core/src/common/schema/origin-schema.ts
class OriginData (line 13) | class OriginData extends EntityData<OriginSchema> implements OriginSchema {
method getDefaultData (line 16) | getDefaultData(): OriginSchema {
method x (line 20) | get x(): number {
method y (line 24) | get y(): number {
method x (line 28) | set x(x: number) {
method y (line 32) | set y(y: number) {
FILE: packages/canvas-engine/core/src/common/schema/position-schema.ts
class PositionData (line 13) | class PositionData extends EntityData<PositionSchema> implements Positio...
method getDefaultData (line 16) | getDefaultData(): PositionSchema {
method x (line 20) | get x(): number {
method y (line 24) | get y(): number {
method x (line 28) | set x(x: number) {
method y (line 32) | set y(y: number) {
FILE: packages/canvas-engine/core/src/common/schema/rotation-schema.ts
class RotationData (line 13) | class RotationData extends EntityData<RotationSchema> {
method getDefaultData (line 16) | getDefaultData(): RotationSchema {
FILE: packages/canvas-engine/core/src/common/schema/scale-schema.ts
class ScaleData (line 13) | class ScaleData extends EntityData<ScaleSchema> implements ScaleSchema {
method getDefaultData (line 16) | getDefaultData(): ScaleSchema {
method x (line 20) | get x(): number {
method y (line 24) | get y(): number {
method x (line 28) | set x(x: number) {
method y (line 32) | set y(y: number) {
FILE: packages/canvas-engine/core/src/common/schema/size-schema.ts
class SizeData (line 12) | class SizeData extends EntityData<SizeSchema> implements SizeSchema {
method getDefaultData (line 15) | getDefaultData(): SizeSchema {
method width (line 19) | get width(): number {
method height (line 23) | get height(): number {
method width (line 27) | set width(width: number) {
method height (line 31) | set height(height: number) {
method locked (line 35) | get locked(): boolean {
method locked (line 39) | set locked(locked: boolean) {
FILE: packages/canvas-engine/core/src/common/schema/skew-schema.ts
class SkewData (line 13) | class SkewData extends EntityData<SkewSchema> implements SkewSchema {
method getDefaultData (line 16) | getDefaultData(): SkewSchema {
method x (line 20) | get x(): number {
method y (line 24) | get y(): number {
method x (line 28) | set x(x: number) {
method y (line 32) | set y(y: number) {
FILE: packages/canvas-engine/core/src/common/schema/transform-schema.ts
class TransformData (line 32) | class TransformData extends EntityData<TransformSchema> implements Trans...
method children (line 45) | get children(): TransformData[] {
method clearChildren (line 49) | clearChildren(): void {
method isContainer (line 60) | get isContainer(): boolean {
method constructor (line 115) | constructor(entity: Entity) {
method fireChange (line 126) | fireChange(): void {
method localTransform (line 133) | get localTransform(): Matrix {
method worldTransform (line 138) | get worldTransform(): Matrix {
method getDefaultData (line 143) | getDefaultData(): TransformSchema {
method update (line 147) | update(data: Partial<TransformSchema>): void {
method position (line 168) | get position(): PositionSchema {
method position (line 172) | set position(position: PositionSchema) {
method size (line 176) | get size(): SizeSchema {
method size (line 180) | set size(size: SizeSchema) {
method origin (line 184) | get origin(): OriginSchema {
method origin (line 188) | set origin(origin: OriginSchema) {
method scale (line 192) | get scale(): ScaleSchema {
method scale (line 196) | set scale(scale: ScaleSchema) {
method skew (line 200) | get skew(): SkewSchema {
method skew (line 204) | set skew(skew: SkewSchema) {
method rotation (line 208) | get rotation(): number {
method rotation (line 212) | set rotation(rotation: number) {
method data (line 216) | get data(): TransformSchema {
method updateSkew (line 225) | protected updateSkew(): void {
method updateLocalTransformMatrix (line 238) | protected updateLocalTransformMatrix(): void {
method localID (line 258) | get localID() {
method worldID (line 262) | get worldID() {
method updateTransformMatrix (line 270) | protected updateTransformMatrix(): void {
method setFromMatrix (line 302) | setFromMatrix(matrix: Matrix): void {
method getMutationCache (line 333) | getMutationCache<T>(key: string, fn: () => T): T {
method bounds (line 341) | get bounds(): Rectangle {
method boundsWithoutRotation (line 352) | get boundsWithoutRotation(): Rectangle {
method localSize (line 369) | get localSize(): SizeSchema {
method worldSize (line 384) | get worldSize(): SizeSchema {
method localBounds (line 396) | get localBounds(): Rectangle {
method contains (line 414) | contains(x: number, y: number, asCircle?: boolean): boolean {
method parent (line 437) | get parent(): TransformData | undefined {
method isParent (line 441) | isParent(parent: TransformData): boolean {
method isParentTransform (line 450) | isParentTransform(parent?: TransformData): boolean {
method setParent (line 463) | setParent(parent: TransformData | undefined, listenParentData = true):...
method intersects (line 502) | intersects(rect: Rectangle): boolean {
method worldScale (line 515) | get worldScale(): ScaleSchema {
method worldRotation (line 527) | get worldRotation(): number {
method worldDegree (line 538) | get worldDegree(): number {
method localOrigin (line 542) | get localOrigin(): PositionSchema {
method worldOrigin (line 554) | get worldOrigin(): PositionSchema {
method widthToScaleX (line 567) | widthToScaleX(width: number, isWorldSize?: boolean): number {
method heightToScaleY (line 576) | heightToScaleY(height: number, isWorldSize?: boolean): number {
method sizeToScaleValue (line 581) | sizeToScaleValue(
function isParentOrChildrenTransform (line 597) | function isParentOrChildrenTransform(dragableEntities: Entity[], target:...
FILE: packages/canvas-engine/core/src/common/utils/bounds.spec.ts
function createContainer (line 14) | function createContainer(): Container {
function createEntity (line 24) | function createEntity(): Entity {
function expectRectangle (line 28) | function expectRectangle(target: Rectangle, arr: number[]): void {
FILE: packages/canvas-engine/core/src/common/utils/bounds.ts
type TransformOriginAndSize (line 10) | type TransformOriginAndSize = Pick<TransformSchema, 'origin'> & Pick<Tra...
function getPointWithMatrix (line 18) | function getPointWithMatrix(output: PositionSchema, matrix?: Matrix): Po...
function getBounds (line 32) | function getBounds(target: TransformOriginAndSize, matrix?: Matrix): Rec...
function applyMatrix (line 54) | function applyMatrix(bounds: Rectangle, matrix: Matrix): Rectangle {
function getLeftPointFromBounds (line 79) | function getLeftPointFromBounds(
function getTopPointFromBounds (line 93) | function getTopPointFromBounds(
function getCenter (line 104) | function getCenter(target: TransformSchema, matrix?: Matrix): PositionSc...
function getTopLeft (line 112) | function getTopLeft(target: TransformOriginAndSize, matrix?: Matrix): Po...
function getTopCenter (line 120) | function getTopCenter(target: TransformOriginAndSize, matrix?: Matrix): ...
function getTopRight (line 128) | function getTopRight(target: TransformOriginAndSize, matrix?: Matrix): P...
function getLeftCenter (line 136) | function getLeftCenter(target: TransformOriginAndSize, matrix?: Matrix):...
function getRightCenter (line 144) | function getRightCenter(target: TransformOriginAndSize, matrix?: Matrix)...
function getBottomLeft (line 152) | function getBottomLeft(target: TransformOriginAndSize, matrix?: Matrix):...
function getBottomCenter (line 160) | function getBottomCenter(target: TransformOriginAndSize, matrix?: Matrix...
function getBottomRight (line 168) | function getBottomRight(target: TransformOriginAndSize, matrix?: Matrix)...
FILE: packages/canvas-engine/core/src/core/layer/config/editor-state-config-entity.ts
type EditorState (line 14) | interface EditorState {
constant EDITOR_STATE_DEFAULTS (line 56) | const EDITOR_STATE_DEFAULTS: EditorState[] = [
type EditorStateChangeEvent (line 62) | interface EditorStateChangeEvent {
class EditorStateConfigEntity (line 71) | class EditorStateConfigEntity extends ConfigEntity {
method constructor (line 85) | constructor(opts: EntityOpts) {
method isPressingSpaceBar (line 90) | get isPressingSpaceBar(): boolean {
method isPressingSpaceBar (line 94) | set isPressingSpaceBar(isPressing: boolean) {
method isPressingShift (line 98) | get isPressingShift(): boolean {
method isPressingShift (line 102) | set isPressingShift(isPressing: boolean) {
method onCancel (line 111) | onCancel(stateId: string, fn: () => void): Disposable {
method getCurrentState (line 119) | getCurrentState(): EditorState | undefined {
method is (line 123) | is(stateId: string): boolean {
method changeState (line 127) | changeState(stateId: string, event?: React.MouseEvent): void {
method toDefaultState (line 138) | toDefaultState(): void {
method registerState (line 142) | registerState(state: EditorState): void {
method getStates (line 148) | getStates(): EditorState[] {
method isMouseFriendlyMode (line 155) | isMouseFriendlyMode(): boolean {
method getStateFromShortcut (line 160) | getStateFromShortcut(e: KeyboardEvent): EditorState | undefined {
FILE: packages/canvas-engine/core/src/core/layer/config/playground-config-entity.ts
type PlaygroundConfigEntityData (line 19) | interface PlaygroundConfigEntityData {
type PlaygroundConfigRevealOpts (line 43) | interface PlaygroundConfigRevealOpts {
constant SCALE_WIDTH (line 54) | const SCALE_WIDTH = 0
type PlaygroundScrollLimitFn (line 58) | type PlaygroundScrollLimitFn = (scroll: { scrollX: number; scrollY: numb...
type Cursors (line 62) | type Cursors = Record<string, string>;
class PlaygroundConfigEntity (line 66) | class PlaygroundConfigEntity extends ConfigEntity<PlaygroundConfigEntity...
method constructor (line 82) | constructor(opts: any) {
method grabDisable (line 90) | get grabDisable(): boolean {
method grabDisable (line 97) | set grabDisable(grabDisable: boolean) {
method scrollDisable (line 102) | get scrollDisable(): boolean {
method scrollDisable (line 105) | set scrollDisable(scrollDisable: boolean) {
method zoomDisable (line 110) | get zoomDisable(): boolean {
method zoomDisable (line 113) | set zoomDisable(zoomDisable: boolean) {
method getDefaultConfig (line 118) | getDefaultConfig(): PlaygroundConfigEntityData {
method addScrollLimit (line 145) | addScrollLimit(fn: PlaygroundScrollLimitFn): void {
method updateConfig (line 153) | updateConfig(props: Partial<PlaygroundConfigEntityData>): void {
method finalScale (line 199) | get finalScale(): number {
method zoom (line 207) | get zoom(): number {
method scrollData (line 212) | get scrollData(): { scrollX: number; scrollY: number } {
method normalizeZoom (line 219) | protected normalizeZoom(zoom: number): number {
method updateCursor (line 234) | updateCursor(cursor: string): void {
method getPosFromMouseEvent (line 246) | getPosFromMouseEvent(
method getClientBounds (line 265) | getClientBounds(): Rectangle {
method toFixedPos (line 273) | toFixedPos(pos: PositionSchema): PositionSchema {
method getViewport (line 285) | getViewport(withScale: boolean = true): Rectangle {
method isViewportVisible (line 302) | isViewportVisible(bounds: Rectangle, rotation: number = 0, includeAll:...
method scrollToView (line 311) | scrollToView(opts: PlaygroundConfigRevealOpts = {}): Promise<void> {
method setPageBounds (line 377) | setPageBounds(bounds: Rectangle): void {
method getPageBounds (line 388) | getPageBounds(): Rectangle | undefined {
method scrollPageBoundsToCenter (line 401) | scrollPageBoundsToCenter(
method scroll (line 448) | scroll(
method fixLayerPosition (line 490) | fixLayerPosition(layerNode: HTMLElement): void {
method loading (line 497) | get loading(): boolean {
method loading (line 501) | set loading(loading: boolean) {
method zoomEnable (line 511) | get zoomEnable(): boolean {
method zoomEnable (line 519) | set zoomEnable(zoomEnable: boolean) {
method zoomin (line 529) | zoomin(easing?: boolean, easingDuration?: number): void {
method zoomout (line 538) | zoomout(easing?: boolean, easingDuration?: number): void {
method updateZoom (line 544) | updateZoom(newZoom: number, easing: boolean = true, easingDuration = 2...
method disabled (line 565) | get disabled(): boolean {
method readonly (line 568) | get readonly(): boolean {
method readonlyOrDisabled (line 571) | get readonlyOrDisabled(): boolean {
method readonly (line 574) | set readonly(readonly) {
method disabled (line 579) | set disabled(disabled) {
method fitView (line 592) | fitView(bounds: Rectangle, easing = true, padding = 0, easingDuration ...
FILE: packages/canvas-engine/core/src/core/layer/layer.ts
type LayerOptions (line 28) | interface LayerOptions {}
class Layer (line 36) | class Layer<
method dispose (line 178) | dispose(): void {
method createDOMCache (line 186) | createDOMCache<T extends DOMCache>(
method getPosFromMouseEvent (line 228) | getPosFromMouseEvent(
type LayerRegistry (line 245) | interface LayerRegistry<P extends Layer = Layer> {
FILE: packages/canvas-engine/core/src/core/layer/playground-layer.ts
type PlaygroundInteractiveType (line 28) | type PlaygroundInteractiveType = 'MOUSE' | 'PAD';
type PlaygroundLayerOptions (line 30) | interface PlaygroundLayerOptions extends LayerOptions {
class PlaygroundLayer (line 51) | class PlaygroundLayer extends Layer<PlaygroundLayerOptions> {
method onReady (line 77) | onReady(): void {
method getCursor (line 272) | private getCursor(cursor: string | undefined) {
method isMouseMode (line 280) | private isMouseMode() {
method onStateChanged (line 284) | onStateChanged(e: EditorStateChangeEvent): void {
method isGrab (line 376) | protected isGrab(): boolean {
method createGesture (line 386) | createGesture(): void {
method handleScrollEvent (line 396) | protected handleScrollEvent(event: WheelEvent): void {
method getMouseScaleDelta (line 407) | protected getMouseScaleDelta(): number {
method handleWheelEvent (line 419) | protected handleWheelEvent(event: WheelEvent): void {
method getScrollParent (line 479) | protected getScrollParent(ele?: HTMLElement | null): HTMLElement | null {
method autorun (line 502) | autorun(): void {
FILE: packages/canvas-engine/core/src/core/pipeline/pipeline-entities-selector.ts
type SelectorVersion (line 19) | type SelectorVersion = Map<string, number>;
type LayerEntitiesSelector (line 21) | interface LayerEntitiesSelector {
class PipelineEntitiesSelector (line 34) | class PipelineEntitiesSelector {
method subscribeEntities (line 48) | subscribeEntities(layer: Layer, entities: EntityRegistry[]): void {
method subscribleEntityByData (line 83) | subscribleEntityByData(layer: Layer, entity: EntityRegistry, data: Ent...
method getSelector (line 96) | protected getSelector(layer: Layer): LayerEntitiesSelector {
method getLayerEntities (line 108) | getLayerEntities(layer: Layer): { entities: Entity[]; changed: boolean...
method getLayerEntityDatas (line 151) | getLayerEntityDatas(layer: Layer): { datas: EntityData[]; changed: boo...
method getLayerData (line 178) | getLayerData(layer: Layer): {
function checkChanged (line 193) | function checkChanged(v1: SelectorVersion = new Map(), v2: SelectorVersi...
FILE: packages/canvas-engine/core/src/core/pipeline/pipeline-entities.ts
type PipelineEntities (line 18) | interface PipelineEntities extends Iterable<Entity> {
class PipelineEntitiesImpl (line 80) | class PipelineEntitiesImpl implements PipelineEntities {
method constructor (line 92) | constructor(protected readonly entityManager: EntityManager) {}
method size (line 94) | get size(): number {
method load (line 103) | load(observeEntites: Entity[], observeDatas: EntityData[]): void {
method get (line 112) | get<T extends Entity>(registry: EntityRegistry, id?: string): T | unde...
method has (line 120) | has(registy: EntityRegistry): boolean {
method getEntities (line 124) | getEntities<T extends Entity>(registry: EntityRegistry): T[] {
method getEntityDatas (line 138) | getEntityDatas<T extends EntityData = EntityData>(
method updateConfig (line 180) | updateConfig<E extends ConfigEntity>(
method getConfig (line 191) | getConfig<E extends ConfigEntity>(registry: EntityRegistry): E['config...
method createEntity (line 202) | createEntity<E extends Entity>(
method removeEntities (line 212) | removeEntities(registry: EntityRegistry): void {
method [Symbol.iterator] (line 216) | [Symbol.iterator](): Iterator<Entity> {
FILE: packages/canvas-engine/core/src/core/pipeline/pipeline-registry.ts
type PipelineMessage (line 40) | enum PipelineMessage {
class PipelineRegistry (line 50) | class PipelineRegistry implements Disposable, IMessageHandler {
method constructor (line 75) | constructor() {
method _listenEvent (line 114) | _listenEvent(
method listenPlaygroundEvent (line 167) | listenPlaygroundEvent(
method listenGlobalEvent (line 181) | listenGlobalEvent(
method registerLayer (line 195) | registerLayer<P extends Layer = Layer>(
method getLayer (line 287) | getLayer<T extends Layer>(layerRegistry: LayerRegistry<T>): T | undefi...
method configEntity (line 291) | get configEntity(): PlaygroundConfigEntity {
method ready (line 295) | ready(): void {
method processMessage (line 323) | processMessage(msg: Message): void {
method dispose (line 341) | dispose(): void {
FILE: packages/canvas-engine/core/src/core/pipeline/pipeline-renderer.tsx
constant FLUSH_LAYER_REQUEST (line 24) | const FLUSH_LAYER_REQUEST = 'flush-layer-request';
class FlushLayerMessage (line 28) | class FlushLayerMessage extends ConflatableMessage {
method constructor (line 29) | constructor(readonly layer: Layer) {
class PipelineRenderer (line 38) | class PipelineRenderer implements Disposable, IMessageHandler {
method constructor (line 66) | constructor(
method reportLayerRendered (line 84) | reportLayerRendered(layer: Layer): void {
method addLayer (line 102) | addLayer(layer: Layer): void {
method flush (line 146) | flush(forceUpdate?: boolean): void {
method ready (line 152) | ready(): void {
method dispose (line 163) | dispose(): void {
method processMessage (line 168) | processMessage(msg: Message): void {
method loadLayerEntities (line 174) | protected loadLayerEntities(layer: Layer): boolean {
method onFlushRequest (line 186) | protected onFlushRequest(layer: Layer): boolean {
method updateLayer (line 224) | updateLayer(layer: Layer, forceUpdate?: boolean): void {
method toReactComponent (line 240) | toReactComponent(): React.FC {
FILE: packages/canvas-engine/core/src/core/pipeline/pipeline.ts
type PipeSupportEvent (line 8) | type PipeSupportEvent = MouseEvent | DragEvent | KeyboardEvent | UIEvent...
type PipeEventName (line 9) | type PipeEventName = string;
type PipelineDimension (line 10) | interface PipelineDimension {
type PipelineEventHandler (line 15) | type PipelineEventHandler = (event: PipeSupportEvent) => boolean | undef...
type PipelineEventRegsiter (line 17) | interface PipelineEventRegsiter {
type PipelineLayerPriority (line 22) | enum PipelineLayerPriority {
type PipelineLayerFactory (line 28) | type PipelineLayerFactory = (layerRegistry: LayerRegistry, layerOptions?...
FILE: packages/canvas-engine/core/src/core/pipeline/pipline-react-utils.tsx
type LayerReactAutorun (line 14) | interface LayerReactAutorun {
function OriginComp (line 19) | function OriginComp({
function createLayerReactAutorun (line 32) | function createLayerReactAutorun(
FILE: packages/canvas-engine/core/src/core/utils/inject-provider-decorators.ts
method get (line 21) | get() {
FILE: packages/canvas-engine/core/src/core/utils/lazy-inject-decorators.ts
constant IS_LAZY_INJECT_CONTEXT_INJECTED (line 9) | const IS_LAZY_INJECT_CONTEXT_INJECTED = Symbol('IS_LAZY_INJECT_CONTEXT_I...
method get (line 26) | get() {
method set (line 30) | set() {}
FILE: packages/canvas-engine/core/src/core/utils/playground-drag.ts
constant SCROLL_DELTA (line 19) | const SCROLL_DELTA = 4;
constant SCROLL_AUTO_DISTANCE (line 21) | const SCROLL_AUTO_DISTANCE = 20;
constant SCROLL_INTERVAL (line 23) | const SCROLL_INTERVAL = 6;
function createMouseEvent (line 26) | function createMouseEvent(type: string, clientX: number, clientY: number...
type PlaygroundDragEvent (line 49) | interface PlaygroundDragEvent extends MouseEvent {
type PlaygroundDragOptions (line 59) | interface PlaygroundDragOptions<T> {
class PlaygroundDrag (line 67) | class PlaygroundDrag<T = undefined> implements Disposable {
method constructor (line 92) | constructor(options: PlaygroundDragOptions<T> = {}) {
method isStarted (line 99) | get isStarted(): boolean {
method start (line 103) | start(
method stop (line 128) | stop(clientX: number, clientY: number): void {
method dispose (line 136) | dispose(): void {
method handleEvent (line 147) | handleEvent(_event: Event): void {
method scale (line 178) | get scale(): number {
method getRelativePos (line 182) | protected getRelativePos(event: MouseEvent): PositionSchema {
method getDragEvent (line 194) | protected getDragEvent(event: MouseEvent): PlaygroundDragEvent {
method _finalize (line 241) | private _finalize(): void {
method _evtMouseMove (line 258) | private _evtMouseMove(event: MouseEvent): void {
method _evtMouseUp (line 272) | private _evtMouseUp(event: MouseEvent): void {
method _evtKeyDown (line 289) | private _evtKeyDown(event: KeyboardEvent): void {
method _addListeners (line 303) | private _addListeners(): void {
method _removeListeners (line 323) | private _removeListeners(): void {
method _startScrollX (line 368) | private _startScrollX(origin: number, added: boolean): void {
method _stopScrollX (line 380) | private _stopScrollX(): void {
method _startScrollY (line 387) | private _startScrollY(origin: number, added: boolean): void {
method _stopScrollY (line 397) | private _stopScrollY(): void {
method fireScroll (line 409) | fireScroll(scrollKey: 'scrollY' | 'scrollX', added: boolean): void {
type PlaygroundDragEntitiesOpts (line 449) | interface PlaygroundDragEntitiesOpts<T> extends PlaygroundDragOptions<T> {
function startDrag (line 462) | function startDrag<T>(
FILE: packages/canvas-engine/core/src/core/utils/playground-gesture.spec.ts
class Gesture (line 11) | class Gesture {}
FILE: packages/canvas-engine/core/src/core/utils/playground-gesture.ts
class PlaygroundGesture (line 12) | class PlaygroundGesture extends DisposableImpl {
method constructor (line 15) | constructor(
method handlePinch (line 59) | handlePinch(params: {
method getScaleBounds (line 91) | getScaleBounds(): { min: number; max: number } {
method preventDefault (line 98) | protected preventDefault(): void {
method pinching (line 115) | get pinching(): boolean {
FILE: packages/canvas-engine/core/src/core/utils/tween.ts
function startTweenLoop (line 12) | function startTweenLoop(): void {
function stopTweenLoop (line 22) | function stopTweenLoop(): void {
type TweenValues (line 26) | interface TweenValues {
type TweenOpts (line 30) | interface TweenOpts<V> {
function startTween (line 40) | function startTween<V extends TweenValues = TweenValues>(opts: TweenOpts...
type ScrollIntoViewOpts (line 66) | interface ScrollIntoViewOpts {
function scrollIntoViewWithTween (line 88) | function scrollIntoViewWithTween(opts: ScrollIntoViewOpts): Disposable {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/Controller.ts
class Controller (line 21) | class Controller {
method constructor (line 58) | constructor(handlers: InternalHandlers) {
method setEventIds (line 66) | setEventIds(event: TouchEvent | PointerEvent) {
method applyHandlers (line 83) | applyHandlers(handlers: InternalHandlers, nativeHandlers?: NativeHandl...
method applyConfig (line 93) | applyConfig(config: UserGestureConfig, gestureKey?: GestureKey) {
method clean (line 101) | clean() {
method effect (line 113) | effect() {
method bind (line 123) | bind(...args: any[]) {
function setupGesture (line 178) | function setupGesture(ctrl: Controller, gestureKey: GestureKey) {
function resolveGestures (line 184) | function resolveGestures(ctrl: Controller, internalHandlers: InternalHan...
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/EventStore.ts
class EventStore (line 10) | class EventStore {
method constructor (line 17) | constructor(ctrl: Controller, gestureKey?: GestureKey) {
method add (line 22) | add(
method clean (line 42) | clean() {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/TimeoutStore.ts
class TimeoutStore (line 6) | class TimeoutStore {
method add (line 9) | add<FunctionType extends (...args: any[]) => any>(
method remove (line 19) | remove(key: string) {
method clean (line 24) | clean() {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/actions.ts
function registerAction (line 24) | function registerAction(action: Action) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/commonConfigResolver.ts
constant DEFAULT_RUBBERBAND (line 11) | const DEFAULT_RUBBERBAND = 0.15
method enabled (line 14) | enabled(value = true) {
method eventOptions (line 17) | eventOptions(value: AddEventListenerOptions | undefined, _k: string, con...
method preventDefault (line 20) | preventDefault(value = false) {
method triggerAllEvents (line 23) | triggerAllEvents(value = false) {
method rubberband (line 26) | rubberband(value: number | boolean | Vector2 = 0): Vector2 {
method from (line 36) | from(value: number | Vector2 | ((s: State) => Vector2)) {
method transform (line 41) | transform(this: InternalGestureOptions, value: any, _k: string, config: ...
method threshold (line 58) | threshold(value: any) {
method domTarget (line 65) | domTarget(value: any) {
method lockDirection (line 71) | lockDirection(value: any) {
method initial (line 79) | initial(value: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/coordinatesConfigResolver.ts
constant DEFAULT_AXIS_THRESHOLD (line 9) | const DEFAULT_AXIS_THRESHOLD = 0
method axis (line 13) | axis(
method axisThreshold (line 22) | axisThreshold(value = DEFAULT_AXIS_THRESHOLD) {
method bounds (line 25) | bounds(
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/dragConfigResolver.ts
constant DEFAULT_PREVENT_SCROLL_DELAY (line 12) | const DEFAULT_PREVENT_SCROLL_DELAY = 250
constant DEFAULT_DRAG_DELAY (line 13) | const DEFAULT_DRAG_DELAY = 180
constant DEFAULT_SWIPE_VELOCITY (line 14) | const DEFAULT_SWIPE_VELOCITY = 0.5
constant DEFAULT_SWIPE_DISTANCE (line 15) | const DEFAULT_SWIPE_DISTANCE = 50
constant DEFAULT_SWIPE_DURATION (line 16) | const DEFAULT_SWIPE_DURATION = 250
constant DEFAULT_KEYBOARD_DISPLACEMENT (line 17) | const DEFAULT_KEYBOARD_DISPLACEMENT = 10
constant DEFAULT_DRAG_AXIS_THRESHOLD (line 19) | const DEFAULT_DRAG_AXIS_THRESHOLD: Record<PointerType, number> = { mouse...
method device (line 23) | device(
method preventScrollAxis (line 36) | preventScrollAxis(this: InternalDragOptions, value: 'x' | 'y' | 'xy', _k...
method pointerCapture (line 46) | pointerCapture(
method threshold (line 56) | threshold(
method swipe (line 68) | swipe(
method delay (line 78) | delay(value: number | boolean = 0) {
method axisThreshold (line 88) | axisThreshold(value: Record<PointerType, number>) {
method keyboardDisplacement (line 92) | keyboardDisplacement(value: number = DEFAULT_KEYBOARD_DISPLACEMENT) {
method useTouch (line 99) | useTouch(value: any) {
method experimental_preventWindowScrollY (line 107) | experimental_preventWindowScrollY(value: any) {
method swipeVelocity (line 115) | swipeVelocity(value: any) {
method swipeDistance (line 123) | swipeDistance(value: any) {
method swipeDuration (line 131) | swipeDuration(value: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/pinchConfigResolver.ts
method device (line 15) | device(
method bounds (line 32) | bounds(_v: any, _k: string, { scaleBounds = {}, angleBounds = {} }: Pinc...
method threshold (line 47) | threshold(this: InternalPinchOptions, value: number | Vector2, _k: strin...
method modifierKey (line 52) | modifierKey(value: ModifierKey | ModifierKey[]) {
method pinchOnWheel (line 56) | pinchOnWheel(value = true) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/resolver.ts
type Resolver (line 10) | type Resolver = (x: any, key: string, obj: any) => any
type ResolverMap (line 11) | type ResolverMap = { [k: string]: Resolver | ResolverMap | boolean }
function resolveWith (line 13) | function resolveWith<T extends { [k: string]: any }, V extends { [k: str...
function parse (line 42) | function parse(newConfig: UserGestureConfig, gestureKey?: GestureKey, _c...
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/sharedConfigResolver.ts
method target (line 10) | target(value: Target) {
method enabled (line 16) | enabled(value = true) {
method window (line 19) | window(value = SUPPORT.isBrowser ? window : undefined) {
method eventOptions (line 22) | eventOptions({ passive = true, capture = false } = {}) {
method transform (line 25) | transform(value: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/config/support.ts
function supportsTouchEvents (line 8) | function supportsTouchEvents(): boolean {
function isTouchScreen (line 12) | function isTouchScreen(): boolean {
function supportsPointerEvents (line 16) | function supportsPointerEvents(): boolean {
function supportsPointerLock (line 20) | function supportsPointerLock(): boolean {
function supportsGestureEvents (line 24) | function supportsGestureEvents(): boolean {
constant SUPPORT (line 34) | const SUPPORT = {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/CoordinatesEngine.ts
function selectAxis (line 11) | function selectAxis([dx, dy]: Vector2, threshold: number) {
method reset (line 27) | reset() {
method init (line 32) | init() {
method computeOffset (line 37) | computeOffset() {
method computeMovement (line 41) | computeMovement() {
method axisIntent (line 45) | axisIntent(event?: UIEvent) {
method restrictToAxis (line 66) | restrictToAxis(v: Vector2) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/DragEngine.ts
constant KEYS_DELTA_MAP (line 12) | const KEYS_DELTA_MAP = {
class DragEngine (line 19) | class DragEngine extends CoordinatesEngine<'drag'> {
method reset (line 23) | reset(this: DragEngine) {
method setup (line 37) | setup() {
method cancel (line 53) | cancel() {
method setActive (line 65) | setActive() {
method clean (line 70) | clean() {
method pointerDown (line 77) | pointerDown(event: PointerEvent) {
method startPointerDrag (line 142) | startPointerDrag(event: PointerEvent) {
method pointerMove (line 152) | pointerMove(event: PointerEvent) {
method pointerUp (line 202) | pointerUp(event: PointerEvent) {
method pointerClick (line 258) | pointerClick(event: MouseEvent) {
method setupPointer (line 269) | setupPointer(event: PointerEvent) {
method pointerClean (line 302) | pointerClean() {
method preventScroll (line 308) | preventScroll(event: PointerEvent) {
method setupScrollPrevention (line 314) | setupScrollPrevention(event: PointerEvent) {
method setupDelayTrigger (line 338) | setupDelayTrigger(event: PointerEvent) {
method keyDown (line 351) | keyDown(event: KeyboardEvent) {
method keyUp (line 369) | keyUp(event: KeyboardEvent) {
method bind (line 378) | bind(bindFunction: any) {
function persistEvent (line 400) | function persistEvent(event: PointerEvent) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/Engine.ts
constant BEFORE_LAST_KINEMATICS_DELAY (line 26) | const BEFORE_LAST_KINEMATICS_DELAY = 32;
type Engine (line 29) | interface Engine<Key extends GestureKey> {
method constructor (line 78) | constructor(ctrl: Controller, args: any[], key: Key) {
method state (line 122) | get state() {
method state (line 126) | set state(state) {
method shared (line 133) | get shared() {
method eventStore (line 140) | get eventStore() {
method timeoutStore (line 147) | get timeoutStore() {
method config (line 154) | get config() {
method sharedConfig (line 161) | get sharedConfig() {
method handler (line 168) | get handler() {
method reset (line 172) | reset() {
method start (line 201) | start(event: NonUndefined<State[Key]>['event']) {
method computeValues (line 222) | computeValues(values: Vector2) {
method computeInitial (line 234) | computeInitial() {
method compute (line 244) | compute(event?: NonUndefined<State[Key]>['event']) {
method emit (line 380) | emit() {
method clean (line 402) | clean() {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/HoverEngine.ts
class HoverEngine (line 10) | class HoverEngine extends CoordinatesEngine<'hover'> {
method enter (line 13) | enter(event: PointerEvent) {
method leave (line 22) | leave(event: PointerEvent) {
method bind (line 39) | bind(bindFunction: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/MoveEngine.ts
class MoveEngine (line 10) | class MoveEngine extends CoordinatesEngine<'move'> {
method move (line 13) | move(event: PointerEvent) {
method moveStart (line 20) | moveStart(event: PointerEvent) {
method moveChange (line 28) | moveChange(event: PointerEvent) {
method moveEnd (line 41) | moveEnd(event?: PointerEvent) {
method bind (line 48) | bind(bindFunction: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/PinchEngine.ts
constant SCALE_ANGLE_RATIO_INTENT_DEG (line 12) | const SCALE_ANGLE_RATIO_INTENT_DEG = 30;
constant PINCH_WHEEL_RATIO (line 13) | const PINCH_WHEEL_RATIO = 100;
class PinchEngine (line 15) | class PinchEngine extends Engine<'pinch'> {
method init (line 20) | init() {
method reset (line 27) | reset() {
method computeOffset (line 36) | computeOffset() {
method computeMovement (line 45) | computeMovement() {
method axisIntent (line 50) | axisIntent() {
method restrictToAxis (line 60) | restrictToAxis(v: Vector2) {
method cancel (line 67) | cancel() {
method touchStart (line 79) | touchStart(event: TouchEvent) {
method pointerStart (line 104) | pointerStart(event: PointerEvent) {
method pinchStart (line 132) | pinchStart(
method touchMove (line 145) | touchMove(event: TouchEvent) {
method pointerMove (line 153) | pointerMove(event: PointerEvent) {
method pinchMove (line 166) | pinchMove(
method touchEnd (line 190) | touchEnd(event: TouchEvent) {
method pointerEnd (line 202) | pointerEnd(event: PointerEvent) {
method gestureStart (line 223) | gestureStart(event: WebKitGestureEvent) {
method gestureMove (line 237) | gestureMove(event: WebKitGestureEvent) {
method gestureEnd (line 253) | gestureEnd(event: WebKitGestureEvent) {
method wheel (line 262) | wheel(event: WheelEvent) {
method wheelStart (line 274) | wheelStart(event: WheelEvent) {
method wheelChange (line 279) | wheelChange(event: WheelEvent) {
method wheelEnd (line 318) | wheelEnd() {
method bind (line 325) | bind(bindFunction: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/ScrollEngine.ts
class ScrollEngine (line 10) | class ScrollEngine extends CoordinatesEngine<'scroll'> {
method scroll (line 13) | scroll(event: UIEvent) {
method scrollChange (line 19) | scrollChange(event: UIEvent) {
method scrollEnd (line 32) | scrollEnd() {
method bind (line 39) | bind(bindFunction: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/engines/WheelEngine.ts
type WheelEngine (line 11) | interface WheelEngine extends CoordinatesEngine<'wheel'> {
method wheel (line 20) | wheel(event: WheelEvent) {
method wheelChange (line 26) | wheelChange(event: WheelEvent) {
method wheelEnd (line 38) | wheelEnd() {
method bind (line 45) | bind(bindFunction: any) {
class WheelEngine (line 17) | class WheelEngine extends CoordinatesEngine<'wheel'> {
method wheel (line 20) | wheel(event: WheelEvent) {
method wheelChange (line 26) | wheelChange(event: WheelEvent) {
method wheelEnd (line 38) | wheelEnd() {
method bind (line 45) | bind(bindFunction: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/parser.ts
constant RE_NOT_NATIVE (line 15) | const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/;
function sortHandlers (line 17) | function sortHandlers(_handlers: GestureHandlers) {
type HandlerKey (line 36) | type HandlerKey = 'onDrag' | 'onPinch' | 'onWheel' | 'onMove' | 'onScrol...
function registerGesture (line 38) | function registerGesture(
function parseMergedHandlers (line 76) | function parseMergedHandlers(
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/types/action.ts
type EngineClass (line 11) | type EngineClass<Key extends GestureKey> = {
type Action (line 15) | type Action = {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/types/config.ts
type GestureKey (line 9) | type GestureKey = Exclude<keyof State, 'shared'>;
type CoordinatesKey (line 10) | type CoordinatesKey = Exclude<GestureKey, 'pinch'>;
type GenericOptions (line 12) | type GenericOptions = {
type GestureOptions (line 38) | type GestureOptions<T extends GestureKey> = GenericOptions & {
type Bounds (line 79) | type Bounds = {
type CoordinatesConfig (line 86) | type CoordinatesConfig<Key extends CoordinatesKey = CoordinatesKey> = Ge...
type PinchBounds (line 103) | type PinchBounds = { min?: number; max?: number };
type ModifierKey (line 104) | type ModifierKey = 'ctrlKey' | 'altKey' | 'metaKey' | null;
type PinchConfig (line 106) | type PinchConfig = GestureOptions<'pinch'> & {
type DragBounds (line 135) | type DragBounds = Bounds | HTMLElement | { current: HTMLElement | null };
type MoveAndHoverMouseOnly (line 137) | type MoveAndHoverMouseOnly = {
type MoveConfig (line 144) | type MoveConfig = CoordinatesConfig<'move'> & MoveAndHoverMouseOnly;
type HoverConfig (line 146) | type HoverConfig = MoveAndHoverMouseOnly;
type DragConfig (line 148) | type DragConfig = Omit<CoordinatesConfig<'drag'>, 'axisThreshold' | 'bou...
type UserDragConfig (line 241) | type UserDragConfig = GenericOptions & DragConfig;
type UserPinchConfig (line 242) | type UserPinchConfig = GenericOptions & PinchConfig;
type UserWheelConfig (line 243) | type UserWheelConfig = GenericOptions & CoordinatesConfig<'wheel'>;
type UserScrollConfig (line 244) | type UserScrollConfig = GenericOptions & CoordinatesConfig<'scroll'>;
type UserMoveConfig (line 245) | type UserMoveConfig = GenericOptions & MoveConfig;
type UserHoverConfig (line 246) | type UserHoverConfig = GenericOptions & HoverConfig;
type UserGestureConfig (line 248) | type UserGestureConfig = GenericOptions & {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/types/handlers.ts
type Handler (line 10) | type Handler<Key extends GestureKey, EventType = EventTypes[Key]> = (
type check (line 16) | type check<T extends AnyHandlerEventTypes, Key extends GestureKey> = und...
type UserHandlers (line 20) | type UserHandlers<T extends AnyHandlerEventTypes = EventTypes> = {
type NativeHandlersKeys (line 39) | type NativeHandlersKeys = keyof Omit<DOMHandlers, keyof UserHandlers>;
type GetEventType (line 41) | type GetEventType<Key extends NativeHandlersKeys> = DOMHandlers[Key] ext...
type NativeHandlers (line 47) | type NativeHandlers<T extends AnyHandlerEventTypes = {}> = {
type AnyHandlerEventTypes (line 58) | type AnyHandlerEventTypes = Partial<
type GestureHandlers (line 69) | type GestureHandlers<HandlerType extends AnyHandlerEventTypes = EventTyp...
type InternalHandlers (line 73) | type InternalHandlers = { [Key in GestureKey]?: Handler<Key, any> };
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/types/internalConfig.ts
type InternalGenericOptions (line 10) | type InternalGenericOptions = {
type InternalGestureOptions (line 18) | type InternalGestureOptions<Key extends GestureKey = GestureKey> = {
type InternalCoordinatesOptions (line 31) | type InternalCoordinatesOptions<Key extends CoordinatesKey = Coordinates...
type InternalDragOptions (line 38) | type InternalDragOptions = Omit<InternalCoordinatesOptions<'drag'>, 'axi...
type InternalPinchOptions (line 58) | type InternalPinchOptions = InternalGestureOptions<'pinch'> & {
type MoveAndHoverMouseOnly (line 68) | type MoveAndHoverMouseOnly = {
type InternalConfig (line 72) | type InternalConfig = {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/types/state.ts
type IngKey (line 9) | type IngKey = 'dragging' | 'wheeling' | 'moving' | 'hovering' | 'scrolli...
type SharedGestureState (line 11) | type SharedGestureState = {
type CommonGestureState (line 74) | type CommonGestureState = {
type CoordinatesState (line 189) | type CoordinatesState = CommonGestureState & {
type DragState (line 200) | type DragState = CoordinatesState & {
type PinchState (line 225) | interface PinchState extends CommonGestureState {
type EventTypes (line 255) | type EventTypes = {
type State (line 264) | interface State {
type FullGestureState (line 274) | type FullGestureState<Key extends GestureKey> = SharedGestureState &
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/types/utils.ts
type Vector2 (line 6) | type Vector2 = [number, number];
type WebKitGestureEvent (line 7) | type WebKitGestureEvent = PointerEvent & { scale: number; rotation: numb...
type Target (line 8) | type Target = EventTarget | { current: EventTarget | null };
type PointerType (line 9) | type PointerType = 'mouse' | 'touch' | 'pen';
type NonUndefined (line 12) | type NonUndefined<T> = T extends undefined ? never : T;
type EventHandler (line 13) | type EventHandler<E extends Event = Event> = (event: E) => void;
type DOMHandlers (line 16) | interface DOMHandlers {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/utils/events.ts
constant EVENT_TYPE_MAP (line 9) | const EVENT_TYPE_MAP: any = {
function capitalize (line 16) | function capitalize(string: string) {
function hasCapture (line 23) | function hasCapture(capture = false, actionKey: string) {
function toHandlerProp (line 27) | function toHandlerProp(device: string, action = '', capture: boolean = f...
function parseProp (line 40) | function parseProp(prop: string) {
function toDomEventType (line 53) | function toDomEventType(device: string, action = '') {
function isTouch (line 59) | function isTouch(event: UIEvent) {
function getPointerType (line 63) | function getPointerType(event: UIEvent): PointerType {
function getCurrentTargetTouchList (line 69) | function getCurrentTargetTouchList(event: TouchEvent) {
function getTouchList (line 77) | function getTouchList(event: TouchEvent) {
function getValueEvent (line 83) | function getValueEvent<EventType extends TouchEvent | PointerEvent>(
function distanceAngle (line 89) | function distanceAngle(P1: Touch | PointerEvent, P2: Touch | PointerEven...
function touchIds (line 106) | function touchIds(event: TouchEvent) {
function touchDistanceAngle (line 110) | function touchDistanceAngle(event: TouchEvent, ids: number[]) {
function pointerId (line 115) | function pointerId(event: PointerEvent | TouchEvent) {
function pointerValues (line 120) | function pointerValues(event: PointerEvent | TouchEvent): Vector2 {
constant LINE_HEIGHT (line 127) | const LINE_HEIGHT = 40;
constant PAGE_HEIGHT (line 128) | const PAGE_HEIGHT = 800;
function wheelValues (line 130) | function wheelValues(event: WheelEvent): Vector2 {
function scrollValues (line 143) | function scrollValues(event: UIEvent): Vector2 {
function getEventDetails (line 150) | function getEventDetails(event: any) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/utils/fn.ts
function call (line 6) | function call<T>(v: T | ((...args: any[]) => T), ...args: any[]): T {
function noop (line 15) | function noop() {}
function chain (line 17) | function chain(...fns: Function[]): Function {
function assignDefault (line 30) | function assignDefault<T extends Object>(value: Partial<T> | undefined, ...
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/utils/maths.ts
function clamp (line 8) | function clamp(v: number, min: number, max: number) {
method toVector (line 13) | toVector<T>(v: T | [T, T] | undefined, fallback?: T | [T, T]): [T, T] {
method add (line 17) | add(v1: Vector2, v2: Vector2): Vector2 {
method sub (line 20) | sub(v1: Vector2, v2: Vector2): Vector2 {
method addTo (line 23) | addTo(v1: Vector2, v2: Vector2) {
method subTo (line 27) | subTo(v1: Vector2, v2: Vector2) {
function rubberband (line 39) | function rubberband(distance: number, dimension: number, constant: numbe...
function rubberbandIfOutOfBounds (line 44) | function rubberbandIfOutOfBounds(
function computeRubberband (line 56) | function computeRubberband(
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/core/utils/state.ts
function clampStateInternalMovementToBounds (line 12) | function clampStateInternalMovementToBounds(state: CommonGestureState) {
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/DragGesture.ts
type DragGestureConstructor (line 10) | interface DragGestureConstructor {
type DragGesture (line 18) | interface DragGesture extends Recognizer<'drag'> {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/Gesture.ts
type GestureConstructor (line 23) | interface GestureConstructor {
type Gesture (line 31) | interface Gesture extends Recognizer {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/HoverGesture.ts
type HoverGestureConstructor (line 10) | interface HoverGestureConstructor {
type HoverGesture (line 18) | interface HoverGesture extends Recognizer<'hover'> {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/MoveGesture.ts
type MoveGestureConstructor (line 10) | interface MoveGestureConstructor {
type MoveGesture (line 18) | interface MoveGesture extends Recognizer<'move'> {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/PinchGesture.ts
type PinchGestureConstructor (line 10) | interface PinchGestureConstructor {
type PinchGesture (line 18) | interface PinchGesture extends Recognizer<'pinch'> {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/Recognizer.ts
class Recognizer (line 9) | class Recognizer<GK extends GestureKey | undefined = undefined> {
method constructor (line 16) | constructor(
method destroy (line 32) | destroy() {
method setConfig (line 36) | setConfig(
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/ScrollGesture.ts
type ScrollGestureConstructor (line 10) | interface ScrollGestureConstructor {
type ScrollGesture (line 18) | interface ScrollGesture extends Recognizer<'scroll'> {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/WheelGesture.ts
type WheelGestureConstructor (line 10) | interface WheelGestureConstructor {
type WheelGesture (line 18) | interface WheelGesture extends Recognizer<'wheel'> {}
FILE: packages/canvas-engine/core/src/core/utils/use-gesture/vanilla/createGesture.ts
function createGesture (line 11) | function createGesture(actions: Action[]) {
FILE: packages/canvas-engine/core/src/playground-config.ts
type PlaygroundConfig (line 30) | interface PlaygroundConfig {
function createDefaultPlaygroundConfig (line 49) | function createDefaultPlaygroundConfig(): PlaygroundConfig {
FILE: packages/canvas-engine/core/src/playground-container.ts
function createPluginContextDefault (line 44) | function createPluginContextDefault(container: interfaces.Container): Pl...
function createPlaygroundLayerDefault (line 57) | function createPlaygroundLayerDefault(
function createPlaygroundContainer (line 109) | function createPlaygroundContainer(
FILE: packages/canvas-engine/core/src/playground-contribution.ts
type PlaygroundContribution (line 20) | interface PlaygroundContribution {
class PlaygroundRegistry (line 51) | class PlaygroundRegistry {
method config (line 60) | config(config: Partial<PlaygroundConfig>): void {
method registerLayer (line 64) | registerLayer(layerRegistry: LayerRegistry): void {
method registerEntity (line 68) | registerEntity(entityRegistry: EntityRegistry): void {
method registerEditorState (line 76) | registerEditorState(state: EditorState): void {
FILE: packages/canvas-engine/core/src/playground-mock-tools.ts
type LayerStateProvider (line 30) | type LayerStateProvider = WeakMap<LayerRegistry, LayerTestState>;
type SpyInstance (line 32) | interface SpyInstance {
class LayerTestState (line 41) | class LayerTestState<T extends Layer = Layer> {
method constructor (line 62) | constructor(
method hijackMethod (line 79) | private hijackMethod(layer: Layer, layerMethod: keyof Layer & keyof La...
function createContainer (line 88) | function createContainer(modules?: interfaces.ContainerModule[]): interf...
function createPlayground (line 113) | function createPlayground(modules?: interfaces.ContainerModule[]): Playg...
function getLayerTestState (line 117) | function getLayerTestState<T extends Layer = Layer>(
function createLayerTestState (line 131) | function createLayerTestState<T extends Layer = Layer>(
FILE: packages/canvas-engine/core/src/playground.ts
class Playground (line 41) | class Playground<CONTEXT = PlaygroundContext> implements Disposable {
method onResize (line 56) | get onResize() {
method constructor (line 63) | constructor(
method context (line 156) | get context(): CONTEXT {
method contributions (line 160) | protected get contributions(): PlaygroundContribution[] {
method init (line 164) | init(): void {
method pipelineNode (line 174) | get pipelineNode(): HTMLDivElement {
method setParent (line 178) | setParent(parent: HTMLElement): void {
method zoomEnable (line 193) | get zoomEnable(): boolean {
method zoomEnable (line 197) | set zoomEnable(zoomEnable) {
method flush (line 218) | flush(): void {
method ready (line 232) | ready(): void {
method scrollToView (line 271) | scrollToView(opts?: PlaygroundConfigRevealOpts): Promise<void> {
method resize (line 281) | resize(msg?: PipelineDimension, scrollToCenter = true): boolean {
method focus (line 318) | protected focus(): void {
method blur (line 327) | protected blur(): void {
method focused (line 333) | get focused(): boolean {
method config (line 340) | get config(): PlaygroundConfigEntity {
method editorState (line 347) | get editorState(): EditorStateConfigEntity {
method getConfigEntity (line 351) | getConfigEntity<T extends ConfigEntity>(r: EntityRegistry<T>): T {
method dispose (line 355) | dispose(): void {
method disposed (line 364) | get disposed(): boolean {
method toReactComponent (line 371) | toReactComponent(): React.FC {
method registerLayer (line 378) | registerLayer<P extends Layer = Layer>(
method registerLayers (line 388) | registerLayers(...layerRegistries: LayerRegistry[]): void {
method getLayer (line 395) | getLayer<T extends Layer>(layerRegistry: LayerRegistry<T>): T | undefi...
method onAllLayersRendered (line 399) | get onAllLayersRendered(): Event<void> {
FILE: packages/canvas-engine/core/src/plugin/plugin.ts
type PluginContext (line 11) | interface PluginContext {
type PluginBindConfig (line 33) | interface PluginBindConfig {
type PluginConfig (line 40) | interface PluginConfig<Opts, CTX extends PluginContext = PluginContext> {
type Plugin (line 70) | type Plugin<Options = any> = {
type PluginsProvider (line 79) | interface PluginsProvider<CTX extends PluginContext = PluginContext> {
type PluginCreator (line 83) | type PluginCreator<Options> = (opts: Options) => Plugin<Options>;
function loadPlugins (line 85) | function loadPlugins(plugins: Plugin[], container: interfaces.Container)...
function toPlaygroundContainerModule (line 122) | function toPlaygroundContainerModule<Options, CTX extends PluginContext ...
function definePluginCreator (line 153) | function definePluginCreator<Options, CTX extends PluginContext = Plugin...
FILE: packages/canvas-engine/core/src/react-hooks/use-config-entity.ts
function useConfigEntity (line 17) | function useConfigEntity<T extends ConfigEntity>(
FILE: packages/canvas-engine/core/src/react-hooks/use-entities.ts
function useEntities (line 16) | function useEntities<T extends Entity>(entityRegistry: EntityRegistry): ...
FILE: packages/canvas-engine/core/src/react-hooks/use-entity-data-from-context.ts
function useEntityDataFromContext (line 19) | function useEntityDataFromContext<T extends EntityData>(
FILE: packages/canvas-engine/core/src/react-hooks/use-entity-from-context.ts
function useEntityFromContext (line 18) | function useEntityFromContext<T extends Entity>(listenChange = false): T {
FILE: packages/canvas-engine/core/src/react-hooks/use-listen-events.ts
function useListenEvents (line 17) | function useListenEvents(...events: Event<any>[]): void {
FILE: packages/canvas-engine/core/src/react-hooks/use-playground-container.ts
function usePlaygroundContainer (line 15) | function usePlaygroundContainer(): interfaces.Container {
FILE: packages/canvas-engine/core/src/react-hooks/use-playground-context.ts
function usePlaygroundContext (line 13) | function usePlaygroundContext<T>(): T {
FILE: packages/canvas-engine/core/src/react-hooks/use-playground-drag.ts
type UsePlaygroundDragReturn (line 13) | interface UsePlaygroundDragReturn {
function usePlaygroundDrag (line 20) | function usePlaygroundDrag(): UsePlaygroundDragReturn {
FILE: packages/canvas-engine/core/src/react-hooks/use-playground.ts
function usePlayground (line 14) | function usePlayground(): Playground {
FILE: packages/canvas-engine/core/src/react-hooks/use-service.ts
function useService (line 14) | function useService<T>(identifier: interfaces.ServiceIdentifier<T>): T {
FILE: packages/canvas-engine/core/src/react/playground-react-provider.tsx
type PlaygroundReactProviderProps (line 20) | interface PlaygroundReactProviderProps {
FILE: packages/canvas-engine/core/src/react/playground-react-renderer.tsx
type PlaygroundReactRendererProps (line 13) | interface PlaygroundReactRendererProps {
FILE: packages/canvas-engine/core/src/services/clipboard-service.ts
type ClipboardService (line 11) | interface ClipboardService {
class DefaultClipboardService (line 23) | class DefaultClipboardService implements ClipboardService {
method readText (line 30) | readText(): string {
method writeText (line 34) | writeText(value: string): void {
FILE: packages/canvas-engine/core/src/services/context-menu-service.ts
class ContextMenuService (line 12) | class ContextMenuService {
method rightPanelVisible (line 18) | get rightPanelVisible(): boolean {
method rightPanelVisible (line 22) | set rightPanelVisible(visible: boolean) {
FILE: packages/canvas-engine/core/src/services/logger-service.ts
type LoggerProps (line 9) | interface LoggerProps {
type LoggerEvent (line 14) | enum LoggerEvent {
class LoggerService (line 23) | class LoggerService implements Disposable {
method onAllLayersRendered (line 29) | onAllLayersRendered() {
method onFlushRequest (line 35) | onFlushRequest(renderFrameInterval: number) {
method dispose (line 46) | dispose() {
FILE: packages/canvas-engine/core/src/services/selection-service.ts
class SelectionService (line 15) | class SelectionService implements Disposable {
method selection (line 24) | get selection(): Entity[] {
method isEmpty (line 28) | isEmpty(): boolean {
method selection (line 32) | set selection(selection: Entity<any>[]) {
method changeSelection (line 46) | private changeSelection(selection: Entity<any>[]) {
method dispose (line 51) | dispose() {
FILE: packages/canvas-engine/core/src/services/storage-service.ts
type StorageService (line 13) | interface StorageService {
type LocalStorage (line 27) | interface LocalStorage {
class LocalStorageService (line 32) | class LocalStorageService implements StorageService {
method setData (line 37) | setData<T>(key: string, data: T): void {
method getData (line 41) | getData<T>(key: string, defaultValue?: T): T {
method prefix (line 49) | prefix(key: string) {
method setPrefix (line 53) | setPrefix(prefix: string) {
method init (line 58) | protected init(): void {
FILE: packages/canvas-engine/document/__tests__/flow-document-container.mock.ts
class FlowDocumentMockRegister (line 18) | class FlowDocumentMockRegister implements FlowDocumentContribution {
method registerDocument (line 19) | registerDocument(document: FlowDocument) {
function createDocumentContainer (line 26) | function createDocumentContainer(): interfaces.Container {
FILE: packages/canvas-engine/document/__tests__/flow-document-transformer.test.ts
type TransformTestData (line 13) | interface TransformTestData {
function getTransformData (line 21) | function getTransformData(document: FlowDocument): Record<string, Transf...
FILE: packages/canvas-engine/document/__tests__/flow-document.test.ts
function normalizeNode (line 44) | function normalizeNode(node: FlowNodeJSON): FlowNodeJSON {
function jsonEqual (line 51) | function jsonEqual(from: FlowDocumentJSON, to: FlowDocumentJSON) {
FILE: packages/canvas-engine/document/__tests__/flow-node-entity.spec.ts
type BlockData (line 13) | interface BlockData {
FILE: packages/canvas-engine/document/__tests__/flow-node-registry.spec.ts
function registerNode (line 11) | function registerNode(doc: FlowDocument, newRegistry: FlowNodeRegistry):...
method onCreate (line 19) | onCreate(node, json) {
FILE: packages/canvas-engine/document/__tests__/flow-virtual-tree.spec.ts
type Node (line 12) | interface Node {
function addBase (line 24) | function addBase(): void {
function get (line 32) | function get(id: string): Node {
function getInfo (line 36) | function getInfo(id: string): FlowVirtualTree.NodeInfo<Node> {
FILE: packages/canvas-engine/document/src/datas/flow-node-render-data.ts
type FlowNodeRenderSchema (line 13) | interface FlowNodeRenderSchema {
class FlowNodeRenderData (line 28) | class FlowNodeRenderData extends EntityData<FlowNodeRenderSchema> {
method key (line 39) | get key(): string {
method getDefaultData (line 43) | getDefaultData(): FlowNodeRenderSchema {
method updateExtInfo (line 56) | updateExtInfo(info: Record<string, any>, fullUpdate?: boolean) {
method getExtInfo (line 67) | getExtInfo(): Record<string, any> | undefined {
method constructor (line 71) | constructor(entity: FlowNodeEntity) {
method addable (line 80) | get addable(): boolean {
method expandable (line 84) | get expandable(): boolean {
method draggable (line 88) | get draggable(): boolean {
method expanded (line 98) | get expanded(): boolean {
method expanded (line 102) | set expanded(expanded: boolean) {
method toggleExpand (line 109) | toggleExpand() {
method toggleMouseEnter (line 115) | toggleMouseEnter(silent = false) {
method toggleMouseLeave (line 137) | toggleMouseLeave(silent = false) {
method hidden (line 151) | get hidden(): boolean {
method hovered (line 155) | set hovered(hovered: boolean) {
method hovered (line 160) | get hovered() {
method dragging (line 164) | get dragging(): boolean {
method dragging (line 168) | set dragging(dragging: boolean) {
method activated (line 175) | set activated(activated: boolean) {
method activated (line 186) | get activated() {
method stackIndex (line 194) | get stackIndex(): number {
method stackIndex (line 198) | set stackIndex(index: number) {
method lineActivated (line 202) | get lineActivated() {
method node (line 215) | get node(): HTMLDivElement {
method dispose (line 223) | dispose() {
FILE: packages/canvas-engine/document/src/datas/flow-node-transform-data.ts
type FlowNodeTransformSchema (line 18) | interface FlowNodeTransformSchema {
class FlowNodeTransformData (line 22) | class FlowNodeTransformData extends EntityData<FlowNodeTransformSchema> {
method origin (line 34) | get origin() {
method key (line 38) | get key(): string {
method getDefaultData (line 42) | getDefaultData(): FlowNodeTransformSchema {
method constructor (line 50) | constructor(entity: FlowNodeEntity) {
method collapsed (line 73) | get collapsed(): boolean {
method collapsed (line 77) | set collapsed(collapsed: boolean) {
method size (line 90) | get size(): SizeSchema {
method position (line 97) | get position(): PositionSchema {
method position (line 105) | set position(position: PositionSchema) {
method size (line 111) | set size(size: SizeSchema) {
method inputPoint (line 122) | get inputPoint() {
method defaultInputPoint (line 131) | get defaultInputPoint() {
method defaultOutputPoint (line 137) | get defaultOutputPoint() {
method outputPoint (line 143) | get outputPoint() {
method originDeltaX (line 155) | get originDeltaX(): number {
method originDeltaY (line 180) | get originDeltaY(): number {
method bounds (line 205) | get bounds(): Rectangle {
method boundsWithPadding (line 220) | get boundsWithPadding(): Rectangle {
method isContainer (line 234) | get isContainer(): boolean {
method localBounds (line 241) | get localBounds(): Rectangle {
method padding (line 257) | get padding() {
method setParentTransform (line 261) | setParentTransform(transform?: FlowNodeTransformData): void {
method spacing (line 269) | get spacing(): number {
method inlineSpacingPre (line 274) | get inlineSpacingPre(): number {
method inlineSpacingAfter (line 279) | get inlineSpacingAfter(): number {
method minInlineBlockSpacing (line 284) | get minInlineBlockSpacing(): number {
method children (line 291) | get children(): FlowNodeTransformData[] {
method pre (line 300) | get pre(): FlowNodeTransformData | undefined {
method originParent (line 304) | get originParent(): FlowNodeTransformData | undefined {
method isFirst (line 308) | get isFirst(): boolean {
method isLast (line 312) | get isLast(): boolean {
method lastChild (line 316) | get lastChild(): FlowNodeTransformData | undefined {
method firstChild (line 320) | get firstChild(): FlowNodeTransformData | undefined {
method next (line 327) | get next(): FlowNodeTransformData | undefined {
method parent (line 334) | get parent(): FlowNodeTransformData | undefined {
FILE: packages/canvas-engine/document/src/datas/flow-node-transition-data.ts
type FlowNodeTransitionSchema (line 20) | interface FlowNodeTransitionSchema {}
class FlowNodeTransitionData (line 67) | class FlowNodeTransitionData extends EntityData<FlowNodeTransitionSchema> {
method getDefaultData (line 77) | getDefaultData(): FlowNodeTransitionSchema {
method formatLines (line 81) | formatLines(lines: FlowTransitionLine[]) {
method formatLabels (line 88) | formatLabels(labels: FlowTransitionLabel[]) {
method lines (line 95) | get lines(): FlowTransitionLine[] {
method labels (line 118) | get labels() {
method constructor (line 166) | constructor(entity: FlowNodeEntity) {
method collapsed (line 175) | get collapsed() {
method isNodeEnd (line 179) | get isNodeEnd(): boolean {
FILE: packages/canvas-engine/document/src/entities/flow-document-transformer-entity.ts
type FlowDocumentTransformerEntityConfig (line 12) | interface FlowDocumentTransformerEntityConfig extends EntityOpts {
class FlowDocumentTransformerEntity (line 19) | class FlowDocumentTransformerEntity extends ConfigEntity<
method constructor (line 38) | constructor(conf: FlowDocumentTransformerEntityConfig) {
method getDefaultConfig (line 50) | getDefaultConfig(): { loading: boolean; treeVersion: number } {
method loading (line 57) | get loading(): boolean {
method loading (line 61) | set loading(loading) {
method updateTransformsTree (line 71) | updateTransformsTree(): void {
method clear (line 87) | clear(): void {
method isTreeDirty (line 92) | isTreeDirty(): boolean {
method refresh (line 102) | refresh(): void {
FILE: packages/canvas-engine/document/src/entities/flow-node-entity.ts
type FlowNodeEntityConfig (line 19) | interface FlowNodeEntityConfig extends EntityOpts {
type FlowNodeInitData (line 26) | interface FlowNodeInitData {
class FlowNodeEntity (line 34) | class FlowNodeEntity extends Entity<FlowNodeEntityConfig> {
method constructor (line 66) | constructor(conf: FlowNodeEntityConfig) {
method initData (line 84) | initData(initConf: FlowNodeInitData): void {
method isStart (line 100) | get isStart(): boolean {
method isFirst (line 104) | get isFirst(): boolean {
method isLast (line 108) | get isLast(): boolean {
method isInlineBlocks (line 115) | get isInlineBlocks(): boolean {
method isInlineBlock (line 125) | get isInlineBlock(): boolean {
method isNodeEnd (line 138) | get isNodeEnd(): boolean {
method addChild (line 161) | addChild(child: FlowNodeEntity, index?: number) {
method hasChild (line 166) | get hasChild(): boolean {
method pre (line 170) | get pre(): FlowNodeEntity | undefined {
method next (line 174) | get next(): FlowNodeEntity | undefined {
method parent (line 178) | get parent(): FlowNodeEntity | undefined {
method getNodeRegistry (line 182) | getNodeRegistry<M extends FlowNodeRegistry = FlowNodeRegistry & { meta...
method getNodeRegister (line 192) | getNodeRegister<M extends FlowNodeRegistry = FlowNodeRegistry>(): M {
method getNodeMeta (line 196) | getNodeMeta<M extends FlowNodeMeta = FlowNodeMeta>(): M & Required<Flo...
method allChildren (line 212) | get allChildren(): FlowNodeEntity[] {
method allCollapsedChildren (line 224) | get allCollapsedChildren(): FlowNodeEntity[] {
method collapsedChildren (line 241) | get collapsedChildren(): FlowNodeEntity[] {
method blocks (line 248) | get blocks(): FlowNodeEntity[] {
method lastBlock (line 255) | get lastBlock(): FlowNodeEntity | undefined {
method lastCollapsedChild (line 262) | get lastCollapsedChild(): FlowNodeEntity | undefined {
method children (line 270) | get children(): FlowNodeEntity[] {
method lastChild (line 274) | get lastChild(): FlowNodeEntity | undefined {
method firstChild (line 279) | get firstChild(): FlowNodeEntity | undefined {
method memoLocal (line 283) | memoLocal<T>(key: string, fn: () => T): T {
method memoGlobal (line 292) | memoGlobal<T>(key: string, fn: () => T): T {
method clearMemoGlobal (line 301) | clearMemoGlobal() {
method clearMemoLocal (line 305) | clearMemoLocal() {
method childrenLength (line 309) | get childrenLength() {
method collapsed (line 313) | get collapsed(): boolean {
method collapsed (line 318) | set collapsed(collapsed) {
method hidden (line 324) | get hidden(): boolean {
method openInsideCollapsed (line 329) | openInsideCollapsed() {
method getJSONData (line 336) | getJSONData(): any {
method toJSON (line 344) | toJSON(): FlowNodeJSON {
method isVertical (line 348) | get isVertical(): boolean {
method updateExtInfo (line 356) | updateExtInfo<T extends Record<string, any> = Record<string, any>>(
method getExtInfo (line 366) | getExtInfo<T extends Record<string, any> = Record<string, any>>(): T {
method onExtInfoChange (line 370) | get onExtInfoChange(): Event<{ newInfo: any; oldInfo: any }> {
method renderData (line 377) | get renderData(): FlowNodeRenderData {
method transform (line 384) | get transform(): FlowNodeTransformData {
method bounds (line 391) | get bounds(): Rectangle {
method isExtend (line 398) | isExtend(parentType: FlowNodeType): boolean {
method isTypeOrExtendType (line 406) | isTypeOrExtendType(parentType: FlowNodeType): boolean {
function is (line 412) | function is(obj: Entity): obj is FlowNodeEntity {
FILE: packages/canvas-engine/document/src/entities/flow-renderer-state-entity.ts
type FlowRendererStateEntityConfig (line 13) | interface FlowRendererStateEntityConfig extends EntityOpts {}
type FlowRendererState (line 15) | interface FlowRendererState {
class FlowRendererStateEntity (line 28) | class FlowRendererStateEntity extends ConfigEntity<
method getDefaultConfig (line 34) | getDefaultConfig() {
method constructor (line 38) | constructor(conf: FlowRendererStateEntityConfig) {
method getNodeHovered (line 42) | getNodeHovered(): FlowNodeEntity | undefined {
method setNodeHovered (line 48) | setNodeHovered(node: FlowNodeEntity | undefined): void {
method dragging (line 54) | get dragging() {
method setDragging (line 58) | setDragging(dragging: boolean) {
method isBranch (line 64) | get isBranch() {
method setIsBranch (line 68) | setIsBranch(isBranch: boolean) {
method getDragLabelSide (line 74) | getDragLabelSide(): LABEL_SIDE_TYPE | undefined {
method setDragLabelSide (line 78) | setDragLabelSide(dragLabelSide?: LABEL_SIDE_TYPE): void {
method getNodeDroppingId (line 84) | getNodeDroppingId(): string | undefined {
method setNodeDroppingId (line 88) | setNodeDroppingId(nodeDroppingId?: string): void {
method getDragStartEntity (line 94) | getDragStartEntity(): FlowNodeEntity | undefined {
method setDragStartEntity (line 99) | setDragStartEntity(node?: FlowNodeEntity): void {
method getDragEntities (line 106) | getDragEntities(): FlowNodeEntity[] {
method setDragEntities (line 112) | setDragEntities(nodes: FlowNodeEntity[]): void {
method onNodeHoveredChange (line 121) | onNodeHoveredChange(
FILE: packages/canvas-engine/document/src/flow-document-config.ts
class FlowDocumentConfig (line 15) | class FlowDocumentConfig {
method constructor (line 20) | constructor(
method get (line 26) | get(key: string): any {
method set (line 30) | set(key: string, value: any): void {
method registerConfigs (line 37) | registerConfigs(config: Record<string, any>) {
FILE: packages/canvas-engine/document/src/flow-document-contribution.ts
type FlowDocumentContribution (line 10) | interface FlowDocumentContribution<T extends FlowDocument = FlowDocument> {
FILE: packages/canvas-engine/document/src/flow-document-options.ts
type FlowDocumentOptions (line 21) | interface FlowDocumentOptions {
FILE: packages/canvas-engine/document/src/flow-document.ts
type FlowDocumentProvider (line 33) | type FlowDocumentProvider = () => FlowDocument;
class FlowDocument (line 39) | class FlowDocument<T = FlowDocumentJSON> implements Disposable {
method disposed (line 121) | get disposed(): boolean {
method init (line 126) | init(): void {
method fromJSON (line 152) | fromJSON(json: FlowDocumentJSON | any, fireRender = true): void {
method layout (line 175) | get layout(): FlowLayout {
method load (line 183) | async load(): Promise<void> {
method loading (line 187) | get loading(): boolean {
method fireRender (line 194) | fireRender(): void {
method addFromNode (line 206) | addFromNode(fromNode: FlowNodeEntity | string, json: FlowNodeJSON): Fl...
method removeNode (line 221) | removeNode(node: FlowNodeEntity | string) {
method addNode (line 234) | addNode(data: AddNodeData, addedNodes?: FlowNodeEntity[]): FlowNodeEnt...
method addBlocksAsChildren (line 305) | addBlocksAsChildren(
method addInlineBlocks (line 334) | addInlineBlocks(
method addBlock (line 368) | addBlock(
method getNode (line 414) | getNode(id: string): FlowNodeEntity | undefined {
method registerFlowNodes (line 423) | registerFlowNodes<T extends FlowNodeRegistry<any>>(...registries: T[])...
method isExtend (line 449) | isExtend(currentType: FlowNodeType, extendType: FlowNodeType): boolean {
method isTypeOrExtendType (line 458) | isTypeOrExtendType(currentType: FlowNodeType, extendType: FlowNodeType...
method toJSON (line 465) | toJSON(): T | any {
method getNodeRegister (line 480) | getNodeRegister<T extends FlowNodeRegistry = FlowNodeRegistry>(
method getNodeRegistry (line 487) | getNodeRegistry<T extends FlowNodeRegistry = FlowNodeRegistry>(
method registerNodeDatas (line 545) | registerNodeDatas(...nodeDatas: EntityDataRegistry[]): void {
method traverse (line 577) | traverse(
method size (line 585) | get size(): number {
method hasNode (line 589) | hasNode(nodeId: string): boolean {
method getAllNodes (line 593) | getAllNodes(): FlowNodeEntity[] {
method toString (line 597) | toString(showType?: boolean): string {
method getRenderDatas (line 604) | getRenderDatas<T extends EntityData>(
method toNodeJSON (line 616) | toNodeJSON(node: FlowNodeEntity): FlowNodeJSON {
method moveNodes (line 655) | moveNodes({
method moveChildNodes (line 690) | moveChildNodes({
method registerLayout (line 724) | registerLayout(layout: FlowLayout) {
method setLayout (line 732) | setLayout(layoutKey: string) {
method toggleFixedLayout (line 746) | toggleFixedLayout() {
method dispose (line 754) | dispose() {
FILE: packages/canvas-engine/document/src/flow-render-tree.ts
class FlowRenderTree (line 14) | class FlowRenderTree<T extends FlowNodeEntity> extends FlowVirtualTree<T> {
method constructor (line 25) | constructor(readonly root: T, originTree: FlowVirtualTree<T>, document...
method isCollapsed (line 32) | isCollapsed(node: T): boolean {
method collapsedNodeList (line 36) | get collapsedNodeList(): T[] {
method setCollapsed (line 45) | setCollapsed(node: T, collapsed: boolean): void {
method openNodeInsideCollapsed (line 57) | openNodeInsideCollapsed(node: T) {
method updateRenderStruct (line 74) | updateRenderStruct(): void {
method hideCollapsed (line 89) | protected hideCollapsed() {
method isNodeEnd (line 120) | isNodeEnd(node: T): boolean {
method refineBranch (line 141) | protected refineBranch(block: T) {
method dragNextNodesToBlock (line 174) | protected dragNextNodesToBlock(toBlock: T, next: T) {
method getInfo (line 206) | getInfo(node: T): FlowVirtualTree.NodeInfo<T> {
method getOriginInfo (line 212) | getOriginInfo(node: T): FlowVirtualTree.NodeInfo<T> {
method getCollapsedChildren (line 217) | getCollapsedChildren(node: T): T[] {
method remove (line 221) | remove(): void {
method addChild (line 225) | addChild(): T {
method insertAfter (line 229) | insertAfter(): void {
method removeParent (line 233) | removeParent(): void {
FILE: packages/canvas-engine/document/src/flow-virtual-tree.ts
class FlowVirtualTree (line 14) | class FlowVirtualTree<T extends { id: string; flowNodeType?: FlowNodeTyp...
method constructor (line 26) | constructor(readonly root: T) {}
method dispose (line 28) | dispose() {
method getInfo (line 33) | getInfo(node: T): FlowVirtualTree.NodeInfo<T> {
method clear (line 42) | clear(): void {
method cloneMap (line 46) | cloneMap(): Map<T, FlowVirtualTree.NodeInfo<T>> {
method clone (line 58) | clone(): FlowVirtualTree<T> {
method remove (line 64) | remove(node: T, withChildren = true): void {
method addChild (line 73) | addChild(parent: T, child: T, index?: number): T {
method moveChilds (line 97) | moveChilds(parent: T, childs: T[], index?: number): T[] {
method getById (line 127) | getById(id: string): T | undefined {
method insertAfter (line 138) | insertAfter(before: T, after: T) {
method removeParent (line 157) | removeParent(node: T): void {
method _removeChildren (line 169) | private _removeChildren(node: T): void {
method getParent (line 180) | getParent(node: T): T | undefined {
method getPre (line 184) | getPre(node: T): T | undefined {
method getNext (line 188) | getNext(node: T): T | undefined {
method getChildren (line 192) | getChildren(node: T): T[] {
method traverse (line 196) | traverse(
method fireTreeChange (line 212) | fireTreeChange(): void {
method size (line 216) | get size(): number {
method toString (line 220) | toString(showType?: boolean): string {
type NodeInfo (line 238) | interface NodeInfo<T> {
FILE: packages/canvas-engine/document/src/layout/horizontal-fixed-layout.ts
constant DEFAULT_SCROLL (line 15) | const DEFAULT_SCROLL = -36;
type FlowNodeTransformStructData (line 20) | interface FlowNodeTransformStructData {
type FlowNodeTransformStructData (line 27) | interface FlowNodeTransformStructData {
function isStructDataEqual (line 32) | function isStructDataEqual(
class HorizontalFixedLayout (line 40) | class HorizontalFixedLayout implements FlowLayout {
method document (line 51) | get document(): FlowDocument {
method reload (line 55) | reload() {
method update (line 62) | update(): void {
method updateLocalTransform (line 71) | updateLocalTransform(node: FlowNodeEntity, forceChange = false): boole...
method onAfterUpdateLocalTransform (line 145) | onAfterUpdateLocalTransform(transform: FlowNodeTransformData) {
method getNodeTransform (line 156) | getNodeTransform(node: FlowNodeEntity): FlowNodeTransformData {
method getPadding (line 160) | getPadding(node: FlowNodeEntity): PaddingSchema {
method getInitScroll (line 180) | getInitScroll(contentSize: SizeSchema): ScrollSchema {
method getDefaultInputPoint (line 187) | getDefaultInputPoint(node: FlowNodeEntity): IPoint {
method getDefaultOutputPoint (line 191) | getDefaultOutputPoint(node: FlowNodeEntity): IPoint {
method getDefaultNodeOrigin (line 195) | getDefaultNodeOrigin(): OriginSchema {
FILE: packages/canvas-engine/document/src/layout/vertical-fixed-layout.ts
constant DEFAULT_SCROLL (line 15) | const DEFAULT_SCROLL = -36;
type FlowNodeTransformStructData (line 20) | interface FlowNodeTransformStructData {
type FlowNodeTransformStructData (line 27) | interface FlowNodeTransformStructData {
function isStructDataEqual (line 32) | function isStructDataEqual(
class VerticalFixedLayout (line 40) | class VerticalFixedLayout implements FlowLayout {
method document (line 51) | get document(): FlowDocument {
method reload (line 55) | reload() {
method update (line 62) | update(): void {
method updateLocalTransform (line 71) | updateLocalTransform(node: FlowNodeEntity, forceChange = false): boole...
method onAfterUpdateLocalTransform (line 145) | onAfterUpdateLocalTransform(transform: FlowNodeTransformData) {
method getNodeTransform (line 156) | getNodeTransform(node: FlowNodeEntity): FlowNodeTransformData {
method getPadding (line 160) | getPadding(node: FlowNodeEntity): PaddingSchema {
method getInitScroll (line 180) | getInitScroll(contentSize: SizeSchema): ScrollSchema {
method getDefaultInputPoint (line 187) | getDefaultInputPoint(node: FlowNodeEntity): IPoint {
method getDefaultOutputPoint (line 191) | getDefaultOutputPoint(node: FlowNodeEntity): IPoint {
method getDefaultNodeOrigin (line 195) | getDefaultNodeOrigin(): OriginSchema {
FILE: packages/canvas-engine/document/src/services/flow-drag-service.ts
class FlowDragService (line 25) | class FlowDragService {
method renderState (line 43) | get renderState(): FlowRendererStateEntity {
method dragStartNode (line 48) | get dragStartNode(): FlowNodeEntity {
method dragNodes (line 53) | get dragNodes(): FlowNodeEntity[] {
method dropNodeId (line 58) | get dropNodeId(): string | undefined {
method isDragBranch (line 63) | get isDragBranch(): boolean {
method nodeDragIdsWithChildren (line 68) | get nodeDragIdsWithChildren(): string[] {
method dragging (line 72) | get dragging(): boolean {
method labelSide (line 76) | get labelSide(): LABEL_SIDE_TYPE | undefined {
method dropBranch (line 83) | dropBranch(): void {
method dropCreateNode (line 91) | async dropCreateNode(
method dropNode (line 114) | dropNode(): void {
method isDroppableNode (line 143) | isDroppableNode(node: FlowNodeEntity) {
method isDroppableBranch (line 180) | isDroppableBranch(node: FlowNodeEntity, side: LABEL_SIDE_TYPE = LABEL_...
FILE: packages/canvas-engine/document/src/services/flow-group-service/flow-group-controller.ts
class FlowGroupController (line 13) | class FlowGroupController {
method constructor (line 14) | private constructor(public readonly groupNode: FlowNodeEntity) {}
method nodes (line 16) | public get nodes(): FlowNodeEntity[] {
method collapsed (line 20) | public get collapsed(): boolean {
method collapse (line 25) | public collapse(): void {
method expand (line 29) | public expand(): void {
method bounds (line 34) | public get bounds(): Rectangle {
method isStartNode (line 41) | public isStartNode(node?: FlowNodeEntity): boolean {
method isEndNode (line 53) | public isEndNode(node?: FlowNodeEntity): boolean {
method note (line 64) | public set note(note: string) {
method note (line 68) | public get note(): string {
method noteHeight (line 72) | public set noteHeight(height: number) {
method noteHeight (line 76) | public get noteHeight(): number {
method positionConfig (line 80) | public get positionConfig(): Record<string, number> {
method collapsed (line 84) | private set collapsed(collapsed: boolean) {
method hovered (line 93) | public set hovered(hovered: boolean) {
method hovered (line 106) | public get hovered(): boolean {
method create (line 111) | public static create(groupNode?: FlowNodeEntity): FlowGroupController ...
FILE: packages/canvas-engine/document/src/services/flow-group-service/flow-group-service.ts
class FlowGroupService (line 17) | class FlowGroupService {
method createGroup (line 24) | public createGroup(nodes: FlowNodeEntity[]): FlowNodeEntity | undefined {
method deleteGroup (line 55) | public deleteGroup(groupNode: FlowNodeEntity): void {
method ungroup (line 70) | public ungroup(groupNode: FlowNodeEntity): void {
method getAllGroups (line 91) | public getAllGroups(): FlowGroupController[] {
method groupController (line 100) | public groupController(group: FlowNodeEntity): FlowGroupController | u...
method validate (line 104) | public static validate(nodes: FlowNodeEntity[]): boolean {
FILE: packages/canvas-engine/document/src/services/flow-operation-base-service.ts
class FlowOperationBaseServiceImpl (line 34) | class FlowOperationBaseServiceImpl implements FlowOperationBaseService {
method init (line 52) | protected init() {
method addNode (line 56) | addNode(nodeJSON: FlowNodeJSON, config: AddNodeConfig = {}): FlowNodeE...
method addFromNode (line 99) | addFromNode(fromNode: FlowNodeEntityOrId, nodeJSON: FlowNodeJSON): Flo...
method deleteNode (line 103) | deleteNode(node: FlowNodeEntityOrId): void {
method deleteNodes (line 107) | deleteNodes(nodes: FlowNodeEntityOrId[]): void {
method addBlock (line 113) | addBlock(
method moveNode (line 122) | moveNode(node: FlowNodeEntityOrId, config: MoveNodeConfig = {}) {
method dragNodes (line 150) | dragNodes({ dropNode, nodes }: { dropNode: FlowNodeEntity; nodes: Flow...
method apply (line 191) | apply(operation: FlowOperation): any {
method transact (line 286) | transact(transaction: () => void) {
method dispose (line 290) | dispose() {
method toId (line 294) | protected toId(node: FlowNodeEntityOrId): string {
method toNodeEntity (line 298) | protected toNodeEntity(node: FlowNodeEntityOrId): FlowNodeEntity | und...
method getNodeIndex (line 302) | protected getNodeIndex(node: FlowNodeEntityOrId): number {
method doMoveNode (line 313) | protected doMoveNode(node: FlowNodeEntity, newParent: FlowNodeEntity, ...
FILE: packages/canvas-engine/document/src/typings/flow-group.ts
type FlowGroupJSON (line 6) | interface FlowGroupJSON {
FILE: packages/canvas-engine/document/src/typings/flow-layout.ts
type FlowLayoutDefault (line 14) | enum FlowLayoutDefault {
function isVertical (line 20) | function isVertical(layout: FlowLayout): boolean {
type FlowLayoutContribution (line 25) | interface FlowLayoutContribution {
type FlowLayout (line 32) | interface FlowLayout {
FILE: packages/canvas-engine/document/src/typings/flow-node-register.ts
type FlowNodeMeta (line 26) | interface FlowNodeMeta {
constant DEFAULT_SPACING (line 98) | const DEFAULT_SPACING = {
type DRAGGING_TYPE (line 124) | enum DRAGGING_TYPE {
type LABEL_SIDE_TYPE (line 132) | enum LABEL_SIDE_TYPE {
constant DEFAULT_SIZE (line 141) | const DEFAULT_SIZE = {
type FlowNodeRegistry (line 181) | interface FlowNodeRegistry<M extends FlowNodeMeta = FlowNodeMeta> {
function mergeChildRegistries (line 309) | function mergeChildRegistries(
function merge (line 326) | function merge(
function extend (line 349) | function extend(
FILE: packages/canvas-engine/document/src/typings/flow-operation.ts
type OperationType (line 12) | enum OperationType {
type AddOrDeleteFromNodeOperationValue (line 30) | interface AddOrDeleteFromNodeOperationValue {
type AddOrDeleteNodeOperationValue (line 35) | interface AddOrDeleteNodeOperationValue {
type AddFromNodeOperation (line 40) | interface AddFromNodeOperation {
type DeleteFromNodeOperation (line 45) | interface DeleteFromNodeOperation {
type AddOrDeleteBlockValue (line 50) | interface AddOrDeleteBlockValue {
type createOrUngroupValue (line 57) | interface createOrUngroupValue {
type AddBlockOperation (line 63) | interface AddBlockOperation {
type DeleteBlockOperation (line 68) | interface DeleteBlockOperation {
type CreateGroupOperation (line 73) | interface CreateGroupOperation {
type UngroupOperation (line 78) | interface UngroupOperation {
type MoveNodesOperationValue (line 83) | interface MoveNodesOperationValue {
type MoveNodesOperation (line 89) | interface MoveNodesOperation {
type AddOrDeleteNodesOperationValue (line 94) | interface AddOrDeleteNodesOperationValue {
type AddNodesOperation (line 99) | interface AddNodesOperation {
type DeleteNodesOperation (line 104) | interface DeleteNodesOperation {
type MoveChildNodesOperationValue (line 109) | interface MoveChildNodesOperationValue {
type MoveBlockOperationValue (line 117) | type MoveBlockOperationValue = {
type MoveBlockOperation (line 125) | interface MoveBlockOperation {
type MoveChildNodesOperation (line 130) | interface MoveChildNodesOperation {
type AddChildNodeOperation (line 135) | interface AddChildNodeOperation {
type DeleteChildNodeOperation (line 140) | interface DeleteChildNodeOperation {
type AddOrDeleteChildNodeValue (line 145) | interface AddOrDeleteChildNodeValue {
type AddNodeOperation (line 153) | interface AddNodeOperation {
type DeleteNodeOperation (line 158) | interface DeleteNodeOperation {
type AddOrDeleteNodeValue (line 163) | interface AddOrDeleteNodeValue {
type FlowOperation (line 170) | type FlowOperation =
type FlowNodeEntityOrId (line 187) | type FlowNodeEntityOrId = string | FlowNodeEntity;
type AddNodeConfig (line 190) | type AddNodeConfig = {
type AddBlockConfig (line 202) | interface AddBlockConfig {
type MoveNodeConfig (line 212) | interface MoveNodeConfig {
type OnNodeAddEvent (line 222) | interface OnNodeAddEvent {
type OnNodeMoveEvent (line 230) | interface OnNodeMoveEvent {
type FlowOperationBaseService (line 238) | interface FlowOperationBaseService extends Disposable {
FILE: packages/canvas-engine/document/src/typings/flow-transition.ts
type FlowTransitionLineEnum (line 12) | enum FlowTransitionLineEnum {
type Vertex (line 21) | interface Vertex extends IPoint {
type FlowTransitionLine (line 33) | interface FlowTransitionLine {
type FlowTransitionLabelEnum (line 49) | enum FlowTransitionLabelEnum {
type FlowTransitionLabel (line 58) | interface FlowTransitionLabel {
type AdderProps (line 77) | interface AdderProps {
type CollapseProps (line 85) | interface CollapseProps {
type CustomLabelProps (line 93) | interface CustomLabelProps {
type CollapseAdderProps (line 98) | interface CollapseAdderProps extends AdderProps, CollapseProps {
type DragNodeProps (line 102) | interface DragNodeProps {
FILE: packages/canvas-engine/document/src/typings/flow.ts
type FlowNodeType (line 9) | type FlowNodeType = string | number;
type FlowNodeJSON (line 14) | interface FlowNodeJSON {
type FlowDocumentJSON (line 22) | type FlowDocumentJSON = {
type FlowNodeBaseType (line 26) | enum FlowNodeBaseType {
type FlowNodeSplitType (line 48) | enum FlowNodeSplitType {
type FlowDocumentConfigEnum (line 54) | enum FlowDocumentConfigEnum {
constant FLOW_DEFAULT_HIDDEN_TYPES (line 59) | const FLOW_DEFAULT_HIDDEN_TYPES: FlowNodeType[] = [
type AddNodeData (line 65) | type AddNodeData = FlowNodeJSON & {
FILE: packages/canvas-engine/fixed-layout-core/__tests__/flow-activities.mock.ts
function createDocumentContainer (line 16) | function createDocumentContainer(): interfaces.Container {
method addChild (line 151) | addChild(node, json, options = {}) {
FILE: packages/canvas-engine/fixed-layout-core/__tests__/flow-activities.spec.ts
type TransformTestData (line 25) | interface TransformTestData {
function getTransformData (line 33) | function getTransformData(document: FlowDocument): Record<string, Transf...
function refreshTwice (line 57) | function refreshTwice(data: FlowDocumentJSON): Record<string, TransformT...
function get (line 67) | function get(key: string): FlowNodeTransformData {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/block-icon.ts
method getLabels (line 27) | getLabels(transition) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/block-order-icon.ts
method getLabels (line 23) | getLabels(transition) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/block.ts
method getLines (line 27) | getLines(transition) {
method getInputPoint (line 100) | getInputPoint(trans) {
method getOutputPoint (line 104) | getOutputPoint(trans, layout) {
method getLabels (line 118) | getLabels(transition) {
method addChild (line 182) | addChild(node, json, options = {}) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/dynamic-split.ts
method getLabels (line 37) | getLabels(transition) {
method onCreate (line 49) | onCreate(node, json) {
method getInputPoint (line 52) | getInputPoint(transform) {
method getOutputPoint (line 56) | getOutputPoint(transform, layout) {
method addChild (line 79) | addChild(node, json, options = {}) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/empty.ts
method getLabels (line 27) | getLabels(transition) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/end.ts
method getLines (line 20) | getLines() {
method getLabels (line 23) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/inline-blocks.ts
method getChildDelta (line 50) | getChildDelta(child, layout) {
method getDelta (line 94) | getDelta(trans, layout) {
method getLabels (line 123) | getLabels(transition) {
method getLines (line 126) | getLines() {
method getInputPoint (line 130) | getInputPoint(transform, layout) {
method getOutputPoint (line 143) | getOutputPoint(transform, layout) {
function getBranchAdderLabel (line 166) | function getBranchAdderLabel(transition: FlowNodeTransitionData) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/input.ts
method getLines (line 24) | getLines(transition, layout) {
method getLabels (line 92) | getLabels(transition) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/loop-extends/constants.ts
type LoopTypeEnum (line 8) | enum LoopTypeEnum {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/loop-extends/loop-empty-branch.ts
method getLabels (line 20) | getLabels(transition) {
method onAfterUpdateLocalTransform (line 44) | onAfterUpdateLocalTransform(transform): void {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/loop-extends/loop-inline-blocks.ts
method getLines (line 45) | getLines(transition) {
method getLabels (line 96) | getLabels(transition) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/loop-extends/loop-left-empty-block.ts
method onAfterUpdateLocalTransform (line 20) | onAfterUpdateLocalTransform(transform): void {
method getLines (line 37) | getLines() {
method getLabels (line 40) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/loop.ts
method onCreate (line 58) | onCreate(node: FlowNodeEntity, json: FlowNodeJSON) {
method getLabels (line 118) | getLabels(transition) {
method getInputPoint (line 145) | getInputPoint(transform) {
method getOutputPoint (line 158) | getOutputPoint(transform) {
method addChild (line 188) | addChild(node, json, options = {}) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/multi-inputs.ts
method getLines (line 35) | getLines() {
method getLabels (line 38) | getLabels() {
method getLabels (line 47) | getLabels(transition) {
method getLabels (line 95) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/multi-outputs.ts
method getOutputPoint (line 41) | getOutputPoint(transform, layout) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/root.ts
method getInputPoint (line 17) | getInputPoint(transform) {
method getOutputPoint (line 20) | getOutputPoint(transform) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/simple-split.ts
method onBlockChildCreate (line 24) | onBlockChildCreate(
FILE: packages/canvas-engine/fixed-layout-core/src/activities/slot/constants.ts
constant RENDER_SLOT_ADDER_KEY (line 8) | const RENDER_SLOT_ADDER_KEY: string = FlowRendererKey.SLOT_ADDER;
constant RENDER_SLOT_LABEL_KEY (line 9) | const RENDER_SLOT_LABEL_KEY: string = FlowRendererKey.SLOT_LABEL;
constant RENDER_SLOT_COLLAPSE_KEY (line 10) | const RENDER_SLOT_COLLAPSE_KEY: string = FlowRendererKey.SLOT_COLLAPSE;
constant SLOT_START_DISTANCE (line 49) | const SLOT_START_DISTANCE = 16;
constant SLOT_PORT_DISTANCE (line 50) | const SLOT_PORT_DISTANCE = 100;
constant SLOT_LABEL_DISTANCE (line 51) | const SLOT_LABEL_DISTANCE = 32;
constant SLOT_BLOCK_PORT_DISTANCE (line 52) | const SLOT_BLOCK_PORT_DISTANCE = 32.5;
constant SLOT_RADIUS (line 53) | const SLOT_RADIUS = 16;
constant SLOT_SPACING (line 54) | const SLOT_SPACING = 32;
constant SLOT_BLOCK_VERTICAL_SPACING (line 55) | const SLOT_BLOCK_VERTICAL_SPACING = 32.5;
constant SLOT_NODE_LAST_SPACING (line 56) | const SLOT_NODE_LAST_SPACING = 10;
FILE: packages/canvas-engine/fixed-layout-core/src/activities/slot/extends/slot-block.ts
method getLines (line 48) | getLines(transition) {
method getLabels (line 140) | getLabels(transition) {
method getInputPoint (line 174) | getInputPoint(transform) {
method getChildDelta (line 193) | getChildDelta(child, layout) {
method getChildLabels (line 217) | getChildLabels() {
method getChildLines (line 220) | getChildLines() {
method getDelta (line 223) | getDelta(transform) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/slot/extends/slot-inline-blocks.ts
method getLines (line 26) | getLines() {
method getLabels (line 29) | getLabels() {
method getChildDelta (line 32) | getChildDelta(child, layout) {
method getDelta (line 51) | getDelta(transform) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/slot/slot.ts
method onAfterUpdateLocalTransform (line 56) | onAfterUpdateLocalTransform(transform) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/slot/typings.ts
type SlotNodeType (line 8) | enum SlotNodeType {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/static-split.ts
method getLabels (line 24) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch-extends/catch-block.ts
method getLines (line 25) | getLines(transition) {
method getLabels (line 75) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch-extends/catch-inline-blocks.ts
method getDelta (line 30) | getDelta() {
method getLines (line 33) | getLines(transition) {
method getOriginDeltaX (line 55) | getOriginDeltaX(transform) {
method getLabels (line 60) | getLabels(transition) {
method getInputPoint (line 91) | getInputPoint(transform, layout) {
method getOutputPoint (line 100) | getOutputPoint(transform, layout) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch-extends/constants.ts
type TryCatchTypeEnum (line 9) | enum TryCatchTypeEnum {
type TryCatchSpacings (line 17) | enum TryCatchSpacings {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch-extends/main-inline-blocks.ts
method getLines (line 30) | getLines(transition) {
method getLabels (line 44) | getLabels(transition) {
method getInputPoint (line 96) | getInputPoint(transform) {
method getOutputPoint (line 100) | getOutputPoint(transform, layout) {
method getDelta (line 114) | getDelta() {
method getChildDelta (line 117) | getChildDelta(child, layout) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch-extends/try-block.ts
method getLines (line 20) | getLines() {
method getLabels (line 23) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch-extends/try-slot.ts
method onAfterUpdateLocalTransform (line 23) | onAfterUpdateLocalTransform(transform): void {
method getLabels (line 40) | getLabels(transition) {
FILE: packages/canvas-engine/fixed-layout-core/src/activities/try-catch.ts
method onCreate (line 50) | onCreate(node: FlowNodeEntity, json: FlowNodeJSON) {
method onBlockChildCreate (line 113) | onBlockChildCreate(node, blockData, addedNodes) {
method getInputPoint (line 135) | getInputPoint(transform) {
method getOutputPoint (line 140) | getOutputPoint(transform, layout) {
method getLabels (line 166) | getLabels() {
FILE: packages/canvas-engine/fixed-layout-core/src/flow-registers.ts
class FlowRegisters (line 48) | class FlowRegisters
method registerDocument (line 55) | registerDocument(document: FlowDocument) {
method registerRenderer (line 95) | registerRenderer(renderer: FlowRendererRegistry) {
method onReady (line 111) | onReady(): void {}
method onDispose (line 116) | onDispose(): void {}
FILE: packages/canvas-engine/free-layout-core/__tests__/mocks/index.tsx
function createWorkflowContainer (line 27) | function createWorkflowContainer(): interfaces.Container {
function createDocument (line 124) | function createDocument(data: WorkflowJSON = baseJSON) {
function createHookWrapper (line 134) | function createHookWrapper(
function createSubCanvasNodes (line 148) | function createSubCanvasNodes(document: WorkflowDocument) {
FILE: packages/canvas-engine/free-layout-core/__tests__/service/workflow-drag-service.test.ts
function fireMouseEvent (line 25) | async function fireMouseEvent(type: string, point: IPoint): Promise<void> {
function drawingLine (line 48) | async function drawingLine(
function drawingLineBetweenNodes (line 65) | async function drawingLineBetweenNodes(params: {
function dragNodes (line 112) | async function dragNodes(
FILE: packages/canvas-engine/free-layout-core/__tests__/simple-line.ts
constant LINE_PADDING (line 12) | const LINE_PADDING = 12;
type StraightData (line 14) | interface StraightData {
class WorkflowSimpleLineContribution (line 21) | class WorkflowSimpleLineContribution implements WorkflowLineRenderContri...
method constructor (line 26) | constructor(entity: Wor
Condensed preview — 3381 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,574K chars).
[
{
"path": ".claude/commands/add-tests.md",
"chars": 3758,
"preview": "---\ndescription: 为代码添加单元测试(支持增量和存量代码测试补齐)\n---\n\n# 单元测试生成\n\n## 用法\n- `/add-tests [dir]` - 为指定模块或文件添加单元测试\n - `[dir]` 可选参数:包名"
},
{
"path": ".claude/skills/create-node/SKILL.md",
"chars": 7477,
"preview": "---\nskill_name: create-node\ndescription: 用于在 FlowGram demo-free-layout 中创建新的自定义节点,支持简单节点(自动表单)和复杂节点(自定义 UI)\nversion: 1.0"
},
{
"path": ".claude/skills/create-node/templates/README.md",
"chars": 1535,
"preview": "# Node Templates\n\n这些是创建新节点的模板文件,使用时需要替换其中的占位符。\n\n## 占位符说明\n\n在使用模板时,需要将以下占位符替换为实际值:\n\n| 占位符 | 说明 | 示例 |\n|-------|------|----"
},
{
"path": ".claude/skills/create-node/templates/complex-node/components/custom-component.tsx",
"chars": 1505,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Field } fro"
},
{
"path": ".claude/skills/create-node/templates/complex-node/form-meta.tsx",
"chars": 1078,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormMeta, F"
},
{
"path": ".claude/skills/create-node/templates/complex-node/index.tsx",
"chars": 1232,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": ".claude/skills/create-node/templates/complex-node/types.tsx",
"chars": 360,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeJSO"
},
{
"path": ".claude/skills/create-node/templates/simple-node/index.ts",
"chars": 2377,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": ".claude/skills/material-component-dev/SKILL.md",
"chars": 7088,
"preview": "---\nskill_name: material-component-dev\ndescription: FlowGram 物料组件开发指南 - 用于在 form-materials 包中创建新的物料组件\nversion: 1.0.0\ntag"
},
{
"path": ".claude/skills/material-component-doc/SKILL.md",
"chars": 6443,
"preview": "---\nname: material-component-doc\ndescription: 用于 FlowGram 物料库组件文档撰写的专用技能,提供组件文档生成、Story 创建、翻译等功能的指导和自动化支持\nmetadata:\n ve"
},
{
"path": ".claude/skills/material-component-doc/templates/material.mdx",
"chars": 3678,
"preview": "import { SourceCode } from '@theme';\nimport { BasicStory, WithSchemaStory } from 'components/form-materials/components/{"
},
{
"path": ".gitattributes",
"chars": 735,
"preview": "# Don't allow people to merge changes to these generated files, because the result\n# may be invalid. You need to run \"r"
},
{
"path": ".github/CODEOWNERS",
"chars": 574,
"preview": "# 文件路径与代码负责人分配\n# 对整个仓库设置代码负责人\n* @xiamidaxia @luics @dragooncjw @YuanHeDx @sanmaopep @louisyoungx\n\n# 对特定目录设置代码负责人\n/apps/"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.md",
"chars": 278,
"preview": "---\nname: Bug Report\nabout: Report Bug\ntitle: \"[Bug] \"\nlabels: [bug]\n---\n\n## 🙋 SDK Version\nPlease input version of SDK.\n"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 298,
"preview": "---\nname: Question Report\nabout: Report Question\ntitle: \"[Question] \"\nlabels: [question]\n---\n\n## 🙋 SDK Version\nPlease in"
},
{
"path": ".github/workflows/ci.yml",
"chars": 1139,
"preview": "name: CI\non:\n push:\n branches: [\"main\"]\n pull_request:\n branches: [\"main\"]\n merge_group:\n branches: [\"main\"]"
},
{
"path": ".github/workflows/common-pr-checks.yml",
"chars": 1237,
"preview": "name: PR Common Checks\non:\n pull_request:\n types: [opened, edited, synchronize, reopened]\n\njobs:\n common-checks:\n "
},
{
"path": ".github/workflows/deploy.yml",
"chars": 1859,
"preview": "name: Deploy With Actions\non: workflow_dispatch\n\nconcurrency:\n group: \"main-deploy-branch-workflow\"\n cancel-in-progres"
},
{
"path": ".github/workflows/e2e.yml",
"chars": 996,
"preview": "name: E2E Tests\n\non:\n pull_request:\n branches: [\"main\"]\n merge_group:\n branches: [\"main\"]\n\njobs:\n e2e:\n runs"
},
{
"path": ".github/workflows/publish-alpha.yml",
"chars": 3218,
"preview": "name: Publish Alpha Version\non: workflow_dispatch\n\nconcurrency:\n group: \"main-branch-alpha-publish-workflow\" # 唯一标识符,确保"
},
{
"path": ".github/workflows/publish-app-to-version.yml",
"chars": 2716,
"preview": "name: Publish App To Version\non:\n workflow_dispatch:\n inputs:\n sdk-version:\n description: \"要升级到的 SDK 版本("
},
{
"path": ".github/workflows/publish-app.yml",
"chars": 2307,
"preview": "name: Publish-Apps\non: workflow_dispatch\n\nconcurrency:\n group: \"main-branch-workflow\" # 唯一标识符,确保只运行一个实例\n cancel-in-pro"
},
{
"path": ".github/workflows/publish-minor.yml",
"chars": 2733,
"preview": "name: Publish-Minor\non: workflow_dispatch\n\nconcurrency:\n group: \"main-branch-workflow\" # 唯一标识符,确保只运行一个实例\n cancel-in-pr"
},
{
"path": ".github/workflows/publish-to-version.yml",
"chars": 2720,
"preview": "name: Publish To Version\non:\n workflow_dispatch:\n inputs:\n sdk-version:\n description: \"要升级到的 SDK 版本(e.g."
},
{
"path": ".github/workflows/publish.yml",
"chars": 2727,
"preview": "name: Publish\non: workflow_dispatch\n\nconcurrency:\n group: \"main-branch-workflow\" # 唯一标识符,确保只运行一个实例\n cancel-in-progress"
},
{
"path": ".github/workflows/sync-screenshot.yml",
"chars": 1400,
"preview": "name: Sync Screenshot\non: workflow_dispatch\n\nconcurrency:\n group: \"manual-sync-screenshot\"\n cancel-in-progress: false\n"
},
{
"path": ".gitignore",
"chars": 2043,
"preview": "# e2e results\ntest-results/\ndoc_build/\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# "
},
{
"path": ".vscode/extentions.json",
"chars": 389,
"preview": "{\n \"recommendations\": [\n \"styled-components.vscode-styled-components\",\n \"editorconfig.editorconfig\",\n \"dbaeume"
},
{
"path": ".vscode/settings.json",
"chars": 3974,
"preview": "{\n \"eslint.nodePath\": \"config/eslint-config/node_modules/eslint\",\n \"prettier.prettierPath\": \"config/eslint-config/node"
},
{
"path": "AGENTS.md",
"chars": 2513,
"preview": "# Repository Guidelines\n\n## Project Structure & Module Organization\nFlowGram is a Rush-managed monorepo. Production-read"
},
{
"path": "CHANGELOG.md",
"chars": 1044,
"preview": "# Changelog\n\n## [Unreleased]\n\n### Added\n\n- Add `flowing` field to `LineColor` interface for configuring flowing line col"
},
{
"path": "CLAUDE.md",
"chars": 9221,
"preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
},
{
"path": "CNAME",
"chars": 11,
"preview": "flowgram.ai"
},
{
"path": "CONTRIBUTING.md",
"chars": 2188,
"preview": "# Contributing to flowgram.ai\n\n## Quick Start\n\n### Prerequisites\n\n- Node.js 18+ (LTS/Hydrogen recommended)\n- pnpm 10.6.5"
},
{
"path": "LICENSE",
"chars": 1093,
"preview": "MIT License\n\nCopyright (c) 2025 Bytedance Ltd. and/or its affiliates\n\nPermission is hereby granted, free of charge, to a"
},
{
"path": "README.md",
"chars": 6683,
"preview": "\n\n<div align=\"center\">\n\n[\n\n<div align=\"center\">\n\n[\n\n<div align=\"center\">\n\n[\n\n<div align=\"center\">\n\n[\n\n<div align=\"center\">\n\n[\n\n<div align=\"center\">\n\n["
},
{
"path": "README_ZH.md",
"chars": 4714,
"preview": "\n\n<div align=\"center\">\n\n[![Lice"
},
{
"path": "apps/cli/.gitignore",
"chars": 10,
"preview": ".download\n"
},
{
"path": "apps/cli/bin/index.js",
"chars": 47,
"preview": "#!/usr/bin/env node\nimport '../dist/index.js';\n"
},
{
"path": "apps/cli/eslint.config.js",
"chars": 473,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { defineFlatC"
},
{
"path": "apps/cli/package.json",
"chars": 1110,
"preview": "{\n \"name\": \"@flowgram.ai/cli\",\n \"version\": \"0.1.8\",\n \"description\": \"A CLI tool to create demo projects or sync mater"
},
{
"path": "apps/cli/src/create-app/index.ts",
"chars": 4727,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/find-materials/index.ts",
"chars": 2318,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport chalk from 'c"
},
{
"path": "apps/cli/src/index.ts",
"chars": 1932,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/materials/copy.ts",
"chars": 2059,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/materials/index.ts",
"chars": 2586,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/materials/material.ts",
"chars": 1522,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/materials/refresh-project-import.ts",
"chars": 2751,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/materials/select.ts",
"chars": 1964,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport inquirer from"
},
{
"path": "apps/cli/src/materials/types.ts",
"chars": 584,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Project } f"
},
{
"path": "apps/cli/src/update-version/index.ts",
"chars": 1741,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport chalk from 'c"
},
{
"path": "apps/cli/src/utils/export.ts",
"chars": 3475,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport function extr"
},
{
"path": "apps/cli/src/utils/file.ts",
"chars": 2037,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/utils/import.ts",
"chars": 3481,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport interface Nam"
},
{
"path": "apps/cli/src/utils/npm.ts",
"chars": 2917,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/utils/project.ts",
"chars": 2761,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path from 'pa"
},
{
"path": "apps/cli/src/utils/ts-file.ts",
"chars": 3531,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport path, { join "
},
{
"path": "apps/cli/tsconfig.json",
"chars": 496,
"preview": "{\n \"compilerOptions\": {\n \"experimentalDecorators\": true,\n \"target\": \"es2020\",\n \"module\": \"esnext\",\n \"strict"
},
{
"path": "apps/cli/tsup.config.js",
"chars": 186,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { defineConfi"
},
{
"path": "apps/create-app/bin/index.js",
"chars": 47,
"preview": "#!/usr/bin/env node\nimport '../dist/index.js';\n"
},
{
"path": "apps/create-app/eslint.config.js",
"chars": 1605,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { defineFlatC"
},
{
"path": "apps/create-app/package.json",
"chars": 967,
"preview": "{\n \"name\": \"@flowgram.ai/create-app\",\n \"version\": \"0.1.8\",\n \"description\": \"A CLI tool to create demo projects\",\n \"b"
},
{
"path": "apps/create-app/src/index.ts",
"chars": 4976,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Copyright (c)"
},
{
"path": "apps/create-app/tsconfig.json",
"chars": 496,
"preview": "{\n \"compilerOptions\": {\n \"experimentalDecorators\": true,\n \"target\": \"es2020\",\n \"module\": \"esnext\",\n \"strict"
},
{
"path": "apps/demo-fixed-layout/README.md",
"chars": 11463,
"preview": "# FlowGram.AI - Demo Fixed Layout\n\nBest practices demo for fixed layout\n\n## Installation\n\n```shell\nnpx @flowgram.ai/crea"
},
{
"path": "apps/demo-fixed-layout/README.zh_CN.md",
"chars": 8852,
"preview": "# FlowGram.AI - Demo Fixed Layout\n\n固定布局最佳实践 demo\n\n## 安装\n\n```shell\nnpx @flowgram.ai/create-app@latest fixed-layout\n```\n\n#"
},
{
"path": "apps/demo-fixed-layout/eslint.config.js",
"chars": 388,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nconst { defineFlatCo"
},
{
"path": "apps/demo-fixed-layout/index.html",
"chars": 340,
"preview": "<!DOCTYPE html>\n<html lang=\"en\" data-bundler=\"rspack\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"X-UA-"
},
{
"path": "apps/demo-fixed-layout/package.json",
"chars": 2108,
"preview": "{\n \"name\": \"@flowgram.ai/demo-fixed-layout\",\n \"version\": \"0.1.0\",\n \"description\": \"\",\n \"keywords\": [],\n \"license\": "
},
{
"path": "apps/demo-fixed-layout/rsbuild.config.ts",
"chars": 789,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { pluginReact"
},
{
"path": "apps/demo-fixed-layout/src/app.tsx",
"chars": 267,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { createRoot "
},
{
"path": "apps/demo-fixed-layout/src/assets/icon-mouse.tsx",
"chars": 3924,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport function Icon"
},
{
"path": "apps/demo-fixed-layout/src/assets/icon-pad.tsx",
"chars": 1626,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport function Icon"
},
{
"path": "apps/demo-fixed-layout/src/components/agent-adder/index.tsx",
"chars": 1581,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n type Flow"
},
{
"path": "apps/demo-fixed-layout/src/components/agent-label/index.tsx",
"chars": 895,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeEnt"
},
{
"path": "apps/demo-fixed-layout/src/components/base-node/index.tsx",
"chars": 2886,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useCallback"
},
{
"path": "apps/demo-fixed-layout/src/components/base-node/styles.tsx",
"chars": 841,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/components/branch-adder/index.tsx",
"chars": 1586,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type FlowNo"
},
{
"path": "apps/demo-fixed-layout/src/components/branch-adder/styles.tsx",
"chars": 700,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/components/drag-node/index.tsx",
"chars": 1481,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { FlowNo"
},
{
"path": "apps/demo-fixed-layout/src/components/drag-node/styles.tsx",
"chars": 830,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/components/index.ts",
"chars": 221,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { DemoTools }"
},
{
"path": "apps/demo-fixed-layout/src/components/node-adder/index.tsx",
"chars": 4402,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useCallback"
},
{
"path": "apps/demo-fixed-layout/src/components/node-adder/styles.tsx",
"chars": 569,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/components/node-adder/utils.ts",
"chars": 297,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/components/node-list.tsx",
"chars": 1923,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/components/selector-box-popover/index.tsx",
"chars": 4879,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FunctionCom"
},
{
"path": "apps/demo-fixed-layout/src/components/sidebar/index.tsx",
"chars": 159,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { nodeFormPan"
},
{
"path": "apps/demo-fixed-layout/src/components/sidebar/sidebar-node-renderer.tsx",
"chars": 922,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n useNodeRe"
},
{
"path": "apps/demo-fixed-layout/src/components/sidebar/sidebar-renderer.tsx",
"chars": 2649,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useCallback"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/download.tsx",
"chars": 2570,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect, "
},
{
"path": "apps/demo-fixed-layout/src/components/tools/fit-view.tsx",
"chars": 452,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { IconButton,"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/index.tsx",
"chars": 2220,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState, u"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/interactive.tsx",
"chars": 2904,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect, "
},
{
"path": "apps/demo-fixed-layout/src/components/tools/minimap-switch.tsx",
"chars": 772,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Tooltip, Ic"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/minimap.tsx",
"chars": 767,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { MinimapRend"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/mouse-pad-selector.less",
"chars": 2348,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/* stylelint-disable"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/mouse-pad-selector.tsx",
"chars": 3618,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { type"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/readonly.tsx",
"chars": 768,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useCallback"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/run.tsx",
"chars": 2783,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState } "
},
{
"path": "apps/demo-fixed-layout/src/components/tools/save.tsx",
"chars": 1974,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState, u"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/styles.tsx",
"chars": 942,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/switch-vertical.tsx",
"chars": 821,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { usePlaygrou"
},
{
"path": "apps/demo-fixed-layout/src/components/tools/zoom-select.tsx",
"chars": 1347,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState } "
},
{
"path": "apps/demo-fixed-layout/src/context/index.ts",
"chars": 213,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { NodeRenderC"
},
{
"path": "apps/demo-fixed-layout/src/context/node-render-context.ts",
"chars": 294,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'r"
},
{
"path": "apps/demo-fixed-layout/src/context/sidebar-context.ts",
"chars": 197,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'r"
},
{
"path": "apps/demo-fixed-layout/src/editor.tsx",
"chars": 784,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { EditorRende"
},
{
"path": "apps/demo-fixed-layout/src/form-components/feedback.tsx",
"chars": 902,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-content/index.tsx",
"chars": 809,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'r"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-content/styles.tsx",
"chars": 574,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-header/index.tsx",
"chars": 4112,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useContext,"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-header/styles.tsx",
"chars": 742,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-header/title-input.tsx",
"chars": 1364,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useRef, use"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-header/utils.tsx",
"chars": 435,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type FlowNo"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-inputs/index.tsx",
"chars": 2369,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { DynamicValu"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-inputs/styles.tsx",
"chars": 152,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n// import styled fro"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-item/index.css",
"chars": 251,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n.form-item-type-tag "
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-item/index.tsx",
"chars": 1972,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { useC"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-outputs/index.tsx",
"chars": 364,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { DisplayOutp"
},
{
"path": "apps/demo-fixed-layout/src/form-components/form-outputs/styles.tsx",
"chars": 392,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/form-components/index.ts",
"chars": 318,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './fee"
},
{
"path": "apps/demo-fixed-layout/src/form-components/properties-edit/index.tsx",
"chars": 3975,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { useC"
},
{
"path": "apps/demo-fixed-layout/src/form-components/properties-edit/property-edit.tsx",
"chars": 2418,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { useS"
},
{
"path": "apps/demo-fixed-layout/src/form-components/properties-edit/styles.tsx",
"chars": 388,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from '"
},
{
"path": "apps/demo-fixed-layout/src/hooks/index.ts",
"chars": 317,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { useEditorPr"
},
{
"path": "apps/demo-fixed-layout/src/hooks/use-editor-props.ts",
"chars": 8944,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useMemo } f"
},
{
"path": "apps/demo-fixed-layout/src/hooks/use-form-value.ts",
"chars": 1551,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect, "
},
{
"path": "apps/demo-fixed-layout/src/hooks/use-is-sidebar.ts",
"chars": 259,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useContext "
},
{
"path": "apps/demo-fixed-layout/src/hooks/use-node-render-context.ts",
"chars": 269,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useContext "
},
{
"path": "apps/demo-fixed-layout/src/index.ts",
"chars": 154,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { Editor as D"
},
{
"path": "apps/demo-fixed-layout/src/initial-data.ts",
"chars": 9128,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowDocumen"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/agent-llm.ts",
"chars": 484,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeBas"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/agent-memory.ts",
"chars": 471,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeBas"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/agent-tools.ts",
"chars": 799,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/agent.ts",
"chars": 1469,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/index.ts",
"chars": 582,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ToolNodeReg"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/memory.ts",
"chars": 792,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/agent/tool.ts",
"chars": 720,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/break-loop/form-meta.tsx",
"chars": 344,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormMeta } "
},
{
"path": "apps/demo-fixed-layout/src/nodes/break-loop/index.ts",
"chars": 917,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/case/form-meta.tsx",
"chars": 1092,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormRenderP"
},
{
"path": "apps/demo-fixed-layout/src/nodes/case/index.ts",
"chars": 1106,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/case-default/form-meta.tsx",
"chars": 1092,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormRenderP"
},
{
"path": "apps/demo-fixed-layout/src/nodes/case-default/index.ts",
"chars": 840,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeReg"
},
{
"path": "apps/demo-fixed-layout/src/nodes/catch-block/form-meta.tsx",
"chars": 1092,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormRenderP"
},
{
"path": "apps/demo-fixed-layout/src/nodes/catch-block/index.ts",
"chars": 1062,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/default-form-meta.tsx",
"chars": 2000,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n autoRenam"
},
{
"path": "apps/demo-fixed-layout/src/nodes/end/form-meta.tsx",
"chars": 1487,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n createInf"
},
{
"path": "apps/demo-fixed-layout/src/nodes/end/index.ts",
"chars": 2240,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/if/index.ts",
"chars": 1414,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/if-block/form-meta.tsx",
"chars": 881,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormRenderP"
},
{
"path": "apps/demo-fixed-layout/src/nodes/if-block/index.ts",
"chars": 730,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeReg"
},
{
"path": "apps/demo-fixed-layout/src/nodes/index.ts",
"chars": 1117,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type FlowNo"
},
{
"path": "apps/demo-fixed-layout/src/nodes/llm/index.ts",
"chars": 2077,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/loop/form-meta.tsx",
"chars": 1757,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n BatchVari"
},
{
"path": "apps/demo-fixed-layout/src/nodes/loop/index.ts",
"chars": 703,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/start/form-meta.tsx",
"chars": 1568,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n JsonSchem"
},
{
"path": "apps/demo-fixed-layout/src/nodes/start/index.ts",
"chars": 828,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowNodeReg"
},
{
"path": "apps/demo-fixed-layout/src/nodes/switch/index.ts",
"chars": 2040,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/nodes/trycatch/form-meta.tsx",
"chars": 730,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FormRenderP"
},
{
"path": "apps/demo-fixed-layout/src/nodes/trycatch/index.ts",
"chars": 1268,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/plugins/clipboard-plugin/create-clipboard-plugin.ts",
"chars": 803,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n definePlu"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/group-box-header.tsx",
"chars": 1312,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type CSSPro"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/group-node.tsx",
"chars": 1722,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { IGroupNode "
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/group-note.tsx",
"chars": 2457,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useRef, use"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/group-tools.tsx",
"chars": 3804,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type CSSPro"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/icons/index.tsx",
"chars": 2769,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type ReactN"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/index.ts",
"chars": 195,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { GroupBoxHea"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/multilang-textarea-editor/base-textarea.tsx",
"chars": 1502,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { useS"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/multilang-textarea-editor/index.css",
"chars": 316,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n.node-description {\n"
},
{
"path": "apps/demo-fixed-layout/src/plugins/group-plugin/multilang-textarea-editor/index.tsx",
"chars": 2007,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { useS"
},
{
"path": "apps/demo-fixed-layout/src/plugins/index.ts",
"chars": 253,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { createClipb"
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/full-variable-list.tsx",
"chars": 325,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useVariable"
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/global-variable-editor.tsx",
"chars": 995,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect }"
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/index.module.less",
"chars": 700,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n.panel-wrapper {\n p"
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/components/variable-panel.tsx",
"chars": 1458,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState } "
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/index.ts",
"chars": 169,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { createVaria"
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/variable-panel-layer.tsx",
"chars": 674,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { domUtils, i"
},
{
"path": "apps/demo-fixed-layout/src/plugins/variable-panel-plugin/variable-panel-plugin.ts",
"chars": 1087,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { JsonSchemaU"
},
{
"path": "apps/demo-fixed-layout/src/services/custom-service.ts",
"chars": 1088,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable,"
},
{
"path": "apps/demo-fixed-layout/src/services/index.ts",
"chars": 150,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { CustomServi"
},
{
"path": "apps/demo-fixed-layout/src/shortcuts/constants.ts",
"chars": 431,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport enum FlowComm"
},
{
"path": "apps/demo-fixed-layout/src/shortcuts/index.ts",
"chars": 6201,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nanoid } fr"
},
{
"path": "apps/demo-fixed-layout/src/shortcuts/utils.ts",
"chars": 1444,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ClipboardSe"
},
{
"path": "apps/demo-fixed-layout/src/type.d.ts",
"chars": 200,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\ndeclare module '*.sv"
},
{
"path": "apps/demo-fixed-layout/src/typings/index.ts",
"chars": 155,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './nod"
},
{
"path": "apps/demo-fixed-layout/src/typings/json-schema.ts",
"chars": 269,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { IJsonS"
},
{
"path": "apps/demo-fixed-layout/src/typings/node.ts",
"chars": 1798,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { IFlowValue "
},
{
"path": "apps/demo-fixed-layout/tsconfig.json",
"chars": 658,
"preview": "{\n \"extends\": \"@flowgram.ai/ts-config/tsconfig.flow.path.json\",\n \"compilerOptions\": {\n \"rootDir\": \"./src\",\n \"out"
},
{
"path": "apps/demo-fixed-layout-animation/eslint.config.js",
"chars": 405,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nconst { defineFlatCo"
},
{
"path": "apps/demo-fixed-layout-animation/index.html",
"chars": 340,
"preview": "<!DOCTYPE html>\n<html lang=\"en\" data-bundler=\"rspack\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"X-UA-"
},
{
"path": "apps/demo-fixed-layout-animation/package.json",
"chars": 1826,
"preview": "{\n \"name\": \"@flowgram.ai/demo-fixed-layout-animation\",\n \"version\": \"0.1.0\",\n \"description\": \"\",\n \"keywords\": [],\n \""
},
{
"path": "apps/demo-fixed-layout-animation/rsbuild.config.ts",
"chars": 799,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { pluginReact"
},
{
"path": "apps/demo-fixed-layout-animation/src/app.tsx",
"chars": 781,
"preview": "/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport '@flowgram.ai"
}
]
// ... and 3181 more files (download for full content)
About this extraction
This page contains the full source code of the bytedance/flowgram.ai GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3381 files (6.7 MB), approximately 2.0M tokens, and a symbol index with 5937 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.