├── .cz-config.js
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .prettierrc
├── LICENSE
├── README.md
├── commitlint.config.js
├── favicon.svg
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
├── components
│ ├── GenerateCodeModal.tsx
│ ├── GenerateJsonModal.tsx
│ ├── Icon.tsx
│ ├── MonacoEditor.tsx
│ ├── PreviewModal.tsx
│ ├── SvgIcon.tsx
│ └── UploadModal.tsx
├── config
│ ├── AlertConfig.tsx
│ ├── AutoCompleteConfig.tsx
│ ├── ButtonConfig.tsx
│ ├── CalendarConfig.tsx
│ ├── CascaderConfig.tsx
│ ├── CheckboxConfig.tsx
│ ├── CheckboxGroupConfig.tsx
│ ├── ColConfig.tsx
│ ├── DatePickerConfig.tsx
│ ├── DividerConfig.tsx
│ ├── FormItemLayoutConfig.tsx
│ ├── IconConfig.tsx
│ ├── ImageConfig.tsx
│ ├── InputConfig.tsx
│ ├── InputNumberConfig.tsx
│ ├── LayoutConfig.tsx
│ ├── MentionsConfig.tsx
│ ├── OptionSourceTypeConfig.tsx
│ ├── ParagraphConfig.tsx
│ ├── PasswordConfig.tsx
│ ├── RadioGroupConfig.tsx
│ ├── RangePickerConfig.tsx
│ ├── RateConfig.tsx
│ ├── RowConfig.tsx
│ ├── SearchConfig.tsx
│ ├── SelectConfig.tsx
│ ├── SiderConfig.tsx
│ ├── SliderConfig.tsx
│ ├── SpaceConfig.tsx
│ ├── SwitchConfig.tsx
│ ├── TableConfig.tsx
│ ├── TextAreaConfig.tsx
│ ├── TextConfig.tsx
│ ├── TimePickerConfig.tsx
│ ├── TitleConfig.tsx
│ ├── TreeConfig.tsx
│ ├── TreeSelectConfig.tsx
│ ├── UploadConfig.tsx
│ ├── ValidateRuleConfig.tsx
│ └── index.ts
├── core
│ ├── ComponentsGroup.tsx
│ ├── DesignForm.tsx
│ ├── GenerateForm.tsx
│ ├── GenerateFormItem.tsx
│ ├── GlobalConfig.tsx
│ ├── Header.tsx
│ ├── WidgetConfig.tsx
│ ├── WidgetForm.tsx
│ ├── WidgetFormItem.tsx
│ └── index.ts
├── example
│ ├── assets
│ │ ├── favicon.17e50649.svg
│ │ ├── index.23b5abfa.js
│ │ ├── index.a99868fe.css
│ │ └── vendor.d1a493fe.js
│ └── index.html
├── hooks
│ └── index.ts
├── icons
│ ├── Alert.svg
│ ├── AutoComplete.svg
│ ├── Button.svg
│ ├── Calendar.svg
│ ├── Cascader.svg
│ ├── Checkbox.svg
│ ├── CheckboxGroup.svg
│ ├── Col.svg
│ ├── Copy.svg
│ ├── DatePicker.svg
│ ├── Delete.svg
│ ├── Divider.svg
│ ├── GenerateCode.svg
│ ├── GenerateJson.svg
│ ├── Grid.svg
│ ├── Icon.svg
│ ├── Image.svg
│ ├── Input.svg
│ ├── InputNumber.svg
│ ├── Item.svg
│ ├── Mentions.svg
│ ├── Move.svg
│ ├── Paragraph.svg
│ ├── Password.svg
│ ├── Preview.svg
│ ├── RadioGroup.svg
│ ├── RangePicker.svg
│ ├── Rate.svg
│ ├── Row.svg
│ ├── Search.svg
│ ├── Select.svg
│ ├── Slider.svg
│ ├── Space.svg
│ ├── Switch.svg
│ ├── Table.svg
│ ├── Text.svg
│ ├── TextArea.svg
│ ├── TimePicker.svg
│ ├── Title.svg
│ ├── Tree.svg
│ ├── TreeSelect.svg
│ ├── Typography.svg
│ ├── Upload.svg
│ └── index.ts
├── index.tsx
├── locale
│ └── index.ts
├── store
│ ├── action.ts
│ ├── index.ts
│ └── state.ts
├── styles
│ ├── antd.less
│ ├── index.less
│ └── scrollbar.less
├── types
│ ├── index.d.ts
│ └── types.d.ts
├── utils
│ ├── generateCode.ts
│ ├── index.ts
│ └── options.tsx
└── vite-env.d.ts
├── stylelint.config.js
├── tsconfig.json
└── vite.config.ts
/.cz-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | types: [
3 | { value: 'feat', name: 'feat: 新增功能' },
4 | { value: 'fix', name: 'fix: 修复 bug' },
5 | { value: 'docs', name: 'docs: 文档变更' },
6 | { value: 'style', name: 'style: 代码格式(不影响功能,例如空格、分号等格式修正)' },
7 | { value: 'refactor', name: 'refactor: 代码重构(不包括 bug 修复、功能新增)' },
8 | { value: 'perf', name: 'perf: 性能优化' },
9 | { value: 'test', name: 'test: 添加、修改测试用例' },
10 | { value: 'build', name: 'build: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)' },
11 | { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
12 | { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
13 | { value: 'revert', name: 'revert: 回滚 commit' }
14 | ],
15 | scopes: [
16 | ['components', '组件相关'],
17 | ['hooks', 'hook 相关'],
18 | ['utils', 'utils 相关'],
19 | ['element-ui', '对 element-ui 的调整'],
20 | ['styles', '样式相关'],
21 | ['deps', '项目依赖'],
22 | ['auth', '对 auth 修改'],
23 | ['other', '其他修改'],
24 | ['custom', '以上都不是?我要自定义']
25 | ].map(([value, description]) => {
26 | return {
27 | value,
28 | name: `${value.padEnd(30)} (${description})`
29 | }
30 | }),
31 | messages: {
32 | type: '确保本次提交遵循 Angular 规范!\n选择你要提交的类型:',
33 | scope: '\n选择一个 scope(可选):',
34 | customScope: '请输入自定义的 scope:',
35 | subject: '填写简短精炼的变更描述:\n',
36 | body: '填写更加详细的变更描述(可选)。使用 "|" 换行:\n',
37 | breaking: '列举非兼容性重大的变更(可选):\n',
38 | footer: '列举出所有变更的 ISSUES CLOSED(可选)。 例如: #31, #34:\n',
39 | confirmCommit: '确认提交?'
40 | },
41 | allowBreakingChanges: ['feat', 'fix'],
42 | skipQuestions: ['body', 'footer'],
43 | subjectLimit: 100
44 | }
45 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | example
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es2021: true,
5 | node: true
6 | },
7 | extends: ['plugin:react/recommended', 'airbnb', 'plugin:prettier/recommended'],
8 | parser: '@typescript-eslint/parser',
9 | parserOptions: {
10 | ecmaFeatures: {
11 | jsx: true
12 | },
13 | ecmaVersion: 12,
14 | sourceType: 'module'
15 | },
16 | plugins: ['react', '@typescript-eslint'],
17 | rules: {
18 | 'react/jsx-filename-extension': 'off',
19 | 'react/jsx-props-no-spreading': 'off',
20 | 'react/prop-types': 'off',
21 | 'no-use-before-define': 'off',
22 | 'import/extensions': 'off',
23 | 'import/no-unresolved': 'off',
24 | 'import/no-extraneous-dependencies': 'off',
25 | 'no-plusplus': 'off',
26 | 'no-eval': 'off',
27 | 'no-shadow': 'off',
28 | 'no-unused-vars': 'off',
29 | 'no-restricted-globals': 'off',
30 | 'jsx-a11y/no-static-element-interactions': 'off',
31 | 'jsx-a11y/click-events-have-key-events': 'off',
32 | 'react/function-component-definition': 'off',
33 | 'no-underscore-dangle': 'off',
34 | 'react/jsx-no-useless-fragment': 'off'
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | dist-ssr
5 | *.local
6 | *.lock
7 | *lock.json
8 | .idea
9 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx --no-install commitlint --edit
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "tabWidth": 2,
4 | "printWidth": 180,
5 | "singleQuote": true,
6 | "jsxSingleQuote": false,
7 | "jsxBracketSameLine": false,
8 | "trailingComma": "none",
9 | "bracketSpacing": true,
10 | "semi": false
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 付成伟
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 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional']
3 | }
4 |
--------------------------------------------------------------------------------
/favicon.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
21 | react-form-create
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-form-create",
3 | "description": "一个基于 React + TS 的表单设计器",
4 | "version": "1.0.0",
5 | "main": "dist/react-form-create.umd.js",
6 | "module": "dist/react-form-create.es.js",
7 | "types": "src/types/index.d.ts",
8 | "exports": {
9 | ".": {
10 | "import": "./dist/react-form-create.es.js",
11 | "require": "./dist/react-form-create.umd.js"
12 | },
13 | "./dist/style.css": "./dist/style.css"
14 | },
15 | "homepage": "https://github.com/fuchengwei/react-form-create-base",
16 | "author": {
17 | "name": "fuchengwei"
18 | },
19 | "keywords": [
20 | "Form",
21 | "FormCreate",
22 | "React",
23 | "Antd",
24 | "Drag"
25 | ],
26 | "repository": {
27 | "type": "git",
28 | "url": "git+https://github.com:fuchengwei/react-form-create-base"
29 | },
30 | "files": [
31 | "dist/*",
32 | "src/types/index.d.ts"
33 | ],
34 | "scripts": {
35 | "dev": "vite",
36 | "build": "vite build",
37 | "serve": "vite preview",
38 | "prepare": "husky install"
39 | },
40 | "lint-staged": {
41 | "*.{vue,js,ts,jsx,tsx}": "eslint --fix",
42 | "*.{css,less}": "stylelint 'src/**/*.{css,less}' --fix"
43 | },
44 | "dependencies": {
45 | "@ant-design/icons": "^4.7.0",
46 | "@babel/standalone": "^7.16.7",
47 | "antd": "^4.18.2",
48 | "lodash-es": "^4.17.21",
49 | "moment": "^2.29.1",
50 | "react": "^17.0.2",
51 | "react-color": "^2.19.3",
52 | "react-dom": "^17.0.2",
53 | "sortablejs": "^1.14.0",
54 | "uuid": "^8.3.2"
55 | },
56 | "devDependencies": {
57 | "@commitlint/cli": "^16.0.1",
58 | "@commitlint/config-conventional": "^16.0.0",
59 | "@types/babel__standalone": "^7.1.4",
60 | "@types/lodash-es": "^4.17.6",
61 | "@types/node": "^17.0.8",
62 | "@types/react": "^17.0.38",
63 | "@types/react-color": "^3.0.6",
64 | "@types/react-dom": "^17.0.11",
65 | "@types/sortablejs": "^1.10.7",
66 | "@types/uuid": "^8.3.3",
67 | "@types/vite-plugin-react-svg": "^0.2.0",
68 | "@typescript-eslint/eslint-plugin": "^5.9.0",
69 | "@typescript-eslint/parser": "^5.9.0",
70 | "@vitejs/plugin-react-refresh": "^1.3.6",
71 | "commitizen": "^4.2.4",
72 | "cz-conventional-changelog": "^3.3.0",
73 | "cz-customizable": "^6.3.0",
74 | "eslint": "^8.6.0",
75 | "eslint-config-airbnb": "^19.0.4",
76 | "eslint-config-prettier": "^8.3.0",
77 | "eslint-plugin-import": "^2.25.4",
78 | "eslint-plugin-jsx-a11y": "^6.5.1",
79 | "eslint-plugin-prettier": "^4.0.0",
80 | "eslint-plugin-react": "^7.28.0",
81 | "eslint-plugin-react-hooks": "^4.3.0",
82 | "husky": "^7.0.4",
83 | "less": "^4.1.2",
84 | "lint-staged": "^12.1.5",
85 | "monaco-editor": "^0.32.1",
86 | "prettier": "^2.5.1",
87 | "stylelint": "^14.2.0",
88 | "stylelint-config-recess-order": "^3.0.0",
89 | "stylelint-config-standard": "^24.0.0",
90 | "stylelint-less": "^1.0.1",
91 | "stylelint-order": "^5.0.0",
92 | "typescript": "^4.5.4",
93 | "vite": "^2.7.10",
94 | "vite-plugin-svg-icons": "^1.1.0"
95 | },
96 | "config": {
97 | "commitizen": {
98 | "path": "./node_modules/cz-customizable"
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/components/GenerateCodeModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useContext, useState } from 'react'
2 | import { Modal, ModalProps, message, Tabs } from 'antd'
3 | import MonacoEditor from '@/components/MonacoEditor'
4 | import { DesignContext } from '@/store'
5 | import { copy } from '@/utils'
6 | import generateCode from '@/utils/generateCode'
7 |
8 | const GenerateCodeModal: FC = (props) => {
9 | const [activeKey, setActiveKey] = useState('Component')
10 | const { state } = useContext(DesignContext)
11 |
12 | const handleCopy = () => {
13 | copy(generateCode(activeKey === 'Component' ? 'component' : 'html', state))
14 | message.success('Copy成功')
15 | }
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | export default GenerateCodeModal
32 |
--------------------------------------------------------------------------------
/src/components/GenerateJsonModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useContext } from 'react'
2 | import { Modal, ModalProps, message } from 'antd'
3 | import MonacoEditor from '@/components/MonacoEditor'
4 | import { DesignContext } from '@/store'
5 | import { copy } from '@/utils'
6 |
7 | const GenerateJsonModal: FC = (props) => {
8 | const { state } = useContext(DesignContext)
9 | const monacoValue = JSON.stringify(state, null, 2)
10 |
11 | const handleCopy = () => {
12 | copy(monacoValue)
13 | message.success('Copy成功')
14 | }
15 |
16 | return (
17 | <>
18 |
19 |
20 |
21 | >
22 | )
23 | }
24 |
25 | export default GenerateJsonModal
26 |
--------------------------------------------------------------------------------
/src/components/Icon.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 |
3 | interface Props {
4 | iconName?: string
5 | fontSize?: number
6 | color?: string
7 | className?: string
8 | onClick?: () => void
9 | }
10 |
11 | const Icon: FC = (props) => {
12 | const { iconName, fontSize, color, className, onClick } = props
13 |
14 | return (
15 |
18 | )
19 | }
20 |
21 | Icon.defaultProps = {
22 | iconName: undefined,
23 | fontSize: 40,
24 | color: '',
25 | className: '',
26 | onClick: () => {}
27 | }
28 |
29 | export default Icon
30 |
--------------------------------------------------------------------------------
/src/components/MonacoEditor.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, FC, useEffect, useRef } from 'react'
2 |
3 | interface Props {
4 | value: string
5 | height?: string | number
6 | theme?: string
7 | language?: string
8 | readonly?: boolean
9 | onChange?: (value: string) => void
10 | }
11 |
12 | const MonacoEditor: FC = (props) => {
13 | const { value, language, onChange, height, theme, readonly } = props
14 | const editorRef = useRef(null)
15 |
16 | const monacoEditorDecorator = () => {
17 | const model = window.monaco?.editor.createModel(value, language)
18 | const editorInstance = window.monaco?.editor.create(editorRef.current!, {
19 | model,
20 | theme,
21 | tabSize: 2,
22 | fontSize: 14,
23 | formatOnType: true,
24 | formatOnPaste: true,
25 | automaticLayout: true,
26 | emptySelectionClipboard: true,
27 | scrollBeyondLastLine: true,
28 | readOnly: readonly,
29 | minimap: {
30 | enabled: false
31 | },
32 | scrollbar: {
33 | vertical: 'hidden',
34 | horizontal: 'hidden',
35 | verticalScrollbarSize: 0,
36 | horizontalScrollbarSize: 0,
37 | alwaysConsumeMouseWheel: false
38 | }
39 | })
40 |
41 | editorInstance?.onDidChangeModelContent(() => onChange?.(editorInstance.getValue()))
42 | }
43 |
44 | useEffect(monacoEditorDecorator, [])
45 | return
46 | }
47 |
48 | MonacoEditor.defaultProps = {
49 | height: '100%',
50 | theme: 'vs',
51 | language: undefined,
52 | onChange: undefined,
53 | readonly: false
54 | }
55 |
56 | export default memo(MonacoEditor)
57 |
--------------------------------------------------------------------------------
/src/components/PreviewModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useContext, useRef, useState } from 'react'
2 | import { Modal, ModalProps, message } from 'antd'
3 | import GenerateForm, { GenerateFormRef } from '@/core/GenerateForm'
4 | import MonacoEditor from '@/components/MonacoEditor'
5 | import { DesignContext } from '@/store'
6 | import { copy } from '@/utils'
7 |
8 | const PreviewModal: FC = (props) => {
9 | const [dataModal, setDataModal] = useState(false)
10 | const [monacoValue, setMonacoValue] = useState('')
11 | const ref = useRef(null)
12 |
13 | const { state } = useContext(DesignContext)
14 |
15 | const handleGetData = async () => {
16 | const formValue = await ref.current?.getData()
17 | setMonacoValue(JSON.stringify(formValue, null, 2))
18 | setDataModal(true)
19 | }
20 |
21 | const handleCopy = () => {
22 | copy(monacoValue)
23 | message.success('Copy成功')
24 | }
25 |
26 | return (
27 | <>
28 |
29 |
30 |
31 | setDataModal(false)} okText="Copy" onOk={handleCopy}>
32 |
33 |
34 | >
35 | )
36 | }
37 |
38 | export default PreviewModal
39 |
--------------------------------------------------------------------------------
/src/components/SvgIcon.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, CSSProperties, MouseEvent } from 'react'
2 |
3 | interface Props {
4 | name: string
5 | prefix?: string
6 | color?: string
7 | className?: string
8 | style?: CSSProperties
9 | onClick?: (event: MouseEvent) => void
10 | }
11 |
12 | const SvgIcon: FC = (props) => {
13 | const { name, prefix, color, className, style, onClick } = props
14 | const symbolId = `#${prefix}-${name}`
15 |
16 | return (
17 |
18 |
21 |
22 | )
23 | }
24 |
25 | SvgIcon.defaultProps = {
26 | prefix: 'svg-icon',
27 | color: 'currentColor',
28 | className: '',
29 | style: {},
30 | onClick: () => {}
31 | }
32 |
33 | export default SvgIcon
34 |
--------------------------------------------------------------------------------
/src/components/UploadModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useRef } from 'react'
2 | import { Modal, message } from 'antd'
3 | import MonacoEditor from '@/components/MonacoEditor'
4 | import { useConfig } from '@/hooks'
5 | import { ActionType } from '@/store/action'
6 |
7 | import type { Props } from './StateEditorModal'
8 |
9 | const UploadModal: FC = (props) => {
10 | const { close } = props
11 | const monacoValue = useRef('')
12 | const { dispatch } = useConfig()
13 |
14 | const handleChange = (value: string) => {
15 | monacoValue.current = value
16 | }
17 |
18 | const handleUpload = () => {
19 | try {
20 | dispatch({
21 | type: ActionType.SET_GLOBAL,
22 | payload: JSON.parse(monacoValue.current)
23 | })
24 | message.success('导入成功')
25 | close()
26 | } catch (error) {
27 | message.error('导入失败')
28 | }
29 | }
30 |
31 | return (
32 |
33 |
34 |
35 | )
36 | }
37 |
38 | export default UploadModal
39 |
--------------------------------------------------------------------------------
/src/config/AlertConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Select, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { alertTypeOptions } from '@/utils/options'
5 |
6 | const AlertConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.message')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.description')} />
17 |
18 |
19 |
22 | 警告提示样式
23 | {selectWidgetItem?.config?.type && (
24 | {
27 | event.preventDefault()
28 | handleChange(undefined, 'config.type')
29 | }}
30 | >
31 | 还原
32 |
33 | )}
34 |
35 | }
36 | >
37 |
39 |
40 |
41 | handleChange(checked, 'config.hidden')} />
42 |
43 |
44 |
45 | handleChange(checked, 'config.banner')} />
46 |
47 |
48 |
49 | handleChange(checked, 'config.closable')} />
50 |
51 |
52 |
55 | 是否显示辅助图标
56 | {selectWidgetItem?.config?.type && (
57 | {
60 | event.preventDefault()
61 | handleChange(undefined, 'config.showIcon')
62 | }}
63 | >
64 | 还原
65 |
66 | )}
67 |
68 | }
69 | >
70 | handleChange(checked, 'config.showIcon')} />
71 |
72 | >
73 | )
74 | }
75 |
76 | export default AlertConfig
77 |
--------------------------------------------------------------------------------
/src/config/AutoCompleteConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import OptionSourceTypeConfig from '@/config/OptionSourceTypeConfig'
5 |
6 | const AutoCompleteConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.placeholder')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'config.dropdownClassName')}
24 | />
25 |
26 |
27 |
28 | handleChange(event.target.value, 'config.notFoundContent')}
32 | />
33 |
34 |
35 |
36 |
37 |
38 | handleChange(checked, 'config.hidden')} />
39 |
40 |
41 |
42 | handleChange(checked, 'config.allowClear')} />
43 |
44 |
45 |
46 | handleChange(checked, 'config.autoFocus')} />
47 |
48 |
49 |
50 | handleChange(checked, 'config.backfill')} />
51 |
52 |
53 |
54 | handleChange(checked, 'config.defaultActiveFirstOption')} />
55 |
56 |
57 |
58 | handleChange(checked, 'config.defaultOpen')} />
59 |
60 |
61 |
62 | handleChange(checked, 'config.disabled')} />
63 |
64 | >
65 | )
66 | }
67 |
68 | export default AutoCompleteConfig
69 |
--------------------------------------------------------------------------------
/src/config/ButtonConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Radio, Select, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { buttonShapeOptions, buttonTypeOptions, htmlButtonTypeOptions, sizeOptions } from '@/utils/options'
5 |
6 | const ButtonConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.children')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.href')}
20 | />
21 |
22 |
23 | {selectWidgetItem?.config?.href && (
24 |
25 | handleChange(event.target.value, 'config.target')}
29 | />
30 |
31 | )}
32 |
33 |
34 |
36 |
37 |
40 | 按钮大小
41 | {selectWidgetItem?.config?.size && (
42 | {
45 | event.preventDefault()
46 | handleChange(undefined, 'config.size')
47 | }}
48 | >
49 | 还原
50 |
51 | )}
52 |
53 | }
54 | >
55 | handleChange(event.target.value, 'config.size')}
61 | />
62 |
63 |
64 |
65 | handleChange(event.target.value, 'config.shape')}
71 | />
72 |
73 |
74 |
75 | handleChange(checked, 'config.hidden')} />
76 |
77 |
78 |
79 | handleChange(checked, 'config.block')} />
80 |
81 |
82 |
83 | handleChange(checked, 'config.danger')} />
84 |
85 |
86 |
87 | handleChange(checked, 'config.disabled')} />
88 |
89 |
90 |
91 | handleChange(checked, 'config.ghost')} />
92 |
93 |
94 |
95 | handleChange(checked, 'config.loading')} />
96 |
97 |
98 |
99 | handleChange(event.target.value, 'config.htmlType')}
105 | />
106 |
107 | >
108 | )
109 | }
110 |
111 | export default ButtonConfig
112 |
--------------------------------------------------------------------------------
/src/config/CalendarConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { DatePicker, Form, Switch } from 'antd'
3 | import moment from 'moment'
4 | import { useConfig } from '@/hooks'
5 |
6 | const CalendarConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(dateString, 'config.defaultValue')}
15 | />
16 |
17 |
18 |
19 | handleChange(checked, 'config.hidden')} />
20 |
21 |
22 |
23 | handleChange(checked, 'config.fullscreen')} />
24 |
25 | >
26 | )
27 | }
28 |
29 | export default CalendarConfig
30 |
--------------------------------------------------------------------------------
/src/config/CheckboxConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const CheckboxConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 | <>
10 |
11 | handleChange(event.target.value, 'label')} />
12 |
13 |
14 |
15 | handleChange(event.target.value, 'config.children')} />
16 |
17 |
18 |
19 | handleChange(checked, 'formItemConfig.initialValue')} />
20 |
21 |
22 |
23 | handleChange(checked, 'config.autoFocus')} />
24 |
25 |
26 |
27 | handleChange(checked, 'config.indeterminate')} />
28 |
29 |
30 |
31 | handleChange(checked, 'config.hidden')} />
32 |
33 |
34 |
35 | handleChange(checked, 'config.disabled')} />
36 |
37 | >
38 | )
39 | }
40 |
41 | export default CheckboxConfig
42 |
--------------------------------------------------------------------------------
/src/config/CheckboxGroupConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import OptionSourceTypeConfig from '@/config/OptionSourceTypeConfig'
5 |
6 | const CheckboxGroupConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 |
17 |
18 | handleChange(checked, 'config.hidden')} />
19 |
20 |
21 |
22 | handleChange(checked, 'config.disabled')} />
23 |
24 | >
25 | )
26 | }
27 |
28 | export default CheckboxGroupConfig
29 |
--------------------------------------------------------------------------------
/src/config/ColConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, InputNumber, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const ColConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 | <>
10 |
11 | handleChange(value, 'config.flex')} />
12 |
13 |
14 |
15 | handleChange(value, 'config.offset')} />
16 |
17 |
18 |
19 | handleChange(value, 'config.order')} />
20 |
21 |
22 |
23 | handleChange(value, 'config.pull')} />
24 |
25 |
26 |
27 | handleChange(value, 'config.push')} />
28 |
29 |
30 |
31 | handleChange(value, 'config.span')} />
32 |
33 |
34 |
35 | handleChange(value, 'config.xs')} />
36 |
37 |
38 |
39 | handleChange(value, 'config.sm')} />
40 |
41 |
42 |
43 | handleChange(value, 'config.md')} />
44 |
45 |
46 |
47 | handleChange(value, 'config.lg')} />
48 |
49 |
50 |
51 | handleChange(value, 'config.xl')} />
52 |
53 |
54 |
55 | handleChange(value, 'config.xxl')} />
56 |
57 |
58 |
59 | handleChange(checked, 'config.hidden')} />
60 |
61 | >
62 | )
63 | }
64 |
65 | export default ColConfig
66 |
--------------------------------------------------------------------------------
/src/config/DatePickerConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { DatePicker, Form, Input, Radio, Space, Switch } from 'antd'
3 | import moment from 'moment'
4 | import { useConfig } from '@/hooks'
5 | import { datePickerTypeOptions, sizeOptions } from '@/utils/options'
6 |
7 | const DatePickerConfig = () => {
8 | const { selectWidgetItem, handleChange } = useConfig()
9 |
10 | return (
11 | <>
12 |
13 | handleChange(event.target.value, 'label')} />
14 |
15 |
16 |
17 | handleChange(event.target.value, 'config.placeholder')} />
18 |
19 |
20 |
21 | handleChange(dateString, 'formItemConfig.initialValue')}
25 | />
26 |
27 |
28 |
29 | handleChange(event.target.value, 'config.format')} />
30 |
31 |
32 |
35 | 输入框大小
36 | {selectWidgetItem?.config?.size && (
37 | {
40 | event.preventDefault()
41 | handleChange(undefined, 'config.size')
42 | }}
43 | >
44 | 还原
45 |
46 | )}
47 |
48 | }
49 | >
50 | handleChange(event.target.value, 'config.size')}
56 | />
57 |
58 |
59 |
60 | {
66 | let format: string
67 | switch (event.target.value) {
68 | case 'date':
69 | format = 'YYYY-MM-DD'
70 | break
71 | case 'week':
72 | format = 'YYYY-ww'
73 | break
74 | case 'month':
75 | format = 'YYYY-MM'
76 | break
77 | case 'quarter':
78 | format = 'YYYY-Qo'
79 | break
80 | case 'year':
81 | format = 'YYYY'
82 | break
83 | default:
84 | format = ''
85 | }
86 | handleChange(format, 'config.format')
87 | handleChange(event.target.value, 'config.picker')
88 | }}
89 | />
90 |
91 |
92 |
93 | handleChange(event.target.value, 'config.className')} />
94 |
95 |
96 |
97 | handleChange(event.target.value, 'config.dropdownClassName')} />
98 |
99 |
100 |
101 | handleChange(checked, 'config.hidden')} />
102 |
103 |
104 |
105 | handleChange(checked, 'config.allowClear')} />
106 |
107 |
108 |
109 | handleChange(checked, 'config.autoFocus')} />
110 |
111 |
112 |
113 | handleChange(checked, 'config.bordered')} />
114 |
115 |
116 |
117 | handleChange(checked, 'config.disabled')} />
118 |
119 |
120 |
121 | handleChange(checked, 'config.inputReadOnly')} />
122 |
123 |
124 |
125 | handleChange(checked, 'config.showTime')} />
126 |
127 |
128 |
129 | handleChange(checked, 'config.showNow')} />
130 |
131 |
132 |
133 | handleChange(checked, 'config.showToday')} />
134 |
135 | >
136 | )
137 | }
138 |
139 | export default DatePickerConfig
140 |
--------------------------------------------------------------------------------
/src/config/DividerConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Radio, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { directionTypeOptions, orientationOptions } from '@/utils/options'
5 |
6 | const DividerConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.children')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.orientation')}
22 | />
23 |
24 |
25 |
26 | handleChange(event.target.value, 'config.type')}
32 | />
33 |
34 |
35 |
36 | handleChange(checked, 'config.dashed')} />
37 |
38 |
39 |
40 | handleChange(checked, 'config.plain')} />
41 |
42 |
43 |
44 | handleChange(checked, 'config.hidden')} />
45 |
46 | >
47 | )
48 | }
49 |
50 | export default DividerConfig
51 |
--------------------------------------------------------------------------------
/src/config/FormItemLayoutConfig.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { Form, Radio, Switch, InputNumber, Space } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { labelAlignOptions } from '@/utils/options'
5 |
6 | const FormItemLayoutConfig: FC = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 | 布局配置
12 |
15 | 标签对齐方式
16 | {selectWidgetItem?.formItemConfig?.labelAlign && (
17 | {
20 | event.preventDefault()
21 | handleChange(undefined, 'formItemConfig.labelAlign')
22 | }}
23 | >
24 | 还原
25 |
26 | )}
27 |
28 | }
29 | >
30 | handleChange(event.target.value, 'formItemConfig.labelAlign')}
36 | />
37 |
38 |
39 |
42 | 是否显示label后面的冒号
43 | {selectWidgetItem?.formItemConfig?.colon !== undefined && (
44 | {
47 | event.preventDefault()
48 | handleChange(undefined, 'formItemConfig.colon')
49 | }}
50 | >
51 | 还原
52 |
53 | )}
54 |
55 | }
56 | >
57 | handleChange(checked, 'formItemConfig.colon')} />
58 |
59 |
60 |
63 | 标签文本换行方式
64 | {selectWidgetItem?.formItemConfig?.labelWrap !== undefined && (
65 | {
68 | event.preventDefault()
69 | handleChange(undefined, 'formItemConfig.labelWrap')
70 | }}
71 | >
72 | 还原
73 |
74 | )}
75 |
76 | }
77 | >
78 | handleChange(checked, 'formItemConfig.labelWrap')} />
79 |
80 |
81 |
84 | 标签布局
85 | {selectWidgetItem?.formItemConfig?.labelCol && (
86 | {
89 | event.preventDefault()
90 | handleChange(undefined, 'formItemConfig.labelCol')
91 | }}
92 | >
93 | 还原
94 |
95 | )}
96 |
97 | }
98 | >
99 | span
100 | handleChange(value, 'formItemConfig.labelCol.span')} />
101 | offset
102 | handleChange(value, 'formItemConfig.labelCol.offset')} />
103 |
104 |
105 |
108 | 输入控件布局
109 | {selectWidgetItem?.formItemConfig?.wrapperCol && (
110 | {
113 | event.preventDefault()
114 | handleChange(undefined, 'formItemConfig.wrapperCol')
115 | }}
116 | >
117 | 还原
118 |
119 | )}
120 |
121 | }
122 | >
123 | span
124 | handleChange(value, 'formItemConfig.wrapperCol.span')} />
125 | offset
126 | handleChange(value, 'formItemConfig.wrapperCol.offset')} />
127 |
128 | >
129 | )
130 | }
131 |
132 | export default FormItemLayoutConfig
133 |
--------------------------------------------------------------------------------
/src/config/IconConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Switch } from 'antd'
3 | import { SketchPicker } from 'react-color'
4 | import { useConfig } from '@/hooks'
5 |
6 | const IconConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.iconName')} />
13 |
14 |
15 |
16 | `${value}px`}
19 | value={selectWidgetItem?.config?.fontSize}
20 | onChange={(value) => handleChange(value, 'config.fontSize')}
21 | />
22 |
23 |
24 |
25 | handleChange(color.hex, 'config.color')} />
26 |
27 |
28 |
29 | handleChange(checked, 'config.hidden')} />
30 |
31 | >
32 | )
33 | }
34 |
35 | export default IconConfig
36 |
--------------------------------------------------------------------------------
/src/config/ImageConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const ImageConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 | <>
10 |
11 | handleChange(event.target.value, 'config.src')} />
12 |
13 |
14 |
15 | handleChange(event.target.value, 'config.fallback')} />
16 |
17 |
18 |
19 | handleChange(event.target.value, 'config.alt')} />
20 |
21 |
22 |
23 | handleChange(value, 'config.width')} />
24 |
25 |
26 |
27 | handleChange(value, 'config.height')} />
28 |
29 |
30 |
31 | handleChange(checked, 'config.hidden')} />
32 |
33 | >
34 | )
35 | }
36 |
37 | export default ImageConfig
38 |
--------------------------------------------------------------------------------
/src/config/InputConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { sizeOptions } from '@/utils/options'
5 |
6 | const InputConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.placeholder')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'formItemConfig.initialValue')}
24 | />
25 |
26 |
27 |
28 | handleChange(event.target.value, 'config.addonBefore')} />
29 |
30 |
31 |
32 | handleChange(event.target.value, 'config.addonAfter')} />
33 |
34 |
35 |
36 | handleChange(event.target.value, 'config.prefix')} />
37 |
38 |
39 |
40 | handleChange(event.target.value, 'config.suffix')} />
41 |
42 |
43 |
46 | 控件大小
47 | {selectWidgetItem?.config?.size && (
48 | {
51 | event.preventDefault()
52 | handleChange(undefined, 'config.size')
53 | }}
54 | >
55 | 还原
56 |
57 | )}
58 |
59 | }
60 | >
61 | handleChange(event.target.value, 'config.size')}
67 | />
68 |
69 |
70 |
71 | handleChange(value, 'config.maxLength')} />
72 |
73 |
74 |
75 | handleChange(checked, 'config.hidden')} />
76 |
77 |
78 |
79 | handleChange(checked, 'config.allowClear')} />
80 |
81 |
82 |
83 | handleChange(checked, 'config.bordered')} />
84 |
85 |
86 |
87 | handleChange(checked, 'config.disabled')} />
88 |
89 |
90 |
91 | handleChange(checked, 'config.showCount')} />
92 |
93 | >
94 | )
95 | }
96 |
97 | export default InputConfig
98 |
--------------------------------------------------------------------------------
/src/config/InputNumberConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { sizeOptions } from '@/utils/options'
5 |
6 | const InputNumberConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(value, 'formItemConfig.initialValue')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'config.addonBefore')} />
21 |
22 |
23 |
24 | handleChange(event.target.value, 'config.addonAfter')} />
25 |
26 |
27 |
28 | handleChange(event.target.value, 'config.prefix')} />
29 |
30 |
31 |
32 | handleChange(value, 'config.step')} />
33 |
34 |
35 |
36 | handleChange(value, 'config.precision')} />
37 |
38 |
39 |
40 | handleChange(event.target.value, 'config.decimalSeparator')} />
41 |
42 |
43 |
46 | 控件大小
47 | {selectWidgetItem?.config?.size && (
48 | {
51 | event.preventDefault()
52 | handleChange(undefined, 'config.size')
53 | }}
54 | >
55 | 还原
56 |
57 | )}
58 |
59 | }
60 | >
61 | handleChange(event.target.value, 'config.size')}
67 | />
68 |
69 |
70 |
71 | handleChange(value, 'config.max')} />
72 |
73 |
74 |
75 | handleChange(value, 'config.min')} />
76 |
77 |
78 |
79 | handleChange(checked, 'config.hidden')} />
80 |
81 |
82 |
83 | handleChange(checked, 'config.autoFocus')} />
84 |
85 |
86 |
87 | handleChange(checked, 'config.bordered')} />
88 |
89 |
90 |
91 | handleChange(checked, 'config.controls')} />
92 |
93 |
94 |
95 | handleChange(checked, 'config.disabled')} />
96 |
97 |
98 |
99 | handleChange(checked, 'config.keyboard')} />
100 |
101 |
102 |
103 | handleChange(checked, 'config.readOnly')} />
104 |
105 |
106 |
107 | handleChange(checked, 'config.stringMode')} />
108 |
109 | >
110 | )
111 | }
112 |
113 | export default InputNumberConfig
114 |
--------------------------------------------------------------------------------
/src/config/LayoutConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const LayoutConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 |
10 | handleChange(checked, 'config.hidden')} />
11 |
12 | )
13 | }
14 |
15 | export default LayoutConfig
16 |
--------------------------------------------------------------------------------
/src/config/MentionsConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Radio, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import OptionSourceTypeConfig from '@/config/OptionSourceTypeConfig'
5 | import { mentionsPlacementOptions } from '@/utils/options'
6 |
7 | const MentionsConfig = () => {
8 | const { selectWidgetItem, handleChange } = useConfig()
9 |
10 | return (
11 | <>
12 |
13 | handleChange(event.target.value, 'label')} />
14 |
15 |
16 |
17 | handleChange(event.target.value, 'config.placeholder')} />
18 |
19 |
20 |
21 | handleChange(event.target.value, 'config.notFoundContent')} />
22 |
23 |
24 |
25 | handleChange(event.target.value, 'config.prefix')} />
26 |
27 |
28 |
29 | handleChange(event.target.value, 'config.split')} />
30 |
31 |
32 |
33 | handleChange(event.target.value, 'config.placement')}
39 | />
40 |
41 |
42 |
43 |
44 |
45 | handleChange(checked, 'config.hidden')} />
46 |
47 |
48 |
49 | handleChange(checked, 'config.autoFocus')} />
50 |
51 |
52 |
53 | handleChange(checked, 'config.autoSize')} />
54 |
55 |
56 |
57 | handleChange(checked, 'config.disabled')} />
58 |
59 |
60 |
61 | handleChange(checked, 'config.readOnly')} />
62 |
63 | >
64 | )
65 | }
66 |
67 | export default MentionsConfig
68 |
--------------------------------------------------------------------------------
/src/config/ParagraphConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Select, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { textTypeOptions } from '@/utils/options'
5 |
6 | const ParagraphConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.children')} />
13 |
14 |
15 |
16 |
18 |
19 |
20 | handleChange(checked, 'config.hidden')} />
21 |
22 |
23 |
24 | handleChange(checked, 'config.code')} />
25 |
26 |
27 |
28 | handleChange(checked, 'config.copyable')} />
29 |
30 |
31 |
32 | handleChange(checked, 'config.delete')} />
33 |
34 |
35 |
36 | handleChange(checked, 'config.disabled')} />
37 |
38 |
39 |
40 | handleChange(checked, 'config.editable')} />
41 |
42 |
43 |
44 | handleChange(checked, 'config.ellipsis')} />
45 |
46 |
47 |
48 | handleChange(checked, 'config.mark')} />
49 |
50 |
51 |
52 | handleChange(checked, 'config.strong')} />
53 |
54 |
55 |
56 | handleChange(checked, 'config.italic')} />
57 |
58 |
59 |
60 | handleChange(checked, 'config.underline')} />
61 |
62 | >
63 | )
64 | }
65 |
66 | export default ParagraphConfig
67 |
--------------------------------------------------------------------------------
/src/config/PasswordConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { sizeOptions } from '@/utils/options'
5 |
6 | const PasswordConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.placeholder')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'formItemConfig.initialValue')}
24 | />
25 |
26 |
27 |
28 | handleChange(event.target.value, 'config.addonBefore')} />
29 |
30 |
31 |
32 | handleChange(event.target.value, 'config.addonAfter')} />
33 |
34 |
35 |
36 | handleChange(event.target.value, 'config.prefix')} />
37 |
38 |
39 |
42 | 控件大小
43 | {selectWidgetItem?.config?.size && (
44 | {
47 | event.preventDefault()
48 | handleChange(undefined, 'config.size')
49 | }}
50 | >
51 | 还原
52 |
53 | )}
54 |
55 | }
56 | >
57 | handleChange(event.target.value, 'config.size')}
63 | />
64 |
65 |
66 |
67 | handleChange(value, 'config.maxLength')} />
68 |
69 |
70 |
71 | handleChange(checked, 'config.hidden')} />
72 |
73 |
74 |
75 | handleChange(checked, 'config.visibilityToggle')} />
76 |
77 |
78 |
79 | handleChange(checked, 'config.bordered')} />
80 |
81 |
82 |
83 | handleChange(checked, 'config.disabled')} />
84 |
85 |
86 |
87 | handleChange(checked, 'config.showCount')} />
88 |
89 | >
90 | )
91 | }
92 |
93 | export default PasswordConfig
94 |
--------------------------------------------------------------------------------
/src/config/RadioGroupConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Radio, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import OptionSourceTypeConfig from '@/config/OptionSourceTypeConfig'
5 | import { radioGroupButtonStyleOptions, radioGroupOptionTypeOptions, sizeOptions } from '@/utils/options'
6 |
7 | const RadioGroupConfig = () => {
8 | const { selectWidgetItem, handleChange } = useConfig()
9 |
10 | return (
11 | <>
12 |
13 | handleChange(event.target.value, 'label')} />
14 |
15 |
16 |
17 | handleChange(event.target.value, 'config.optionType')}
23 | />
24 |
25 |
26 |
27 | handleChange(event.target.value, 'config.buttonStyle')}
33 | />
34 |
35 |
36 |
39 | 大小
40 | {selectWidgetItem?.config?.size && (
41 | {
44 | event.preventDefault()
45 | handleChange(undefined, 'config.size')
46 | }}
47 | >
48 | 还原
49 |
50 | )}
51 |
52 | }
53 | >
54 | handleChange(event.target.value, 'config.size')}
60 | />
61 |
62 |
63 |
64 |
65 |
66 | handleChange(checked, 'config.hidden')} />
67 |
68 |
69 |
70 | handleChange(checked, 'config.disabled')} />
71 |
72 | >
73 | )
74 | }
75 |
76 | export default RadioGroupConfig
77 |
--------------------------------------------------------------------------------
/src/config/RateConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const RateConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 | <>
10 |
11 | handleChange(event.target.value, 'label')} />
12 |
13 |
14 |
15 | handleChange(value, 'formItemConfig.initialValue')} />
16 |
17 |
18 |
19 | handleChange(value, 'config.count')} />
20 |
21 |
22 |
23 | handleChange(event.target.value || undefined, 'config.character')} />
24 |
25 |
26 |
27 | handleChange(event.target.value, 'config.className')} />
28 |
29 |
30 |
31 | handleChange(event.target.value.split(','), 'config.tooltips')} />
32 |
33 |
34 |
35 | handleChange(checked, 'config.allowClear')} />
36 |
37 |
38 |
39 | handleChange(checked, 'config.allowHalf')} />
40 |
41 |
42 |
43 | handleChange(checked, 'config.autoFocus')} />
44 |
45 |
46 |
47 | handleChange(checked, 'config.hidden')} />
48 |
49 |
50 |
51 | handleChange(checked, 'config.disabled')} />
52 |
53 | >
54 | )
55 | }
56 |
57 | export default RateConfig
58 |
--------------------------------------------------------------------------------
/src/config/RowConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, InputNumber, Radio, Select, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { alignOptions, justifyOptions } from '@/utils/options'
5 |
6 | const RowConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.align')}
18 | />
19 |
20 |
21 |
22 |
24 |
25 |
26 | handleChange(value ?? 0, 'config.gutter')} />
27 |
28 |
29 |
30 | handleChange(checked, 'config.wrap')} />
31 |
32 |
33 |
34 | handleChange(checked, 'config.hidden')} />
35 |
36 | >
37 | )
38 | }
39 |
40 | export default RowConfig
41 |
--------------------------------------------------------------------------------
/src/config/SearchConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { sizeOptions } from '@/utils/options'
5 |
6 | const SearchConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.placeholder')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'formItemConfig.initialValue')}
24 | />
25 |
26 |
27 |
28 | handleChange(event.target.value, 'config.addonBefore')} />
29 |
30 |
31 |
32 | handleChange(event.target.value, 'config.addonAfter')} />
33 |
34 |
35 |
36 | handleChange(event.target.value, 'config.prefix')} />
37 |
38 |
39 |
40 | handleChange(event.target.value, 'config.suffix')} />
41 |
42 |
43 |
46 | 控件大小
47 | {selectWidgetItem?.config?.size && (
48 | {
51 | event.preventDefault()
52 | handleChange(undefined, 'config.size')
53 | }}
54 | >
55 | 还原
56 |
57 | )}
58 |
59 | }
60 | >
61 | handleChange(event.target.value, 'config.size')}
67 | />
68 |
69 |
70 |
71 | handleChange(value, 'config.maxLength')} />
72 |
73 |
74 |
75 | handleChange(checked, 'config.hidden')} />
76 |
77 |
78 |
79 | handleChange(checked, 'config.enterButton')} />
80 |
81 |
82 |
83 | handleChange(checked, 'config.allowClear')} />
84 |
85 |
86 |
87 | handleChange(checked, 'config.bordered')} />
88 |
89 |
90 |
91 | handleChange(checked, 'config.disabled')} />
92 |
93 |
94 |
95 | handleChange(checked, 'config.showCount')} />
96 |
97 | >
98 | )
99 | }
100 |
101 | export default SearchConfig
102 |
--------------------------------------------------------------------------------
/src/config/SiderConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Select, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { breakpointOptions, themeOptions } from '@/utils/options'
5 |
6 | const SiderConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.width')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.collapsedWidth')} />
17 |
18 |
19 |
20 |
22 |
23 |
24 | handleChange(event.target.value, 'config.theme')}
30 | />
31 |
32 |
33 |
34 | handleChange(checked, 'config.hidden')} />
35 |
36 |
37 |
38 | handleChange(checked, 'config.collapsible')} />
39 |
40 |
41 |
42 | handleChange(checked, 'config.defaultCollapsed')} />
43 |
44 |
45 |
46 | handleChange(checked, 'config.reverseArrow')} />
47 |
48 | >
49 | )
50 | }
51 |
52 | export default SiderConfig
53 |
--------------------------------------------------------------------------------
/src/config/SliderConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const SliderConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 | <>
10 |
11 | handleChange(event.target.value, 'label')} />
12 |
13 |
14 |
15 | {selectWidgetItem?.config?.range ? (
16 | <>
17 | handleChange(value || 0, 'formItemConfig.initialValue[0]')} />
18 | handleChange(value || 0, 'formItemConfig.initialValue[1]')} />
19 | >
20 | ) : (
21 | handleChange(value || 0, 'formItemConfig.initialValue')} />
22 | )}
23 |
24 |
25 |
26 | handleChange(value, 'config.max')} />
27 |
28 |
29 |
30 | handleChange(value, 'config.min')} />
31 |
32 |
33 |
34 | handleChange(value, 'config.step')} />
35 |
36 |
37 |
38 | handleChange(checked, 'config.allowClear')} />
39 |
40 |
41 |
42 | handleChange(checked, 'config.dots')} />
43 |
44 |
45 |
46 | {
49 | handleChange(checked ? [0, 0] : 0, 'formItemConfig.initialValue')
50 | handleChange(checked ? 'array' : 'number', 'formItemConfig.rules[0].type')
51 | setTimeout(() => handleChange(checked, 'config.range'), 100)
52 | }}
53 | />
54 |
55 |
56 |
57 | handleChange(checked, 'config.reverse')} />
58 |
59 |
60 |
63 | 是否始终显示Tooltip
64 | {selectWidgetItem?.config?.tooltipVisible !== undefined && (
65 | {
68 | event.preventDefault()
69 | handleChange(undefined, 'config.tooltipVisible')
70 | }}
71 | >
72 | 还原
73 |
74 | )}
75 |
76 | }
77 | >
78 | handleChange(checked, 'config.tooltipVisible')} />
79 |
80 |
81 |
82 | handleChange(checked, 'config.hidden')} />
83 |
84 |
85 |
86 | handleChange(checked, 'config.disabled')} />
87 |
88 | >
89 | )
90 | }
91 |
92 | export default SliderConfig
93 |
--------------------------------------------------------------------------------
/src/config/SpaceConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Radio, Select, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { directionTypeOptions, sizeOptions, spaceAlignOptions } from '@/utils/options'
5 |
6 | const SpaceConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.direction')}
18 | />
19 |
20 |
21 |
24 | 间距大小
25 | {selectWidgetItem?.config?.size && (
26 | {
29 | event.preventDefault()
30 | handleChange(undefined, 'config.size')
31 | }}
32 | >
33 | 还原
34 |
35 | )}
36 |
37 | }
38 | >
39 | handleChange(event.target.value, 'config.size')}
45 | />
46 |
47 |
48 |
49 |
51 |
52 |
53 | handleChange(checked, 'config.hidden')} />
54 |
55 |
56 |
57 | handleChange(checked, 'config.wrap')} />
58 |
59 | >
60 | )
61 | }
62 |
63 | export default SpaceConfig
64 |
--------------------------------------------------------------------------------
/src/config/SwitchConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Radio, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { switchSizeOptions } from '@/utils/options'
5 |
6 | const SwitchConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(checked, 'formItemConfig.initialValue')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'config.className')} />
21 |
22 |
23 |
24 | handleChange(event.target.value, 'config.checkedChildren')} />
25 |
26 |
27 |
28 | handleChange(event.target.value, 'config.unCheckedChildren')} />
29 |
30 |
31 |
32 | handleChange(event.target.value, 'config.size')}
38 | />
39 |
40 |
41 |
42 | handleChange(checked, 'config.autoFocus')} />
43 |
44 |
45 |
46 | handleChange(checked, 'config.hidden')} />
47 |
48 |
49 |
50 | handleChange(checked, 'config.disabled')} />
51 |
52 | >
53 | )
54 | }
55 |
56 | export default SwitchConfig
57 |
--------------------------------------------------------------------------------
/src/config/TableConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Radio, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { tableSizeOptions } from '@/utils/options'
5 |
6 | const TableConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.rowKey')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.size')}
22 | />
23 |
24 |
25 |
26 | handleChange(checked, 'config.hidden')} />
27 |
28 |
29 |
30 | handleChange(checked, 'config.bordered')} />
31 |
32 |
33 |
34 | handleChange(checked, 'config.showHeader')} />
35 |
36 |
37 |
38 | handleChange(checked, 'config.showSorterTooltip')} />
39 |
40 | >
41 | )
42 | }
43 |
44 | export default TableConfig
45 |
--------------------------------------------------------------------------------
/src/config/TextAreaConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Space, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { sizeOptions } from '@/utils/options'
5 |
6 | const TextAreaConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(event.target.value, 'config.placeholder')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'formItemConfig.initialValue')}
24 | />
25 |
26 |
27 |
30 | 控件大小
31 | {selectWidgetItem?.config?.size && (
32 | {
35 | event.preventDefault()
36 | handleChange(undefined, 'config.size')
37 | }}
38 | >
39 | 还原
40 |
41 | )}
42 |
43 | }
44 | >
45 | handleChange(event.target.value, 'config.size')}
51 | />
52 |
53 |
54 |
55 | handleChange(value, 'config.maxLength')} />
56 |
57 |
58 |
59 | handleChange(checked, 'config.autoSize')} />
60 |
61 |
62 |
63 | handleChange(checked, 'config.hidden')} />
64 |
65 |
66 |
67 | handleChange(checked, 'config.allowClear')} />
68 |
69 |
70 |
71 | handleChange(checked, 'config.bordered')} />
72 |
73 |
74 |
75 | handleChange(checked, 'config.disabled')} />
76 |
77 |
78 |
79 | handleChange(checked, 'config.showCount')} />
80 |
81 | >
82 | )
83 | }
84 |
85 | export default TextAreaConfig
86 |
--------------------------------------------------------------------------------
/src/config/TextConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Select, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { textTypeOptions } from '@/utils/options'
5 |
6 | const TextConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.children')} />
13 |
14 |
15 |
16 |
18 |
19 |
20 | handleChange(checked, 'config.code')} />
21 |
22 |
23 |
24 | handleChange(checked, 'config.copyable')} />
25 |
26 |
27 |
28 | handleChange(checked, 'config.delete')} />
29 |
30 |
31 |
32 | handleChange(checked, 'config.hidden')} />
33 |
34 |
35 |
36 | handleChange(checked, 'config.disabled')} />
37 |
38 |
39 |
40 | handleChange(checked, 'config.editable')} />
41 |
42 |
43 |
44 | handleChange(checked, 'config.ellipsis')} />
45 |
46 |
47 |
48 | handleChange(checked, 'config.keyboard')} />
49 |
50 |
51 |
52 | handleChange(checked, 'config.mark')} />
53 |
54 |
55 |
56 | handleChange(checked, 'config.strong')} />
57 |
58 |
59 |
60 | handleChange(checked, 'config.italic')} />
61 |
62 |
63 |
64 | handleChange(checked, 'config.underline')} />
65 |
66 | >
67 | )
68 | }
69 |
70 | export default TextConfig
71 |
--------------------------------------------------------------------------------
/src/config/TitleConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, Select, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { levelOptions, textTypeOptions } from '@/utils/options'
5 |
6 | const TitleConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'config.children')} />
13 |
14 |
15 |
16 |
18 |
19 |
20 |
22 |
23 |
24 | handleChange(checked, 'config.code')} />
25 |
26 |
27 |
28 | handleChange(checked, 'config.copyable')} />
29 |
30 |
31 |
32 | handleChange(checked, 'config.delete')} />
33 |
34 |
35 |
36 | handleChange(checked, 'config.hidden')} />
37 |
38 |
39 |
40 | handleChange(checked, 'config.disabled')} />
41 |
42 |
43 |
44 | handleChange(checked, 'config.editable')} />
45 |
46 |
47 |
48 | handleChange(checked, 'config.ellipsis')} />
49 |
50 |
51 |
52 | handleChange(checked, 'config.mark')} />
53 |
54 |
55 |
56 | handleChange(checked, 'config.strong')} />
57 |
58 |
59 |
60 | handleChange(checked, 'config.italic')} />
61 |
62 |
63 |
64 | handleChange(checked, 'config.underline')} />
65 |
66 | >
67 | )
68 | }
69 |
70 | export default TitleConfig
71 |
--------------------------------------------------------------------------------
/src/config/TreeConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 |
5 | const TreeConfig = () => {
6 | const { selectWidgetItem, handleChange } = useConfig()
7 |
8 | return (
9 | <>
10 |
11 | handleChange(checked, 'config.hidden')} />
12 |
13 |
14 |
15 | handleChange(checked, 'config.autoExpandParent')} />
16 |
17 |
18 |
19 | handleChange(checked, 'config.blockNode')} />
20 |
21 |
22 |
23 | handleChange(checked, 'config.checkable')} />
24 |
25 |
26 |
27 | handleChange(checked, 'config.checkStrictly')} />
28 |
29 |
30 |
31 | handleChange(checked, 'config.defaultExpandAll')} />
32 |
33 |
34 |
35 | handleChange(checked, 'config.defaultExpandParent')} />
36 |
37 |
38 |
39 | handleChange(checked, 'config.disabled')} />
40 |
41 |
42 |
43 | handleChange(checked, 'config.draggable')} />
44 |
45 |
46 |
47 | handleChange(checked, 'config.multiple')} />
48 |
49 |
50 |
51 | handleChange(checked, 'config.selectable')} />
52 |
53 |
54 |
55 | handleChange(checked, 'config.showLine')} />
56 |
57 |
58 |
59 | handleChange(checked, 'config.virtual')} />
60 |
61 | >
62 | )
63 | }
64 |
65 | export default TreeConfig
66 |
--------------------------------------------------------------------------------
/src/config/UploadConfig.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Form, Input, InputNumber, Radio, Switch } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { uploadListTypeOptions, uploadRequestMethodOptions } from '@/utils/options'
5 |
6 | const UploadConfig = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 |
12 | handleChange(event.target.value, 'label')} />
13 |
14 |
15 |
16 | handleChange(event.target.value || undefined, 'config.accept')} />
17 |
18 |
19 |
20 | handleChange(event.target.value, 'config.action')} />
21 |
22 |
23 |
24 | handleChange(event.target.value, 'config.name')} />
25 |
26 |
27 |
28 | handleChange(value || undefined, 'config.maxCount')} />
29 |
30 |
31 |
32 | handleChange(event.target.value, 'config.method')}
38 | />
39 |
40 |
41 |
42 | handleChange(event.target.value, 'config.listType')}
48 | />
49 |
50 |
51 |
52 | handleChange(checked, 'config.hidden')} />
53 |
54 |
55 |
56 | handleChange(checked, 'config.drop')} />
57 |
58 |
59 |
60 | handleChange(checked, 'config.directory')} />
61 |
62 |
63 |
64 | handleChange(checked, 'config.multiple')} />
65 |
66 |
67 |
68 | handleChange(checked, 'config.openFileDialogOnClick')} />
69 |
70 |
71 |
72 | handleChange(checked, 'config.showUploadList')} />
73 |
74 |
75 |
76 | handleChange(checked, 'config.withCredentials')} />
77 |
78 |
79 |
80 | handleChange(checked, 'config.disabled')} />
81 |
82 | >
83 | )
84 | }
85 |
86 | export default UploadConfig
87 |
--------------------------------------------------------------------------------
/src/config/ValidateRuleConfig.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { Form, Radio, Switch, Select, Space, Input, InputNumber } from 'antd'
3 | import { useConfig } from '@/hooks'
4 | import { validateTriggerOptions, validateTypeOptions } from '@/utils/options'
5 |
6 | const ValidateRuleConfig: FC = () => {
7 | const { selectWidgetItem, handleChange } = useConfig()
8 |
9 | return (
10 | <>
11 | 验证规则
12 |
13 | handleChange(event.target.value, 'formItemConfig.rules[0].validateTrigger')}
19 | />
20 |
21 |
22 | handleChange(checked, 'formItemConfig.rules[0].required')} />
23 |
24 |
25 | handleChange(checked, 'formItemConfig.rules[0].warningOnly')} />
26 |
27 |
28 | handleChange(checked, 'formItemConfig.rules[0].whitespace')} />
29 |
30 |
31 |
33 |
34 | handleChange(event.target.value, 'formItemConfig.rules[0].message')}
38 | />
39 |
40 |
43 | 字段长度
44 | {selectWidgetItem?.formItemConfig?.rules[0].len !== undefined && (
45 | {
48 | event.preventDefault()
49 | handleChange(undefined, 'formItemConfig.rules[0].len')
50 | }}
51 | >
52 | 还原
53 |
54 | )}
55 |
56 | }
57 | >
58 | handleChange(value, 'formItemConfig.rules[0].len')}
63 | />
64 |
65 |
68 | 最大长度
69 | {selectWidgetItem?.formItemConfig?.rules[0].max !== undefined && (
70 | {
73 | event.preventDefault()
74 | handleChange(undefined, 'formItemConfig.rules[0].max')
75 | }}
76 | >
77 | 还原
78 |
79 | )}
80 |
81 | }
82 | >
83 | handleChange(value, 'formItemConfig.rules[0].max')}
88 | />
89 |
90 |
93 | 最小长度
94 | {selectWidgetItem?.formItemConfig?.rules[0].min !== undefined && (
95 | {
98 | event.preventDefault()
99 | handleChange(undefined, 'formItemConfig.rules[0].min')
100 | }}
101 | >
102 | 还原
103 |
104 | )}
105 |
106 | }
107 | >
108 | handleChange(value, 'formItemConfig.rules[0].min')}
113 | />
114 |
115 |
116 | handleChange(event.target.value, 'formItemConfig.rules[0].pattern')} />
117 |
118 | >
119 | )
120 | }
121 |
122 | export default ValidateRuleConfig
123 |
--------------------------------------------------------------------------------
/src/core/ComponentsGroup.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import Sortable from 'sortablejs'
3 | import SvgIcon from '@/components/SvgIcon'
4 |
5 | import type { ComponentGroup } from '@/config'
6 |
7 | interface Props {
8 | componentGroup: ComponentGroup
9 | }
10 |
11 | const ComponentsGroup: FC = (props) => {
12 | const {
13 | componentGroup: { title, components }
14 | } = props
15 |
16 | const sortableGroupDecorator = (instance: HTMLUListElement | null) => {
17 | if (instance) {
18 | const options: Sortable.Options = {
19 | sort: false,
20 | ghostClass: 'ghost',
21 | group: {
22 | name: 'people',
23 | pull: 'clone',
24 | put: false
25 | },
26 | setData: (dataTransfer, dragEl) => {
27 | dataTransfer.setData('SortableDataClone', JSON.stringify(components[parseInt(dragEl.dataset.index!, 10)]))
28 | }
29 | }
30 |
31 | Sortable.create(instance, options)
32 | }
33 | }
34 |
35 | return (
36 | <>
37 | {title}
38 |
48 | >
49 | )
50 | }
51 |
52 | export default ComponentsGroup
53 |
--------------------------------------------------------------------------------
/src/core/DesignForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useMemo, useState, forwardRef, useImperativeHandle } from 'react'
2 | import { Layout, Form, message } from 'antd'
3 |
4 | import ComponentsGroup from './ComponentsGroup'
5 | import Header from './Header'
6 | import WidgetForm from './WidgetForm'
7 | import WidgetConfig from './WidgetConfig'
8 | import GlobalConfig from './GlobalConfig'
9 |
10 | import { DesignContext, DesignProvider } from '@/store'
11 | import { ActionType } from '@/store/action'
12 | import { componentsGroup } from '@/config'
13 | import generateCode from '@/utils/generateCode'
14 |
15 | const { Content, Sider } = Layout
16 |
17 | export interface DesignFormProps {
18 | uploadJson?: boolean
19 | clearable?: boolean
20 | preview?: boolean
21 | generateJson?: boolean
22 | generateCode?: boolean
23 | }
24 |
25 | export interface DesignFormRef {
26 | getJson: () => string
27 | setJson: (value: string) => void
28 | clear: () => void
29 | getTemplate: (type: 'component' | 'html') => string
30 | }
31 |
32 | const DesignForm = forwardRef((props, ref) => {
33 | const { state, dispatch } = useContext(DesignContext)
34 | const [formInstance] = Form.useForm()
35 |
36 | const [currentTab, setCurrentTab] = useState<'Global' | 'Local'>('Global')
37 |
38 | useImperativeHandle(ref, () => ({
39 | getJson: () => JSON.stringify(state),
40 | setJson: (value) => {
41 | try {
42 | dispatch({
43 | type: ActionType.SET_GLOBAL,
44 | payload: JSON.parse(value)
45 | })
46 | } catch (error) {
47 | message.error('设置 JSON 出错')
48 | }
49 | },
50 | clear: () => {
51 | dispatch({
52 | type: ActionType.SET_GLOBAL,
53 | payload: {
54 | widgetFormList: [],
55 | selectWidgetItem: undefined
56 | }
57 | })
58 | },
59 | getTemplate: (type) => generateCode(type, state)
60 | }))
61 |
62 | return (
63 |
64 |
65 |
66 | {useMemo(
67 | () => (
68 |
69 | {componentsGroup.map((componentGroup) => (
70 |
71 | ))}
72 |
73 | ),
74 | []
75 | )}
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | {useMemo(
88 | () => (
89 | <>
90 |
91 | setCurrentTab('Local')}>
92 | 字段设置
93 |
94 | setCurrentTab('Global')}>
95 | 全局设置
96 |
97 |
98 | {currentTab === 'Local' ? : }
99 | >
100 | ),
101 | [currentTab]
102 | )}
103 |
104 |
105 |
106 |
107 | )
108 | })
109 |
110 | DesignForm.defaultProps = {
111 | uploadJson: true,
112 | clearable: true,
113 | preview: true,
114 | generateJson: true,
115 | generateCode: true
116 | }
117 |
118 | export default forwardRef((props, ref) => (
119 |
120 |
121 |
122 | ))
123 |
--------------------------------------------------------------------------------
/src/core/GenerateForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useImperativeHandle, forwardRef } from 'react'
2 | import { ConfigProvider, Form } from 'antd'
3 | import { cloneDeep } from 'lodash-es'
4 | import { State } from '@/store/state'
5 | import { loadJsLink } from '@/utils'
6 | import { GenerateProvider } from '@/store'
7 | import GenerateFormItem from '@/core/GenerateFormItem'
8 |
9 | export interface GenerateFormProps {
10 | widgetInfoJson: string
11 | formValue?: Record
12 | }
13 |
14 | export interface GenerateFormRef {
15 | getData: () => Promise>
16 | reset: () => void
17 | }
18 |
19 | const GenerateForm = forwardRef((props, ref) => {
20 | const { widgetInfoJson, formValue } = props
21 | const [formInstance] = Form.useForm()
22 |
23 | useImperativeHandle(ref, () => ({
24 | getData: async () => {
25 | const validateResult = await formInstance.validateFields()
26 | return validateResult
27 | },
28 | reset: () => formInstance.resetFields()
29 | }))
30 |
31 | const widgetInfo: State = JSON.parse(widgetInfoJson)
32 |
33 | useEffect(() => {
34 | formInstance.setFieldsValue(cloneDeep(formValue))
35 | loadJsLink(widgetInfo.iconSrc)
36 | }, [])
37 |
38 | return (
39 |
40 |
41 |
46 |
47 |
48 | )
49 | })
50 |
51 | GenerateForm.defaultProps = {
52 | formValue: {}
53 | }
54 |
55 | export default forwardRef((props, ref) => {
56 | return (
57 |
58 |
59 |
60 | )
61 | })
62 |
--------------------------------------------------------------------------------
/src/core/Header.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo, useState, MouseEvent, FC } from 'react'
2 | import { Layout, Space } from 'antd'
3 | import UploadModal from '@/components/UploadModal'
4 | import PreviewModal from '@/components/PreviewModal'
5 | import GenerateJsonModal from '@/components/GenerateJsonModal'
6 | import GenerateCodeModal from '@/components/GenerateCodeModal'
7 | import SvgIcon from '@/components/SvgIcon'
8 | import { useConfig } from '@/hooks'
9 | import { ActionType } from '@/store/action'
10 |
11 | import type { DesignFormProps } from './index'
12 |
13 | const Header: FC = (props) => {
14 | const { uploadJson, clearable, preview, generateJson, generateCode } = props
15 | const { handlerSetVisible, dispatch } = useConfig()
16 | const [uploadVisible, setUploadVisible] = useState(false)
17 | const [previewVisible, setPreviewVisible] = useState(false)
18 | const [generateJsonVisible, setGenerateJsonVisible] = useState(false)
19 | const [generateCodeVisible, setGenerateCodeVisible] = useState(false)
20 |
21 | const handleClear = (event: MouseEvent) => {
22 | event.preventDefault()
23 | dispatch({
24 | type: ActionType.SET_WIDGET_FORM_LIST,
25 | payload: []
26 | })
27 | }
28 |
29 | return (
30 | <>
31 | {useMemo(
32 | () => (
33 |
34 |
35 | {uploadJson && (
36 |
37 |
38 | 导入Json
39 |
40 | )}
41 | {clearable && (
42 |
43 |
44 | 清空
45 |
46 | )}
47 | {preview && (
48 |
49 |
50 | 预览
51 |
52 | )}
53 | {generateJson && (
54 |
55 |
56 | 生成JSON
57 |
58 | )}
59 | {generateCode && (
60 |
61 |
62 | 生成代码
63 |
64 | )}
65 |
66 |
67 | ),
68 | [uploadJson, clearable, preview, generateJson, generateCode]
69 | )}
70 |
71 |
86 |
87 |
88 | >
89 | )
90 | }
91 |
92 | export default Header
93 |
--------------------------------------------------------------------------------
/src/core/WidgetForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useContext, useEffect, useMemo, useRef } from 'react'
2 | import { ConfigProvider, Form, FormInstance } from 'antd'
3 | import Sortable from 'sortablejs'
4 | import { v4 } from 'uuid'
5 | import { cloneDeep } from 'lodash-es'
6 | import WidgetFormItem from '@/core/WidgetFormItem'
7 | import { DesignContext } from '@/store'
8 | import { ActionType } from '@/store/action'
9 | import { removeDomNode } from '@/utils'
10 | import { Component } from '@/config'
11 |
12 | interface Props {
13 | formInstance: FormInstance
14 | }
15 |
16 | const WidgetForm: FC = (props) => {
17 | const { formInstance } = props
18 | const { state, dispatch } = useContext(DesignContext)
19 | const widgetFormListRef = useRef(state.widgetFormList)
20 | const selectWidgetItemRef = useRef(state.selectWidgetItem)
21 |
22 | useEffect(() => {
23 | widgetFormListRef.current = state.widgetFormList
24 | }, [state.widgetFormList])
25 |
26 | useEffect(() => {
27 | selectWidgetItemRef.current = state.selectWidgetItem
28 | }, [state.selectWidgetItem])
29 |
30 | const sortableGroupDecorator = (instance: HTMLDivElement | null) => {
31 | if (instance) {
32 | const options: Sortable.Options = {
33 | ghostClass: 'ghost',
34 | handle: '.drag-widget',
35 | animation: 500,
36 | group: {
37 | name: 'people'
38 | },
39 | setData: (dataTransfer) => {
40 | dataTransfer.setData('SortableDataMove', selectWidgetItemRef.current?.key!)
41 | },
42 | onAdd: (event: any) => {
43 | const { newIndex } = event
44 | const key = v4().replaceAll('-', '')
45 | const widgetFormList = cloneDeep(state.widgetFormList)
46 | const SortableDataClone = event.originalEvent.dataTransfer.getData('SortableDataClone')
47 | const SortableDataMove = event.originalEvent.dataTransfer.getData('SortableDataMove')
48 |
49 | removeDomNode('.widget-form-list>.form-edit-widget-label')
50 |
51 | if (SortableDataMove) {
52 | const itemEl = event.item
53 | const origParent = event.from
54 | origParent.appendChild(itemEl)
55 |
56 | let newSelectWidgetItem: Component
57 |
58 | const generateNewWidgetFormList = (list: Component[], key: string) => {
59 | const newList = cloneDeep(list)
60 |
61 | for (let index = 0; index < newList.length; index++) {
62 | if (newList[index].key === key) {
63 | newSelectWidgetItem = newList.splice(index, 1).at(0)!
64 | break
65 | }
66 |
67 | if (newList[index].childNodes) {
68 | newList[index].childNodes = generateNewWidgetFormList(newList[index].childNodes!, key)
69 | }
70 | }
71 |
72 | return newList
73 | }
74 |
75 | const selectWidgetItemKey = SortableDataMove
76 | const newWidgetFormList = generateNewWidgetFormList(widgetFormList, selectWidgetItemKey)
77 |
78 | newWidgetFormList.splice(newIndex, 0, newSelectWidgetItem!)
79 |
80 | dispatch({
81 | type: ActionType.SET_WIDGET_FORM_LIST,
82 | payload: newWidgetFormList
83 | })
84 | }
85 |
86 | if (SortableDataClone) {
87 | const widgetFormItem = JSON.parse(SortableDataClone)
88 |
89 | const newItem = {
90 | ...widgetFormItem,
91 | key: `${widgetFormItem.type}_${key}`
92 | }
93 |
94 | widgetFormList.splice(newIndex, 0, newItem)
95 |
96 | dispatch({
97 | type: ActionType.SET_WIDGET_FORM_LIST,
98 | payload: widgetFormList
99 | })
100 |
101 | dispatch({
102 | type: ActionType.SET_SELECT_WIDGET_ITEM,
103 | payload: newItem
104 | })
105 | }
106 | },
107 | onUpdate: (event) => {
108 | const { newIndex, oldIndex } = event
109 | const widgetFormList = cloneDeep(widgetFormListRef.current)
110 |
111 | widgetFormList.splice(newIndex!, 1, ...widgetFormList.splice(oldIndex!, 1, widgetFormList[newIndex!]))
112 |
113 | dispatch({
114 | type: ActionType.SET_WIDGET_FORM_LIST,
115 | payload: widgetFormList
116 | })
117 | }
118 | }
119 |
120 | Sortable.create(instance, options)
121 | }
122 | }
123 |
124 | return (
125 |
126 | {!state.widgetFormList.length &&
从左侧拖拽来添加字段
}
127 |
128 | {useMemo(
129 | () => (
130 |
137 | ),
138 | [state.formConfig, state.widgetFormList, state.globalClass, state.globalState]
139 | )}
140 |
141 |
142 | )
143 | }
144 |
145 | export default WidgetForm
146 |
--------------------------------------------------------------------------------
/src/core/index.ts:
--------------------------------------------------------------------------------
1 | import _DesignForm from './DesignForm'
2 | import _GenerateForm from './GenerateForm'
3 | import '@/styles/index.less'
4 | import 'virtual:svg-icons-register'
5 |
6 | export * from './DesignForm'
7 | export * from './GenerateForm'
8 | export const DesignForm = _DesignForm
9 | export const GenerateForm = _GenerateForm
10 |
--------------------------------------------------------------------------------
/src/example/assets/favicon.17e50649.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 | react-form-create-pro
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch, SetStateAction, MouseEvent, useCallback, useContext, useState } from 'react'
2 | import { update } from 'lodash-es'
3 | import { DesignContext } from '@/store'
4 | import { ActionType } from '@/store/action'
5 |
6 | export const useConfig = () => {
7 | const {
8 | state: { selectWidgetItem },
9 | dispatch
10 | } = useContext(DesignContext)
11 |
12 | const handlerSetVisible = useCallback(
13 | (callback: Dispatch>, value: boolean) => (event?: MouseEvent) => {
14 | event?.preventDefault()
15 | callback(value)
16 | },
17 | []
18 | )
19 |
20 | const [eventName, setEventName] = useState('')
21 | const [sourceType, setSourceType] = useState('静态数据')
22 | const [classEditorVisible, setClassEditorVisible] = useState(false)
23 | const [propsEditorVisible, setPropsEditorVisible] = useState(false)
24 | const [formItemPropsEditorVisible, setFormItemPropsEditorVisible] = useState(false)
25 | const [functionEditorVisible, setFunctionEditorVisible] = useState(false)
26 |
27 | const handleChange = (value: any, fieldName: string) => {
28 | update(selectWidgetItem!, fieldName, () => value)
29 |
30 | const action = {
31 | type: ActionType.SET_SELECT_WIDGET_ITEM,
32 | payload: selectWidgetItem
33 | }
34 |
35 | dispatch(action)
36 | }
37 |
38 | return {
39 | selectWidgetItem,
40 | dispatch,
41 | handleChange,
42 | handlerSetVisible,
43 | eventName,
44 | setEventName,
45 | sourceType,
46 | setSourceType,
47 | classEditorVisible,
48 | setClassEditorVisible,
49 | propsEditorVisible,
50 | setPropsEditorVisible,
51 | formItemPropsEditorVisible,
52 | setFormItemPropsEditorVisible,
53 | functionEditorVisible,
54 | setFunctionEditorVisible
55 | }
56 | }
57 |
58 | export const useForceUpdate = () => {
59 | const [flag, setFlag] = useState(false)
60 |
61 | const forceUpdate = () => setFlag(!flag)
62 |
63 | return forceUpdate
64 | }
65 |
--------------------------------------------------------------------------------
/src/icons/Alert.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/AutoComplete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Button.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Calendar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Cascader.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Checkbox.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/CheckboxGroup.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Col.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Copy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/DatePicker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Divider.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/GenerateCode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/GenerateJson.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Grid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Image.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Input.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/InputNumber.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Item.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Mentions.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Move.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Paragraph.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Preview.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/RadioGroup.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/RangePicker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Rate.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Row.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Select.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Slider.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Space.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Switch.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Text.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/TextArea.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/TimePicker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Title.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/TreeSelect.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Typography.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/Upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/index.ts:
--------------------------------------------------------------------------------
1 | const modules = import.meta.globEager('./*.svg')
2 |
3 | const Icons: Record = {}
4 |
5 | Object.keys(modules).forEach((key) => {
6 | Icons[key.replace('./', '').replace('.svg', '')] = key.replace('./', '').replace('.svg', '')
7 | })
8 |
9 | export default Icons
10 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { DesignForm } from '@/core/index'
4 | import 'antd/dist/antd.css'
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | )
12 |
--------------------------------------------------------------------------------
/src/locale/index.ts:
--------------------------------------------------------------------------------
1 | // 导入 moment
2 | import moment from 'moment'
3 | import 'moment/locale/zh-cn'
4 | import 'moment/locale/zh-tw'
5 | import 'moment/locale/zh-hk'
6 | import 'moment/locale/eu'
7 | import 'moment/locale/af'
8 | import 'moment/locale/fr'
9 | import 'moment/locale/de'
10 | import 'moment/locale/el'
11 | import 'moment/locale/id'
12 | import 'moment/locale/ja'
13 | import 'moment/locale/ko'
14 | import 'moment/locale/pt'
15 | import 'moment/locale/th'
16 |
17 | // 导入ant
18 | import zhCN from 'antd/lib/locale/zh_CN'
19 | import zhTW from 'antd/lib/locale/zh_TW'
20 | import zhHK from 'antd/lib/locale/zh_HK'
21 | import enUS from 'antd/lib/locale/en_US'
22 | import arEG from 'antd/lib/locale/ar_EG'
23 | import frFR from 'antd/lib/locale/fr_FR'
24 | import deDE from 'antd/lib/locale/de_DE'
25 | import elGR from 'antd/lib/locale/el_GR'
26 | import idID from 'antd/lib/locale/id_ID'
27 | import itIT from 'antd/lib/locale/it_IT'
28 | import jaJP from 'antd/lib/locale/ja_JP'
29 | import koKR from 'antd/lib/locale/ko_KR'
30 | import ptPT from 'antd/lib/locale/pt_PT'
31 | import thTH from 'antd/lib/locale/th_TH'
32 |
33 | moment.locale('zh-cn')
34 |
35 | export const changeMomentLocale = (locale: string) => moment.locale(locale)
36 |
37 | export const locales = [
38 | {
39 | label: '中国',
40 | locale: zhCN
41 | },
42 | {
43 | label: '中国-台湾',
44 | locale: zhTW
45 | },
46 | {
47 | label: '中国-香港',
48 | locale: zhHK
49 | },
50 | {
51 | label: '英国',
52 | locale: enUS
53 | },
54 | {
55 | label: '阿拉伯',
56 | locale: arEG
57 | },
58 | {
59 | label: '法国',
60 | locale: frFR
61 | },
62 | {
63 | label: '德国',
64 | locale: deDE
65 | },
66 | {
67 | label: '希腊',
68 | locale: elGR
69 | },
70 | {
71 | label: '印尼',
72 | locale: idID
73 | },
74 | {
75 | label: '意大利',
76 | locale: itIT
77 | },
78 | {
79 | label: '日本',
80 | locale: jaJP
81 | },
82 | {
83 | label: '韩国',
84 | locale: koKR
85 | },
86 | {
87 | label: '葡萄牙',
88 | locale: ptPT
89 | },
90 | {
91 | label: '泰国',
92 | locale: thTH
93 | }
94 | ]
95 |
--------------------------------------------------------------------------------
/src/store/action.ts:
--------------------------------------------------------------------------------
1 | export interface Action {
2 | type: ActionType
3 | payload: any
4 | }
5 |
6 | export enum ActionType {
7 | SET_GLOBAL = 'SET_GLOBAL',
8 | SET_SELECT_WIDGET_ITEM = 'SET_SELECT_WIDGET_ITEM',
9 | SET_WIDGET_FORM_LIST = 'SET_WIDGET_FORM_LIST',
10 | SET_ICON_SRC = 'SET_ICON_SRC',
11 | SET_GLOBAL_CONFIG = 'SET_GLOBAL_CONFIG',
12 | SET_FORM_CONFIG = 'SET_FORM_CONFIG'
13 | }
14 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import { useReducer, createContext, createElement, Dispatch, FC } from 'react'
2 | import { cloneDeep } from 'lodash-es'
3 | import { initState, State } from './state'
4 | import { Action, ActionType } from './action'
5 | import { Component } from '@/config'
6 |
7 | const designReducer = (prevState: State, action: Action) => {
8 | const handleSetSelectWidgetItem = () => {
9 | const createNewWidgetFormList = (list: Component[]) => {
10 | const newList = cloneDeep(list)
11 |
12 | for (let index = 0; index < newList.length; index++) {
13 | if (newList[index].key === action.payload?.key) {
14 | newList[index] = action.payload
15 | break
16 | }
17 | if (newList[index].childNodes) {
18 | newList[index].childNodes = createNewWidgetFormList(newList[index].childNodes!)
19 | }
20 | }
21 |
22 | return newList
23 | }
24 |
25 | return {
26 | ...prevState,
27 | widgetFormList: createNewWidgetFormList(prevState.widgetFormList),
28 | selectWidgetItem: action.payload
29 | }
30 | }
31 |
32 | switch (action.type) {
33 | case ActionType.SET_SELECT_WIDGET_ITEM:
34 | return handleSetSelectWidgetItem()
35 | case ActionType.SET_WIDGET_FORM_LIST:
36 | return {
37 | ...prevState,
38 | widgetFormList: action.payload
39 | }
40 | case ActionType.SET_ICON_SRC:
41 | return {
42 | ...prevState,
43 | iconSrc: action.payload
44 | }
45 | case ActionType.SET_GLOBAL_CONFIG:
46 | return {
47 | ...prevState,
48 | globalConfig: action.payload
49 | }
50 | case ActionType.SET_FORM_CONFIG:
51 | return {
52 | ...prevState,
53 | formConfig: action.payload
54 | }
55 | case ActionType.SET_GLOBAL:
56 | return {
57 | ...prevState,
58 | ...action.payload
59 | }
60 | default:
61 | return initState
62 | }
63 | }
64 |
65 | const generateReducer = (_prevState: State, action: Action) => {
66 | switch (action.type) {
67 | default:
68 | return initState.globalState
69 | }
70 | }
71 |
72 | export const DesignContext = createContext<{ state: State; dispatch: Dispatch }>({
73 | state: initState,
74 | dispatch: () => {}
75 | })
76 |
77 | export const GenerateContext = createContext<{ state: State['globalState']; dispatch: Dispatch }>({
78 | state: {},
79 | dispatch: () => {}
80 | })
81 |
82 | export const DesignProvider: FC = ({ children }) => {
83 | const [state, dispatch] = useReducer(designReducer, initState)
84 |
85 | return createElement(
86 | DesignContext.Provider,
87 | {
88 | value: {
89 | state,
90 | dispatch
91 | }
92 | },
93 | children
94 | )
95 | }
96 |
97 | export const GenerateProvider: FC = ({ children }) => {
98 | const [state, dispatch] = useReducer(generateReducer, initState.globalState)
99 |
100 | return createElement(
101 | GenerateContext.Provider,
102 | {
103 | value: {
104 | state,
105 | dispatch
106 | }
107 | },
108 | children
109 | )
110 | }
111 |
--------------------------------------------------------------------------------
/src/store/state.ts:
--------------------------------------------------------------------------------
1 | import zhCN from 'antd/lib/locale/zh_CN'
2 |
3 | import type { ConfigProviderProps } from 'antd/lib/config-provider'
4 | import type { FormProps } from 'antd/lib/form'
5 | import type { Component } from '@/config'
6 |
7 | export const initState: State = {
8 | selectWidgetItem: undefined,
9 | widgetFormList: [],
10 | iconSrc: undefined,
11 | globalConfig: {
12 | componentSize: 'middle',
13 | direction: 'ltr',
14 | locale: zhCN
15 | },
16 | formConfig: {
17 | colon: true,
18 | labelAlign: 'right',
19 | layout: 'horizontal',
20 | labelWrap: false,
21 | labelCol: {},
22 | wrapperCol: {}
23 | }
24 | }
25 |
26 | export interface State {
27 | selectWidgetItem?: Component
28 | widgetFormList: Component[]
29 | iconSrc?: string
30 | globalConfig: ConfigProviderProps
31 | formConfig: FormProps
32 | [key: string]: any
33 | }
34 |
--------------------------------------------------------------------------------
/src/styles/antd.less:
--------------------------------------------------------------------------------
1 | .fc-style {
2 | .config-content {
3 | .ant-radio-wrapper {
4 | margin: 8px 0 0 8px;
5 | }
6 |
7 | .ant-checkbox-wrapper {
8 | margin: 8px 8px 0;
9 | }
10 |
11 | .ant-picker {
12 | width: 100%;
13 | }
14 | }
15 |
16 | .ant-form-item-control-wrapper {
17 | flex: 1;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/styles/scrollbar.less:
--------------------------------------------------------------------------------
1 | ::-webkit-scrollbar {
2 | width: 5px;
3 | height: 5px;
4 | }
5 |
6 | ::-webkit-scrollbar-thumb,
7 | ::-webkit-scrollbar-track {
8 | background-color: rgba(50, 50, 50, 30%);
9 | border-radius: 1em;
10 | }
11 |
--------------------------------------------------------------------------------
/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | export type { DesignFormProps, DesignFormRef, GenerateFormProps, GenerateFormRef } from '@/core'
2 |
--------------------------------------------------------------------------------
/src/types/types.d.ts:
--------------------------------------------------------------------------------
1 | import * as monaco from 'monaco-editor'
2 |
3 | export {}
4 |
5 | declare global {
6 | interface Window {
7 | MonacoEnvironment: any
8 | monaco: typeof monaco
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/generateCode.ts:
--------------------------------------------------------------------------------
1 | import { State } from '@/store/state'
2 |
3 | export default (type: 'component' | 'html', state: State) => {
4 | let str
5 | if (type === 'component') {
6 | str = `
7 | import React from 'react'
8 | import { GenerateForm } from 'react-form-create'
9 |
10 | const widgetInfoJson = '${JSON.stringify(state, null, 2)}'
11 |
12 | export default () => {
13 | return
14 | }
15 | `
16 | } else {
17 | str = `
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
45 |
46 |
47 |
48 |
56 |
57 |
58 | `
59 | }
60 | return str.trim()
61 | }
62 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import _React, { createElement } from 'react'
2 | import * as _antd from 'antd'
3 | import { cloneDeep } from 'lodash-es'
4 | import { Component } from '@/config'
5 |
6 | // 加载js链接
7 | export const loadJsLink = (src?: string) => {
8 | if (!src) return
9 | const id = 'customScript'
10 |
11 | removeDomNode(`#${id}`)
12 |
13 | const script = document.createElement('script')
14 | script.id = id
15 | script.src = src
16 | document.getElementsByTagName('head')[0].appendChild(script)
17 | }
18 |
19 | // 复制文本
20 | export const copy = (text: string) => {
21 | const input = document.createElement('textarea')
22 | input.value = text
23 | document.body.appendChild(input)
24 | input.select()
25 | document.execCommand('copy')
26 | document.body.removeChild(input)
27 | }
28 |
29 | // 创建newWidgetFormList
30 | export const createNewWidgetFormList = (list: Component[], childNodes: Component[], key: string) => {
31 | const newList = cloneDeep(list)
32 |
33 | for (let index = 0; index < newList.length; index++) {
34 | if (newList[index].key === key) {
35 | newList[index].childNodes = childNodes
36 | break
37 | }
38 |
39 | if (newList[index].childNodes) {
40 | newList[index].childNodes = createNewWidgetFormList(newList[index].childNodes!, childNodes, key)
41 | }
42 | }
43 |
44 | return newList
45 | }
46 |
47 | // 创建MentionsOptions
48 | export const createMentionsOptions = (item: Component) => {
49 | const { remoteConfig, config } = item
50 | const options = remoteConfig?.remote ? remoteConfig.remoteOptions : config?.options
51 |
52 | return options.map((option: { label: string; value: string }) => createElement(_antd.Mentions.Option, { key: option.value, value: option.value }, option.label))
53 | }
54 |
55 | // 处理响应数据
56 | export const handleResponseData = (remoteData: any[], remoteConfig: Record): Record[] => {
57 | return remoteData?.map((data) => ({
58 | label: data[remoteConfig.remoteProps.label],
59 | value: data[remoteConfig.remoteProps.value],
60 | children: handleResponseData(data[remoteConfig.remoteProps.children], remoteConfig)
61 | }))
62 | }
63 |
64 | // 删除domNode
65 | export const removeDomNode = (selectors: string) => document.querySelectorAll(selectors).forEach((node) => node.remove())
66 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/stylelint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
3 | plugins: ['stylelint-less'],
4 | rules: {
5 | 'no-descending-specificity': null,
6 | 'color-function-notation': null,
7 | 'at-rule-no-unknown': null,
8 | 'property-no-vendor-prefix': null
9 | },
10 | ignoreFiles: ['src/example/**']
11 | }
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
5 | "allowJs": false,
6 | "skipLibCheck": false,
7 | "esModuleInterop": false,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "module": "ESNext",
12 | "moduleResolution": "Node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noEmit": true,
16 | "jsx": "react",
17 | "baseUrl": "./",
18 | "paths": {
19 | "@/*": ["src/*"]
20 | }
21 | },
22 | "include": ["./src"]
23 | }
24 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import reactRefresh from '@vitejs/plugin-react-refresh'
3 | import viteSvgIcons from 'vite-plugin-svg-icons'
4 | import path from 'path'
5 |
6 | export default defineConfig({
7 | plugins: [
8 | reactRefresh(),
9 | viteSvgIcons({
10 | iconDirs: [path.resolve(process.cwd(), 'src/icons')],
11 | symbolId: 'svg-icon-[dir]-[name]'
12 | })
13 | ],
14 | css: {
15 | preprocessorOptions: {
16 | less: {
17 | javascriptEnabled: true
18 | }
19 | }
20 | },
21 | resolve: {
22 | alias: {
23 | '@': path.resolve(__dirname, 'src')
24 | }
25 | },
26 | base: './',
27 | server: {
28 | open: true,
29 | cors: true,
30 | host: true
31 | },
32 | build: {
33 | emptyOutDir: true,
34 | lib: {
35 | entry: path.resolve(__dirname, 'src/core/index.ts'),
36 | formats: ['es', 'umd'],
37 | name: 'ReactFormCreate',
38 | fileName: (format) => `react-form-create.${format}.js`
39 | },
40 | rollupOptions: {
41 | external: ['react', 'react-dom', 'antd', 'moment', '@babel/standalone'],
42 | output: {
43 | globals: {
44 | react: 'React',
45 | 'react-dom': 'ReactDom',
46 | antd: 'antd',
47 | moment: 'moment',
48 | '@babel/standalone': 'Babel'
49 | }
50 | }
51 | }
52 | }
53 | })
54 |
--------------------------------------------------------------------------------