add example

This commit is contained in:
hufeixiong
2021-07-10 19:35:06 +08:00
parent b1133c8773
commit c27b4eb8e0
50 changed files with 5786 additions and 212 deletions

10
.gitignore vendored
View File

@@ -5,4 +5,12 @@ node_modules
yarn-error.log yarn-error.log
.vercel_build_output .vercel_build_output
build build
dist dist
/yarn-error.log
# umi
.umi
.umi-production
.umi-test
.env.local

View File

@@ -2,3 +2,11 @@
static/** static/**
build/** build/**
node_modules/** node_modules/**
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

View File

@@ -5,6 +5,8 @@
], ],
"scripts": { "scripts": {
"start": "lerna exec npm run start --scope=dooringx-lib", "start": "lerna exec npm run start --scope=dooringx-lib",
"start:example":"lerna exec npm run start --scope=dooringx-example",
"start:doc":"lerna exec npm run start --scope=dooringx-doc",
"build": "lerna exec npm run build --scope=dooringx-lib", "build": "lerna exec npm run build --scope=dooringx-lib",
"deploy": "lerna exec npm run deploy --scope=dooringx-doc", "deploy": "lerna exec npm run deploy --scope=dooringx-doc",
"pub": "node ./script/publish.js" "pub": "node ./script/publish.js"

View File

@@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

View File

@@ -0,0 +1,35 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 11:11:52
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 20:18:39
* @FilePath: \visual-editor\.umirc.ts
*/
import { defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
dynamicImport: {
loading: '@/components/Loading',
},
locale: {
default: 'zh-CN',
antd: true,
baseNavigator: true,
},
routes: [
{
exact: false,
path: '/',
component: '@/layouts/index',
routes: [
{ path: '/', component: '@/pages/index' },
{ path: '/preview', component: '@/pages/preview' },
{ path: '/iframe', component: '@/pages/iframe' },
],
},
],
fastRefresh: {},
});

View File

@@ -0,0 +1,15 @@
# umi project
## Getting Started
Install dependencies,
```bash
$ yarn
```
Start the dev server,
```bash
$ yarn start
```

View File

View File

@@ -0,0 +1,43 @@
{
"name":"dooringx-example",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "umi dev",
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"@ant-design/icons": "^4.6.2",
"antd": "^4.15.2",
"@ant-design/pro-layout": "^6.5.0",
"@umijs/preset-react": "1.x",
"umi": "^3.5.4",
"animate.css": "^4.1.1"
},
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@umijs/test": "^3.5.4",
"lint-staged": "^10.0.7",
"prettier": "^2.2.0",
"react": "17.x",
"react-dom": "17.x",
"typescript": "^4.1.2",
"yorkie": "^2.0.0"
}
}

View File

@@ -0,0 +1,11 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:59:34
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 15:00:05
* @FilePath: \visual-editor\src\components\Loading.tsx
*/
function Loading() {
return <div>loading</div>;
}
export default Loading;

View File

@@ -0,0 +1,8 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 20:11:11
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 20:11:29
* @FilePath: \visual-editor\src\constant\index.ts
*/
export const PREVIEWSTATE = 'PREVIEWSTATE';

View File

@@ -0,0 +1,3 @@
.ant-menu-title-content {
margin: 0 !important;
}

View File

@@ -0,0 +1,54 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:51:17
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 19:07:10
* @FilePath: \dooringx\packages\dooringx-example\src\layouts\index.tsx
*/
import { Button } from 'antd';
import { UserConfig } from 'dooringx-lib/dist';
import 'dooringx-lib/dist/dooringx-lib.esm.css';
import { createContext } from 'react';
import { IRouteComponentProps } from 'umi';
import plugin from '../plugin';
import 'antd/dist/antd.css';
import 'dooringx-lib/dist/dooringx-lib.esm';
import '../global.less';
import 'animate.css';
export const config = new UserConfig(plugin);
export const configContext = createContext<UserConfig>(config);
// 自定义右键
const contextMenuState = config.getContextMenuState();
const unmountContextMenu = contextMenuState.unmountContextMenu;
const commander = config.getCommanderRegister();
const ContextMenu = () => {
const handleclick = () => {
unmountContextMenu();
};
return (
<div
style={{
left: contextMenuState.left,
top: contextMenuState.top,
position: 'fixed',
background: 'rgb(24, 23, 23)',
}}
>
<div
style={{ width: '100%' }}
onClick={() => {
commander.exec('redo');
handleclick();
}}
>
<Button></Button>
</div>
</div>
);
};
contextMenuState.contextMenu = <ContextMenu></ContextMenu>;
export default function Layout({ children }: IRouteComponentProps) {
return <configContext.Provider value={config}>{children}</configContext.Provider>;
}

View File

@@ -0,0 +1,22 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 20:16:00
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 22:18:55
* @FilePath: \visual-editor\src\pages\iframe\index.tsx
*/
function IframePage() {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<iframe style={{ width: '375px', height: '667px' }} src="/preview"></iframe>
</div>
);
}
export default IframePage;

View File

@@ -0,0 +1,82 @@
/*
* @Author: yehuozhili
* @Date: 2021-05-15 12:49:28
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 19:08:25
* @FilePath: \dooringx\packages\dooringx-example\src\pages\index.tsx
*/
import {
RightConfig,
Container,
useStoreState,
innerContainerDragUp,
LeftConfig,
ContainerWrapper,
Control,
} from 'dooringx-lib';
import { useContext } from 'react';
import { configContext } from '@/layouts';
import { useCallback } from 'react';
import { PREVIEWSTATE } from '@/constant';
export const HeaderHeight = '40px';
export default function IndexPage() {
const config = useContext(configContext);
const everyFn = () => {};
const subscribeFn = useCallback(() => {
localStorage.setItem(PREVIEWSTATE, JSON.stringify(config.getStore().getData()));
}, [config]);
const [state] = useStoreState(config, subscribeFn, everyFn);
return (
<div {...innerContainerDragUp()}>
<div style={{ height: HeaderHeight }}>
head
<button
onClick={() => {
window.open('/iframe');
}}
>
go preview
</button>
<button
onClick={() => {
window.open('/preview');
}}
>
go preview
</button>
</div>
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: `calc(100vh - ${HeaderHeight})`,
width: '100vw',
}}
>
<div style={{ height: '100%' }}>
<LeftConfig config={config}></LeftConfig>
</div>
<ContainerWrapper>
<>
<Control
config={config}
style={{ position: 'fixed', bottom: '60px', right: '450px' }}
></Control>
<Container state={state} config={config} context="edit"></Container>
</>
</ContainerWrapper>
<div className="rightrender" style={{ height: '100%' }}>
<RightConfig state={state} config={config}></RightConfig>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,38 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 20:05:48
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 18:01:15
* @FilePath: \dooringx\packages\dooringx-example\src\pages\preview\index.tsx
*/
import { PREVIEWSTATE } from '@/constant';
import { Preview, UserConfig } from 'dooringx-lib';
import plugin from '../../plugin';
const config = new UserConfig(plugin);
function PreviewPage() {
const data = localStorage.getItem(PREVIEWSTATE);
if (data) {
try {
const json = JSON.parse(data);
config.resetData([json]);
} catch {
console.log('err');
}
}
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Preview config={config}></Preview>
</div>
);
}
export default PreviewPage;

View File

@@ -0,0 +1,20 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:27:01
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 14:27:38
* @FilePath: \visual-editor\src\plugin\commanderModules.ts
*/
import { CommanderItem } from 'dooringx-lib/dist/core/command/commanderType';
const modulesFiles = (require as any).context('./commands', true, /\.(js|ts)$/);
const commandModules: CommanderItem[] = modulesFiles
.keys()
.reduce((modules: any, modulePath: any) => {
const value = modulesFiles(modulePath);
modules.push(value.default);
return modules;
}, []);
export default commandModules;

View File

@@ -0,0 +1,18 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:28:20
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 14:28:28
* @FilePath: \visual-editor\src\plugin\commands\redo.ts
*/
import { CommanderItemFactory } from 'dooringx-lib';
const undo = new CommanderItemFactory(
'redo',
'Control+Shift+z',
(store) => {
store.redo();
},
'重做'
);
export default undo;

View File

@@ -0,0 +1,19 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:28:00
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 14:28:08
* @FilePath: \visual-editor\src\plugin\commands\undo.ts
*/
import { CommanderItemFactory } from 'dooringx-lib';
const undo = new CommanderItemFactory(
'undo',
'Control+z',
(store) => {
store.undo();
},
'撤销'
);
export default undo;

View File

@@ -0,0 +1,21 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:29:38
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-09 13:51:32
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\registFormComponents.ts
*
*/
import { ComponentClass } from 'react';
import { FunctionComponent } from 'react';
const modulesFiles = (require as any).context('./formComponents', true, /\.(js|tsx)$/);
export const Formmodules: Record<string, FunctionComponent<any> | ComponentClass<any, any>> =
modulesFiles.keys().reduce((modules: any, modulePath: any) => {
const tmp = modulePath.split('.');
const name = tmp[tmp.length - 2].slice(1);
const value = modulesFiles(modulePath);
modules[name] = value.default;
return modules;
}, []);

View File

@@ -0,0 +1,515 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:46:01
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 18:33:35
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\formComponents\actionButton.tsx
*/
import { Button, Col, Input, message, Modal, Row, Select } from 'antd';
import { memo, useMemo, useState } from 'react';
import React from 'react';
import { UserConfig, createUid, deepCopy } from 'dooringx-lib';
import { unstable_batchedUpdates } from 'react-dom';
import { FormMap } from '../formTypes';
import { CreateOptionsRes } from 'dooringx-lib/dist/core/components/formTypes';
import { IBlockType, IStoreData } from 'dooringx-lib/dist/core/store/storetype';
import { FunctionConfigType } from 'dooringx-lib/dist/core/functionCenter/config';
import { EventCenterUserSelect } from 'dooringx-lib/dist/core/eventCenter';
const { Option } = Select;
interface ActionButtonProps {
data: CreateOptionsRes<FormMap, 'actionButton'>;
current: IBlockType;
config: UserConfig;
}
function ActionButton(props: ActionButtonProps) {
const [visible, setVisible] = useState(false);
const [cur, setCur] = useState('');
const eventMap = props.config.getEventCenter().getEventMap();
const currentOption = useMemo(() => {
return Object.keys(eventMap).filter((v) => v.indexOf(props.current.id) >= 0);
}, [eventMap, props.current.id]);
const [search, setSearch] = useState<EventCenterUserSelect[]>([]);
const functionCenter = props.config.getEventCenter().getFunctionCenter();
const functionConfig = functionCenter.getConfigMap();
const functionMap = functionCenter.getFunctionMap();
const isEdit = props.config.getStoreChanger().isEdit();
const dataMap = props.config.getDataCenter().getDataMap();
let modalMap: Record<string, IStoreData>;
if (isEdit) {
modalMap = props.config.getStoreChanger().getOrigin()?.now.modalMap || {};
} else {
modalMap = props.config.getStore().getData().modalMap;
}
const handleInputDataSource = (
w: {
uid: string;
value: string;
detail: Record<string, any>;
},
c: any,
name = 'dataSource'
) => {
return (
<div>
<div
style={{
textAlign: 'right',
margin: '10px 0',
}}
>
<Button
type="primary"
onClick={() => {
setSearch((pre) => {
pre.forEach((v) => {
if (v.uid === w.uid) {
let sign = true;
if (!v.detail[name][c.name]) {
v.detail[name][c.name] = [];
}
if (!c.options.multi) {
if (v.detail[name][c.name].length >= 1) {
sign = false;
message.error('该函数最多只能添加1个');
}
}
if (sign) {
v.detail[name][c.name].push('');
}
}
});
return [...pre];
});
}}
>
</Button>
</div>
<div>
{w.detail[name] &&
w.detail[name][c.name] &&
w.detail[name][c.name].map((vvv: string, x: number) => {
return (
<Row key={x}>
<Col span={19}>
<Select
style={{ width: '100%' }}
value={vvv}
onChange={(e) => {
const value = e;
setSearch((pre) => {
pre.forEach((v) => {
v.uid === w.uid ? (v.detail[name][c.name][x] = value || '') : '';
});
return [...pre];
});
}}
>
{Object.keys(dataMap).map((n) => {
return (
<Option key={n} value={n}>
{n}
</Option>
);
})}
</Select>
</Col>
<Col span={5} style={{ textAlign: 'right' }}>
<Button
danger
onClick={() => {
setSearch((pre) => {
pre.forEach((v) => {
v.uid === w.uid ? v.detail[name][c.name].splice(x, 1) : '';
});
return [...pre];
});
}}
>
</Button>
</Col>
</Row>
);
})}
</div>
</div>
);
};
const handleInput = (
w: {
uid: string;
value: string;
detail: Record<string, any>;
},
c: any,
name = 'ctx'
) => {
return (
<div>
<div
style={{
textAlign: 'right',
margin: '10px 0',
}}
>
<Button
type="primary"
onClick={() => {
setSearch((pre) => {
pre.forEach((v) => {
if (v.uid === w.uid) {
if (!v.detail[name][c.name]) {
v.detail[name][c.name] = [];
}
let sign = true;
if (!c.options.multi) {
if (v.detail[name][c.name].length >= 1) {
sign = false;
message.error('该函数最多只能添加1个');
}
}
if (sign) {
v.detail[name][c.name].push('');
}
}
});
return [...pre];
});
}}
>
</Button>
</div>
<div>
{w.detail[name] &&
w.detail[name][c.name] &&
w.detail[name][c.name].map((vvv: string, x: number) => {
return (
<Row key={x}>
<Col span={19}>
<Input
value={vvv}
onChange={(e) => {
const value = e.target.value;
setSearch((pre) => {
pre.forEach((v) => {
v.uid === w.uid ? (v.detail[name][c.name][x] = value || '') : '';
});
return [...pre];
});
}}
></Input>
</Col>
<Col span={5} style={{ textAlign: 'right' }}>
<Button
danger
onClick={() => {
setSearch((pre) => {
pre.forEach((v) => {
v.uid === w.uid ? v.detail[name][c.name].splice(x, 1) : '';
});
return [...pre];
});
}}
>
</Button>
</Col>
</Row>
);
})}
</div>
</div>
);
};
return (
<div style={{ padding: '10px 20px' }}>
<Row
style={{
padding: 20,
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Col span={8}>ID</Col>
<Col span={16}>{props.current.id}</Col>
</Row>
{currentOption.map((j, i) => {
return (
<Row
key={i}
style={{
padding: 20,
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div>{eventMap[j].displayName}</div>
<Button
onClick={() => {
unstable_batchedUpdates(() => {
setVisible(true);
setCur((pre) => {
if (pre !== j) {
//查找该cur的选项
const store = props.config.getStore().getData();
let init: EventCenterUserSelect[] = [];
store.block.forEach((v) => {
if (v.id === props.current.id) {
init = v.eventMap[j]?.userSelect || [];
}
});
setSearch(init);
}
return j;
});
});
}}
>
</Button>
</Row>
);
})}
<Modal
width={800}
title={'事件编辑' + `-${(eventMap[cur] && eventMap[cur].displayName) || ''}`}
forceRender
onOk={() => {
// 更新store中的eventMap
const store = props.config.getStore();
const cloneData: IStoreData = deepCopy(store.getData());
const arr = search.map((v) => {
// name: string; // 函数名
// args: Record<string, any>; // 输入参数都会变成对象传来,
// data: Record<string, FunctionDataType>; // 用户选的种类 键是每个配置项名
const name = v.value; //函数名
const options: FunctionConfigType = functionConfig[name];
const dataMap = v.detail['data'];
const combine = options.map((jkk) => {
const select: string = dataMap[jkk.name]; // datasource / input / modal
let val = {};
if (select) {
const value = v.detail[select]; //{name:array<>}
const receive = jkk.options.receive;
val = { [receive]: value[jkk.name] }; //这里不能换算否则修改data后值不会更新
}
const choose = { [jkk.name]: select };
return {
...v,
choose,
val,
};
});
const combineVal = combine.reduce((prev, next) => {
return Object.assign(prev, next.val);
}, {});
const combineChoose = combine.reduce((prev, next) => {
return Object.assign(prev, next.choose);
}, {});
return {
name: name,
data: combineChoose,
args: combineVal,
};
});
let displayName = '';
cloneData.block.forEach((v) => {
if (v.id === props.current.id) {
v.eventMap[cur].userSelect = search;
v.eventMap[cur].arr = arr;
displayName = v.eventMap[cur].displayName;
}
});
const eventCenter = props.config.getEventCenter();
eventCenter.manualUpdateMap(cur, displayName, arr);
store.setData(cloneData);
setVisible(false);
}}
onCancel={() => {
setVisible(false);
}}
visible={visible}
>
<div>
<Row align="middle">
<Col span={6}>ID</Col>
<Col span={18}>{cur}</Col>
</Row>
<Row justify="space-between" style={{ justifyContent: 'flex-end', margin: '20px 0' }}>
<Button
type="primary"
onClick={() => {
setSearch((pre) => {
pre.push({
uid: createUid(),
value: '',
detail: {
input: {},
ctx: {},
dataSource: {},
data: {},
modal: {},
},
});
return [...pre];
});
}}
>
</Button>
</Row>
<div>
{search.map((w, i) => {
const current = search.find((v) => v.uid === w.uid);
const options: FunctionConfigType | undefined = functionConfig[current?.value || ''];
return (
<div key={w.uid}>
<Row align="middle">
<Col span={6}></Col>
<Col span={14}>
<Select
value={current?.value || ''}
style={{ width: '100%' }}
optionFilterProp="children"
filterOption={(input, option) =>
option!.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
onChange={(e) => {
setSearch((pre) => {
pre.forEach((v) => {
// 切换选择要把下一级制空
if (v.uid === w.uid) {
v.value = e as string;
v.detail['data'] = {};
}
});
return [...pre];
});
}}
>
{Object.keys(functionMap).map((v) => {
return (
<Option key={v} value={v}>
{v}
</Option>
);
})}
</Select>
</Col>
<Col span={4} style={{ textAlign: 'right' }}>
<Button
danger
onClick={() => {
setSearch((pre) => {
pre.splice(i, 1);
return [...pre];
});
}}
>
</Button>
</Col>
</Row>
<div
//[{data: ""
/// name: "改变文本数据源"
//options: {receive: "_changeval"}}]
>
{options &&
options.map((c) => {
return (
<Row key={c.name} style={{ margin: '10px 0' }}>
<Col span={6}>{c.name}:</Col>
<Col span={18}>
{
<Select
value={current?.detail?.data?.[c.name] || ''}
style={{ width: '100%' }}
onChange={(e) => {
setSearch((pre) => {
pre.forEach((v) => {
v.uid === w.uid
? (v.detail['data'][c.name] = (e as string) || '')
: '';
});
return [...pre];
});
}}
>
{c.data.includes('dataSource') && (
<Option value="dataSource"></Option>
)}
{c.data.includes('ctx') && <Option value="ctx"></Option>}
{c.data.includes('input') && (
<Option value="input"></Option>
)}
{c.data.includes('modal') && (
<Option value="modal"></Option>
)}
</Select>
}
{w.detail['data'] && w.detail['data'][c.name] === 'dataSource' && (
<div>{handleInputDataSource(w, c)}</div>
)}
{w.detail['data'] && w.detail['data'][c.name] === 'ctx' && (
<div>{handleInput(w, c, 'ctx')}</div>
)}
{w.detail['data'] && w.detail['data'][c.name] === 'input' && (
<div>{handleInput(w, c, 'input')}</div>
)}
{w.detail['data'] && w.detail['data'][c.name] === 'modal' && (
<div>
<Select
value={w.detail['modal'][c.name] || ''}
onChange={(e) => {
setSearch((pre) => {
pre.forEach((v) => {
v.uid === w.uid
? (v.detail['modal'][c.name] = (e as string) || '')
: '';
});
return [...pre];
});
}}
style={{ width: '100%' }}
>
{Object.keys(modalMap).map((v) => {
return (
<Option key={v} value={v}>
{v}
</Option>
);
})}
</Select>
</div>
)}
</Col>
</Row>
);
})}
</div>
</div>
);
})}
</div>
</div>
</Modal>
</div>
);
}
export default memo(ActionButton);

View File

@@ -0,0 +1,309 @@
import React, { useMemo, useState } from 'react';
import { UserConfig, deepCopy } from 'dooringx-lib';
import { Col, Row, Select, InputNumber } from 'antd';
import { FormMap, FormBaseType } from '../formTypes';
import { CreateOptionsRes } from 'dooringx-lib/dist/core/components/formTypes';
import { IBlockType } from 'dooringx-lib/dist/core/store/storetype';
export interface FormAnimateControlType extends FormBaseType {}
interface AnimateControlProps {
data: CreateOptionsRes<FormMap, 'animateControl'>;
current: IBlockType;
config: UserConfig;
}
//类型待修改
const animateCategory: Record<string, string> = {
'': '无',
animate__bounce: 'bounce',
animate__flash: 'flash',
animate__pulse: 'pulse',
animate__rubberBand: 'rubberBand',
animate__shakeX: 'shakeX',
animate__shakeY: 'shakeY',
animate__headShake: 'headShake',
animate__swing: 'swing',
animate__tada: 'tada',
animate__wobble: 'wobble',
animate__jello: 'jello',
animate__heartBeat: 'heartBeat',
animate__backInDown: 'backInDown',
animate__backInLeft: 'backInLeft',
animate__backInRight: 'backInRight',
animate__backInUp: 'backInUp',
animate__backOutDown: 'backOutDown',
animate__backOutLeft: 'backOutLeft',
animate__backOutRight: 'backOutRight',
animate__backOutUp: 'backOutUp',
animate__bounceIn: 'bounceIn',
animate__bounceInDown: 'bounceInDown',
animate__bounceInLeft: 'bounceInLeft',
animate__bounceInRight: 'bounceInRight',
animate__bounceInUp: 'bounceInUp',
animate__bounceOut: 'bounceOut',
animate__bounceOutDown: 'bounceOutDown',
animate__bounceOutLeft: 'bounceOutLeft',
animate__bounceOutRight: 'bounceOutRight',
animate__bounceOutUp: 'bounceOutUp',
animate__fadeIn: 'fadeIn',
animate__fadeInDown: 'fadeInDown',
animate__fadeInDownBig: 'fadeInDownBig',
animate__fadeInLeft: 'fadeInLeft',
animate__fadeInLeftBig: 'fadeInLeftBig',
animate__fadeInRight: 'fadeInRight',
animate__fadeInRightBig: 'fadeInRightBig',
animate__fadeInUp: 'fadeInUp',
animate__fadeInUpBig: 'fadeInUpBig',
animate__fadeInTopLeft: 'fadeInTopLeft',
animate__fadeInTopRight: 'fadeInTopRight',
animate__fadeInBottomLeft: 'fadeInBottomLeft',
animate__fadeInBottomRight: 'fadeInBottomRight',
animate__fadeOut: 'fadeOut',
animate__fadeOutDown: 'fadeOutDown',
animate__fadeOutDownBig: 'fadeOutDownBig',
animate__fadeOutLeft: 'fadeOutLeft',
animate__fadeOutLeftBig: 'fadeOutLeftBig',
animate__fadeOutRight: 'fadeOutRight',
animate__fadeOutRightBig: 'fadeOutRightBig',
animate__fadeOutUp: 'fadeOutUp',
animate__fadeOutUpBig: 'fadeOutUpBig',
animate__fadeOutTopLeft: 'fadeOutTopLeft',
animate__fadeOutTopRight: 'fadeOutTopRight',
animate__fadeOutBottomRight: 'fadeOutBottomRight',
animate__fadeOutBottomLeft: 'fadeOutBottomLeft',
animate__flip: 'flip',
animate__flipInX: 'flipInX',
animate__flipInY: 'flipInY',
animate__flipOutX: 'flipOutX',
animate__flipOutY: 'flipOutY',
animate__lightSpeedInRight: 'lightSpeedInRight',
animate__lightSpeedInLeft: 'lightSpeedInLeft',
animate__lightSpeedOutRight: 'lightSpeedOutRight',
animate__lightSpeedOutLeft: 'lightSpeedOutLeft',
animate__rotateIn: 'rotateIn',
animate__rotateInDownLeft: 'rotateInDownLeft',
animate__rotateInDownRight: 'rotateInDownRight',
animate__rotateInUpLeft: 'rotateInUpLeft',
animate__rotateInUpRight: 'rotateInUpRight',
animate__rotateOut: 'rotateOut',
animate__rotateOutDownLeft: 'rotateOutDownLeft',
animate__rotateOutDownRight: 'rotateOutDownRight',
animate__rotateOutUpLeft: 'rotateOutUpLeft',
animate__rotateOutUpRight: 'rotateOutUpRight',
animate__hinge: 'hinge',
animate__jackInTheBox: 'jackInTheBox',
animate__rollIn: 'rollIn',
animate__rollOut: 'rollOut',
animate__zoomIn: 'zoomIn',
animate__zoomInDown: 'zoomInDown',
animate__zoomInLeft: 'zoomInLeft',
animate__zoomInRight: 'zoomInRight',
animate__zoomInUp: 'zoomInUp',
animate__zoomOut: 'zoomOut',
animate__zoomOutDown: 'zoomOutDown',
animate__zoomOutLeft: 'zoomOutLeft',
animate__zoomOutRight: 'zoomOutRight',
animate__zoomOutUp: 'zoomOutUp',
animate__slideInDown: 'slideInDown',
animate__slideInLeft: 'slideInLeft',
animate__slideInRight: 'slideInRight',
animate__slideInUp: 'slideInUp',
animate__slideOutDown: 'slideOutDown',
animate__slideOutLeft: 'slideOutLeft',
animate__slideOutRight: 'slideOutRight',
animate__slideOutUp: 'slideOutUp',
};
const animateRepeat: Record<string, string> = {
'': '无',
'1': '1次',
'2': '2次',
'3': '3次',
'4': '4次',
infinite: '无限',
};
const animateSpeed: Record<string, string> = {
'': '普通',
animate__slow: '特慢',
animate__slower: '慢速',
animate__fast: '快速',
animate__faster: '特快',
};
let lastAnimate = '';
/**
*
* 这个控制组件配置项写死,只可能出现或者不出现
* @return {*}
*/
function AnimateControl(props: AnimateControlProps) {
const [count, setCount] = useState<number | null>(null);
const [sign, setSign] = useState(false);
const v1 = useMemo(() => {
if (sign) {
return lastAnimate;
} else {
const val = props.current.animate.animate
? animateCategory[props.current.animate.animate]
: '';
lastAnimate = val;
return val;
}
}, [props.current.animate.animate, sign]);
const v2 = useMemo(() => {
if (typeof props.current.animate.animationIterationCount === 'number') {
setCount(props.current.animate.animationIterationCount);
return '';
} else {
setCount(null);
return props.current.animate.animationIterationCount
? animateRepeat[props.current.animate.animationIterationCount]
: '';
}
}, [props.current.animate.animationIterationCount]);
const v3 = useMemo(() => {
return animateSpeed[props.current.animate.speed ?? ''];
}, [props.current.animate.speed]);
const changeAnimation = (
e: any,
props: AnimateControlProps,
type: 'animate' | 'animationIterationCount' | 'speed'
) => {
if (type === 'animationIterationCount') {
setCount(null);
}
const clonedata = deepCopy(props.config.getStore().getData());
const newblock = clonedata.block.map((v: IBlockType) => {
if (v.id === props.current.id) {
if (type === 'animationIterationCount') {
v.animate[type] = Number(e);
}
v.animate[type] = e;
}
return v;
});
const [item] = clonedata.block.filter((item: IBlockType) => item.id === props.current.id);
if (item?.animate?.animate) {
const cloneNewBlock = deepCopy(newblock);
const temporaryBlock = cloneNewBlock.map((item: IBlockType) => {
if (item.id === props.current.id) {
delete item.animate.animate;
}
return item;
});
setSign(true);
// 若有动画属性则删除动画属性再将动画属性添加
props.config.getStore().setData({ ...clonedata, block: [...temporaryBlock] });
}
setTimeout(() => {
props.config.getStore().setData({ ...clonedata, block: [...newblock] });
setSign(false);
});
};
return (
<>
<Row style={{ padding: '20px' }}>
<Col span={6} style={{ lineHeight: '30px' }}>
</Col>
<Col span={18}>
<Select
value={v1}
onChange={(e) => changeAnimation(e, props, 'animate')}
style={{ width: '100%' }}
>
{Object.keys(animateCategory).map((v) => {
return (
<Select.Option value={v} key={v}>
{animateCategory[v]}
</Select.Option>
);
})}
</Select>
</Col>
</Row>
<Row style={{ padding: '20px' }}>
<Col span={6} style={{ lineHeight: '30px' }}>
</Col>
<Col span={18} style={{ display: 'flex', justifyContent: 'space-between' }}>
<InputNumber
min={1}
value={count as number}
onChange={(value) => {
setCount(value);
const clonedata = deepCopy(props.config.getStore().getData());
const newblock = clonedata.block.map((v: IBlockType) => {
if (v.id === props.current.id) {
v.animate.animationIterationCount = value;
}
return v;
});
const [item] = clonedata.block.filter(
(item: IBlockType) => item.id === props.current.id
);
if (item?.animate?.animate) {
const cloneNewBlock = deepCopy(newblock);
const temporaryBlock = cloneNewBlock.map((item: IBlockType) => {
if (item.id === props.current.id) {
delete item.animate.animate;
}
return item;
});
setSign(true);
props.config.getStore().setData({ ...clonedata, block: [...temporaryBlock] });
}
setTimeout(() => {
props.config.getStore().setData({ ...clonedata, block: [...newblock] });
setSign(false);
});
}}
></InputNumber>
<Select
value={v2}
onChange={(e) => changeAnimation(e, props, 'animationIterationCount')}
style={{ width: '60%' }}
>
{Object.keys(animateRepeat).map((v) => {
return (
<Select.Option value={v} key={v}>
{animateRepeat[v]}
</Select.Option>
);
})}
</Select>
</Col>
</Row>
<Row style={{ padding: '20px' }}>
<Col span={6} style={{ lineHeight: '30px' }}>
</Col>
<Col span={18}>
<Select
value={v3}
onChange={(e: any) => changeAnimation(e, props, 'speed')}
style={{ width: '100%' }}
>
{Object.keys(animateSpeed).map((v) => {
return (
<Select.Option value={v} key={v}>
{animateSpeed[v]}
</Select.Option>
);
})}
</Select>
</Col>
</Row>
</>
);
}
export default AnimateControl;

View File

@@ -0,0 +1,51 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:32:55
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 14:33:06
* @FilePath: \visual-editor\src\plugin\formComponents\input.tsx
*/
import { deepCopy } from 'dooringx-lib';
import { store } from 'dooringx-lib';
import { Col, Input, Row } from 'antd';
import { memo, useMemo } from 'react';
import React from 'react';
import { FormMap } from '../formTypes';
import { CreateOptionsRes } from 'dooringx-lib/dist/core/components/formTypes';
import { IBlockType } from 'dooringx-lib/dist/core/store/storetype';
interface MInputProps {
data: CreateOptionsRes<FormMap, 'input'>;
current: IBlockType;
}
function MInput(props: MInputProps) {
const option = useMemo(() => {
return props.data?.option || {};
}, [props.data]);
return (
<Row style={{ padding: '10px 20px' }}>
<Col span={6} style={{ lineHeight: '30px' }}>
{(option as any)?.label || '文字'}
</Col>
<Col span={18}>
<Input
value={props.current.props[(option as any).receive] || ''}
onChange={(e) => {
const receive = (option as any).receive;
const clonedata = deepCopy(store.getData());
const newblock = clonedata.block.map((v: IBlockType) => {
if (v.id === props.current.id) {
v.props[receive] = e.target.value;
}
return v;
});
store.setData({ ...clonedata, block: [...newblock] });
}}
></Input>
</Col>
</Row>
);
}
export default memo(MInput);

View File

@@ -0,0 +1,21 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:31:20
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 17:21:04
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\formTypes.ts
*/
export interface FormBaseType {
receive?: string;
}
export interface FormInputType extends FormBaseType {
label: string;
text: string;
}
export interface FormActionButtonType {}
export interface FormAnimateControlType {}
export interface FormMap {
input: FormInputType;
actionButton: FormActionButtonType;
animateControl: FormAnimateControlType;
}

View File

@@ -0,0 +1,10 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:22:51
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-09 13:52:51
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\functionMap\index.ts
*/
import { FunctionCenterType } from 'dooringx-lib/dist/core/functionCenter';
export const functionMap: FunctionCenterType = {};

View File

@@ -0,0 +1,83 @@
/*
* @Author: yehuozhili
* @Date: 2021-02-27 21:33:36
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 19:32:16
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\index.tsx
*/
import { InitConfig } from 'dooringx-lib';
import { LeftRegistComponentMapItem } from 'dooringx-lib/dist/core/crossDrag';
import { ContainerOutlined, HighlightOutlined } from '@ant-design/icons';
import commandModules from './commanderModules';
import { functionMap } from './functionMap';
import { Formmodules } from './formComponentModules';
const LeftRegistMap: LeftRegistComponentMapItem[] = [
// build 时如果用代码分割会生成多个文件,这样就不能生成多类型文件。
// 建议基础包全部不分割。后面插件包可以用webpack的特性所以插件包用新脚手架制作
// 基础包不独立出去的原因是部分左侧分类起始值最好规定住
// {
// type: 'xxa',
// component: 'asyncCo',
// img: '',
// urlFn: () => import('./registComponents/asyncCo'),
// displayName:'xxx'
// },
{
type: 'basic',
component: 'button',
img: 'icon-anniu',
displayName: '按钮',
urlFn: () => import('./registComponents/button'),
},
];
export const defaultConfig: Partial<InitConfig> = {
leftAllRegistMap: LeftRegistMap,
leftRenderListCategory: [
{
type: 'basic',
icon: <HighlightOutlined />,
displayName: '基础组件',
},
{
type: 'xxc',
icon: <ContainerOutlined />,
custom: true,
customRender: <div></div>,
},
],
initComponentCache: {},
rightRenderListCategory: [
{
type: 'style',
icon: (
<div className="right-tab-item" style={{ width: 50, textAlign: 'center' }}>
</div>
),
},
{
type: 'animate',
icon: (
<div className="right-tab-item" style={{ width: 50, textAlign: 'center' }}>
</div>
),
},
{
type: 'actions',
icon: (
<div className="right-tab-item" style={{ width: 50, textAlign: 'center' }}>
</div>
),
},
],
initFunctionMap: functionMap,
initCommandModule: commandModules,
initFormComponents: Formmodules,
};
export default defaultConfig;

View File

@@ -0,0 +1,138 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-07 14:35:38
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 19:04:05
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\registComponents\button.tsx
*/
import { Button } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
changeUserValue,
ComponentItemFactory,
createPannelOptions,
useDynamicAddEventCenter,
} from 'dooringx-lib';
import { FormMap } from '../formTypes';
import { ComponentRenderConfigProps } from 'dooringx-lib/dist/core/components/componentItem';
function ButtonTemp(pr: ComponentRenderConfigProps) {
const props = pr.data.props;
const eventCenter = useMemo(() => {
return pr.config.getEventCenter();
}, [pr.config]);
useDynamicAddEventCenter(pr, `${pr.data.id}-init`, '初始渲染时机'); //注册名必须带id 约定!
useDynamicAddEventCenter(pr, `${pr.data.id}-click`, '点击执行时机');
useEffect(() => {
// 模拟抛出事件
if (pr.context === 'preview') {
eventCenter.runEventQueue(`${pr.data.id}-init`, pr.config);
}
}, [eventCenter, pr.config, pr.context, pr.data.id]);
const [text, setText] = useState('');
useEffect(() => {
//模拟改变文本
const functionCenter = eventCenter.getFunctionCenter();
const unregist = functionCenter.register(
`${pr.data.id}+改变文本函数`,
async (ctx, next, config, args: any, _eventList, iname) => {
const userSelect = iname.data;
const ctxVal = changeUserValue(
userSelect['改变文本数据源'],
args,
'_changeval',
config,
ctx
);
const text = ctxVal[0];
setText(text);
next();
},
[
{
name: '改变文本数据源',
data: ['ctx', 'input', 'dataSource'],
options: {
receive: '_changeval',
multi: false,
},
},
]
);
return () => {
unregist();
};
}, []);
return (
<Button
style={{
width: pr.data.width ? pr.data.width : props.sizeData[0],
height: pr.data.height ? pr.data.height : props.sizeData[1],
borderRadius: props.borderRadius + 'px',
border: `${props.borderData.borderWidth}px ${props.borderData.borderStyle} ${props.borderData.borderColor}`,
backgroundColor: props.backgroundColor,
color: props.fontData.color,
fontSize: props.fontData.fontSize,
fontWeight: props.fontData.fontWeight,
fontStyle: props.fontData.fontStyle,
textDecoration: props.fontData.textDecoration,
lineHeight: props.lineHeight,
}}
onClick={() => {
eventCenter.runEventQueue(`${pr.data.id}-click`, pr.config);
}}
// type={props.type}
// size={props.size}
>
{text ? text : props.text}
</Button>
);
}
const MButton = new ComponentItemFactory(
'button',
'按钮',
{
style: [
createPannelOptions<FormMap, 'input'>('input', {
receive: 'text', //用于发送回的props必传 ,跨组件传递需要指定额外字段
label: '文字',
text: 'yehuozhili',
}),
],
animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})],
actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})],
},
{
props: {
text: 'yehuozhili',
sizeData: [100, 30],
backgroundColor: 'rgba(0,132,255,1)',
lineHeight: 1,
borderRadius: 0,
borderData: {
borderWidth: 0,
borderColor: 'rgba(0,0,0,1)',
borderStyle: 'solid',
},
fontData: {
fontSize: 14,
textDecoration: 'none',
fontStyle: 'normal',
color: 'rgba(255,255,255,1)',
fontWeight: 'normal',
},
},
},
(data, context, store, config) => {
return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>;
},
true
);
export default MButton;

View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"jsx": "react-jsx",
"esModuleInterop": true,
"sourceMap": true,
"baseUrl": "./",
"strict": true,
"paths": {
"@/*": ["src/*"],
"@@/*": ["src/.umi/*"]
},
"allowSyntheticDefaultImports": true
},
"include": ["mock/**/*", "src/**/*", "config/**/*", ".umirc.ts", "typings.d.ts"],
"exclude": [
"node_modules",
"lib",
"es",
"dist",
"typings",
"**/__test__",
"test",
"docs",
"tests"
]
}

View File

@@ -0,0 +1,8 @@
declare module '*.css';
declare module '*.less';
declare module '*.png';
declare module '*.svg' {
export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement;
const url: string;
export default url;
}

View File

@@ -2,15 +2,16 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-01-31 20:44:16 * @Date: 2021-01-31 20:44:16
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-08 20:44:20 * @LastEditTime: 2021-07-10 18:07:00
* @FilePath: \DooringV2\packages\dooringx-lib\README.md * @FilePath: \dooringx\packages\dooringx-lib\README.md
--> -->
## DooringX 核心包 ## Dooringx-lib
## changelog ## changelog
- 0.1.7 修改预览特殊条件显示,删除 console - 0.1.9 增加全局body设置
- 0.1.8 增加弹窗设置移除modalContainer
- 0.1.7 修改预览特殊条件显示删除console
- 0.1.6 调整初始缩放,画布初始比例,增加回正画布功能。 - 0.1.6 调整初始缩放,画布初始比例,增加回正画布功能。
- 0.1.5 删除未作按钮,增加 fixed 配置 - 0.1.5 删除未作按钮增加fixed配置
- 0.1.4 基础功能 - 0.1.4 基础功能

View File

@@ -1,9 +1,7 @@
{ {
"version": "0.1.7", "version": "0.1.9",
"license": "MIT", "license": "MIT",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/dooringx-lib.esm.js",
"browser": "dist/dooringx-lib.esm.js",
"typings": "dist/index.d.ts", "typings": "dist/index.d.ts",
"files": [ "files": [
"dist" "dist"
@@ -20,7 +18,8 @@
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16.8", "react": ">=16.8",
"antd": ">=4" "antd": ">=4",
"animate.css": ">=4"
}, },
"name": "dooringx-lib", "name": "dooringx-lib",
"author": "yehuozhili", "author": "yehuozhili",
@@ -46,7 +45,6 @@
"deepcopy": "^2.1.0", "deepcopy": "^2.1.0",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-sortable-hoc": "^2.0.0", "react-sortable-hoc": "^2.0.0",
"uuid": "^8.3.2", "uuid": "^8.3.2"
"animate.css": "^4.1.1"
} }
} }

View File

@@ -39,7 +39,6 @@ function Container(props: PropsWithChildren<ContainerProps>) {
return props.state.globalState.containerColor; return props.state.globalState.containerColor;
} }
}; };
return ( return (
<> <>
{props.context === 'edit' && ( {props.context === 'edit' && (

View File

@@ -2,8 +2,8 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-02-04 10:32:45 * @Date: 2021-02-04 10:32:45
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-06 23:55:37 * @LastEditTime: 2021-07-10 15:47:34
* @FilePath: \dooringv2\packages\dooring-v2-lib\src\components\leftConfig.tsx * @FilePath: \DooringV2\packages\dooringx-lib\src\components\leftConfig.tsx
*/ */
import React, { ReactNode, useEffect, useMemo, useState } from 'react'; import React, { ReactNode, useEffect, useMemo, useState } from 'react';
import { Input, Menu } from 'antd'; import { Input, Menu } from 'antd';
@@ -42,7 +42,7 @@ function LeftConfig(props: LeftConfigProps) {
cache = config.leftAllRegistMap.filter((k) => k.type === type); cache = config.leftAllRegistMap.filter((k) => k.type === type);
cache.forEach((v) => props.config.asyncRegistComponent(v.component)); cache.forEach((v) => props.config.asyncRegistComponent(v.component));
setLeftRender( setLeftRender(
<div className={styles.leftco}> <div className={`${styles.leftco} yh-leftcomp`}>
<div <div
style={{ style={{
display: 'flex', display: 'flex',
@@ -53,7 +53,7 @@ function LeftConfig(props: LeftConfigProps) {
> >
<div <div
style={{ style={{
width: 100, width: 120,
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',

View File

@@ -29,6 +29,8 @@ export function ModalRender(props: ModalRenderProps) {
}, [props.data.modalMap, props.name]); }, [props.data.modalMap, props.name]);
const { parentDom, rootDom } = props; const { parentDom, rootDom } = props;
const modalConfig = props.data.modalConfig[props.name];
//这里还要添加个关闭函数, //这里还要添加个关闭函数,
const unmount = useMemo(() => { const unmount = useMemo(() => {
return () => { return () => {
@@ -58,7 +60,9 @@ export function ModalRender(props: ModalRenderProps) {
})} })}
<div <div
onClick={() => { onClick={() => {
unmount(); if (!modalConfig) {
unmount();
}
}} }}
style={{ style={{
backgroundColor: '#716f6f9e', backgroundColor: '#716f6f9e',

View File

@@ -2,7 +2,7 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 05:40:37 * @Date: 2021-03-14 05:40:37
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-08 20:44:45 * @LastEditTime: 2021-07-10 16:09:19
* @FilePath: \DooringV2\packages\dooringx-lib\src\components\preview.tsx * @FilePath: \DooringV2\packages\dooringx-lib\src\components\preview.tsx
*/ */
import Container from './container'; import Container from './container';
@@ -24,6 +24,12 @@ function Preview(props: { config: UserConfig; loadText?: ReactNode }): ReactElem
.getEventCenter() .getEventCenter()
.syncEventMap(props.config.getStore().getData(), props.config.getStoreChanger()); .syncEventMap(props.config.getStore().getData(), props.config.getStoreChanger());
setTimeout(() => { setTimeout(() => {
// 设置全局
const bodyColor = props.config.getStore().getData().globalState?.bodyColor;
if (bodyColor) {
document.body.style.backgroundColor = bodyColor;
}
setLoading(false); setLoading(false);
}); });
}, [props.config]); }, [props.config]);

View File

@@ -2,15 +2,15 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 05:42:13 * @Date: 2021-03-14 05:42:13
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-05 23:35:05 * @LastEditTime: 2021-07-10 16:06:33
* @FilePath: \DooringV2\packages\dooring-v2-lib\src\components\rightConfig.tsx * @FilePath: \DooringV2\packages\dooringx-lib\src\components\rightConfig.tsx
*/ */
import { CreateOptionsRes } from '../core/components/formTypes'; import { CreateOptionsRes } from '../core/components/formTypes';
import { IBlockType, IStoreData } from '../core/store/storetype'; import { IBlockType, IStoreData } from '../core/store/storetype';
import { store } from '../runtime/store'; import { store } from '../runtime/store';
import { PropsWithChildren, useEffect, useMemo, useState } from 'react'; import { PropsWithChildren, useEffect, useMemo, useState } from 'react';
import React from 'react'; import React from 'react';
import { Tabs, Input, Row, Col } from 'antd'; import { Tabs, Input, Row, Col, Checkbox } from 'antd';
import UserConfig from '../config'; import UserConfig from '../config';
import { RGBColor, SketchPicker } from 'react-color'; import { RGBColor, SketchPicker } from 'react-color';
import { rgba2Obj } from '../core/utils'; import { rgba2Obj } from '../core/utils';
@@ -89,8 +89,15 @@ function RightConfig(props: PropsWithChildren<RightConfigProps>) {
? rgba2Obj(props.config.getStoreChanger().getOrigin()?.now.globalState.containerColor) ? rgba2Obj(props.config.getStoreChanger().getOrigin()?.now.globalState.containerColor)
: rgba2Obj(props.config.getStore().getData().globalState.containerColor); : rgba2Obj(props.config.getStore().getData().globalState.containerColor);
}, [props.config]); }, [props.config]);
const initColor2 = useMemo(() => {
return props.config.getStoreChanger().isEdit()
? rgba2Obj(props.config.getStoreChanger().getOrigin()?.now.globalState.bodyColor)
: rgba2Obj(props.config.getStore().getData().globalState.bodyColor);
}, [props.config]);
const [color, setColor] = useState<RGBColor>(initColor); const [color, setColor] = useState<RGBColor>(initColor);
const [color2, setColor2] = useState<RGBColor>(initColor2);
const [colorPickerVisible, setColorPickerVisible] = useState(false); const [colorPickerVisible, setColorPickerVisible] = useState(false);
const [colorPickerVisible2, setColorPickerVisible2] = useState(false);
const initTitle = useMemo(() => { const initTitle = useMemo(() => {
const title = props.config.getStoreChanger().isEdit() const title = props.config.getStoreChanger().isEdit()
? props.config.getStoreChanger().getOrigin()?.now.globalState.title ? props.config.getStoreChanger().getOrigin()?.now.globalState.title
@@ -100,6 +107,9 @@ function RightConfig(props: PropsWithChildren<RightConfigProps>) {
const [title, setTitle] = useState(initTitle); const [title, setTitle] = useState(initTitle);
const customGlobal = props.config.getConfig().rightGlobalCustom; const customGlobal = props.config.getConfig().rightGlobalCustom;
const isEdit = props.config.getStoreChanger().isEdit();
const modalName = props.config.getStoreChanger().getState().modalEditName;
const originData = props.config.getStoreChanger().getOrigin()?.now;
return ( return (
<div <div
className="ant-menu" className="ant-menu"
@@ -137,7 +147,7 @@ function RightConfig(props: PropsWithChildren<RightConfigProps>) {
})} })}
</Tabs> </Tabs>
)} )}
{!current && !customGlobal && ( {!current && !isEdit && !customGlobal && (
<div style={{ padding: '20px' }}> <div style={{ padding: '20px' }}>
<Row style={{ padding: '10 0 20px 0', fontWeight: 'bold' }}></Row> <Row style={{ padding: '10 0 20px 0', fontWeight: 'bold' }}></Row>
<Row style={{ padding: '10px 0' }}> <Row style={{ padding: '10px 0' }}>
@@ -230,9 +240,97 @@ function RightConfig(props: PropsWithChildren<RightConfigProps>) {
} }
</Col> </Col>
</Row> </Row>
<Row style={{ padding: '10px 0' }}>
<Col span={6}>body底色</Col>
<Col span={18}>
{
<div style={{ position: 'relative' }}>
<div
onClick={() => {
setColorPickerVisible2((pre) => !pre);
}}
style={{
background: '#fff',
borderRadius: '1px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
cursor: 'pointer',
display: 'inline-block',
}}
>
<div
style={{
width: '20px',
height: '20px',
borderRadius: '2px',
background: `rgba(${color2.r}, ${color2.g}, ${color2.b}, ${color2.a})`,
}}
/>
</div>
{colorPickerVisible2 && (
<>
<div style={{ position: 'absolute', zIndex: 2000 }}>
<SketchPicker
color={color2}
onChange={(c) => {
const newcolor = c.rgb;
setColor2(newcolor);
const isEdit = props.config.getStoreChanger().isEdit();
if (isEdit) {
const originData: IStoreData = deepcopy(
props.config.getStoreChanger().getOrigin()!.now
);
originData.globalState.bodyColor = `rgba(${newcolor.r}, ${newcolor.g}, ${newcolor.b}, ${newcolor.a})`;
props.config.getStoreChanger().updateOrigin(originData);
} else {
const originData = deepcopy(props.config.getStore().getData());
originData.globalState.bodyColor = `rgba(${newcolor.r}, ${newcolor.g}, ${newcolor.b}, ${newcolor.a})`;
props.config.getStore().setData(originData);
}
}}
></SketchPicker>
</div>
<div
style={{
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
zIndex: 1000,
}}
onClick={() => setColorPickerVisible2(false)}
/>
</>
)}
</div>
}
</Col>
</Row>
</div>
)}
{!current && !isEdit && customGlobal && customGlobal}
{!current && isEdit && (
<div style={{ padding: '20px' }} className="yh-tcsz">
<Row style={{ padding: '10 0 20px 0', fontWeight: 'bold' }}></Row>
<Row style={{ padding: '10px 0' }}>
<Col span={8}></Col>
<Col span={16} style={{ textAlign: 'right' }}>
<Checkbox
checked={originData ? originData.modalConfig[modalName] : false}
onChange={(e) => {
const val = e.target.checked;
const cloneData = deepcopy(originData);
if (cloneData) {
cloneData.modalConfig[modalName] = val;
props.config.getStoreChanger().updateOrigin(cloneData);
props.config.getStore().forceUpdate();
}
}}
></Checkbox>
</Col>
</Row>
</div> </div>
)} )}
{!current && customGlobal && customGlobal}
</div> </div>
); );
} }

View File

@@ -2,8 +2,8 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-02-25 21:16:58 * @Date: 2021-02-25 21:16:58
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-08 20:42:22 * @LastEditTime: 2021-07-10 18:29:07
* @FilePath: \DooringV2\packages\dooringx-lib\src\config\index.tsx * @FilePath: \dooringx\packages\dooringx-lib\src\config\index.tsx
*/ */
import { IBlockType, IStoreData } from '../core/store/storetype'; import { IBlockType, IStoreData } from '../core/store/storetype';
import { store } from '../runtime/store'; import { store } from '../runtime/store';
@@ -23,7 +23,6 @@ import { createModal, unmountMap } from '../components/modalRender';
import { scaleState } from '../core/scale/state'; import { scaleState } from '../core/scale/state';
import { CommanderItemFactory } from '../core/command/abstract'; import { CommanderItemFactory } from '../core/command/abstract';
import MmodalMask from '../core/components/defaultFormComponents/modalMask'; import MmodalMask from '../core/components/defaultFormComponents/modalMask';
import MmodalContainer from '../core/components/defaultFormComponents/modalContainer';
// 组件部分 // 组件部分
@@ -156,7 +155,9 @@ export const defaultStore: IStoreData = {
globalState: { globalState: {
containerColor: 'rgba(255,255,255,1)', containerColor: 'rgba(255,255,255,1)',
title: 'dooring', title: 'dooring',
bodyColor: 'rgba(255,255,255,1)',
}, },
modalConfig: {},
}; };
export const defaultConfig: InitConfig = { export const defaultConfig: InitConfig = {
@@ -166,8 +167,7 @@ export const defaultConfig: InitConfig = {
rightGlobalCustom: null, rightGlobalCustom: null,
rightRenderListCategory: [], rightRenderListCategory: [],
initComponentCache: { initComponentCache: {
modalMask: { component: MmodalMask }, // 这2个组件不配置显示 modalMask: { component: MmodalMask }, // 这个组件不配置显示
modalContainer: { component: MmodalContainer },
}, },
initFunctionMap: { initFunctionMap: {
: { : {
@@ -192,7 +192,9 @@ export const defaultConfig: InitConfig = {
fn: (_ctx, next, _config, args) => { fn: (_ctx, next, _config, args) => {
const modalName = args['_modal']; const modalName = args['_modal'];
const fn = unmountMap.get(modalName); const fn = unmountMap.get(modalName);
fn ? fn() : ''; if (fn) {
fn();
}
next(); next();
}, },
config: [ config: [

View File

@@ -1,34 +0,0 @@
/*
* @Author: yehuozhili
* @Date: 2021-04-05 19:21:36
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-05 23:56:07
* @FilePath: \DooringV2\packages\dooring-v2-lib\src\core\components\defaultFormComponents\modalContainer.tsx
*/
import React from 'react';
import { ComponentItemFactory } from '../abstract';
const MmodalContainer = new ComponentItemFactory(
'modalContainer',
'模态框容器',
{},
{
props: {},
width: 300,
height: 300,
},
(data) => {
return (
<div
style={{
zIndex: data.zIndex,
width: data.width,
height: data.height,
backgroundColor: 'white',
}}
></div>
);
}
);
export default MmodalContainer;

View File

@@ -2,8 +2,8 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 04:29:09 * @Date: 2021-03-14 04:29:09
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-03-14 04:43:53 * @LastEditTime: 2021-07-10 18:34:34
* @FilePath: \dooring-v2\src\core\components\index.ts * @FilePath: \dooringx\packages\dooringx-lib\src\core\components\index.ts
*/ */
import { ComponentItem } from './componentItem'; import { ComponentItem } from './componentItem';

View File

@@ -2,8 +2,8 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 04:29:09 * @Date: 2021-03-14 04:29:09
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-04 15:21:54 * @LastEditTime: 2021-07-10 18:34:40
* @FilePath: \DooringV2\packages\dooring-v2-lib\src\core\crossDrag\index.ts * @FilePath: \dooringx\packages\dooringx-lib\src\core\crossDrag\index.ts
*/ */
import { store } from '../../runtime/store'; import { store } from '../../runtime/store';
import { componentRegister } from '../../runtime'; import { componentRegister } from '../../runtime';

View File

@@ -2,8 +2,8 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-04-06 19:33:17 * @Date: 2021-04-06 19:33:17
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-04 14:41:48 * @LastEditTime: 2021-07-09 16:33:22
* @FilePath: \DooringV2\packages\dooring-v2-lib\src\core\eventCenter\index.ts * @FilePath: \DooringV2\packages\dooringx-lib\src\core\eventCenter\index.ts
*/ */
import UserConfig from '../../config'; import UserConfig from '../../config';
import { FunctionCenter, FunctionCenterType } from '../functionCenter'; import { FunctionCenter, FunctionCenterType } from '../functionCenter';

View File

@@ -2,8 +2,8 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-04-08 19:59:01 * @Date: 2021-04-08 19:59:01
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 01:46:17 * @LastEditTime: 2021-07-09 16:23:02
* @FilePath: \dooringv2\packages\dooringx-lib\src\core\functionCenter\index.ts * @FilePath: \DooringV2\packages\dooringx-lib\src\core\functionCenter\index.ts
*/ */
import UserConfig from '../../config'; import UserConfig from '../../config';
@@ -83,6 +83,17 @@ export class FunctionCenter {
return this.configMap; return this.configMap;
} }
/**
*
* 删除的组件需要删除动态注册的函数
* @param {string} name
* @memberof FunctionCenter
*/
deleteFunc(name: string) {
delete this.funcitonMap[name];
delete this.configMap[name];
}
/** /**
* *
* 注册函数,同名覆盖,返回删除函数 * 注册函数,同名覆盖,返回删除函数

View File

@@ -1,9 +1,9 @@
/* /*
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 04:29:09 * @Date: 2021-03-14 04:29:09
* @LastEditors: Please set LastEditors * @LastEditors: yehuozhili
* @LastEditTime: 2021-06-19 17:07:10 * @LastEditTime: 2021-07-10 18:17:56
* @FilePath: \dooringv2\packages\dooring-v2-lib\src\core\store\index.ts * @FilePath: \dooringx\packages\dooringx-lib\src\core\store\index.ts
*/ */
import { IStoreData } from './storetype'; import { IStoreData } from './storetype';
import { storeChangerState } from '../storeChanger/state'; import { storeChangerState } from '../storeChanger/state';
@@ -17,9 +17,11 @@ export const initialData: IStoreData = {
modalMap: {}, modalMap: {},
dataSource: {}, dataSource: {},
globalState: {}, globalState: {},
modalConfig: {},
}; };
class Store { class Store {
static instance: Store;
constructor( constructor(
public storeDataList: IStoreData[] = [initialData], public storeDataList: IStoreData[] = [initialData],
public listeners: Array<Function> = [], public listeners: Array<Function> = [],

View File

@@ -2,7 +2,7 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 04:29:09 * @Date: 2021-03-14 04:29:09
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 17:00:07 * @LastEditTime: 2021-07-09 17:22:14
* @FilePath: \DooringV2\packages\dooringx-lib\src\core\store\storetype.ts * @FilePath: \DooringV2\packages\dooringx-lib\src\core\store\storetype.ts
*/ */
@@ -17,6 +17,7 @@ export interface IStoreData {
modalMap: Record<string, IStoreData>; modalMap: Record<string, IStoreData>;
dataSource: Record<string, any>; dataSource: Record<string, any>;
globalState: Record<string, any>; globalState: Record<string, any>;
modalConfig: Record<string, any>;
} }
export interface IBlockType { export interface IBlockType {
@@ -38,7 +39,7 @@ export interface IBlockType {
functionList: Array<string>; //抛出的函数名 functionList: Array<string>; //抛出的函数名
animate: { animate: {
animate?: string; //动画名 animate?: string; //动画名
animationIterationCount?: any; animationIterationCount?: number | string;
speed?: //动画速度 speed?: //动画速度
'animate__slow' | 'animate__slower' | 'animate__fast' | 'animate__faster' | ''; 'animate__slow' | 'animate__slower' | 'animate__fast' | 'animate__faster' | '';
delay?: //首次延迟 delay?: //首次延迟

View File

@@ -2,7 +2,7 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-04-05 14:55:31 * @Date: 2021-04-05 14:55:31
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-07 16:59:54 * @LastEditTime: 2021-07-09 18:31:24
* @FilePath: \DooringV2\packages\dooringx-lib\src\core\storeChanger\index.ts * @FilePath: \DooringV2\packages\dooringx-lib\src\core\storeChanger\index.ts
*/ */
@@ -43,26 +43,6 @@ function createDefaultModalBlock(): IStoreData['block'] {
animate: {}, animate: {},
fixed: false, fixed: false,
}, },
{
id: createUid('modal-container'),
name: 'modalContainer',
top: 100,
left: 35,
zIndex: 0,
props: {},
resize: true,
focus: true,
position: 'absolute',
display: 'block',
width: 300,
height: 300,
syncList: [],
canDrag: true,
eventMap: {},
functionList: [],
animate: {},
fixed: false,
},
]; ];
} }
@@ -80,6 +60,7 @@ const defaultModalStore: () => IStoreData = () => {
modalMap: {}, modalMap: {},
dataSource: {}, dataSource: {},
globalState: {}, globalState: {},
modalConfig: {},
}; };
}; };

View File

@@ -1,7 +1,14 @@
/*
* @Author: yehuozhili
* @Date: 2021-07-10 16:52:41
* @LastEditors: yehuozhili
* @LastEditTime: 2021-07-10 18:28:18
* @FilePath: \dooringx\packages\dooringx-lib\src\core\utils\icon.ts
*/
import { createFromIconfontCN } from '@ant-design/icons'; import { createFromIconfontCN } from '@ant-design/icons';
export const IconFont = createFromIconfontCN({ export const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_2607370_myr2zkz3ku.js', // 在 iconfont.cn 上生成 scriptUrl: '//at.alicdn.com/t/font_2607370_zx7pglxj1m.js', // 在 iconfont.cn 上生成
extraCommonProps: { extraCommonProps: {
fill: 'currentColor', fill: 'currentColor',
stroke: 'currentColor', stroke: 'currentColor',

View File

@@ -156,7 +156,7 @@ export const changeLayer = (store: Store, id: string, action: 'up' | 'down' | 'd
* @param {*} from * @param {*} from
* @param {*} to * @param {*} to
*/ */
export const arrayMove = (array: any, from: number, to: number) => { export const arrayMove = (array: Array<any>, from: number, to: number) => {
array = [...array]; array = [...array];
arrayMoveMutate(array, from, to); arrayMoveMutate(array, from, to);
return array; return array;
@@ -179,7 +179,7 @@ const indexSub = (arrLength: number, toIndex: number) => {
* @param {Number} to Index of where to move the item. If negative, it will begin that many elements from the end / 0 / -1 / 2 * @param {Number} to Index of where to move the item. If negative, it will begin that many elements from the end / 0 / -1 / 2
* returns A new array with the item moved to the new position [1,2,3] -> [1,3,2] * returns A new array with the item moved to the new position [1,2,3] -> [1,3,2]
*/ */
const arrayMoveMutate = (array: [], from: number, to: number) => { const arrayMoveMutate = (array: Array<any>, from: number, to: number) => {
const arrLength = array.length; const arrLength = array.length;
const startIndex = indexSub(arrLength, from); const startIndex = indexSub(arrLength, from);
if (startIndex >= 0 && startIndex < arrLength) { if (startIndex >= 0 && startIndex < arrLength) {

View File

@@ -2,10 +2,9 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 05:35:15 * @Date: 2021-03-14 05:35:15
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-07-04 17:52:02 * @LastEditTime: 2021-07-10 17:46:26
* @FilePath: \DooringV2\packages\dooring-v2-lib\src\hooks\index.ts * @FilePath: \dooringx\packages\dooringx-lib\src\hooks\index.ts
*/ */
import { store } from '../runtime/store';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import UserConfig from '../config'; import UserConfig from '../config';
import { ComponentRenderConfigProps } from '../core/components/componentItem'; import { ComponentRenderConfigProps } from '../core/components/componentItem';
@@ -16,11 +15,13 @@ export function useStoreState(
extraFn: Function = () => {}, extraFn: Function = () => {},
everyFn: Function = () => {} everyFn: Function = () => {}
) { ) {
const store = config.getStore();
const [state, setState] = useState(store.getData()); const [state, setState] = useState(store.getData());
const forceUpdate = useState(0)[1]; const forceUpdate = useState(0)[1];
useEffect(() => { useEffect(() => {
const unRegister = store.subscribe(() => { const unRegister = store.subscribe(() => {
setState(store.getData()); const data = store.getData();
setState(data);
config.getEventCenter().syncEventMap(store.getData(), config.getStoreChanger()); config.getEventCenter().syncEventMap(store.getData(), config.getStoreChanger());
extraFn(); extraFn();
}); });
@@ -32,7 +33,7 @@ export function useStoreState(
unRegister(); unRegister();
unRegistCommandFn(commandModules, commander); unRegistCommandFn(commandModules, commander);
}; };
}, [config, extraFn]); }, [config, extraFn, forceUpdate, store]);
useEffect(() => { useEffect(() => {
everyFn(); everyFn();
}, [everyFn]); }, [everyFn]);

View File

@@ -2,15 +2,14 @@
* @Author: yehuozhili * @Author: yehuozhili
* @Date: 2021-03-14 04:33:52 * @Date: 2021-03-14 04:33:52
* @LastEditors: yehuozhili * @LastEditors: yehuozhili
* @LastEditTime: 2021-05-30 15:51:50 * @LastEditTime: 2021-07-10 18:18:15
* @FilePath: \dooringv2\packages\dooring-v2-lib\src\runtime\index.ts * @FilePath: \dooringx\packages\dooringx-lib\src\runtime\index.ts
*/ */
import CommanderWrapper from '../core/command'; import CommanderWrapper from '../core/command';
import ComponentRegister from '../core/components'; import ComponentRegister from '../core/components';
import { FormComponentRegister } from '../core/components/formComponentRegister'; import { FormComponentRegister } from '../core/components/formComponentRegister';
import { StoreChanger } from '../core/storeChanger'; import { StoreChanger } from '../core/storeChanger';
import { store } from './store'; import { store } from './store';
export const commander = new CommanderWrapper(store); export const commander = new CommanderWrapper(store);
export const componentRegister = new ComponentRegister(); export const componentRegister = new ComponentRegister();
export const formRegister = new FormComponentRegister(); export const formRegister = new FormComponentRegister();

4112
yarn.lock

File diff suppressed because it is too large Load Diff