@oinone/kunlun-vue-widget 6.4.9 → 7.2.0
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/dist/oinone-kunlun-vue-widget.esm.js +1 -16
- package/dist/types/index.d.ts +1 -1
- package/dist/types/src/basic/AsyncVueWidget.d.ts +7 -7
- package/dist/types/src/basic/VueFragment.vue.d.ts +2 -2
- package/dist/types/src/basic/VueWidget.d.ts +339 -331
- package/dist/types/src/basic/Widget.d.ts +260 -257
- package/dist/types/src/basic/index.d.ts +3 -3
- package/dist/types/src/data/ActiveRecordsWidget.d.ts +271 -261
- package/dist/types/src/data/PathWidget.d.ts +34 -34
- package/dist/types/src/data/index.d.ts +2 -2
- package/dist/types/src/dsl/DslDefinitionWidget.d.ts +66 -68
- package/dist/types/src/dsl/DslNodeWidget.d.ts +42 -42
- package/dist/types/src/dsl/DslRenderWidget.d.ts +47 -44
- package/dist/types/src/dsl/index.d.ts +3 -3
- package/dist/types/src/feature/index.d.ts +1 -1
- package/dist/types/src/feature/invisible-supported.d.ts +11 -11
- package/dist/types/src/hooks/all-mounted.d.ts +20 -20
- package/dist/types/src/hooks/index.d.ts +1 -1
- package/dist/types/src/index.d.ts +10 -10
- package/dist/types/src/state/context.d.ts +41 -41
- package/dist/types/src/state/global.d.ts +3 -4
- package/dist/types/src/state/index.d.ts +3 -3
- package/dist/types/src/state/method/action.d.ts +18 -18
- package/dist/types/src/state/method/field.d.ts +3 -3
- package/dist/types/src/state/method/index.d.ts +2 -2
- package/dist/types/src/state/typing.d.ts +112 -105
- package/dist/types/src/state/use-state.d.ts +15 -16
- package/dist/types/src/state/view.d.ts +5 -5
- package/dist/types/src/token/index.d.ts +2 -2
- package/dist/types/src/typing/WidgetTagContext.d.ts +39 -39
- package/dist/types/src/typing/WidgetTagProps.d.ts +23 -23
- package/dist/types/src/typing/index.d.ts +3 -3
- package/dist/types/src/typing/typing.d.ts +7 -7
- package/dist/types/src/util/dsl-render.d.ts +106 -106
- package/dist/types/src/util/index.d.ts +4 -4
- package/dist/types/src/util/install.d.ts +4 -4
- package/dist/types/src/util/render.d.ts +7 -7
- package/dist/types/src/util/widget-manager.d.ts +4 -4
- package/dist/types/src/view/index.d.ts +161 -161
- package/package.json +29 -18
- package/src/basic/AsyncVueWidget.ts +2 -2
- package/src/basic/VueWidget.ts +67 -31
- package/src/basic/Widget.ts +11 -9
- package/src/basic/__tests__/Widget.spec.ts +82 -0
- package/src/data/ActiveRecordsWidget.ts +51 -21
- package/src/data/PathWidget.ts +1 -1
- package/src/dsl/DslDefinitionWidget.ts +10 -33
- package/src/dsl/DslNodeWidget.ts +3 -3
- package/src/dsl/DslRenderWidget.ts +32 -3
- package/src/feature/__tests__/invisible-supported.spec.ts +31 -0
- package/src/hooks/__tests__/all-mounted.spec.ts +41 -0
- package/src/hooks/all-mounted.ts +1 -1
- package/src/shim-translate.d.ts +5 -2
- package/src/state/__tests__/state.spec.ts +114 -0
- package/src/state/context.ts +6 -2
- package/src/state/global.ts +16 -5
- package/src/state/method/action.ts +7 -2
- package/src/state/method/field.ts +1 -1
- package/src/state/typing.ts +10 -0
- package/src/state/use-state.ts +2 -2
- package/src/state/view.ts +3 -3
- package/src/token/index.ts +1 -1
- package/src/typing/WidgetTagContext.ts +3 -3
- package/src/typing/WidgetTagProps.ts +2 -2
- package/src/util/__tests__/dsl-render.spec.ts +112 -0
- package/src/util/__tests__/render.spec.ts +69 -0
- package/src/util/__tests__/widget-manager.spec.ts +27 -0
- package/src/util/dsl-render.ts +6 -7
- package/src/util/install.ts +1 -1
- package/src/util/render.ts +3 -7
- package/src/view/index.ts +15 -8
- package/rollup.config.js +0 -22
package/src/basic/Widget.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IWidget, WidgetConstructor, WidgetProps } from '@oinone/kunlun-engine';
|
|
1
|
+
import type { IWidget, WidgetConstructor, WidgetProps } from '@oinone/kunlun-engine';
|
|
2
2
|
import { instantiate } from '@oinone/kunlun-shared';
|
|
3
3
|
import { BehaviorSubject, Subject, Subscription } from '@oinone/kunlun-state';
|
|
4
4
|
import { InnerWidgetType } from '../typing/typing';
|
|
@@ -32,6 +32,8 @@ export interface WidgetBehaviorSubjection<T> extends BaseWidgetSubjection<T> {
|
|
|
32
32
|
export type watcher<T> = { path: string; handler: (newVal: T, oldVal: T) => void; options?: { deep?: boolean } };
|
|
33
33
|
export type HANDLE = string;
|
|
34
34
|
|
|
35
|
+
type InjectionType = { name: typeof Widget; list: Map<string | Symbol, string> };
|
|
36
|
+
|
|
35
37
|
export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknown> implements IWidget<Props> {
|
|
36
38
|
private static widgetCount = 0;
|
|
37
39
|
|
|
@@ -223,10 +225,10 @@ export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknow
|
|
|
223
225
|
*/
|
|
224
226
|
protected static Inject(injectName?: string | Symbol) {
|
|
225
227
|
return <T extends Widget>(target: T, name: string) => {
|
|
226
|
-
let injection
|
|
228
|
+
let injection = (Reflect.get(target, 'injection') || {
|
|
227
229
|
name: this,
|
|
228
230
|
list: new Map()
|
|
229
|
-
};
|
|
231
|
+
}) as InjectionType;
|
|
230
232
|
if (injection.name !== target.constructor) {
|
|
231
233
|
const oldInjection = injection;
|
|
232
234
|
injection = { name: target.constructor as typeof Widget, list: new Map() };
|
|
@@ -260,10 +262,10 @@ export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknow
|
|
|
260
262
|
*/
|
|
261
263
|
protected static Provide(provideName?: string | Symbol) {
|
|
262
264
|
return <T extends Widget>(target: T, name: string) => {
|
|
263
|
-
let injection
|
|
265
|
+
let injection = (Reflect.get(target, 'provider') || {
|
|
264
266
|
name: this,
|
|
265
267
|
list: new Map()
|
|
266
|
-
};
|
|
268
|
+
}) as InjectionType;
|
|
267
269
|
if (injection.name !== (target.constructor as typeof Widget)) {
|
|
268
270
|
const old = injection;
|
|
269
271
|
injection = { name: target.constructor as typeof Widget, list: new Map() };
|
|
@@ -319,7 +321,7 @@ export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknow
|
|
|
319
321
|
}
|
|
320
322
|
|
|
321
323
|
const props = {};
|
|
322
|
-
const injection = (Reflect.get(this, 'injection') || { list: new Map() })
|
|
324
|
+
const injection = ((Reflect.get(this, 'injection') || { list: new Map() }) as InjectionType).list;
|
|
323
325
|
const attrs = this.getAttributes();
|
|
324
326
|
|
|
325
327
|
if (injection) {
|
|
@@ -378,7 +380,7 @@ export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknow
|
|
|
378
380
|
* 包装发布者事件
|
|
379
381
|
* 如果启动了作用域检查,那么发布的时候会携带发布者的widget实例
|
|
380
382
|
**/
|
|
381
|
-
private wrapSubjectWithScope(subject: AnySubject
|
|
383
|
+
private wrapSubjectWithScope(subject: AnySubject<any>, scope?: WidgetTypeKey): AnySubject {
|
|
382
384
|
if (!scope) {
|
|
383
385
|
return subject;
|
|
384
386
|
}
|
|
@@ -763,7 +765,7 @@ export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknow
|
|
|
763
765
|
}
|
|
764
766
|
|
|
765
767
|
private releaseInjection() {
|
|
766
|
-
const injection
|
|
768
|
+
const injection = Reflect.get(this, 'injection') as InjectionType;
|
|
767
769
|
if (injection) {
|
|
768
770
|
injection.list.forEach((name) => {
|
|
769
771
|
const widget = this.getSelf()!;
|
|
@@ -778,7 +780,7 @@ export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknow
|
|
|
778
780
|
}
|
|
779
781
|
|
|
780
782
|
public getComputeHandler(name: string) {
|
|
781
|
-
return Reflect.get(this, `$compute$${name}`);
|
|
783
|
+
return Reflect.get(this, `$compute$${name}`) as { get: Function; set: Function };
|
|
782
784
|
}
|
|
783
785
|
|
|
784
786
|
protected getProps() {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Widget } from '../Widget';
|
|
2
|
+
import type { WidgetBehaviorSubjection } from '../Widget';
|
|
3
|
+
|
|
4
|
+
class TestWidget extends Widget<{ value: number }, null> {
|
|
5
|
+
@Widget.Reactive({ displayName: 'displayValue' })
|
|
6
|
+
public value = 0;
|
|
7
|
+
|
|
8
|
+
@Widget.Method('increment')
|
|
9
|
+
public increment() {
|
|
10
|
+
this.value += 1;
|
|
11
|
+
return this.value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Widget.Watch('displayValue')
|
|
15
|
+
public onValueChange() {}
|
|
16
|
+
|
|
17
|
+
public render() {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const behaviorIdentifier = Symbol('behavior-sub-context');
|
|
23
|
+
|
|
24
|
+
class BehaviorWidget extends Widget<{}, null> {
|
|
25
|
+
@Widget.BehaviorSubContext(behaviorIdentifier)
|
|
26
|
+
public channel!: WidgetBehaviorSubjection<{ value: string }>;
|
|
27
|
+
|
|
28
|
+
public render() {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('Widget 基类', () => {
|
|
34
|
+
it('Reactive/Method 装饰器应注册属性元数据', () => {
|
|
35
|
+
const widget = new TestWidget().initialize({ value: 1 } as any) as TestWidget;
|
|
36
|
+
const attrs = widget.getAttributes();
|
|
37
|
+
const props = (widget as any).getProps();
|
|
38
|
+
|
|
39
|
+
expect(attrs.get('displayValue')).toBe('value');
|
|
40
|
+
expect(props).toContain('displayValue');
|
|
41
|
+
|
|
42
|
+
const handle = widget.getHandle();
|
|
43
|
+
const selected = Widget.select<TestWidget>(handle);
|
|
44
|
+
expect(selected).toBe(widget);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('Watch 装饰器应注册监听配置', () => {
|
|
48
|
+
const widget = new TestWidget().initialize({ value: 1 } as any) as TestWidget;
|
|
49
|
+
const watchers = widget.getWatchers();
|
|
50
|
+
|
|
51
|
+
expect(watchers.length).toBeGreaterThan(0);
|
|
52
|
+
expect(watchers.some((w) => w.path === 'displayValue')).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('dispose 应从全局注册表中移除实例', () => {
|
|
56
|
+
const widget = new TestWidget().initialize({ value: 1 } as any) as TestWidget;
|
|
57
|
+
const handle = widget.getHandle();
|
|
58
|
+
|
|
59
|
+
expect(Widget.select(handle)).toBe(widget);
|
|
60
|
+
|
|
61
|
+
widget.dispose();
|
|
62
|
+
|
|
63
|
+
expect(Widget.select(handle)).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('BehaviorSubContext 应支持组件间通信', () => {
|
|
67
|
+
const publisher = new BehaviorWidget().initialize() as BehaviorWidget;
|
|
68
|
+
const subscriber = new BehaviorWidget().initialize() as BehaviorWidget;
|
|
69
|
+
|
|
70
|
+
const received: string[] = [];
|
|
71
|
+
|
|
72
|
+
subscriber.channel.subscribe((data) => {
|
|
73
|
+
if (data) {
|
|
74
|
+
received.push(data.value);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
publisher.channel.subject.next({ value: 'hello' });
|
|
79
|
+
|
|
80
|
+
expect(received).toContain('hello');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ActiveRecord,
|
|
3
|
-
ActiveRecords,
|
|
2
|
+
type ActiveRecord,
|
|
3
|
+
type ActiveRecords,
|
|
4
4
|
ActiveRecordsOperator,
|
|
5
|
-
DeleteActiveRecordsByEntityFunction,
|
|
6
|
-
DeleteActiveRecordsByEntityPredict,
|
|
7
|
-
DeleteActiveRecordsFunction,
|
|
8
|
-
FlushActiveRecordsFunction,
|
|
9
|
-
PushActiveRecordsFunction,
|
|
10
|
-
PushActiveRecordsPredict,
|
|
11
|
-
ReloadActiveRecordsFunction,
|
|
12
|
-
RuntimeRelationField,
|
|
5
|
+
type DeleteActiveRecordsByEntityFunction,
|
|
6
|
+
type DeleteActiveRecordsByEntityPredict,
|
|
7
|
+
type DeleteActiveRecordsFunction,
|
|
8
|
+
type FlushActiveRecordsFunction,
|
|
9
|
+
type PushActiveRecordsFunction,
|
|
10
|
+
type PushActiveRecordsPredict,
|
|
11
|
+
type ReloadActiveRecordsFunction,
|
|
12
|
+
type RuntimeRelationField,
|
|
13
13
|
SubmitCacheManager,
|
|
14
|
-
UpdateActiveRecordsByEntityFunction,
|
|
15
|
-
UpdateActiveRecordsByEntityPredict,
|
|
16
|
-
UpdateActiveRecordsFunction,
|
|
17
|
-
UpdateEntity
|
|
14
|
+
type UpdateActiveRecordsByEntityFunction,
|
|
15
|
+
type UpdateActiveRecordsByEntityPredict,
|
|
16
|
+
type UpdateActiveRecordsFunction,
|
|
17
|
+
type UpdateEntity
|
|
18
18
|
} from '@oinone/kunlun-engine';
|
|
19
19
|
import { Widget } from '../basic';
|
|
20
|
-
import { OioAnyViewState, useOioState } from '../state';
|
|
21
|
-
import { PathWidget, PathWidgetProps } from './PathWidget';
|
|
20
|
+
import { type OioAnyViewState, OioGlobalState, useOioState } from '../state';
|
|
21
|
+
import { PathWidget, type PathWidgetProps } from './PathWidget';
|
|
22
22
|
|
|
23
23
|
export interface ActiveRecordsWidgetProps extends PathWidgetProps {
|
|
24
24
|
dataSource?: ActiveRecords | null;
|
|
25
25
|
activeRecords?: ActiveRecords;
|
|
26
|
+
isInitViewState?: boolean;
|
|
27
|
+
viewState?: OioAnyViewState;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -31,6 +33,22 @@ export interface ActiveRecordsWidgetProps extends PathWidgetProps {
|
|
|
31
33
|
export class ActiveRecordsWidget<
|
|
32
34
|
Props extends ActiveRecordsWidgetProps = ActiveRecordsWidgetProps
|
|
33
35
|
> extends PathWidget<Props> {
|
|
36
|
+
/**
|
|
37
|
+
* 全局状态,在 beforeMounted 后可获取到有效值
|
|
38
|
+
* @protected
|
|
39
|
+
*/
|
|
40
|
+
protected globalState: OioGlobalState | undefined;
|
|
41
|
+
|
|
42
|
+
public getGlobalState(): OioGlobalState | undefined {
|
|
43
|
+
return this.globalState;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public setGlobalState(state: OioGlobalState) {
|
|
47
|
+
this.globalState = state;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected isInitViewState?: boolean;
|
|
51
|
+
|
|
34
52
|
/**
|
|
35
53
|
* 视图级别状态, 在 beforeMounted 后可获取到有效值
|
|
36
54
|
* @protected
|
|
@@ -47,9 +65,13 @@ export class ActiveRecordsWidget<
|
|
|
47
65
|
|
|
48
66
|
public initialize(props: Props) {
|
|
49
67
|
super.initialize(props);
|
|
50
|
-
const { dataSource, activeRecords } = props;
|
|
68
|
+
const { dataSource, activeRecords, viewState } = props;
|
|
51
69
|
this.setCurrentDataSource(dataSource);
|
|
52
70
|
this.setCurrentActiveRecords(activeRecords);
|
|
71
|
+
if (viewState) {
|
|
72
|
+
this.isInitViewState = props.isInitViewState ?? true;
|
|
73
|
+
this.setViewState(viewState);
|
|
74
|
+
}
|
|
53
75
|
return this;
|
|
54
76
|
}
|
|
55
77
|
|
|
@@ -587,8 +609,16 @@ export class ActiveRecordsWidget<
|
|
|
587
609
|
protected $$beforeMount() {
|
|
588
610
|
super.$$beforeMount();
|
|
589
611
|
let isInitStatePosition = false;
|
|
590
|
-
if (
|
|
591
|
-
this.
|
|
612
|
+
if (this.viewState) {
|
|
613
|
+
if (this.isInitViewState) {
|
|
614
|
+
isInitStatePosition = true;
|
|
615
|
+
this.$$initViewStatePosition(this.viewState);
|
|
616
|
+
this.$$initViewState(this.viewState);
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
const { globalState, viewState } = useOioState();
|
|
620
|
+
this.globalState = globalState;
|
|
621
|
+
this.viewState = viewState;
|
|
592
622
|
if (this.viewState) {
|
|
593
623
|
isInitStatePosition = true;
|
|
594
624
|
this.$$initViewStatePosition(this.viewState);
|
|
@@ -600,8 +630,8 @@ export class ActiveRecordsWidget<
|
|
|
600
630
|
}
|
|
601
631
|
}
|
|
602
632
|
|
|
603
|
-
protected $$
|
|
604
|
-
super.$$
|
|
633
|
+
protected $$mountedAfterProperties() {
|
|
634
|
+
super.$$mountedAfterProperties();
|
|
605
635
|
if (this.viewState) {
|
|
606
636
|
this.$$clearViewStatePosition(this.viewState);
|
|
607
637
|
this.$$clearViewState(this.viewState);
|
package/src/data/PathWidget.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isNil } from 'lodash-es';
|
|
2
2
|
import { Widget } from '../basic';
|
|
3
|
-
import { DslDefinitionWidgetProps, DslDefinitionWidget } from '../dsl';
|
|
3
|
+
import { type DslDefinitionWidgetProps, DslDefinitionWidget } from '../dsl';
|
|
4
4
|
|
|
5
5
|
export interface PathWidgetProps extends DslDefinitionWidgetProps {
|
|
6
6
|
path?: string;
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import { getMergeConfig } from '@oinone/kunlun-config';
|
|
2
1
|
import {
|
|
3
|
-
ComputeContext,
|
|
2
|
+
type ComputeContext,
|
|
4
3
|
ComputeContextManager,
|
|
5
4
|
ROOT_HANDLE,
|
|
6
|
-
RuntimeContext,
|
|
5
|
+
type RuntimeContext,
|
|
7
6
|
RuntimeContextManager,
|
|
8
|
-
RuntimeModelField
|
|
7
|
+
type RuntimeModelField
|
|
9
8
|
} from '@oinone/kunlun-engine';
|
|
10
|
-
import { BooleanHelper, CSSClass, CSSStyle } from '@oinone/kunlun-shared';
|
|
9
|
+
import { BooleanHelper, type CSSClass, type CSSStyle } from '@oinone/kunlun-shared';
|
|
11
10
|
import { StyleHelper } from '@oinone/kunlun-vue-ui-common';
|
|
12
11
|
import { isNil } from 'lodash-es';
|
|
13
12
|
import { Widget } from '../basic';
|
|
14
|
-
import { InvisibleSupported, isAllInvisible } from '../feature';
|
|
15
|
-
import { DslRenderWidget, DslRenderWidgetProps } from './DslRenderWidget';
|
|
13
|
+
import { type InvisibleSupported, isAllInvisible } from '../feature';
|
|
14
|
+
import { DslRenderWidget, type DslRenderWidgetProps } from './DslRenderWidget';
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* dsl组件属性
|
|
@@ -183,7 +182,7 @@ export class DslDefinitionWidget<Props extends DslDefinitionWidgetProps = DslDef
|
|
|
183
182
|
|
|
184
183
|
public get rootViewRuntimeContext(): { runtimeContext: RuntimeContext; fields: RuntimeModelField[] } {
|
|
185
184
|
const fields: RuntimeModelField[] = [];
|
|
186
|
-
let targetRuntimeContext: RuntimeContext = this.rootRuntimeContext;
|
|
185
|
+
let targetRuntimeContext: RuntimeContext | undefined = this.rootRuntimeContext;
|
|
187
186
|
let field = targetRuntimeContext?.parentContext?.field;
|
|
188
187
|
while (field && targetRuntimeContext) {
|
|
189
188
|
fields.push(field);
|
|
@@ -204,37 +203,15 @@ export class DslDefinitionWidget<Props extends DslDefinitionWidgetProps = DslDef
|
|
|
204
203
|
field = parentRuntimeContext.field;
|
|
205
204
|
targetRuntimeContext = nextTargetRuntimeContext;
|
|
206
205
|
}
|
|
206
|
+
if (!targetRuntimeContext) {
|
|
207
|
+
throw new Error('Invalid target runtime context.');
|
|
208
|
+
}
|
|
207
209
|
return {
|
|
208
210
|
runtimeContext: targetRuntimeContext,
|
|
209
211
|
fields
|
|
210
212
|
};
|
|
211
213
|
}
|
|
212
214
|
|
|
213
|
-
protected cacheConfigProxy;
|
|
214
|
-
|
|
215
|
-
protected getMergeConfig(...keys: string[]): Record<string, any> {
|
|
216
|
-
// dsl
|
|
217
|
-
// appConfig
|
|
218
|
-
// themeConfig
|
|
219
|
-
// runtime config ConfigHelper
|
|
220
|
-
if (this.cacheConfigProxy) {
|
|
221
|
-
return this.cacheConfigProxy;
|
|
222
|
-
}
|
|
223
|
-
const result = getMergeConfig(keys, {
|
|
224
|
-
defaultValue: undefined
|
|
225
|
-
});
|
|
226
|
-
this.cacheConfigProxy = new Proxy(this.getDsl(), {
|
|
227
|
-
get(target, prop) {
|
|
228
|
-
if (prop in target) {
|
|
229
|
-
return target[prop as keyof typeof target];
|
|
230
|
-
}
|
|
231
|
-
return result[prop as keyof typeof result];
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
return this.cacheConfigProxy;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
215
|
protected invisibleProcess(invisible: boolean | string) {
|
|
239
216
|
return BooleanHelper.toBoolean(invisible);
|
|
240
217
|
}
|
package/src/dsl/DslNodeWidget.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DslDefinition, XMLTemplateParser } from '@oinone/kunlun-dsl';
|
|
2
|
-
import { DslProps, RuntimeContext, RuntimeContextManager } from '@oinone/kunlun-engine';
|
|
3
|
-
import { IDslNode } from '@oinone/kunlun-meta';
|
|
1
|
+
import { type DslDefinition, XMLTemplateParser } from '@oinone/kunlun-dsl';
|
|
2
|
+
import { type DslProps, type RuntimeContext, RuntimeContextManager } from '@oinone/kunlun-engine';
|
|
3
|
+
import type { IDslNode } from '@oinone/kunlun-meta';
|
|
4
4
|
import { isNil } from 'lodash-es';
|
|
5
5
|
import { VueWidget, Widget } from '../basic';
|
|
6
6
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { getMergeConfig } from '@oinone/kunlun-config';
|
|
2
|
+
import { type DslDefinition, type DslSlots, DslSlotUtils, UnknownDslDefinition } from '@oinone/kunlun-dsl';
|
|
3
|
+
import type { WidgetProps } from '@oinone/kunlun-engine';
|
|
4
|
+
import type { Slots, VNode } from 'vue';
|
|
4
5
|
import { VueWidget, Widget } from '../basic';
|
|
5
6
|
import { DslRender } from '../util';
|
|
6
7
|
|
|
@@ -40,6 +41,8 @@ export class DslRenderWidget<Props extends DslRenderWidgetProps = DslRenderWidge
|
|
|
40
41
|
@Widget.Reactive()
|
|
41
42
|
protected slotName: string | undefined;
|
|
42
43
|
|
|
44
|
+
protected renderProps: Props | undefined;
|
|
45
|
+
|
|
43
46
|
protected supportedSlotNames!: string[];
|
|
44
47
|
|
|
45
48
|
protected dslSlots: DslSlots | undefined;
|
|
@@ -48,6 +51,7 @@ export class DslRenderWidget<Props extends DslRenderWidgetProps = DslRenderWidge
|
|
|
48
51
|
|
|
49
52
|
public initialize(props: Props) {
|
|
50
53
|
super.initialize(props);
|
|
54
|
+
this.renderProps = props;
|
|
51
55
|
this.internal = props.internal || false;
|
|
52
56
|
this.template = props.template;
|
|
53
57
|
this.slotName = props.slotName;
|
|
@@ -62,6 +66,31 @@ export class DslRenderWidget<Props extends DslRenderWidgetProps = DslRenderWidge
|
|
|
62
66
|
return this.template || UnknownDslDefinition;
|
|
63
67
|
}
|
|
64
68
|
|
|
69
|
+
protected cacheConfigProxy;
|
|
70
|
+
|
|
71
|
+
protected getMergeConfig(...keys: string[]): Record<string, any> {
|
|
72
|
+
// dsl
|
|
73
|
+
// appConfig
|
|
74
|
+
// themeConfig
|
|
75
|
+
// runtime config ConfigHelper
|
|
76
|
+
if (this.cacheConfigProxy) {
|
|
77
|
+
return this.cacheConfigProxy;
|
|
78
|
+
}
|
|
79
|
+
const result = getMergeConfig(keys, {
|
|
80
|
+
defaultValue: undefined
|
|
81
|
+
});
|
|
82
|
+
this.cacheConfigProxy = new Proxy(this.getDsl(), {
|
|
83
|
+
get(target, prop) {
|
|
84
|
+
if (prop in target) {
|
|
85
|
+
return target[prop as keyof typeof target];
|
|
86
|
+
}
|
|
87
|
+
return result[prop as keyof typeof result];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return this.cacheConfigProxy;
|
|
92
|
+
}
|
|
93
|
+
|
|
65
94
|
public getSlotName() {
|
|
66
95
|
return this.slotName;
|
|
67
96
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { executeInvisible, isAllInvisible, type InvisibleSupported } from '../invisible-supported';
|
|
2
|
+
|
|
3
|
+
describe('invisible-supported', () => {
|
|
4
|
+
it('executeInvisible: 不传或为 undefined 时返回 false', () => {
|
|
5
|
+
expect(executeInvisible(undefined)).toBe(false);
|
|
6
|
+
expect(executeInvisible({ invisible: undefined })).toBe(false);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('executeInvisible: 布尔值时直接返回布尔值', () => {
|
|
10
|
+
expect(executeInvisible({ invisible: true })).toBe(true);
|
|
11
|
+
expect(executeInvisible({ invisible: false })).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('executeInvisible: 函数时执行并返回结果', () => {
|
|
15
|
+
const supported: InvisibleSupported = {
|
|
16
|
+
invisible: () => true
|
|
17
|
+
};
|
|
18
|
+
expect(executeInvisible(supported)).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('isAllInvisible: 空数组或 undefined 返回 true, 否则需全部为 invisible', () => {
|
|
22
|
+
expect(isAllInvisible(undefined)).toBe(true);
|
|
23
|
+
expect(isAllInvisible([])).toBe(true);
|
|
24
|
+
expect(
|
|
25
|
+
isAllInvisible([{ invisible: true } as InvisibleSupported, { invisible: () => true } as InvisibleSupported])
|
|
26
|
+
).toBe(true);
|
|
27
|
+
expect(
|
|
28
|
+
isAllInvisible([{ invisible: true } as InvisibleSupported, { invisible: false } as InvisibleSupported])
|
|
29
|
+
).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { defineComponent, h, nextTick } from 'vue';
|
|
3
|
+
import { onAllMounted, reportAllMounted } from '../all-mounted';
|
|
4
|
+
|
|
5
|
+
describe('onAllMounted & reportAllMounted', () => {
|
|
6
|
+
it('不传回调时应打印警告且不抛错', () => {
|
|
7
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
8
|
+
// @ts-expect-error
|
|
9
|
+
onAllMounted(undefined);
|
|
10
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
11
|
+
warnSpy.mockRestore();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('所有子组件挂载后应触发 allMounted 回调', async () => {
|
|
15
|
+
const allMounted = jest.fn();
|
|
16
|
+
const allMountedUpdate = jest.fn();
|
|
17
|
+
|
|
18
|
+
const Parent = defineComponent({
|
|
19
|
+
setup() {
|
|
20
|
+
onAllMounted({ allMounted, allMountedUpdate });
|
|
21
|
+
return () => h('div', [h(Child), h(Child)]);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const Child = defineComponent({
|
|
26
|
+
setup() {
|
|
27
|
+
reportAllMounted();
|
|
28
|
+
return () => h('div');
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const wrapper = mount(Parent);
|
|
33
|
+
|
|
34
|
+
await nextTick();
|
|
35
|
+
expect(allMounted).toHaveBeenCalledTimes(1);
|
|
36
|
+
|
|
37
|
+
wrapper.unmount();
|
|
38
|
+
await nextTick();
|
|
39
|
+
expect(allMountedUpdate).toHaveBeenCalledTimes(0);
|
|
40
|
+
});
|
|
41
|
+
});
|
package/src/hooks/all-mounted.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isFunction, isNil } from 'lodash-es';
|
|
2
2
|
|
|
3
|
-
import { inject, InjectionKey, onBeforeMount, onMounted, onUnmounted, provide } from 'vue';
|
|
3
|
+
import { inject, type InjectionKey, onBeforeMount, onMounted, onUnmounted, provide } from 'vue';
|
|
4
4
|
|
|
5
5
|
interface AllMountedContext {
|
|
6
6
|
reportBeforeMount: (key: string) => void;
|
package/src/shim-translate.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export {};
|
|
2
2
|
|
|
3
|
-
declare module '
|
|
3
|
+
declare module 'vue' {
|
|
4
4
|
interface ComponentCustomProperties {
|
|
5
|
-
$translate<T extends string | null | undefined = string | null | undefined>(
|
|
5
|
+
$translate<T extends string | null | undefined = string | null | undefined>(
|
|
6
|
+
text: T,
|
|
7
|
+
context?: Record<string, unknown>
|
|
8
|
+
): T;
|
|
6
9
|
}
|
|
7
10
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { computed, createApp, defineComponent, h } from 'vue';
|
|
2
|
+
import { ViewType } from '@oinone/kunlun-meta';
|
|
3
|
+
import { useProviderMetaContext, useInjectMetaContext, defaultMetaContext } from '../context';
|
|
4
|
+
import { clearViewState, createViewState, getViewState, setViewState } from '../view';
|
|
5
|
+
import { globalState } from '../global';
|
|
6
|
+
import { useOioState } from '../use-state';
|
|
7
|
+
import { createActionBarState, getActionBarState, popAction, pushAction } from '../method/action';
|
|
8
|
+
import { popField, pushField } from '../method/field';
|
|
9
|
+
|
|
10
|
+
describe('state/context', () => {
|
|
11
|
+
it('useProviderMetaContext/ useInjectMetaContext 应合并默认值和传入状态', () => {
|
|
12
|
+
let ctx: ReturnType<typeof useInjectMetaContext> | undefined;
|
|
13
|
+
|
|
14
|
+
const App = defineComponent({
|
|
15
|
+
setup() {
|
|
16
|
+
useProviderMetaContext({});
|
|
17
|
+
return () =>
|
|
18
|
+
h(
|
|
19
|
+
defineComponent({
|
|
20
|
+
setup() {
|
|
21
|
+
ctx = useInjectMetaContext();
|
|
22
|
+
return () => null;
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const app = createApp(App);
|
|
30
|
+
const container = document.createElement('div');
|
|
31
|
+
app.mount(container);
|
|
32
|
+
|
|
33
|
+
expect(ctx).toBeDefined();
|
|
34
|
+
expect(ctx!.viewType.value).toBe(defaultMetaContext.viewType.value);
|
|
35
|
+
expect(ctx!.model.value).toBe(defaultMetaContext.model.value);
|
|
36
|
+
|
|
37
|
+
app.unmount();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('state/view & use-state', () => {
|
|
42
|
+
it('createViewState/ setViewState/ getViewState/ clearViewState 应维护视图状态', () => {
|
|
43
|
+
const handle = 'view-handle';
|
|
44
|
+
const state = createViewState(handle);
|
|
45
|
+
expect(state.handle).toBe(handle);
|
|
46
|
+
|
|
47
|
+
setViewState(state);
|
|
48
|
+
expect(getViewState(handle)).toBe(state);
|
|
49
|
+
|
|
50
|
+
const cleared = clearViewState(handle);
|
|
51
|
+
expect(cleared).toBe(state);
|
|
52
|
+
expect(getViewState(handle)).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('useOioState 不带 handle 时返回全局状态和当前 viewState 方法', () => {
|
|
56
|
+
const handle = 'view-handle-2';
|
|
57
|
+
const state = createViewState(handle);
|
|
58
|
+
setViewState(state);
|
|
59
|
+
|
|
60
|
+
const result = useOioState();
|
|
61
|
+
expect(result.globalState).toBe(globalState);
|
|
62
|
+
expect(result.viewState).toBeUndefined();
|
|
63
|
+
expect(typeof result.createViewState).toBe('function');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('useOioState 带 handle 时返回该视图的快捷操作函数', () => {
|
|
67
|
+
const handle = 'view-handle-3';
|
|
68
|
+
const state = createViewState(handle);
|
|
69
|
+
setViewState(state);
|
|
70
|
+
|
|
71
|
+
const result = useOioState(handle);
|
|
72
|
+
expect(result.globalState).toBe(globalState);
|
|
73
|
+
expect(result.viewState).toBe(state);
|
|
74
|
+
|
|
75
|
+
const newState = result.createViewState();
|
|
76
|
+
expect(newState.handle).toBe(handle);
|
|
77
|
+
expect(result.getViewState()).toBe(newState);
|
|
78
|
+
|
|
79
|
+
const removed = result.clearViewState();
|
|
80
|
+
expect(removed).toBe(newState);
|
|
81
|
+
expect(result.getViewState()).toBeUndefined();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('state/method/action', () => {
|
|
86
|
+
it('createActionBarState/getActionBarState/pushAction/popAction 应正确维护动作条', () => {
|
|
87
|
+
const viewState = createViewState('action-view');
|
|
88
|
+
const actionBar = createActionBarState.call(viewState, { handle: 'action-view' });
|
|
89
|
+
(viewState as any).actionBar = actionBar;
|
|
90
|
+
|
|
91
|
+
const currentActionBar = getActionBarState.call(viewState);
|
|
92
|
+
expect(currentActionBar).toBe(actionBar);
|
|
93
|
+
|
|
94
|
+
pushAction.call(viewState, 'action1');
|
|
95
|
+
expect(actionBar.actions).toContain('action1');
|
|
96
|
+
|
|
97
|
+
popAction.call(viewState, 'action1');
|
|
98
|
+
expect(actionBar.actions).not.toContain('action1');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('state/method/field', () => {
|
|
103
|
+
it('pushField/popField 应维护字段集合', () => {
|
|
104
|
+
const viewState = createViewState('field-view');
|
|
105
|
+
(viewState as any).fields = [];
|
|
106
|
+
(viewState as any).viewType = ViewType.Table;
|
|
107
|
+
|
|
108
|
+
pushField.call(viewState, 'field1');
|
|
109
|
+
expect(viewState.fields).toContain('field1');
|
|
110
|
+
|
|
111
|
+
popField.call(viewState, 'field1');
|
|
112
|
+
expect(viewState.fields).not.toContain('field1');
|
|
113
|
+
});
|
|
114
|
+
});
|
package/src/state/context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ViewType } from '@oinone/kunlun-meta';
|
|
2
|
-
import { computed, ComputedRef, inject, InjectionKey, provide } from 'vue';
|
|
2
|
+
import { computed, type ComputedRef, inject, type InjectionKey, provide } from 'vue';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 元数据上下文
|
|
@@ -53,5 +53,9 @@ export const useProviderMetaContext = (state: Partial<MetaContext>): void => {
|
|
|
53
53
|
* 获取元数据上下文
|
|
54
54
|
*/
|
|
55
55
|
export const useInjectMetaContext = (): MetaContext => {
|
|
56
|
-
|
|
56
|
+
const res = inject(MetaContextKey, defaultMetaContext);
|
|
57
|
+
if (!res) {
|
|
58
|
+
return { ...defaultMetaContext };
|
|
59
|
+
}
|
|
60
|
+
return res;
|
|
57
61
|
};
|