+
{result}
);
diff --git a/packages/runtime/src/components/core/ModuleContainer.tsx b/packages/runtime/src/components/core/ModuleContainer.tsx
index b8b94e94..94e4160c 100644
--- a/packages/runtime/src/components/core/ModuleContainer.tsx
+++ b/packages/runtime/src/components/core/ModuleContainer.tsx
@@ -2,6 +2,7 @@ import { implementRuntimeComponent } from '../../utils/buildKit';
import { ModuleRenderSpec, CORE_VERSION, CoreComponentName } from '@sunmao-ui/shared';
import { ModuleRenderer } from '../_internal/ModuleRenderer';
import React from 'react';
+import { css } from '@emotion/css';
export default implementRuntimeComponent({
version: CORE_VERSION,
@@ -22,10 +23,10 @@ export default implementRuntimeComponent({
state: {},
methods: {},
slots: {},
- styleSlots: [],
+ styleSlots: ['content'],
events: [],
},
-})(({ id, type, properties, handlers, services, app, elementRef }) => {
+})(({ id, type, properties, handlers, services, app, elementRef, customStyle }) => {
if (!type) {
return
Please choose a module to render.;
}
@@ -36,6 +37,9 @@ export default implementRuntimeComponent({
return (
;
overrideScope?: boolean;
- fallbackWhenError?: (exp: string) => any;
+ fallbackWhenError?: (exp: string, err: Error) => any;
// when ignoreEvalError is true, the eval process will continue after error happens in nests expression.
ignoreEvalError?: boolean;
slotKey?: string;
@@ -128,7 +128,9 @@ export class StateManager {
consoleError(ConsoleType.Expression, raw, expressionError.message);
}
- return fallbackWhenError ? fallbackWhenError(raw) : expressionError;
+ return fallbackWhenError
+ ? fallbackWhenError(raw, expressionError)
+ : expressionError;
}
return undefined;
}
@@ -169,18 +171,10 @@ export class StateManager {
options: EvalOptions = {}
): EvaledResult {
const store = this.slotStore;
- const redirector = new Proxy(
- {},
- {
- get(_, prop) {
- return options.slotKey ? store[options.slotKey][prop] : undefined;
- },
- }
- );
options.scopeObject = {
...options.scopeObject,
- $slot: redirector,
+ $slot: options.slotKey ? store[options.slotKey] : undefined,
};
// just eval
if (typeof value !== 'string') {
@@ -208,17 +202,9 @@ export class StateManager {
: PropsAfterEvaled>;
const store = this.slotStore;
- const redirector = new Proxy(
- {},
- {
- get(_, prop) {
- return options.slotKey ? store[options.slotKey][prop] : undefined;
- },
- }
- );
options.scopeObject = {
...options.scopeObject,
- $slot: redirector,
+ $slot: options.slotKey ? store[options.slotKey] : undefined,
};
// watch change
if (value && typeof value === 'object') {
diff --git a/packages/runtime/src/traits/core/ArrayState.tsx b/packages/runtime/src/traits/core/ArrayState.tsx
index 0842dd62..0118ef56 100644
--- a/packages/runtime/src/traits/core/ArrayState.tsx
+++ b/packages/runtime/src/traits/core/ArrayState.tsx
@@ -5,7 +5,7 @@ import { CORE_VERSION, CoreTraitName } from '@sunmao-ui/shared';
type KeyValue = { key: string; value: unknown };
export const ArrayStateTraitPropertiesSpec = Type.Object({
- key: Type.String(),
+ key: Type.String({ default: 'value' }),
initialValue: Type.Optional(Type.Array(Type.Any())),
});
diff --git a/packages/runtime/src/traits/core/LocalStorage.tsx b/packages/runtime/src/traits/core/LocalStorage.tsx
index b483f6aa..a0404d5c 100644
--- a/packages/runtime/src/traits/core/LocalStorage.tsx
+++ b/packages/runtime/src/traits/core/LocalStorage.tsx
@@ -65,6 +65,7 @@ function getLocalStorage(
export const LocalStorageTraitPropertiesSpec = Type.Object({
key: Type.String({
title: 'Key',
+ default: 'value',
}),
initialValue: Type.Any({
title: 'Initial Value',
@@ -86,7 +87,6 @@ export default implementRuntimeTrait({
spec: {
properties: LocalStorageTraitPropertiesSpec,
state: Type.Object({
- value: Type.Any(),
version: Type.Number(),
}),
methods: [
@@ -117,7 +117,7 @@ export default implementRuntimeTrait({
if (key) {
if (!hasInitialized) {
const storageItem = getLocalStorage(hashId, initialValue, { version });
- setValue(storageItem?.value, storageItem.version);
+ setValue(storageItem?.value || initialValue, storageItem.version);
subscribeMethods({
setValue: ({ value: newValue }: { value: any }) => {
diff --git a/packages/runtime/src/traits/core/State.tsx b/packages/runtime/src/traits/core/State.tsx
index f108bddd..3f8a1eda 100644
--- a/packages/runtime/src/traits/core/State.tsx
+++ b/packages/runtime/src/traits/core/State.tsx
@@ -7,6 +7,7 @@ type KeyValue = { key: string; value: unknown };
export const StateTraitPropertiesSpec = Type.Object({
key: Type.String({
title: 'Key',
+ default: 'value',
}),
initialValue: Type.Any({
title: 'Initial Value',
diff --git a/packages/runtime/src/utils/runEventHandler.ts b/packages/runtime/src/utils/runEventHandler.ts
index 115bcaa6..702bfa1f 100644
--- a/packages/runtime/src/utils/runEventHandler.ts
+++ b/packages/runtime/src/utils/runEventHandler.ts
@@ -1,6 +1,6 @@
import { Static, Type } from '@sinclair/typebox';
import { debounce, throttle, delay } from 'lodash';
-import { EventCallBackHandlerSpec } from '@sunmao-ui/shared';
+import { EventCallBackHandlerSpec, MODULE_ID_EXP } from '@sunmao-ui/shared';
import { type PropsBeforeEvaled } from '@sunmao-ui/core';
import { UIServices } from '../types';
@@ -18,6 +18,10 @@ export const runEventHandler = (
// Eval before sending event to assure the handler object is evaled from the latest state.
const evalOptions = {
slotKey,
+ // keep MODULE_ID_EXP when error
+ fallbackWhenError(exp: string, err: Error) {
+ return exp === MODULE_ID_EXP ? exp : err;
+ },
};
const evaledHandlers = stateManager.deepEval(rawHandlers, evalOptions) as Static<
typeof EventCallBackHandlerSpec
diff --git a/packages/shared/src/constants/expression.ts b/packages/shared/src/constants/expression.ts
index 8de94eca..4435aeb1 100644
--- a/packages/shared/src/constants/expression.ts
+++ b/packages/shared/src/constants/expression.ts
@@ -7,6 +7,7 @@ export const LIST_ITEM_INDEX_EXP = '$i';
export const SLOT_PROPS_EXP = '$slot';
export const GLOBAL_UTIL_METHOD_ID = '$utils';
export const GLOBAL_MODULE_ID = '$module';
+export const MODULE_ID_EXP = '{{$moduleId}}';
export const ExpressionKeywords = [
LIST_ITEM_EXP,
diff --git a/packages/shared/src/specs/module.ts b/packages/shared/src/specs/module.ts
index 389f747b..7d6649db 100644
--- a/packages/shared/src/specs/module.ts
+++ b/packages/shared/src/specs/module.ts
@@ -1,6 +1,7 @@
import { EventHandlerSpec } from './event';
import { Type } from '@sinclair/typebox';
import { CORE_VERSION, CoreWidgetName } from '../constants/core';
+import { MODULE_ID_EXP } from '../constants';
export const ModuleRenderSpec = Type.Object(
{
@@ -27,3 +28,7 @@ export const ModuleRenderSpec = Type.Object(
widget: 'core/v1/module',
}
);
+
+export const ModuleEventMethodSpec = Type.Object({
+ moduleId: Type.Literal(MODULE_ID_EXP),
+});
diff --git a/packages/shared/src/utils/spec.ts b/packages/shared/src/utils/spec.ts
index db56bca0..f0f5890b 100644
--- a/packages/shared/src/utils/spec.ts
+++ b/packages/shared/src/utils/spec.ts
@@ -34,8 +34,12 @@ function getArray(items: JSONSchema7Definition[], options?: Options): JSONSchema
);
}
+function isJSONSchema7Object(value: unknown): value is JSONSchema7Object {
+ return !!value && typeof value === 'object' && value instanceof Array === false;
+}
+
function getObject(spec: JSONSchema7, options?: Options): JSONSchema7Object | string {
- const obj: JSONSchema7Object = {};
+ const obj: JSONSchema7Object = isJSONSchema7Object(spec.default) ? spec.default : {};
if (spec.allOf && spec.allOf.length > 0) {
return (getArray(spec.allOf, options) as JSONSchema7Object[]).reduce((prev, cur) => {
@@ -47,10 +51,10 @@ function getObject(spec: JSONSchema7, options?: Options): JSONSchema7Object | st
// if not specific property, treat it as any type
if (!spec.properties) {
if (options?.returnPlaceholderForAny) {
- return AnyTypePlaceholder;
+ return isJSONSchema7Object(spec.default) ? spec.default : AnyTypePlaceholder;
}
- return {};
+ return isJSONSchema7Object(spec.default) ? spec.default : {};
}
for (const key in spec.properties) {
@@ -58,7 +62,8 @@ function getObject(spec: JSONSchema7, options?: Options): JSONSchema7Object | st
if (typeof subSpec === 'boolean') {
obj[key] = null;
} else if (subSpec) {
- obj[key] = generateDefaultValueFromSpec(subSpec, options);
+ obj[key] =
+ subSpec.default ?? obj[key] ?? generateDefaultValueFromSpec(subSpec, options);
}
}
return obj;
@@ -98,14 +103,14 @@ export function generateDefaultValueFromSpec(
}
case spec.type === 'string':
if (spec.enum && spec.enum.length > 0) {
- return spec.enum[0];
+ return spec.default ?? spec.enum[0];
} else {
- return '';
+ return spec.default ?? '';
}
case spec.type === 'boolean':
- return false;
+ return spec.default ?? false;
case spec.type === 'array':
- return spec.items
+ return spec.default ?? spec.items
? Array.isArray(spec.items)
? getArray(spec.items, options)
: isJSONSchema(spec.items)
@@ -116,13 +121,13 @@ export function generateDefaultValueFromSpec(
: [];
case spec.type === 'number':
case spec.type === 'integer':
- return 0;
+ return spec.default ?? 0;
case spec.type === 'object':
return getObject(spec, options);
case spec.type === 'null':
return null;
default:
- return {};
+ return spec.default ?? {};
}
}