feat(runtime): use render set to check all the slot elements hidden or not

only attach fallback element to the last hidden slot
This commit is contained in:
Yanzhen Yu 2022-07-13 22:22:55 +08:00
parent 01404a2d20
commit bae3f5d5b7
6 changed files with 45 additions and 11 deletions

View File

@ -76,6 +76,28 @@
}
]
},
{
"id": "text_2",
"type": "core/v1/text",
"properties": {
"value": {
"raw": "also in tab3",
"format": "plain"
}
},
"traits": [
{
"type": "core/v1/slot",
"properties": {
"container": {
"id": "nested_tabs",
"slot": "content"
},
"ifCondition": "{{ $slot.tabIndex === 0 }}"
}
}
]
},
{
"id": "nested_tabs",
"type": "chakra_ui/v1/tabs",

View File

@ -23,7 +23,7 @@ export const ImplWrapper = React.memo<ImplWrapperProps>(
prevComponent === nextComponent &&
// TODO: keep ImplWrapper memorized and get slot props from store
shallowCompare(prevProps.slotProps, nextProps.slotProps) &&
shallowCompare(prevProps.slotFallback, nextProps.slotFallback)
shallowCompare(prevProps.slotContext, nextProps.slotContext)
);
}
);

View File

@ -161,7 +161,7 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
<Impl
ref={ref}
key={c.id}
{...omit(props, ['slotProps', 'slotFallback'])}
{...omit(props, ['slotProps', 'slotContext'])}
{...mergedProps}
slotsElements={slotElements}
mergeState={mergeState}

View File

@ -8,7 +8,7 @@ import { watch } from '../../..';
export const UnmountImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>(
function UnmountImplWrapper(props, ref) {
const { component: c, services, slotFallback } = props;
const { component: c, services, slotContext } = props;
const { stateManager, registry } = services;
const { executeTrait } = useRuntimeFunctions(props);
@ -76,10 +76,12 @@ export const UnmountImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperPr
initSingleComponentState(registry, stateManager, c);
}
return !isHidden ? (
<ImplWrapperMain {...props} ref={ref} />
) : slotFallback ? (
<>{slotFallback}</>
) : null;
if (isHidden && slotContext) {
slotContext.renderSet.delete(c.id);
if (slotContext.renderSet.size === 0) {
return <>{slotContext.fallback}</>;
}
}
return !isHidden ? <ImplWrapperMain {...props} ref={ref} /> : null;
}
);

View File

@ -18,9 +18,19 @@ export function getSlotElements(
});
slotElements[slot] = function getSlot(slotProps, slotFallback) {
return slotChildren.map(child =>
React.cloneElement(child, { slotProps, slotFallback })
const slotContext = {
renderSet: new Set(childrenMap[c.id][slot].map(child => child.id)),
parentId: c.id,
slotProps: JSON.stringify(slotProps),
fallback: slotFallback,
};
const children = slotChildren.map(child =>
React.cloneElement(child, {
slotProps,
slotContext,
})
);
return children;
};
}
return slotElements;

View File

@ -21,7 +21,7 @@ export type ImplWrapperProps<
app: RuntimeApplication;
evalListItem?: boolean;
slotProps?: unknown;
slotFallback?: React.ReactNode;
slotContext?: { renderSet: Set<string>; fallback?: React.ReactNode };
} & ComponentParamsFromApp;
export type ComponentImplProps<