mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-04-06 21:40:23 +08:00
modify components to new slot
This commit is contained in:
parent
dd974ea085
commit
ca0a780d96
@ -292,7 +292,7 @@ export default implementRuntimeComponent({
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
})(({ customStyle, Slot, ...restProps }) => {
|
||||
})(({ customStyle, slotsElements, ...restProps }) => {
|
||||
const styleProps = pick(restProps, StyleProps);
|
||||
return (
|
||||
<BaseBox
|
||||
@ -307,7 +307,7 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.content}
|
||||
`}
|
||||
>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
</BaseBox>
|
||||
);
|
||||
});
|
||||
|
@ -37,7 +37,7 @@ export default implementRuntimeComponent({
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
})(({ size, defaultValue, isDisabled, Slot, mergeState }) => {
|
||||
})(({ size, defaultValue, isDisabled, slotsElements, mergeState }) => {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
useEffect(() => {
|
||||
mergeState({ value });
|
||||
@ -50,7 +50,7 @@ export default implementRuntimeComponent({
|
||||
isDisabled={isDisabled}
|
||||
onChange={val => setValue(val)}
|
||||
>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
</BaseCheckboxGroup>
|
||||
);
|
||||
});
|
||||
|
@ -61,7 +61,7 @@ export default implementRuntimeComponent({
|
||||
},
|
||||
})(
|
||||
({
|
||||
Slot,
|
||||
slotsElements,
|
||||
subscribeMethods,
|
||||
callbackMap: callbacks,
|
||||
title: customerTitle,
|
||||
@ -132,7 +132,7 @@ export default implementRuntimeComponent({
|
||||
>
|
||||
<AlertDialogHeader>{title}</AlertDialogHeader>
|
||||
<AlertDialogBody>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
</AlertDialogBody>
|
||||
|
||||
<AlertDialogFooter>
|
||||
|
@ -42,8 +42,8 @@ export default implementRuntimeComponent({
|
||||
callbackMap,
|
||||
services,
|
||||
customStyle,
|
||||
Slot,
|
||||
treeMap,
|
||||
slotsElements,
|
||||
childrenMap,
|
||||
component
|
||||
}) => {
|
||||
const [invalidArray, setInvalidArray] = useState<boolean[]>([]);
|
||||
@ -51,11 +51,11 @@ export default implementRuntimeComponent({
|
||||
const formDataRef = useRef<Record<string, any>>({});
|
||||
const formControlIds = useMemo<string[]>(() => {
|
||||
return (
|
||||
treeMap[component.id]?.content.map(slot => {
|
||||
childrenMap[component.id]?.content.map(slot => {
|
||||
return slot.id;
|
||||
}) || []
|
||||
);
|
||||
}, [component.id, treeMap]);
|
||||
}, [component.id, childrenMap]);
|
||||
|
||||
useEffect(() => {
|
||||
setInvalidArray(
|
||||
@ -149,7 +149,7 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.content}
|
||||
`}
|
||||
>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
{hideSubmit ? undefined : (
|
||||
<Button
|
||||
marginInlineStart="auto !important"
|
||||
|
@ -63,14 +63,14 @@ export default implementRuntimeComponent({
|
||||
mergeState,
|
||||
services,
|
||||
customStyle,
|
||||
Slot,
|
||||
treeMap,
|
||||
slotsElements,
|
||||
childrenMap,
|
||||
component,
|
||||
}) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
// don't show Invalid state on component mount
|
||||
const [hideInvalid, setHideInvalid] = useState(true);
|
||||
const inputId = useMemo(() => first(treeMap[component.id].content)?.id || '', [component.id, treeMap]);
|
||||
const inputId = useMemo(() => first(childrenMap[component.id]?.content)?.id || '', [component.id, childrenMap]);
|
||||
const [validResult, setValidResult] = useState({
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
@ -129,7 +129,7 @@ export default implementRuntimeComponent({
|
||||
}, [inputId, fieldName, isInvalid, isRequired, inputValue, mergeState]);
|
||||
|
||||
const placeholder = <Text color="gray.200">Please Add Input Here</Text>;
|
||||
const slotView = <Slot {...FormItemCSS} slot="content" />;
|
||||
const slotView = slotsElements.content;
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
|
@ -39,7 +39,7 @@ export default implementRuntimeComponent({
|
||||
methods: {},
|
||||
events: [],
|
||||
},
|
||||
})(({ direction, wrap, align, justify, spacing, contentChildren , customStyle }) => {
|
||||
})(({ direction, wrap, align, justify, spacing, slotsElements, customStyle }) => {
|
||||
return (
|
||||
<BaseHStack
|
||||
height="full"
|
||||
@ -54,7 +54,7 @@ export default implementRuntimeComponent({
|
||||
`}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
{contentChildren}
|
||||
{slotsElements.content}
|
||||
</BaseHStack>
|
||||
);
|
||||
});
|
||||
|
@ -35,7 +35,7 @@ export default implementRuntimeComponent({
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
})(({ defaultValue, isNumerical, Slot, mergeState, customStyle }) => {
|
||||
})(({ defaultValue, isNumerical, slotsElements, mergeState, customStyle }) => {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
useEffect(() => {
|
||||
@ -54,7 +54,7 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.content}
|
||||
`}
|
||||
>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
</BaseRadioGroup>
|
||||
);
|
||||
});
|
||||
|
@ -21,7 +21,7 @@ export default implementRuntimeComponent({
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
})(({ Slot }) => {
|
||||
})(({ slotsElements }) => {
|
||||
return (
|
||||
<ChakraProvider
|
||||
theme={extendTheme({
|
||||
@ -29,7 +29,7 @@ export default implementRuntimeComponent({
|
||||
useSystemColorMode: false,
|
||||
})}
|
||||
>
|
||||
<Slot slot="root" />
|
||||
<>{slotsElements.root}</>
|
||||
</ChakraProvider>
|
||||
);
|
||||
});
|
||||
|
@ -67,10 +67,10 @@ export default implementRuntimeComponent({
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
})(({ direction, wrap, align, justify, spacing, Slot }) => {
|
||||
})(({ direction, wrap, align, justify, spacing, slotsElements }) => {
|
||||
return (
|
||||
<BaseStack {...{ direction, wrap, align, justify, spacing }}>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
</BaseStack>
|
||||
);
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
Text,
|
||||
} from '@chakra-ui/react';
|
||||
import { Type } from '@sinclair/typebox';
|
||||
import { implementRuntimeComponent, genSlotsAsArray } from '@sunmao-ui/runtime';
|
||||
import { implementRuntimeComponent } from '@sunmao-ui/runtime';
|
||||
|
||||
const StateSchema = Type.Object({
|
||||
selectedTabIndex: Type.Number(),
|
||||
@ -43,15 +43,15 @@ export default implementRuntimeComponent({
|
||||
styleSlots: ['tabItem', 'tabContent'],
|
||||
events: [],
|
||||
},
|
||||
})((props) => {
|
||||
const { tabNames, mergeState, initialSelectedTabIndex, customStyle } = props
|
||||
})(props => {
|
||||
const { tabNames, mergeState, initialSelectedTabIndex, customStyle, slotsElements } =
|
||||
props;
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(initialSelectedTabIndex ?? 0);
|
||||
|
||||
useEffect(() => {
|
||||
mergeState({ selectedTabIndex });
|
||||
}, [mergeState, selectedTabIndex]);
|
||||
|
||||
const slotComponents = genSlotsAsArray(props, 'content');
|
||||
const placeholder = (
|
||||
<Text color="gray">Slot content is empty.Please drag component to this slot.</Text>
|
||||
);
|
||||
@ -74,7 +74,7 @@ export default implementRuntimeComponent({
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
{tabNames.map((_, idx) => {
|
||||
const Component = slotComponents[idx]
|
||||
const ele = slotsElements.content ? slotsElements.content[idx] : placeholder;
|
||||
return (
|
||||
<TabPanel
|
||||
key={idx}
|
||||
@ -82,7 +82,7 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.tabContent}
|
||||
`}
|
||||
>
|
||||
{Component ? <Component /> : placeholder}
|
||||
{ele}
|
||||
</TabPanel>
|
||||
);
|
||||
})}
|
||||
|
@ -64,7 +64,7 @@ export default implementRuntimeComponent({
|
||||
hasArrow,
|
||||
isDisabled,
|
||||
defaultIsOpen,
|
||||
Slot,
|
||||
slotsElements,
|
||||
}) => {
|
||||
return (
|
||||
/*
|
||||
@ -80,7 +80,7 @@ export default implementRuntimeComponent({
|
||||
defaultIsOpen={defaultIsOpen}
|
||||
shouldWrapChildren={shouldWrapChildren}
|
||||
>
|
||||
<Slot slot="content" />
|
||||
{slotsElements.content}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
@ -19,50 +19,42 @@ const PropsSchema = Type.Object({
|
||||
});
|
||||
|
||||
export default implementRuntimeComponent({
|
||||
version: 'chakra_ui/v1',
|
||||
metadata: {
|
||||
name: 'vstack',
|
||||
displayName: 'VStack',
|
||||
description: 'chakra-ui vstack',
|
||||
exampleProperties: {
|
||||
spacing: '24px',
|
||||
},
|
||||
exampleSize: [6, 6],
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
version: 'chakra_ui/v1',
|
||||
metadata: {
|
||||
name: 'vstack',
|
||||
displayName: 'VStack',
|
||||
description: 'chakra-ui vstack',
|
||||
exampleProperties: {
|
||||
spacing: '24px',
|
||||
},
|
||||
spec: {
|
||||
properties: PropsSchema,
|
||||
state: Type.Object({}),
|
||||
slots: ['content'],
|
||||
styleSlots: ['content'],
|
||||
methods: {},
|
||||
events: [],
|
||||
},
|
||||
})(({
|
||||
direction,
|
||||
wrap,
|
||||
align,
|
||||
justify,
|
||||
spacing,
|
||||
contentChildren,
|
||||
customStyle,
|
||||
}) => {
|
||||
return (
|
||||
<BaseVStack
|
||||
width="full"
|
||||
height="full"
|
||||
padding="4"
|
||||
background="white"
|
||||
border="1px solid"
|
||||
borderColor="gray.200"
|
||||
borderRadius="4"
|
||||
className={css`
|
||||
${customStyle?.content}
|
||||
`}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
{contentChildren}
|
||||
</BaseVStack>
|
||||
);
|
||||
})
|
||||
exampleSize: [6, 6],
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
},
|
||||
spec: {
|
||||
properties: PropsSchema,
|
||||
state: Type.Object({}),
|
||||
slots: ['content'],
|
||||
styleSlots: ['content'],
|
||||
methods: {},
|
||||
events: [],
|
||||
},
|
||||
})(({ direction, wrap, align, justify, spacing, slotsElements, customStyle }) => {
|
||||
return (
|
||||
<BaseVStack
|
||||
width="full"
|
||||
height="full"
|
||||
padding="4"
|
||||
background="white"
|
||||
border="1px solid"
|
||||
borderColor="gray.200"
|
||||
borderRadius="4"
|
||||
className={css`
|
||||
${customStyle?.content}
|
||||
`}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
{slotsElements.content}
|
||||
</BaseVStack>
|
||||
);
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createApplication } from '@sunmao-ui/core';
|
||||
import { resolveTreeMap } from '../src/utils/resolveTreeMap';
|
||||
import { resolveChildrenMap } from '../src/utils/resolveChildrenMap';
|
||||
|
||||
const origin = createApplication({
|
||||
version: 'example/v1',
|
||||
@ -82,24 +82,24 @@ const origin = createApplication({
|
||||
});
|
||||
|
||||
describe('resolve tree map', () => {
|
||||
const { treeMap, topLevelComponents } = resolveTreeMap(origin.spec.components);
|
||||
const { childrenMap, topLevelComponents } = resolveChildrenMap(origin.spec.components);
|
||||
it('resolve tree map', () => {
|
||||
expect(treeMap['hstack1'].content.map(c => c.id)).toEqual(['button1', 'vstack1']);
|
||||
expect(treeMap['vstack1'].content.map(c => c.id)).toEqual(['hstack2']);
|
||||
expect(treeMap['hstack2'].content.map(c => c.id)).toEqual(['text1', 'text2']);
|
||||
expect(childrenMap['hstack1'].content.map(c => c.id)).toEqual(['button1', 'vstack1']);
|
||||
expect(childrenMap['vstack1'].content.map(c => c.id)).toEqual(['hstack2']);
|
||||
expect(childrenMap['hstack2'].content.map(c => c.id)).toEqual(['text1', 'text2']);
|
||||
expect(topLevelComponents.map(c => c.id)).toEqual(['hstack1', 'hstack3']);
|
||||
expect(treeMap['hstack1']._grandChildren!.map(c => c.id)).toEqual([
|
||||
expect(childrenMap['hstack1']._grandChildren!.map(c => c.id)).toEqual([
|
||||
'button1',
|
||||
'vstack1',
|
||||
'hstack2',
|
||||
'text1',
|
||||
'text2',
|
||||
]);
|
||||
expect(treeMap['vstack1']._grandChildren!.map(c => c.id)).toEqual([
|
||||
expect(childrenMap['vstack1']._grandChildren!.map(c => c.id)).toEqual([
|
||||
'hstack2',
|
||||
'text1',
|
||||
'text2',
|
||||
]);
|
||||
expect(treeMap['hstack2']._grandChildren!.map(c => c.id)).toEqual(['text1', 'text2']);
|
||||
expect(childrenMap['hstack2']._grandChildren!.map(c => c.id)).toEqual(['text1', 'text2']);
|
||||
});
|
||||
});
|
@ -4,7 +4,7 @@ import { ImplWrapper } from './components/_internal/ImplWrapper';
|
||||
import { AppProps, UIServices } from './types/RuntimeSchema';
|
||||
import { DebugEvent, DebugStore } from './services/DebugComponents';
|
||||
import { RuntimeAppSchemaManager } from './services/RuntimeAppSchemaManager';
|
||||
import { resolveTreeMap } from './utils/resolveTreeMap';
|
||||
import { resolveChildrenMap } from './utils/resolveChildrenMap';
|
||||
|
||||
// inject modules to App
|
||||
export function genApp(services: UIServices) {
|
||||
@ -26,7 +26,7 @@ export const App: React.FC<AppProps> = props => {
|
||||
const app = runtimeAppSchemaManager.current.update(options);
|
||||
initStateAndMethod(services.registry, services.stateManager, app.spec.components);
|
||||
|
||||
const { treeMap, topLevelComponents } = resolveTreeMap(app.spec.components);
|
||||
const { childrenMap, topLevelComponents } = resolveChildrenMap(app.spec.components);
|
||||
return (
|
||||
<div className="App" style={{ height: '100vh', overflow: 'auto' }}>
|
||||
{topLevelComponents.map(c => {
|
||||
@ -35,7 +35,7 @@ export const App: React.FC<AppProps> = props => {
|
||||
key={c.id}
|
||||
component={c}
|
||||
services={services}
|
||||
treeMap={treeMap}
|
||||
childrenMap={childrenMap}
|
||||
app={app}
|
||||
componentWrapper={componentWrapper}
|
||||
gridCallbacks={gridCallbacks}
|
||||
|
@ -20,9 +20,8 @@ const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props,
|
||||
children,
|
||||
componentWrapper: ComponentWrapper,
|
||||
services,
|
||||
treeMap,
|
||||
childrenMap,
|
||||
} = props;
|
||||
console.log('wrapper', c.id);
|
||||
const { registry, stateManager, globalHandlerMap, apiService } = props.services;
|
||||
const childrenCache = new Map<RuntimeApplicationComponent, React.ReactElement>();
|
||||
|
||||
@ -154,26 +153,30 @@ const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props,
|
||||
}, [c.properties, stateManager]);
|
||||
|
||||
const mergedProps = { ...evaledComponentProperties, ...propsFromTraits };
|
||||
const contentChildren = (
|
||||
<>
|
||||
{treeMap[c.id]
|
||||
? treeMap[c.id]._allChildren.map(child => {
|
||||
if (!childrenCache.get(child)) {
|
||||
const ele = <ImplWrapper key={child.id} {...props} component={child} />;
|
||||
console.log('render element', c.id);
|
||||
childrenCache.set(child, ele);
|
||||
}
|
||||
return childrenCache.get(child);
|
||||
})
|
||||
: null}
|
||||
</>
|
||||
);
|
||||
|
||||
function genSlotsElements() {
|
||||
if (!childrenMap[c.id]) {
|
||||
return {};
|
||||
}
|
||||
const res: Record<string, React.ReactElement[]> = {};
|
||||
for (const slot in childrenMap[c.id]) {
|
||||
res[slot] = childrenMap[c.id][slot].map(child => {
|
||||
if (!childrenCache.get(child)) {
|
||||
const ele = <ImplWrapper key={child.id} {...props} component={child} />;
|
||||
childrenCache.set(child, ele);
|
||||
}
|
||||
return childrenCache.get(child)!;
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const C = unmount ? null : (
|
||||
<Impl
|
||||
key={c.id}
|
||||
{...props}
|
||||
{...mergedProps}
|
||||
contentChildren={contentChildren}
|
||||
slotsElements={genSlotsElements()}
|
||||
mergeState={mergeState}
|
||||
subscribeMethods={subscribeMethods}
|
||||
/>
|
||||
@ -227,8 +230,8 @@ const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props,
|
||||
export const ImplWrapper = React.memo<ImplWrapperProps>(
|
||||
_ImplWrapper,
|
||||
(prevProps, nextProps) => {
|
||||
const prevChildren = prevProps.treeMap[prevProps.component.id]?._grandChildren;
|
||||
const nextChildren = nextProps.treeMap[nextProps.component.id]?._grandChildren;
|
||||
const prevChildren = prevProps.childrenMap[prevProps.component.id]?._grandChildren;
|
||||
const nextChildren = nextProps.childrenMap[nextProps.component.id]?._grandChildren;
|
||||
if (!prevChildren || !nextProps) return false;
|
||||
let isEqual = false;
|
||||
|
||||
|
@ -12,7 +12,7 @@ import { EventHandlerSchema } from '../../types/TraitPropertiesSchema';
|
||||
import { ImplWrapper } from './ImplWrapper';
|
||||
import { watch } from '../../utils/watchReactivity';
|
||||
import { ImplementedRuntimeModule } from '../../services/registry';
|
||||
import { resolveTreeMap } from '../../utils/resolveTreeMap';
|
||||
import { resolveChildrenMap } from '../../utils/resolveChildrenMap';
|
||||
|
||||
type Props = Static<typeof RuntimeModuleSchema> & {
|
||||
evalScope?: Record<string, any>;
|
||||
@ -148,7 +148,7 @@ const ModuleRendererContent: React.FC<Props & { moduleSpec: ImplementedRuntimeMo
|
||||
}, [evaledHanlders, moduleId, services.apiService]);
|
||||
|
||||
const result = useMemo(() => {
|
||||
const { treeMap, topLevelComponents } = resolveTreeMap(evaledModuleTemplate);
|
||||
const { childrenMap, topLevelComponents } = resolveChildrenMap(evaledModuleTemplate);
|
||||
return topLevelComponents.map(c => {
|
||||
return (
|
||||
<ImplWrapper
|
||||
@ -156,7 +156,7 @@ const ModuleRendererContent: React.FC<Props & { moduleSpec: ImplementedRuntimeMo
|
||||
component={c}
|
||||
services={services}
|
||||
app={app}
|
||||
treeMap={treeMap}
|
||||
childrenMap={childrenMap}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
@ -40,7 +40,7 @@ export default implementRuntimeComponent({
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
})(({ layout = [], gridCallbacks, component, customStyle, Slot }) => {
|
||||
})(({ layout = [], gridCallbacks, component, customStyle, slotsElements }) => {
|
||||
const onDragStop = gridCallbacks?.onDragStop
|
||||
? partial(gridCallbacks.onDragStop, component.id)
|
||||
: undefined;
|
||||
@ -60,7 +60,7 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.content}
|
||||
`}
|
||||
>
|
||||
<Slot slot='content' />
|
||||
{slotsElements.content}
|
||||
</BaseGridLayout>
|
||||
</Suspense>
|
||||
);
|
||||
|
@ -24,9 +24,8 @@ import {
|
||||
import {
|
||||
RuntimeApplicationComponent,
|
||||
UIServices,
|
||||
TreeMap,
|
||||
ChildrenMap,
|
||||
} from '../../../types/RuntimeSchema';
|
||||
import { genSlotsAsArray } from '../../../components/_internal/Slot';
|
||||
|
||||
export type RouteLikeElement = PropsWithChildren<{
|
||||
path?: string;
|
||||
@ -65,14 +64,23 @@ type SwitchProps = {
|
||||
location?: string;
|
||||
switchPolicy: SwitchPolicy;
|
||||
component: RuntimeApplicationComponent;
|
||||
treeMap: TreeMap<string>;
|
||||
childrenMap: ChildrenMap<string>;
|
||||
services: UIServices;
|
||||
slotsElements: Record<string, ReactElement[]>;
|
||||
mergeState: (partialState: any) => void;
|
||||
subscribeMethods: (map: { [key: string]: (parameters: any) => void }) => void;
|
||||
};
|
||||
|
||||
export const Switch: React.FC<SwitchProps> = props => {
|
||||
const { switchPolicy, location, mergeState, subscribeMethods } = props;
|
||||
const {
|
||||
switchPolicy,
|
||||
location,
|
||||
mergeState,
|
||||
subscribeMethods,
|
||||
slotsElements,
|
||||
childrenMap,
|
||||
component,
|
||||
} = props;
|
||||
const [originalLocation] = useLocation();
|
||||
const matcher = useMemo(() => makeMatcher(), []);
|
||||
|
||||
@ -82,7 +90,7 @@ export const Switch: React.FC<SwitchProps> = props => {
|
||||
let defaultPath: string | undefined = undefined;
|
||||
const result = switchPolicy.map(
|
||||
({ type, path, slotId, href, default: _default, exact, strict, sensitive }) => {
|
||||
const componentsArr = genSlotsAsArray(props, slotId);
|
||||
const children = slotsElements[slotId];
|
||||
if (defaultPath === undefined && _default) {
|
||||
defaultPath = path;
|
||||
}
|
||||
@ -101,19 +109,19 @@ export const Switch: React.FC<SwitchProps> = props => {
|
||||
</Route>
|
||||
);
|
||||
case RouteType.ROUTE:
|
||||
if (!componentsArr) {
|
||||
if (!children) {
|
||||
console.warn('component not registered to router');
|
||||
return <></>;
|
||||
}
|
||||
if (componentsArr.length !== 1) {
|
||||
if (children.length !== 1) {
|
||||
console.warn('router slot can only have one component');
|
||||
}
|
||||
const C = componentsArr[0];
|
||||
if (C.displayName === 'router') {
|
||||
const ele = children[0];
|
||||
if (childrenMap[component.id][slotId][0].parsedType.name === 'router') {
|
||||
return (
|
||||
// it should match both itself and its children path
|
||||
<Nested path={`(${path}|${path}/.*)`} base={path} key={path}>
|
||||
<C key={slotId}></C>
|
||||
{ele}
|
||||
</Nested>
|
||||
);
|
||||
}
|
||||
@ -126,7 +134,7 @@ export const Switch: React.FC<SwitchProps> = props => {
|
||||
path={path}
|
||||
mergeState={mergeState}
|
||||
>
|
||||
<C key={slotId}></C>
|
||||
{ele}
|
||||
</Route>
|
||||
);
|
||||
default:
|
||||
@ -143,7 +151,7 @@ export const Switch: React.FC<SwitchProps> = props => {
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}, [mergeState, props, switchPolicy]);
|
||||
}, [component.id, mergeState, slotsElements, switchPolicy, childrenMap]);
|
||||
|
||||
useEffect(() => {
|
||||
subscribeMethods({
|
||||
|
@ -29,7 +29,6 @@ export * from './types/RuntimeSchema';
|
||||
export * from './types/TraitPropertiesSchema';
|
||||
export * from './constants';
|
||||
export * from './services/registry';
|
||||
export { genSlots, genSlotsAsArray } from './components/_internal/Slot';
|
||||
export { ModuleRenderer } from './components/_internal/ModuleRenderer';
|
||||
export { default as Text, TextPropertySchema } from './components/_internal/Text';
|
||||
|
||||
|
@ -44,12 +44,12 @@ export type AppProps = {
|
||||
// TODO: (type-safe), remove fallback type
|
||||
export type ImplWrapperProps<KSlot extends string = string> = {
|
||||
component: RuntimeApplicationComponent;
|
||||
treeMap: TreeMap<KSlot>;
|
||||
childrenMap: ChildrenMap<KSlot>;
|
||||
services: UIServices;
|
||||
app?: RuntimeApplication;
|
||||
} & ComponentParamsFromApp;
|
||||
|
||||
export type TreeMap<KSlot extends string> = Record<
|
||||
export type ChildrenMap<KSlot extends string> = Record<
|
||||
string,
|
||||
Record<KSlot, RuntimeApplicationComponent[]> & {
|
||||
_grandChildren?: RuntimeApplicationComponent[];
|
||||
@ -78,7 +78,7 @@ export type ComponentImplementationProps<
|
||||
> = ImplWrapperProps<KSlot> &
|
||||
TraitResult<KStyleSlot, KEvent>['props'] &
|
||||
RuntimeFunctions<TState, TMethods> & {
|
||||
contentChildren: Record<KSlot, React.ReactElement>
|
||||
slotsElements: Record<KSlot, React.ReactElement[]>
|
||||
};
|
||||
|
||||
export type TraitResult<KStyleSlot extends string, KEvent extends string> = {
|
||||
|
62
packages/runtime/src/utils/resolveChildrenMap.ts
Normal file
62
packages/runtime/src/utils/resolveChildrenMap.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { RuntimeApplicationComponent, ChildrenMap } from '../types/RuntimeSchema';
|
||||
|
||||
export function resolveChildrenMap(components: RuntimeApplicationComponent[]): {
|
||||
childrenMap: ChildrenMap<string>;
|
||||
topLevelComponents: RuntimeApplicationComponent[];
|
||||
} {
|
||||
const childrenMap: ChildrenMap<string> = {};
|
||||
const topLevelComponents: RuntimeApplicationComponent[] = [];
|
||||
|
||||
for (const c of components) {
|
||||
const slotTrait = c.traits.find(t => t.parsedType.name === 'slot');
|
||||
if (!slotTrait) {
|
||||
topLevelComponents.push(c);
|
||||
continue;
|
||||
}
|
||||
const { id, slot } = slotTrait.properties.container as any;
|
||||
if (!childrenMap[id]) {
|
||||
childrenMap[id] = {
|
||||
_allChildren: [],
|
||||
};
|
||||
}
|
||||
const children = childrenMap[id];
|
||||
if (!children[slot]) {
|
||||
children[slot] = [];
|
||||
}
|
||||
children[slot].push(c);
|
||||
children._allChildren.push(c);
|
||||
}
|
||||
|
||||
// get allChildren and grand children
|
||||
function getAllChildren(id: string): RuntimeApplicationComponent[] {
|
||||
if (!childrenMap[id]) {
|
||||
return [];
|
||||
}
|
||||
if (childrenMap[id]?._grandChildren) {
|
||||
return childrenMap[id]._grandChildren!;
|
||||
}
|
||||
const children = childrenMap[id];
|
||||
|
||||
childrenMap[id]._grandChildren = children._allChildren.reduce((res, curr) => {
|
||||
const cccc = getAllChildren(curr.id);
|
||||
return res.concat(cccc);
|
||||
}, children._allChildren);
|
||||
|
||||
return childrenMap[id]._grandChildren!;
|
||||
}
|
||||
|
||||
for (const id in childrenMap) {
|
||||
childrenMap[id]._grandChildren = getAllChildren(id);
|
||||
Object.defineProperty(childrenMap[id], '_allChildren', {
|
||||
enumerable: false,
|
||||
});
|
||||
Object.defineProperty(childrenMap[id], '_grandChildren', {
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
childrenMap,
|
||||
topLevelComponents,
|
||||
};
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
import { flatten } from 'lodash-es';
|
||||
import { RuntimeApplicationComponent, TreeMap } from '../types/RuntimeSchema';
|
||||
|
||||
export function resolveTreeMap(components: RuntimeApplicationComponent[]): {
|
||||
treeMap: TreeMap<string>;
|
||||
topLevelComponents: RuntimeApplicationComponent[];
|
||||
} {
|
||||
const treeMap: TreeMap<string> = {};
|
||||
const topLevelComponents: RuntimeApplicationComponent[] = [];
|
||||
|
||||
for (const c of components) {
|
||||
const slotTrait = c.traits.find(t => t.parsedType.name === 'slot');
|
||||
if (!slotTrait) {
|
||||
topLevelComponents.push(c);
|
||||
continue;
|
||||
}
|
||||
const { id, slot } = slotTrait.properties.container as any;
|
||||
if (!treeMap[id]) {
|
||||
treeMap[id] = {
|
||||
_allChildren: []
|
||||
};
|
||||
}
|
||||
const children = treeMap[id];
|
||||
if (!children[slot]) {
|
||||
children[slot] = [];
|
||||
}
|
||||
children[slot].push(c);
|
||||
children._allChildren.push(c)
|
||||
}
|
||||
|
||||
// get allChildren and grand children
|
||||
function getAllChildren(id: string): RuntimeApplicationComponent[] {
|
||||
if (!treeMap[id]) {
|
||||
return [];
|
||||
}
|
||||
if (treeMap[id]?._grandChildren) {
|
||||
return treeMap[id]._grandChildren!;
|
||||
}
|
||||
const children = treeMap[id];
|
||||
|
||||
treeMap[id]._grandChildren = children._allChildren.reduce((res, curr) => {
|
||||
const cccc = getAllChildren(curr.id);
|
||||
return res.concat(cccc);
|
||||
}, children._allChildren);
|
||||
|
||||
return treeMap[id]._grandChildren!;
|
||||
}
|
||||
|
||||
for (const id in treeMap) {
|
||||
treeMap[id]._grandChildren = getAllChildren(id);
|
||||
Object.defineProperty(treeMap[id], '_allChildren', {
|
||||
enumerable: false,
|
||||
});
|
||||
Object.defineProperty(treeMap[id], '_grandChildren', {
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
treeMap,
|
||||
topLevelComponents,
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user