refactor core components

This commit is contained in:
Bowen Tan 2021-12-30 15:27:54 +08:00
parent c3834ae3ef
commit 70dad17dee
25 changed files with 195 additions and 222 deletions

View File

@ -313,7 +313,7 @@ export default {
spec: {
properties: StyleSchema,
state: {},
methods: [],
methods: {},
slots: ['content'],
styleSlots: ['content'],
events: [],

View File

@ -132,7 +132,7 @@ export default {
spec: {
properties: PropsSchema,
state: CheckboxStateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: [],

View File

@ -60,7 +60,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: ['content'],
styleSlots: [],
events: [],

View File

@ -28,7 +28,7 @@ export default {
spec: {
properties: {},
state: {},
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: [],

View File

@ -157,7 +157,7 @@ export default {
isInvalid: Type.Boolean(),
value: Type.Any(),
}),
methods: [],
methods: {},
slots: ['content'],
styleSlots: ['content'],
events: [],

View File

@ -151,7 +151,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: ['onLoad', 'onError'],

View File

@ -53,7 +53,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: [],

View File

@ -51,7 +51,7 @@ export default {
spec: {
properties: PropsSchema,
state: {},
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: [],

View File

@ -93,7 +93,7 @@ export default {
},
spec: {
properties: PropsSchema,
methods: [],
methods: {},
state: {},
slots: [],
styleSlots: ['content'],

View File

@ -122,7 +122,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: [],
events: [],

View File

@ -98,7 +98,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: [],

View File

@ -62,7 +62,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: ['content'],
styleSlots: ['content'],
events: [],

View File

@ -30,7 +30,7 @@ export default {
spec: {
properties: {},
state: {},
methods: [],
methods: {},
slots: ['root'],
styleSlots: [],
events: [],

View File

@ -126,7 +126,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: ['content'],
events: [],

View File

@ -77,7 +77,7 @@ export default {
spec: {
properties: PropsSchema,
state: {},
methods: [],
methods: {},
slots: ['content'],
styleSlots: [],
events: [],

View File

@ -54,7 +54,7 @@ export default {
spec: {
properties: PropsSchema,
state: TableStateSchema,
methods: [],
methods: {},
slots: [],
styleSlots: [],
events: [],

View File

@ -91,7 +91,7 @@ export default {
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
methods: {},
// tab slot is dynamic
slots: ['content'],
styleSlots: ['tabItem', 'tabContent'],

View File

@ -81,7 +81,7 @@ export default {
spec: {
properties: PropsSchema,
state: {},
methods: [],
methods: {},
slots: ['content'],
styleSlots: [],
events: [],

View File

@ -1,8 +1,27 @@
import { createComponent } from '@sunmao-ui/core';
import { implementRuntimeComponent2 } from '../../utils/buildKit';
import { useEffect } from 'react';
import { ComponentImplementation } from '../../services/registry';
import { Type } from '@sinclair/typebox';
const Dummy: ComponentImplementation<Record<string, unknown>> = ({ effects }) => {
export default implementRuntimeComponent2({
version: 'core/v1',
metadata: {
name: 'dummy',
displayName: 'Dummy',
description: 'Dummy Invisible component',
isDraggable: false,
isResizable: false,
exampleProperties: {},
exampleSize: [1, 1],
},
spec: {
properties: Type.Object({}),
state: Type.Object({}),
methods: {},
slots: [],
styleSlots: [],
events: [],
},
})(({ effects }) => {
useEffect(() => {
return () => {
effects?.forEach(e => e());
@ -10,27 +29,4 @@ const Dummy: ComponentImplementation<Record<string, unknown>> = ({ effects }) =>
}, [effects]);
return null;
};
export default {
...createComponent({
version: 'core/v1',
metadata: {
name: 'dummy',
displayName: 'Dummy',
description: 'Dummy Invisible component',
isDraggable: false,
isResizable: false,
exampleProperties: {},
exampleSize: [1, 1],
},
spec: {
properties: {},
state: {},
methods: [],
slots: [],
styleSlots: [],
events: [],
},
}),
impl: Dummy,
};
});

View File

@ -1,20 +1,47 @@
import React, { Suspense } from 'react';
import { ComponentImplementation } from '../../services/registry';
import { createComponent } from '@sunmao-ui/core';
import { implementRuntimeComponent2 } from '../../utils/buildKit';
import { getSlots } from '../_internal/Slot';
import { Static, Type } from '@sinclair/typebox';
import { Type } from '@sinclair/typebox';
import { partial } from 'lodash-es';
import { css } from '@emotion/css';
const BaseGridLayout = React.lazy(() => import('../_internal/GridLayout'));
const GridLayout: ComponentImplementation<Static<typeof PropsSchema>> = ({
slotsMap,
layout = [],
gridCallbacks,
component,
customStyle,
}) => {
const PropsSchema = Type.Object({
layout: Type.Array(
Type.Object({
x: Type.Number(),
y: Type.Number(),
w: Type.Number(),
h: Type.Number(),
i: Type.String(),
isResizable: Type.Optional(Type.Boolean()),
})
),
});
export default implementRuntimeComponent2({
version: 'core/v1',
metadata: {
name: 'grid_layout',
displayName: 'Grid Layout',
description: 'drag and drop to layout in a grid',
isDraggable: true,
isResizable: true,
exampleProperties: {
layout: [],
},
exampleSize: [6, 6],
},
spec: {
properties: PropsSchema,
state: {},
methods: {},
slots: ['content'],
styleSlots: ['content'],
events: [],
},
})(({ slotsMap, layout = [], gridCallbacks, component, customStyle }) => {
const onDragStop = gridCallbacks?.onDragStop
? partial(gridCallbacks.onDragStop, component.id)
: undefined;
@ -30,49 +57,12 @@ const GridLayout: ComponentImplementation<Static<typeof PropsSchema>> = ({
onDragStop={onDragStop}
onDrop={onDrop}
layout={layout}
className={css`${customStyle?.content}`}
className={css`
${customStyle?.content}
`}
>
{getSlots(slotsMap, 'content', {})}
</BaseGridLayout>
</Suspense>
);
};
const PropsSchema = Type.Object({
layout: Type.Array(
Type.Object({
x: Type.Number(),
y: Type.Number(),
w: Type.Number(),
h: Type.Number(),
i: Type.String(),
isResizable: Type.Optional(Type.Boolean()),
})
),
});
export default {
...createComponent({
version: 'core/v1',
metadata: {
name: 'grid_layout',
displayName: 'Grid Layout',
description: 'drag and drop to layout in a grid',
isDraggable: true,
isResizable: true,
exampleProperties: {
layout: [],
},
exampleSize: [6, 6],
},
spec: {
properties: PropsSchema,
state: {},
methods: [],
slots: ['content'],
styleSlots: ['content'],
events: [],
},
}),
impl: GridLayout,
};

View File

@ -1,40 +1,8 @@
import { createComponent } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { ComponentImplementation } from '../../services/registry';
import { implementRuntimeComponent2 } from '../../utils/buildKit';
import { RuntimeModuleSchema } from '../../types/RuntimeSchema';
import { ModuleRenderer } from '../_internal/ModuleRenderer';
type Props = Static<typeof RuntimeModuleSchema>;
const ModuleContainer: ComponentImplementation<Props> = ({
id,
type,
properties,
handlers,
services,
app
}) => {
if (!type) {
return <span>Please choose a module to render.</span>
}
if (!id) {
return <span>Please set a id for module.</span>
}
return (
<ModuleRenderer
id={id}
type={type}
properties={properties}
handlers={handlers}
services={services}
app={app}
/>
);
};
export default {
...createComponent({
export default implementRuntimeComponent2({
version: 'core/v1',
metadata: {
name: 'moduleContainer',
@ -49,17 +17,36 @@ export default {
exampleSize: [6, 6],
},
spec: {
properties: Type.Object({
id: Type.String(),
type: Type.String(),
properties: Type.Record(Type.String(), Type.Any()),
}),
properties: RuntimeModuleSchema,
state: {},
methods: [],
methods: {},
slots: [],
styleSlots: [],
events: [],
},
}),
impl: ModuleContainer,
};
})(({
id,
type,
properties,
handlers,
services,
app
}) => {
if (!type) {
return <span>Please choose a module to render.</span>
}
if (!id) {
return <span>Please set a id for module.</span>
}
return (
<ModuleRenderer
id={id}
type={type}
properties={properties}
handlers={handlers}
services={services}
app={app}
/>
);
})

View File

@ -1,22 +1,7 @@
import { Static, Type } from '@sinclair/typebox';
import { createComponent } from '@sunmao-ui/core';
import { ComponentImplementation } from '../../../services/registry';
import { implementRuntimeComponent2 } from '../../../utils/buildKit';
import { Switch } from './component';
const Router: ComponentImplementation<{
switchPolicy: Static<typeof SwitchPolicyPropertySchema>;
nested?: boolean;
}> = ({ slotsMap, switchPolicy, subscribeMethods, mergeState }) => {
return (
<Switch
slotMap={slotsMap}
switchPolicy={switchPolicy}
subscribeMethods={subscribeMethods}
mergeState={mergeState}
></Switch>
);
};
export enum RouteType {
REDIRECT = 'REDIRECT',
ROUTE = 'ROUTE',
@ -52,29 +37,35 @@ const PropsSchema = Type.Object({
),
});
export default {
...createComponent({
version: 'core/v1',
metadata: {
name: 'router',
displayName: 'Router',
description: 'create a router-controlled component',
isDraggable: true,
isResizable: true,
exampleProperties: {
switchPolicy: [],
},
exampleSize: [6, 6],
export default implementRuntimeComponent2({
version: 'core/v1',
metadata: {
name: 'router',
displayName: 'Router',
description: 'create a router-controlled component',
isDraggable: true,
isResizable: true,
exampleProperties: {
switchPolicy: [],
},
spec: {
properties: PropsSchema,
state: {},
methods: [],
// route slots are dynamic
slots: [],
styleSlots: [],
events: [],
},
}),
impl: Router,
};
exampleSize: [6, 6],
},
spec: {
properties: PropsSchema,
state: Type.Object({}),
methods: {},
// route slots are dynamic
slots: [],
styleSlots: [],
events: [],
},
})(({ slotsMap, switchPolicy, subscribeMethods, mergeState }) => {
return (
<Switch
slotMap={slotsMap}
switchPolicy={switchPolicy}
subscribeMethods={subscribeMethods}
mergeState={mergeState}
></Switch>
);
});

View File

@ -1,14 +1,6 @@
import { createComponent } from '@sunmao-ui/core';
import { Type, Static } from '@sinclair/typebox';
import { ComponentImplementation } from '../../services/registry';
import { Type } from '@sinclair/typebox';
import _Text, { TextPropertySchema } from '../_internal/Text';
const Text: ComponentImplementation<Static<typeof PropsSchema>> = ({
value,
customStyle,
}) => {
return <_Text value={value} cssStyle={customStyle?.content} />;
};
import { implementRuntimeComponent2 } from '../../utils/buildKit';
const StateSchema = Type.Object({
value: Type.String(),
@ -18,31 +10,30 @@ const PropsSchema = Type.Object({
value: TextPropertySchema,
});
export default {
...createComponent({
version: 'core/v1',
metadata: {
name: 'text',
displayName: 'Text',
description: 'support plain and markdown formats',
isDraggable: true,
isResizable: false,
exampleProperties: {
value: {
raw: 'text',
format: 'plain',
},
export default implementRuntimeComponent2({
version: 'core/v1',
metadata: {
name: 'text',
displayName: 'Text',
description: 'support plain and markdown formats',
isDraggable: true,
isResizable: false,
exampleProperties: {
value: {
raw: 'text',
format: 'plain',
},
exampleSize: [4, 1],
},
spec: {
properties: PropsSchema,
state: StateSchema,
methods: [],
slots: [],
styleSlots: ['content'],
events: [],
},
}),
impl: Text,
};
exampleSize: [4, 1],
},
spec: {
properties: PropsSchema,
state: StateSchema,
methods: {},
slots: [],
styleSlots: ['content'],
events: [],
},
})(({ value, customStyle }) => {
return <_Text value={value} cssStyle={customStyle?.content} />;
});

View File

@ -1,7 +1,7 @@
import { useEffect, useRef } from 'react';
import { Type } from '@sinclair/typebox';
import Text, { TextPropertySchema } from '../_internal/Text';
import { implementRuntimeComponent2 } from 'src/utils/buildKit';
import { implementRuntimeComponent2 } from '../../utils/buildKit';
const StateSchema = Type.Object({
value: Type.String(),

View File

@ -29,6 +29,7 @@ import {
import { parseType } from '../utils/parseType';
import { parseModuleSchema } from '../utils/parseModuleSchema';
import { cloneDeep } from 'lodash-es';
import { ImplementedRuntimeComponent2 } from '../utils/buildKit';
export type ComponentImplementation<
TProps = any,
@ -60,7 +61,7 @@ export type SunmaoLib = {
};
export class Registry {
components = new Map<string, Map<string, ImplementedRuntimeComponent>>();
components = new Map<string, Map<string, any>>();
traits = new Map<string, Map<string, ImplementedRuntimeTrait>>();
modules = new Map<string, Map<string, ImplementedRuntimeModule>>();
@ -76,6 +77,23 @@ export class Registry {
this.components.get(c.version)?.set(c.metadata.name, c);
}
registerComponent2<
KMethodName extends string,
KStyleSlot extends string,
KSlot extends string,
KEvent extends string
>(c: ImplementedRuntimeComponent2<KMethodName, KStyleSlot, KSlot, KEvent>) {
if (this.components.get(c.version)?.has(c.metadata.name)) {
throw new Error(
`Already has component ${c.version}/${c.metadata.name} in this registry.`
);
}
if (!this.components.has(c.version)) {
this.components.set(c.version, new Map());
}
this.components.get(c.version)?.set(c.metadata.name, c);
}
getComponent(version: string, name: string): ImplementedRuntimeComponent {
const c = this.components.get(version)?.get(name);
if (!c) {
@ -181,11 +199,11 @@ export function initRegistry(): Registry {
const registry = new Registry();
// TODO: (type-safe) register v2 component
// registry.registerComponent(PlainButton);
registry.registerComponent(CoreText);
registry.registerComponent(CoreGridLayout);
registry.registerComponent(CoreRouter);
registry.registerComponent(CoreDummy);
registry.registerComponent(CoreModuleContainer);
registry.registerComponent2(CoreText);
registry.registerComponent2(CoreGridLayout);
registry.registerComponent2(CoreRouter);
registry.registerComponent2(CoreDummy);
registry.registerComponent2(CoreModuleContainer);
registry.registerTrait(CoreState);
registry.registerTrait(CoreArrayState);