mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-02-17 17:40:31 +08:00
misc update on router
1. update example page's title 2. pass params to ImplWrapper(currently not pass it to the component, need discussion on it)
This commit is contained in:
parent
619e86e526
commit
5bfc886b31
@ -6,7 +6,7 @@
|
|||||||
<script>
|
<script>
|
||||||
delete window.history;
|
delete window.history;
|
||||||
</script>
|
</script>
|
||||||
<title>meta-ui runtime example: nested components</title>
|
<title>meta-ui runtime example: hash router</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>meta-ui runtime example: nested components</title>
|
<title>meta-ui runtime example: nested hash router</title>
|
||||||
<script>
|
<script>
|
||||||
delete window.history;
|
delete window.history;
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>meta-ui runtime example: nested components</title>
|
<title>meta-ui runtime example: history router</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>meta-ui runtime example: nested components</title>
|
<title>meta-ui runtime example: nested router</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -30,146 +30,155 @@ const ImplWrapper = React.forwardRef<
|
|||||||
routerMap: RouterComponentMap | undefined;
|
routerMap: RouterComponentMap | undefined;
|
||||||
targetSlot: { id: string; slot: string } | null;
|
targetSlot: { id: string; slot: string } | null;
|
||||||
app: RuntimeApplication;
|
app: RuntimeApplication;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
>(({ component: c, slotsMap, routerMap, targetSlot, app, ...props }, ref) => {
|
>(
|
||||||
// TODO: find better way to add barrier
|
(
|
||||||
if (!stateStore[c.id]) {
|
{ component: c, slotsMap, routerMap, targetSlot, app, children, ...props },
|
||||||
stateStore[c.id] = {};
|
ref
|
||||||
}
|
) => {
|
||||||
|
// TODO: find better way to add barrier
|
||||||
|
if (!stateStore[c.id]) {
|
||||||
|
stateStore[c.id] = {};
|
||||||
|
}
|
||||||
|
|
||||||
const Impl = registry.getComponent(c.parsedType.version, c.parsedType.name)
|
const Impl = registry.getComponent(c.parsedType.version, c.parsedType.name)
|
||||||
.impl;
|
.impl;
|
||||||
|
|
||||||
const handlerMap = useRef<Record<string, (parameters?: any) => void>>({});
|
const handlerMap = useRef<Record<string, (parameters?: any) => void>>({});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (s: {
|
const handler = (s: {
|
||||||
componentId: string;
|
componentId: string;
|
||||||
name: string;
|
name: string;
|
||||||
parameters?: any;
|
parameters?: any;
|
||||||
}) => {
|
}) => {
|
||||||
if (s.componentId !== c.id) {
|
if (s.componentId !== c.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!handlerMap.current[s.name]) {
|
if (!handlerMap.current[s.name]) {
|
||||||
// maybe log?
|
// maybe log?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handlerMap.current[s.name](s.parameters);
|
handlerMap.current[s.name](s.parameters);
|
||||||
};
|
};
|
||||||
apiService.on("uiMethod", handler);
|
apiService.on("uiMethod", handler);
|
||||||
return () => {
|
return () => {
|
||||||
apiService.off("uiMethod", handler);
|
apiService.off("uiMethod", handler);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const mergeState = useCallback(
|
const mergeState = useCallback(
|
||||||
(partial: any) => {
|
(partial: any) => {
|
||||||
stateStore[c.id] = { ...stateStore[c.id], ...partial };
|
stateStore[c.id] = { ...stateStore[c.id], ...partial };
|
||||||
},
|
},
|
||||||
[c.id]
|
[c.id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subscribeMethods = useCallback(
|
const subscribeMethods = useCallback(
|
||||||
(map: any) => {
|
(map: any) => {
|
||||||
handlerMap.current = merge(handlerMap.current, map);
|
handlerMap.current = merge(handlerMap.current, map);
|
||||||
},
|
},
|
||||||
[handlerMap.current]
|
[handlerMap.current]
|
||||||
);
|
);
|
||||||
|
|
||||||
// traits
|
// traits
|
||||||
const [traitPropertiesMap, setTraitPropertiesMap] = useState<
|
const [traitPropertiesMap, setTraitPropertiesMap] = useState<
|
||||||
Map<typeof c["traits"][0], object>
|
Map<typeof c["traits"][0], object>
|
||||||
>(
|
>(
|
||||||
c.traits.reduce((prev, cur) => {
|
c.traits.reduce((prev, cur) => {
|
||||||
prev.set(cur, deepEval(cur.properties).result);
|
prev.set(cur, deepEval(cur.properties).result);
|
||||||
return prev;
|
return prev;
|
||||||
}, new Map())
|
}, new Map())
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const stops: ReturnType<typeof watch>[] = [];
|
const stops: ReturnType<typeof watch>[] = [];
|
||||||
for (const t of c.traits) {
|
for (const t of c.traits) {
|
||||||
const { stop, result } = deepEval(t.properties, ({ result }) => {
|
const { stop, result } = deepEval(t.properties, ({ result }) => {
|
||||||
|
setTraitPropertiesMap(
|
||||||
|
new Map(traitPropertiesMap.set(t, { ...result }))
|
||||||
|
);
|
||||||
|
});
|
||||||
setTraitPropertiesMap(
|
setTraitPropertiesMap(
|
||||||
new Map(traitPropertiesMap.set(t, { ...result }))
|
new Map(traitPropertiesMap.set(t, { ...result }))
|
||||||
);
|
);
|
||||||
|
stops.push(stop);
|
||||||
|
}
|
||||||
|
return () => stops.forEach((s) => s());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const traitsProps = {};
|
||||||
|
const wrappers: React.FC[] = [];
|
||||||
|
for (const t of c.traits) {
|
||||||
|
const tImpl = registry.getTrait(t.parsedType.version, t.parsedType.name)
|
||||||
|
.impl;
|
||||||
|
const { props: tProps, component: Wrapper } = tImpl({
|
||||||
|
...traitPropertiesMap.get(t),
|
||||||
|
mergeState,
|
||||||
|
subscribeMethods,
|
||||||
});
|
});
|
||||||
setTraitPropertiesMap(new Map(traitPropertiesMap.set(t, { ...result })));
|
merge(traitsProps, tProps);
|
||||||
stops.push(stop);
|
if (Wrapper) {
|
||||||
|
wrappers.push(Wrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return () => stops.forEach((s) => s());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const traitsProps = {};
|
const [mergedProps, setMergedProps] = useState(
|
||||||
const wrappers: React.FC[] = [];
|
deepEval({
|
||||||
for (const t of c.traits) {
|
...c.properties,
|
||||||
const tImpl = registry.getTrait(t.parsedType.version, t.parsedType.name)
|
...traitsProps,
|
||||||
.impl;
|
}).result
|
||||||
const { props: tProps, component: Wrapper } = tImpl({
|
);
|
||||||
...traitPropertiesMap.get(t),
|
useEffect(() => {
|
||||||
mergeState,
|
const rawProps: Record<string, unknown> = {
|
||||||
subscribeMethods,
|
...c.properties,
|
||||||
});
|
...traitsProps,
|
||||||
merge(traitsProps, tProps);
|
};
|
||||||
if (Wrapper) {
|
|
||||||
wrappers.push(Wrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [mergedProps, setMergedProps] = useState(
|
const { stop, result } = deepEval(rawProps, ({ result }) => {
|
||||||
deepEval({
|
setMergedProps({ ...result });
|
||||||
...c.properties,
|
});
|
||||||
...traitsProps,
|
|
||||||
}).result
|
|
||||||
);
|
|
||||||
useEffect(() => {
|
|
||||||
const rawProps: Record<string, unknown> = {
|
|
||||||
...c.properties,
|
|
||||||
...traitsProps,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { stop, result } = deepEval(rawProps, ({ result }) => {
|
|
||||||
setMergedProps({ ...result });
|
setMergedProps({ ...result });
|
||||||
});
|
return stop;
|
||||||
|
}, []);
|
||||||
|
|
||||||
setMergedProps({ ...result });
|
let C = (
|
||||||
return stop;
|
<Impl
|
||||||
}, []);
|
key={c.id}
|
||||||
|
{...mergedProps}
|
||||||
|
{...props}
|
||||||
|
mergeState={mergeState}
|
||||||
|
subscribeMethods={subscribeMethods}
|
||||||
|
slotsMap={slotsMap}
|
||||||
|
routerMap={routerMap}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
let C = (
|
while (wrappers.length) {
|
||||||
<Impl
|
const W = wrappers.pop()!;
|
||||||
key={c.id}
|
C = <W>{C}</W>;
|
||||||
{...mergedProps}
|
|
||||||
mergeState={mergeState}
|
|
||||||
subscribeMethods={subscribeMethods}
|
|
||||||
slotsMap={slotsMap}
|
|
||||||
routerMap={routerMap}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
while (wrappers.length) {
|
|
||||||
const W = wrappers.pop()!;
|
|
||||||
C = <W>{C}</W>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetSlot) {
|
|
||||||
const targetC = app.spec.components.find((c) => c.id === targetSlot.id);
|
|
||||||
if (targetC?.parsedType.name === "grid_layout") {
|
|
||||||
return (
|
|
||||||
<div key={c.id} data-meta-ui-id={c.id} ref={ref} {...props}>
|
|
||||||
{C}
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
if (targetSlot) {
|
||||||
<React.Fragment key={c.id}>
|
const targetC = app.spec.components.find((c) => c.id === targetSlot.id);
|
||||||
{C}
|
if (targetC?.parsedType.name === "grid_layout") {
|
||||||
{props.children}
|
return (
|
||||||
</React.Fragment>
|
<div key={c.id} data-meta-ui-id={c.id} ref={ref} {...props}>
|
||||||
);
|
{C}
|
||||||
});
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={c.id}>
|
||||||
|
{C}
|
||||||
|
{children}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const DebugStore: React.FC = () => {
|
const DebugStore: React.FC = () => {
|
||||||
const [store, setStore] = useState(stateStore);
|
const [store, setStore] = useState(stateStore);
|
||||||
|
@ -34,7 +34,6 @@ const useHashLocation = ({ base = "" } = {}): [
|
|||||||
const [loc, setLoc] = useState(currentLocation(base));
|
const [loc, setLoc] = useState(currentLocation(base));
|
||||||
const navigate = useCallback(
|
const navigate = useCallback(
|
||||||
(to: string) => {
|
(to: string) => {
|
||||||
console.log(base);
|
|
||||||
window.location.hash = base + to;
|
window.location.hash = base + to;
|
||||||
},
|
},
|
||||||
[base]
|
[base]
|
||||||
@ -73,7 +72,7 @@ export const RouterProvider: React.FC<{
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// all route-like component must have path property, router use path to determined if a component match the route
|
// all route-like component must have path property, wouter use path to determined if a component match the route
|
||||||
// but we need path to match both nested router itself and its child route, so we need to have an alternative property called base as the real path of the nested router
|
// but we need path to match both nested router itself and its child route, so we need to have an alternative property called base as the real path of the nested router
|
||||||
// and used by its children
|
// and used by its children
|
||||||
const NestedWouter: React.FC<{ path: string; base: string }> = ({
|
const NestedWouter: React.FC<{ path: string; base: string }> = ({
|
||||||
@ -108,9 +107,8 @@ const NestedWouter: React.FC<{ path: string; base: string }> = ({
|
|||||||
|
|
||||||
const Router: ComponentImplementation<{
|
const Router: ComponentImplementation<{
|
||||||
routerPolicy: Static<typeof RouterPolicyPropertySchema>;
|
routerPolicy: Static<typeof RouterPolicyPropertySchema>;
|
||||||
}> = ({ routerMap, routerPolicy, subscribeMethods }) => {
|
}> = ({ routerMap, routerPolicy, subscribeMethods, mergeState }) => {
|
||||||
const [, naviagte] = useLocation();
|
const [location, naviagte] = useLocation();
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const routes = useMemo(() => {
|
const routes = useMemo(() => {
|
||||||
let defaultPath: string | undefined = undefined;
|
let defaultPath: string | undefined = undefined;
|
||||||
@ -134,7 +132,7 @@ const Router: ComponentImplementation<{
|
|||||||
}
|
}
|
||||||
if (C.displayName === "router") {
|
if (C.displayName === "router") {
|
||||||
return (
|
return (
|
||||||
// it should match both itself and its children path, so we need to match its path itself
|
// it should match both itself and its children path
|
||||||
<NestedWouter
|
<NestedWouter
|
||||||
path={`(${path}|${path}/.*)`}
|
path={`(${path}|${path}/.*)`}
|
||||||
base={path}
|
base={path}
|
||||||
@ -146,7 +144,9 @@ const Router: ComponentImplementation<{
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Woute key={path} path={path}>
|
<Woute key={path} path={path}>
|
||||||
<C key={cid}></C>
|
{(params) => {
|
||||||
|
return <C {...params} key={cid}></C>;
|
||||||
|
}}
|
||||||
</Woute>
|
</Woute>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
@ -163,7 +163,8 @@ const Router: ComponentImplementation<{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, []);
|
}, [routerPolicy]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeMethods({
|
subscribeMethods({
|
||||||
navigate: (path: string) => {
|
navigate: (path: string) => {
|
||||||
@ -171,6 +172,14 @@ const Router: ComponentImplementation<{
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// to assign location as a state
|
||||||
|
mergeState({
|
||||||
|
route: location,
|
||||||
|
});
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
return <Switch children={routes}></Switch>;
|
return <Switch children={routes}></Switch>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user