amis-saas-7517 editor

Change-Id: I3165b21aff1f0065ceddf6d025881a7e2b299d6c
This commit is contained in:
qkiroc 2022-11-16 10:25:42 +08:00
parent e470882ee7
commit 0f2a7dffe0
4 changed files with 235 additions and 9 deletions

View File

@ -229,6 +229,12 @@
}
}
.editor-code-tabs,
.editor-code-tabs-cont,
.editor-code-tabs-cont .in {
height: 100%;
}
// 左侧面板悬浮模式时的占位避免折叠状态遮挡内容区
.editor-left-panel-fixed-placeholder {
position: relative;

View File

@ -0,0 +1,70 @@
import React, {useEffect, useState} from 'react';
import {Editor} from 'amis-ui';
export interface AmisStyleCodeEditorProps {
value: any;
onChange: (value: any, diff: any) => void;
onPaste?: () => void;
disabled?: boolean;
$schemaUrl?: string;
$schema?: string;
className?: string;
}
function json2Css(data: any) {
let res = '';
for (let className in data) {
if (typeof data[className] === 'object') {
let value = [];
for (let key in data[className]) {
if (typeof data[className][key] !== 'object') {
if (data[className][key]) {
value.push(`${key}: ${data[className][key]};`);
}
} else {
for (let k in data[className][key]) {
if (data[className][key][k]) {
value.push(`${k}: ${data[className][key][k]};`);
}
}
}
}
res += `.${className} {
${value.join('\n ')}
}\n`;
}
}
return res;
}
function AmisStyleCodeEditor(props: AmisStyleCodeEditorProps) {
const [value, setValue] = useState(props.value);
debugger;
useEffect(() => {
setValue(props.value);
}, [props.value]);
console.log(json2Css(value));
return (
<Editor
value={json2Css(value)}
language="css"
options={{
automaticLayout: true,
lineNumbers: 'off',
glyphMargin: false,
tabSize: 2,
wordWrap: 'on',
lineDecorationsWidth: 0,
lineNumbersMinChars: 0,
selectOnLineNumbers: true,
scrollBeyondLastLine: false,
folding: true,
minimap: {
enabled: false
}
}}
/>
);
}
export default AmisStyleCodeEditor;

View File

@ -2,8 +2,13 @@ import React from 'react';
import {PanelProps} from '../../plugin';
import {autobind} from '../../util';
import AMisCodeEditor from './AMisCodeEditor';
import AmisStyleCodeEditor from './AmisStyleCodeEditor';
import {Tab, Tabs} from 'amis-ui';
export default class CodeEditorPanel extends React.Component<PanelProps> {
state = {
tabsKey: 'schema'
};
@autobind
handleCodePaste() {
setTimeout(() => {
@ -11,6 +16,11 @@ export default class CodeEditorPanel extends React.Component<PanelProps> {
}, 500);
}
@autobind
handleSelect(key: string) {
this.setState({tabsKey: key});
}
render() {
const {onChange, manager, store} = this.props;
@ -18,13 +28,45 @@ export default class CodeEditorPanel extends React.Component<PanelProps> {
<div className="ae-CodePanel">
<div className="panel-header"></div>
<div className="ae-CodePanel-content">
<AMisCodeEditor
value={store.valueWithoutHiddenProps}
onChange={onChange}
$schema={store.jsonSchemaUri}
$schemaUrl={manager.config.$schemaUrl}
onPaste={this.handleCodePaste}
/>
<Tabs
tabsMode="line"
activeKey={this.state.tabsKey}
onSelect={this.handleSelect}
className="editor-code-tabs"
linksClassName="editor-code-tabs-links"
contentClassName="editor-code-tabs-cont"
>
<Tab
key={'schema'}
eventKey={'schema'}
title={'Schema'}
mountOnEnter={true}
unmountOnExit={false}
>
<AMisCodeEditor
value={store.valueWithoutHiddenProps}
onChange={onChange}
$schema={store.jsonSchemaUri}
$schemaUrl={manager.config.$schemaUrl}
onPaste={this.handleCodePaste}
/>
</Tab>
<Tab
key={'style'}
eventKey={'style'}
title={'Style'}
mountOnEnter={true}
unmountOnExit={false}
>
<AmisStyleCodeEditor
value={store.cssValue}
onChange={onChange}
$schema={store.jsonSchemaUri}
$schemaUrl={manager.config.$schemaUrl}
onPaste={this.handleCodePaste}
/>
</Tab>
</Tabs>
</div>
</div>
);

View File

@ -40,6 +40,7 @@ import isPlainObject from 'lodash/isPlainObject';
import {EditorManagerConfig} from '../manager';
import {EditorNode, EditorNodeType} from './node';
import findIndex from 'lodash/findIndex';
import {cloneDeep} from 'lodash';
export interface SchemaHistory {
versionId: number;
@ -154,6 +155,7 @@ export const EditorStore = types
showInsertRenderer: false, // 是否显示插入组件面板(抽屉弹出模式)
schema: types.frozen(),
style: types.frozen(),
versionId: 0,
schemaHistory: types.optional(
types.array(types.frozen<SchemaHistory>()),
@ -497,8 +499,46 @@ export const EditorStore = types
return this.getValueOf(self.activeId);
},
get cssValue() {
if (!self.activeId) {
return undefined;
}
const schema = JSONGetById(self.schema, self.activeId);
return this.getCssValueof(schema)?.res;
},
getValueOf(id: string) {
return JSONPipeOut(JSONGetById(self.schema, id), false);
const schema = JSONGetById(self.schema, id);
const res = JSONPipeOut(
Object.assign({}, schema, this.getCssValueof(schema)?.css),
false
);
return res;
},
getCssValueof(schema: any) {
if (!self.style) {
return null;
}
const list = [];
for (let key in schema) {
if (/[c|C]lassName/.test(key)) {
const className = schema[key];
if (/(\S*[C|c]lassName-\S*)/.test(className)) {
list.push({
key,
value: /(\S*[C|c]lassName-\S*)/.exec(className)![0]
});
}
}
}
const css: any = {};
const res: any = {};
list.forEach(item => {
css[item.key] = self.style[item.value];
res[item.value] = self.style[item.value];
});
return {css: {css}, res};
},
get valueWithoutHiddenProps() {
@ -1181,7 +1221,11 @@ export const EditorStore = types
if (!self.activeId) {
return;
}
this.changeValueById(self.activeId, value, diff);
if (this.isStyleChange(diff)) {
this.changeStyle(value, diff);
} else {
this.changeValueById(self.activeId, value, diff);
}
},
changeValueById(
@ -1212,6 +1256,70 @@ export const EditorStore = types
}
},
isStyleChange(diff: any) {
if (
Array.isArray(diff) &&
!!diff.find(
(n: any) =>
!!n.path.find(
(path: any) =>
typeof path === 'string' && !!~path.indexOf('css')
)
)
) {
return true;
} else {
return false;
}
},
changeStyle(value: Schema, diff?: any) {
const styleDiff = diff.find(
(n: any) =>
!!n.path.find(
(path: any) => typeof path === 'string' && !!~path.indexOf('css')
)
);
const obj = cloneDeep(value);
const style = cloneDeep(self.style);
let key = '';
let styleValue = {};
const cssIndex = styleDiff.path.findIndex((path: any) =>
/css/.test(path)
);
key = styleDiff.path[cssIndex + 1];
if (!key) {
key = Object.keys(styleDiff.rhs)[0];
styleValue = obj.css[key];
} else {
const styleKey = styleDiff.path[cssIndex + 2];
if (styleKey) {
styleValue = {
[styleKey]: obj.css[key][styleKey]
};
} else {
styleValue = obj.css[key];
}
}
let classname = `${key}-${guid()}`;
if (!value[key]) {
obj[key] = classname;
} else if (/(\S*[C|c]lassName-\S*)/.test(obj[key])) {
classname = /(\S*[C|c]lassName-\S*)/.exec(obj[key])![0];
} else {
obj[key] += ' ' + classname;
}
self.style = Object.assign(style || {}, {
[classname]: Object.assign(
style ? style[classname] || {} : {},
styleValue
)
});
delete obj.css;
this.changeValueById(self.activeId, obj);
},
moveUp(id: string) {
if (!id) {
return;