diff --git a/examples/box/index.json b/examples/box/index.json
index bf83cda4..c05192b5 100644
--- a/examples/box/index.json
+++ b/examples/box/index.json
@@ -1,15 +1,18 @@
{
"app": {
- "version": "example/v1",
- "metadata": { "name": "box", "description": "box" },
+ "version": "sunmao/v1",
+ "kind": "Application",
+ "metadata": {
+ "name": "some App"
+ },
"spec": {
"components": [
{
- "id": "tester5",
+ "id": "tester",
"type": "test/v1/tester",
"properties": {
- "testId": "single",
- "text": "text"
+ "testId": "tester",
+ "text": "2333"
},
"traits": []
}
diff --git a/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx b/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx
index f0e0a3b5..3cad1a25 100644
--- a/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx
+++ b/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx
@@ -3,7 +3,13 @@ import { render, fireEvent, screen, waitFor, act } from '@testing-library/react'
import produce from 'immer';
import { times } from 'lodash';
import { initSunmaoUI } from '../../src';
-import { SingleComponentSchema, ComponentSchemaChangeSchema } from './mockSchema.spec';
+import {
+ SingleComponentSchema,
+ ComponentSchemaChangeSchema,
+ HiddenTraitSchema,
+} from './mockSchema.spec';
+
+const SingleComponentRenderTimes = '2';
describe('single component condition', () => {
it('only render one time', () => {
@@ -11,7 +17,7 @@ describe('single component condition', () => {
const { unmount } = render();
// simple component will render 2 times, because it have to eval trait and properties twice
- expect(screen.getByTestId('single')?.textContent).toEqual('2');
+ expect(screen.getByTestId('single')?.textContent).toEqual(SingleComponentRenderTimes);
expect(screen.getByTestId('single-destroy')?.textContent).toEqual('0');
unmount();
});
@@ -38,6 +44,19 @@ describe('after the schema changes', () => {
});
});
+describe('hidden trait condition', () => {
+ it('the hidden component should not merge state in store', () => {
+ const { App, stateManager } = initSunmaoUI();
+ stateManager.noConsoleError = true;
+ const { unmount } = render();
+ expect(screen.getByTestId('tester')?.textContent).toEqual(SingleComponentRenderTimes);
+ expect(screen.getByTestId('tester-text')?.textContent).toEqual('');
+ expect(stateManager.store['input1']).toBeUndefined();
+
+ unmount();
+ });
+});
+
// expect(screen.getByTestId('tester1-text')?.textContent).toEqual('0');
// expect(screen.getByTestId('tester1')?.textContent).toEqual('3');
diff --git a/packages/runtime/__tests__/ImplWrapper/mockSchema.spec.ts b/packages/runtime/__tests__/ImplWrapper/mockSchema.spec.ts
index 706be0c0..895e7eb2 100644
--- a/packages/runtime/__tests__/ImplWrapper/mockSchema.spec.ts
+++ b/packages/runtime/__tests__/ImplWrapper/mockSchema.spec.ts
@@ -118,3 +118,40 @@ export const MockSchema: Application = {
],
},
};
+
+export const HiddenTraitSchema: Application = {
+ version: 'sunmao/v1',
+ kind: 'Application',
+ metadata: {
+ name: 'some App',
+ },
+ spec: {
+ components: [
+ {
+ id: 'input1',
+ type: 'test/v1/input',
+ properties: {
+ testId: '',
+ defaultValue: 'foo',
+ },
+ traits: [
+ {
+ type: 'core/v1/hidden',
+ properties: {
+ hidden: true,
+ },
+ },
+ ],
+ },
+ {
+ id: 'tester',
+ type: 'test/v1/tester',
+ properties: {
+ testId: 'tester',
+ text: '{{input1.value}}',
+ },
+ traits: [],
+ },
+ ],
+ },
+};
diff --git a/packages/runtime/__tests__/expression.spec.ts b/packages/runtime/__tests__/expression.spec.ts
index 119e6bd5..92d72fe6 100644
--- a/packages/runtime/__tests__/expression.spec.ts
+++ b/packages/runtime/__tests__/expression.spec.ts
@@ -24,8 +24,9 @@ describe('evalExpression function', () => {
},
};
const stateManager = new StateManager();
+ stateManager.noConsoleError = true;
it('can eval {{}} expression', () => {
- const evalOptions = { evalListItem: false, scopeObject: scope, noConsoleError: true };
+ const evalOptions = { evalListItem: false, scopeObject: scope };
expect(stateManager.maskedEval('value', evalOptions)).toEqual('value');
expect(stateManager.maskedEval('{{true}}', evalOptions)).toEqual(true);
@@ -80,7 +81,6 @@ describe('evalExpression function', () => {
stateManager.maskedEval('{{value}}', {
scopeObject: { override: 'foo' },
overrideScope: true,
- noConsoleError: true,
})
).toBeInstanceOf(ExpressionError);
expect(
@@ -95,7 +95,6 @@ describe('evalExpression function', () => {
expect(
stateManager.maskedEval('{{wrongExp}}', {
fallbackWhenError: exp => exp,
- noConsoleError: true,
})
).toEqual('{{wrongExp}}');
});
@@ -107,7 +106,6 @@ describe('evalExpression function', () => {
$moduleId: 'myModule',
text: 'hello',
},
- noConsoleError: true,
ignoreEvalError: true,
})
).toEqual(`hello {{myModule__state0.value}}`);
diff --git a/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapperMain.tsx b/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapperMain.tsx
index 2242cf68..fe07fcf5 100644
--- a/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapperMain.tsx
+++ b/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapperMain.tsx
@@ -8,23 +8,16 @@ import { getSlotElements } from './hooks/useSlotChildren';
import { useGlobalHandlerMap } from './hooks/useGlobalHandlerMap';
import { useEleRef } from './hooks/useEleMap';
import { useGridLayout } from './hooks/useGridLayout';
-import { initStateAndMethod } from '../../../utils/initStateAndMethod';
export const ImplWrapperMain = React.forwardRef(
function ImplWrapperMain(props, ref) {
- const { component: c, children, slotProps, evalListItem } = props;
+ const { component: c, children } = props;
const { registry, stateManager } = props.services;
const Impl = registry.getComponent(c.parsedType.version, c.parsedType.name).impl;
useGlobalHandlerMap(props);
- // This code is to init dynamic generated components
- // because they have not be initialized before
- if (!stateManager.store[c.id]) {
- initStateAndMethod(registry, stateManager, [c]);
- }
-
const { eleRef, onRef } = useEleRef(props);
const { mergeState, subscribeMethods, executeTrait } = useRuntimeFunctions(props);
@@ -35,8 +28,7 @@ export const ImplWrapperMain = React.forwardRef undefined,
})
)
@@ -67,8 +59,7 @@ export const ImplWrapperMain = React.forwardRef undefined,
}
);
@@ -79,7 +70,7 @@ export const ImplWrapperMain = React.forwardRef executeTrait(trait, properties[i])));
return () => stops.forEach(s => s());
- }, [c.id, c.traits, executeTrait, stateManager, slotProps, evalListItem]);
+ }, [c.id, c.traits, executeTrait, stateManager, props.slotProps]);
// reduce traitResults
const propsFromTraits: TraitResult['props'] = useMemo(() => {
@@ -106,8 +97,7 @@ export const ImplWrapperMain = React.forwardRef undefined,
- evalListItem,
- scopeObject: { $slot: slotProps },
+ scopeObject: { $slot: props.slotProps },
}),
propsFromTraits
);
@@ -119,17 +109,13 @@ export const ImplWrapperMain = React.forwardRef {
setEvaledComponentProperties({ ...newResult });
},
- {
- evalListItem,
- fallbackWhenError: () => undefined,
- scopeObject: { $slot: slotProps },
- }
+ { fallbackWhenError: () => undefined, scopeObject: { $slot: props.slotProps } }
);
// must keep this line, reason is the same as above
setEvaledComponentProperties({ ...result });
return stop;
- }, [c.properties, stateManager, slotProps]);
+ }, [c.properties, stateManager, props.slotProps]);
useEffect(() => {
const clearFunctions = propsFromTraits?.componentDidMount?.map(e => e());
diff --git a/packages/runtime/src/components/test/Input.tsx b/packages/runtime/src/components/test/Input.tsx
new file mode 100644
index 00000000..63f22ab1
--- /dev/null
+++ b/packages/runtime/src/components/test/Input.tsx
@@ -0,0 +1,40 @@
+import { implementRuntimeComponent } from '../../utils/buildKit';
+import { Type } from '@sinclair/typebox';
+import { useState , useEffect } from 'react';
+
+export default implementRuntimeComponent({
+ version: 'test/v1',
+ metadata: {
+ name: 'input',
+ displayName: 'Input',
+ description: 'for test',
+ isDraggable: false,
+ isResizable: false,
+ exampleProperties: {},
+ exampleSize: [1, 1],
+ annotations: {
+ category: 'Advance',
+ },
+ },
+ spec: {
+ properties: Type.Object({
+ testId: Type.String(),
+ defaultValue: Type.String(),
+ }),
+ state: Type.Object({
+ value: Type.String(),
+ }),
+ methods: {},
+ slots: {},
+ styleSlots: [],
+ events: [],
+ },
+})(({ testId, defaultValue, mergeState }) => {
+ const [value, setValue] = useState(defaultValue || '');
+ useEffect(() => {
+ mergeState({ value });
+ });
+ return (
+ setValue(e.target.value)} />
+ );
+});
diff --git a/packages/runtime/src/components/test/Tester.tsx b/packages/runtime/src/components/test/Tester.tsx
index 358f4944..529cee61 100644
--- a/packages/runtime/src/components/test/Tester.tsx
+++ b/packages/runtime/src/components/test/Tester.tsx
@@ -34,6 +34,7 @@ export default implementRuntimeComponent({
},
})(({ testId, text }) => {
renderTimesMap[testId] = (renderTimesMap[testId] || 0) + 1;
+ console.log('testId', renderTimesMap);
useEffect(() => {
return () => {
diff --git a/packages/runtime/src/services/Registry.tsx b/packages/runtime/src/services/Registry.tsx
index 41ec7dfd..f22ddaca 100644
--- a/packages/runtime/src/services/Registry.tsx
+++ b/packages/runtime/src/services/Registry.tsx
@@ -14,6 +14,7 @@ import CoreIframe from '../components/core/Iframe';
// test
import TestButton from '../components/test/Button';
import TestTester from '../components/test/Tester';
+import TestInput from '../components/test/Input';
// traits
import CoreArrayState from '../traits/core/ArrayState';
@@ -253,6 +254,7 @@ export function initRegistry(
registry.registerComponent(TestTester);
registry.registerComponent(TestButton);
+ registry.registerComponent(TestInput);
registry.registerTrait(CoreState);
registry.registerTrait(CoreArrayState);
diff --git a/packages/runtime/src/services/StateManager.ts b/packages/runtime/src/services/StateManager.ts
index c10987b6..118689c3 100644
--- a/packages/runtime/src/services/StateManager.ts
+++ b/packages/runtime/src/services/StateManager.ts
@@ -25,8 +25,6 @@ type EvalOptions = {
scopeObject?: Record;
overrideScope?: boolean;
fallbackWhenError?: (exp: string) => any;
- noConsoleError?: boolean;
- // when ignoreEvalError is true, the eval process will continue after error happens in nests expression.
ignoreEvalError?: boolean;
};
@@ -50,6 +48,9 @@ export class StateManager {
dependencies: Record;
+ // when ignoreEvalError is true, the eval process will continue after error happens in nests expression.
+ noConsoleError = false;
+
constructor(dependencies: Record = {}) {
this.dependencies = { ...DefaultDependencies, ...dependencies };
}
@@ -93,7 +94,7 @@ export class StateManager {
};
maskedEval(raw: string, options: EvalOptions = {}): unknown | ExpressionError {
- const { evalListItem = false, fallbackWhenError, noConsoleError } = options;
+ const { evalListItem = false, fallbackWhenError } = options;
let result: unknown[] = [];
try {
@@ -122,7 +123,7 @@ export class StateManager {
if (error instanceof Error) {
const expressionError = new ExpressionError(error.message);
- if (!noConsoleError) {
+ if (!this.noConsoleError) {
consoleError(ConsoleType.Expression, '', expressionError.message);
}