mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2024-11-21 03:15:49 +08:00
refactor structureTree
This commit is contained in:
parent
ef869d5ad6
commit
45753ee0af
@ -92,8 +92,7 @@ export const Editor = () => {
|
||||
height="100%"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
textAlign="left"
|
||||
>
|
||||
textAlign="left">
|
||||
<TabList background="gray.50">
|
||||
<Tab>UI Tree</Tab>
|
||||
<Tab>State</Tab>
|
||||
@ -102,6 +101,7 @@ export const Editor = () => {
|
||||
<TabPanel p={0}>
|
||||
<StructureTree
|
||||
app={app}
|
||||
selectedComponentId={selectedComponentId}
|
||||
onSelectComponent={id => setSelectedComponentId(id)}
|
||||
/>
|
||||
</TabPanel>
|
||||
@ -116,8 +116,7 @@ export const Editor = () => {
|
||||
widht="100%"
|
||||
height="100%"
|
||||
background="white"
|
||||
transform={`scale(${scale / 100})`}
|
||||
>
|
||||
transform={`scale(${scale / 100})`}>
|
||||
{appComponent}
|
||||
</Box>
|
||||
</Box>
|
||||
@ -127,8 +126,7 @@ export const Editor = () => {
|
||||
textAlign="left"
|
||||
height="100%"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
>
|
||||
flexDirection="column">
|
||||
<TabList background="gray.50">
|
||||
<Tab>Inspect</Tab>
|
||||
<Tab>Insert</Tab>
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { DeleteIcon } from '@chakra-ui/icons';
|
||||
import { HStack, IconButton, Text } from '@chakra-ui/react';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
isSelected: boolean;
|
||||
onClick: () => void;
|
||||
onClickRemove: () => void;
|
||||
};
|
||||
|
||||
export const ComponentItemView: React.FC<Props> = props => {
|
||||
const { title, isSelected, onClick, onClickRemove } = props;
|
||||
return (
|
||||
<HStack width="full" justify="space-between">
|
||||
<Text color={isSelected ? 'red.500' : 'black'} onClick={onClick}>
|
||||
{title}
|
||||
</Text>
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
aria-label="remove"
|
||||
icon={<DeleteIcon />}
|
||||
onClick={onClickRemove}
|
||||
/>
|
||||
</HStack>
|
||||
);
|
||||
};
|
@ -0,0 +1,87 @@
|
||||
import { Box, Text } from '@chakra-ui/react';
|
||||
import { ApplicationComponent } from '@meta-ui/core';
|
||||
import React, { useMemo } from 'react';
|
||||
import { eventBus } from '../../eventBus';
|
||||
import { registry } from '../../metaUI';
|
||||
import {
|
||||
CreateComponentOperation,
|
||||
RemoveComponentOperation,
|
||||
} from '../../operations/Operations';
|
||||
import { ComponentItemView } from './ComponentItemView';
|
||||
import { ChildrenMap } from './StructureTree';
|
||||
|
||||
type Props = {
|
||||
component: ApplicationComponent;
|
||||
childrenMap: ChildrenMap;
|
||||
selectedComponentId: string;
|
||||
onSelectComponent: (id: string) => void;
|
||||
};
|
||||
|
||||
export const ComponentTree: React.FC<Props> = props => {
|
||||
const { component, childrenMap, selectedComponentId, onSelectComponent } = props;
|
||||
const slots = registry.getComponentByType(component.type).spec.slots;
|
||||
|
||||
const slotsEle = useMemo(() => {
|
||||
if (slots.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const slotsMap = childrenMap.get(component.id);
|
||||
return slots.map(slot => {
|
||||
let slotContent;
|
||||
const slotChildren = slotsMap?.get(slot);
|
||||
if (slotChildren && slotChildren.length > 0) {
|
||||
slotContent = slotChildren.map(c => {
|
||||
return (
|
||||
<ComponentTree
|
||||
key={c.id}
|
||||
component={c}
|
||||
childrenMap={childrenMap}
|
||||
selectedComponentId={selectedComponentId}
|
||||
onSelectComponent={onSelectComponent}
|
||||
/>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
slotContent = (
|
||||
<Text fontSize="sm" color="gray.500">
|
||||
Empty
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
const onDrop = (e: React.DragEvent) => {
|
||||
const creatingComponent = e.dataTransfer?.getData('component') || '';
|
||||
|
||||
eventBus.send(
|
||||
'operation',
|
||||
new CreateComponentOperation(component.id, slot, creatingComponent)
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Box key={slot} paddingLeft="6">
|
||||
<Text color="gray.500" fontWeight="medium" onDrop={onDrop}>
|
||||
Slot: {slot}
|
||||
</Text>
|
||||
{slotContent}
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
}, [component, childrenMap]);
|
||||
|
||||
const onClickRemove = () => {
|
||||
eventBus.send('operation', new RemoveComponentOperation(component.id));
|
||||
};
|
||||
|
||||
return (
|
||||
<Box key={component.id} width="full">
|
||||
<ComponentItemView
|
||||
title={component.id}
|
||||
isSelected={component.id === selectedComponentId}
|
||||
onClick={() => {
|
||||
onSelectComponent(component.id);
|
||||
}}
|
||||
onClickRemove={onClickRemove}
|
||||
/>
|
||||
{slotsEle}
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -1,17 +1,13 @@
|
||||
import React, { DragEvent } from 'react';
|
||||
import { Application } from '@meta-ui/core';
|
||||
import { IconButton } from '@chakra-ui/react';
|
||||
import { DeleteIcon } from '@chakra-ui/icons';
|
||||
import React from 'react';
|
||||
import { Application, ApplicationComponent } from '@meta-ui/core';
|
||||
import { eventBus } from '../../eventBus';
|
||||
import {
|
||||
CreateComponentOperation,
|
||||
RemoveComponentOperation,
|
||||
} from '../../operations/Operations';
|
||||
import { css } from '@emotion/react';
|
||||
import { RemoveComponentOperation } from '../../operations/Operations';
|
||||
import { ComponentItemView } from './ComponentItemView';
|
||||
import { ComponentTree } from './ComponentTree';
|
||||
import { Text, VStack } from '@chakra-ui/react';
|
||||
|
||||
type ChildrenMap = Map<string, SlotsMap>;
|
||||
type SlotsMap = Map<string, Array<Application['spec']['components'][0]>>;
|
||||
type Component = Application['spec']['components'][0];
|
||||
export type ChildrenMap = Map<string, SlotsMap>;
|
||||
type SlotsMap = Map<string, ApplicationComponent[]>;
|
||||
|
||||
type Props = {
|
||||
app: Application;
|
||||
@ -21,7 +17,7 @@ type Props = {
|
||||
|
||||
export const StructureTree: React.FC<Props> = props => {
|
||||
const { app, selectedComponentId, onSelectComponent } = props;
|
||||
const topLevelComponents: Component[] = [];
|
||||
const topLevelComponents: ApplicationComponent[] = [];
|
||||
const childrenMap: ChildrenMap = new Map();
|
||||
|
||||
const components = app.spec.components.filter(c => c.type !== 'core/v1/dummy');
|
||||
@ -45,60 +41,42 @@ export const StructureTree: React.FC<Props> = props => {
|
||||
}
|
||||
});
|
||||
|
||||
function genTreeItem(component: Component) {
|
||||
const slots = childrenMap.get(component.id);
|
||||
let slotsEle;
|
||||
if (slots) {
|
||||
slotsEle = Array.from(slots.keys()).map(slot => {
|
||||
const children = slots.get(slot)!.map(genTreeItem);
|
||||
const onDrop = (e: DragEvent) => {
|
||||
const creatingComponent = e.dataTransfer?.getData('component') || '';
|
||||
console.log('createComponent', component.id, slot, creatingComponent);
|
||||
eventBus.send(
|
||||
'operation',
|
||||
new CreateComponentOperation(component.id, slot, creatingComponent)
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div key={slot}>
|
||||
<div onDrop={onDrop}>slot: {slot}</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const topEles = topLevelComponents.map(c => (
|
||||
<ComponentTree
|
||||
key={c.id}
|
||||
component={c}
|
||||
childrenMap={childrenMap}
|
||||
selectedComponentId={selectedComponentId}
|
||||
onSelectComponent={onSelectComponent}
|
||||
/>
|
||||
));
|
||||
const dataSourcesEles = dataSources.map(dummy => {
|
||||
const onClickRemove = () => {
|
||||
eventBus.send('operation', new RemoveComponentOperation(component.id));
|
||||
eventBus.send('operation', new RemoveComponentOperation(dummy.id));
|
||||
};
|
||||
|
||||
return (
|
||||
<div key={component.id} style={{ paddingLeft: '16px' }}>
|
||||
<strong
|
||||
css={css`
|
||||
color: ${component.id === selectedComponentId ? 'red' : 'black'};
|
||||
`}
|
||||
onClick={() => {
|
||||
onSelectComponent(component.id);
|
||||
}}
|
||||
>
|
||||
{component.id}
|
||||
</strong>
|
||||
<IconButton aria-label="remove" icon={<DeleteIcon />} onClick={onClickRemove} />
|
||||
{slotsEle}
|
||||
</div>
|
||||
<ComponentItemView
|
||||
key={dummy.id}
|
||||
title={dummy.id}
|
||||
isSelected={dummy.id === selectedComponentId}
|
||||
onClick={() => {
|
||||
onSelectComponent(dummy.id);
|
||||
}}
|
||||
onClickRemove={onClickRemove}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const topEles = topLevelComponents.map(genTreeItem);
|
||||
const dataSourcesEles = dataSources.map(genTreeItem);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<strong>Components</strong>
|
||||
<VStack spacing="2" padding="4" alignItems="start">
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
Components
|
||||
</Text>
|
||||
{topEles}
|
||||
<strong>DataSources</strong>
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
DataSources
|
||||
</Text>
|
||||
{dataSourcesEles}
|
||||
</div>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
@ -42,6 +42,7 @@ import {
|
||||
ComponentImplementationProps,
|
||||
TraitImplementation,
|
||||
} from 'src/types/RuntimeSchema';
|
||||
import { parseType } from '../utils/parseType';
|
||||
|
||||
export type ComponentImplementation<T = any> = React.FC<T & ComponentImplementationProps>;
|
||||
|
||||
@ -77,6 +78,11 @@ export class Registry {
|
||||
return c;
|
||||
}
|
||||
|
||||
getComponentByType(type: string): ImplementedRuntimeComponent {
|
||||
const { version, name } = parseType(type);
|
||||
return this.getComponent(version, name);
|
||||
}
|
||||
|
||||
registerTrait(t: ImplementedRuntimeTrait) {
|
||||
if (this.traits.get(t.version)?.has(t.metadata.name)) {
|
||||
throw new Error(
|
||||
|
Loading…
Reference in New Issue
Block a user