add utilMethods to sunmaoLib & implement chakra toast as utilMethod of lib

This commit is contained in:
Bowen Tan 2022-01-24 11:41:25 +08:00
parent e7fb968e06
commit d618d8bd6d
8 changed files with 128 additions and 82 deletions

View File

@ -1,4 +1,7 @@
import { Type, Static } from '@sinclair/typebox';
import { Type, Static, TProperties, TObject } from '@sinclair/typebox';
import { createStandaloneToast } from '@chakra-ui/react';
import { UtilMethod } from '@sunmao-ui/runtime';
const ToastPosition = Type.Union([
Type.Literal('top'),
Type.Literal('top-right'),
@ -38,4 +41,50 @@ export const ToastCloseParameterSchema = Type.Object({
});
export type ToastOpenParameter = Static<typeof ToastOpenParamterSchema>;
export type ToastCloseParameter = Static<typeof ToastCloseParameterSchema>;
export type ToastCloseParameter = Static<typeof ToastCloseParameterSchema>;
const pickProperty = <T, U extends Record<string, any>>(
schema: TObject<T>,
object: U
): Partial<Static<TObject<T>>> => {
const result: Partial<TProperties> = {};
for (const key in schema.properties) {
result[key] = object[key];
}
return result as Partial<Static<TObject<T>>>;
};
export default function ToastUtilMethodFactory() {
let toast: ReturnType<typeof createStandaloneToast> | undefined;
const toastOpen: UtilMethod = {
name: 'toast.open',
method(parameters: Static<typeof ToastOpenParamterSchema>) {
if (!toast) {
toast = createStandaloneToast();
}
if (parameters) {
toast(pickProperty(ToastOpenParamterSchema, parameters));
}
},
};
const toastClose: UtilMethod = {
name: 'toast.close',
method(parameters: Static<typeof ToastCloseParameterSchema>) {
if (!toast) {
return;
}
if (!parameters) {
toast.closeAll();
} else {
const closeParameters = pickProperty(ToastCloseParameterSchema, parameters);
if (closeParameters.id !== undefined) {
toast.close(closeParameters.id);
} else {
toast.closeAll(closeParameters);
}
}
},
};
return [toastOpen, toastClose];
}

View File

@ -24,6 +24,7 @@ import ChakraUIDialog from './components/Dialog';
import ChakraUISelect from './components/Select';
import ChakraUIRadioGroup from './components/RadioGroup';
import ChakraUIRadio from './components/Radio';
import ChakraUIToastUtilMethodFactory from './components/Types/Toast';
export const sunmaoChakraUILib: SunmaoLib = {
components: [
@ -55,4 +56,5 @@ export const sunmaoChakraUILib: SunmaoLib = {
],
traits: [],
modules: [],
utilMethods: [ChakraUIToastUtilMethodFactory],
};

View File

@ -31,7 +31,7 @@ export default implementRuntimeComponent({
properties: PropsSchema,
state: StateSchema,
methods: {
click: void 0,
click: undefined,
},
slots: [],
styleSlots: ['content'],

View File

@ -1,21 +1,20 @@
import { StateManager } from './services/stateStore';
import { genApp } from './App';
import { initRegistry } from './services/registry';
import { initRegistry, UtilMethod } from './services/registry';
import { initApiService } from './services/apiService';
import { mountUtilMethods } from './services/util-methods';
import { initGlobalHandlerMap } from './services/handler';
import './style.css';
export type SunmaoUIRuntimeProps = {
dependencies?: Record<string, any>
}
dependencies?: Record<string, any>;
utilMethods?: UtilMethod[];
};
export function initSunmaoUI(props: SunmaoUIRuntimeProps = {}) {
const registry = initRegistry();
const stateManager = new StateManager(props.dependencies);
const globalHandlerMap = initGlobalHandlerMap();
const apiService = initApiService();
mountUtilMethods(apiService);
const registry = initRegistry(apiService);
return {
App: genApp({ registry, stateManager, globalHandlerMap, apiService }),

View File

@ -18,9 +18,35 @@ export function initApiService() {
eventType: string;
};
}>();
return {
const apiService = {
on: emitter.on,
off: emitter.off,
send: emitter.emit,
};
mountSystemMethods(apiService);
return apiService;
}
function mountSystemMethods(apiService: ApiService) {
apiService.on('uiMethod', ({ componentId, name, parameters }) => {
switch (componentId) {
// hanlder as module event
case '$module':
apiService.send('moduleEvent', {
fromId: parameters.moduleId,
eventType: name,
});
break;
case '$utils':
// handle as window function
if (name in window) {
const method = window[name as keyof Window];
if (typeof method === 'function') {
method(parameters);
}
}
break;
}
});
}

View File

@ -22,11 +22,20 @@ import {
ImplementedRuntimeTrait,
ImplementedRuntimeModule,
} from '../types';
import { ApiService } from './apiService';
export type UtilMethod = {
name: string;
method: (parameters?: any) => void;
};
export type UtilMethodFactory = () => UtilMethod[];
export type SunmaoLib = {
components?: ImplementedRuntimeComponent<string, string, string, string>[];
traits?: ImplementedRuntimeTrait[];
modules?: ImplementedRuntimeModule[];
utilMethods?: UtilMethodFactory[];
};
type AnyImplementedRuntimeComponent = ImplementedRuntimeComponent<
@ -40,6 +49,12 @@ export class Registry {
components = new Map<string, Map<string, AnyImplementedRuntimeComponent>>();
traits = new Map<string, Map<string, ImplementedRuntimeTrait>>();
modules = new Map<string, Map<string, ImplementedRuntimeModule>>();
utilMethods = new Map<string, UtilMethod['method']>();
private apiService: ApiService;
constructor(apiService: ApiService) {
this.apiService = apiService;
}
registerComponent(c: AnyImplementedRuntimeComponent) {
if (this.components.get(c.version)?.has(c.metadata.name)) {
@ -146,15 +161,40 @@ export class Registry {
return this.getModule(version, name);
}
registerUtilMethod(m: UtilMethod) {
if (this.utilMethods.get(m.name)) {
throw new Error(`Already has utilMethod ${m.name} in this registry.`);
}
this.utilMethods.set(m.name, m.method);
}
installLib(lib: SunmaoLib) {
lib.components?.forEach(c => this.registerComponent(c));
lib.traits?.forEach(t => this.registerTrait(t));
lib.modules?.forEach(m => this.registerModule(m));
if (lib.utilMethods) {
lib.utilMethods.forEach(factory => {
const methods = factory();
methods.forEach(m => this.registerUtilMethod(m));
});
this.mountUtilMethods();
}
}
private mountUtilMethods() {
this.apiService.on('uiMethod', ({ componentId, name, parameters }) => {
if (componentId === '$utils') {
const utilMethod = this.utilMethods.get(name);
if (utilMethod) {
utilMethod(parameters);
}
}
});
}
}
export function initRegistry(): Registry {
const registry = new Registry();
export function initRegistry(apiService: ApiService): Registry {
const registry = new Registry(apiService);
registry.registerComponent(PlainButton);
registry.registerComponent(CoreText);
registry.registerComponent(CoreGridLayout);

View File

@ -1,58 +0,0 @@
import { ApiService } from './apiService';
// import { createStandaloneToast } from '@chakra-ui/react';
// import {
// ToastCloseParameterSchema,
// ToastOpenParamterSchema,
// } from '../components/chakra-ui/Types/Toast';
// import { pickProperty } from '../utils/pickProperty';
export function mountUtilMethods(apiService: ApiService) {
// let toast: ReturnType<typeof createStandaloneToast> | undefined = undefined;
apiService.on('uiMethod', ({ componentId, name, parameters }) => {
if (componentId === '$utils') {
switch (name) {
case 'alert':
window.alert(parameters);
break;
// case 'toast.open':
// if (!toast) {
// toast = createStandaloneToast();
// }
// if (parameters) {
// toast(pickProperty(ToastOpenParamterSchema, parameters));
// }
// break;
// case 'toast.close':
// if (!toast) {
// break;
// }
// if (!parameters) {
// toast.closeAll();
// } else {
// const closeParameters = pickProperty(ToastCloseParameterSchema, parameters);
// if (closeParameters.id !== undefined) {
// toast.close(closeParameters.id);
// } else {
// toast.closeAll(closeParameters);
// }
// }
// break;
default:
break;
}
if (name in window) {
const method = window[name as keyof Window];
if (typeof method === 'function') {
method(parameters);
}
}
}
if (componentId === '$module') {
apiService.send('moduleEvent', {
fromId: parameters.moduleId,
eventType: name,
});
}
});
}

View File

@ -1,12 +0,0 @@
import { Static, TObject, TProperties } from '@sinclair/typebox';
export const pickProperty = <T, U extends TProperties>(
schema: TObject<T>,
object: U
): Partial<Static<TObject<T>>> => {
const result: Partial<TProperties> = {};
for (const key in schema.properties) {
result[key] = object[key];
}
return result as Partial<Static<TObject<T>>>;
};