├── .nvmrc ├── .husky ├── .gitignore └── pre-commit ├── .npmrc ├── scripts ├── build.types.js ├── clean.js ├── build.document.js ├── env │ ├── development.js │ └── production.js ├── release.js ├── build.code.js ├── jest │ ├── raw-loader.js │ └── setup.js ├── webpack │ └── loaders │ │ └── markdown-loader │ │ ├── extend-html.js │ │ ├── highlight.js │ │ ├── index.js │ │ ├── md-section.js │ │ ├── md-container.js │ │ └── markdown-it.js ├── types.json ├── dev.js ├── example.js └── args.js ├── .gitignore ├── packages ├── core │ ├── util │ │ ├── index.ts │ │ ├── component.ts │ │ └── dom.ts │ ├── assets │ │ ├── img │ │ │ └── xform-tip.png │ │ └── css │ │ │ ├── variables.css │ │ │ └── common.css │ ├── README.md │ ├── api │ │ ├── Exports.ts │ │ ├── test │ │ │ ├── Preset.spec.ts │ │ │ └── Config.spec.ts │ │ ├── Slots.ts │ │ ├── Preset.ts │ │ ├── Config.ts │ │ ├── Store.ts │ │ ├── DefaultValue.ts │ │ └── Logic │ │ │ ├── logic.ts │ │ │ └── builtin.tsx │ ├── component │ │ ├── FormBuilder │ │ │ └── component.css │ │ ├── FormViewer │ │ │ └── component.css │ │ ├── FormDesigner │ │ │ └── component.module.css │ │ └── FormItem │ │ │ └── component.css │ ├── index.css │ ├── model │ │ ├── index.ts │ │ ├── Exports.ts │ │ ├── Serializable.ts │ │ ├── action.ts │ │ ├── Emitter.ts │ │ └── Button.ts │ ├── __test__ │ │ ├── FormSchema.spec.ts │ │ ├── FormScope.spec.ts │ │ ├── FormField.spec.ts │ │ ├── lang.spec.ts │ │ └── api.spec.ts │ ├── package.json │ └── index.ts ├── element-plus │ ├── util.ts │ ├── fields │ │ ├── datatable │ │ │ └── common.ts │ │ ├── divider │ │ │ ├── index.ts │ │ │ ├── divider.vue │ │ │ └── setting.vue │ │ ├── text │ │ │ ├── index.ts │ │ │ ├── text.vue │ │ │ └── setting.vue │ │ ├── textarea │ │ │ ├── index.ts │ │ │ ├── textarea.vue │ │ │ └── setting.vue │ │ ├── date │ │ │ ├── index.ts │ │ │ ├── date.vue │ │ │ └── setting.vue │ │ ├── number │ │ │ ├── index.ts │ │ │ └── number.vue │ │ ├── select │ │ │ ├── index.ts │ │ │ └── select.vue │ │ ├── index.ts │ │ ├── radio │ │ │ ├── index.ts │ │ │ └── radio.vue │ │ ├── checkbox │ │ │ ├── index.ts │ │ │ └── checkbox.vue │ │ ├── group │ │ │ ├── setting.vue │ │ │ └── index.scss │ │ └── tabs │ │ │ └── index.scss │ ├── README.md │ ├── logic │ │ ├── index.module.scss │ │ ├── common.tsx │ │ ├── index.ts │ │ ├── date.tsx │ │ └── number.tsx │ ├── index.scss │ ├── index.ts │ ├── package.json │ └── FormSetting.vue ├── bootstrap │ ├── fields │ │ ├── datatable │ │ │ └── common.ts │ │ ├── divider │ │ │ ├── index.ts │ │ │ └── divider.vue │ │ ├── date │ │ │ ├── index.ts │ │ │ ├── date.vue │ │ │ └── setting.vue │ │ ├── text │ │ │ ├── index.ts │ │ │ ├── text.vue │ │ │ └── setting.vue │ │ ├── textarea │ │ │ ├── index.ts │ │ │ ├── textarea.vue │ │ │ └── setting.vue │ │ ├── select │ │ │ ├── index.ts │ │ │ └── select.vue │ │ ├── index.ts │ │ ├── radio │ │ │ ├── index.ts │ │ │ └── radio.vue │ │ ├── checkbox │ │ │ ├── index.ts │ │ │ └── checkbox.vue │ │ ├── group │ │ │ ├── setting.vue │ │ │ └── index.scss │ │ ├── number │ │ │ ├── setting.vue │ │ │ └── index.tsx │ │ └── tabs │ │ │ └── index.scss │ ├── README.md │ ├── logic │ │ ├── common.tsx │ │ ├── index.tsx │ │ ├── date.tsx │ │ └── number.tsx │ ├── index.ts │ ├── package.json │ ├── index.scss │ ├── FormSetting.vue │ ├── util.ts │ └── FieldLogic.vue ├── common │ ├── svg │ │ ├── raw.js │ │ ├── select.svg │ │ ├── textarea.svg │ │ ├── text.svg │ │ ├── radio.svg │ │ ├── remove.svg │ │ ├── info.svg │ │ ├── pickup.svg │ │ ├── checkbox.svg │ │ ├── number.svg │ │ ├── pick.svg │ │ ├── group.svg │ │ ├── divider.svg │ │ ├── clone.svg │ │ ├── trash.svg │ │ ├── datatable.svg │ │ ├── date.svg │ │ └── tabs.svg │ ├── button.ts │ └── __test__ │ │ └── operator.spec.ts ├── antdv │ └── index.ts ├── props.d.ts └── global.d.ts ├── docs ├── img │ └── ac762befe393daba8318.png ├── 305.6de560aa.js ├── index.html └── 55.9b82bab6.js ├── document ├── assets │ ├── image │ │ └── architecture.png │ ├── style │ │ └── document │ │ │ ├── index.css │ │ │ ├── _vars.css │ │ │ ├── article.css │ │ │ └── highlight.css │ └── svg │ │ ├── outbound-dark.svg │ │ ├── outbound.svg │ │ ├── github.svg │ │ └── github-dark.svg ├── views │ ├── example │ │ ├── bootstrap │ │ │ ├── index.ts │ │ │ └── index.scss │ │ ├── element-plus │ │ │ ├── index.ts │ │ │ └── index.scss │ │ └── viewer.vue │ ├── not-found.vue │ └── document │ │ ├── index.ts │ │ └── menus.ts ├── native │ ├── index.ts │ ├── codebox │ │ ├── index.css │ │ └── index.ts │ └── is-link.ts ├── app.vue ├── docs │ ├── concept.md │ ├── components │ │ ├── XFormItem.md │ │ ├── XFormViewer.md │ │ ├── XFormBuilder.md │ │ └── XFormDesigner.md │ ├── introduction.md │ ├── index.ts │ └── model.md ├── component │ ├── index.ts │ ├── FooterGuide.vue │ └── Notification │ │ └── index.scss ├── index.ts ├── index.html ├── router.ts └── util │ └── enhance.ts ├── postcss.config.js ├── example ├── index.css ├── bootstrap.html ├── element.html ├── bootstrap.esm.html └── element.esm.html ├── babel.config.js ├── jest.config.js ├── tsconfig.json ├── api-extractor.json ├── README.md └── LICENSE /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false -------------------------------------------------------------------------------- /scripts/build.types.js: -------------------------------------------------------------------------------- 1 | require('./utils').buildTypes() -------------------------------------------------------------------------------- /scripts/clean.js: -------------------------------------------------------------------------------- 1 | require('./utils').cleanAll() 2 | -------------------------------------------------------------------------------- /scripts/build.document.js: -------------------------------------------------------------------------------- 1 | require('./utils').buildDocument() -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /scripts/env/development.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | website: { 3 | base: '/' 4 | } 5 | } -------------------------------------------------------------------------------- /scripts/release.js: -------------------------------------------------------------------------------- 1 | require('./utils').release().catch(err => { 2 | console.error(err) 3 | }) -------------------------------------------------------------------------------- /scripts/env/production.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | website: { 3 | base: '/xForm/' 4 | } 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .vscode 4 | __private__ 5 | coverage 6 | types 7 | example/packages -------------------------------------------------------------------------------- /scripts/build.code.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils') 2 | 3 | utils.cleanAll() 4 | utils.buildCode() -------------------------------------------------------------------------------- /packages/core/util/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lang' 2 | export * from './dom' 3 | export * from './component' 4 | -------------------------------------------------------------------------------- /docs/img/ac762befe393daba8318.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongls/xForm/HEAD/docs/img/ac762befe393daba8318.png -------------------------------------------------------------------------------- /document/assets/image/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongls/xForm/HEAD/document/assets/image/architecture.png -------------------------------------------------------------------------------- /packages/core/assets/img/xform-tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongls/xForm/HEAD/packages/core/assets/img/xform-tip.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('autoprefixer') 5 | ] 6 | } -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # xForm 2 | `xForm`核心组件库。 3 | 4 | - [文档](https://dongls.github.io/xForm/) 5 | 6 | ## License 7 | [MIT](LICENSE) -------------------------------------------------------------------------------- /document/views/example/bootstrap/index.ts: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | import Bootstrap from '@bootstrap/index' 3 | 4 | export default Bootstrap -------------------------------------------------------------------------------- /packages/core/api/Exports.ts: -------------------------------------------------------------------------------- 1 | import * as api from './index' 2 | 3 | export * from './index' 4 | export function useApi(){ 5 | return api 6 | } -------------------------------------------------------------------------------- /document/views/example/element-plus/index.ts: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | import ElementPlus from '@element-plus/index' 3 | 4 | export default ElementPlus -------------------------------------------------------------------------------- /document/native/index.ts: -------------------------------------------------------------------------------- 1 | import CodeBox from './codebox/index' 2 | import IsLink from './is-link' 3 | 4 | [ 5 | CodeBox, 6 | IsLink 7 | ].forEach(c => c.install()) -------------------------------------------------------------------------------- /packages/element-plus/util.ts: -------------------------------------------------------------------------------- 1 | export { 2 | useValue, 3 | useDefaultValueApi, 4 | useFieldProp, 5 | useOptions, 6 | useSchemaProp 7 | } from '@common/util' 8 | -------------------------------------------------------------------------------- /scripts/jest/raw-loader.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | process(src) { 3 | return { 4 | code: 'module.exports = ' + JSON.stringify(src) + ';' 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /document/assets/style/document/index.css: -------------------------------------------------------------------------------- 1 | @import './_vars.css'; 2 | 3 | @import './base.css'; 4 | @import './highlight.css'; 5 | @import './doc.css'; 6 | @import './article.css'; -------------------------------------------------------------------------------- /document/views/not-found.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /scripts/webpack/loaders/markdown-loader/extend-html.js: -------------------------------------------------------------------------------- 1 | const blocks = require('markdown-it/lib/common/html_blocks'); 2 | 3 | [ 4 | 'md-meta', 5 | 'code-box' 6 | ].forEach(b => blocks.push(b)) 7 | -------------------------------------------------------------------------------- /docs/305.6de560aa.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunkxform=self.webpackChunkxform||[]).push([[305],{8305:(n,e,s)=>{s.r(e),s.d(e,{default:()=>t});const t={name:"antdv",version:"0.8.1",install:function(){}}}}]); -------------------------------------------------------------------------------- /scripts/jest/setup.js: -------------------------------------------------------------------------------- 1 | window.__VERSION__ = require('../../package.json').version 2 | window.__IS_TEST__ = true 3 | window.__IS_DEV__ = false 4 | 5 | HTMLElement.prototype.scrollIntoView = function(){ /** */} -------------------------------------------------------------------------------- /document/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /packages/core/component/FormBuilder/component.css: -------------------------------------------------------------------------------- 1 | .xform-builder{ 2 | background-color: #fff; 3 | 4 | font-size: var(--xform-font-size); 5 | color: var(--xform-text-color); 6 | padding: 0 10px; 7 | margin: 0 auto; 8 | } -------------------------------------------------------------------------------- /document/views/document/index.ts: -------------------------------------------------------------------------------- 1 | import '@document/assets/style/document/index.css' 2 | import '@document/native/index' 3 | 4 | import Doc from './doc.vue' 5 | import Page from './page.vue' 6 | 7 | export { 8 | Doc, 9 | Page 10 | } -------------------------------------------------------------------------------- /packages/bootstrap/fields/datatable/common.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from '@dongls/xform' 2 | 3 | export type Row = {[prop: string]: FormField} 4 | 5 | export const DEF_COLUMN_WIDTH = 150 6 | export const BODY_CLASS = 'xform-bs-datatable-columns' -------------------------------------------------------------------------------- /packages/element-plus/fields/datatable/common.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from '@dongls/xform' 2 | 3 | export type Row = {[prop: string]: FormField} 4 | 5 | export const DEF_COLUMN_WIDTH = 150 6 | export const BODY_CLASS = 'xform-el-datatable-columns' -------------------------------------------------------------------------------- /packages/element-plus/README.md: -------------------------------------------------------------------------------- 1 | # ElementPlus For xForm 2 | 基于[Element Plus][element]的[xForm][xForm]字段库。 3 | 4 | ## License 5 | [MIT](LICENSE) 6 | 7 | [element]: https://github.com/element-plus/element-plus 8 | [xForm]: https://github.com/dongls/xForm -------------------------------------------------------------------------------- /document/views/example/bootstrap/index.scss: -------------------------------------------------------------------------------- 1 | .example-designer-tool-left { 2 | .form-check{ 3 | height: 24px; 4 | line-height: 24px; 5 | margin-right: 10px; 6 | } 7 | 8 | .form-check-input{ 9 | margin-top: 5px; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /scripts/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "emitDeclarationOnly": true 6 | }, 7 | "include": [ 8 | "../packages/**.d.ts", 9 | "../packages/core/index.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /document/docs/concept.md: -------------------------------------------------------------------------------- 1 | # 概念 2 | 3 | 通常来说,对于表单设计器,需要提供以下配置: 4 | - **表单设置组件** - 用于设置表单的属性,通过`preset.slots.setting`或者name为`setting`的`slot`提供。 5 | - **字段预览组件** - 用于预览字段,通过以下位置:`FieldConf.preview`,`FieldConf.build`按顺序提供。 6 | - **字段设置组件** - 用于设置字段的属性,通过`FieldConf.setting`提供。 7 | -------------------------------------------------------------------------------- /packages/common/svg/raw.js: -------------------------------------------------------------------------------- 1 | import IconClone from '@common/svg/clone.svg?raw-loader' 2 | import IconRemove from '@common/svg/remove.svg?raw-loader' 3 | import IconPickUp from '@common/svg/pickup.svg?raw-loader' 4 | 5 | export { 6 | IconClone, 7 | IconRemove, 8 | IconPickUp 9 | } -------------------------------------------------------------------------------- /packages/antdv/index.ts: -------------------------------------------------------------------------------- 1 | import { FormPreset } from '@dongls/xform' 2 | 3 | const antdv: FormPreset = { 4 | name: 'antdv', 5 | version: __VERSION__, 6 | install(){ 7 | // TODO: antdv 8 | // https://github.com/vueComponent/ant-design-vue 9 | } 10 | } 11 | 12 | export default antdv -------------------------------------------------------------------------------- /packages/core/index.css: -------------------------------------------------------------------------------- 1 | @import './assets/css/variables.css'; 2 | @import './assets/css/common.css'; 3 | 4 | @import './component/FormBuilder/component.css'; 5 | @import './component/FormDesigner/component.css'; 6 | @import './component/FormItem/component.css'; 7 | @import './component/FormViewer/component.css'; -------------------------------------------------------------------------------- /packages/core/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './action' 2 | export * from './common' 3 | export * from './constant' 4 | export * from './drag' 5 | export * from './Field' 6 | export * from './FormField' 7 | export * from './FormSchema' 8 | export * from './Serializable' 9 | export * from './FormScope' 10 | export * from './Button' 11 | -------------------------------------------------------------------------------- /document/assets/style/document/_vars.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --doc-color-primary: rgb(0,123,255); 3 | 4 | --doc-text-color-primary: rgb(36, 41, 46); 5 | --doc-head-text-color: rgb(33, 36, 51); 6 | 7 | --doc-link-color: rgb(0,123,255); 8 | --doc-link-hover-bg-color: rgba(0, 76, 252, .1); 9 | 10 | --doc-main-width: 1180px; 11 | } 12 | -------------------------------------------------------------------------------- /scripts/dev.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | const utils = require('./utils') 3 | 4 | utils.cleanAll() 5 | 6 | execa.sync( 7 | 'node_modules/.bin/webpack', 8 | [ 9 | 'serve', 10 | '--config', 11 | 'scripts/webpack/webpack.document.config.js', 12 | ], 13 | { 14 | stdio: 'inherit', 15 | env: { 'NODE_ENV': 'development' } 16 | } 17 | ) 18 | -------------------------------------------------------------------------------- /packages/props.d.ts: -------------------------------------------------------------------------------- 1 | import { FormSchema, FormField } from './core' 2 | import { FormScope } from './core/model' 3 | 4 | declare global { 5 | interface Element{ 6 | __PROP_XFORM_DRAGE_MODE__: string 7 | __PROP_XFORM_FIELD__: FormField 8 | __PROP_XFORM_FIELD_TYPE__: string 9 | __PROP_XFORM_SCHEMA__: FormSchema 10 | __PROP_XFORM_SCOPE__: FormScope 11 | } 12 | } -------------------------------------------------------------------------------- /example/index.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | display: flex; 4 | } 5 | 6 | aside{ 7 | width: 200px; 8 | border-right: 1px solid #aaa; 9 | padding: 5px; 10 | overflow: auto; 11 | } 12 | 13 | aside a{ 14 | display: block; 15 | color: rgb(0, 0, 238); 16 | } 17 | 18 | aside a + a{ 19 | margin-top: 4px; 20 | } 21 | 22 | iframe{ 23 | display: block; 24 | border: none; 25 | flex: 1; 26 | } -------------------------------------------------------------------------------- /packages/core/model/Exports.ts: -------------------------------------------------------------------------------- 1 | export { 2 | FormBuilderApi, 3 | FormBuilderContext, 4 | FormDesignerApi, 5 | FormDesignerContext, 6 | FormPreset, 7 | FormRenderContext, 8 | FormViewerContext, 9 | RawProps, 10 | Button, 11 | Icon 12 | } from './common' 13 | 14 | export { Field, FieldLogic } from './Field' 15 | export { FormField, FormFieldLogic } from './FormField' 16 | export { FormSchema } from './FormSchema' 17 | -------------------------------------------------------------------------------- /document/component/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | 3 | import Modal from './Modal.vue' 4 | import FooterGuide from './FooterGuide.vue' 5 | import PresetPicker from './PresetPicker.vue' 6 | 7 | export { useNotification } from './Notification' 8 | 9 | export default function(app: App){ 10 | app.component(Modal.name, Modal) 11 | app.component(FooterGuide.name, FooterGuide) 12 | app.component(PresetPicker.name, PresetPicker) 13 | } -------------------------------------------------------------------------------- /document/assets/svg/outbound-dark.svg: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /document/assets/svg/outbound.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /packages/common/svg/select.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/core/component/FormViewer/component.css: -------------------------------------------------------------------------------- 1 | .xform-viewer{ 2 | font-size: var(--xform-font-size); 3 | color: var(--xform-text-color); 4 | background-color: #fff; 5 | margin: 0 auto; 6 | padding: 0 10px; 7 | } 8 | 9 | .xform-viewer .xform-item-label > span:before{ 10 | content: none !important; 11 | } 12 | 13 | .xform-viewer-value{ 14 | line-height: 21px; 15 | display: inline-block; 16 | padding-top: 5px; 17 | padding-bottom: 5px; 18 | } -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const RELEASE_TARGET = process.env.RELEASE_TARGET 2 | const FOR_BUNDLER = RELEASE_TARGET === 'bundler' 3 | 4 | const presets = ( 5 | FOR_BUNDLER 6 | ? [] 7 | : [ 8 | ['@babel/preset-env',{ 9 | browserslistEnv: RELEASE_TARGET, 10 | useBuiltIns: 'usage', 11 | corejs: 3, 12 | }] 13 | ] 14 | ) 15 | 16 | const plugins = ['@vue/babel-plugin-jsx'] 17 | 18 | module.exports = { presets, plugins } -------------------------------------------------------------------------------- /packages/common/svg/textarea.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /packages/bootstrap/README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap For xForm 2 | 基于[Bootstrap@5.x][bootstrap]的[xForm][xForm]字段库。 3 | 4 | ## 已支持字段 5 | - checkbox - 多选 6 | - datatable - 数据表格 7 | - date - 日期 8 | - divider - 分割线 9 | - group - 分组 10 | - number - 数字 11 | - radio - 单选 12 | - select - 下拉选择 13 | - tabs - 标签页 14 | - text - 单行文本 15 | - textarea - 多行文本 16 | 17 | ## License 18 | [MIT](LICENSE) 19 | 20 | 21 | [bootstrap]: https://github.com/twbs/bootstrap 22 | [xForm]: https://github.com/dongls/xForm 23 | -------------------------------------------------------------------------------- /packages/core/assets/css/variables.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --xform-color-primary: #409eff; 3 | --xform-color-primary-lighten: #e8f3ff; 4 | 5 | --xform-color-danger: #f56c6c; 6 | --xform-color-warning: #e6a23c; 7 | 8 | --xform-border-color: #eee; 9 | 10 | --xform-text-color: #343a40; 11 | --xform-text-color-secondary: #9a9a9a; 12 | 13 | --xform-font-size: 14px; 14 | 15 | --xform-label-width: 120px; 16 | 17 | --xform-designer-mark-color: red; 18 | --xform-designer-responsive-width: 640px; 19 | } -------------------------------------------------------------------------------- /document/index.ts: -------------------------------------------------------------------------------- 1 | import '../packages/core/index.css' 2 | 3 | import * as Vue from 'vue' 4 | 5 | import xForm from '@dongls/xform' 6 | import App from './app.vue' 7 | import router from './router' 8 | import component from './component/index' 9 | 10 | const app = Vue.createApp(App) 11 | 12 | app.use(router) 13 | app.use(xForm) 14 | app.use(component) 15 | app.mount('#app') 16 | 17 | app.config.performance = __IS_DEV__ 18 | app.config.globalProperties.IS_DEV = __IS_DEV__ 19 | 20 | // 暴露Vue对象给外部引入的库使用 21 | ;(window as any).Vue = Vue -------------------------------------------------------------------------------- /document/native/codebox/index.css: -------------------------------------------------------------------------------- 1 | @import '../../assets/style/document/highlight.css'; 2 | 3 | .code-box-root pre{ 4 | margin: 0; 5 | } 6 | 7 | .code-box-root:hover .toolbox > button{ 8 | visibility: visible; 9 | } 10 | 11 | .toolbox{ 12 | position: absolute; 13 | bottom: 5px; 14 | right: 5px; 15 | text-align: right; 16 | } 17 | 18 | .toolbox button{ 19 | visibility: hidden; 20 | background-color: transparent; 21 | border: none; 22 | cursor: pointer; 23 | outline: none; 24 | color: rgb(0,123,255); 25 | } 26 | -------------------------------------------------------------------------------- /document/native/is-link.ts: -------------------------------------------------------------------------------- 1 | import icon from '!!raw-loader!../assets/svg/outbound.svg' 2 | 3 | class IconOutbound extends HTMLElement { 4 | constructor(){ 5 | super() 6 | 7 | this.innerHTML = icon 8 | this.title = '查看详情' 9 | 10 | this.addEventListener('click', function(){ 11 | const path = this.getAttribute('path') 12 | window.open(window.location.origin + path) 13 | }) 14 | } 15 | } 16 | 17 | 18 | export default { 19 | install(){ 20 | customElements.define('is-link', IconOutbound) 21 | } 22 | } -------------------------------------------------------------------------------- /document/views/example/element-plus/index.scss: -------------------------------------------------------------------------------- 1 | .example-designer-tool{ 2 | .el-button--small{ 3 | font-size: 14px; 4 | } 5 | 6 | .el-button + .el-button{ 7 | margin-left: 15px; 8 | } 9 | } 10 | 11 | .example-builder-footer{ 12 | .el-button--small{ 13 | font-size: 14px; 14 | } 15 | } 16 | 17 | .example-el-confirm strong{ 18 | margin: 0 2px; 19 | 20 | &[danger]{ 21 | color: #F56C6C; 22 | } 23 | 24 | &[info]{ 25 | color: #409EFF; 26 | } 27 | } 28 | 29 | .example-el-notify{ 30 | .example-schema-error{ 31 | padding-left: 0; 32 | } 33 | } -------------------------------------------------------------------------------- /packages/element-plus/logic/index.module.scss: -------------------------------------------------------------------------------- 1 | .logicForm{ 2 | display: flex; 3 | flex-flow: row nowrap; 4 | align-items: center; 5 | height: 30px; 6 | line-height: 30px; 7 | 8 | strong{ 9 | margin: 0 4px; 10 | } 11 | 12 | & > :global(.el-select){ 13 | width: 100px; 14 | margin-left: 10px; 15 | } 16 | 17 | & > :global(.el-input){ 18 | width: 150px; 19 | margin-left: 10px; 20 | } 21 | 22 | & > :global(.el-input-number){ 23 | width: 150px; 24 | margin-left: 10px; 25 | } 26 | 27 | & > .valueSelect{ 28 | width: 150px; 29 | } 30 | } -------------------------------------------------------------------------------- /packages/bootstrap/logic/common.tsx: -------------------------------------------------------------------------------- 1 | import classes from './index.module.scss' 2 | import { FormField, FormFieldLogic, useConstant } from '@dongls/xform' 3 | 4 | const { CLASS } = useConstant() 5 | 6 | export function createWarnTip(logic: FormFieldLogic, field: FormField){ 7 | const targetField = field.parent.find(logic.field) 8 | if(targetField == null) return
当前逻辑失效,目标字段被删除或位置发生变化
9 | 10 | const title = {targetField.title} 11 | return
当前逻辑失效,目标字段{title}的位置发生变化
12 | } -------------------------------------------------------------------------------- /packages/bootstrap/fields/divider/index.ts: -------------------------------------------------------------------------------- 1 | import { Field } from '@dongls/xform' 2 | import icon from '@common/svg/divider.svg' 3 | 4 | import divider from './divider.vue' 5 | import setting from './setting.vue' 6 | 7 | export default Field.create({ 8 | icon: icon, 9 | type: 'divider', 10 | title: '分割线', 11 | custom: true, 12 | setting: setting, 13 | build: divider, 14 | view: divider, 15 | onCreate(field, params, init){ 16 | if(init){ 17 | field.attributes.type = 'solid' 18 | field.attributes.top = 0 19 | field.attributes.bottom = 0 20 | } 21 | }, 22 | }) -------------------------------------------------------------------------------- /packages/common/svg/text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /packages/element-plus/logic/common.tsx: -------------------------------------------------------------------------------- 1 | import classes from './index.module.scss' 2 | import { FormField, FormFieldLogic, useConstant } from '@dongls/xform' 3 | 4 | const { CLASS } = useConstant() 5 | 6 | export function createWarnTip(logic: FormFieldLogic, field: FormField){ 7 | const targetField = field.parent.find(logic.field) 8 | if(targetField == null) return
当前逻辑失效,目标字段被删除或位置发生变化
9 | 10 | const title = {targetField.title} 11 | return
当前逻辑失效,目标字段{title}的位置发生变化
12 | } -------------------------------------------------------------------------------- /packages/element-plus/fields/divider/index.ts: -------------------------------------------------------------------------------- 1 | import { Field } from '@dongls/xform' 2 | import icon from '@common/svg/divider.svg' 3 | 4 | import divider from './divider.vue' 5 | import setting from './setting.vue' 6 | 7 | export default Field.create({ 8 | icon: icon, 9 | type: 'divider', 10 | title: '分割线', 11 | custom: true, 12 | setting: setting, 13 | build: divider, 14 | view: divider, 15 | onCreate(field, params, init){ 16 | if(init){ 17 | field.attributes.type = 'solid' 18 | field.attributes.top = 0 19 | field.attributes.bottom = 0 20 | } 21 | }, 22 | }) -------------------------------------------------------------------------------- /packages/bootstrap/fields/date/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { DATE_VALUE_COMPARE } from '@bootstrap/logic' 3 | 4 | import icon from '@common/svg/date.svg' 5 | import date from './date.vue' 6 | import setting from './setting.vue' 7 | 8 | export default Field.create({ 9 | icon: icon, 10 | type: 'date', 11 | title: '日期', 12 | setting: setting, 13 | build: date, 14 | validator(field, value: string){ 15 | if(field.required && isEmpty(value)) return Promise.reject('必填') 16 | return Promise.resolve() 17 | }, 18 | logic: [ 19 | DATE_VALUE_COMPARE 20 | ] 21 | }) -------------------------------------------------------------------------------- /packages/element-plus/index.scss: -------------------------------------------------------------------------------- 1 | .xform-setting + .xform-setting{ 2 | margin-top: 10px; 3 | } 4 | 5 | .xform-setting header{ 6 | font-weight: 700; 7 | } 8 | 9 | .xform-el-setting-option{ 10 | display: flex; 11 | flex-flow: row nowrap; 12 | align-items: center; 13 | margin-bottom: 5px; 14 | 15 | .el-button{ 16 | margin-left: 5px; 17 | } 18 | } 19 | 20 | .xform-el-empty-tip{ 21 | position: absolute; 22 | top: 45%; 23 | left: 50%; 24 | transform: translateX(-50%); 25 | margin: 0; 26 | text-align: center; 27 | color: #9a9a9a; 28 | font-size: 14px; 29 | font-weight: 600; 30 | } 31 | -------------------------------------------------------------------------------- /packages/core/api/test/Preset.spec.ts: -------------------------------------------------------------------------------- 1 | import { reset, isImmediateValidate } from '..' 2 | import { FormPreset } from '../../model' 3 | import { useApi, usePreset } from '../Exports' 4 | 5 | describe('usePreset', () => { 6 | test('with config', () => { 7 | const preset: FormPreset = { 8 | name: 'test', 9 | install(){ 10 | const api = useApi() 11 | api.useConfig({ 12 | validation: { 13 | immediate: false 14 | } 15 | }) 16 | } 17 | } 18 | 19 | reset() 20 | usePreset(preset) 21 | 22 | expect(isImmediateValidate()).toBe(false) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /packages/bootstrap/index.ts: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | 3 | import { FormPreset, registerSlot, removeSlot } from '@dongls/xform' 4 | 5 | import logic from './logic' 6 | import fields from './fields' 7 | 8 | import FormSetting from './FormSetting.vue' 9 | 10 | const bootstrap: FormPreset = { 11 | name: 'bootstrap', 12 | version: __VERSION__, 13 | install(){ 14 | registerSlot('setting_form', FormSetting) 15 | 16 | fields.use() 17 | logic.use() 18 | 19 | return function(){ 20 | removeSlot('setting_form') 21 | 22 | fields.remove() 23 | logic.remove() 24 | } 25 | } 26 | } 27 | 28 | export default bootstrap -------------------------------------------------------------------------------- /packages/core/api/Slots.ts: -------------------------------------------------------------------------------- 1 | import { ComponentOptions } from 'vue' 2 | import { isObject } from '../util' 3 | import { store } from './Store' 4 | 5 | export function registerSlots(o: { [prop: string]: ComponentOptions }){ 6 | if(!isObject(o)) return 7 | 8 | for(const key in o){ 9 | const slot = o[key] 10 | registerSlot(key, slot) 11 | } 12 | } 13 | 14 | export function registerSlot(key: string, slot: ComponentOptions){ 15 | store.slots.set(key, slot) 16 | } 17 | 18 | export function getSlot(key: string){ 19 | return store.slots.get(key) 20 | } 21 | 22 | export function removeSlot(key: string){ 23 | store.slots.delete(key) 24 | } -------------------------------------------------------------------------------- /packages/element-plus/index.ts: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | 3 | import { FormPreset, registerSlot, removeSlot } from '@dongls/xform' 4 | 5 | import logic from './logic' 6 | import fields from './fields' 7 | 8 | import FormSetting from './FormSetting.vue' 9 | 10 | const elementPlus: FormPreset = { 11 | name: 'element-plus', 12 | version: __VERSION__, 13 | install(){ 14 | registerSlot('setting_form', FormSetting) 15 | 16 | fields.use() 17 | logic.use() 18 | 19 | return function(){ 20 | removeSlot('setting_form') 21 | 22 | fields.remove() 23 | logic.remove() 24 | } 25 | } 26 | } 27 | 28 | export default elementPlus -------------------------------------------------------------------------------- /packages/core/api/Preset.ts: -------------------------------------------------------------------------------- 1 | import { FormPreset } from '../model' 2 | import { store } from './Store' 3 | import { isFunction } from '../util' 4 | 5 | export function usePreset(preset: FormPreset, options?: any){ 6 | if(null == preset || !isFunction(preset.install)) return 7 | 8 | store.preset = { 9 | name: preset.name, 10 | version: preset.version, 11 | cleanup: preset.install(options) 12 | } 13 | } 14 | 15 | export function resetPreset(){ 16 | if(store.preset == null) return 17 | if(isFunction(store.preset.cleanup)) store.preset.cleanup() 18 | 19 | store.preset = null 20 | } 21 | 22 | export function getPreset(){ 23 | return store.preset 24 | } 25 | -------------------------------------------------------------------------------- /packages/element-plus/fields/text/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { STRING_LENGTH_COMPARE, STRING_VALUE_COMPARE } from '@element-plus/logic/string' 3 | 4 | import icon from '@common/svg/text.svg' 5 | import text from './text.vue' 6 | import setting from './setting.vue' 7 | 8 | export default Field.create({ 9 | icon: icon, 10 | type: 'text', 11 | title: '单行文本', 12 | setting: setting, 13 | build: text, 14 | validator(field, value){ 15 | if(field.required && isEmpty(value)) return Promise.reject('必填') 16 | return Promise.resolve() 17 | }, 18 | logic: [ 19 | STRING_VALUE_COMPARE, 20 | STRING_LENGTH_COMPARE 21 | ] 22 | }) -------------------------------------------------------------------------------- /packages/bootstrap/fields/text/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { 3 | STRING_VALUE_COMPARE, 4 | STRING_LENGTH_COMPARE 5 | } from '@bootstrap/logic' 6 | 7 | import icon from '@common/svg/text.svg' 8 | import text from './text.vue' 9 | import setting from './setting.vue' 10 | 11 | export default Field.create({ 12 | icon: icon, 13 | type: 'text', 14 | title: '单行文本', 15 | setting: setting, 16 | build: text, 17 | validator(field, value){ 18 | if(field.required && isEmpty(value)) return Promise.reject('必填') 19 | return Promise.resolve() 20 | }, 21 | logic: [ 22 | STRING_VALUE_COMPARE, 23 | STRING_LENGTH_COMPARE 24 | ] 25 | }) -------------------------------------------------------------------------------- /packages/element-plus/fields/textarea/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { STRING_LENGTH_COMPARE, STRING_VALUE_COMPARE } from '@element-plus/logic/string' 3 | 4 | import icon from '@common/svg/textarea.svg' 5 | import textarea from './textarea.vue' 6 | import setting from './setting.vue' 7 | 8 | export default Field.create({ 9 | icon: icon, 10 | type: 'textarea', 11 | title: '多行文本', 12 | setting: setting, 13 | build: textarea, 14 | validator(field, value){ 15 | if(field.required && isEmpty(value)) return Promise.reject('必填') 16 | return Promise.resolve() 17 | }, 18 | logic: [ 19 | STRING_VALUE_COMPARE, 20 | STRING_LENGTH_COMPARE 21 | ] 22 | }) -------------------------------------------------------------------------------- /packages/bootstrap/fields/textarea/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { 3 | STRING_VALUE_COMPARE, 4 | STRING_LENGTH_COMPARE 5 | } from '@bootstrap/logic' 6 | 7 | import icon from '@common/svg/textarea.svg' 8 | import textarea from './textarea.vue' 9 | import setting from './setting.vue' 10 | 11 | export default Field.create({ 12 | icon: icon, 13 | type: 'textarea', 14 | title: '多行文本', 15 | setting: setting, 16 | build: textarea, 17 | validator(field, value){ 18 | if(field.required && isEmpty(value)) return Promise.reject('必填') 19 | return Promise.resolve() 20 | }, 21 | logic: [ 22 | STRING_VALUE_COMPARE, 23 | STRING_LENGTH_COMPARE 24 | ] 25 | }) -------------------------------------------------------------------------------- /document/assets/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /document/docs/components/XFormItem.md: -------------------------------------------------------------------------------- 1 | # XFormItem 2 | 通常情况下,`XFormDesigner`、`XFormBuilder`和`XFormViewer`会默认使用该组件包裹每一个字段所对应的表单组件,**用于提供统一的布局和表单验证**。当你需要提供某些特殊的表单字段时,你需要使用该组件将字段包装,以便提供统一的验证。例如,需要在`XFormBuilder`中插入一些固定的表单字段: 3 | ```html 4 | 5 | 13 | 14 | ``` 15 | 16 | ## Props 17 | ### field 18 | - **类型**:`XField` 19 | - **说明**:字段配置。 20 | ### validation 21 | - **类型**:`boolean | () => Promise` 22 | - **说明**:字段配置。 -------------------------------------------------------------------------------- /document/assets/svg/github-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/__test__/FormSchema.spec.ts: -------------------------------------------------------------------------------- 1 | import { createSchema } from '../api' 2 | import { getPrivateProps } from '../util/lang' 3 | 4 | test('validate', async () => { 5 | const schema = createSchema({ 6 | fields: [ 7 | {}, 8 | { title: '字段1' }, 9 | { title: '字段2', fields: [{}] }, 10 | { title: '字段3', fields: [{ title: '字段3-1', fields: [{}] }] } 11 | ] 12 | }) 13 | 14 | const r = await schema.validate() 15 | expect(r.valid).toBe(false) 16 | expect(r.result.length).toBe(3) 17 | const result = r.result 18 | expect(result[2].fields[0].fields[0].valid).toBe(false) 19 | }) 20 | 21 | test('FormSchema: private props', () => { 22 | const schema = createSchema() 23 | expect(() => getPrivateProps(schema, Symbol())).toThrow() 24 | }) -------------------------------------------------------------------------------- /packages/core/api/Config.ts: -------------------------------------------------------------------------------- 1 | import { FormConfig } from '../model' 2 | import { clonePlainObject, mergePlainObject } from '../util' 3 | import { store, createConfig } from './Store' 4 | 5 | // TODO: 使用Proxy重构 6 | export function useConfig(config: FormConfig){ 7 | if(config == null) return 8 | 9 | const clone = clonePlainObject(config) 10 | mergePlainObject(store.config, clone) 11 | 12 | if(store.config.logic === true){ 13 | console.warn('[xForm]: 字段逻辑目前为实验性功能,未来可能会发生变更,请谨慎使用!') 14 | } 15 | } 16 | 17 | export function resetConfig(){ 18 | store.config = createConfig() 19 | } 20 | 21 | export function getConfig(){ 22 | return store.config 23 | } 24 | 25 | export function isImmediateValidate(){ 26 | return store.config.validation.immediate !== false 27 | } -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | transform: { 4 | "^.+\\.vue$": "@vue/vue3-jest", 5 | "^.+\\.js$": "babel-jest", 6 | "^.+\\.(svg|png)$": "/scripts/jest/raw-loader.js", 7 | '^.+\\.tsx?$': ['ts-jest', { babelConfig: true }] 8 | }, 9 | moduleFileExtensions: ["vue", "js", "jsx", "ts", "tsx"], 10 | moduleNameMapper: { 11 | "@common/(.*)": "/packages/common/$1", 12 | "@dongls/xform": "/packages/core/index.ts", 13 | "\\.module.css$": "identity-obj-proxy" 14 | }, 15 | setupFiles: [ 16 | '/scripts/jest/setup.js' 17 | ], 18 | testEnvironment: "jsdom", 19 | testEnvironmentOptions: { 20 | customExportConditions: [ 21 | 'node', 22 | 'node-addons' 23 | ] 24 | }, 25 | } -------------------------------------------------------------------------------- /packages/bootstrap/fields/divider/divider.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | -------------------------------------------------------------------------------- /packages/bootstrap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dongls/xform.bootstrap", 3 | "version": "0.8.1", 4 | "description": "基于Bootstrap的xForm字段库。", 5 | "main": "dist/index.js", 6 | "style": "dist/index.css", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/dongls/xForm.git" 10 | }, 11 | "homepage": "https://github.com/dongls/xForm", 12 | "keywords": [ 13 | "vue", 14 | "form", 15 | "xform" 16 | ], 17 | "author": { 18 | "name": "dongls", 19 | "email": "173110115@qq.com" 20 | }, 21 | "license": "MIT", 22 | "files": [ 23 | "dist" 24 | ], 25 | "peerDependencies": { 26 | "@dongls/xform": "0.8.1" 27 | }, 28 | "publishConfig": { 29 | "registry": "https://registry.npmjs.org", 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dongls/xform", 3 | "version": "0.8.1", 4 | "description": "Vue驱动的自定义表单套件。", 5 | "main": "dist/index.js", 6 | "style": "dist/index.css", 7 | "types": "dist/index.d.ts", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/dongls/xForm.git" 11 | }, 12 | "homepage": "https://github.com/dongls/xForm", 13 | "keywords": [ 14 | "vue", 15 | "form", 16 | "xform" 17 | ], 18 | "author": { 19 | "name": "dongls", 20 | "email": "173110115@qq.com" 21 | }, 22 | "license": "MIT", 23 | "files": [ 24 | "dist" 25 | ], 26 | "peerDependencies": { 27 | "vue": "^3.2.21" 28 | }, 29 | "publishConfig": { 30 | "registry": "https://registry.npmjs.org", 31 | "access": "public" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/common/svg/radio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/element-plus/fields/divider/divider.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | -------------------------------------------------------------------------------- /packages/element-plus/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dongls/xform.element-plus", 3 | "version": "0.8.1", 4 | "description": "基于Element Plus的xForm字段库。", 5 | "main": "dist/index.js", 6 | "style": "dist/index.css", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/dongls/xForm.git" 10 | }, 11 | "homepage": "https://github.com/dongls/xForm", 12 | "keywords": [ 13 | "vue", 14 | "form", 15 | "xform" 16 | ], 17 | "author": { 18 | "name": "dongls", 19 | "email": "173110115@qq.com" 20 | }, 21 | "license": "MIT", 22 | "files": [ 23 | "dist" 24 | ], 25 | "peerDependencies": { 26 | "@dongls/xform": "0.8.1" 27 | }, 28 | "publishConfig": { 29 | "registry": "https://registry.npmjs.org", 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/core/api/test/Config.spec.ts: -------------------------------------------------------------------------------- 1 | import { reset } from '..' 2 | import { 3 | resetConfig, 4 | useConfig, 5 | getConfig, 6 | isImmediateValidate, 7 | } from '../Config' 8 | 9 | describe('useConfig', () => { 10 | test('default config', () => { 11 | reset() 12 | const config = getConfig() 13 | 14 | expect(config).not.toBeNull() 15 | expect(config.modes).toBeNull() 16 | expect(config.validation.immediate).toBe(true) 17 | expect(config.genName).toBeInstanceOf(Function) 18 | }) 19 | 20 | test('validator.immediate', () => { 21 | resetConfig() 22 | useConfig({ validation: { immediate: false } }) 23 | 24 | const config = getConfig() 25 | expect(config.validation.immediate).toBe(false) 26 | expect(isImmediateValidate()).toBe(false) 27 | }) 28 | }) 29 | 30 | -------------------------------------------------------------------------------- /packages/element-plus/fields/date/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { DATE_VALUE_COMPARE } from '@element-plus/logic' 3 | 4 | import icon from '@common/svg/date.svg' 5 | import date from './date.vue' 6 | import setting from './setting.vue' 7 | 8 | export default Field.create({ 9 | icon: icon, 10 | type: 'date', 11 | title: '日期', 12 | setting: setting, 13 | build: date, 14 | onCreate(field){ 15 | field.attributes.format = field.attributes.format ?? 'YYYY-MM-DD' 16 | field.attributes.valueFormat = field.attributes.valueFormat ?? 'YYYY-MM-DD' 17 | }, 18 | validator(field, value: string){ 19 | if(field.required && isEmpty(value)) return Promise.reject('必填') 20 | return Promise.resolve() 21 | }, 22 | logic: [ 23 | DATE_VALUE_COMPARE 24 | ] 25 | }) -------------------------------------------------------------------------------- /packages/element-plus/fields/text/text.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | -------------------------------------------------------------------------------- /packages/element-plus/fields/number/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { NUMBER_VALUE_COMPARE } from '@element-plus/logic' 3 | 4 | import icon from '@common/svg/number.svg' 5 | import setting from './setting.vue' 6 | import number from './number.vue' 7 | 8 | export default Field.create({ 9 | icon, 10 | type: 'number', 11 | title: '数字', 12 | setting, 13 | build: number, 14 | validator(field, value: number | string){ 15 | if(field.required && isEmpty(value)) return Promise.reject('必填') 16 | if(field.attributes.integer && !/^[-+]?[1-9]?\d+$/.test(value + '')) return Promise.reject('请输入整数') 17 | 18 | return Promise.resolve() 19 | }, 20 | onValueInit(field, value){ 21 | return parseFloat(value) 22 | }, 23 | logic: [ 24 | NUMBER_VALUE_COMPARE 25 | ] 26 | }) -------------------------------------------------------------------------------- /packages/bootstrap/fields/date/date.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 35 | -------------------------------------------------------------------------------- /packages/bootstrap/fields/text/text.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 35 | -------------------------------------------------------------------------------- /packages/bootstrap/fields/select/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { OPTION_VALUE_COMPARE } from '@bootstrap/logic' 3 | 4 | import icon from '@common/svg/select.svg' 5 | import select from './select.vue' 6 | import setting from './setting.vue' 7 | 8 | export default Field.create({ 9 | icon: icon, 10 | type: 'select', 11 | title: '下拉选择', 12 | setting: setting, 13 | build: select, 14 | validator(field, value){ 15 | if(field.required && isEmpty(value)) return Promise.reject('必填') 16 | return Promise.resolve() 17 | }, 18 | onCreate(field, params, init){ 19 | const options = Array.isArray(params.options) ? params.options : [] 20 | if(init) options.push({ value: '选项1' }) 21 | 22 | field.options = options 23 | }, 24 | logic: [ 25 | OPTION_VALUE_COMPARE 26 | ] 27 | }) -------------------------------------------------------------------------------- /packages/element-plus/fields/select/index.ts: -------------------------------------------------------------------------------- 1 | import { Field, isEmpty } from '@dongls/xform' 2 | import { OPTION_VALUE_COMPARE } from '@element-plus/logic' 3 | 4 | import icon from '@common/svg/select.svg' 5 | import select from './select.vue' 6 | import setting from './setting.vue' 7 | 8 | export default Field.create({ 9 | icon: icon, 10 | type: 'select', 11 | title: '下拉选择', 12 | setting: setting, 13 | build: select, 14 | validator(field, value){ 15 | if(field.required && isEmpty(value)) return Promise.reject('必填') 16 | return Promise.resolve() 17 | }, 18 | onCreate(field, params, init){ 19 | const options = Array.isArray(params.options) ? params.options : [] 20 | if(init) options.push({ value: '选项1' }) 21 | 22 | field.options = options 23 | }, 24 | logic: [ 25 | OPTION_VALUE_COMPARE 26 | ] 27 | }) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "baseUrl": ".", 5 | "esModuleInterop": true, 6 | "jsx": "preserve", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "outDir": "./dist/", 12 | "paths": { 13 | "@common/*": ["packages/common/*"], 14 | "@document/*": ["document/*"], 15 | "@bootstrap/*": ["packages/bootstrap/*"], 16 | "@element-plus/*": ["packages/element-plus/*"], 17 | "@dongls/xform": ["packages/core/index"] 18 | }, 19 | "target": "ESNext" 20 | }, 21 | "include": [ 22 | "packages/**/*.ts", 23 | "packages/**/*.tsx", 24 | "packages/**.d.ts", 25 | "packages/**/*.vue", 26 | "document/**/*.ts", 27 | "document/**/*.tsx", 28 | "document/**/*.vue" 29 | ] 30 | } -------------------------------------------------------------------------------- /packages/bootstrap/fields/textarea/textarea.vue: -------------------------------------------------------------------------------- 1 |