feat: 更换 json 查看组件,支持查看并修改功能 (#2360)

This commit is contained in:
liaoxuezhi 2021-08-06 20:03:00 +08:00 committed by GitHub
parent d9ef3ba9fe
commit 771c676424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 119 deletions

View File

@ -124,9 +124,12 @@ List 的内容、Card 卡片的内容配置同上
}, },
"body": [ "body": [
{ {
"type": "static-json", "type": "control",
"name": "json", "name": "json",
"label": "颜色" "label": "Json",
"body": {
"type": "json"
}
} }
] ]
} }
@ -186,6 +189,29 @@ List 的内容、Card 卡片的内容配置同上
如上,`levelExpand`配置为`0`,则默认不展开。 如上,`levelExpand`配置为`0`,则默认不展开。
## 开启 json 修改
> since 1.2.3
可配置`mutable` 为 true展示 json 的同时支持修改。记得配置 name 属性。
```schema: scope="body"
[
{
"type": "json",
"name": "json",
"mutable": true,
"value": {
"a": "a",
"b": "b",
"c": {
"d": "d"
}
}
}
]
```
## 属性表 ## 属性表
| 属性名 | 类型 | 默认值 | 说明 | | 属性名 | 类型 | 默认值 | 说明 |
@ -196,5 +222,5 @@ List 的内容、Card 卡片的内容配置同上
| source | `string` | `''` | 通过数据映射获取数据链中的值 | | source | `string` | `''` | 通过数据映射获取数据链中的值 |
| placeholder | `string` | `-` | 占位文本 | | placeholder | `string` | `-` | 占位文本 |
| levelExpand | `number` | `1` | 默认展开的层级 | | levelExpand | `number` | `1` | 默认展开的层级 |
| hideRoot | `boolean` | `false` | 是否隐藏根节点 |
| jsonTheme | `string` | `twilight` | 主题,可选`twilight`和`eighties` | | jsonTheme | `string` | `twilight` | 主题,可选`twilight`和`eighties` |
| mutable | `boolean` | `false` | 是否可修改 |

View File

@ -78,7 +78,7 @@
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-dropzone": "11.2.4", "react-dropzone": "11.2.4",
"react-input-range": "1.3.0", "react-input-range": "1.3.0",
"react-json-tree": "0.15.0", "react-json-view": "1.21.3",
"react-overlays": "0.8.3", "react-overlays": "0.8.3",
"react-textarea-autosize": "5.1.0", "react-textarea-autosize": "5.1.0",
"react-transition-group": "2.9.0", "react-transition-group": "2.9.0",

View File

@ -3,6 +3,7 @@ import React from 'react';
import {RendererProps, Renderer} from '../../factory'; import {RendererProps, Renderer} from '../../factory';
import {SchemaCollection} from '../../Schema'; import {SchemaCollection} from '../../Schema';
import {autobind} from '../../utils/helper'; import {autobind} from '../../utils/helper';
import {resolveVariable} from '../../utils/tpl-builtin';
import {FormBaseControl, FormItemWrap} from './Item'; import {FormBaseControl, FormItemWrap} from './Item';
/** /**
@ -24,8 +25,10 @@ export interface FormControlSchema extends FormBaseControl {
export class ControlRenderer extends React.Component<RendererProps> { export class ControlRenderer extends React.Component<RendererProps> {
@autobind @autobind
renderInput() { renderInput() {
const {render, body} = this.props; const {render, body, name, data} = this.props;
return render('inner', body); return render('inner', body, {
value: typeof name === 'string' ? resolveVariable(name, data) : undefined
});
} }
render() { render() {

View File

@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import {Renderer, RendererProps} from '../factory'; import {Renderer, RendererProps} from '../factory';
import JSONTree from 'react-json-tree'; import JsonView, {InteractionProps} from 'react-json-view';
import {autobind, getPropValue} from '../utils/helper'; import {autobind, getPropValue, noop} from '../utils/helper';
import {BaseSchema} from '../Schema'; import {BaseSchema} from '../Schema';
import {resolveVariableAndFilter, isPureVariable} from '../utils/tpl-builtin'; import {resolveVariableAndFilter, isPureVariable} from '../utils/tpl-builtin';
/** /**
@ -20,15 +20,15 @@ export interface JsonSchema extends BaseSchema {
*/ */
levelExpand?: number; levelExpand?: number;
/**
*
*/
hideRoot?: boolean;
/** /**
* *
*/ */
source?: string; source?: string;
/**
*
*/
mutable?: boolean;
} }
export interface JSONProps extends RendererProps, JsonSchema { export interface JSONProps extends RendererProps, JsonSchema {
@ -40,123 +40,46 @@ export interface JSONProps extends RendererProps, JsonSchema {
source?: string; source?: string;
} }
const twilight = {
scheme: 'twilight',
author: 'david hart (http://hart-dev.com)',
base00: '#1e1e1e',
base01: '#323537',
base02: '#464b50',
base03: '#5f5a60',
base04: '#838184',
base05: '#a7a7a7',
base06: '#c3c3c3',
base07: '#ffffff',
base08: '#cf6a4c',
base09: '#cda869',
base0A: '#f9ee98',
base0B: '#8f9d6a',
base0C: '#afc4db',
base0D: '#7587a6',
base0E: '#9b859d',
base0F: '#9b703f',
tree: {
border: 0,
padding: '0 0.625em 0.425em',
marginTop: '-0.25em',
marginBottom: '0',
marginLeft: '0',
marginRight: 0,
listStyle: 'none',
MozUserSelect: 'none',
WebkitUserSelect: 'none',
backgroundColor: 'rgba(255, 255, 255, 0.4)',
whiteSpace: 'nowrap',
display: 'inline-block',
width: '100%'
}
};
const eighties = {
scheme: 'eighties',
author: 'chris kempson (http://chriskempson.com)',
base00: '#2d2d2d',
base01: '#393939',
base02: '#515151',
base03: '#747369',
base04: '#a09f93',
base05: '#d3d0c8',
base06: '#e8e6df',
base07: '#f2f0ec',
base08: '#f2777a',
base09: '#f99157',
base0A: '#ffcc66',
base0B: '#99cc99',
base0C: '#66cccc',
base0D: '#6699cc',
base0E: '#cc99cc',
base0F: '#d27b53',
tree: {
border: 0,
padding: '0 0.625em 0.425em',
marginTop: '-0.25em',
marginBottom: '0',
marginLeft: '0',
marginRight: 0,
listStyle: 'none',
MozUserSelect: 'none',
WebkitUserSelect: 'none',
backgroundColor: '#2D2D2D',
whiteSpace: 'nowrap',
display: 'inline-block',
width: '100%'
}
};
const themes: any = {
twilight,
eighties
};
export class JSONField extends React.Component<JSONProps, object> { export class JSONField extends React.Component<JSONProps, object> {
static defaultProps: Partial<JSONProps> = { static defaultProps: Partial<JSONProps> = {
placeholder: '-', placeholder: '-',
levelExpand: 1, levelExpand: 1,
jsonTheme: 'twilight',
hideRoot: false,
source: '' source: ''
}; };
@autobind @autobind
valueRenderer(raw: any) { emitChange(e: InteractionProps) {
const cx = this.props.classnames; const {onChange, name} = this.props;
if (typeof raw === 'string' && /^\"?https?:\/\//.test(raw)) {
return ( if (!name || !onChange) {
<a return false;
className={cx('JsonField-nodeValue')}
rel="noopener"
href={raw.replace(/^\"(.*)\"$/, '$1')}
target="_blank"
>
{raw}
</a>
);
} }
return <span className={cx('JsonField-nodeValue')}>{raw}</span>;
onChange(e.updated_src, name);
return true;
} }
shouldExpandNode = (keyName: any, data: any, level: any) => { @autobind
shouldExpandNode({namespace}: {namespace: Array<string | null>}) {
const {levelExpand} = this.props; const {levelExpand} = this.props;
return level < levelExpand;
}; if (typeof levelExpand !== 'number') {
return false;
}
return namespace.length > levelExpand;
}
render() { render() {
const { const {
className, className,
jsonTheme, jsonTheme,
classnames: cx, classnames: cx,
hideRoot,
placeholder, placeholder,
source source,
levelExpand,
mutable,
name
} = this.props; } = this.props;
const value = getPropValue(this.props); const value = getPropValue(this.props);
@ -174,19 +97,21 @@ export class JSONField extends React.Component<JSONProps, object> {
} }
} }
const theme = themes[jsonTheme] ? themes[jsonTheme] : themes['twilight'];
return ( return (
<div className={cx('JsonField', className)}> <div className={cx('JsonField', className)}>
{typeof data === 'undefined' || data === null ? ( {typeof data === 'undefined' || data === null ? (
placeholder placeholder
) : ( ) : (
<JSONTree <JsonView
data={data} name={false}
theme={theme} src={data}
shouldExpandNode={this.shouldExpandNode} theme={(jsonTheme as any) ?? 'rjv-default'}
valueRenderer={this.valueRenderer} shouldCollapse={this.shouldExpandNode}
hideRoot={hideRoot} enableClipboard={false}
iconStyle="square"
onEdit={name && mutable ? this.emitChange : false}
onDelete={name && mutable ? this.emitChange : false}
onAdd={name && mutable ? this.emitChange : false}
/> />
)} )}
</div> </div>