├── widgets
├── RichText
│ ├── README.md
│ ├── .fatherrc.js
│ └── package.json
├── template
│ ├── README.md
│ ├── src
│ │ └── index.js
│ ├── .fatherrc.js
│ └── package.json
└── AsyncOptions
│ ├── README.md
│ ├── src
│ └── index.js
│ ├── .fatherrc.js
│ └── package.json
├── packages
├── data-render
│ ├── CONTRIBUTING.md
│ ├── src
│ │ ├── core
│ │ │ └── index.less
│ │ ├── widgets
│ │ │ ├── FPanel
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FTooltip
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FSteps
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FCard
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── components
│ │ │ │ ├── RequestTable
│ │ │ │ │ └── index.less
│ │ │ │ ├── BaseTable
│ │ │ │ │ └── index.less
│ │ │ │ ├── CopyLabel
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── IconLabel
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TextEllipsis
│ │ │ │ │ └── index.less
│ │ │ │ ├── IconView
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── InnerHtml
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Encryption
│ │ │ │ │ └── index.less
│ │ │ │ └── ReactNode
│ │ │ │ │ └── index.tsx
│ │ │ ├── FButton
│ │ │ │ └── index.less
│ │ │ ├── FButtonFold
│ │ │ │ └── index.less
│ │ │ ├── utils
│ │ │ │ ├── createIconFont.ts
│ │ │ │ └── hooks.ts
│ │ │ ├── FLabel
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FText
│ │ │ │ └── index.less
│ │ │ ├── FRow
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FImage
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FTitle
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── FTabs
│ │ │ │ └── index.tsx
│ │ │ ├── FSpace
│ │ │ │ └── index.tsx
│ │ │ ├── FProgress
│ │ │ │ ├── index.tsx
│ │ │ │ └── index.less
│ │ │ ├── FTextEllipsis
│ │ │ │ └── index.tsx
│ │ │ ├── FTimeline
│ │ │ │ └── index.tsx
│ │ │ ├── FSuckNav
│ │ │ │ └── index.tsx
│ │ │ └── FIconLabel
│ │ │ │ └── index.tsx
│ │ ├── type.ts
│ │ ├── models
│ │ │ ├── context.ts
│ │ │ └── store.ts
│ │ └── index.ts
│ ├── CHANGELOG.md
│ ├── .fatherrc.js
│ ├── tsconfig.json
│ └── LICENSE
├── form-render-mobile
│ ├── src
│ │ ├── widgets
│ │ │ ├── index.less
│ │ │ ├── Group
│ │ │ │ ├── index.tsx
│ │ │ │ └── index.less
│ │ │ ├── Radio
│ │ │ │ └── index.tsx
│ │ │ ├── utils.ts
│ │ │ ├── Collapse
│ │ │ │ └── index.tsx
│ │ │ ├── Card
│ │ │ │ └── index.less
│ │ │ └── Cascader
│ │ │ │ └── index.tsx
│ │ ├── locales
│ │ │ ├── index.ts
│ │ │ ├── zh_CN.ts
│ │ │ └── en_US.ts
│ │ ├── render-core
│ │ │ ├── FieldList
│ │ │ │ └── index.less
│ │ │ └── FieldItem
│ │ │ │ └── field.tsx
│ │ ├── models
│ │ │ ├── context.ts
│ │ │ └── store.ts
│ │ ├── form-core
│ │ │ ├── connectForm.tsx
│ │ │ └── index.less
│ │ └── index.tsx
│ ├── CHANGELOG.md
│ ├── .fatherrc.js
│ ├── CONTRIBUTING.md
│ ├── tsconfig.json
│ └── LICENSE
├── form-render
│ ├── src
│ │ ├── widgets
│ │ │ ├── listTab
│ │ │ │ └── index.less
│ │ │ ├── components
│ │ │ │ ├── HeaderTitle
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── PanelView
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TimePicker
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── FButton
│ │ │ │ │ └── index.tsx
│ │ │ │ └── DatePicker
│ │ │ │ │ └── index.tsx
│ │ │ ├── fields
│ │ │ │ ├── slider
│ │ │ │ │ └── index.less
│ │ │ │ ├── imageInput
│ │ │ │ │ └── index.less
│ │ │ │ ├── rate
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── input
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── select
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── switch
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── number
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── treeSelect
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── textArea
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── checkbox
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── color
│ │ │ │ │ └── index.less
│ │ │ │ ├── upload
│ │ │ │ │ └── index.less
│ │ │ │ ├── time
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── radio
│ │ │ │ │ └── index.tsx
│ │ │ │ └── checkboxes
│ │ │ │ │ └── index.tsx
│ │ │ ├── voidTitle
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── listDrawer
│ │ │ │ ├── index.less
│ │ │ │ └── drawerForm.tsx
│ │ │ ├── listCard
│ │ │ │ └── index.less
│ │ │ ├── boxcard
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── boxLineTitle
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── boxSubInline
│ │ │ │ └── index.less
│ │ │ ├── utils
│ │ │ │ ├── hooks.ts
│ │ │ │ └── withFieldWrap.tsx
│ │ │ ├── ErrorSchema
│ │ │ │ └── index.tsx
│ │ │ ├── listSimple
│ │ │ │ └── index.less
│ │ │ ├── listTable
│ │ │ │ └── index.less
│ │ │ └── listVirtual
│ │ │ │ └── index.less
│ │ ├── locales
│ │ │ ├── index.ts
│ │ │ ├── zh_CN.ts
│ │ │ └── en_US.ts
│ │ ├── models
│ │ │ ├── context.ts
│ │ │ ├── store.ts
│ │ │ ├── sortProperties.ts
│ │ │ └── formDataSkeleton.ts
│ │ ├── derivative
│ │ │ ├── SlimRender
│ │ │ │ └── index.tsx
│ │ │ └── SearchForm
│ │ │ │ └── index.less
│ │ ├── form-core
│ │ │ ├── connectForm.tsx
│ │ │ └── index.less
│ │ ├── render-core
│ │ │ └── index.less
│ │ └── index.ts
│ ├── .fatherrc.js
│ ├── __tests__
│ │ ├── core-utils.spec.ts
│ │ └── form.spec.tsx
│ ├── CONTRIBUTING.md
│ ├── tsconfig.json
│ └── LICENSE
├── chart-render
│ ├── src
│ │ ├── components
│ │ │ ├── ChartContainer
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── ChartProvider
│ │ │ │ └── index.tsx
│ │ │ └── Search
│ │ │ │ └── index.less
│ │ ├── utils
│ │ │ ├── index.ts
│ │ │ └── store.ts
│ │ ├── index.ts
│ │ └── widgets
│ │ │ └── Pie
│ │ │ └── index.tsx
│ ├── .fatherrc.ts
│ ├── tsconfig.json
│ └── CHANGELOG.md
├── x-flow
│ ├── src
│ │ ├── components
│ │ │ ├── NodesPopover
│ │ │ │ └── index.less
│ │ │ ├── TextEllipsis
│ │ │ │ └── index.less
│ │ │ ├── IconView
│ │ │ │ └── index.tsx
│ │ │ ├── CustomEdge
│ │ │ │ └── index.less
│ │ │ └── NodeContainer
│ │ │ │ └── TitleMenuTooltip.tsx
│ │ ├── index.less
│ │ ├── utils
│ │ │ ├── createIconFont.ts
│ │ │ └── flow.ts
│ │ ├── nodes
│ │ │ ├── node-common
│ │ │ │ └── index.less
│ │ │ ├── node-end
│ │ │ │ └── index.less
│ │ │ ├── node-start
│ │ │ │ └── index.less
│ │ │ ├── index.tsx
│ │ │ └── index.less
│ │ ├── models
│ │ │ ├── context.ts
│ │ │ └── event-emitter.tsx
│ │ ├── operator
│ │ │ ├── UndoRedo
│ │ │ │ └── index.less
│ │ │ ├── index.less
│ │ │ ├── ZoomInOut
│ │ │ │ ├── shortcuts-name.tsx
│ │ │ │ └── index.less
│ │ │ └── Control
│ │ │ │ └── index.less
│ │ ├── index.ts
│ │ └── hooks
│ │ │ ├── useNodes.ts
│ │ │ ├── useEdges.ts
│ │ │ └── useTemporalStore.ts
│ ├── CHANGELOG.md
│ ├── .fatherrc.js
│ ├── CONTRIBUTING.md
│ ├── tsconfig.json
│ └── LICENSE
└── table-render
│ ├── src
│ ├── locales
│ │ ├── index.ts
│ │ ├── zh_CN.ts
│ │ └── en_US.ts
│ └── core
│ │ ├── ToolbarView
│ │ ├── index.less
│ │ └── InteriorTool
│ │ │ └── ReloadIcon.tsx
│ │ ├── index.less
│ │ ├── TableView
│ │ ├── copy.tsx
│ │ └── widgets.tsx
│ │ └── ErrorBoundary
│ │ └── index.tsx
│ ├── CONTRIBUTION.md
│ ├── 开发文档.md
│ ├── .fatherrc.ts
│ ├── CHANGELOG.md
│ ├── tsconfig.json
│ ├── __tests__
│ └── utils.spec.ts
│ └── LICENSE
├── .npmrc
├── tools
└── schema-builder
│ ├── CHANGELOG.md
│ ├── src
│ ├── index.ts
│ ├── settings
│ │ └── meta
│ │ │ ├── color.ts
│ │ │ ├── imageInput.ts
│ │ │ ├── date.ts
│ │ │ ├── time.ts
│ │ │ ├── checkbox.ts
│ │ │ ├── urlInput.ts
│ │ │ ├── slider.ts
│ │ │ ├── timeRange.ts
│ │ │ └── dateRange.ts
│ └── type.ts
│ ├── README.md
│ ├── .fatherrc.js
│ └── LICENSE
├── typing.d.ts
├── docs
├── table-render
│ ├── .test
│ │ └── test.md
│ ├── basic.md
│ ├── custom-table.md
│ ├── toolbar.md
│ ├── noSearch.md
│ ├── static
│ │ └── request.ts
│ ├── tabs.md
│ └── demo
│ │ └── display
│ │ └── custom-table.tsx
├── form-render-mobile
│ ├── test
│ │ └── test.md
│ └── disaply.md
├── xflow
│ ├── demo
│ │ ├── flow-provider
│ │ │ ├── edges.ts
│ │ │ └── nodes.ts
│ │ ├── nodeWidget
│ │ │ └── index.less
│ │ ├── nodeSetting
│ │ │ └── fullDemo
│ │ │ │ └── CustomImg.tsx
│ │ ├── custom-flow
│ │ │ ├── fullCase
│ │ │ │ └── components
│ │ │ │ │ └── ReadOnlyPanel.tsx
│ │ │ ├── customWidget.tsx
│ │ │ └── index.tsx
│ │ ├── best
│ │ │ ├── basic
│ │ │ │ ├── TextEllipsis
│ │ │ │ │ └── index.less
│ │ │ │ ├── tools.tsx
│ │ │ │ ├── header.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── showSwitchNode.tsx
│ │ │ └── demo2
│ │ │ │ ├── TextEllipsis
│ │ │ │ └── index.less
│ │ │ │ ├── tools.tsx
│ │ │ │ ├── header.tsx
│ │ │ │ └── showSwitchNode.tsx
│ │ ├── log
│ │ │ ├── utils.tsx
│ │ │ ├── runNode
│ │ │ │ └── utils.tsx
│ │ │ ├── buildIn-log
│ │ │ │ ├── utils.tsx
│ │ │ │ └── CustomGroupTittle.tsx
│ │ │ └── custom-log
│ │ │ │ └── utils.tsx
│ │ ├── switchNode
│ │ │ └── customSwitchNode
│ │ │ │ └── index.tsx
│ │ └── basic
│ │ │ └── index.tsx
│ ├── best-practices.md
│ ├── updateLog.md
│ └── custom-node-view.md
├── playground
│ ├── index.md
│ ├── controller
│ │ └── index.css
│ └── json
│ │ ├── dynamic-function.js
│ │ ├── test.json
│ │ ├── format.json
│ │ └── select.json
├── form-render
│ ├── changelog.md
│ ├── utils
│ │ └── index.js
│ ├── demo
│ │ ├── FormRender.jsx
│ │ ├── widget
│ │ │ ├── label-widget.tsx
│ │ │ └── desc-widget.tsx
│ │ └── form-slim
│ │ │ ├── basic.tsx
│ │ │ └── form-list.tsx
│ ├── test
│ │ └── test.md
│ ├── schema
│ │ ├── basic.ts
│ │ ├── simple.ts
│ │ ├── cellSpan.ts
│ │ └── span.ts
│ └── faq.md
└── schema-builder-online
│ └── index.md
├── .dumi
├── tmp-production
│ ├── core
│ │ ├── helmetContext.ts
│ │ ├── EmptyRoute.tsx
│ │ ├── exportStaticRuntimePlugin.ts
│ │ ├── helmet.ts
│ │ ├── defineApp.ts
│ │ └── pluginConfigJoi.d.ts
│ └── dumi
│ │ ├── meta
│ │ ├── tabs.ts
│ │ └── atoms.ts
│ │ ├── theme
│ │ ├── slots
│ │ │ ├── Hero.ts
│ │ │ ├── Logo.ts
│ │ │ ├── Toc.ts
│ │ │ ├── Content.ts
│ │ │ ├── Footer.ts
│ │ │ ├── Header.ts
│ │ │ ├── Navbar.ts
│ │ │ ├── Sidebar.ts
│ │ │ ├── Features.ts
│ │ │ ├── HeadeExtra.ts
│ │ │ ├── HeroTitle.ts
│ │ │ ├── LangSwitch.ts
│ │ │ ├── NotFound.ts
│ │ │ ├── RtlSwitch.ts
│ │ │ ├── SocialIcon.ts
│ │ │ ├── ColorSwitch.ts
│ │ │ ├── ContentTabs.ts
│ │ │ ├── NavbarExtra.ts
│ │ │ ├── SearchResult.ts
│ │ │ ├── PreviewerActions.ts
│ │ │ ├── PreviewerActionsExtra.ts
│ │ │ └── SearchBar.ts
│ │ ├── builtins
│ │ │ ├── API.ts
│ │ │ ├── Badge.ts
│ │ │ ├── Table.ts
│ │ │ ├── Container.ts
│ │ │ ├── Previewer.ts
│ │ │ └── SourceCode.ts
│ │ └── layouts
│ │ │ └── DocLayout.ts
│ │ ├── exports.ts
│ │ └── exportStaticRuntimePlugin.ts
├── loading.tsx
└── theme
│ ├── layouts
│ └── GlobalLayout
│ │ └── index.tsx
│ └── slots
│ └── Header
│ └── GithubLink.tsx
├── lerna.json
├── scripts
└── dumi-plugin
│ ├── publicPath.ts
│ └── redirect.ts
├── .fatherrc.js
├── turbo.json
├── app.ts
├── .prettierrc
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug-report.md
└── workflows
│ ├── emoji-helper.yml
│ ├── mirror.yml
│ ├── coverage.yml
│ ├── deploy.yml
│ └── ci.yml
├── tsconfig.jest.json
├── vitest.config.ts
├── .prettierignore
├── .gitignore
└── .turbo
└── daemon
└── ae401ef4dd981f33-turbo.log.2024-08-26
/widgets/RichText/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/widgets/template/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/widgets/AsyncOptions/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/data-render/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/data-render/src/core/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org/
2 |
--------------------------------------------------------------------------------
/tools/schema-builder/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FPanel/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listTab/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/data-render/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 更新日志
2 |
3 |
4 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/HeaderTitle/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/typing.d.ts:
--------------------------------------------------------------------------------
1 | interface Window {
2 | publicPath: string;
3 | }
4 |
--------------------------------------------------------------------------------
/docs/table-render/.test/test.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/form-render-mobile/test/test.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/index.ts:
--------------------------------------------------------------------------------
1 | import Main from './main';
2 |
3 | export default Main
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTooltip/index.less:
--------------------------------------------------------------------------------
1 | .dr-tooltip {
2 | margin-top: 8px;
3 | }
4 |
--------------------------------------------------------------------------------
/docs/xflow/demo/flow-provider/edges.ts:
--------------------------------------------------------------------------------
1 | export const edges = [{ source: '1', target: '2', id: '234123' }];
2 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FSteps/index.less:
--------------------------------------------------------------------------------
1 | .dr-steps {
2 | width: 100%;
3 | padding: 10px 15px;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/chart-render/src/components/ChartContainer/index.less:
--------------------------------------------------------------------------------
1 | .cr-chart-container {
2 | position: relative;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FCard/index.less:
--------------------------------------------------------------------------------
1 | .dr-card {
2 | margin-top: 16px;
3 | border-color: #f4f4f4;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/data-render/src/type.ts:
--------------------------------------------------------------------------------
1 | export interface DataVProps {
2 | [key: string]: any;
3 | }
4 |
5 | export default DataVProps;
6 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/RequestTable/index.less:
--------------------------------------------------------------------------------
1 | .custom-table {
2 | width: 100%;
3 | margin: 10px 0;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/slider/index.less:
--------------------------------------------------------------------------------
1 | .fr-slider {
2 | display: flex;
3 | width: 100%;
4 | align-items: center;
5 | }
--------------------------------------------------------------------------------
/packages/x-flow/src/components/NodesPopover/index.less:
--------------------------------------------------------------------------------
1 | .nodes-popover {
2 | .ant-popover-inner-content {
3 | padding: 0;
4 | }
5 | }
--------------------------------------------------------------------------------
/widgets/AsyncOptions/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function index() {
4 | return
haha
;
5 | }
6 |
--------------------------------------------------------------------------------
/widgets/template/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Template() {
4 | return hello world
;
5 | }
6 |
--------------------------------------------------------------------------------
/docs/xflow/demo/nodeWidget/index.less:
--------------------------------------------------------------------------------
1 | .node-llm-style {
2 | .custom-node-container{
3 | background-color: rgba(97, 113, 243,0.3);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/docs/playground/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 0
3 | mobile: false
4 | title: ''
5 | sidebar: false
6 | ---
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages/chart-render/.fatherrc.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | esm: 'rollup',
3 | cjs: 'rollup',
4 | lessInBabelMode: true,
5 | lessInRollupMode: {},
6 | };
7 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/core/helmetContext.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export const context = {};
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/meta/tabs.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export const tabs = {
5 | }
6 |
--------------------------------------------------------------------------------
/packages/form-render/src/locales/index.ts:
--------------------------------------------------------------------------------
1 | import enUS from './en_US';
2 | import zhCN from './zh_CN';
3 |
4 | export default {
5 | 'en-US': enUS,
6 | 'zh-CN': zhCN,
7 | }
--------------------------------------------------------------------------------
/packages/table-render/src/locales/index.ts:
--------------------------------------------------------------------------------
1 | import enUS from './en_US';
2 | import zhCN from './zh_CN';
3 |
4 | export default {
5 | 'en-US': enUS,
6 | 'zh-CN': zhCN,
7 | }
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/meta/atoms.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export const components = null;
5 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": ["packages/*", "widgets/*", "tools/schema-generator"],
3 | "version": "independent",
4 | "npmClient": "yarn",
5 | "useWorkspaces": true
6 | }
7 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/locales/index.ts:
--------------------------------------------------------------------------------
1 | import enUS from './en_US';
2 | import zhCN from './zh_CN';
3 |
4 | export default {
5 | 'en-US': enUS,
6 | 'zh-CN': zhCN,
7 | }
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/imageInput/index.less:
--------------------------------------------------------------------------------
1 | .fr-preview-image {
2 | width: 160px;
3 | }
4 |
5 | .fr-preview {
6 | position: relative;
7 | cursor: pointer;
8 | }
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/rate/index.tsx:
--------------------------------------------------------------------------------
1 | import { Rate } from 'antd';
2 | import withFieldWrap from '../../utils/withFieldWrap';
3 |
4 | export default withFieldWrap(Rate);
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/render-core/FieldList/index.less:
--------------------------------------------------------------------------------
1 | .frm-list {
2 | .frm-widget-card {
3 | margin-left: 0;
4 | margin-right: 0;
5 | margin-top: 0;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/input/index.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 | import withFieldWrap from '../../utils/withFieldWrap';
3 |
4 | export default withFieldWrap(Input);
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/select/index.tsx:
--------------------------------------------------------------------------------
1 | import { Select } from 'antd';
2 | import withFieldWrap from '../../utils/withFieldWrap';
3 |
4 | export default withFieldWrap(Select);
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/switch/index.tsx:
--------------------------------------------------------------------------------
1 | import { Switch } from 'antd';
2 | import withFieldWrap from '../../utils/withFieldWrap';
3 |
4 | export default withFieldWrap(Switch);
--------------------------------------------------------------------------------
/scripts/dumi-plugin/publicPath.ts:
--------------------------------------------------------------------------------
1 | import { IApi } from 'dumi';
2 |
3 | export default (api: IApi) => {
4 | api.modifyPublicPathStr(() => {
5 | return '/x-render/';
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/packages/form-render/src/models/context.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | export const FRContext = createContext(null);
4 |
5 | export const ConfigContext = createContext(null);
--------------------------------------------------------------------------------
/.fatherrc.js:
--------------------------------------------------------------------------------
1 | // 通用的配置,可以在每个package里写 fatherrc.js 来覆盖
2 | export default {
3 | esm: 'rollup',
4 | disableTypeCheck: false, // 如果出了问题,这个可以改成true
5 | cjs: { type: 'babel', lazy: true },
6 | };
7 |
--------------------------------------------------------------------------------
/packages/data-render/src/models/context.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | export const FRContext = createContext(null);
4 |
5 | export const ConfigContext = createContext(null);
6 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/BaseTable/index.less:
--------------------------------------------------------------------------------
1 | .dv-base-table {
2 | width: 100%;
3 |
4 | .ant-table-cell {
5 | color: #141414;
6 | font-weight: normal;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/models/context.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | export const FRContext = createContext(null);
4 |
5 | export const ConfigContext = createContext(null);
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/number/index.tsx:
--------------------------------------------------------------------------------
1 | import { InputNumber } from 'antd';
2 | import withFieldWrap from '../../utils/withFieldWrap';
3 |
4 | export default withFieldWrap(InputNumber);
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/voidTitle/index.less:
--------------------------------------------------------------------------------
1 | .fr-void-title {
2 | height: 24px;
3 | color: #000000e0;
4 | font-weight: 600;
5 | font-size: 16px;
6 | line-height: 24px;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/treeSelect/index.tsx:
--------------------------------------------------------------------------------
1 | import { TreeSelect } from 'antd';
2 | import withFieldWrap from '../../utils/withFieldWrap';
3 |
4 | export default withFieldWrap(TreeSelect);
--------------------------------------------------------------------------------
/docs/table-render/basic.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 2
3 | title: '基础交互'
4 | mobile: false
5 | group:
6 | title: 最佳展示
7 | order: 2
8 | ---
9 | # 基础交互
10 |
11 |
12 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/PanelView/index.less:
--------------------------------------------------------------------------------
1 | .fr-panel-bordered {
2 | border-radius: 4px;
3 | border: 1px solid #f4f4f4;
4 | padding: 52px 24px 0px 24px;
5 | margin-bottom: 24px;
6 | }
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turborepo.org/schema.json",
3 | "pipeline": {
4 | "build": {
5 | "dependsOn": ["^build"],
6 | "outputs": ["dist/**"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/docs/form-render/changelog.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 2
3 | toc: content
4 | mobile: false
5 | group:
6 | title: 其他
7 | order: 5
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/CopyLabel/index.less:
--------------------------------------------------------------------------------
1 | .icon-label-view {
2 | display: inline-flex;
3 | align-items: center;
4 | margin-right: 5px;
5 | .anticon {
6 | cursor: pointer;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/x-flow/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 更新日志
2 |
3 | ### 1.0.3
4 | - [+] xflow 初始版本发布
5 |
6 | ### 1.0.4
7 | - [+] 增加自定义组件完整案例,修复下拉框在全屏模式下无法显示的问题,增加撤销与重做按钮的隐藏配置
8 |
9 | ### 1.0.5
10 | - [+] 补充节点图标配置文档,以及更新图标的SVG形式的用法
11 |
--------------------------------------------------------------------------------
/packages/x-flow/src/index.less:
--------------------------------------------------------------------------------
1 | #xflow-container {
2 | height: 100%;
3 | width: 100%;
4 | background: #F0F2F7;
5 | position: relative;
6 |
7 | .react-flow__attribution {
8 | display: none;
9 | }
10 | }
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/IconLabel/index.less:
--------------------------------------------------------------------------------
1 | .custom-icon-label-view {
2 | display: inline-flex;
3 | align-items: center;
4 | margin-right: 5px;
5 |
6 | .content {
7 | margin: 0 2px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app.ts:
--------------------------------------------------------------------------------
1 | window.publicPath = '/';
2 |
3 | if (location.origin.includes('gitee')) {
4 | location.href = 'https://xrender.fun/';
5 | }
6 |
7 | if (location.origin.includes('alibaba')) {
8 | window.publicPath = '/x-render/';
9 | }
10 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Hero.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Hero/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Logo.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Logo/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Toc.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Toc/index.js';
5 |
--------------------------------------------------------------------------------
/packages/form-render/src/derivative/SlimRender/index.tsx:
--------------------------------------------------------------------------------
1 | import FormCore from '../../form-core';
2 | import withProvider from '../../withProvider';
3 | import Html from '../../widgets/fields/html';
4 |
5 | export default withProvider(FormCore, { Html });
6 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/builtins/API.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/builtins/API/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Content.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Content/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Footer.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Footer/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Header.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Header/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Navbar.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Navbar/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Sidebar.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Sidebar/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/exports.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export * from '../exports';
5 | export * from '/Users/zhanbo/happy/x-render/node_modules/dumi/dist/client/theme-api/index.js';
6 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/builtins/Badge.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/builtins/Badge/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/builtins/Table.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/builtins/Table/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/Features.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/Features/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/HeadeExtra.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/HeadeExtra/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/HeroTitle.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/HeroTitle/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/LangSwitch.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/LangSwitch/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/NotFound.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/NotFound/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/RtlSwitch.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/RtlSwitch/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/SocialIcon.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/SocialIcon/index.js';
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "printWidth": 80,
5 | "arrowParens": "avoid",
6 | "overrides": [
7 | {
8 | "files": ".prettierrc",
9 | "options": { "parser": "json" }
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/builtins/Container.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/builtins/Container/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/builtins/Previewer.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/builtins/Previewer/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/layouts/DocLayout.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/layouts/DocLayout/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/ColorSwitch.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/ColorSwitch/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/ContentTabs.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/ContentTabs/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/NavbarExtra.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/NavbarExtra/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/SearchResult.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/SearchResult/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/builtins/SourceCode.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/builtins/SourceCode/index.js';
5 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/PreviewerActions.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/PreviewerActions/index.js';
5 |
--------------------------------------------------------------------------------
/docs/form-render/utils/index.js:
--------------------------------------------------------------------------------
1 | export const delay = ms => new Promise(res => setTimeout(res, ms));
2 |
3 | export const fakeApi = (url, data) => {
4 | console.group('request:', url);
5 | console.log('params:', data);
6 | console.groupEnd();
7 | return delay(500);
8 | };
9 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FButton/index.less:
--------------------------------------------------------------------------------
1 | .dr-button {
2 | height: 22px;
3 | padding: 0;
4 | line-height: 22px;
5 | }
6 |
7 | .dr-button-modal {
8 | .ant-modal-confirm-content {
9 | margin-left: 0 !important;
10 | overflow: auto;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FButtonFold/index.less:
--------------------------------------------------------------------------------
1 | .dr-button {
2 | height: 22px;
3 | padding: 0;
4 | line-height: 22px;
5 | }
6 |
7 | .dr-button-modal {
8 | .ant-modal-confirm-content {
9 | margin-left: 0 !important;
10 | overflow: auto;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/utils/createIconFont.ts:
--------------------------------------------------------------------------------
1 | import { createFromIconfontCN } from '@ant-design/icons';
2 |
3 | export default (url?: string) => {
4 | return createFromIconfontCN({
5 | scriptUrl: url || '//at.alicdn.com/t/a/font_2750617_sax751jyfjl.js',
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/PreviewerActionsExtra.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/PreviewerActionsExtra/index.js';
5 |
--------------------------------------------------------------------------------
/docs/xflow/demo/nodeSetting/fullDemo/CustomImg.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const CustomImg = ({ setting }) => {
4 | console.log('props', setting);
5 | return (
6 |
7 | );
8 | }
9 |
10 | export default CustomImg;
--------------------------------------------------------------------------------
/scripts/dumi-plugin/redirect.ts:
--------------------------------------------------------------------------------
1 | import { IApi } from 'dumi'
2 |
3 | export default (api: IApi) => {
4 | api.addEntryCodeAhead(() => {
5 | const code = `
6 | if(location.origin.includes('gitee')) location.href = 'https://xrender.fun'
7 | `
8 | return code
9 | })
10 | };
--------------------------------------------------------------------------------
/.dumi/loading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Spin } from 'antd';
3 |
4 | export default () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
--------------------------------------------------------------------------------
/docs/xflow/demo/custom-flow/fullCase/components/ReadOnlyPanel.tsx:
--------------------------------------------------------------------------------
1 | import '../index.less';
2 |
3 | const ReadOnlyPanel = (props) => {
4 | const { value } = props;
5 |
6 | return {value?? '-'}
;
7 | };
8 |
9 | export default ReadOnlyPanel;
10 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FLabel/index.less:
--------------------------------------------------------------------------------
1 | .dr-label {
2 | font-size: 14px;
3 | line-height: 24px;
4 |
5 | .label {
6 | display: inline-block;
7 | font-weight: bold;
8 | text-align: right;
9 | }
10 |
11 | .content {
12 | color: #141414;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/docs/xflow/best-practices.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | title: '最佳实践'
4 | mobile: false
5 | group:
6 | title: 最佳实践
7 | order: 3
8 | ---
9 |
10 | # 最佳实践
11 |
12 |
13 | ## 案例1
14 |
15 |
16 | ## 案例2
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/basic/TextEllipsis/index.less:
--------------------------------------------------------------------------------
1 | .text-ellipsis {
2 | display: inline-block;
3 | max-width: 100%;
4 | overflow: hidden;
5 | white-space: nowrap;
6 | text-overflow: ellipsis;
7 | }
8 |
9 | .paragraph-ellipsis {
10 | display: block;
11 | width: 100%;
12 | word-break: break-all;
13 | }
14 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/demo2/TextEllipsis/index.less:
--------------------------------------------------------------------------------
1 | .text-ellipsis {
2 | display: inline-block;
3 | max-width: 100%;
4 | overflow: hidden;
5 | white-space: nowrap;
6 | text-overflow: ellipsis;
7 | }
8 |
9 | .paragraph-ellipsis {
10 | display: block;
11 | width: 100%;
12 | word-break: break-all;
13 | }
14 |
--------------------------------------------------------------------------------
/packages/chart-render/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { MetaItem } from './type';
2 |
3 | export function splitMeta(meta: MetaItem[] = []) {
4 | const metaDim: MetaItem[] = [];
5 | const metaInd: MetaItem[] = [];
6 | meta.forEach(item => (item.isDim ? metaDim : metaInd).push(item));
7 | return { metaDim, metaInd };
8 | }
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: lhbxs
7 | ---
8 |
9 | ### 期望的新功能 (describe the expected new feature)
10 |
11 | ### 简述一下使用场景,便于开发者更好理解新功能的必要性 (describe your scenario for us to understand the need)
12 |
--------------------------------------------------------------------------------
/docs/xflow/updateLog.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 2
3 | title: '更新日志'
4 | mobile: false
5 | group:
6 | title: '其他'
7 | order: 5
8 | ---
9 |
10 | # 更新日志
11 |
12 | ### 1.0.3
13 | - [+] xflow 初始版本发布
14 |
15 | ### 1.0.4
16 | - [+] 增加自定义组件完整案例,修复下拉框在全屏模式下无法显示的问题,增加撤销与重做按钮的隐藏配置
17 |
18 | ### 1.0.5
19 | - [+] 补充节点图标配置文档,以及更新图标的SVG形式的用法
20 |
--------------------------------------------------------------------------------
/packages/x-flow/src/components/TextEllipsis/index.less:
--------------------------------------------------------------------------------
1 | .text-ellipsis {
2 | display: inline-block;
3 | max-width: 100%;
4 | overflow: hidden;
5 | text-overflow: ellipsis;
6 | white-space: nowrap;
7 | }
8 |
9 |
10 | .paragraph-ellipsis {
11 | display: block;
12 | width: 100%;
13 | word-break: break-all;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/data-render/src/index.ts:
--------------------------------------------------------------------------------
1 | import DRender from './core';
2 | import withProvider from './withProvider';
3 | import * as defaultWidgets from './widgets';
4 |
5 | export { default as FRender } from './core/renderer';
6 |
7 | export const DataSlimRender = withProvider(DRender);
8 | export default withProvider(DRender, defaultWidgets);
9 |
--------------------------------------------------------------------------------
/docs/form-render/demo/FormRender.jsx:
--------------------------------------------------------------------------------
1 | import FormRender, { useForm } from 'form-render';
2 | import React from 'react';
3 |
4 | const Demo = ({ schema, ...otherProps }) => {
5 | const form = useForm();
6 |
7 | return
8 | };
9 |
10 | export default Demo;
11 |
--------------------------------------------------------------------------------
/docs/table-render/custom-table.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 6
3 | mobile: false
4 | title: 'Table 包裹容器'
5 | group:
6 | title: 最佳展示
7 | order: 0
8 | ---
9 |
10 | # tableWrapper 包裹容器
11 |
12 | 有些情况下,你会希望在搜索栏和表格之间增加一些内容。这时可以通过 `tableWrapper` 实现你的需求。
13 |
14 |
15 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/TextEllipsis/index.less:
--------------------------------------------------------------------------------
1 | .text-ellipsis-hidden {
2 | visibility: hidden;
3 | }
4 | .text-ellipsis-box {
5 | overflow: hidden;
6 |
7 | .text-ellipsis-all {
8 | padding: 0 16px;
9 | color: rgba(63, 127, 251, 1);
10 | font-size: 14px;
11 | cursor: pointer;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FText/index.less:
--------------------------------------------------------------------------------
1 | .dv-text {
2 | display: inline-flex;
3 | align-items: center;
4 | min-width: 20px;
5 | min-height: 18px;
6 | margin-right: 10px;
7 | font-size: 14px;
8 |
9 | .left-icon {
10 | margin-right: 4px;
11 | }
12 |
13 | .right-icon {
14 | margin-left: 4px;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/table-render/src/core/ToolbarView/index.less:
--------------------------------------------------------------------------------
1 | .tr-toolbar {
2 | display: flex;
3 | align-items: center;
4 | justify-content: space-between;
5 | height: 64px;
6 | }
7 |
8 | .tr-toolbar-nohead {
9 | height: 24px;
10 | }
11 |
12 |
13 | .tr-toolbar-right {
14 | display: flex;
15 | align-items: flex-start;
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/.github/workflows/emoji-helper.yml:
--------------------------------------------------------------------------------
1 | name: Emoji Helper
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | emoji:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions-cool/emoji-helper@v1.0.0
12 | with:
13 | type: 'release'
14 | emoji: '+1, laugh, heart, hooray, rocket, eyes'
15 |
--------------------------------------------------------------------------------
/packages/form-render/src/form-core/connectForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | import useForm from '../models/useForm';
3 |
4 | export default (Component: React.FC) => {
5 | return forwardRef((props, ref) => {
6 | const form = useForm();
7 |
8 | return ;
9 | });
10 | }
--------------------------------------------------------------------------------
/packages/table-render/CONTRIBUTION.md:
--------------------------------------------------------------------------------
1 | ## 如何贡献代码
2 |
3 | ```
4 | # fork项目 & git clone
5 |
6 | # 安装依赖
7 | tnpm i
8 |
9 | # 切到 dev 分支
10 | git checkout dev
11 |
12 | # 跑起来
13 | npm start
14 |
15 | # 发布
16 | ## 1. 更新版本
17 | npm version patch (major, minor)
18 |
19 | ## 2. 修改 README.md / CHANGELOG.md
20 |
21 | ## 3. 发布
22 | tnpm publish
23 | ```
24 |
--------------------------------------------------------------------------------
/packages/x-flow/src/utils/createIconFont.ts:
--------------------------------------------------------------------------------
1 | import { createFromIconfontCN } from '@ant-design/icons';
2 |
3 | export default (url?: string) => {
4 | return createFromIconfontCN({
5 | // scriptUrl: url || '//at.alicdn.com/t/a/font_4201076_frx3c9x07if.js',
6 | scriptUrl: url || '//at.alicdn.com/t/a/font_4069358_dd524fgnynb.js',
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/docs/playground/controller/index.css:
--------------------------------------------------------------------------------
1 | .playground-controller .fr-field {
2 | margin-bottom: 4px;
3 | }
4 |
5 | .playground-controller {
6 | margin-bottom: 1px;
7 | background-color: #fff;
8 | padding: 12px 30px 6px 30px;
9 | border-radius: 3px;
10 | }
11 |
12 | .playground-controller .fr-inline-field {
13 | margin-right: 60px !important;
14 | }
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FRow/index.less:
--------------------------------------------------------------------------------
1 | .dr-row {
2 | height: 100%;
3 |
4 | .col-item {
5 | width: 0;
6 | }
7 |
8 | .col-item-background {
9 | position: relative;
10 | padding: 10px 15px;
11 | background: #fff;
12 | border-radius: 3px;
13 |
14 | box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.06);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/form-core/connectForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | import useForm from '../models/useForm';
3 |
4 | export default (Component: React.FC) => {
5 | return forwardRef((props, ref) => {
6 | const form = useForm();
7 |
8 | return ;
9 | });
10 | }
--------------------------------------------------------------------------------
/packages/table-render/开发文档.md:
--------------------------------------------------------------------------------
1 | # 开发文档
2 |
3 | ## 启动
4 |
5 | ```
6 | # 安装依赖
7 | yarn
8 | # 起项目
9 | npm start
10 | ```
11 |
12 | ## 开发
13 |
14 | 小需求 & 简单的 bug fix,在 dev 分支开发,大改动另起一个分支,分支名表达改动内容就行
15 |
16 | ## 发布
17 |
18 | ```
19 | # tag版本号
20 | npm version 1.0.0 或者 npm version patch
21 | # 发版
22 | npm publish
23 | # 部署文档
24 | npm run deploy
25 | ```
26 |
--------------------------------------------------------------------------------
/packages/x-flow/src/nodes/node-common/index.less:
--------------------------------------------------------------------------------
1 | .custom-node-start {
2 | width: 240px;
3 | padding: 0 12px;
4 | background: #fff;
5 | border-radius: 12px;
6 |
7 | .title {
8 | display: flex;
9 | height: 50px;
10 | align-items: center;
11 | span {
12 | font-weight: bold;
13 | margin-left: 8px;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/packages/x-flow/src/nodes/node-end/index.less:
--------------------------------------------------------------------------------
1 | .custom-node-start {
2 | width: 240px;
3 | padding: 0 12px;
4 | background: #fff;
5 | border-radius: 12px;
6 |
7 | .title {
8 | display: flex;
9 | height: 50px;
10 | align-items: center;
11 | span {
12 | font-weight: bold;
13 | margin-left: 8px;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/packages/x-flow/src/nodes/node-start/index.less:
--------------------------------------------------------------------------------
1 | .custom-node-start {
2 | width: 240px;
3 | padding: 0 12px;
4 | background: #fff;
5 | border-radius: 12px;
6 |
7 | .title {
8 | display: flex;
9 | height: 50px;
10 | align-items: center;
11 | span {
12 | font-weight: bold;
13 | margin-left: 8px;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/.dumi/tmp-production/core/EmptyRoute.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | import React from 'react';
5 | import { Outlet, useOutletContext } from 'umi';
6 | export default function EmptyRoute() {
7 | const context = useOutletContext();
8 | return ;
9 | }
10 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/theme/slots/SearchBar.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export { default } from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/SearchBar/index.js';
5 | export * from '/Users/zhanbo/happy/x-render/node_modules/dumi/theme-default/slots/SearchBar/index.js';
6 |
--------------------------------------------------------------------------------
/docs/xflow/demo/flow-provider/nodes.ts:
--------------------------------------------------------------------------------
1 | export const nodes = [
2 | {
3 | id: '1',
4 | type: 'Start',
5 | data: {},
6 | position: {
7 | x: 40,
8 | y: 240,
9 | },
10 | },
11 | {
12 | id: '2',
13 | type: 'End',
14 | data: {},
15 | position: {
16 | x: 500,
17 | y: 240,
18 | },
19 | },
20 | ];
21 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FImage/index.less:
--------------------------------------------------------------------------------
1 | .custom-image-widget {
2 | width: 170px;
3 | height: 100px;
4 | margin: 8px 0;
5 | background-image: linear-gradient(180deg, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.25) 100%);
6 | border-radius: 2px;
7 |
8 | img {
9 | width: 100%;
10 | height: 100%;
11 | border-radius: 2px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/voidTitle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import './index.less';
4 |
5 | export default ({ schema }) => {
6 | return (
7 |
8 | {schema.title}
9 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/packages/chart-render/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { Schema } from 'formRenderV1';
2 | export { ChartProvider, withChart } from './components/ChartProvider';
3 | export { default as Search } from './components/Search';
4 | export { useChart } from './utils/store';
5 |
6 | export { default as Column } from './widgets/Column';
7 | export { default as Pie } from './widgets/Pie';
8 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/IconView/index.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { createFromIconfontCN } from '@ant-design/icons';
3 |
4 | /**
5 | * icon 图标库
6 | *
7 | * 图标库资源变动需要更新 scriptUrl 资源路径
8 | */
9 |
10 | const IconView = createFromIconfontCN({
11 | scriptUrl: '//at.alicdn.com/t/font_2750617_db4bg3gyled.js',
12 | });
13 |
14 | export default IconView;
15 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/PanelView/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames'
3 | import './index.less';
4 |
5 | const PanelView = ({ children, bordered } : any) => {
6 | return {children}
;
7 | }
8 |
9 | export default PanelView;
10 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/dumi/exportStaticRuntimePlugin.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export function modifyClientRenderOpts(memo: any) {
5 | const { history, hydrate } = memo;
6 |
7 | return {
8 | ...memo,
9 | hydrate: hydrate && !history.location.pathname.startsWith('/~demos'),
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/.dumi/theme/layouts/GlobalLayout/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ConfigProvider } from 'antd';
3 | import { useOutlet } from 'dumi';
4 |
5 | const GlobalLayout: React.FC = () => {
6 | const outlet = useOutlet();
7 | return (
8 |
10 | {outlet}
11 |
12 | );
13 | };
14 |
15 | export default GlobalLayout;
16 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/core/exportStaticRuntimePlugin.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | export function modifyClientRenderOpts(memo: any) {
5 | const { history, hydrate } = memo;
6 |
7 | return {
8 | ...memo,
9 | hydrate: hydrate && !["/~demos/:id"].includes(history.location.pathname),
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/docs/xflow/demo/custom-flow/customWidget.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 |
3 | const customWidget = ({ value, onChange,...rest }) => {
4 | console.log("参数", { value, onChange, ...rest })
5 | return (
6 | onChange({ inputVal: e.target.value })}
9 | />
10 | );
11 | };
12 |
13 | export default customWidget;
14 |
--------------------------------------------------------------------------------
/packages/table-render/src/locales/zh_CN.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "search": "查询",
3 | "reset": "重置",
4 | "copy_success": "复制成功",
5 | "column_setting": "列设置",
6 | "default": "默认",
7 | "middle": "中等",
8 | "small": "紧凑",
9 | "table_density": "表格密度",
10 | "exit_full_screen": "退出全屏",
11 | "full_screen": "全屏",
12 | "cannot_full_screen": "当前页面不支持全屏功能",
13 | "reload": "刷新"
14 | };
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTitle/index.less:
--------------------------------------------------------------------------------
1 | .dr-title {
2 | display: flex;
3 | align-items: center;
4 | margin-bottom: 10px;
5 |
6 | .view-title {
7 | margin: 0;
8 | color: #141414;
9 | }
10 |
11 | .view-title-icon {
12 | width: 6px;
13 | height: 6px;
14 | margin-right: 10px;
15 | background-color: #3f7ffb;
16 | border-radius: 6px;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/Group/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | const prefix = 'frm-widget-group';
5 |
6 | export default (props: any) => {
7 | const { children, title } = props;
8 |
9 | return (
10 |
11 |
{title}
12 | {children}
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/widgets/RichText/.fatherrc.js:
--------------------------------------------------------------------------------
1 | // 通用的配置,可以在每个package里写 fatherrc.js 来覆盖
2 | export default {
3 | esm: 'rollup',
4 | cjs: 'rollup',
5 | disableTypeCheck: false, // 如果出了问题,这个可以改成true
6 | extraBabelPlugins: [
7 | [
8 | 'babel-plugin-import',
9 | {
10 | libraryName: 'antd',
11 | libraryDirectory: 'lib',
12 | style: true,
13 | },
14 | ],
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/widgets/template/.fatherrc.js:
--------------------------------------------------------------------------------
1 | // 通用的配置,可以在每个package里写 fatherrc.js 来覆盖
2 | export default {
3 | esm: 'rollup',
4 | cjs: 'rollup',
5 | disableTypeCheck: false, // 如果出了问题,这个可以改成true
6 | extraBabelPlugins: [
7 | [
8 | 'babel-plugin-import',
9 | {
10 | libraryName: 'antd',
11 | libraryDirectory: 'lib',
12 | style: true,
13 | },
14 | ],
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/widgets/AsyncOptions/.fatherrc.js:
--------------------------------------------------------------------------------
1 | // 通用的配置,可以在每个package里写 fatherrc.js 来覆盖
2 | export default {
3 | esm: 'rollup',
4 | cjs: 'rollup',
5 | disableTypeCheck: false, // 如果出了问题,这个可以改成true
6 | extraBabelPlugins: [
7 | [
8 | 'babel-plugin-import',
9 | {
10 | libraryName: 'antd',
11 | libraryDirectory: 'lib',
12 | style: true,
13 | },
14 | ],
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/Group/index.less:
--------------------------------------------------------------------------------
1 | .frm-widget-group {
2 |
3 | &-title {
4 | font-size: 15px;
5 | color: #999;
6 | padding: 6px 16px;
7 | border-top: 1px solid rgb(238, 238, 238);
8 | border-bottom: 1px solid rgb(238, 238, 238);
9 | }
10 |
11 | .adm-grid-item:first-of-type {
12 | .adm-list-item-content {
13 | border-top: none;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/x-flow/src/components/IconView/index.tsx:
--------------------------------------------------------------------------------
1 | import { createFromIconfontCN } from '@ant-design/icons';
2 |
3 | /**
4 | * icon 图标库
5 | * 图标库资源变动需要更新 scriptUrl 资源路径
6 | * https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4201076
7 | */
8 |
9 | const Icon = createFromIconfontCN({
10 | scriptUrl: '//at.alicdn.com/t/a/font_4069358_dd524fgnynb.js',
11 | });
12 |
13 | export default Icon;
14 |
--------------------------------------------------------------------------------
/tsconfig.jest.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES5",
4 | "types": ["jest", "jest-enzyme"],
5 | "allowJs": true,
6 | "skipLibCheck": false,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "jsx": "react",
10 | "paths": {
11 | "@@/*": [".dumi/tmp/*"]
12 | }
13 | },
14 | "exclude": ["./packages/*/esm", "./packages/*/lib"]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/x-flow/src/models/context.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 | import { FlowProps } from '../types';
3 | import { FlowStore } from './store';
4 |
5 | type Config = FlowProps & Record
6 | export const ConfigContext = createContext(null);
7 |
8 | const StoreContext = createContext(null);
9 | export const Provider = StoreContext.Provider;
10 | export default StoreContext;
11 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import { defineConfig } from 'vitest/config';
4 | import react from '@vitejs/plugin-react';
5 |
6 | export default defineConfig({
7 | plugins: [
8 | react({
9 | babel: {
10 | plugins: ['@babel/plugin-transform-react-jsx'],
11 | },
12 | }) as any,
13 | ],
14 | test: {
15 | globals: true,
16 | environment: 'jsdom',
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listDrawer/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-list-drawer {
4 | margin-bottom: 24px;
5 |
6 | &-table-header {
7 | width: 100%;
8 | display: flex;
9 | justify-content: right;
10 | align-items: center;
11 | margin-bottom: 10px;
12 | }
13 |
14 | .@{ant-prefix}-form-item {
15 | margin-bottom: 0;
16 | }
17 |
18 | .fr-list-item-operate {
19 | gap: 0 !important;
20 | }
21 | }
--------------------------------------------------------------------------------
/packages/form-render-mobile/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 更新日志
2 |
3 | ### 1.0.15
4 | - [!] 修复 removeHidden 配置不生效
5 |
6 | ### 1.0.14
7 | - [+] labelWidget、descWidget 增加 addons 访问属性
8 | - [-] 兼容 widget 大小写配置
9 | ### 1.0.13
10 | - [+] 增加输入控件单独配置布局 layout = 'row' | 'column'
11 | - [+] 补齐 tooltip 字段,与 PC 端保持一致
12 | - [!] 修复 title 不存在时,校验信息不提示
13 | ### 1.0.5
14 | - [+] 增加 form.getFieldRef API,自定义组件可以暴露实例,供 getFieldRef 使用
15 | ### 1.0.0
16 |
17 | - [+] form-render-mobile 1.0 正式发版
18 |
--------------------------------------------------------------------------------
/packages/x-flow/src/operator/UndoRedo/index.less:
--------------------------------------------------------------------------------
1 | .fai-reactflow-undoredo {
2 | display: flex;
3 | align-items: center;
4 | padding: 2px 1px;
5 | border-radius: 8px;
6 | border: 0.5px solid #f3f4f6;
7 | background-color: #ffffff;
8 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
9 | color: #667085;
10 | margin-right: 10px;
11 |
12 | .ant-btn {
13 | display: inline-flex;
14 | align-items: center;
15 | justify-content: center;
16 | }
17 | }
--------------------------------------------------------------------------------
/docs/form-render/test/test.md:
--------------------------------------------------------------------------------
1 | ---
2 | mobile: false
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/form-core/index.less:
--------------------------------------------------------------------------------
1 | .frm-form {
2 | .adm-list-item {
3 | padding: 0 16px;
4 | }
5 |
6 | .adm-collapse-panel-content-inner > .adm-list-item {
7 | padding: 0;
8 |
9 | .adm-list-item-content {
10 | padding-right: 0;
11 | }
12 | }
13 |
14 | .adm-list-body {
15 | background: transparent;
16 | }
17 | }
18 |
19 | .frm-form-card {
20 | .adm-list-body {
21 | border: none !important;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/core/helmet.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | import React from 'react';
5 | import { HelmetProvider } from '/Users/zhanbo/happy/x-render/node_modules/@umijs/preset-umi/node_modules/@umijs/renderer-react';
6 | import { context } from './helmetContext';
7 |
8 | export const innerProvider = (container) => {
9 | return React.createElement(HelmetProvider, { context }, container);
10 | }
11 |
--------------------------------------------------------------------------------
/docs/form-render/schema/basic.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | type: 'object',
3 | column: 3,
4 | displayType: 'row',
5 | properties: {
6 | input1: {
7 | title: 'Field A',
8 | type: 'string'
9 | },
10 | input2: {
11 | title: 'Field B',
12 | type: 'string'
13 | },
14 | input3: {
15 | title: 'Field C',
16 | type: 'string'
17 | },
18 | input4: {
19 | title: 'Field D',
20 | type: 'string'
21 | }
22 | }
23 | };
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/HeaderTitle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | const HeaderTitle = (props: any) => {
5 | const { title, description } = props;
6 |
7 | return (
8 |
9 | {title}
10 | {description && ( {description} ) }
11 |
12 | );
13 | }
14 |
15 | export default HeaderTitle
16 |
--------------------------------------------------------------------------------
/docs/playground/json/dynamic-function.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | schema: {
3 | type: 'object',
4 | properties: {
5 | input: {
6 | title: '动态函数检验',
7 | tooltip: '动态函数检验,存储的是纯函数',
8 | type: 'string',
9 | labelWidth: 120,
10 | rules: [
11 | {
12 | validator: (rule, value) => value === 'muji',
13 | message: '输入的值不等于muji,请重新输入!',
14 | },
15 | ],
16 | },
17 | },
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/textArea/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Input } from 'antd';
3 | import withFieldWrap from '../../utils/withFieldWrap';
4 |
5 | const TextArea = (props: any) => {
6 | let finalProps = {
7 | autoSize: {
8 | minRows: 3,
9 | },
10 | ...props,
11 | };
12 | if (finalProps.rows) delete finalProps.autoSize;
13 |
14 | return ;
15 | };
16 |
17 |
18 | export default withFieldWrap(TextArea)
--------------------------------------------------------------------------------
/packages/table-render/src/locales/en_US.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "search": "Search",
3 | "reset": "Reset",
4 | "copy_success": "Copy Success",
5 | "column_setting": "ColumnSetting",
6 | "default": "Default",
7 | "middle": "Middle",
8 | "small": "small",
9 | "table_density": "Table Density",
10 | "exit_full_screen": "Exit FullScreen",
11 | "full_screen": "FullScreen",
12 | "cannot_full_screen": "The current page does not support full screen function",
13 | "reload": "Reload"
14 | }
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listCard/index.less:
--------------------------------------------------------------------------------
1 | .fr-list-card {
2 | margin-bottom: 24px;
3 |
4 | .fr-list-item {
5 | display: flex;
6 | align-items: flex-start;
7 | position: relative;
8 | }
9 |
10 | .fr-list-item-operate {
11 | padding: 0 20px;
12 | height: 32px;
13 | gap: 0 !important;
14 | }
15 |
16 | .fr-list-item-operate-fixed {
17 | position: absolute;
18 | right: 8px;
19 | }
20 |
21 | .fr-list-add-btn {
22 | padding: 0 8px;
23 | }
24 | }
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/utils/hooks.ts:
--------------------------------------------------------------------------------
1 | import { useReducer, useRef, useEffect } from 'react';
2 |
3 | export function usePrevious(value: any) {
4 | const ref = useRef(null);
5 | useEffect(() => {
6 | ref.current = value;
7 | }, [value]);
8 | return ref.current;
9 | }
10 |
11 | // 类似于class component的setState
12 | export const useSet = (initState: any) => {
13 | return useReducer((state: any, newState: any) => {
14 | return { ...state, ...newState };
15 | }, initState);
16 | };
17 |
--------------------------------------------------------------------------------
/docs/form-render/schema/simple.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | type: 'object',
3 | properties: {
4 | input: {
5 | title: '输入框',
6 | type: 'string',
7 | widget: 'input'
8 | },
9 | select: {
10 | title: '下拉框',
11 | type: 'string',
12 | widget: 'select',
13 | props: {
14 | options: [
15 | { label: '早', value: 'a' },
16 | { label: '中', value: 'b' },
17 | { label: '晚', value: 'c' }
18 | ]
19 | }
20 | }
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/basic/tools.tsx:
--------------------------------------------------------------------------------
1 | import { Button, Space } from 'antd';
2 | import React from 'react'
3 |
4 |
5 | export const Tools = () => {
6 | return (
7 |
8 |
9 | 预览
10 |
11 |
12 | 保存
13 |
14 |
15 | 立即发布
16 |
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/demo2/tools.tsx:
--------------------------------------------------------------------------------
1 | import { Button, Space } from 'antd';
2 | import React from 'react'
3 |
4 |
5 | export const Tools = () => {
6 | return (
7 |
8 |
9 | 预览
10 |
11 |
12 | 保存
13 |
14 |
15 | 立即发布
16 |
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/boxcard/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-obj-card {
4 | border-radius: 4px;
5 | border-color: #f4f4f4;
6 | margin-bottom: 24px !important;
7 |
8 | .@{ant-prefix}-card-head {
9 | border: none
10 | }
11 |
12 | .@{ant-prefix}-card-body {
13 | padding: 12px 24px !important;
14 | }
15 |
16 | .fr-header-desc {
17 | word-break: break-all;
18 | color: rgba(0, 0, 0, .45);
19 | margin-left: 6px;
20 | font-weight: normal;
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/docs/table-render/toolbar.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 7
3 | title: '工具栏'
4 | mobile: false
5 | group:
6 | title: 最佳展示
7 | ---
8 |
9 | # 工具栏
10 |
11 | Table Render 内置工具栏,通过 `toolbarAction` 开启。默认四种功能,刷新表格、更改表格 `size`、全屏显示表格、表格列设置。
12 |
13 | :::warning
14 | 使用表格列设置功能,必须为每个 `column` 指定 `key` 或 `dataIndex`。大多数场景下使用 `dataIndex` 就足够了,但前提是必须保证其是唯一的,如果不是,需要另外指定 `key` 的值。
15 | :::
16 |
17 |
18 |
19 | 可以通过传入一个对象控制具体使用哪些工具,例如只显示列设置功能。
20 |
21 |
--------------------------------------------------------------------------------
/packages/chart-render/src/components/ChartContainer/index.tsx:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React, { CSSProperties, FC, memo } from 'react';
3 | import './index.less';
4 |
5 | const ChartContainer: FC<{
6 | children: React.ReactNode;
7 | className?: string;
8 | style?: CSSProperties;
9 | }> = ({ children, className, style }) => (
10 |
11 | {children}
12 |
13 | );
14 |
15 | export default memo(ChartContainer);
16 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/boxLineTitle/index.less:
--------------------------------------------------------------------------------
1 | .fr-obj-line-title {
2 | .fr-obj-header {
3 | line-height: 36px;
4 | border-bottom: 1px solid #e9e9e9;
5 | }
6 |
7 | .fr-header-title {
8 | color: #000000e0;
9 | font-size: 16px;
10 | font-weight: 600;
11 | }
12 |
13 | .fr-header-desc {
14 | word-break: break-all;
15 | color: rgba(0, 0, 0, .45);
16 | margin-left: 6px;
17 | font-weight: normal;
18 | }
19 |
20 | .fr-obj-content {
21 | padding: 24px 0 0 0;
22 | }
23 | }
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/boxSubInline/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-obj-subinline-label-hidden > .@{ant-prefix}-form-item-row > .@{ant-prefix}-form-item-label {
4 | visibility: hidden;
5 | }
6 |
7 | .fr-obj-subinline-background > .@{ant-prefix}-form-item-row > .@{ant-prefix}-form-item-control {
8 | background-color: #f6f6f6;
9 | padding: 24px 24px 0 24px;
10 | border-radius: 4px;
11 | }
12 |
13 | .fr-obj-subinline {
14 | .@{ant-prefix}-form-item-row {
15 | flex-wrap: nowrap;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/x-flow/src/index.ts:
--------------------------------------------------------------------------------
1 | import XFlow from './XFlow';
2 | import withProvider from './withProvider';
3 |
4 | import * as nodes from './nodes';
5 | import FlowProps from './types';
6 |
7 | export type {
8 | default as FR,
9 | } from './types';
10 |
11 | export { FlowProvider } from './components/FlowProvider';
12 | export { useFlow } from './hooks/useFlow';
13 | export { useNodes } from './hooks/useNodes';
14 | export { useEdges } from './hooks/useEdges';
15 |
16 | export default withProvider(XFlow, nodes);
17 |
--------------------------------------------------------------------------------
/packages/x-flow/src/nodes/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as StartNode } from './node-start';
2 | export { default as EndNode } from './node-end';
3 | export { default as CommonNode } from './node-common';
4 | export { default as SwitchNode } from './node-switch';
5 | export { default as SwitchNodeSettingWidget } from './node-switch/setting';
6 | export { default as ParallelNode } from './node-parallel';
7 | export { default as ParallelNodeSettingWidget } from './node-parallel/setting';
8 | export { default as NoteNode } from './node-note';
9 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/render-core/FieldItem/field.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useUpdateEffect } from 'ahooks';
3 |
4 | const FieldWrapper = (props: any) => {
5 | const { Field, fieldProps, defaultValue, ...otherProps } = props;
6 |
7 | useUpdateEffect(() => {
8 | otherProps.onChange(defaultValue);
9 | }, [JSON.stringify(defaultValue)]);
10 |
11 | return (
12 |
16 | );
17 | }
18 |
19 | export default FieldWrapper;
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/checkbox/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Checkbox } from 'antd';
3 | import withFieldWrap from '../../utils/withFieldWrap';
4 |
5 | interface Props {
6 | title: string;
7 | [key: string]: any;
8 | }
9 |
10 | const CheckBox: React.FC = ({ title, ...rest }) => {
11 | return (
12 | <>
13 |
14 | {title}
15 | >
16 | );
17 | }
18 |
19 | export default withFieldWrap(CheckBox);
20 |
21 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/color/index.less:
--------------------------------------------------------------------------------
1 | .fr-color-picker {
2 | width: 100%;
3 | display: flex;
4 | flex-direction: row;
5 | align-items: center;
6 | color: #666;
7 | }
8 |
9 | .fr-color-picker .rc-color-picker-trigger {
10 | margin-right: 12px;
11 | height: 32px;
12 | width: 60px;
13 | border: 1px solid #e5e5e5;
14 | }
15 |
16 | .fr-color-picker > p {
17 | margin: 0;
18 | font-size: 14px;
19 | line-height: 28px;
20 | }
21 |
22 | .fr-color-picker .rc-color-picker-wrap {
23 | display: flex;
24 | }
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/InnerHtml/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | const InnerHtml = (props: any) => {
5 | const { data, style, className } = props;
6 |
7 | if (typeof data === 'object') {
8 | return null;
9 | }
10 |
11 | return (
12 |
17 | );
18 | };
19 |
20 | export default InnerHtml;
21 |
--------------------------------------------------------------------------------
/packages/x-flow/src/utils/flow.ts:
--------------------------------------------------------------------------------
1 | import { uuid } from './';
2 |
3 | /**
4 | * 获取所有子节点
5 | */
6 | export const generateCopyNodes = (parentNode: any) => {
7 | // 1、定义 childNodeIds 数组,用于存储找到的所有节点的 id,默认把 rootNode 添加到数组中
8 | const childNodes: any[] = [];
9 | const rootNode = {
10 | id: uuid(),
11 | type: parentNode.type,
12 | data: {
13 | ...parentNode.data,
14 | },
15 | position: { x: 0, y: 0 },
16 | sourceId: parentNode.id,
17 | };
18 | childNodes.push(rootNode);
19 |
20 | return childNodes;
21 | };
22 |
--------------------------------------------------------------------------------
/docs/playground/json/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "properties": {
5 | "listName": {
6 | "title": "对象数组",
7 | "description": "对象数组嵌套功能",
8 | "type": "array",
9 | "items": {
10 | "type": "object",
11 | "properties": {
12 | "inputName": {
13 | "title": "简单输入框",
14 | "type": "string"
15 | }
16 | }
17 | }
18 | }
19 | },
20 | "required": []
21 | },
22 | "formData": {}
23 | }
24 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/utils/hooks.ts:
--------------------------------------------------------------------------------
1 | import { message } from 'antd';
2 | import { useReducer, useRef, useEffect, useState } from 'react';
3 |
4 | export function usePrevious(value: any) {
5 | const ref = useRef(null);
6 | useEffect(() => {
7 | ref.current = value;
8 | }, [value]);
9 | return ref.current;
10 | }
11 |
12 | // 类似于class component的setState
13 | export const useSet = (initState: any) => {
14 | return useReducer((state: any, newState: any) => {
15 | return { ...state, ...newState };
16 | }, initState);
17 | };
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/ErrorSchema/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { translation } from '../utils';
3 | import { ConfigProvider } from 'antd';
4 |
5 | const ErrorSchema = (schema: any) => {
6 | const configCtx = useContext(ConfigProvider.ConfigContext);
7 | const t = translation(configCtx);
8 |
9 | return (
10 |
11 |
{t('schema_not_match')}
12 |
{JSON.stringify(schema)}
13 |
14 | );
15 | }
16 |
17 | export default ErrorSchema;
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/utils/withFieldWrap.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const getProps = (props: any, filter: any[]) => {
4 | const result = {};
5 |
6 | Object.keys(props).forEach(key => {
7 | if (filter.includes(key)) {
8 | return;
9 | }
10 | result[key] = props[key];
11 | });
12 |
13 | return result;
14 | }
15 |
16 | export default (Field: any, filterProps = ['addons', 'schema', 'dependValues']) => {
17 | return (props: any) => {
18 | return ;
19 | };
20 | }
--------------------------------------------------------------------------------
/packages/x-flow/src/components/CustomEdge/index.less:
--------------------------------------------------------------------------------
1 |
2 | .custom-edge-line {
3 | position: absolute;
4 | z-index: 1000;
5 | pointer-events: all;
6 |
7 | .line-content {
8 | width: 60px;
9 | display: flex;
10 | justify-content: space-around;
11 | align-items: center;
12 | }
13 |
14 | .line-icon-box {
15 | width: 16px;
16 | height: 16px;
17 | border-radius: 16px;
18 | display: flex;
19 | align-items: center;
20 | justify-content: center;
21 | background: #296dff;
22 | visibility: visible;
23 | }
24 | }
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/TimePicker/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import DatePicker from '../DatePicker';
3 |
4 | const TimePicker: any = React.forwardRef((props: any, ref: any) => {
5 | return ;
6 | });
7 |
8 | TimePicker.displayName = 'TimePicker';
9 |
10 | TimePicker.RangePicker = React.forwardRef((props: any, ref: any) => {
11 | return ;
12 | });
13 |
14 | export default TimePicker;
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/Radio/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Radio, Space } from 'antd-mobile';
3 | import { omit } from 'lodash-es';
4 |
5 | export default (props: any) => {
6 | const { options, ...rest } = omit(props, ['addons', 'schema'])
7 | return (
8 |
9 |
10 | {options.map((item: any) => {
11 | return {item.label}
12 | })}
13 |
14 |
15 | )
16 | }
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/FButton/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button } from 'antd';
3 |
4 | const HeaderTitle = (props: any) => {
5 | const { icon, children, btnType, ...otherProps } = props;
6 |
7 | let btnProps = { ...otherProps };
8 | if (btnType === 'icon') {
9 | btnProps.icon = icon;
10 | btnProps.size = 'small'
11 | } else {
12 | btnProps.children = children;
13 | }
14 |
15 | return (
16 |
17 | );
18 | }
19 |
20 | export default HeaderTitle
21 |
--------------------------------------------------------------------------------
/packages/x-flow/.fatherrc.js:
--------------------------------------------------------------------------------
1 | import copy from 'rollup-plugin-copy';
2 |
3 | export default {
4 | cjs: 'babel',
5 | esm: {
6 | type: 'babel',
7 | importLibToEs: true,
8 | },
9 | lessInBabelMode: true,
10 | extraRollupPlugins: [
11 | copy({
12 | targets: [{ src: 'src/index.d.ts', dest: 'dist/' }],
13 | }),
14 | ],
15 | extraBabelPlugins: [
16 | [
17 | 'import',
18 | {
19 | libraryName: 'antd',
20 | libraryDirectory: 'es',
21 | style: true,
22 | },
23 | 'antd',
24 | ],
25 | ],
26 | };
27 |
--------------------------------------------------------------------------------
/.dumi/theme/slots/Header/GithubLink.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button, Tooltip } from 'antd';
3 |
4 | import { GithubFilled } from '@ant-design/icons';
5 |
6 | const GithubLink: React.FC = () => {
7 | return (
8 |
9 | }
14 | type="text"
15 | />
16 |
17 | );
18 | };
19 |
20 | export default GithubLink;
21 |
--------------------------------------------------------------------------------
/packages/x-flow/src/hooks/useNodes.ts:
--------------------------------------------------------------------------------
1 | import { shallow } from 'zustand/shallow';
2 |
3 | import { useStore } from '../hooks/useStore';
4 | import type { FlowNode, FlowState } from '../models/store';
5 |
6 | const nodesSelector = (state: FlowState) => state.nodes;
7 |
8 | /**
9 | * Hook for getting the current nodes from the store.
10 | *
11 | * @public
12 | * @returns An array of nodes
13 | */
14 | export function useNodes(): NodeType[] {
15 | const nodes = useStore(nodesSelector, shallow) as NodeType[];
16 |
17 | return nodes;
18 | }
19 |
--------------------------------------------------------------------------------
/docs/form-render/schema/cellSpan.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | type: 'object',
3 | column: 3,
4 | displayType: 'row',
5 | properties: {
6 | input1: {
7 | title: 'Field A',
8 | type: 'string'
9 | },
10 | input2: {
11 | title: 'Field B',
12 | type: 'string'
13 | },
14 | input3: {
15 | title: 'Field C',
16 | type: 'string'
17 | },
18 | input4: {
19 | title: 'Field D',
20 | type: 'string',
21 | cellSpan: 2
22 | },
23 | input5: {
24 | title: 'Field E',
25 | type: 'string'
26 | }
27 | }
28 | };
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/Encryption/index.less:
--------------------------------------------------------------------------------
1 | .encryption-view {
2 | display: inline-flex;
3 | align-items: center;
4 | .line-label {
5 | margin-right: 5px;
6 | }
7 |
8 | .icon-text {
9 | height: 22px;
10 | margin: 0 3px;
11 | color: #3f7ffb;
12 | font-size: 14px;
13 | line-height: 22px;
14 | cursor: pointer;
15 | }
16 |
17 | .line-span {
18 | display: flex;
19 | align-items: center;
20 | margin-right: 5px;
21 | cursor: pointer;
22 | }
23 |
24 | .encry-content {
25 | margin-right: 5px;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/mirror.yml:
--------------------------------------------------------------------------------
1 | # name: 🔀 Sync mirror to Vercel
2 |
3 | # on:
4 | # push:
5 | # branches:
6 | # - master
7 |
8 | # jobs:
9 | # mirror:
10 | # runs-on: ubuntu-latest
11 | # steps:
12 | # - name: mirror actions
13 | # continue-on-error: true
14 | # uses: wearerequired/git-mirror-action@v1
15 | # env:
16 | # SSH_PRIVATE_KEY: ${{ secrets.FORK_PRIVATE_KEY }}
17 | # with:
18 | # source-repo: 'https://github.com/alibaba/x-render.git'
19 | # destination-repo: 'git@github.com:siyi98/x-render.git'
20 |
--------------------------------------------------------------------------------
/packages/table-render/src/core/ToolbarView/InteriorTool/ReloadIcon.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext} from 'react';
2 | import { Tooltip, ConfigProvider } from 'antd';
3 | import { ReloadOutlined } from '@ant-design/icons';
4 | import { translation } from '../../../utils';
5 |
6 | const ReloadIcon = ({ refresh }) => {
7 | const configCtx = useContext(ConfigProvider.ConfigContext);
8 | const t = translation(configCtx);
9 | return (
10 |
11 | refresh()} />
12 |
13 | );
14 | };
15 |
16 | export default ReloadIcon;
17 |
--------------------------------------------------------------------------------
/packages/x-flow/src/hooks/useEdges.ts:
--------------------------------------------------------------------------------
1 | import type { Edge } from "@xyflow/react";
2 | import { shallow } from 'zustand/shallow';
3 |
4 | import { useStore } from './useStore';
5 | import type { FlowState } from '../models/store';
6 |
7 | const nodesSelector = (state: FlowState) => state.edges;
8 |
9 | /**
10 | * Hook for getting the current edges from the store.
11 | *
12 | * @public
13 | * @returns An array of edges
14 | */
15 | export function useEdges(): Edge[] {
16 | const nodes = useStore(nodesSelector, shallow) as EdgeType[];
17 |
18 | return nodes;
19 | }
20 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/color.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, notInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('Color', {
4 | title: '颜色选择',
5 | category: '其他',
6 | props: [
7 | {
8 | title: '基础配置',
9 | type: 'group',
10 | display: 'accordion',
11 | items: notInputPropsBasic
12 | }
13 | ],
14 | snippets: [
15 | {
16 | title: '颜色选择',
17 | screenshot:'icon-color',
18 | schema: {
19 | componentName: 'Color',
20 | props: {
21 | title: '颜色选择',
22 | }
23 | }
24 | }
25 | ]
26 | });
27 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/index.tsx:
--------------------------------------------------------------------------------
1 | import FormCore from './form-core';
2 | import withProvider from './withProvider';
3 |
4 | export * as widgets from './widgets';
5 |
6 | export { default as useForm } from './models/useForm';
7 | export { default as connectForm } from './form-core/connectForm';
8 |
9 | export type {
10 | default as FR,
11 | Schema,
12 | FRProps,
13 | FormInstance,
14 | FormParams,
15 | FieldParams,
16 | WatchProperties,
17 | SchemaType,
18 | SchemaBase,
19 | ValidateParams,
20 | ResetParams,
21 | RuleItem,
22 | } from './type';
23 |
24 | export default withProvider(FormCore);
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/components/DatePicker/index.tsx:
--------------------------------------------------------------------------------
1 | import dayjsGenerateConfig from 'rc-picker/es/generate/dayjs';
2 | import generatePicker from 'antd/es/date-picker/generatePicker';
3 | import 'antd/es/date-picker/style/index';
4 |
5 | // 修复 dayjs 生成配置中缺失的毫秒相关方法
6 | const enhancedDayjsConfig = {
7 | ...dayjsGenerateConfig,
8 | // 添加缺失的毫秒相关方法
9 | getMillisecond: (date: any) => date.millisecond(),
10 | setMillisecond: (date: any, millisecond: number) => date.millisecond(millisecond),
11 | };
12 |
13 | const DatePicker: any = generatePicker(enhancedDayjsConfig);
14 |
15 | export default DatePicker;
16 |
--------------------------------------------------------------------------------
/.github/workflows/coverage.yml:
--------------------------------------------------------------------------------
1 | # name: 💯 Coverage CI
2 |
3 | # on:
4 | # workflow_run:
5 | # workflows: ["🚀 Build CI"]
6 | # types:
7 | # - completed
8 |
9 |
10 | # jobs:
11 | # build:
12 | # runs-on: ubuntu-latest
13 | # strategy:
14 | # matrix:
15 | # node: [ '14', '16' ]
16 | # name: build steps
17 | # steps:
18 | # - uses: actions/checkout@v2
19 | # - name: Use Node.js ${{ matrix.node }}
20 | # uses: actions/setup-node@v2
21 | # with:
22 | # node-version: ${{ matrix.node }}
23 | # - name: Run Test
24 | # - run: yarn run test
25 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/imageInput.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, inputPropsBasic } from '../utils';
2 |
3 | export default createMeta('ImageInput', {
4 | title: '图片 URL',
5 | category: '其他',
6 | props: [
7 | {
8 | title: '基础配置',
9 | type: 'group',
10 | display: 'accordion',
11 | items: inputPropsBasic
12 | },
13 | ],
14 | snippets: [
15 | {
16 | title: '图片 URL',
17 | screenshot: 'icon-image',
18 | schema: {
19 | componentName: 'ImageInput',
20 | props: {
21 | title: '图片 URL',
22 | },
23 | }
24 | }
25 | ]
26 | });
27 |
--------------------------------------------------------------------------------
/docs/schema-builder-online/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar: false
3 | ---
4 |
5 | ```jsx
6 | /**
7 | * transform: true
8 | * compact: true
9 | * inline: true
10 | */
11 | import React from 'react';
12 | import SchemaBuilder from '@xrenders/schema-builder';
13 |
14 | import ReactDOM from 'react-dom';
15 |
16 | // 将 React 和 ReactDOM 绑定到全局作用域中
17 | window.React = React;
18 | window.ReactDOM = ReactDOM;
19 |
20 | const Demo = () => {
21 | return (
22 |
23 |
24 |
25 | );
26 | };
27 |
28 | export default Demo;
29 | ```
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | # name: Deploy CI
2 |
3 | # on:
4 | # push:
5 | # branches:
6 | # - master
7 |
8 | # jobs:
9 | # build-and-deploy:
10 | # runs-on: ubuntu-latest
11 | # name: deploy steps
12 | # steps:
13 | # - uses: actions/checkout@v2
14 | # - name: install
15 | # run: yarn install
16 | # - name: build
17 | # run: yarn doc
18 | # - name: Deploy Action
19 | # uses: peaceiris/actions-gh-pages@v3
20 | # with:
21 | # deploy_key: ${{ secrets.ACTIONS_DEPLOY_TOKEN }}
22 | # publish_dir: ./docs-dist
23 | # force_orphan: true
24 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/utils.ts:
--------------------------------------------------------------------------------
1 | export function getFormat(format) {
2 | switch (format) {
3 | case 'date': return 'YYYY-MM-DD'
4 | case 'year': return 'YYYY';
5 | case 'month': return 'YYYY-MM';
6 | case 'week': return 'YYYY-w';
7 | case 'hour': return 'YYYY-MM-DD hh';
8 | case 'minute': return 'YYYY-MM-DD hh:mm';
9 | case 'second': return 'YYYY-MM-DD hh:mm:ss';
10 | case 'week-day': return 'w-d';
11 | default: return 'YYYY-MM-DD';
12 | }
13 | }
14 |
15 | export const translation = (configCtx) => (key) => {
16 | const locale = configCtx?.locale.FormRender;
17 | return locale[key];
18 | }
19 |
--------------------------------------------------------------------------------
/docs/xflow/demo/log/utils.tsx:
--------------------------------------------------------------------------------
1 | export const delay = ms => new Promise(res => setTimeout(res, ms));
2 |
3 | export const fakeApi = (url, data) => {
4 | console.group('request:', url);
5 | console.log('params:', data);
6 | console.groupEnd();
7 | return delay(500).then(res => ({
8 | success: true,
9 | message: 'Data fetched successfully',
10 | data: {
11 | id: data.id || 'default-id',
12 | name: 'Sample Node',
13 | logs: [
14 | { timestamp: '2023-10-01T10:00:00Z', message: 'Log entry 1' },
15 | { timestamp: '2023-10-01T11:00:00Z', message: 'Log entry 2' },
16 | ],
17 | },
18 | }));
19 | };
20 |
--------------------------------------------------------------------------------
/docs/xflow/demo/log/runNode/utils.tsx:
--------------------------------------------------------------------------------
1 | export const delay = ms => new Promise(res => setTimeout(res, ms));
2 |
3 | export const fakeApi = (url, data) => {
4 | console.group('request:', url);
5 | console.log('params:', data);
6 | console.groupEnd();
7 | return delay(500).then(res => ({
8 | success: true,
9 | message: 'Data fetched successfully',
10 | data: {
11 | id: data.id || 'default-id',
12 | name: 'Sample Node',
13 | logs: [
14 | { timestamp: '2023-10-01T10:00:00Z', message: 'Log entry 1' },
15 | { timestamp: '2023-10-01T11:00:00Z', message: 'Log entry 2' },
16 | ],
17 | },
18 | }));
19 | };
20 |
--------------------------------------------------------------------------------
/docs/xflow/demo/log/buildIn-log/utils.tsx:
--------------------------------------------------------------------------------
1 | export const delay = ms => new Promise(res => setTimeout(res, ms));
2 |
3 | export const fakeApi = (url, data) => {
4 | console.group('request:', url);
5 | console.log('params:', data);
6 | console.groupEnd();
7 | return delay(500).then(res => ({
8 | success: true,
9 | message: 'Data fetched successfully',
10 | data: {
11 | id: data.id || 'default-id',
12 | name: 'Sample Node',
13 | logs: [
14 | { timestamp: '2023-10-01T10:00:00Z', message: 'Log entry 1' },
15 | { timestamp: '2023-10-01T11:00:00Z', message: 'Log entry 2' },
16 | ],
17 | },
18 | }));
19 | };
20 |
--------------------------------------------------------------------------------
/docs/xflow/demo/log/custom-log/utils.tsx:
--------------------------------------------------------------------------------
1 | export const delay = ms => new Promise(res => setTimeout(res, ms));
2 |
3 | export const fakeApi = (url, data) => {
4 | console.group('request:', url);
5 | console.log('params:', data);
6 | console.groupEnd();
7 | return delay(500).then(res => ({
8 | success: true,
9 | message: 'Data fetched successfully',
10 | data: {
11 | id: data.id || 'default-id',
12 | name: 'Sample Node',
13 | logs: [
14 | { timestamp: '2023-10-01T10:00:00Z', message: 'Log entry 1' },
15 | { timestamp: '2023-10-01T11:00:00Z', message: 'Log entry 2' },
16 | ],
17 | },
18 | }));
19 | };
20 |
--------------------------------------------------------------------------------
/packages/chart-render/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | "strict": true,
12 | "paths": {
13 | "@/*": ["src/*"],
14 | "@@/*": ["src/.umi/*"]
15 | },
16 | "allowSyntheticDefaultImports": true
17 | },
18 | "exclude": [
19 | "node_modules",
20 | "lib",
21 | "es",
22 | "dist",
23 | "typings",
24 | "**/__test__",
25 | "test",
26 | "docs",
27 | "tests"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/docs/xflow/demo/log/buildIn-log/CustomGroupTittle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tag } from 'antd';
3 |
4 | const CustomGroupTitle = ({ logData }) => {
5 | return (
6 |
7 |
8 |
9 | {logData?.groupTitle}
10 |
11 | 自定义分组标题
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | export default CustomGroupTitle;
19 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/Collapse/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Collapse } from 'antd-mobile';
3 |
4 | export default ({ schema, addons, renderCore, ...props }) => {
5 | const { items } = schema;
6 |
7 | return (
8 |
9 | {Object.keys(items).map((key: string) => {
10 | const { type, properties, ...other } = items[key];
11 | return (
12 |
13 | {renderCore({ schema: { type, properties }, parentPath: [key] })}
14 |
15 | );
16 | })}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/basic/header.tsx:
--------------------------------------------------------------------------------
1 | import React ,{ FC } from 'react';
2 | import './index.less';
3 |
4 | const Header: FC<{ data: any }> = ({ data }) => {
5 | // const container = (document.getElementById('xflow-container') as HTMLElement);
6 | return (
7 |
8 |
9 |
13 |
14 | XFlow
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default Header;
22 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/demo2/header.tsx:
--------------------------------------------------------------------------------
1 | import React ,{ FC } from 'react';
2 | import './index.less';
3 |
4 | const Header: FC<{ data: any }> = ({ data }) => {
5 | // const container = (document.getElementById('xflow-container') as HTMLElement);
6 | return (
7 |
8 |
9 |
13 |
14 | XFlow
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default Header;
22 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FImage/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Image } from 'antd';
3 | import { combineClass } from '../utils/common';
4 | import './index.less';
5 |
6 | /**
7 | *
8 | * 图片组件
9 | */
10 | export default (props: any) => {
11 | const { data, className, style, images, preview = false, addons, ...imageProps } = props;
12 |
13 | let src = data;
14 | if (images) {
15 | src = images[data] || images.default;
16 | }
17 |
18 | return (
19 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/locales/zh_CN.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "copy_max_tip": "已达表单项数量上限,无法复制!",
3 | "copy": "复制",
4 | "add_item": "新增一条",
5 | "confirm_delete": "确定删除?",
6 | "confirm": "确定",
7 | "cancel": "取消",
8 | "operate": "操作",
9 | "delete": "删除",
10 | "edit": "编辑",
11 | "img_src_error": "图片地址错误",
12 | "upload": "上传",
13 | "upload_success": "上传成功",
14 | "upload_fail": "上传失败",
15 | "uploaded_address": "已上传地址",
16 | "test_src": "测试链接",
17 | "schema_not_match": "schema未匹配到展示组件:",
18 | "item": "项目",
19 | "search": "查询",
20 | "reset": "重置",
21 | "expand": "展开",
22 | "fold": "收起",
23 | "submit": "提交",
24 | "moveDown": "下移",
25 | "moveUp": "上移"
26 | };
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listSimple/index.less:
--------------------------------------------------------------------------------
1 | .fr-list-simple {
2 | display: inline-block;
3 |
4 | .fr-inline-field {
5 | min-width: 220px;
6 | margin-bottom: 24px !important;
7 | }
8 |
9 | .fr-list-item {
10 | display: flex;
11 | align-items: flex-start;
12 | position: relative;
13 | }
14 |
15 | .fr-list-item-operate {
16 | height: 32px;
17 | gap: 0 !important;
18 | }
19 | }
20 |
21 | .fr-list-simple-background {
22 | padding: 24px 24px 0 24px;
23 | background-color: #f6f6f6;
24 | border-radius: 4px;
25 |
26 | .add-btn {
27 | margin-bottom: 24px;
28 | }
29 | }
30 |
31 | .fr-list-simple-column .fr-list-item {
32 | align-items: center;
33 | }
--------------------------------------------------------------------------------
/packages/form-render/src/locales/zh_CN.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "copy_max_tip": "已达表单项数量上限,无法复制!",
3 | "copy": "复制",
4 | "add_item": "新增一条",
5 | "confirm_delete": "确定删除?",
6 | "confirm": "确定",
7 | "cancel": "取消",
8 | "operate": "操作",
9 | "delete": "删除",
10 | "edit": "编辑",
11 | "img_src_error": "图片地址错误",
12 | "upload": "上传",
13 | "upload_success": "上传成功",
14 | "upload_fail": "上传失败",
15 | "uploaded_address": "已上传地址",
16 | "test_src": "测试链接",
17 | "schema_not_match": "schema未匹配到展示组件:",
18 | "item": "项目",
19 | "search": "查询",
20 | "reset": "重置",
21 | "expand": "展开",
22 | "fold": "收起",
23 | "submit": "提交",
24 | "save": "保存",
25 | "moveDown": "下移",
26 | "moveUp": "上移"
27 | };
--------------------------------------------------------------------------------
/packages/x-flow/src/hooks/useTemporalStore.ts:
--------------------------------------------------------------------------------
1 | import StoreContext from '../models/context';
2 | import { useContext } from 'react';
3 |
4 | export const useTemporalStore = () => {
5 | const store = useContext(StoreContext);
6 |
7 | if (store === null) {
8 | throw new Error(
9 | '[XFlow]: Seems like you have not used zustand provider as an ancestor.'
10 | );
11 | }
12 | const temporalStore = store.temporal.getState();
13 | // 默认关闭时间机器
14 | temporalStore.pause();
15 |
16 | return {
17 | ...store.temporal.getState(),
18 | record: (callback: () => void) => {
19 | temporalStore.resume();
20 | callback();
21 | temporalStore.pause();
22 | },
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/packages/table-render/.fatherrc.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | cjs: { type: 'rollup' },
3 | esm: {
4 | type: 'rollup',
5 | importLibToEs: true,
6 | },
7 | extraBabelPlugins: [
8 | [
9 | 'import',
10 | {
11 | libraryName: 'antd',
12 | libraryDirectory: 'es',
13 | style: true,
14 | },
15 | 'antd',
16 | ],
17 | // [
18 | // 'import',
19 | // {
20 | // libraryName: '@ant-design/icons',
21 | // libraryDirectory: 'lib/icons',
22 | // camel2DashComponentName: false,
23 | // },
24 | // '@ant-design/icons',
25 | // ],
26 | // ['transform-remove-console', { exclude: ['error', 'warn'] }],
27 | ],
28 | };
29 |
--------------------------------------------------------------------------------
/tools/schema-builder/README.md:
--------------------------------------------------------------------------------
1 | ## 如何使用
2 |
3 | ### 安装
4 |
5 | ```bash
6 | npm i @xrenders/schema-builder
7 | ```
8 |
9 | ### 代码演示
10 |
11 | ```jsx
12 | /**
13 | * transform: true
14 | * defaultShowCode: true
15 | */
16 | import React from 'react';
17 | import SchemaBuilder from '@xrenders/schema-builder';
18 |
19 | const defaultValue = {
20 | type: 'object',
21 | properties: {
22 | inputName: {
23 | title: '简单输入框',
24 | type: 'string',
25 | },
26 | },
27 | };
28 |
29 | const Demo = () => {
30 | return (
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | export default Demo;
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/core/defineApp.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // This file is generated by Umi automatically
3 | // DO NOT CHANGE IT MANUALLY!
4 | interface IDefaultRuntimeConfig {
5 | onRouteChange?: (props: { routes: any, clientRoutes: any, location: any, action: any, isFirst: boolean }) => void;
6 | patchRoutes?: (props: { routes: any }) => void;
7 | patchClientRoutes?: (props: { routes: any }) => void;
8 | render?: (oldRender: () => void) => void;
9 | rootContainer?: (lastRootContainer: JSX.Element, args?: any) => void;
10 | [key: string]: any;
11 | }
12 | export type RuntimeConfig = IDefaultRuntimeConfig
13 |
14 | export function defineApp(config: RuntimeConfig): RuntimeConfig {
15 | return config;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/table-render/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 更新日志
2 |
3 | ### 2.1.4
4 | -[!] 修复 onSearch 方法缺失
5 |
6 | ### 2.0.18
7 | -[!] 修复 table-render 切换 pageSize 无效
8 | ### 2.0.17
9 | -[!] 修复 table-render 配置 pagesize 查询无效
10 | ### 2.0.16
11 | -[+] 工具栏增加列字段筛选显示
12 |
13 | ### 2.0.13
14 | -[+] 增加 tableWrapper 属性,可以通过 tableWrapper 在搜索栏和表格之间增加一些内容
15 | ### 2.0.9
16 | -[+] Search 增加极简模式 mode='simple'配置,直接通过onChange触发查询事件,并且去除查询按钮
17 | -[+] 增加 autoSize 是否自适应布局
18 |
19 | ### 2.0.8
20 | -[+] valueType 新增 image、tag、tags、progress、dateRange、dateTimeRange 类型
21 | -[+] 支持列头配置气泡 tooltip 提示
22 |
23 | ### 2.0.5
24 | -[!] 修复 DatePicker 组件显示默认是英文提示
25 | ### 2.0.1
26 | -[+] table-render 新版发布上线,props 调整
27 | ### 2.0.0
28 |
29 | - [+] table-render 2.0 正式发版
30 |
--------------------------------------------------------------------------------
/packages/x-flow/src/operator/index.less:
--------------------------------------------------------------------------------
1 | .fai-reactflow-operator {
2 | position: absolute;
3 | left: 4px;
4 | bottom: 14px;
5 | height: 50px;
6 |
7 | .mini-map {
8 | position: absolute;
9 | left: 12px;
10 | bottom: 45px;
11 | margin: 0;
12 | border: 0.5px solid rgba(0, 0, 0, 0.08);
13 | border-radius: 8px;
14 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
15 | z-index: 9;
16 | }
17 |
18 | .operator-section {
19 | display: flex;
20 | align-items: center;
21 | position: absolute;
22 | left: 10px;
23 | bottom: 4px;
24 | z-index: 9;
25 | }
26 | }
27 |
28 |
29 | .icon {
30 | width: 16px;
31 | height: 16px;
32 | color: #666F83;
33 | font-size: 20;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/chart-render/src/components/ChartProvider/index.tsx:
--------------------------------------------------------------------------------
1 | import { ConfigProvider } from 'antd';
2 | import zh_CN from 'antd/lib/locale/zh_CN';
3 | import React, { FC, ReactNode } from 'react';
4 | import { createStore, Provider } from '../../utils/store';
5 |
6 | const ChartProvider: FC<{ children?: ReactNode }> = ({ children }) => (
7 |
8 | {/* @ts-ignore */}
9 | {children}
10 |
11 | );
12 |
13 | // @ts-ignore
14 | const withChart = Component => props => {
15 | return (
16 |
17 |
18 |
19 | );
20 | };
21 |
22 | export { ChartProvider, withChart };
23 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/Card/index.less:
--------------------------------------------------------------------------------
1 | .frm-widget-card {
2 | border-radius: 4px;
3 | margin: 0 12px;
4 |
5 | margin-top: 12px;
6 |
7 | .adm-card-header {
8 | border-bottom: none !important;
9 | }
10 |
11 | .adm-card-body {
12 | padding: 0;
13 | }
14 |
15 | .adm-form-item {
16 | padding-left: 4px;
17 | }
18 |
19 | &-title {
20 | margin-right: 6px;
21 | padding-left: 4px;
22 | }
23 |
24 | &-desc {
25 | font-size: 12px;
26 | word-break: break-all;
27 | color: rgba(0, 0, 0, .45);
28 | }
29 |
30 | &-no-title {
31 | .adm-grid-item:first-of-type {
32 | .adm-list-item-content {
33 | border-top: none;
34 | }
35 | }
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/.fatherrc.js:
--------------------------------------------------------------------------------
1 | import copy from 'rollup-plugin-copy';
2 |
3 | export default {
4 | cjs: 'babel',
5 | esm: {
6 | type: 'babel',
7 | importLibToEs: true,
8 | },
9 | lessInBabelMode: true,
10 | extraBabelPlugins: [
11 | [
12 | 'import',
13 | {
14 | libraryName: 'antd-mobile',
15 | libraryDirectory: 'es/components',
16 | style: false,
17 | },
18 | 'antd-mobile',
19 | ],
20 | // [
21 | // 'import',
22 | // {
23 | // libraryName: '@ant-design/icons',
24 | // libraryDirectory: 'lib/icons',
25 | // camel2DashComponentName: false,
26 | // },
27 | // '@ant-design/icons',
28 | // ],
29 | ],
30 | };
31 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTabs/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tabs } from 'antd';
3 | import { combineClass } from '../utils/common';
4 |
5 | const { TabPane } = Tabs;
6 |
7 | const FTabList: React.FC = (props: any) => {
8 | const { className, style, items = [], data, addons } = props;
9 |
10 | return (
11 |
12 | {items.map((item: any, index: number) => (
13 |
14 | {addons.renderer({ schema: item.children, data, addons })}
15 |
16 | ))}
17 |
18 | );
19 | };
20 |
21 | export default FTabList;
22 |
--------------------------------------------------------------------------------
/packages/form-render/src/models/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore as createx } from 'zustand';
2 |
3 | type FormStore = {
4 | schema?: any;
5 | flattenSchema: any;
6 | context?: any;
7 | initialized: boolean,
8 | init?: (schema: FormStore['schema']) => any;
9 | setContext: (context: any) => any;
10 | };
11 |
12 | // 将 useStore 改为 createStore, 并把它改为 create 方法
13 | export const createStore = () => createx((setState: any, get: any) => ({
14 | initialized: false,
15 | schema: {},
16 | flattenSchema: {},
17 | context: {},
18 | init: data => {
19 | return setState({
20 | initialized: true,
21 | ...data
22 | });
23 | },
24 | setContext: context => {
25 | return setState({ context });
26 | }
27 | }));
--------------------------------------------------------------------------------
/docs/playground/json/format.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "properties": {
5 | "inputName": {
6 | "title": "url输入框",
7 | "type": "string",
8 | "format": "url"
9 | },
10 | "imageName": {
11 | "title": "图片展示",
12 | "type": "string",
13 | "format": "image"
14 | },
15 | "inputName2": {
16 | "title": "email输入框",
17 | "type": "string",
18 | "format": "email"
19 | },
20 | "string": {
21 | "title": "正则校验字符串",
22 | "tooltip": "a-z",
23 | "type": "string",
24 | "rules": [
25 | {
26 | "pattern": "^[a-z]+$"
27 | }
28 | ]
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FLabel/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { combineClass } from '../utils/common';
3 | import FText from '../FText';
4 |
5 | import './index.less';
6 |
7 | const FLabel = (props: any) => {
8 | const { colon = true, label, className, style, labelStyle, contentStyle, ...otherProps } = props;
9 |
10 | return (
11 |
12 |
13 | {label}
14 | {colon && ':'}
15 |
16 |
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default FLabel;
24 |
--------------------------------------------------------------------------------
/packages/form-render/src/form-core/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-hide-label > .@{ant-prefix}-form-item-row > .@{ant-prefix}-form-item-label {
4 | visibility: hidden;
5 | }
6 |
7 | .fr-field {
8 | .@{ant-prefix}-form-item-row {
9 | flex-wrap: nowrap;
10 | }
11 | .@{ant-prefix}-form-item-control-input-content {
12 | display: flex;
13 | }
14 | }
15 |
16 | .fr-field-visibility {
17 | width: 0;
18 | height: 0;
19 | visibility: hidden;
20 | position: absolute;
21 | opacity: 0;
22 | }
23 |
24 | .fr-form {
25 | // 影响宽度样式,暂时注释
26 | // .@{ant-prefix}-form-item-control {
27 | // width: 0;
28 | // }
29 |
30 | .fr-inline-field {
31 | .@{ant-prefix}-form-item-control {
32 | width: auto;
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/docs/xflow/demo/best/basic/index.tsx:
--------------------------------------------------------------------------------
1 | import XFlow from '@xrenders/xflow';
2 | import { settings } from './setting';
3 | import { nodes,edges } from './const';
4 | import React from 'react';
5 | import './index.less';
6 | import showSwitchNode from './showSwitchNode';
7 | import Header from './header';
8 | import { Tools } from './tools';
9 |
10 | export default () => {
11 | return (
12 |
13 | {/* */}
14 |
22 |
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/packages/form-render/src/render-core/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-inline-field {
4 | display: inline-block;
5 | margin-right: 16px;
6 | }
7 |
8 | .fr-inline-container {
9 | display: inline-flex;
10 | flex-wrap: wrap;
11 | }
12 |
13 | .ant-form-item-optional-hide {
14 | padding: 0 8px;
15 |
16 | .@{ant-prefix}-form-item-label > label {
17 | font-size: 16px;
18 | font-weight: #000000d9;
19 | font-weight: 600;
20 | }
21 |
22 | }
23 |
24 | .fr-desc {
25 | word-break: break-all;
26 | color: rgba(0, 0, 0, .45);
27 | line-height: 22px;
28 | margin-left: 5px;
29 | font-weight: normal;
30 | font-size: 14px;
31 | }
32 |
33 | .fr-item-actions {
34 | margin-left: 12px;
35 | display: inline-flex;
36 | align-items: center;
37 | }
--------------------------------------------------------------------------------
/docs/form-render/demo/widget/label-widget.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Form, { useForm } from 'form-render';
3 |
4 | const schema = {
5 | type: 'object',
6 | properties: {
7 | string: {
8 | title: '自定义 label',
9 | type: 'string',
10 | labelWidget: 'MyLabel',
11 | },
12 | },
13 | };
14 |
15 | const MyLabel = (props) => {
16 | const { schema } = props;
17 | console.log('props:', props)
18 | return (
19 | {schema.title}
20 | )
21 | }
22 |
23 | const Demo = () => {
24 | const form = useForm();
25 | return (
26 |
31 | );
32 | };
33 |
34 | export default Demo;
35 |
--------------------------------------------------------------------------------
/docs/form-render/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | toc: content
4 | mobile: false
5 | group:
6 | title: 其他
7 | order: 5
8 | ---
9 |
10 |
11 |
12 |
16 | # 常见问题
17 |
18 | ##### 1. 只读模式下,默认的渲染不能满足要求我想定制怎么办?
19 |
20 | 参见[只读模式下的自定义组件](/form-render/advanced-widget#只读模式下的自定义组件)
21 |
22 | ##### 2. 我试着使用 form.setValues, 但是被 set 的值还是空的?
23 |
24 | form-render 有生命周期的概念,请在 onMount 这个钩子里 set。
25 |
26 | ##### 3. type 为 object 类型自定义组件没有接收到 value 与 onChange 属性
27 |
28 | 例如下面这种 Schema 结构的自定义组件,2.x 会判定它是容器组件并非表单控件,那如何解决这种误判呢?增加一个 widgetType: 'field'
29 | ```js
30 | {
31 | type: "object",
32 | widget: "WidgetObj",
33 | properties: {
34 | name: {
35 | title: "name",
36 | type: "string",
37 | }
38 | }
39 | }
40 | ```
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/date.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, getInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('DatePicker', {
4 | title: '日期选择',
5 | props: [
6 | {
7 | title: '基础配置',
8 | type: 'group',
9 | display: 'accordion',
10 | items: getInputPropsBasic({
11 | name: 'defaultValue',
12 | title: { label: '默认值', tip: 'defaultValue | 默认值'},
13 | setter: 'CustomDateSetter'
14 | })
15 | },
16 | ],
17 | snippets: [
18 | {
19 | title: '日期选择',
20 | screenshot: 'icon-date',
21 | schema: {
22 | componentName: 'DatePicker',
23 | props: {
24 | title: '日期选择',
25 | type: 'string'
26 | }
27 | }
28 | }
29 | ]
30 | });
--------------------------------------------------------------------------------
/packages/data-render/src/models/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore as createx } from 'zustand';
2 |
3 | type FormStore = {
4 | schema?: any;
5 | flattenSchema: any;
6 | context?: any;
7 | initialized: boolean;
8 | init?: (schema: FormStore['schema']) => any;
9 | setContext: (context: any) => any;
10 | };
11 |
12 | // 将 useStore 改为 createStore, 并把它改为 create 方法
13 | export const createStore = () =>
14 | createx((setState: any, get: any) => ({
15 | initialized: false,
16 | schema: {},
17 | flattenSchema: {},
18 | context: {},
19 | init: (data) => {
20 | return setState({
21 | initialized: true,
22 | ...data,
23 | });
24 | },
25 | setContext: (context) => {
26 | return setState({ context });
27 | },
28 | }));
29 |
--------------------------------------------------------------------------------
/docs/playground/json/select.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "properties": {
5 | "select": {
6 | "title": "带搜索的单选框",
7 | "type": "string",
8 | "enum": ["a", "b", "c"],
9 | "enumNames": ["jack", "steve", "david"],
10 | "widget": "select",
11 | "props": {
12 | "filterOption": true,
13 | "showSearch": true,
14 | "optionFilterProp": "label"
15 | }
16 | },
17 | "multiSelect": {
18 | "title": "标签模式",
19 | "description": "除了可选的标签,还可输入自定义的标签",
20 | "type": "array",
21 | "enum": ["旅行达人", "工作狂", "老司机", "小资"],
22 | "widget": "select",
23 | "props": {
24 | "mode": "tags"
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/table-render/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2015",
4 | "module": "ES2015",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | // "strict": true,
12 | "declaration": true,
13 | "paths": {
14 | "@/*": ["src/*"],
15 | "@@/*": ["src/.umi/*"]
16 | },
17 | "allowJs": true,
18 | "allowSyntheticDefaultImports": true,
19 | "noImplicitAny": false,
20 | "resolveJsonModule": true
21 | },
22 | "exclude": [
23 | "node_modules",
24 | "lib",
25 | "es",
26 | "dist",
27 | "typings",
28 | "**/__test__",
29 | "test",
30 | "tests",
31 | "docs"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/time.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, getInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('TimePicker', {
4 | title: '时间选择',
5 | props: [
6 | {
7 | title: '基础配置',
8 | type: 'group',
9 | display: 'accordion',
10 | items: getInputPropsBasic({
11 | name: 'defaultValue',
12 | title: { label: '默认值', tip: 'default | 默认值'},
13 | setter: 'CustomTimeSetter'
14 | })
15 | }
16 | ],
17 | snippets: [
18 | {
19 | title: '时间选择',
20 | screenshot: 'icon-time',
21 | schema: {
22 | componentName: 'TimePicker',
23 | props: {
24 | title: '时间选择',
25 | type: 'string',
26 | format: 'time'
27 | }
28 | }
29 | }
30 | ]
31 | });
--------------------------------------------------------------------------------
/docs/form-render/demo/widget/desc-widget.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Form, { useForm } from 'form-render';
3 |
4 | const schema = {
5 | type: 'object',
6 | properties: {
7 | string: {
8 | title: '自定义 desc',
9 | type: 'string',
10 | descWidget: 'MyDesc',
11 | description: '这是一段描述',
12 | },
13 | },
14 | };
15 |
16 | const MyDesc = (props) => {
17 | const { schema } = props;
18 | console.log('props:', props)
19 | return (
20 | {schema.description}
21 | )
22 | }
23 |
24 | const Demo = () => {
25 | const form = useForm();
26 | return (
27 |
32 | );
33 | };
34 |
35 | export default Demo;
36 |
--------------------------------------------------------------------------------
/tools/schema-builder/.fatherrc.js:
--------------------------------------------------------------------------------
1 | import copy from 'rollup-plugin-copy';
2 |
3 | export default {
4 | cjs: 'babel',
5 | esm: {
6 | type: 'babel',
7 | importLibToEs: true,
8 | },
9 | lessInBabelMode: true,
10 | extraRollupPlugins: [
11 | copy({
12 | targets: [{ src: 'src/index.d.ts', dest: 'dist/' }],
13 | }),
14 | ],
15 | extraBabelPlugins: [
16 | [
17 | 'import',
18 | {
19 | libraryName: 'antd',
20 | libraryDirectory: 'es',
21 | style: true,
22 | },
23 | 'antd',
24 | ],
25 | [
26 | 'import',
27 | {
28 | libraryName: '@ant-design/icons',
29 | libraryDirectory: 'lib/icons',
30 | camel2DashComponentName: false,
31 | },
32 | '@ant-design/icons'
33 | ]
34 | ]
35 | };
36 |
--------------------------------------------------------------------------------
/docs/form-render/schema/span.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | type: 'object',
3 | displayType: 'row',
4 | properties: {
5 | input1: {
6 | title: 'Field A',
7 | type: 'string',
8 | span: 8
9 | },
10 | input2: {
11 | title: 'Field B',
12 | type: 'string',
13 | span: 8
14 | },
15 | input3: {
16 | title: 'Field C',
17 | type: 'string',
18 | span: 8
19 | },
20 | input11: {
21 | title: 'Field A',
22 | type: 'string',
23 | span: 8
24 | },
25 | input12: {
26 | title: 'Field B',
27 | type: 'string',
28 | span: 8
29 | },
30 | input4: {
31 | title: 'Field D',
32 | type: 'string',
33 | },
34 | input5: {
35 | title: 'Field E',
36 | type: 'string'
37 | }
38 | }
39 | };
--------------------------------------------------------------------------------
/packages/form-render/.fatherrc.js:
--------------------------------------------------------------------------------
1 | import copy from 'rollup-plugin-copy';
2 |
3 | export default {
4 | cjs: 'babel',
5 | esm: {
6 | type: 'babel',
7 | importLibToEs: true,
8 | },
9 | lessInBabelMode: true,
10 | extraRollupPlugins: [
11 | copy({
12 | targets: [{ src: 'src/index.d.ts', dest: 'dist/' }],
13 | }),
14 | ],
15 | extraBabelPlugins: [
16 | [
17 | 'import',
18 | {
19 | libraryName: 'antd',
20 | libraryDirectory: 'es',
21 | style: true,
22 | },
23 | 'antd',
24 | ],
25 | [
26 | 'import',
27 | {
28 | libraryName: '@ant-design/icons',
29 | libraryDirectory: 'lib/icons',
30 | camel2DashComponentName: false,
31 | },
32 | '@ant-design/icons',
33 | ],
34 | ],
35 | };
36 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/checkbox.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, getNotInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('Checkbox', {
4 | title: '是否选择',
5 | priority: 994,
6 | props: [
7 | {
8 | title: '基础配置',
9 | type: 'group',
10 | display: 'accordion',
11 | items: getNotInputPropsBasic({
12 | name: 'defaultValue',
13 | title: { label: '默认值', tip: 'defaultValue | 默认值'},
14 | setter: 'BoolSetter'
15 | })
16 | },
17 | ],
18 | snippets: [
19 | {
20 | title: '是否选择',
21 | screenshot:'icon-isNot',
22 | schema: {
23 | componentName: 'Checkbox',
24 | props: {
25 | title: '是否选择',
26 | type: 'boolean'
27 | },
28 | }
29 | }
30 | ],
31 |
32 | });
33 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/ReactNode/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import InnerHtml from '../InnerHtml';
3 |
4 | const ReactNode = (props: any) => {
5 | const { schema, data, addons } = props;
6 |
7 | if (!schema) {
8 | return null;
9 | }
10 |
11 | // 当 data 为字符串时,直接返回
12 | if (typeof schema === 'string') {
13 | // 直接返回
14 | if (!schema.includes('method:')) {
15 | return ;
16 | }
17 |
18 | // 如果字符串中包含 render: 则调用 render 方法进行渲染
19 | const [_, funcName] = schema.split('method:');
20 | const renderFunc = addons.getMethod(funcName);
21 | return renderFunc(data);
22 | }
23 |
24 | // 当 data 为对象时,则调用 FRender 组件进行渲染
25 | return addons.renderer({ schema, data, addons });
26 | };
27 |
28 | export default ReactNode;
29 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/boxcard/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Card } from 'antd';
3 | import BoxPanel from '../components/PanelView';
4 |
5 | import './index.less';
6 |
7 | const BoxCard = ({ children, title, description }) => {
8 | if (!title) {
9 | return (
10 |
11 | {children}
12 |
13 | )
14 | }
15 | return (
16 |
20 | {title}
21 | {description && (
22 |
23 | {description}
24 |
25 | )}
26 | >
27 | }
28 | // hoverable={true}
29 | >
30 | {children}
31 |
32 | );
33 | }
34 |
35 | export default BoxCard;
36 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/type.ts:
--------------------------------------------------------------------------------
1 | interface TProperties {
2 | [key: string]: any;
3 | }
4 |
5 | interface TLogo {
6 | title?: string;
7 | image?: string;
8 | href?: string;
9 | }
10 |
11 | interface TSchema {
12 | "type": "object",
13 | "properties": TProperties
14 | }
15 |
16 | interface TToolBtn {
17 | text: string;
18 | order: number;
19 | onClick: (schema: TSchema) => void;
20 | }
21 |
22 | export interface TSchemaBuilder {
23 | logo?: TLogo;
24 | importBtn?: boolean;
25 | exportBtn?: boolean;
26 | clearBtn?: boolean | TToolBtn;
27 | saveBtn?: boolean | TToolBtn;
28 | pubBtn?: boolean | TToolBtn;
29 | extraBtns?: TToolBtn[];
30 | defaultValue?: TSchema;
31 | widgets?: any;
32 | settings?: any;
33 | editorWidgets?: any;
34 | onMount?: () => void;
35 | [key: string]: any
36 | }
--------------------------------------------------------------------------------
/packages/chart-render/src/components/Search/index.less:
--------------------------------------------------------------------------------
1 | .ant-card-extra > .cr-search {
2 | display: flex;
3 | align-items: center;
4 | margin: -16px 0;
5 |
6 | > .cr-search-button {
7 | display: inline-block;
8 | margin-left: 12px;
9 | }
10 |
11 | > .fr-container {
12 | .fr-item-wrapper {
13 | > div > div {
14 | flex-direction: row;
15 | flex-wrap: nowrap;
16 | gap: 12px;
17 | > .fr-field {
18 | width: auto;
19 | }
20 | }
21 | }
22 | .fr-label {
23 | width: auto !important;
24 | }
25 | .error-message,
26 | .field-block {
27 | position: absolute;
28 | top: 100%;
29 | }
30 | }
31 | }
32 |
33 | .cr-search-hidden {
34 | display: none;
35 | }
36 |
37 | .cr-search-button {
38 | display: none;
39 | }
40 |
--------------------------------------------------------------------------------
/docs/table-render/noSearch.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 3
3 | mobile: false
4 | group:
5 | title: 最佳展示
6 | order: 2
7 | ---
8 |
9 |
10 | # 无搜索栏
11 |
12 | ```jsx
13 | /**
14 | * transform: true
15 | * defaultShowCode: true
16 | * background: 'rgb(245,245,245)'
17 | */
18 | import React, { useRef } from 'react';
19 | import TableRender from 'table-render';
20 |
21 | import { schema } from './static/search';
22 | import { columns, toolbarRender } from './static/table';
23 | import { searchApi, searchApi2 } from './static/request';
24 |
25 | const Demo = () => {
26 | const tableRef = useRef();
27 |
28 | return (
29 |
35 | )
36 | };
37 |
38 | export default Demo;
39 | ```
40 |
--------------------------------------------------------------------------------
/packages/form-render/src/derivative/SearchForm/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-search {
4 | width: 100%;
5 | background: #fff;
6 | padding: 24px 24px 0 16px;
7 | margin-bottom: 16px;
8 | box-sizing: border-box;
9 | position: relative;
10 |
11 | .search-action-col {
12 | flex: 1;
13 | display: flex;
14 | justify-content: flex-end;
15 | align-items: baseline;
16 | height: 56px;
17 | }
18 |
19 | .search-action-fixed {
20 | position: absolute;
21 | right: 0;
22 | bottom: 0;
23 | background-color: #fff;
24 | padding-right: 24px !important;
25 | }
26 |
27 | .search-action-column {
28 | height: auto;
29 | }
30 |
31 | .fr-form > .@{ant-prefix}-row {
32 | align-items: center;
33 | }
34 | }
35 |
36 | .fr-column-search {
37 | padding-left: 24px;
38 | }
39 |
--------------------------------------------------------------------------------
/packages/x-flow/src/operator/ZoomInOut/shortcuts-name.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from 'react'
2 | import { getKeyboardKeyNameBySystem } from '../../utils'
3 | import cn from 'classnames'
4 |
5 | type ShortcutsNameProps = {
6 | keys: string[]
7 | className?: string
8 | }
9 | const ShortcutsName = ({
10 | keys,
11 | className,
12 | }: ShortcutsNameProps) => {
13 | return (
14 |
18 | {
19 | keys.map(key => (
20 |
24 | {getKeyboardKeyNameBySystem(key)}
25 |
26 | ))
27 | }
28 |
29 | )
30 | }
31 |
32 | export default memo(ShortcutsName)
33 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FPanel/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { combineClass } from '../utils/common';
3 | import FTitle from '../FTitle';
4 |
5 | import './index.less';
6 |
7 | const FPanel = (props: any) => {
8 | const {
9 | className,
10 | style,
11 | data,
12 | addons,
13 |
14 | title,
15 | titleStyle,
16 | titleShowIcon,
17 | childSchema,
18 | render,
19 | } = props;
20 |
21 | return (
22 |
23 | {title && }
24 | {render
25 | ? addons.getMethod(render)(data, props)
26 | : addons.renderer({ schema: childSchema, data, addons })}
27 |
28 | );
29 | };
30 |
31 | export default FPanel;
32 |
--------------------------------------------------------------------------------
/packages/form-render/src/models/sortProperties.ts:
--------------------------------------------------------------------------------
1 | export default (properties, orderKey = 'order') => {
2 | const orderHash = new Map();
3 | // order不为数字的数据
4 | const unsortedList: any[] = [];
5 | const insert = (item: any) => {
6 | const [, value] = item;
7 | if (typeof value[orderKey] !== 'number') {
8 | unsortedList.push(item);
9 | return;
10 | }
11 | if (orderHash.has(value[orderKey])) {
12 | orderHash.get(value[orderKey]).push(item);
13 | } else {
14 | orderHash.set(value[orderKey], [item]);
15 | }
16 | };
17 |
18 | properties.forEach(item => insert(item));
19 | const sortedList = Array.from(orderHash.entries())
20 | .sort(([order1], [order2]) => order1 - order2) // order值越小越靠前
21 | .flatMap(([, items]) => items);
22 | return sortedList.concat(unsortedList);
23 | }
--------------------------------------------------------------------------------
/packages/data-render/.fatherrc.js:
--------------------------------------------------------------------------------
1 | import copy from 'rollup-plugin-copy';
2 |
3 | export default {
4 | cjs: 'babel',
5 | esm: {
6 | type: 'babel',
7 | importLibToEs: true,
8 | },
9 | lessInBabelMode: true,
10 | extraRollupPlugins: [
11 | copy({
12 | targets: [{ src: 'src/index.d.ts', dest: 'dist/' }],
13 | }),
14 | ],
15 | extraBabelPlugins: [
16 | [
17 | 'import',
18 | {
19 | libraryName: 'antd',
20 | libraryDirectory: 'es',
21 | style: true,
22 | },
23 | 'antd',
24 | ],
25 | // [
26 | // 'import',
27 | // {
28 | // libraryName: '@ant-design/icons',
29 | // libraryDirectory: 'lib/icons',
30 | // camel2DashComponentName: false,
31 | // },
32 | // '@ant-design/icons',
33 | // ],
34 | ],
35 | };
36 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/boxLineTitle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import HeaderTitle from '../components/HeaderTitle';
3 | import PanelView from '../components/PanelView';
4 | import './index.less';
5 |
6 | const FLineTitle = ({ children, title, description }) => {
7 |
8 | if (!title) {
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | }
15 |
16 | return (
17 |
18 |
19 | {title}
20 | {description && {description} }
21 |
22 |
23 | {children}
24 |
25 |
26 | );
27 | }
28 |
29 | export default FLineTitle
30 |
--------------------------------------------------------------------------------
/packages/form-render/__tests__/core-utils.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, it, expect } from 'vitest';
2 | import { flattenSchema } from '../src/form-render-core/src/utils';
3 |
4 | describe('Test FormRender Utils', () => {
5 | it('Test flattenSchema', () => {
6 | const schema = {
7 | type: 'object',
8 | properties: {
9 | input1: {
10 | title: '简单输入框',
11 | type: 'string',
12 | order: 2,
13 | required: true,
14 | },
15 | select1: {
16 | title: '单选',
17 | type: 'string',
18 | order: 1,
19 | enum: ['a', 'b', 'c'],
20 | enumNames: ['早', '中', '晚'],
21 | },
22 | },
23 | };
24 |
25 | const _schema = flattenSchema(schema);
26 | expect(Object.keys(_schema)).toEqual(['select1', 'input1', '#']);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/upload/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-upload-mod,
4 | .fr-upload-file {
5 | display: flex;
6 | }
7 | .fr-upload-mod {
8 | align-items: center;
9 | }
10 | .fr-upload-mod .fr-upload-preview {
11 | margin: 0 12px;
12 | }
13 | .fr-upload-file .@{ant-prefix}-upload-list-item {
14 | margin: 5px 0 0 8px;
15 | }
16 | .fr-upload-file .@{ant-prefix}-upload-list-item-name {
17 | margin-right: 6px;
18 | }
19 | .fr-upload-file .@{ant-prefix}-upload-list-item-info {
20 | cursor: pointer;
21 | }
22 | .fr-upload-file .next-upload-list-text .next-upload-list-item-done,
23 | .fr-upload-file .next-upload-list-text .next-upload-list-item .next-icon {
24 | height: 28px;
25 | line-height: 28px;
26 | margin-left: 12px;
27 | }
28 |
29 | .fr-upload-file .next-upload-list-item-name-wrap {
30 | margin-top: -4px;
31 | }
--------------------------------------------------------------------------------
/packages/chart-render/src/utils/store.ts:
--------------------------------------------------------------------------------
1 | import { FormInstance } from 'formRenderV1';
2 | import create, { StoreApi } from 'zustand';
3 | import createContext from 'zustand/context';
4 | import { DataSource } from './type';
5 | export interface IStore {
6 | /** 修改全局状态的工具函数 */
7 | readonly setChart: (store: Partial) => void;
8 |
9 | /** FormRender 实例 */
10 | readonly form?: FormInstance;
11 |
12 | /** 是否在加载中 */
13 | loading: boolean;
14 |
15 | /** 数据,提供给图表组件进行渲染的 */
16 | dataSource: DataSource;
17 |
18 | /** 重新请求数据的方法 */
19 | refresh?: () => void;
20 | }
21 |
22 | export const { Provider, useStore: useChart } =
23 | createContext>();
24 |
25 | export const createStore = () =>
26 | create(setChart => ({
27 | setChart,
28 | loading: false,
29 | dataSource: { meta: [], data: [] },
30 | }));
31 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/CopyLabel/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import IconLabel from '../IconLabel';
4 | import { clipboardCopy } from '../../utils/common';
5 | import './index.less';
6 |
7 | const CopyLabel = (props: any) => {
8 | const { onClick, style, data, fontSize = 22, color = '#1677FF' } = props;
9 |
10 | const handleClick = (ev: any) => {
11 | if (onClick) {
12 | onClick(ev);
13 | return;
14 | }
15 | clipboardCopy(data);
16 | ev.stopPropagation();
17 | };
18 |
19 | if (!data) {
20 | return null;
21 | }
22 |
23 | return (
24 |
32 | );
33 | };
34 |
35 | export default CopyLabel;
36 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/time/index.tsx:
--------------------------------------------------------------------------------
1 | import dayjs from 'dayjs';
2 | import React from 'react';
3 |
4 | import TimePicker from '../../components/TimePicker';
5 | import { getFormat } from '../../utils';
6 | import withFieldWrap from '../../utils/withFieldWrap';
7 |
8 | const Time = ({ onChange, format ='time', value, style, ...rest }) => {
9 | const timeFormat = getFormat(format);
10 | const _value = value ? dayjs(value, timeFormat) : undefined;
11 |
12 | const handleChange = (_: any, valueStr: string) => {
13 | onChange(valueStr);
14 | };
15 |
16 | const timeParams: any = {
17 | value: _value,
18 | style: { width: '100%', ...style },
19 | onChange: handleChange,
20 | format: timeFormat,
21 | ...rest,
22 | };
23 |
24 | return ;
25 | };
26 | export default withFieldWrap(Time);
--------------------------------------------------------------------------------
/packages/table-render/src/core/index.less:
--------------------------------------------------------------------------------
1 | .tr-table-wrapper {
2 | background: #fff;
3 | padding: 0 24px 24px;
4 | width: 100%;
5 | overflow: auto;
6 | box-sizing: border-box;
7 | }
8 |
9 | .tr-action-list {
10 | display: flex;
11 | justify-content: center;
12 | }
13 |
14 | .tr-single-tab {
15 | color: rgba(0, 0, 0, 0.85);
16 | font-size: 16px;
17 | font-weight: 500;
18 | line-height: 24px;
19 | opacity: 0.85;
20 | }
21 |
22 | .tr-extra-tab {
23 | display: inline-block;
24 | margin-left: 16px;
25 | }
26 |
27 | .tr-search-btn.fr-field {
28 | padding-right: 0;
29 | }
30 |
31 | .mb2 {
32 | margin-bottom: 0.5rem;
33 | }
34 |
35 | .mr {
36 | margin-right: 8px;
37 | }
38 |
39 | .flex {
40 | display: flex;
41 | }
42 |
43 | .justify-end {
44 | justify-content: flex-end;
45 | }
46 |
47 | .w-100 {
48 | width: 100%;
49 | }
50 |
--------------------------------------------------------------------------------
/docs/form-render/demo/form-slim/basic.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * transform: true
3 | * defaultShowCode: true
4 | */
5 | import React from 'react';
6 | import { FormSlimRender, useForm, Input, Select } from 'form-render';
7 |
8 | const schema = {
9 | type: 'object',
10 | displayType: 'row',
11 | properties: {
12 | input1: {
13 | title: '输入框',
14 | type: 'string',
15 | props: {},
16 | },
17 | select1: {
18 | title: '单选',
19 | type: 'string',
20 | props: {
21 | options: [
22 | { label: '早', value: 'a' },
23 | { label: '中', value: 'b' },
24 | { label: '晚', value: 'c' }
25 | ]
26 | }
27 | }
28 | }
29 | };
30 |
31 | export default () => {
32 | const form = useForm();
33 |
34 | return ;
35 | };
36 |
--------------------------------------------------------------------------------
/docs/xflow/demo/switchNode/customSwitchNode/index.tsx:
--------------------------------------------------------------------------------
1 | import XFlow from '@xrenders/xflow';
2 | import settings from './setting';
3 | import React from 'react';
4 |
5 | const customWidget = ({ data, index }) => {
6 | return {data?.value}-{index}
;
7 | };
8 |
9 | export default () => {
10 | const nodes = [
11 | {
12 | type: 'Switch',
13 | id: '2',
14 | position: { x: 171.25, y: 218.75 },
15 | data: { list:[{value:"条件1"}]}
16 | },
17 | ];
18 |
19 | const edges = [];
20 |
21 | return (
22 |
23 |
31 |
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/packages/x-flow/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # 如何贡献代码
2 |
3 | 欢迎给 XFlow 提优化建议,或者修复已有 Bug,共促其发展
4 |
5 | ## Branch 管理
6 |
7 | ```
8 | master
9 | ↑
10 | dev <--- Develop/PR
11 | ```
12 |
13 | - `dev` 分支
14 | - 所有的开发均在 dev 分支进行
15 | - 提 PR 时候请提交到 dev 分支
16 | - `master` 分支
17 | - `master` 是稳定不改的分支,不会在上面进行代码开发
18 | - 在 dev 分支 publish 后会 merge 到 master,同时打对应 tag
19 |
20 | ## Commit 格式
21 |
22 | ```
23 | [{action}] {description}
24 | ```
25 |
26 | - `{action}`
27 | - `+` 新增功能
28 | - `!` 更新或者修复 bug
29 | - `-` 移除功能
30 | - `{description}`
31 | - 尽可能详细的描述就好
32 |
33 | for example:
34 |
35 | - [+] 列表选项新增拖拽功能
36 | - [!] 修复输入框长按闪烁的问题
37 |
38 | ## 更多
39 |
40 | - 很推荐在提交 PR 前,先在钉钉群里进行讨论,已防止此功能已经有同学在开发了
41 | - 但是如果是想修复文档和明显代码错误,直接提交 PR 就好
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/x-flow/src/nodes/index.less:
--------------------------------------------------------------------------------
1 | .node-container {
2 | border: 2px solid #fff;
3 | border-radius: 14px;
4 |
5 | .react-flow__edge-path,
6 | .react-flow__connection-path {
7 | stroke: #d0d5dc;
8 | stroke-width: 2px;
9 | }
10 | }
11 |
12 | .node-container-selected {
13 | border: 2px solid #296dff;
14 |
15 | .react-flow__handle::after {
16 | display: none;
17 | }
18 | }
19 |
20 | .react-flow__handle {
21 | width: 32px;
22 | height: 32px;
23 | background: transparent;
24 | border-radius: 0;
25 | border: none;
26 |
27 | :hover {
28 | border: 2px solid #00a952;
29 | transform: scale(1.25);
30 | }
31 | }
32 |
33 | .react-flow__handle::after {
34 | content: '';
35 | --tw-bg-opacity: 1;
36 | background-color: #2970ff;
37 | width: 8px;
38 | height: 2px;
39 | display: block;
40 | margin: 15px 0 0 12px;
41 | }
--------------------------------------------------------------------------------
/packages/form-render/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # 如何贡献代码
2 |
3 | 欢迎给 FormRender 提优化建议,或者修复已有 Bug,共促其发展
4 |
5 | ## Branch 管理
6 |
7 | ```
8 | master
9 | ↑
10 | dev <--- Develop/PR
11 | ```
12 |
13 | - `dev` 分支
14 | - 所有的开发均在 dev 分支进行
15 | - 提 PR 时候请提交到 dev 分支
16 | - `master` 分支
17 | - `master` 是稳定不改的分支,不会在上面进行代码开发
18 | - 在 dev 分支 publish 后会 merge 到 master,同时打对应 tag
19 |
20 | ## Commit 格式
21 |
22 | ```
23 | [{action}] {description}
24 | ```
25 |
26 | - `{action}`
27 | - `+` 新增功能
28 | - `!` 更新或者修复 bug
29 | - `-` 移除功能
30 | - `{description}`
31 | - 尽可能详细的描述就好
32 |
33 | for example:
34 |
35 | - [+] 列表选项新增拖拽功能
36 | - [!] 修复输入框长按闪烁的问题
37 |
38 | ## 更多
39 |
40 | - 很推荐在提交 PR 前,先在钉钉群里进行讨论,已防止此功能已经有同学在开发了
41 | - 但是如果是想修复文档和明显代码错误,直接提交 PR 就好
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTitle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Typography } from 'antd';
3 | import { combineClass } from '../utils/common';
4 | import './index.less';
5 |
6 | const { Title } = Typography;
7 |
8 | const FTitle = (props: any) => {
9 | const { className, style, data, level = 6, showType, addons, ...otherProps } = props;
10 |
11 | let { color, fontSize, ...otherStyle } = style || {};
12 | if (!fontSize && level === 6) {
13 | fontSize = '14px';
14 | }
15 |
16 | return (
17 |
18 | {showType === 1 && }
19 |
20 | {data}
21 |
22 |
23 | );
24 | };
25 |
26 | export default FTitle;
27 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # 如何贡献代码
2 |
3 | 欢迎给 FormRender 提优化建议,或者修复已有 Bug,共促其发展
4 |
5 | ## Branch 管理
6 |
7 | ```
8 | master
9 | ↑
10 | dev <--- Develop/PR
11 | ```
12 |
13 | - `dev` 分支
14 | - 所有的开发均在 dev 分支进行
15 | - 提 PR 时候请提交到 dev 分支
16 | - `master` 分支
17 | - `master` 是稳定不改的分支,不会在上面进行代码开发
18 | - 在 dev 分支 publish 后会 merge 到 master,同时打对应 tag
19 |
20 | ## Commit 格式
21 |
22 | ```
23 | [{action}] {description}
24 | ```
25 |
26 | - `{action}`
27 | - `+` 新增功能
28 | - `!` 更新或者修复 bug
29 | - `-` 移除功能
30 | - `{description}`
31 | - 尽可能详细的描述就好
32 |
33 | for example:
34 |
35 | - [+] 列表选项新增拖拽功能
36 | - [!] 修复输入框长按闪烁的问题
37 |
38 | ## 更多
39 |
40 | - 很推荐在提交 PR 前,先在钉钉群里进行讨论,已防止此功能已经有同学在开发了
41 | - 但是如果是想修复文档和明显代码错误,直接提交 PR 就好
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/table-render/src/core/TableView/copy.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { message, Typography, ConfigProvider } from 'antd';
3 | import { translation } from '../../utils';
4 |
5 | const Copy = ({ item, text }) => {
6 | const configCtx = useContext(ConfigProvider.ConfigContext);
7 | const t = translation(configCtx);
8 |
9 | return (
10 | message.success(t('copy_success')),
21 | }
22 | : undefined
23 | }
24 | ellipsis={item.ellipsis || false}
25 | >
26 | {text}
27 |
28 | );
29 | };
30 |
31 | export default Copy;
32 |
--------------------------------------------------------------------------------
/packages/form-render/src/index.ts:
--------------------------------------------------------------------------------
1 | import FormCore from './form-core';
2 | import withProvider from './withProvider';
3 | import * as defaultWidgets from './widgets';
4 |
5 | export * from './widgets';
6 | export { mapping } from './models/mapping';
7 |
8 | export { default as useForm } from './models/useForm';
9 | export { default as connectForm } from './form-core/connectForm';
10 | export { default as SearchForm } from './derivative/SearchForm';
11 | export { default as FormSlimRender } from './derivative/SlimRender';
12 |
13 | export type {
14 | default as FR,
15 | Schema,
16 | FRProps,
17 | FormInstance,
18 | FormParams,
19 | FieldParams,
20 | WatchProperties,
21 | SchemaType,
22 | SchemaBase,
23 | ValidateParams,
24 | ResetParams,
25 | RuleItem,
26 | WidgetProps,
27 | } from './type';
28 |
29 | export default withProvider(FormCore, defaultWidgets);
30 |
--------------------------------------------------------------------------------
/docs/xflow/demo/basic/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import XFlow from '@xrenders/xflow';
3 | import settings from './setting';
4 |
5 | export default () => {
6 | const nodes = [
7 | {
8 | id: '1',
9 | type: 'Start',
10 | data: {},
11 | position: {
12 | x: 40,
13 | y: 240,
14 | }
15 | },
16 | {
17 | id: '2',
18 | type: 'End',
19 | data: {},
20 | position: {
21 | x: 500,
22 | y: 240,
23 | }
24 | }
25 | ];
26 |
27 | const edges = [
28 | { source: '1', target: '2', id: '234123' }
29 | ]
30 |
31 | return (
32 |
33 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/locales/en_US.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "copy_max_tip": "The maximum number of table items has been reached and cannot be copied",
3 | "copy": "Copy",
4 | "add_item": "Add a new line",
5 | "confirm_delete": "Are you sure to delete?",
6 | "confirm": "Yes",
7 | "cancel": "No",
8 | "operate": "Operate",
9 | "delete": "Delete",
10 | "edit": "Edit",
11 | "img_src_error": "Image address error",
12 | "upload": "Upload",
13 | "upload_success": "upload success",
14 | "upload_fail": "upload failed",
15 | "uploaded_address": "Uploaded address",
16 | "test_src": "Test address",
17 | "schema_not_match": "Schema does not match the display component:",
18 | "item": "Item",
19 | "search": "Search",
20 | "reset": "Reset",
21 | "expand": "Expand",
22 | "fold": "Fold",
23 | "submit": "Submit",
24 | "moveDown": "Move Down",
25 | "moveUp": "Move Up"
26 | }
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/models/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore as createx } from 'zustand';
2 |
3 | type FormStore = {
4 | schema?: any;
5 | flattenSchema: any;
6 | context?: any;
7 | initialized: boolean,
8 | isCardMode: boolean,
9 | init?: (schema: FormStore['schema']) => any;
10 | setContext: (context: any) => any;
11 | setIsCardMode: (mode:boolean) => void;
12 | };
13 |
14 | // 将 useStore 改为 createStore, 并把它改为 create 方法
15 | export const createStore = () => createx((setState: any, get: any) => ({
16 | initialized: false,
17 | schema: {},
18 | flattenSchema: {},
19 | context: {},
20 | isCardMode: false,
21 | init: data => {
22 | return setState({
23 | initialized: true,
24 | ...data
25 | });
26 | },
27 | setContext: context => {
28 | return setState({ context });
29 | },
30 | setIsCardMode: (mode) => setState({ isCardMode: mode }),
31 | }));
--------------------------------------------------------------------------------
/packages/form-render/__tests__/form.spec.tsx:
--------------------------------------------------------------------------------
1 | import { describe, it, afterAll, expect } from 'vitest';
2 | import * as React from 'react';
3 | import { render, act, cleanup } from '@testing-library/react';
4 | import '@testing-library/jest-dom';
5 | import Demo from './demo';
6 |
7 | function sleep(ms): Promise {
8 | return new Promise(resolve => setTimeout(resolve, ms));
9 | }
10 |
11 | afterAll(cleanup);
12 |
13 | describe('FormRender', () => {
14 | it('📦 Render FR Success', async () => {
15 | const { getByTestId, unmount } = render( );
16 | act(() => {
17 | getByTestId('submit').click();
18 | getByTestId('test').click();
19 | });
20 | await act(() => sleep(500));
21 | expect(getByTestId('input')).toHaveTextContent('简单输入框');
22 | expect(getByTestId('select')).toHaveTextContent('a');
23 |
24 | act(() => {
25 | unmount();
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/packages/form-render/src/locales/en_US.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "copy_max_tip": "The maximum number of table items has been reached and cannot be copied",
3 | "copy": "Copy",
4 | "add_item": "Add a new line",
5 | "confirm_delete": "Are you sure to delete?",
6 | "confirm": "Yes",
7 | "cancel": "No",
8 | "operate": "Operate",
9 | "delete": "Delete",
10 | "edit": "Edit",
11 | "img_src_error": "Image address error",
12 | "upload": "Upload",
13 | "upload_success": "upload success",
14 | "upload_fail": "upload failed",
15 | "uploaded_address": "Uploaded address",
16 | "test_src": "Test address",
17 | "schema_not_match": "Schema does not match the display component:",
18 | "item": "Item",
19 | "search": "Search",
20 | "reset": "Reset",
21 | "expand": "Expand",
22 | "fold": "Fold",
23 | "submit": "Submit",
24 | "save": "Save",
25 | "moveDown": "Move Down",
26 | "moveUp": "Move Up"
27 | }
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FSpace/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Space, Divider } from 'antd';
3 | import { combineClass } from '../utils/common';
4 |
5 | const FSpace = (props: any) => {
6 | const {
7 | data,
8 | label,
9 | split = 'divider',
10 | className,
11 | style,
12 | labelStyle,
13 | spaceStyle,
14 | childSchema,
15 | addons,
16 | ...spaceProps
17 | } = props;
18 |
19 | return (
20 |
21 | {label && {label}: }
22 | : null} {...spaceProps}>
23 | {childSchema.map((schema: any, index: number) =>
24 | addons.renderer({ key: index, schema, data, addons }),
25 | )}
26 |
27 |
28 | );
29 | };
30 |
31 | export default FSpace;
32 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTooltip/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tooltip } from 'antd';
3 | import { combineClass } from '../utils/common';
4 | import './index.less';
5 |
6 | const FTooltip = (props: any) => {
7 | const { data, childSchema, className, style, title, tooltip, addons, ...otherProps } = props;
8 | const tooltipTitle =
;
9 |
10 | return (
11 |
20 |
21 | {addons.renderer({ schema: childSchema, data, addons, ...otherProps })}
22 |
23 |
24 | );
25 | };
26 |
27 | export default FTooltip;
28 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listTable/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-table-list {
4 | margin-bottom: 24px;
5 |
6 | .@{ant-prefix}-form-item {
7 | margin-bottom: 0;
8 | }
9 |
10 | .@{ant-prefix}-form-item-label {
11 | display: none;
12 | }
13 |
14 | .@{ant-prefix}-form-item-explain-error {
15 | display: none;
16 | }
17 |
18 | .fr-list-item-operate {
19 | gap: 0 !important;
20 | }
21 | }
22 |
23 | .fr-popover-error {
24 | .@{ant-prefix}-popover-inner-content {
25 | color: #ff4d4f !important
26 | }
27 | }
28 |
29 | .fr-table-list-no-popover {
30 | .@{ant-prefix}-table-tbody {
31 | .@{ant-prefix}-table-cell {
32 | padding: 24px 8px 0px 8px !important;
33 | }
34 | }
35 |
36 | .@{ant-prefix}-form-item {
37 | margin-bottom: 24px;
38 | }
39 |
40 | .@{ant-prefix}-form-item-explain-error {
41 | display: block;
42 | font-size: 10px;
43 | }
44 | }
--------------------------------------------------------------------------------
/packages/chart-render/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ### 1.0.0-alpha.3
4 |
5 | - [!] 修正依赖包
6 |
7 | ### 1.0.0-alpha.2
8 |
9 | - [!] 修复 Search 样式
10 |
11 | ### 1.0.0-alpha.1
12 |
13 | - [+] 完全的重构,使用上尽量与 `TableRender` 保持一致,通过写入 `api` 作为数据请求方法来达到简单出图表的效果
14 | - [+] 暂时支持柱状图、饼图展示
15 |
16 | ### 0.1.9
17 |
18 | - [+] 更新 npm 包的文档信息以及补全对应的 package 信息
19 |
20 | ### 0.1.7
21 |
22 | - [+] 折线图单指标双维度 增加百分数支持
23 |
24 | ### 0.1.6
25 |
26 | - [+] 折线图单指标单维度 增加百分数支持
27 |
28 | ### 0.1.5
29 |
30 | - [+] 折线图增加双指标 双维度 支持
31 |
32 | ### 0.1.4
33 |
34 | - [-] 移除 CrossTreeTable 下钻树表,与 PivotTable 交叉表合并,通过 `leftExpandable`、`topExpandable` 参数控制是否可展开
35 | - [-] 移除 Area 面积图,与 Line 折线图合并,通过 `withArea` 参数控制是否以面积图展示
36 | - [+] 解决 交叉表的 `cellRender` 的入参问题
37 |
38 | ### 0.1.3
39 |
40 | - [-] 重新发布
41 |
42 | ### 0.1.2
43 |
44 | - [-] 移除 Bar 条形图,与 Column 柱状图合并,通过 `inverted` 参数区分
45 | - [+] 修正所有图标的图例提示展示
46 |
47 | ### 0.1.1
48 |
49 | - [+] 迁移到大仓
50 | - [+] 正式发布
51 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listVirtual/index.less:
--------------------------------------------------------------------------------
1 | @ant-prefix: ant;
2 |
3 | .fr-virtual-list {
4 | margin-bottom: 12px;
5 |
6 | .@{ant-prefix}-form-item {
7 | margin-bottom: 0;
8 | }
9 |
10 | .@{ant-prefix}-form-item-label {
11 | display: none;
12 | }
13 |
14 | .@{ant-prefix}-form-item-explain-error {
15 | display: none;
16 | }
17 |
18 | .fr-list-item-operate {
19 | gap: 0 !important;
20 | }
21 | }
22 |
23 | .fr-popover-error {
24 | .@{ant-prefix}-popover-inner-content {
25 | color: #ff4d4f !important
26 | }
27 | }
28 |
29 | .fr-virtual-list-no-popover {
30 | .@{ant-prefix}-table-tbody {
31 | .@{ant-prefix}-table-cell {
32 | padding: 24px 8px 0px 8px !important;
33 | }
34 | }
35 |
36 | .@{ant-prefix}-form-item {
37 | margin-bottom: 24px;
38 | }
39 |
40 | .@{ant-prefix}-form-item-explain-error {
41 | display: block;
42 | font-size: 10px;
43 | }
44 | }
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 | **/*.svg
3 | **/**/*.svg
4 | **/*.ejs
5 | **/**/*.ejs
6 | **/*.html
7 | **/**/*.html
8 |
9 | # dependencies
10 | /node_modules
11 | /npm-debug.log*
12 | /yarn-error.log
13 | /yarn.lock
14 | /package-lock.json
15 |
16 |
17 | # production
18 | /dist
19 | /lib
20 | /docs-dist
21 | # misc
22 | .idea
23 | .DS_Store
24 | .idea
25 | .vscode
26 |
27 | # umi
28 | .umi
29 | .umi-production
30 | .umi-test
31 | .env.local
32 |
33 | # lerna
34 | node_modules
35 |
36 | /.local
37 |
38 | /packages/*/es
39 | /packages/*/lib
40 | /packages/*/.local
41 | /packages/*/dist
42 |
43 | /widgets/*/es
44 | /widgets/*/lib
45 | /widgets/*/.local
46 | /widgets/*/dist
47 |
48 | /tools/*/es
49 | /tools/*/lib
50 | /tools/*/.local
51 | /tools/*/dist
52 |
53 | # custom
54 | old-doc
55 | test.json
56 | /docs/guide/.test
57 | /docs/*/*.md
58 | /docs/playground/monaco/index.js
--------------------------------------------------------------------------------
/docs/form-render/demo/form-slim/form-list.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * transform: true
3 | * defaultShowCode: true
4 | */
5 | import React from 'react';
6 | import { FormSlimRender, useForm, Input, SimpleList, Collapse } from 'form-render';
7 |
8 | const schema = {
9 | type: 'object',
10 | displayType: 'row',
11 | properties: {
12 | list: {
13 | title: '列表按需',
14 | type: 'array',
15 | widget: 'simpleList',
16 | items: {
17 | type: 'object',
18 | properties: {
19 | input1: {
20 | title: '输入框',
21 | type: 'string',
22 | },
23 | },
24 | },
25 | },
26 | },
27 | };
28 |
29 | export default () => {
30 | const form = useForm();
31 |
32 | return (
33 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/packages/x-flow/src/models/event-emitter.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useEventEmitter } from 'ahooks';
3 | import type { EventEmitter } from 'ahooks/lib/useEventEmitter';
4 | import { createContext, useContext } from 'use-context-selector';
5 |
6 | const EventEmitterContext = createContext<{ eventEmitter: EventEmitter | null }>({
7 | eventEmitter: null,
8 | })
9 |
10 | export const useEventEmitterContextContext = () => useContext(EventEmitterContext)
11 |
12 | type EventEmitterContextProviderProps = {
13 | children: React.ReactNode
14 | }
15 |
16 | export const EventEmitterContextProvider = ({
17 | children,
18 | }: EventEmitterContextProviderProps) => {
19 | const eventEmitter = useEventEmitter()
20 |
21 | return (
22 |
23 | {children}
24 |
25 | )
26 | }
27 |
28 | export default EventEmitterContext
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /npm-debug.log*
6 | /yarn-error.log
7 | /yarn.lock
8 | /package-lock.json
9 |
10 | */*/yarn-error.log
11 |
12 | .yarn
13 | .turbo/cookies
14 | .turbo/daemon
15 | .turbo
16 |
17 | # turbo
18 | */*/.turbo
19 |
20 |
21 | # production
22 | /dist
23 | /lib
24 | /docs-dist
25 | # misc
26 | .idea
27 | .DS_Store
28 | .idea
29 | .vscode
30 |
31 | # umi
32 | .dumi/tmp
33 | .dumi-production
34 | .dumi-test
35 | .env.local
36 |
37 | # lerna
38 | node_modules
39 |
40 | /.local
41 |
42 | /packages/*/es
43 | /packages/*/lib
44 | /packages/*/.local
45 | /packages/*/dist
46 |
47 | /widgets/*/es
48 | /widgets/*/lib
49 | /widgets/*/.local
50 | /widgets/*/dist
51 |
52 | /tools/*/es
53 | /tools/*/lib
54 | /tools/*/.local
55 | /tools/*/dist
56 |
57 | # custom
58 | old-doc
59 | test.json
60 | /docs/guide/.test
61 |
62 | /coverage
63 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/urlInput.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, inputPropsBasic } from '../utils';
2 |
3 | export default createMeta('UrlInput', {
4 | title: '链接输入框',
5 | category: '其他',
6 | props: [
7 | {
8 | title: '基础配置',
9 | type: 'group',
10 | display: 'accordion',
11 | items: inputPropsBasic
12 | },
13 | {
14 | title: '其他配置',
15 | display: 'accordion',
16 | type: 'group',
17 | items: [
18 | {
19 | name: 'props.addonText',
20 | title: { label: '按钮文案', tip: '跳转按钮的文案配置' },
21 | defaultValue: '测试链接',
22 | setter: 'StringSetter'
23 | }
24 | ]
25 | }
26 | ],
27 | snippets: [
28 | {
29 | title: '链接输入框',
30 | screenshot: 'icon-link',
31 | schema: {
32 | componentName: 'UrlInput',
33 | props: {
34 | title: '链接输入框',
35 | },
36 | }
37 | }
38 | ]
39 | });
40 |
--------------------------------------------------------------------------------
/packages/x-flow/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2015",
4 | "module": "ES2015",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | "skipLibCheck": true,
12 | // "strict": true,
13 | "declaration": true,
14 | "paths": {
15 | "@/*": [
16 | "src/*"
17 | ],
18 | "@@/*": [
19 | "src/.umi/*"
20 | ],
21 | "form-render": [
22 | "packages/form-render/src/*"
23 | ],
24 | },
25 | "allowJs": true,
26 | "allowSyntheticDefaultImports": true,
27 | "noImplicitAny": false,
28 | "resolveJsonModule": true
29 | },
30 | "exclude": [
31 | "node_modules",
32 | "lib",
33 | "es",
34 | "dist",
35 | "typings",
36 | "**/__test__",
37 | "test",
38 | "tests",
39 | "docs",
40 | "**/*.js"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/packages/data-render/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2015",
4 | "module": "ES2015",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | "skipLibCheck": true,
12 | // "strict": true,
13 | "declaration": true,
14 | "paths": {
15 | "@/*": [
16 | "src/*"
17 | ],
18 | "@@/*": [
19 | "src/.umi/*"
20 | ],
21 | "form-render": [
22 | "packages/form-render/src/*"
23 | ],
24 | },
25 | "allowJs": true,
26 | "allowSyntheticDefaultImports": true,
27 | "noImplicitAny": false,
28 | "resolveJsonModule": true
29 | },
30 | "exclude": [
31 | "node_modules",
32 | "lib",
33 | "es",
34 | "dist",
35 | "typings",
36 | "**/__test__",
37 | "test",
38 | "tests",
39 | "docs",
40 | "**/*.js"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/packages/form-render/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2015",
4 | "module": "ES2015",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | "skipLibCheck": true,
12 | // "strict": true,
13 | "declaration": true,
14 | "paths": {
15 | "@/*": [
16 | "src/*"
17 | ],
18 | "@@/*": [
19 | "src/.umi/*"
20 | ],
21 | "form-render": [
22 | "packages/form-render/src/*"
23 | ],
24 | },
25 | "allowJs": true,
26 | "allowSyntheticDefaultImports": true,
27 | "noImplicitAny": false,
28 | "resolveJsonModule": true
29 | },
30 | "exclude": [
31 | "node_modules",
32 | "lib",
33 | "es",
34 | "dist",
35 | "typings",
36 | "**/__test__",
37 | "test",
38 | "tests",
39 | "docs",
40 | "**/*.js"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/packages/x-flow/src/components/NodeContainer/TitleMenuTooltip.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import createIconFont from '../../utils/createIconFont';
3 |
4 | const TitleMenuTooltip = ({ icon, nodeSettingTitle, description, iconFontUrl, iconSvg }: any) => {
5 | const IconBox = useMemo(() => createIconFont(iconFontUrl), [iconFontUrl]);
6 |
7 | return (
8 |
9 |
10 |
11 | {iconSvg ? iconSvg : }
12 |
13 |
14 | {nodeSettingTitle}
15 |
16 |
17 |
18 | {description}
19 |
20 |
21 | )
22 | };
23 |
24 | export default TitleMenuTooltip;
25 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2015",
4 | "module": "ES2015",
5 | "moduleResolution": "node",
6 | "importHelpers": true,
7 | "jsx": "react",
8 | "esModuleInterop": true,
9 | "sourceMap": true,
10 | "baseUrl": "./",
11 | "skipLibCheck": true,
12 | // "strict": true,
13 | "declaration": true,
14 | "paths": {
15 | "@/*": [
16 | "src/*"
17 | ],
18 | "@@/*": [
19 | "src/.umi/*"
20 | ],
21 | "form-render": [
22 | "packages/form-render-mobile/src/*"
23 | ],
24 | },
25 | "allowJs": true,
26 | "allowSyntheticDefaultImports": true,
27 | "noImplicitAny": false,
28 | "resolveJsonModule": true
29 | },
30 | "exclude": [
31 | "node_modules",
32 | "lib",
33 | "es",
34 | "dist",
35 | "typings",
36 | "**/__test__",
37 | "test",
38 | "tests",
39 | "docs",
40 | "**/*.js"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/packages/table-render/__tests__/utils.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from 'vitest';
2 | import { getDate, getDateTime, getMoneyType, isObj } from '../src/utils';
3 |
4 | describe('Test TableRender valueType', () => {
5 | test('Test getDate', () => {
6 | const current = new Date().getTime();
7 | expect(getDate(current)).toHaveLength(10);
8 | });
9 | test('Test getDateTime', () => {
10 | const current = new Date().getTime();
11 | expect(getDateTime(current)).toHaveLength(19);
12 | });
13 | test('Test getMoneyType', () => {
14 | expect(getMoneyType(10000)).toEqual('¥10,000');
15 | });
16 | test('Test isObj object', () => {
17 | expect(isObj({})).toBeTruthy();
18 | });
19 | test('Test isObj array', () => {
20 | expect(isObj([])).toBeFalsy();
21 | });
22 | test('Test isObj string', () => {
23 | expect(isObj('')).toBeFalsy();
24 | });
25 | test('Test isObj number', () => {
26 | expect(isObj('')).toBeFalsy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/basic/showSwitchNode.tsx:
--------------------------------------------------------------------------------
1 | import { Space } from 'antd';
2 | import React from 'react';
3 | import './index.less';
4 | import TextEllipsis from './TextEllipsis';
5 |
6 | const showSwitchNode = ({ data, index }) => {
7 | const { type, value } = data;
8 | if (!type && !value) {
9 | return
;
10 | }
11 |
12 | return (
13 |
14 | {type && (
15 |
19 | )}
20 | {value && (
21 |
25 | )}
26 |
27 | );
28 | };
29 |
30 | export default showSwitchNode;
31 |
--------------------------------------------------------------------------------
/docs/xflow/demo/best/demo2/showSwitchNode.tsx:
--------------------------------------------------------------------------------
1 | import { Space } from 'antd';
2 | import React from 'react';
3 | import './index.less';
4 | import TextEllipsis from './TextEllipsis';
5 |
6 | const showSwitchNode = ({ data, index }) => {
7 | const { type, value } = data;
8 | if (!type && !value) {
9 | return
;
10 | }
11 |
12 | return (
13 |
14 | {type && (
15 |
19 | )}
20 | {value && (
21 |
25 | )}
26 |
27 | );
28 | };
29 |
30 | export default showSwitchNode;
31 |
--------------------------------------------------------------------------------
/packages/x-flow/src/operator/ZoomInOut/index.less:
--------------------------------------------------------------------------------
1 | .fai-reactflow-zoominout {
2 | display: flex;
3 | align-items: center;
4 | padding: 2px 1px;
5 | border-radius: 8px;
6 | border: 0.5px solid #f3f4f6;
7 | background-color: #ffffff;
8 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
9 | color: #667085;
10 | margin-right: 10px;
11 |
12 | .ant-btn {
13 | display: inline-flex;
14 | align-items: center;
15 | justify-content: center;
16 | }
17 | }
18 |
19 | .fai-reactflow-zoom-select {
20 |
21 | .parting-line {
22 | height: 1px;
23 | background-color: #F3F4F6;
24 | }
25 |
26 | .zoom-item {
27 | display: flex;
28 | align-items: center;
29 | justify-content: space-between;
30 | padding-left: 10px;
31 | padding-right: 10px;
32 | height: 30px;
33 | border-radius: 8px;
34 | cursor: pointer;
35 | font-size: 14px;
36 | color: #374151;
37 |
38 | &:hover {
39 | background-color: #F9FAFB;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FProgress/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { combineClass } from '../utils/common';
3 | import FTitle from '../FTitle';
4 | import './index.less';
5 |
6 | const FTimeline = (props: any) => {
7 | const { data, title, className } = props;
8 |
9 | return (
10 | <>
11 |
12 |
13 | {data.map((item: any, index: number) => (
14 |
19 |
{item.time}
20 |
{item.content}
21 |
22 |
23 | ))}
24 |
25 | >
26 | );
27 | };
28 |
29 | export default FTimeline;
30 |
--------------------------------------------------------------------------------
/packages/table-render/src/core/ErrorBoundary/index.tsx:
--------------------------------------------------------------------------------
1 | import { Result } from 'antd';
2 | import React, { ErrorInfo } from 'react';
3 |
4 | class ErrorBoundary extends React.Component<
5 | {},
6 | { hasError: boolean; errorInfo: string }
7 | > {
8 | state = { hasError: false, errorInfo: '' };
9 |
10 | static getDerivedStateFromError(error: Error) {
11 | return { hasError: true, errorInfo: error.message };
12 | }
13 |
14 | componentDidCatch(error: any, errorInfo: ErrorInfo) {
15 | // eslint-disable-next-line no-console
16 | console.log(error, errorInfo);
17 | }
18 |
19 | render() {
20 | if (this.state.hasError) {
21 | // You can render any custom fallback UI
22 | return (
23 |
28 | );
29 | }
30 | //@ts-ignore
31 | return this.props.children;
32 | }
33 | }
34 |
35 | export default ErrorBoundary;
36 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FCard/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Card } from 'antd';
3 | import { combineClass, isReactNodeSchema } from '../utils/common';
4 | import './index.less';
5 |
6 | export default (props: any) => {
7 | const { data, childSchema, className, style, title, extra, addons, ...otherProps } = props;
8 |
9 | let cardTitle =
;
10 | let cardExtra = extra;
11 |
12 | if (isReactNodeSchema(title)) {
13 | cardTitle = addons.renderer({ schema: title, data, addons });
14 | }
15 |
16 | if (isReactNodeSchema(extra)) {
17 | cardExtra = addons.renderer({ schema: extra, data, addons });
18 | }
19 |
20 | return (
21 |
28 | {addons.renderer({ schema: childSchema, data, addons })}
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: 🚀 Build CI
2 |
3 | env:
4 | NODE_OPTIONS: --max-old-space-size=6144
5 |
6 | on:
7 | push:
8 | branches: [master, dev]
9 | pull_request:
10 | branches: [master, dev]
11 |
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | strategy:
17 | matrix:
18 | node: [ '14', '16' ]
19 | name: build steps
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Use Node.js ${{ matrix.node }}
23 | uses: actions/setup-node@v2
24 | with:
25 | node-version: ${{ matrix.node }}
26 | - name: Cache Node Dependencies
27 | uses: actions/cache@v3
28 | with:
29 | path: node_modules
30 | key: ${{runner.OS}}-${{ hashFiles('**/yarn.lock') }}
31 | - name: Install
32 | run: yarn install
33 | if: steps.cache.outputs.cache-hit != 'true'
34 |
35 | - name: Build
36 | run: yarn build
37 |
38 | - name: Test
39 | run: yarn test
40 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: lhbxs
7 | ---
8 |
9 |
14 |
15 | **1.依赖仓库的版本(Dependencies versions)**:
16 |
17 | - react:
18 | - form-render:
19 | - table-render:
20 | - antd:
21 |
22 | **2.问题描述(Bug description)**:
23 |
24 | **3.出现问题的 schema demo(Reproduction schema demo)**:
25 | ```js
26 | const schema = {
27 | // ...
28 | }
29 | ```
30 |
31 | **4.最小复现 demo(Reproduction demo)**:
32 |
33 |
37 |
38 | form-render demo https://codesandbox.io/s/unruffled-flower-jl78h
39 | table-render demo https://codesandbox.io/s/sweet-euler-bdoty
40 | fr-generator demo https://codesandbox.io/s/s13sh
41 |
--------------------------------------------------------------------------------
/docs/xflow/demo/custom-flow/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import XFlow from '@xrenders/xflow';
3 | import settings from './setting';
4 | import customWidget from './customWidget';
5 |
6 | export default () => {
7 | const nodes = [
8 | {
9 | id: '1',
10 | type: 'Start',
11 | data: {
12 | inputVal:'我是自定义组件'
13 | },
14 | position: {
15 | x: 40,
16 | y: 240,
17 | }
18 | },
19 | {
20 | id: '2',
21 | type: 'End',
22 | data: {},
23 | position: {
24 | x: 500,
25 | y: 240,
26 | }
27 | }
28 | ];
29 |
30 | const edges = [
31 | { source: '1', target: '2', id: '234123' }
32 | ]
33 |
34 | return (
35 |
36 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/widgets/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@form-render/template",
3 | "version": "1.0.0",
4 | "keywords": [
5 | "FormRender",
6 | "Render",
7 | "React",
8 | "Json Schema",
9 | "Ant Design"
10 | ],
11 | "main": "dist/index.js",
12 | "module": "dist/index.esm.js",
13 | "scripts": {
14 | "beta": "npm publish --tag beta",
15 | "build": "father-build",
16 | "prepare": "npm run build",
17 | "prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
18 | "postpublish": "git push --tags",
19 | "release": "npm publish --access public",
20 | "test": "umi-test",
21 | "test:coverage": "umi-test --coverage"
22 | },
23 | "lint-staged": {
24 | "*.{js,jsx,less,md,json}": [
25 | "prettier --write"
26 | ],
27 | "*.ts?(x)": [
28 | "prettier --parser=typescript --write"
29 | ]
30 | },
31 | "peerDependencies": {
32 | "antd": "^4.x",
33 | "react": ">=16.8.0"
34 | },
35 | "gitHooks": {
36 | "pre-commit": "lint-staged"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/docs/form-render-mobile/disaply.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | toc: content
4 | title: 内置控件
5 | ---
6 |
7 | ## 输入控件
8 |
9 | 输入控件是由 antd mobile 组件,做了进一步的封装和兼容之后,组成的一系列开箱即用的 widget。如要对组件进行进一步的配置请参考对应的 antd mobile 文档 。
10 |
11 | form-render-mobile 支持如下输入控件。如需要更多自定义样式和功能,请参考 自定义组件 。
12 |
13 |
14 |
15 | ## 布局控件
16 |
17 | 对于移动端的表单场景,我们内置了两种常用布局控件,分别为 `card`,`group`。
18 |
19 | ### 分组 group
20 |
21 |
22 |
23 |
26 |
27 | ### 卡片 card
28 |
29 |
30 |
31 | ## 列表控件
32 |
33 |
34 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/radio/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Radio, Space } from 'antd';
3 | import withFieldWrap from '../../utils/withFieldWrap';
4 |
5 | interface Option {
6 | label: string;
7 | value: string;
8 | disabled?: boolean;
9 | }
10 |
11 | interface Props {
12 | direction: 'row' | 'column',
13 | options: Option[]
14 | [key: string]: any
15 | }
16 |
17 | const RadioComp = (props: Props) => {
18 | const { direction = 'row', options = [], ...rest } = props
19 |
20 | if (direction === 'column') {
21 | return
22 |
23 | {
24 | options.map((item: Option) => {
25 | const { value, label, ...rest } = item
26 | return {label}
27 | })
28 | }
29 |
30 |
31 | }
32 |
33 | return ;
34 | };
35 |
36 | export default withFieldWrap(RadioComp);
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/slider.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, getNotInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('Slider', {
4 | title: '滑动条',
5 | priority: 991,
6 | props: [
7 | {
8 | title: '基础配置',
9 | type: 'group',
10 | display: 'accordion',
11 | items: getNotInputPropsBasic({
12 | name: 'defaultValue',
13 | title: { label: '默认值', tip: 'defaultValue | 默认值'},
14 | setter: 'NumberSetter'
15 | })
16 | },
17 | {
18 | title: '其他配置',
19 | display: 'accordion',
20 | type: 'group',
21 | items: [
22 | {
23 | name: 'props.hideInput',
24 | title: {label: '隐藏输入框', tip: '隐藏输入框'},
25 | setter: 'BoolSetter',
26 | }
27 | ]
28 | }
29 | ],
30 | snippets: [
31 | {
32 | label: '滑动条',
33 | screenshot: 'icon-slider',
34 | schema: {
35 | componentName: 'Slider',
36 | props: {
37 | title: '滑动条'
38 | }
39 | }
40 | }
41 | ]
42 | });
43 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FRow/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Row, Col } from 'antd';
3 |
4 | import { combineClass } from '../utils/common';
5 |
6 | import './index.less';
7 |
8 | const FRow = (props: any) => {
9 | const { items, data, hasBackground, className, addons, ...options } = props;
10 |
11 | return (
12 |
13 | {(items || []).map((item: any, index: number) => {
14 | const { children, className: itemClassName, ...itemOptions } = item;
15 | return (
16 |
24 | {addons.renderer({ key: index, schema: children, data, addons })}
25 |
26 | );
27 | })}
28 |
29 | );
30 | };
31 |
32 | export default FRow;
33 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/timeRange.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, getInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('TimeRange', {
4 | title: '时间区间选择',
5 | props: [
6 | {
7 | title: '基础配置',
8 | type: 'group',
9 | display: 'accordion',
10 | items: getInputPropsBasic({
11 | name: 'defaultValue',
12 | title: { label: '默认值', tip: 'default | 默认值'},
13 | setter: 'CustomTimeRangeSetter'
14 | },
15 | {
16 | name: 'props.placeholder',
17 | title: {
18 | label: '提示文字',
19 | tip: 'placeholder | 输入框提示文字',
20 | },
21 | defaultValue: ['开始时间', '结束时间'],
22 | setter: 'JsonSetter',
23 | })
24 | }
25 | ],
26 | snippets: [
27 | {
28 | title: '时间区间选择',
29 | screenshot: 'icon-time',
30 | schema: {
31 | componentName: 'TimeRange',
32 | props: {
33 | title: '时间区间',
34 | type: 'range',
35 | format: 'time'
36 | }
37 | }
38 | }
39 | ]
40 | });
--------------------------------------------------------------------------------
/packages/form-render-mobile/src/widgets/Cascader/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useRef, useImperativeHandle} from 'react';
2 | import { Cascader } from 'antd-mobile';
3 | import { omit } from 'lodash-es';
4 |
5 | export default (props: any) => {
6 | const {
7 | placeholder = '请选择',
8 | value,
9 | onChange,
10 | options,
11 | ...rest
12 | } = omit(props, ['addons', 'schema']);
13 |
14 | const pickerRef: any = useRef(null);
15 |
16 | // 使用useImperativeHandle暴露方法给外部
17 | useImperativeHandle(props.addons.fieldRef, () => ({
18 | ...pickerRef?.current
19 | }));
20 |
21 | return (
22 |
29 | {items => {
30 | if (items.every(i => i === null)) {
31 | return {placeholder} ;
32 | } else {
33 | return items.map(i => i?.label ?? '未选择').join('-')
34 | }
35 | }}
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/fields/checkboxes/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Checkbox, Space } from 'antd';
3 | import withFieldWrap from '../../utils/withFieldWrap';
4 |
5 | interface Option {
6 | label: string;
7 | value: string;
8 | disabled?: boolean
9 | }
10 |
11 | interface Props {
12 | direction: 'row' | 'column';
13 | options: Option[];
14 | [key: string]: any
15 | }
16 | const Checkboxes: React.FC = (props) => {
17 | const { direction = 'row', options = [], ...rest } = props
18 |
19 | if (direction === 'column') {
20 | return
21 |
22 | {
23 | options.map((item: Option) => {
24 | const { value, label, ...rest } = item
25 | return {label}
26 | })
27 | }
28 |
29 |
30 | }
31 |
32 | return ;
33 | };
34 |
35 | export default withFieldWrap(Checkboxes);
36 |
--------------------------------------------------------------------------------
/tools/schema-builder/src/settings/meta/dateRange.ts:
--------------------------------------------------------------------------------
1 | import { createMeta, getInputPropsBasic } from '../utils';
2 |
3 | export default createMeta('DateRange', {
4 | title: '日期选择区间',
5 | props: [
6 | {
7 | title: '基础配置',
8 | type: 'group',
9 | display: 'accordion',
10 | items: getInputPropsBasic({
11 | name: 'defaultValue',
12 | title: { label: '默认值', tip: 'defaultValue | 默认值'},
13 | setter: 'CustomDateRangeSetter'
14 | },
15 | {
16 | name: 'props.placeholder',
17 | title: {
18 | label: '提示文字',
19 | tip: 'placeholder | 输入框提示文字',
20 | },
21 | setter: 'JsonSetter',
22 | defaultValue: ['开始时间', '结束时间']
23 | })
24 | },
25 | ],
26 | snippets: [
27 | {
28 | title: '日期区间选择',
29 | screenshot: 'icon-date',
30 | schema: {
31 | componentName: 'DateRange',
32 | props: {
33 | title: '日期区间选择',
34 | type: 'range',
35 | format: 'date',
36 | }
37 | }
38 | }
39 | ]
40 | });
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/components/IconLabel/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import createIconFont from '../../utils/createIconFont';
4 |
5 | import './index.less';
6 |
7 | const IconLabel = (props: any) => {
8 | const {
9 | data,
10 | onClick,
11 | type,
12 | className,
13 | style,
14 | contentStyle,
15 | iconStyle,
16 | direct = 'right',
17 | fontSize,
18 | color,
19 | iconFontUrl,
20 | } = props;
21 |
22 | const Icon = createIconFont(iconFontUrl);
23 |
24 | const IconView = ;
25 |
26 | return (
27 |
31 | {direct === 'left' && IconView}
32 |
33 | {data}
34 |
35 | {direct === 'right' && IconView}
36 |
37 | );
38 | };
39 |
40 | export default IconLabel;
41 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FProgress/index.less:
--------------------------------------------------------------------------------
1 | .dr-progress {
2 | width: 100%;
3 | padding: 10px 0 0 5px;
4 | overflow-y: auto;
5 | white-space: nowrap;
6 |
7 | .step-item {
8 | position: relative;
9 | display: inline-block;
10 | width: 260px;
11 | margin: 0 14px;
12 | padding-top: 11px;
13 | padding-right: 20px;
14 | white-space: normal;
15 | vertical-align: top;
16 | }
17 |
18 | .step-item-active {
19 | border-top: 1px solid rgba(0, 0, 0, 0.15);
20 | }
21 |
22 | .step-title {
23 | color: rgba(20, 20, 20, 0.85);
24 | font-size: 14px;
25 | line-height: 22px;
26 | }
27 |
28 | .step-time {
29 | color: #8a8a8a;
30 | font-size: 12px;
31 | line-height: 22px;
32 | }
33 |
34 | .step-dot {
35 | position: absolute;
36 | top: -5px;
37 | left: -18px;
38 | width: 10px;
39 | height: 10px;
40 | background-color: #fff;
41 | border: 2px solid #ccc;
42 | border-radius: 10px;
43 | }
44 |
45 | .step-item-active .step-dot {
46 | border: 2px solid #3f7ffb;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/form-render/src/widgets/listDrawer/drawerForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Button, Drawer, Space, ConfigProvider } from 'antd';
3 | import { translation } from '../utils';
4 |
5 | const DrawerForm = (props: any) => {
6 | const { children, onConfirm, onClose, ...ret } = props;
7 |
8 | const configCtx = useContext(ConfigProvider.ConfigContext);
9 | const t = translation(configCtx);
10 |
11 | let extraProps: any = { ...ret, open: true };
12 | if ((window as any).antdVersion === 'v4') {
13 | extraProps = { ...ret, visible: true };
14 | }
15 |
16 | return (
17 |
24 | {t('cancel')}
25 |
26 | {t('confirm')}
27 |
28 |
29 | }
30 | >
31 | {children}
32 |
33 | );
34 | };
35 |
36 | export default DrawerForm;
37 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTextEllipsis/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { combineClass } from '../utils/common';
3 | import TextEllipsis from '../components/TextEllipsis';
4 |
5 | /**
6 | *
7 | * 文本组件
8 | */
9 | const FTextEllipsis = (props: any) => {
10 | const {
11 | className,
12 | style,
13 | data,
14 | addons,
15 |
16 | contentStyle,
17 | height = 24,
18 | leftSlot = [],
19 | rightSlot = [],
20 |
21 | } = props;
22 |
23 | const parentData = addons.getParentData();
24 |
25 | return (
26 |
27 |
38 |
39 | );
40 | };
41 |
42 | export default FTextEllipsis;
43 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FTimeline/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Timeline } from 'antd';
3 | import { combineClass } from '../utils/common';
4 | import FTitle from '../FTitle';
5 |
6 | const FTimeline = (props: any) => {
7 | const { data = [], title, className, style, lineItem = {}, addons, ...otherProps } = props;
8 | const {
9 | timeKey = 'time',
10 | contenKey = 'content',
11 | colorKey = 'color',
12 | ...otherLineItem
13 | } = lineItem;
14 |
15 | return (
16 | <>
17 |
18 |
19 | {(data || []).map((item: any = {}, index: number) => (
20 |
21 | {item[timeKey]}
22 | {item[contenKey]}
23 |
24 | ))}
25 |
26 | >
27 | );
28 | };
29 |
30 | export default FTimeline;
31 |
--------------------------------------------------------------------------------
/.turbo/daemon/ae401ef4dd981f33-turbo.log.2024-08-26:
--------------------------------------------------------------------------------
1 | 2024-08-26T15:23:25.560565Z WARN turborepo_lib::package_changes_watcher: changed_files: {AnchoredSystemPathBuf("packages/form-render/package.json")}
2 | 2024-08-26T15:23:25.560588Z WARN turborepo_lib::package_changes_watcher: changed_packages: Ok(Some({WorkspacePackage { name: Other("form-render"), path: AnchoredSystemPathBuf("packages/form-render") }}))
3 | 2024-08-26T15:24:27.958664Z WARN turborepo_lib::package_changes_watcher: changed_files: {AnchoredSystemPathBuf("packages/form-render/CHANGELOG.md")}
4 | 2024-08-26T15:24:27.958679Z WARN turborepo_lib::package_changes_watcher: changed_packages: Ok(Some({WorkspacePackage { name: Other("form-render"), path: AnchoredSystemPathBuf("packages/form-render") }}))
5 | 2024-08-26T15:26:43.157922Z WARN turborepo_lib::package_changes_watcher: changed_files: {AnchoredSystemPathBuf("packages/form-render/CHANGELOG.md")}
6 | 2024-08-26T15:26:43.157934Z WARN turborepo_lib::package_changes_watcher: changed_packages: Ok(Some({WorkspacePackage { name: Other("form-render"), path: AnchoredSystemPathBuf("packages/form-render") }}))
7 |
--------------------------------------------------------------------------------
/docs/table-render/static/request.ts:
--------------------------------------------------------------------------------
1 | import request from 'umi-request';
2 |
3 | const requestData = (params: any) => {
4 | return request
5 | .get(
6 | 'https://www.fastmock.site/mock/62ab96ff94bc013592db1f67667e9c76/getTableList/api/basic',
7 | { params }
8 | )
9 | .then(res => ({ success: true, data: res.data }))
10 | .catch(() => ({ success: false, data: {} }))
11 | }
12 |
13 |
14 | export const searchApi = async (params) => {
15 | const { success, data } = await requestData(params);
16 | if (success) {
17 | return {
18 | data: data,
19 | total: data.length,
20 | }
21 | } else {
22 | // 必须返回 data 和 total
23 | return {
24 | data: [],
25 | total: 0,
26 | }
27 | }
28 | };
29 |
30 | export const searchApi2 = async (params) => {
31 | const { success, data } = await requestData(params);
32 | if (success) {
33 | return {
34 | data: data.slice(1),
35 | total: data.length - 1,
36 | }
37 | } else {
38 | // 必须返回 data 和 total
39 | return {
40 | data: [],
41 | total: 0,
42 | }
43 | }
44 | };
--------------------------------------------------------------------------------
/widgets/AsyncOptions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@form-render/async-options",
3 | "version": "1.0.0",
4 | "keywords": [
5 | "FormRender",
6 | "Render",
7 | "React",
8 | "Json Schema",
9 | "Ant Design"
10 | ],
11 | "main": "dist/index.js",
12 | "module": "dist/index.esm.js",
13 | "scripts": {
14 | "beta": "npm publish --tag beta",
15 | "build": "father-build",
16 | "prepare": "npm run build",
17 | "prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
18 | "postpublish": "git push --tags",
19 | "release": "npm publish --access public",
20 | "test": "umi-test",
21 | "test:coverage": "umi-test --coverage"
22 | },
23 | "lint-staged": {
24 | "*.{js,jsx,less,md,json}": [
25 | "prettier --write"
26 | ],
27 | "*.ts?(x)": [
28 | "prettier --parser=typescript --write"
29 | ]
30 | },
31 | "dependencies": {
32 | "axios": "^0.21.1"
33 | },
34 | "peerDependencies": {
35 | "antd": "^4.x",
36 | "react": ">=16.8.0"
37 | },
38 | "gitHooks": {
39 | "pre-commit": "lint-staged"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/widgets/RichText/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@form-render/rich-text",
3 | "version": "1.0.2",
4 | "keywords": [
5 | "FormRender",
6 | "Render",
7 | "React",
8 | "Json Schema",
9 | "Ant Design"
10 | ],
11 | "main": "dist/index.js",
12 | "module": "dist/index.esm.js",
13 | "scripts": {
14 | "beta": "npm publish --tag beta",
15 | "build": "father-build",
16 | "prepare": "npm run build",
17 | "prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
18 | "postpublish": "git push --tags",
19 | "release": "npm publish --access public",
20 | "test": "umi-test",
21 | "test:coverage": "umi-test --coverage"
22 | },
23 | "lint-staged": {
24 | "*.{js,jsx,less,md,json}": [
25 | "prettier --write"
26 | ],
27 | "*.ts?(x)": [
28 | "prettier --parser=typescript --write"
29 | ]
30 | },
31 | "dependencies": {
32 | "braft-editor": "^2.3.9"
33 | },
34 | "peerDependencies": {
35 | "antd": "^4.x",
36 | "react": ">=16.8.0"
37 | },
38 | "gitHooks": {
39 | "pre-commit": "lint-staged"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docs/table-render/tabs.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 6
3 | mobile: false
4 | title: 'Tab 数据分类'
5 | group:
6 | title: 最佳展示
7 | order: 2
8 | ---
9 |
10 | # 数据分类
11 | ```jsx
12 | /**
13 | * transform: true
14 | * defaultShowCode: true
15 | * background: 'rgb(245,245,245)'
16 | */
17 | import React, { useRef } from 'react';
18 | import TableRender, { TableContext } from 'table-render';
19 |
20 | import { schema } from './static/search';
21 | import { columns, toolbarRender } from './static/table';
22 | import { searchApi, searchApi2 } from './static/request';
23 |
24 | const Demo = () => {
25 | const tableRef = useRef(null);
26 |
27 | return (
28 | {
34 | console.log('onTabChange');
35 | }}
36 | request={[
37 | { name: '我的', api: searchApi },
38 | { name: '全部', api: searchApi2 }
39 | ]}
40 | columns={columns}
41 | toolbarRender={toolbarRender}
42 | />
43 | )
44 | };
45 |
46 | export default Demo;
47 | ```
48 |
49 |
50 |
--------------------------------------------------------------------------------
/docs/xflow/custom-node-view.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | title: '自定义节点展示'
4 | mobile: false
5 | group:
6 | title: 高级用法
7 | order: 2
8 | ---
9 |
10 | # 自定义节点展示
11 |
12 | 当默认的节点内容展示不满足要求时,可以通过 `nodeWidget` 进行自定义渲染。
13 |
14 | 1. 定义自定义组件
15 | 2. 在 XFlow 组件中通过 `widgets` 属性注册组件
16 | 3. 在节点配置中通过 `nodeWidget` 指定使用的组件
17 |
18 | ```js
19 | // 1.自定义节点
20 | const LLMNodeWidget = ({ data }) => {
21 | const { model, temperature, maxTokens, systemPrompt } = data; // data为配置面板数据
22 | return (
23 |
27 | // 自定义渲染节点内容
28 |
29 | );
30 | };
31 | ```
32 | 注册自定义组件
33 | ```js
34 |
41 |
42 | ```
43 | 在settings中使用自定义组件
44 | ```js
45 | {
46 | type: 'LLM',
47 | title: 'LLM 处理',
48 | icon: {
49 | type: 'icon-model',
50 | bgColor: '#6172F3',
51 | },
52 | nodeWidget: 'LLMNodeWidget' // 3.使用自定义组件
53 | }
54 | ```
55 |
56 |
--------------------------------------------------------------------------------
/packages/x-flow/src/operator/Control/index.less:
--------------------------------------------------------------------------------
1 | .fai-reactflow-control {
2 | display: flex;
3 | align-items: center;
4 | padding: 2px 1px;
5 | border-radius: 8px;
6 | border: 0.5px solid #f3f4f6;
7 | background-color: #fff;
8 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
9 | color: #667085;
10 |
11 | .ant-btn {
12 | display: inline-flex;
13 | align-items: center;
14 | justify-content: center;
15 | }
16 | }
17 |
18 | // .control-item {
19 | // display: flex;
20 | // align-items: center;
21 | // justify-content: center;
22 | // width: 2rem;
23 | // height: 2rem;
24 | // border-radius: 0.5rem;
25 | // cursor: pointer;
26 |
27 | // &.inactive:hover {
28 | // background-color: rgba(0, 0, 0, 0.05);
29 | // color: #374151;
30 | // }
31 |
32 | // &.active {
33 | // background-color: #ecfdf5;
34 | // color: #10b981;
35 | // }
36 |
37 | // &.disabled {
38 | // cursor: not-allowed;
39 | // opacity: 0.5;
40 | // }
41 | // }
42 |
43 | .separator {
44 | margin: 0 4px;
45 | width: 1px;
46 | height:18px;
47 | background-color: #e5e7eb;
48 | }
49 |
--------------------------------------------------------------------------------
/docs/table-render/demo/display/custom-table.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * defaultShowCode: true
3 | */
4 | import React, { useRef } from 'react';
5 | import TableRender, { TableContext } from 'table-render';
6 | import { Alert } from 'antd';
7 |
8 | import { schema } from '../../static/search';
9 | import { columns, toolbarRender } from '../../static/table';
10 | import { searchApi } from '../../static/request';
11 |
12 | const Demo = () => {
13 | const tableRef = useRef(null);
14 |
15 | return (
16 | (
25 |
34 | )}
35 | />
36 | )
37 | };
38 |
39 | export default Demo;
40 |
--------------------------------------------------------------------------------
/packages/table-render/src/core/TableView/widgets.tsx:
--------------------------------------------------------------------------------
1 | import { Tag, Tooltip } from 'antd';
2 | import React from 'react';
3 | import { getDate, getDateTime } from '../../utils';
4 |
5 | const PrompText = ({ text = '', prompText = '' }) => (
6 |
7 | {text}
8 |
9 | );
10 |
11 | export default {
12 | tags: tags => (
13 |
14 | {tags.map(tag => {
15 | return (
16 |
17 | {tag.toUpperCase()}
18 |
19 | );
20 | })}
21 |
22 | ),
23 | dateTime: value => getDateTime(value),
24 | date: value => getDate(value),
25 | tooltip: text => ,
26 | status: value => {
27 | switch (value.status) {
28 | case 'Default':
29 | return {value.text} ;
30 | case 'Error':
31 | return {value.text} ;
32 | case 'Success':
33 | return {value.text} ;
34 | default:
35 | return {value.text} ;
36 | }
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/packages/chart-render/src/widgets/Pie/index.tsx:
--------------------------------------------------------------------------------
1 | import { Pie as AntPie } from '@ant-design/plots';
2 | import { PieConfig } from '@ant-design/plots/es/components/pie';
3 | import React, { FC, memo } from 'react';
4 | import ChartContainer from '../../components/ChartContainer';
5 | import { splitMeta } from '../../utils';
6 | import { useChart } from '../../utils/store';
7 |
8 | export interface IPieProps extends Omit, 'data'> {}
9 |
10 | const Pie: FC = ({ className, style, ...props }) => {
11 | const loading = useChart(state => state.loading);
12 | const { meta, data } = useChart(state => state.dataSource) || {};
13 |
14 | const { metaDim, metaInd } = splitMeta(meta);
15 | const colorField = metaDim[0]?.id;
16 | const angleField = metaInd[0]?.id;
17 |
18 | return (
19 |
20 |
27 |
28 | );
29 | };
30 |
31 | export default memo(Pie);
32 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FSuckNav/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { combineClass } from '../utils/common';
3 | import Tabs from '../components/SuckTabs';
4 |
5 | /**
6 | *
7 | * 自定义 Tabs组件
8 | */
9 | const FSuckNav = (props: any) => {
10 | const {
11 | scrollContainer,
12 | items = [],
13 | tabsId = 'tab',
14 | startY = 68,
15 | className,
16 | style,
17 | fixed = true,
18 | addons,
19 | ...otherProps
20 | } = props;
21 |
22 | const childSchema: any[] = [];
23 | const tabs = items.map((item: any) => {
24 | const { children, ...otherItem } = item;
25 | childSchema.push(children);
26 | return otherItem;
27 | });
28 |
29 | return (
30 |
39 | {childSchema.map((item: any, index: number) =>
40 | addons.renderer({ key: index, schema: item, addons, ...otherProps }),
41 | )}
42 |
43 | );
44 | };
45 |
46 | export default FSuckNav;
47 |
--------------------------------------------------------------------------------
/.dumi/tmp-production/core/pluginConfigJoi.d.ts:
--------------------------------------------------------------------------------
1 | // This file is generated by Umi automatically
2 | // DO NOT CHANGE IT MANUALLY!
3 | // Created by Umi Plugin
4 |
5 | export interface IConfigFromPluginsJoi {
6 | verifyCommit?: {
7 | scope?: string[]
8 | allowEmoji?: boolean
9 | }
10 | run?: {
11 | globals?: string[]
12 | }
13 | logo?: string
14 | themeConfig?: {
15 |
16 | }
17 | extraRehypePlugins?: unknown[]
18 | extraRemarkPlugins?: unknown[]
19 | resolve?: {
20 | docDirs?: unknown[]
21 | atomDirs?: {
22 | type?: string
23 | dir?: string
24 | }[]
25 | entityDirs?: unknown
26 | codeBlockMode?: ("active" | "passive")
27 | entryFile?: string
28 | forceKebabCaseRouting?: boolean
29 | }
30 | autoAlias?: boolean
31 | analytics?: ({
32 | baidu?: string
33 | ga?: string
34 | ga_v2?: string
35 | } | boolean)
36 | locales?: ({
37 | id?: string
38 | name?: string
39 | base?: string
40 | }[] | {
41 | id?: string
42 | name?: string
43 | suffix?: ""
44 | }[])
45 | apiParser?: {
46 | unpkgHost?: string
47 | resolveFilter?: (() => any)
48 | parseOptions?: {
49 |
50 | }
51 | }
52 | assets?: {
53 |
54 | }
55 | sitemap?: {
56 | hostname?: string
57 | exclude?: string[]
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FSteps/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Steps } from 'antd';
3 | import { get } from 'lodash-es';
4 | import { combineClass } from '../utils/common';
5 |
6 | import './index.less';
7 |
8 | const { Step } = Steps;
9 |
10 | const FSteps = (props: any) => {
11 | const {
12 | data = [],
13 | stautsKey = 'status',
14 | titleKey = 'title',
15 | descriptionKey = 'description',
16 | subTitleKey = 'subTitle',
17 | size = 'small',
18 | className,
19 | style,
20 | addons,
21 | ...otherProps
22 | } = props;
23 |
24 | return (
25 |
31 | {data.map((item: any, index: number) => (
32 |
39 | ))}
40 |
41 | );
42 | };
43 |
44 | export default FSteps;
45 |
--------------------------------------------------------------------------------
/packages/data-render/src/widgets/FIconLabel/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import IconLabel from '../components/IconLabel';
3 |
4 | const FIconLabel = (props: any) => {
5 | const {
6 | data,
7 | leftText,
8 | rightText,
9 | icon,
10 | method,
11 | href,
12 | target = '_blank',
13 | addons,
14 | ...otherProps
15 | } = props;
16 |
17 | const parentData = addons.getParentData();
18 | const dataKey = addons.dataKey;
19 |
20 | const handleClick = async (ev: any) => {
21 | if (href) {
22 | if (target === '_self') {
23 | window.location.href = href;
24 | } else {
25 | window.open(href);
26 | }
27 | return;
28 | }
29 | // 传人外置方法,实现按钮点击事件
30 | const func = addons.getMethod(method?.name || method);
31 | func({ dataKey, method, data: parentData }, ev);
32 | };
33 |
34 | return (
35 |
42 | );
43 | };
44 |
45 | export default FIconLabel;
46 |
--------------------------------------------------------------------------------
/packages/form-render/src/models/formDataSkeleton.ts:
--------------------------------------------------------------------------------
1 | import { _cloneDeep, isObjType, isListType } from '../utils/index';
2 |
3 | export const createDataSkeleton = (schema: any, formData?: any) => {
4 | let _formData = _cloneDeep(formData);
5 | let result = _formData;
6 |
7 | if (isObjType(schema)) {
8 | if (_formData === undefined || typeof _formData !== 'object') {
9 | _formData = {};
10 | result = {};
11 | }
12 | Object.keys(schema.properties).forEach(key => {
13 | const childSchema = schema.properties[key];
14 | const childData = _formData[key];
15 | const childResult = createDataSkeleton(childSchema, childData);
16 | result[key] = childResult;
17 | });
18 | } else if (_formData !== undefined) {
19 | // result = _formData;
20 | } else if (schema.default !== undefined) {
21 | result = _cloneDeep(schema.default);
22 | } else if (isListType(schema)) {
23 | result = [createDataSkeleton(schema.items)];
24 | } else if (schema.type === 'boolean' && !schema.widget) {
25 | // result = false;
26 | result = undefined;
27 | } else {
28 | result = undefined;
29 | }
30 | return result;
31 | };
--------------------------------------------------------------------------------
/packages/x-flow/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-present XRender Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/data-render/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-present XRender Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/form-render/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-present XRender Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/table-render/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-present XRender Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tools/schema-builder/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-present XRender Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/form-render-mobile/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-present XRender Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------