mirror of
https://github.com/idrawjs/idraw
synced 2026-05-24 10:08:34 +00:00
feat: update component rendering for @idraw/design
This commit is contained in:
parent
2a40bb624e
commit
b23aeae6f1
10 changed files with 105 additions and 96 deletions
|
|
@ -1,11 +1,12 @@
|
|||
import { createUUID } from '@idraw/util';
|
||||
import type { DesignData } from '../src';
|
||||
|
||||
const data: DesignData = {
|
||||
components: [
|
||||
{
|
||||
uuid: 'demo-xxx-001',
|
||||
uuid: createUUID(),
|
||||
type: 'component',
|
||||
name: 'demo',
|
||||
name: 'Button default',
|
||||
x: 50,
|
||||
y: 50,
|
||||
w: 100,
|
||||
|
|
@ -14,7 +15,7 @@ const data: DesignData = {
|
|||
bgColor: '#1f1f1f',
|
||||
children: [
|
||||
{
|
||||
uuid: 'group-001-0014',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: -40,
|
||||
y: 0,
|
||||
|
|
@ -25,7 +26,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0015',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: -20,
|
||||
y: 0,
|
||||
|
|
@ -36,7 +37,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0016',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
|
@ -47,7 +48,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0017',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: 20,
|
||||
y: 0,
|
||||
|
|
@ -58,7 +59,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0018',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: 40,
|
||||
y: 0,
|
||||
|
|
@ -72,9 +73,9 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'demo-xxx-002',
|
||||
uuid: createUUID(),
|
||||
type: 'component',
|
||||
name: 'demo',
|
||||
name: 'Button primary',
|
||||
x: 50,
|
||||
y: 50,
|
||||
w: 100,
|
||||
|
|
@ -83,7 +84,7 @@ const data: DesignData = {
|
|||
bgColor: '#f0f0f0',
|
||||
children: [
|
||||
{
|
||||
uuid: 'group-001-0014',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: -40,
|
||||
y: 0,
|
||||
|
|
@ -94,7 +95,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0015',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: -20,
|
||||
y: 0,
|
||||
|
|
@ -105,7 +106,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0016',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
|
@ -116,7 +117,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0017',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: 20,
|
||||
y: 0,
|
||||
|
|
@ -127,7 +128,7 @@ const data: DesignData = {
|
|||
}
|
||||
},
|
||||
{
|
||||
uuid: 'group-001-0018',
|
||||
uuid: createUUID(),
|
||||
type: 'circle',
|
||||
x: 40,
|
||||
y: 0,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import data from './data';
|
||||
import { Design } from '../src/index';
|
||||
|
||||
const dom = document.querySelector('#lab') as HTMLDivElement;
|
||||
|
|
@ -20,7 +21,7 @@ const App = () => {
|
|||
const width = 800;
|
||||
const height = 600;
|
||||
|
||||
return <Design width={width} height={height} mode={'dark'} style={style} />;
|
||||
return <Design width={width} height={height} style={style} designData={data} />;
|
||||
};
|
||||
|
||||
root.render(<App />);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
import { createContext } from 'react';
|
||||
import type { Dispatch } from 'react';
|
||||
import type { Data } from '@idraw/types';
|
||||
import { DesignData } from './types';
|
||||
|
||||
export interface DesignState {
|
||||
data: DesignData;
|
||||
designData: DesignData | null;
|
||||
viewDrawData: Data | null;
|
||||
viewDrawUUID: string | null;
|
||||
themeMode: 'light' | 'dark';
|
||||
}
|
||||
|
||||
export type DesignActionType = 'updateThemeMode' | 'updateData';
|
||||
export type DesignActionType = 'updateThemeMode' | 'updateDesignData';
|
||||
|
||||
export type DesignAction = {
|
||||
type: DesignActionType;
|
||||
|
|
@ -42,14 +45,14 @@ export function createDesignReducer(state: DesignState, action: DesignAction): D
|
|||
}
|
||||
};
|
||||
}
|
||||
case 'updateData': {
|
||||
if (!action?.payload?.data) {
|
||||
case 'updateDesignData': {
|
||||
if (!action?.payload?.designData) {
|
||||
return state;
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
...{
|
||||
data: action?.payload?.data
|
||||
data: action?.payload?.designData
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -60,8 +63,10 @@ export function createDesignReducer(state: DesignState, action: DesignAction): D
|
|||
|
||||
export function createDesignContextState(opts?: Partial<DesignState>): DesignState {
|
||||
return {
|
||||
data: opts?.data || createDesignData(),
|
||||
themeMode: opts?.themeMode || 'light'
|
||||
designData: opts?.designData || createDesignData(),
|
||||
themeMode: opts?.themeMode || 'light',
|
||||
viewDrawData: null,
|
||||
viewDrawUUID: null
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,24 +13,24 @@ const themeName = 'theme';
|
|||
const themePrefixName = createPrefixName(themeName);
|
||||
|
||||
export type DesignProps = SketchProps & {
|
||||
data?: DesignData;
|
||||
designData?: DesignData;
|
||||
locale?: string; // TODO
|
||||
themeMode?: 'light' | 'dark';
|
||||
};
|
||||
|
||||
export const Design = (props: DesignProps) => {
|
||||
const { width = 1000, height = 600, style, className, data, themeMode } = props;
|
||||
const { width = 1000, height = 600, style, className, designData, themeMode } = props;
|
||||
|
||||
const [state, dispatch] = useReducer(createDesignReducer, createDesignContextState({ data, themeMode }));
|
||||
const [state, dispatch] = useReducer(createDesignReducer, createDesignContextState({ designData, themeMode }));
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
if (designData) {
|
||||
dispatch({
|
||||
type: 'updateData',
|
||||
payload: { data }
|
||||
type: 'updateDesignData',
|
||||
payload: { designData }
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
}, [designData]);
|
||||
|
||||
return (
|
||||
<Provider value={{ state, dispatch }}>
|
||||
|
|
|
|||
|
|
@ -7,27 +7,35 @@ import { prefixName } from './config';
|
|||
import { LayerTree } from './layer-tree';
|
||||
import FileOutlined from '@ant-design/icons/FileOutlined';
|
||||
import AppstoreOutlined from '@ant-design/icons/AppstoreOutlined';
|
||||
import ProjectOutlined from '@ant-design/icons/ProjectOutlined';
|
||||
import CalculatorOutlined from '@ant-design/icons/CalculatorOutlined';
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
key: 'page',
|
||||
label: <FileOutlined className={prefixName('tab', 'title')} />,
|
||||
children: (
|
||||
<div style={{ width: '100%', overflow: 'auto' }}>
|
||||
<LayerTree />
|
||||
<LayerTree type="page" />
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
key: 'module',
|
||||
label: <AppstoreOutlined className={prefixName('tab', 'title')} />,
|
||||
children: `Content of Tab Pane 2`
|
||||
children: (
|
||||
<div style={{ width: '100%', overflow: 'auto' }}>
|
||||
<LayerTree type="module" />
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: <ProjectOutlined className={prefixName('tab', 'title')} />,
|
||||
children: `Content of Tab Pane 3`
|
||||
key: 'component',
|
||||
label: <CalculatorOutlined className={prefixName('tab', 'title')} />,
|
||||
children: (
|
||||
<div style={{ width: '100%', overflow: 'auto' }}>
|
||||
<LayerTree type="component" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
|
|
@ -38,11 +46,13 @@ export interface PanelLayerProps {
|
|||
|
||||
export const PanelLayer = (props: PanelLayerProps) => {
|
||||
const { className, style } = props;
|
||||
|
||||
const defaultTabKey = items[2].key;
|
||||
return (
|
||||
<div style={style} className={classnames(prefixName(), className)}>
|
||||
{/* <div className={prefixName('header')}>header</div> */}
|
||||
<div className={prefixName('content')}>
|
||||
<Tabs className={prefixName('tabs')} defaultActiveKey="1" centered items={items} size="small" />
|
||||
<Tabs className={prefixName('tabs')} defaultActiveKey={defaultTabKey} centered items={items} size="small" />
|
||||
</div>
|
||||
{/* <div className={prefixName('footer')}>footer</div> */}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,78 +1,38 @@
|
|||
import React from 'react';
|
||||
import type { CSSProperties } from 'react';
|
||||
import React, { useEffect, useContext } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import Tree from 'antd/es/tree';
|
||||
import DownOutlined from '@ant-design/icons/DownOutlined';
|
||||
import { prefixName } from './config';
|
||||
import { Context } from '../../context';
|
||||
import { parseComponentViewTree } from '../../util/component';
|
||||
|
||||
import type { CSSProperties } from 'react';
|
||||
import type { DataNode, TreeProps } from 'antd/es/tree';
|
||||
import type { DesignItemType } from '../../types';
|
||||
|
||||
const { DirectoryTree } = Tree;
|
||||
|
||||
const treeData: DataNode[] = [0, 1].map((i) => {
|
||||
return {
|
||||
title: 'design-layer-data parent 1',
|
||||
key: `${i}-0`,
|
||||
children: [
|
||||
{
|
||||
title: 'design-layer-data parent 1-0',
|
||||
key: `${i}-0-0`,
|
||||
children: [
|
||||
{
|
||||
title: 'design-layer-data leaf',
|
||||
key: `${i}-0-0-0`
|
||||
},
|
||||
{
|
||||
title: 'design-layer-data leaf',
|
||||
key: `${i}-0-0-1`
|
||||
},
|
||||
{
|
||||
title: 'design-layer-data leaf',
|
||||
key: `${i}-0-0-2`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'design-layer-data parent 1-1',
|
||||
key: `${i}-0-1`,
|
||||
children: [
|
||||
{
|
||||
title: 'design-layer-data leaf',
|
||||
key: `${i}-0-1-0`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'design-layer-data parent 1-2',
|
||||
key: `${i}-0-2`,
|
||||
children: [
|
||||
{
|
||||
title: 'design-layer-data leaf',
|
||||
key: `${i}-0-2-0`
|
||||
},
|
||||
{
|
||||
title: 'design-layer-data leaf',
|
||||
key: `${i}-0-2-1`
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
const baseName = 'layer-tree';
|
||||
|
||||
export interface LayerTreeProps {
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
type: DesignItemType;
|
||||
}
|
||||
|
||||
export const LayerTree = (props: LayerTreeProps) => {
|
||||
const { className, style } = props;
|
||||
const { className, style, type } = props;
|
||||
const { state } = useContext(Context);
|
||||
|
||||
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
|
||||
console.log('selected', selectedKeys, info);
|
||||
};
|
||||
|
||||
let treeData: DataNode[] = [];
|
||||
|
||||
if (type === 'component') {
|
||||
treeData = parseComponentViewTree(state?.designData || null);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={style} className={classnames(prefixName(baseName), className)}>
|
||||
<DirectoryTree showLine blockNode switcherIcon={<DownOutlined />} icon={null} defaultExpandedKeys={['0-0-0']} onSelect={onSelect} treeData={treeData} />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import type { Element, ElementType, ElementSize, ElementBaseDesc } from '@idraw/types';
|
||||
|
||||
export type DesignItemType = 'component' | 'module' | 'page';
|
||||
|
||||
export type DesignComponent = Omit<ElementSize, 'angle'> & {
|
||||
uuid: string;
|
||||
type: 'component';
|
||||
name?: string;
|
||||
name: string;
|
||||
desc?: ElementBaseDesc & {
|
||||
children: Array<Element<ElementType> | DesignComponent>;
|
||||
};
|
||||
|
|
@ -12,7 +14,7 @@ export type DesignComponent = Omit<ElementSize, 'angle'> & {
|
|||
export type DesignModule = Omit<ElementSize, 'angle'> & {
|
||||
uuid: string;
|
||||
type: 'module';
|
||||
name?: string;
|
||||
name: string;
|
||||
desc?: ElementBaseDesc & {
|
||||
children: Array<DesignComponent>;
|
||||
};
|
||||
|
|
@ -21,7 +23,7 @@ export type DesignModule = Omit<ElementSize, 'angle'> & {
|
|||
export type DesignPage = Omit<ElementSize, 'angle'> & {
|
||||
uuid: string;
|
||||
type: 'page';
|
||||
name?: string;
|
||||
name: string;
|
||||
desc: ElementBaseDesc & {
|
||||
children: Array<DesignModule>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export * from './data';
|
||||
export * from './view';
|
||||
|
|
|
|||
5
packages/design/src/types/view.ts
Normal file
5
packages/design/src/types/view.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export interface ViewTreeNode {
|
||||
title: string;
|
||||
key: string;
|
||||
children?: ViewTreeNode[];
|
||||
}
|
||||
24
packages/design/src/util/component.ts
Normal file
24
packages/design/src/util/component.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { Data } from '@idraw/types';
|
||||
import { ViewTreeNode, DesignData, DesignComponent } from '../types';
|
||||
|
||||
export function parseComponentViewTree(designData: DesignData | null): ViewTreeNode[] {
|
||||
const list: ViewTreeNode[] = [];
|
||||
designData?.components?.forEach((comp: DesignComponent) => {
|
||||
const children: ViewTreeNode[] = [];
|
||||
if (Array.isArray(comp?.desc?.children)) {
|
||||
comp?.desc?.children?.forEach((child) => {
|
||||
children.push({
|
||||
key: child.uuid,
|
||||
title: child.name || 'Unamed',
|
||||
children: []
|
||||
});
|
||||
});
|
||||
}
|
||||
list.push({
|
||||
key: comp.uuid,
|
||||
title: comp.name || 'Unamed',
|
||||
children
|
||||
});
|
||||
});
|
||||
return list;
|
||||
}
|
||||
Loading…
Reference in a new issue