Merge pull request #57 from alibaba/dev

This commit is contained in:
侑夕
2020-01-09 11:21:00 +08:00
committed by GitHub
14 changed files with 170 additions and 43 deletions

View File

@@ -1,5 +1,11 @@
# Change Log
### 0.4.5
- [+] 添加了“复杂联动”的相关 Demo 例子
- [+] 现在 labelWidth 允许输入 “20%”“2.5rem” 等
- [!] 修复了一个类型为对象的自定义组件初始值始终为空的问题
### 0.4.4
- [+] 发布了 schema 书写利器 `form-render snippets`vscode 插件),在 vscode 商店中搜索“formrender”

View File

@@ -109,16 +109,16 @@ ReactDOM.render(<Demo />, rootElement);
### API
| Prop | Type | Required | Default | Description |
| ----------------- | :--------: | :------: | :--------: | :---------------------------------------------: |
| **`name`** | `String` | `Y` | `$form` | 表单的名称 |
| **`propsSchema`** | `Object` | `Y` | `{}` | 表单属性配置 json |
| **`uiSchema`** | `Object` | `N` | `{}` | 表单 UI 配置 json |
| **`formData`** | `Object` | `N` | `{}` | 配置数据 |
| **`onChange`** | `Function` | `Y` | `() => {}` | 数据更改回调函数 |
| **`onValidate`** | `Function` | `N` | `() => {}` | 表单输入校验回调 |
| **`displayType`** | `String` | `N` | `column` | 设置表单横向排列或者纵向排序`column`/ `row` |
| **`readOnly`** | `Boolean` | `N` | `false` | 预览模式/可编辑模式 |
| **`labelWidth`** | `Number` | `N` | `120` | label 的长度,指明 label 的长度px默认 120 |
| ------------------ | :---------------: | :------: | :--------: | :-------------------------------------------------------------------: |
| **`propsSchema`** | `Object` | ✓ | `{}` | 表单属性配置 json |
| **`uiSchema`** | `Object` | | `{}` | 表单 UI 配置 json(可以合并到 propsSchema |
| **`formData`** | `Object` | | `{}` | 配置数据 |
| **`onChange`** | `Function` | | `() => {}` | 数据更改回调函数 |
| **`onValidate`** | `Function` | | `() => {}` | 表单输入校验回调 |
| **`displayType`** | `String` | | `column` | 设置表单横向排列或者纵向排序`column`/ `row` |
| **`showDescIcon`** | `Boolean` | | `false` | 描述是否用 tooltip 展示。`displayType` `row`时建议设为 `true` |
| **`readOnly`** | `Boolean` | | `false` | 预览模式/可编辑模式 |
| **`labelWidth`** | `Number`/`String` | | `110` | label 的长度,默认 110。如为数字则单位是 px也可以使用'20%'/'2rem'等 |
**注 1** 设置表单 `displayType` 为 row 时候,请设置 `showDescIcon``true`,隐藏说明,效果会更好
**注 2** **onChange** 方法会用于初始化表单 data如果不写会造成没有初始值的表单元素无法渲染出现不报错也不显示的情况
@@ -128,11 +128,11 @@ ReactDOM.render(<Demo />, rootElement);
| Prop | Type | Required | Default | Description |
| ------------------ | :-------: | :------: | :-----: | :-----------------------------------------------: |
| **`column`** | `Number` | `1` | `N` | 整体布局 1 排 N局部的 1 排 N 一般使用`ui:width` |
| **`showValidate`** | `Boolean` | `N` | `true` | 是否展示校验信息 |
| **`showDescIcon`** | `Boolean` | `N` | `false` | 是否将文字形式说明显示成描述 tooltip 形式 |
| **`widgets`** | `Object` | `N` | `{}` | 自定义组件 |
| **`mapping`** | `Object` | `N` | `{}` | 用于修改默认组件映射表 |
| **`column`** | `Number` | | `1` | 整体布局 1 排 N局部的 1 排 N 一般使用`ui:width` |
| **`widgets`** | `Object` | | `{}` | 自定义组件 |
| **`name`** | `String` | | `$form` | 表单的名称 |
| **`showValidate`** | `Boolean` | | `true` | 是否展示校验信息 |
| **`mapping`** | `Object` | | `{}` | 用于修改默认组件映射表 |
## 快速书写 schema

View File

@@ -20,7 +20,7 @@ class Root extends Component {
displayType: 'column',
showDescIcon: false,
readOnly: false,
labelWidth: 120,
labelWidth: 110,
};
onThemeChange = e => {
@@ -72,6 +72,7 @@ class Root extends Component {
>
<Radio value="simplest">最简样例</Radio>
<Radio value="basic">基础控件</Radio>
<Radio value="function">复杂联动</Radio>
<Radio value="input">个性输入框</Radio>
<Radio value="select">个性选择框</Radio>
<Radio value="date">日期</Radio>

92
demo/json/function.json Normal file
View File

@@ -0,0 +1,92 @@
{
"propsSchema": {
"type": "object",
"properties": {
"case1": {
"title": "整体隐藏",
"type": "object",
"properties": {
"showMore": {
"title": "显示更多",
"type": "boolean"
},
"x1": {
"title": "输入框1",
"type": "string",
"ui:hidden": "{{rootValue.showMore === false}}"
},
"x2": {
"title": "输入框2",
"type": "string",
"ui:hidden": "{{rootValue.showMore === false}}"
}
}
},
"case2": {
"title": "选项联动",
"type": "object",
"properties": {
"bi": {
"title": "汇款币种",
"type": "string",
"enum": ["rmb", "dollar"],
"enumNames": ["人民币", "美元"]
},
"inputName": {
"title": "金额",
"description": "{{rootValue.bi === 'dollar' ? '一次汇款不超过150美元':'一次汇款不超过1000元'}}",
"type": "string",
"ui:options": "{{{addonBefore: rootValue.bi === 'rmb'? '¥':'$', addonAfter: rootValue.bi === 'rmb'? '元':'美元'}}}"
}
}
},
"case3": {
"title": "列表/显示不同组件",
"type": "object",
"properties": {
"ruleList": {
"title": "球员筛选",
"type": "array",
"items": {
"type": "object",
"properties": {
"attr": {
"title": "标准",
"type": "string",
"enum": ["goal", "league"],
"enumNames": ["入球数", "所在联盟"],
"ui:width": "40%"
},
"relation": {
"title": "-",
"type": "string",
"enum": [">", "<", "="],
"ui:hidden": "{{rootValue.attr === 'league'}}",
"ui:width": "20%"
},
"goal": {
"title": "入球数",
"type": "string",
"pattern": "^[0-9]+$",
"message": {
"pattern": "输入正确得分"
},
"ui:hidden": "{{rootValue.attr !== 'goal'}}",
"ui:width": "40%"
},
"league": {
"title": "名称",
"type": "string",
"enum": ["a", "b", "c"],
"enumNames": ["西甲", "英超", "中超"],
"ui:hidden": "{{rootValue.attr !== 'league'}}",
"ui:width": "40%"
}
}
}
}
}
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -63,7 +63,7 @@ fs.writeFileSync(path.join(__dirname, 'schema.json'), JSON.stringify(apiInfo, nu
<table><tr><td>React 输入</td><td>标准Json schema 输出</td><td>带 Ui 配置的 schema 输出</td></tr><tr><td><img src="https://img.alicdn.com/tfs/TB1jVQFtuuSBuNjy1XcXXcYjFXa-1004-1310.png" width="420"></td><td><img src="https://gw.alicdn.com/tfs/TB14I0Rzx1YBuNjy1zcXXbNcXXa-862-1538.png" width="310"></td><td><img src="https://gw.alicdn.com/tfs/TB1r9QFwXmWBuNjSspdXXbugXXa-898-1460.png" width="340"></td></tr></table>
可以参考 [Demo](http://github.com/tw93/proptypes-to-json-schema/tree/master/demo) 中的使用
可以参考 [Demo](http://github.com/form-render/proptypes-to-json-schema/tree/master/demo) 中的使用
## Changelog

View File

@@ -21,32 +21,21 @@ Could not find a declaration file for module 'form-render/lib/antd'. '/Users/nas
因为 form-render 是以 JavaScript 书写,缺少 typescript 的声明文件。
目前在 ts 项目中使用 form-render 只需自己创建一个 `index.d.ts`,具体如下:
1. 创建一个 `types` 目录,用来存放所有声明文件。可将 `form-render` 的声明文件放到 `types/form-render/index.d.ts`
1. `src`创建一个 `types` 目录,用来存放所有声明文件 `index.d.ts`
目录结构如下:
```
/path/to/project
├── src
| ── index.ts
── types
| └── form-render
| ── index.ts
| └── types
| └── index.d.ts
|
└── tsconfig.json
```
2. 注意在 `tsconfig.json` 中需要 `include` types 文件夹
```json
{
"compilerOptions": {
...
},
"include": ["src", "types"]
}
```
3. `form-render/index.d.ts` 文件如下书写。注意使用 fusion 的同学 module 名称变为`'form-render/lib/fusion'`
2. `index.d.ts` 文件如下书写。注意使用 fusion 的同学 module 名称变为`'form-render/lib/fusion'`
```js
declare module 'form-render/lib/antd' {

View File

@@ -60,7 +60,7 @@
}
.fr-validate {
margin: 3px 0 0 12px;
margin-left: 12px;
font-size: 12px;
word-break: break-all;
color: #f5222d;
@@ -69,7 +69,7 @@
/* Row */
.fr-validate-row {
margin-left: 0;
margin: 3px 0 0 0;
}
.fr-label-row {

View File

@@ -1,6 +1,6 @@
{
"name": "form-render",
"version": "0.4.4",
"version": "0.4.5",
"description": "通过 JSON Schema 生成标准 Form常用于自定义搭建配置界面生成",
"repository": {
"type": "git",

View File

@@ -2,7 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
import { getValidateText } from './validate';
import { isHidden, isDependShow } from './isHidden';
import { evaluateString, isLooselyNumber, isFunction } from './utils';
import {
evaluateString,
isLooselyNumber,
isCssLength,
isFunction,
} from './utils';
// asField拆分成逻辑组件和展示组件从而可替换展示组件的方式完全插拔fr的样式
export const asField = ({ FieldUI, Widget }) => {
@@ -218,7 +223,11 @@ export const DefaultFieldUI = ({
contentClass += ' flex justify-end pr2';
}
const _labelWidth = isLooselyNumber(labelWidth) ? Number(labelWidth) : 120; // 默认是 25% 的长度
const _labelWidth = isLooselyNumber(labelWidth)
? Number(labelWidth)
: isCssLength(labelWidth)
? labelWidth
: 110; // 默认是 110px 的长度
let labelStyle = { width: _labelWidth };
if (type === 'boolean') {
labelStyle = { flexGrow: 1 };

View File

@@ -53,6 +53,7 @@ function resolve(schema, data, options = {}) {
// 必选值,对象的子集
default: def,
required = [],
'ui:widget': widget,
} = schema;
const {
// 按照required规则做数据补全
@@ -62,6 +63,13 @@ function resolve(schema, data, options = {}) {
const value =
typeof data === 'undefined' ? getDefaultValue(schema) : clone(data);
if (type === 'object') {
// 如果自定义组件
if (widget) {
if (def && typeof def === 'object') {
return def;
}
return value;
}
const subs = properties || {};
const ret = {};
Object.keys(subs).forEach(name => {
@@ -74,6 +82,8 @@ function resolve(schema, data, options = {}) {
return ret;
}
if (type === 'array') {
// 如果自定义组件
if (widget) return value;
if (def && Array.isArray(def)) {
return def;
}

View File

@@ -21,6 +21,11 @@ export function isLooselyNumber(num) {
return false;
}
export function isCssLength(str) {
if (typeof str !== 'string') return false;
return str.match(/^([0-9])*(%|px|rem|em)$/i);
}
// 深度对比
export function isDeepEqual(param1, param2) {
if (param1 === undefined && param2 === undefined) return true;
@@ -182,3 +187,18 @@ export function isFunction(func) {
}
return false;
}
// 判断schema中是否有属性值是函数表达式
export function isFunctionSchema(schema) {
return Object.keys(schema).some(key => {
if (typeof schema[key] === 'function') {
return true;
} else if (typeof schema[key] === 'string') {
return isFunction(schema[key]);
} else if (typeof schema[key] === 'object') {
return isFunctionSchema(schema[key]);
} else {
return false;
}
});
}

View File

@@ -79,7 +79,7 @@ class FormRender extends React.Component {
onChange: () => {},
onValidate: () => {},
readOnly: false,
labelWidth: 120,
labelWidth: 110,
};
constructor() {

View File

@@ -9,7 +9,7 @@ module.exports = {
antd: './antd.js',
fusion: './fusion.js',
},
devtool: 'inline-source-map',
devtool: 'source-map', // smaller bundle size: https://webpack.js.org/configuration/devtool/
output: {
filename: '[name].js',
path: resolve(__dirname, 'dist'),