mirror of
https://github.com/zhigang1992/form-render.git
synced 2026-06-14 17:49:04 +08:00
Merge pull request #33 from alibaba/dev
修复了日期组件formData修改后ui展示上不更新的问题。 列表可以使用ui:readonly进入“只读”模式
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# Change Log
|
||||
|
||||
### 0.3.2
|
||||
|
||||
- [!] 列表支持`ui:readonly`进入只读模式,不允许对列表进行增、删和拖拽操作
|
||||
- [!] fix 了日期类组件传入数据变化后显示日期无变化的 bug
|
||||
|
||||
### 0.3.1
|
||||
|
||||
- [+] 重磅:schema 里大部分属性现在都支持函数表达式,方便表单组件间的关联(详见文档 UISchema、PropsSchema 部分)
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<body>
|
||||
<div id="__render_content_"></div>
|
||||
|
||||
<script src="//unpkg.com/react@16.x/umd/react.production.min.js"></script>
|
||||
<script src="//unpkg.com/react@16.x/umd/react.development.js"></script>
|
||||
|
||||
<script src="//unpkg.com/react-dom@16.x/umd/react-dom.production.min.js"></script>
|
||||
<script src="//unpkg.com/react-dom@16.x/umd/react-dom.development.js"></script>
|
||||
|
||||
<script src="//unpkg.com/prop-types@15.x/prop-types.min.js"></script>
|
||||
|
||||
|
||||
@@ -63,7 +63,14 @@
|
||||
### 控制表单项的 UI 展示(共通配置)
|
||||
|
||||
- `ui:disabled`: 可控制 input、number、date、checkbox、radio、select、switch 对于组件的 disabled 属性(变灰不可点击)
|
||||
- `ui:readonly`:可控制 input、number 组件中的 readonly 属性(不可编辑,但不变灰)
|
||||
- `ui:readonly`:可控制 input、number 组件中的 readonly 属性(不可编辑,但不变灰),列表也支持`readonly`,效果是列表的控件都会隐藏,导致列表不能增、删和拖拽,进入“只读”模式。但注意列表内的内容还是允许修改的,所以特别要注意如果列表套列表的场景,内部的列表也要 "ui:readonly": true
|
||||
|
||||
```js
|
||||
"someList": {
|
||||
"ui:readonly": true
|
||||
}
|
||||
```
|
||||
|
||||
- `ui:hidden`:可控制所有基础组件是否显示,可使用 true/false 或表达式,例如:
|
||||
|
||||
```json
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "form-render",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"description": "通过 JSON Schema 生成标准 Form,常用于自定义搭建配置界面生成",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -9,21 +9,7 @@ function clone(data) {
|
||||
|
||||
// 获取当前字段默认值
|
||||
function getDefaultValue({ default: def, enum: enums = [], type }) {
|
||||
// 如果设置默认值,优先从默认值中获取
|
||||
if (typeof def !== 'undefined') {
|
||||
return def;
|
||||
}
|
||||
// array且enum的情况,为多选框,默认值[]
|
||||
if (type === 'array' && enums.length > 0) {
|
||||
return [];
|
||||
}
|
||||
// 如果enum是表达式,不处理
|
||||
// 如果设置枚举值,其次从枚举值中获取
|
||||
if (Array.isArray(enums) && enums[0] && typeof enums[0] !== 'undefined') {
|
||||
return enums[0];
|
||||
}
|
||||
// 最后使用对应基础类型的默认值
|
||||
return {
|
||||
const defaultValue = {
|
||||
array: [],
|
||||
boolean: false,
|
||||
integer: '',
|
||||
@@ -32,7 +18,45 @@ function getDefaultValue({ default: def, enum: enums = [], type }) {
|
||||
object: {},
|
||||
string: '',
|
||||
range: null,
|
||||
}[type];
|
||||
};
|
||||
|
||||
const isFunction = func => {
|
||||
if (typeof func === 'function') {
|
||||
return true;
|
||||
}
|
||||
if (typeof func === 'string' && func.substring(0, 1) === '@') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (isFunction(def)) {
|
||||
return defaultValue[type];
|
||||
}
|
||||
if (isFunction(enums)) {
|
||||
if (type === 'array') {
|
||||
return [];
|
||||
}
|
||||
if (type === 'string' || type === 'number') {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// 如果设置默认值,优先从默认值中获取
|
||||
if (typeof def !== 'undefined') {
|
||||
return def;
|
||||
}
|
||||
// array且enum的情况,为多选框,默认值[]
|
||||
if (type === 'array' && enums.length) {
|
||||
return [];
|
||||
}
|
||||
// 如果enum是表达式,不处理
|
||||
// 如果设置枚举值,其次从枚举值中获取
|
||||
if (Array.isArray(enums) && enums[0] && typeof enums[0] !== 'undefined') {
|
||||
return enums[0];
|
||||
}
|
||||
// 最后使用对应基础类型的默认值
|
||||
return defaultValue[type];
|
||||
}
|
||||
|
||||
function resolve(schema, data, options = {}) {
|
||||
@@ -44,6 +68,7 @@ function resolve(schema, data, options = {}) {
|
||||
// 数组子集
|
||||
items,
|
||||
// 必选值,对象的子集
|
||||
default: def,
|
||||
required = [],
|
||||
} = schema;
|
||||
const {
|
||||
@@ -66,6 +91,9 @@ function resolve(schema, data, options = {}) {
|
||||
return ret;
|
||||
}
|
||||
if (type === 'array') {
|
||||
if (def) {
|
||||
return value;
|
||||
}
|
||||
const subs = [].concat(items || []);
|
||||
const ret = [];
|
||||
value.forEach &&
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function date(p) {
|
||||
let defaultObj = {};
|
||||
if (p.value) {
|
||||
defaultObj = {
|
||||
defaultValue: moment(p.value, dateFormat),
|
||||
value: moment(p.value, dateFormat),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class ListItem extends React.Component {
|
||||
render() {
|
||||
const { item, p = {}, name, fold } = this.props;
|
||||
const descProps = { ...p, index: name };
|
||||
const { options = {} } = p;
|
||||
const { options = {}, readonly } = p;
|
||||
const { foldable: canFold, hideDelete } = options;
|
||||
// 只有当items为object时才做收起(fold)处理
|
||||
const isObj = p.schema.items && p.schema.items.type == 'object';
|
||||
@@ -72,8 +72,8 @@ class ListItem extends React.Component {
|
||||
style={{ position: 'absolute', top: 12, right: 36 }}
|
||||
/>
|
||||
)}
|
||||
<DragHandle />
|
||||
{!((canFold && fold) || hideDelete) && (
|
||||
{!readonly && <DragHandle />}
|
||||
{!((canFold && fold) || hideDelete || readonly) && (
|
||||
<Button
|
||||
className="self-end"
|
||||
type="dashed"
|
||||
@@ -105,6 +105,7 @@ class FieldList extends React.Component {
|
||||
|
||||
render() {
|
||||
const { p, foldList = [], toggleFoldItem } = this.props;
|
||||
const { readonly } = p;
|
||||
const list = p.value || [];
|
||||
return (
|
||||
<ul className="pl0 ma0">
|
||||
@@ -127,37 +128,39 @@ class FieldList extends React.Component {
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
<div className="tr">
|
||||
<Button className="" icon="file-add" onClick={this.handleAddClick}>
|
||||
新增
|
||||
</Button>
|
||||
{p.extraButtons &&
|
||||
p.extraButtons.length > 0 &&
|
||||
p.extraButtons.map(item => (
|
||||
<Button
|
||||
className="ml2"
|
||||
icon={item.icon}
|
||||
onClick={() => {
|
||||
if (item.callback === 'clearAll') {
|
||||
p.onChange(p.name, []);
|
||||
return;
|
||||
}
|
||||
if (item.callback === 'copyLast') {
|
||||
const value = [...p.value];
|
||||
const lastIndex = value.length - 1;
|
||||
value.push(lastIndex > -1 ? value[lastIndex] : p.newItem);
|
||||
p.onChange(p.name, value);
|
||||
return;
|
||||
}
|
||||
if (typeof window[item.callback] === 'function') {
|
||||
window[item.callback].call(); // eslint-disable-line
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.text}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
{!readonly && (
|
||||
<div className="tr">
|
||||
<Button className="" icon="file-add" onClick={this.handleAddClick}>
|
||||
新增
|
||||
</Button>
|
||||
{p.extraButtons &&
|
||||
p.extraButtons.length > 0 &&
|
||||
p.extraButtons.map(item => (
|
||||
<Button
|
||||
className="ml2"
|
||||
icon={item.icon}
|
||||
onClick={() => {
|
||||
if (item.callback === 'clearAll') {
|
||||
p.onChange(p.name, []);
|
||||
return;
|
||||
}
|
||||
if (item.callback === 'copyLast') {
|
||||
const value = [...p.value];
|
||||
const lastIndex = value.length - 1;
|
||||
value.push(lastIndex > -1 ? value[lastIndex] : p.newItem);
|
||||
p.onChange(p.name, value);
|
||||
return;
|
||||
}
|
||||
if (typeof window[item.callback] === 'function') {
|
||||
window[item.callback].call(); // eslint-disable-line
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.text}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function date(p) {
|
||||
let defaultObj = {};
|
||||
if (p.value) {
|
||||
defaultObj = {
|
||||
defaultValue: moment(p.value, dateFormat),
|
||||
value: moment(p.value, dateFormat),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class ListItem extends React.Component {
|
||||
render() {
|
||||
const { item, p = {}, name, fold } = this.props;
|
||||
const descProps = { ...p, index: name };
|
||||
const { options = {} } = p;
|
||||
const { options = {}, readonly } = p;
|
||||
const { foldable: canFold, hideDelete } = options;
|
||||
// 只有当items为object时才做收起(fold)处理
|
||||
const isObj = p.schema.items && p.schema.items.type == 'object';
|
||||
@@ -69,8 +69,8 @@ class ListItem extends React.Component {
|
||||
style={{ position: 'absolute', top: 12, right: 36 }}
|
||||
/>
|
||||
)}
|
||||
<DragHandle />
|
||||
{!((canFold && fold) || hideDelete) && (
|
||||
{!readonly && <DragHandle />}
|
||||
{!((canFold && fold) || hideDelete || readonly) && (
|
||||
<Button
|
||||
className="self-end"
|
||||
onClick={() => {
|
||||
@@ -100,6 +100,7 @@ class FieldList extends React.Component {
|
||||
|
||||
render() {
|
||||
const { p, foldList = [], toggleFoldItem } = this.props;
|
||||
const { readonly } = p;
|
||||
const list = p.value || [];
|
||||
return (
|
||||
<ul className="pl0 ma0">
|
||||
@@ -122,38 +123,40 @@ class FieldList extends React.Component {
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
<div className="tr">
|
||||
<Button className="" onClick={this.handleAddClick}>
|
||||
<Icon type="add" />
|
||||
新增
|
||||
</Button>
|
||||
{p.extraButtons &&
|
||||
p.extraButtons.length > 0 &&
|
||||
p.extraButtons.map(item => (
|
||||
<Button
|
||||
className="ml2"
|
||||
onClick={() => {
|
||||
if (item.callback === 'clearAll') {
|
||||
p.onChange(p.name, []);
|
||||
return;
|
||||
}
|
||||
if (item.callback === 'copyLast') {
|
||||
const value = [...p.value];
|
||||
const lastIndex = value.length - 1;
|
||||
value.push(lastIndex > -1 ? value[lastIndex] : p.newItem);
|
||||
p.onChange(p.name, value);
|
||||
return;
|
||||
}
|
||||
if (typeof window[item.callback] === 'function') {
|
||||
window[item.callback].call(); // eslint-disable-line
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon type={item.icon} />
|
||||
{item.text}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
{!readonly && (
|
||||
<div className="tr">
|
||||
<Button className="" onClick={this.handleAddClick}>
|
||||
<Icon type="add" />
|
||||
新增
|
||||
</Button>
|
||||
{p.extraButtons &&
|
||||
p.extraButtons.length > 0 &&
|
||||
p.extraButtons.map(item => (
|
||||
<Button
|
||||
className="ml2"
|
||||
onClick={() => {
|
||||
if (item.callback === 'clearAll') {
|
||||
p.onChange(p.name, []);
|
||||
return;
|
||||
}
|
||||
if (item.callback === 'copyLast') {
|
||||
const value = [...p.value];
|
||||
const lastIndex = value.length - 1;
|
||||
value.push(lastIndex > -1 ? value[lastIndex] : p.newItem);
|
||||
p.onChange(p.name, value);
|
||||
return;
|
||||
}
|
||||
if (typeof window[item.callback] === 'function') {
|
||||
window[item.callback].call(); // eslint-disable-line
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon type={item.icon} />
|
||||
{item.text}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { resolve } = require('path');
|
||||
const webpack = require('webpack');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
@@ -38,27 +38,24 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
'css-loader'
|
||||
],
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new MonacoWebpackPlugin({
|
||||
languages: ['json'],
|
||||
features: ['snippets', 'suggest']
|
||||
features: ['snippets', 'suggest'],
|
||||
}),
|
||||
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
||||
new HtmlWebpackPlugin({
|
||||
resources: {
|
||||
js: [
|
||||
'react@16.x/umd/react.production.min.js',
|
||||
'react-dom@16.x/umd/react-dom.production.min.js',
|
||||
'react@16.x/umd/react.development.js',
|
||||
'react-dom@16.x/umd/react-dom.development.js',
|
||||
'prop-types@15.x/prop-types.min.js',
|
||||
'moment@2.24.0/min/moment.min.js',
|
||||
'@alifd/next@1.x/dist/next.min.js'
|
||||
'@alifd/next@1.x/dist/next.min.js',
|
||||
],
|
||||
css: ['@alifd/next@1.x/dist/next.min.css'],
|
||||
},
|
||||
@@ -73,14 +70,14 @@ module.exports = {
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
unused: true,
|
||||
drop_debugger: true
|
||||
drop_debugger: true,
|
||||
},
|
||||
warnings: false,
|
||||
output: {
|
||||
comments: false
|
||||
}
|
||||
}
|
||||
})
|
||||
comments: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
externals: {
|
||||
react: 'var window.React',
|
||||
@@ -101,7 +98,7 @@ module.exports = {
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx'],
|
||||
alias: {
|
||||
'monaco-editor': 'monaco-editor/esm/vs/editor/editor.api'
|
||||
}
|
||||
'monaco-editor': 'monaco-editor/esm/vs/editor/editor.api',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user