@bbki.ng/site 5.8.2 → 5.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/package.json +2 -2
- package/src/app/app.tsx +4 -8
- package/src/app/components/BaseLayout.tsx +2 -3
- package/src/app/components/cover/index.tsx +17 -15
- package/src/app/hooks/use_plugin_entries.ts +17 -27
- package/src/core/components/SlotComp.tsx +4 -17
- package/src/core/hooks/index.ts +2 -2
- package/src/core/hooks/useMiddlewareTransData.ts +13 -82
- package/src/core/hooks/useSlotComp.ts +3 -26
- package/src/core/hooks/use_plugins.ts +4 -3
- package/src/core/plugin-system/pluginManager.ts +5 -2
- package/src/core/plugin-system/pluginManifestService.ts +2 -18
- package/src/core/plugin-system/pluginStore.ts +1 -0
- package/src/core/plugin-system/registry.ts +1 -106
- package/src/core/plugin-system/services/systemUIService.ts +31 -126
- package/src/core/shared-service/contract/IUIService.ts +15 -17
- package/src/core/shared-service/factory/createUIService.ts +121 -0
- package/src/core/shared-service/factory/createUIServiceReactKit.tsx +149 -0
- package/src/plugins/blog/components/BlogSlotCom.tsx +4 -17
- package/src/plugins/blog/hooks/useMiddlewareTransData.ts +11 -76
- package/src/plugins/blog/hooks/use_blog_slot_com.ts +2 -24
- package/src/plugins/blog/index.ts +6 -1
- package/src/plugins/blog/services/BlogUIService.ts +10 -103
- package/src/plugins/blog/services/IBlogUIService.ts +1 -16
- package/src/plugins/store/components/storeIcon.tsx +16 -0
- package/src/plugins/store/index.ts +3 -1
- package/src/types/slots.ts +0 -17
- package/tsconfig.json +1 -1
- package/src/utils/index.tsx +0 -20
|
@@ -1,66 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { LinkProps } from '@bbki.ng/ui';
|
|
4
|
-
|
|
1
|
+
import { createUIService } from '#/core/shared-service/factory/createUIService';
|
|
2
|
+
import { createEventBus } from '#/core/utils/eventBus';
|
|
5
3
|
import {
|
|
6
4
|
ISystemUIService,
|
|
7
5
|
SystemDataHookPoint,
|
|
8
6
|
SystemSlotName,
|
|
9
7
|
} from '#/core/shared-service/contract/IUIService';
|
|
10
8
|
import { IPluginEntry, PluginID } from '#/types/plugin';
|
|
11
|
-
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
12
|
-
import { createEventBus } from '#/core/utils/eventBus';
|
|
13
|
-
import { buildEntrySlotCom } from '#/utils';
|
|
14
|
-
|
|
15
|
-
import { IMiddlewareEntry, ISlotEntry } from '../registry';
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
'system:slots:changed': void;
|
|
19
|
-
'system:middleware:changed': SystemDataHookPoint;
|
|
20
|
-
};
|
|
10
|
+
const baseService = createUIService<SystemSlotName, SystemDataHookPoint>('system');
|
|
21
11
|
|
|
22
12
|
export class SystemUIService implements ISystemUIService {
|
|
23
13
|
private static instance: SystemUIService;
|
|
24
14
|
|
|
25
|
-
private
|
|
26
|
-
private middlewares = new Map<SystemDataHookPoint, IMiddlewareEntry<unknown>[]>();
|
|
15
|
+
private pluginEntries = new Map<string, IPluginEntry & { pluginId: PluginID }>();
|
|
27
16
|
|
|
28
|
-
private
|
|
17
|
+
private entryBus = createEventBus<{ pluginEntriesChanged: void }>();
|
|
29
18
|
|
|
30
19
|
private constructor() {}
|
|
31
20
|
|
|
32
|
-
subscribeSlotChange(listener: () => void) {
|
|
33
|
-
return this.bus.on('system:slots:changed', listener);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
registerMiddleware: <T>(
|
|
37
|
-
hookPoint: SystemDataHookPoint,
|
|
38
|
-
fn: (data: T) => T | Promise<T>,
|
|
39
|
-
pluginId: PluginID,
|
|
40
|
-
weight?: number
|
|
41
|
-
) => void = <T>(
|
|
42
|
-
hookPoint: SystemDataHookPoint,
|
|
43
|
-
fn: (data: T) => T | Promise<T>,
|
|
44
|
-
pluginId: PluginID,
|
|
45
|
-
weight = 0
|
|
46
|
-
) => {
|
|
47
|
-
const existing = this.middlewares.get(hookPoint) || [];
|
|
48
|
-
|
|
49
|
-
const newEntry: IMiddlewareEntry<T> = {
|
|
50
|
-
id: `${pluginId}-${hookPoint}-middleware`,
|
|
51
|
-
pluginId,
|
|
52
|
-
fn,
|
|
53
|
-
weight,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const updated = [...existing, newEntry as IMiddlewareEntry<unknown>].sort(
|
|
57
|
-
(a, b) => (b.weight || 0) - (a.weight || 0)
|
|
58
|
-
);
|
|
59
|
-
this.middlewares.set(hookPoint, updated);
|
|
60
|
-
|
|
61
|
-
this.bus.emit('system:middleware:changed', hookPoint);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
21
|
static getInstance(): SystemUIService {
|
|
65
22
|
if (!SystemUIService.instance) {
|
|
66
23
|
SystemUIService.instance = new SystemUIService();
|
|
@@ -68,92 +25,40 @@ export class SystemUIService implements ISystemUIService {
|
|
|
68
25
|
return SystemUIService.instance;
|
|
69
26
|
}
|
|
70
27
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
path: entry.path,
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
},
|
|
82
|
-
id,
|
|
83
|
-
10
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
this.registerSlot('route', buildEntrySlotCom(entry), id);
|
|
87
|
-
|
|
88
|
-
if (!entry.label) return;
|
|
28
|
+
registerSlot = baseService.registerSlot.bind(baseService);
|
|
29
|
+
registerMiddleware = baseService.registerMiddleware.bind(baseService);
|
|
30
|
+
getSlotEntries = baseService.getSlotEntries.bind(baseService);
|
|
31
|
+
getComponents = baseService.getComponents.bind(baseService);
|
|
32
|
+
subscribeSlotChange = baseService.subscribeSlotChange.bind(baseService);
|
|
33
|
+
subscribeMiddlewareChange = baseService.subscribeMiddlewareChange.bind(baseService);
|
|
34
|
+
runMiddlewares = baseService.runMiddlewares.bind(baseService);
|
|
89
35
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return [
|
|
94
|
-
...entries,
|
|
95
|
-
{
|
|
96
|
-
to: entry.path,
|
|
97
|
-
children: entry.label,
|
|
98
|
-
},
|
|
99
|
-
];
|
|
100
|
-
},
|
|
101
|
-
id,
|
|
102
|
-
10
|
|
103
|
-
);
|
|
36
|
+
registerPluginEntry: (entry: IPluginEntry, id: PluginID) => void = (entry, id) => {
|
|
37
|
+
this.pluginEntries.set(entry.path, { ...entry, pluginId: id });
|
|
38
|
+
this.entryBus.emit('pluginEntriesChanged', undefined);
|
|
104
39
|
};
|
|
105
40
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
pluginId: PluginID,
|
|
110
|
-
weight?: number
|
|
111
|
-
) => void = (slotName, component, pluginId, weight = 0) => {
|
|
112
|
-
const existing = this.slots.get(slotName) || [];
|
|
113
|
-
|
|
114
|
-
const newEntry: ISlotEntry = {
|
|
115
|
-
id: `${pluginId}-${component.name || 'comp'}`,
|
|
116
|
-
pluginId,
|
|
117
|
-
component,
|
|
118
|
-
weight,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// 插入并按权重排序(权重大的在前)
|
|
122
|
-
const updated = [...existing, newEntry].sort((a, b) => b.weight - a.weight);
|
|
123
|
-
this.slots.set(slotName, updated);
|
|
41
|
+
getPluginEntries = (): Array<IPluginEntry & { pluginId: PluginID }> => {
|
|
42
|
+
return Array.from(this.pluginEntries.values());
|
|
43
|
+
};
|
|
124
44
|
|
|
125
|
-
|
|
45
|
+
subscribePluginEntryChange = (listener: () => void): (() => void) => {
|
|
46
|
+
return this.entryBus.on('pluginEntriesChanged', listener);
|
|
126
47
|
};
|
|
127
48
|
|
|
128
|
-
unregisterAllByPluginId(pluginId: string) {
|
|
129
|
-
|
|
130
|
-
const filtered = entries.filter(entry => entry.pluginId !== pluginId);
|
|
131
|
-
this.slots.set(slotName, filtered);
|
|
132
|
-
});
|
|
49
|
+
unregisterAllByPluginId: (pluginId: string) => void = pluginId => {
|
|
50
|
+
baseService.unregisterAllByPluginId(pluginId);
|
|
133
51
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
52
|
+
let changed = false;
|
|
53
|
+
this.pluginEntries.forEach((entry, path) => {
|
|
54
|
+
if (entry.pluginId === pluginId) {
|
|
55
|
+
this.pluginEntries.delete(path);
|
|
56
|
+
changed = true;
|
|
57
|
+
}
|
|
138
58
|
});
|
|
139
59
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
getComponents(slotName: SystemSlotName): React.ComponentType<IComPropsRegisteredToSlot>[] {
|
|
144
|
-
return (this.slots.get(slotName) || []).map(entry => entry.component);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
subscribeMiddlewareChange(listener: (point: SystemDataHookPoint) => void) {
|
|
148
|
-
return this.bus.on('system:middleware:changed', listener);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async runMiddlewares<T>(point: SystemDataHookPoint, data: T): Promise<T> {
|
|
152
|
-
const fns = (this.middlewares.get(point) || []).map(entry => entry.fn);
|
|
153
|
-
let result = data;
|
|
154
|
-
for (const fn of fns) {
|
|
155
|
-
result = (await fn(result)) as T;
|
|
60
|
+
if (changed) {
|
|
61
|
+
this.entryBus.emit('pluginEntriesChanged', undefined);
|
|
156
62
|
}
|
|
157
|
-
|
|
158
|
-
}
|
|
63
|
+
};
|
|
159
64
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
|
|
3
|
+
import type { ISlotEntry } from '#/core/plugin-system/registry';
|
|
3
4
|
import { IPluginEntry, PluginID } from '#/types/plugin';
|
|
4
5
|
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
5
6
|
|
|
@@ -23,27 +24,24 @@ export interface IBaseUIService<T extends string, K extends string> {
|
|
|
23
24
|
pluginId: PluginID,
|
|
24
25
|
weight?: number
|
|
25
26
|
) => void;
|
|
27
|
+
|
|
28
|
+
unregisterAllByPluginId(pluginId: string): void;
|
|
29
|
+
|
|
30
|
+
getSlotEntries(slotName: T): ISlotEntry[];
|
|
31
|
+
|
|
32
|
+
getComponents(slotName: T): React.ComponentType<IComPropsRegisteredToSlot>[];
|
|
33
|
+
|
|
34
|
+
subscribeSlotChange(listener: () => void): () => void;
|
|
35
|
+
|
|
36
|
+
subscribeMiddlewareChange(listener: (point: K) => void): () => void;
|
|
37
|
+
|
|
38
|
+
runMiddlewares: <S>(point: K, data: S) => Promise<S>;
|
|
26
39
|
}
|
|
27
40
|
|
|
28
|
-
export type SystemSlotName = 'leftCol' | 'rightCol' | 'logo' | '
|
|
41
|
+
export type SystemSlotName = 'leftCol' | 'rightCol' | 'logo' | 'pageFooter' | 'nav-right';
|
|
29
42
|
|
|
30
|
-
export type SystemDataHookPoint =
|
|
31
|
-
| 'extendedRoutes'
|
|
32
|
-
| 'transformBreadcrumbPath'
|
|
33
|
-
| 'transformCoverEntry';
|
|
43
|
+
export type SystemDataHookPoint = 'transformBreadcrumbPath' | 'transformEntryLink';
|
|
34
44
|
|
|
35
45
|
export interface ISystemUIService extends IBaseUIService<SystemSlotName, SystemDataHookPoint> {
|
|
36
|
-
registerMiddleware: <S>(
|
|
37
|
-
hookPoint: SystemDataHookPoint,
|
|
38
|
-
fn: (data: S) => S | Promise<S>,
|
|
39
|
-
pluginId: PluginID,
|
|
40
|
-
weight?: number
|
|
41
|
-
) => void;
|
|
42
|
-
registerSlot: (
|
|
43
|
-
slotName: SystemSlotName,
|
|
44
|
-
component: React.ComponentType<IComPropsRegisteredToSlot>,
|
|
45
|
-
pluginId: PluginID,
|
|
46
|
-
weight?: number
|
|
47
|
-
) => void;
|
|
48
46
|
registerPluginEntry: (entry: IPluginEntry, id: PluginID) => void;
|
|
49
47
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { IMiddlewareEntry, ISlotEntry } from '#/core/plugin-system/registry';
|
|
4
|
+
import { createEventBus } from '#/core/utils/eventBus';
|
|
5
|
+
import type { PluginID } from '#/types/plugin';
|
|
6
|
+
import type { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
7
|
+
|
|
8
|
+
export interface IUIService<TSlot extends string, THook extends string> {
|
|
9
|
+
registerSlot(
|
|
10
|
+
slotName: TSlot,
|
|
11
|
+
component: React.ComponentType<IComPropsRegisteredToSlot>,
|
|
12
|
+
pluginId: PluginID,
|
|
13
|
+
weight?: number
|
|
14
|
+
): void;
|
|
15
|
+
|
|
16
|
+
registerMiddleware<T>(
|
|
17
|
+
hookPoint: THook,
|
|
18
|
+
fn: (data: T) => T | Promise<T>,
|
|
19
|
+
pluginId: PluginID,
|
|
20
|
+
weight?: number
|
|
21
|
+
): void;
|
|
22
|
+
|
|
23
|
+
unregisterAllByPluginId(pluginId: string): void;
|
|
24
|
+
|
|
25
|
+
getSlotEntries(slotName: TSlot): ISlotEntry[];
|
|
26
|
+
|
|
27
|
+
getComponents(slotName: TSlot): React.ComponentType<IComPropsRegisteredToSlot>[];
|
|
28
|
+
|
|
29
|
+
subscribeSlotChange(listener: () => void): () => void;
|
|
30
|
+
|
|
31
|
+
subscribeMiddlewareChange(listener: (point: THook) => void): () => void;
|
|
32
|
+
|
|
33
|
+
runMiddlewares<T>(point: THook, data: T): Promise<T>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function createUIService<TSlot extends string, THook extends string>(
|
|
37
|
+
_: string
|
|
38
|
+
): IUIService<TSlot, THook> {
|
|
39
|
+
const slots = new Map<TSlot, Array<ISlotEntry>>();
|
|
40
|
+
const middlewares = new Map<THook, Array<IMiddlewareEntry<unknown>>>();
|
|
41
|
+
const bus = createEventBus<{
|
|
42
|
+
slotsChanged: void;
|
|
43
|
+
middlewareChanged: THook;
|
|
44
|
+
}>();
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
registerSlot(slotName, component, pluginId, weight = 0) {
|
|
48
|
+
const existing = slots.get(slotName) || [];
|
|
49
|
+
const newEntry: ISlotEntry = {
|
|
50
|
+
id: `${pluginId}-${slotName}-${component.name || 'comp'}`,
|
|
51
|
+
pluginId,
|
|
52
|
+
component,
|
|
53
|
+
weight,
|
|
54
|
+
};
|
|
55
|
+
const updated = [...existing, newEntry].sort((a, b) => (b.weight || 0) - (a.weight || 0));
|
|
56
|
+
slots.set(slotName, updated);
|
|
57
|
+
bus.emit('slotsChanged', undefined);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
registerMiddleware(hookPoint, fn, pluginId, weight = 0) {
|
|
61
|
+
const existing = middlewares.get(hookPoint) || [];
|
|
62
|
+
const newEntry: IMiddlewareEntry<unknown> = {
|
|
63
|
+
id: `${pluginId}-${hookPoint}-middleware`,
|
|
64
|
+
pluginId,
|
|
65
|
+
fn: fn as (data: unknown) => unknown | Promise<unknown>,
|
|
66
|
+
weight,
|
|
67
|
+
};
|
|
68
|
+
const updated = [...existing, newEntry].sort((a, b) => (b.weight || 0) - (a.weight || 0));
|
|
69
|
+
middlewares.set(hookPoint, updated);
|
|
70
|
+
bus.emit('middlewareChanged', hookPoint);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
unregisterAllByPluginId(pluginId) {
|
|
74
|
+
let slotsChanged = false;
|
|
75
|
+
slots.forEach((entries, slotName) => {
|
|
76
|
+
const filtered = entries.filter(entry => entry.pluginId !== pluginId);
|
|
77
|
+
if (filtered.length !== entries.length) {
|
|
78
|
+
slots.set(slotName, filtered);
|
|
79
|
+
slotsChanged = true;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
middlewares.forEach((entries, point) => {
|
|
84
|
+
const filtered = entries.filter(entry => entry.pluginId !== pluginId);
|
|
85
|
+
if (filtered.length !== entries.length) {
|
|
86
|
+
middlewares.set(point, filtered);
|
|
87
|
+
bus.emit('middlewareChanged', point);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (slotsChanged) {
|
|
92
|
+
bus.emit('slotsChanged', undefined);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
getSlotEntries(slotName) {
|
|
97
|
+
return slots.get(slotName) || [];
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getComponents(slotName) {
|
|
101
|
+
return (slots.get(slotName) || []).map(entry => entry.component);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
subscribeSlotChange(listener) {
|
|
105
|
+
return bus.on('slotsChanged', listener as (data: unknown) => void);
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
subscribeMiddlewareChange(listener) {
|
|
109
|
+
return bus.on('middlewareChanged', listener as (data: unknown) => void);
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
async runMiddlewares(point, data) {
|
|
113
|
+
const fns = (middlewares.get(point) || []).map(entry => entry.fn);
|
|
114
|
+
let result: unknown = data;
|
|
115
|
+
for (const fn of fns) {
|
|
116
|
+
result = await fn(result);
|
|
117
|
+
}
|
|
118
|
+
return result as typeof data;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
4
|
+
|
|
5
|
+
import type { IUIService } from './createUIService';
|
|
6
|
+
|
|
7
|
+
export interface UseMiddlewareRunnerOptions<THook extends string> {
|
|
8
|
+
hookPoint: THook;
|
|
9
|
+
onMiddlewareChange?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseMiddlewareRunnerResult<T> {
|
|
13
|
+
loading: boolean;
|
|
14
|
+
error: Error | null;
|
|
15
|
+
run: (inputData: T) => Promise<T>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createSlotHook<TSlot extends string>(service: IUIService<TSlot, string>) {
|
|
19
|
+
return function useSlotComp(slotName: TSlot) {
|
|
20
|
+
const [components, setComponents] = useState<React.ComponentType<IComPropsRegisteredToSlot>[]>(
|
|
21
|
+
() => service.getComponents(slotName)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
setComponents(service.getComponents(slotName));
|
|
26
|
+
|
|
27
|
+
const unsubscribe = service.subscribeSlotChange(() => {
|
|
28
|
+
setComponents(service.getComponents(slotName));
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return () => {
|
|
32
|
+
unsubscribe();
|
|
33
|
+
};
|
|
34
|
+
}, [slotName]);
|
|
35
|
+
|
|
36
|
+
return components;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function createSlotComponent<TSlot extends string>(service: IUIService<TSlot, string>) {
|
|
41
|
+
return function Slot({
|
|
42
|
+
name,
|
|
43
|
+
data,
|
|
44
|
+
placeholder,
|
|
45
|
+
}: {
|
|
46
|
+
name: TSlot;
|
|
47
|
+
data?: unknown;
|
|
48
|
+
placeholder?: React.ReactNode;
|
|
49
|
+
}) {
|
|
50
|
+
const [entries, setEntries] = useState(() => service.getSlotEntries(name));
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
setEntries(service.getSlotEntries(name));
|
|
54
|
+
|
|
55
|
+
const unsubscribe = service.subscribeSlotChange(() => {
|
|
56
|
+
setEntries(service.getSlotEntries(name));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
unsubscribe();
|
|
61
|
+
};
|
|
62
|
+
}, [name]);
|
|
63
|
+
|
|
64
|
+
if (entries.length === 0) {
|
|
65
|
+
return <>{placeholder}</>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
{entries.map(({ id, component: Component }) => (
|
|
71
|
+
<Component key={id} data={data} />
|
|
72
|
+
))}
|
|
73
|
+
</>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createMiddlewareRunnerHook<THook extends string>(
|
|
79
|
+
service: IUIService<string, THook>
|
|
80
|
+
) {
|
|
81
|
+
return function useMiddlewareRunner<T>({
|
|
82
|
+
hookPoint,
|
|
83
|
+
onMiddlewareChange,
|
|
84
|
+
}: UseMiddlewareRunnerOptions<THook>): UseMiddlewareRunnerResult<T> {
|
|
85
|
+
const [loading, setLoading] = useState(false);
|
|
86
|
+
const [error, setError] = useState<Error | null>(null);
|
|
87
|
+
|
|
88
|
+
const run = useCallback(
|
|
89
|
+
async (inputData: T) => {
|
|
90
|
+
setLoading(true);
|
|
91
|
+
setError(null);
|
|
92
|
+
try {
|
|
93
|
+
const result = await service.runMiddlewares(hookPoint, inputData);
|
|
94
|
+
return result;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
97
|
+
setError(error);
|
|
98
|
+
throw error;
|
|
99
|
+
} finally {
|
|
100
|
+
setLoading(false);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
[hookPoint]
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
const unsubscribe = service.subscribeMiddlewareChange(hook => {
|
|
108
|
+
if (hook === hookPoint) {
|
|
109
|
+
onMiddlewareChange?.();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return () => {
|
|
114
|
+
unsubscribe();
|
|
115
|
+
};
|
|
116
|
+
}, [hookPoint, onMiddlewareChange]);
|
|
117
|
+
|
|
118
|
+
return { loading, error, run };
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function createMiddlewareTransformedDataHook<THook extends string>(
|
|
123
|
+
useMiddlewareRunner: <T>(opts: UseMiddlewareRunnerOptions<THook>) => UseMiddlewareRunnerResult<T>
|
|
124
|
+
) {
|
|
125
|
+
return function useMiddlewareTransformedData<T>(hookPoint: THook, defaultValue: T) {
|
|
126
|
+
const [result, setResult] = useState<T>(defaultValue);
|
|
127
|
+
|
|
128
|
+
const runRef = useRef<(input: T) => Promise<T>>(() => Promise.resolve(defaultValue));
|
|
129
|
+
|
|
130
|
+
const onMiddlewareChange = useCallback(() => {
|
|
131
|
+
runRef.current(defaultValue).then(setResult);
|
|
132
|
+
}, [defaultValue]);
|
|
133
|
+
|
|
134
|
+
const { run } = useMiddlewareRunner<T>({
|
|
135
|
+
hookPoint,
|
|
136
|
+
onMiddlewareChange,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
runRef.current = run;
|
|
141
|
+
}, [run]);
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
run(defaultValue).then(setResult);
|
|
145
|
+
}, [defaultValue, run]);
|
|
146
|
+
|
|
147
|
+
return result;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { createSlotComponent } from '#/core/shared-service/factory/createUIServiceReactKit';
|
|
4
|
+
|
|
5
|
+
import { BlogUIService } from '../services/BlogUIService';
|
|
4
6
|
import { BlogSlotName } from '../services/IBlogUIService';
|
|
5
7
|
|
|
6
8
|
export interface ISlotProps {
|
|
7
9
|
name: BlogSlotName;
|
|
8
10
|
data?: unknown;
|
|
9
|
-
|
|
10
11
|
placeholder?: React.ReactNode;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export const Slot
|
|
14
|
-
const components = useBlogSlotComp(name);
|
|
15
|
-
|
|
16
|
-
if (components.length === 0) {
|
|
17
|
-
return <>{placeholder}</>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<>
|
|
22
|
-
{components.map((Component, index) => (
|
|
23
|
-
<Component key={index} data={data} />
|
|
24
|
-
))}
|
|
25
|
-
</>
|
|
26
|
-
);
|
|
27
|
-
};
|
|
14
|
+
export const Slot = createSlotComponent<BlogSlotName>(BlogUIService.getInstance());
|
|
@@ -1,79 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createMiddlewareRunnerHook,
|
|
3
|
+
createMiddlewareTransformedDataHook,
|
|
4
|
+
} from '#/core/shared-service/factory/createUIServiceReactKit';
|
|
2
5
|
|
|
3
6
|
import { BlogUIService } from '../services/BlogUIService';
|
|
4
|
-
import { BlogDataHookPoint } from '../services/IBlogUIService';
|
|
5
7
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
error: Error | null;
|
|
14
|
-
run: (inputData: T) => Promise<T>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function useMiddlewareRunner<T>({
|
|
18
|
-
hookPoint,
|
|
19
|
-
onMiddlewareChange,
|
|
20
|
-
}: UseMiddlewareTransDataOptions): UseMiddlewareTransDataResult<T> {
|
|
21
|
-
const [loading, setLoading] = useState(false);
|
|
22
|
-
const [error, setError] = useState<Error | null>(null);
|
|
23
|
-
|
|
24
|
-
const run = useCallback(
|
|
25
|
-
async (inputData: T) => {
|
|
26
|
-
setLoading(true);
|
|
27
|
-
setError(null);
|
|
28
|
-
try {
|
|
29
|
-
const result = await BlogUIService.getInstance().runMiddlewares(hookPoint, inputData);
|
|
30
|
-
return result;
|
|
31
|
-
} catch (err) {
|
|
32
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
33
|
-
setError(error);
|
|
34
|
-
throw error;
|
|
35
|
-
} finally {
|
|
36
|
-
setLoading(false);
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
[hookPoint]
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
// 仅通知,不执行
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
const unsubscribe = BlogUIService.getInstance().subscribeMiddlewareChange(hook => {
|
|
45
|
-
if (hook === hookPoint) {
|
|
46
|
-
onMiddlewareChange?.();
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
return () => {
|
|
51
|
-
unsubscribe();
|
|
52
|
-
};
|
|
53
|
-
}, [hookPoint, onMiddlewareChange]);
|
|
54
|
-
|
|
55
|
-
return { loading, error, run };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const useMiddlewareTransformedData = <T>(hookPoint: BlogDataHookPoint, defaultValue: T) => {
|
|
59
|
-
const [result, setResult] = useState<T>(defaultValue);
|
|
60
|
-
|
|
61
|
-
const runRef = useRef<(input: T) => Promise<T>>(() => Promise.resolve(defaultValue));
|
|
62
|
-
|
|
63
|
-
const onMiddlewareChange = useCallback(() => {
|
|
64
|
-
runRef.current(defaultValue).then(setResult);
|
|
65
|
-
}, [defaultValue]);
|
|
66
|
-
|
|
67
|
-
const { run } = useMiddlewareRunner<T>({
|
|
68
|
-
hookPoint,
|
|
69
|
-
onMiddlewareChange,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
runRef.current = run;
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
run(defaultValue).then(setResult);
|
|
76
|
-
}, [defaultValue, run]);
|
|
77
|
-
|
|
78
|
-
return result;
|
|
79
|
-
};
|
|
8
|
+
export const useMiddlewareRunner = createMiddlewareRunnerHook(BlogUIService.getInstance());
|
|
9
|
+
export const useMiddlewareTransformedData =
|
|
10
|
+
createMiddlewareTransformedDataHook(useMiddlewareRunner);
|
|
11
|
+
export type {
|
|
12
|
+
UseMiddlewareRunnerOptions,
|
|
13
|
+
UseMiddlewareRunnerResult as UseMiddlewareTransformedDataResult,
|
|
14
|
+
} from '#/core/shared-service/factory/createUIServiceReactKit';
|
|
@@ -1,27 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createSlotHook } from '#/core/shared-service/factory/createUIServiceReactKit';
|
|
2
2
|
|
|
3
|
-
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
4
|
-
|
|
5
|
-
import { BlogSlotName } from '../services/IBlogUIService';
|
|
6
3
|
import { BlogUIService } from '../services/BlogUIService';
|
|
7
4
|
|
|
8
|
-
export const useBlogSlotComp = (
|
|
9
|
-
const [components, setComponents] = useState<React.ComponentType<IComPropsRegisteredToSlot>[]>(
|
|
10
|
-
() => BlogUIService.getInstance().getComponents(slotName)
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
// setComponents(BlogUIService.getInstance().getComponents(slotName));
|
|
15
|
-
|
|
16
|
-
const unsubscribe = BlogUIService.getInstance().subscribeSlotChange(() => {
|
|
17
|
-
const comps = BlogUIService.getInstance().getComponents(slotName);
|
|
18
|
-
setComponents(comps);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
return () => {
|
|
22
|
-
unsubscribe();
|
|
23
|
-
};
|
|
24
|
-
}, [slotName]);
|
|
25
|
-
|
|
26
|
-
return components;
|
|
27
|
-
};
|
|
5
|
+
export const useBlogSlotComp = createSlotHook(BlogUIService.getInstance());
|
|
@@ -15,6 +15,8 @@ export class BlogPlugin extends BBPlugin {
|
|
|
15
15
|
|
|
16
16
|
private _serviceRegistry?: ServiceRegistry;
|
|
17
17
|
|
|
18
|
+
private _unsubscribePluginUninstall?: () => void;
|
|
19
|
+
|
|
18
20
|
override onInstall = async (ctx: IHostContext) => {
|
|
19
21
|
ctx.service.register('blog:uiService', BlogUIService.getInstance());
|
|
20
22
|
|
|
@@ -28,7 +30,9 @@ export class BlogPlugin extends BBPlugin {
|
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
coreService.subscribePluginUninstall(
|
|
33
|
+
this._unsubscribePluginUninstall = coreService.subscribePluginUninstall(
|
|
34
|
+
this.handlePluginUninstall
|
|
35
|
+
);
|
|
32
36
|
|
|
33
37
|
systemUIService?.registerPluginEntry(
|
|
34
38
|
{
|
|
@@ -50,6 +54,7 @@ export class BlogPlugin extends BBPlugin {
|
|
|
50
54
|
override onDestroy?: (() => void) | undefined = () => {
|
|
51
55
|
BlogUIService.getInstance().unregisterAllByPluginId(this.id);
|
|
52
56
|
this._serviceRegistry?.unregister('blog:uiService');
|
|
57
|
+
this._unsubscribePluginUninstall?.();
|
|
53
58
|
};
|
|
54
59
|
|
|
55
60
|
private handlePluginUninstall = (payload: PluginID) => {
|