mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2024-11-21 03:15:49 +08:00
implement nested router
This commit is contained in:
parent
61b9e897c6
commit
575e999785
222
packages/runtime/example/router/nested.html
Normal file
222
packages/runtime/example/router/nested.html
Normal file
@ -0,0 +1,222 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>meta-ui runtime example: nested components</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module">
|
||||
import renderApp from "../../src/main.tsx";
|
||||
renderApp({
|
||||
version: "example/v1",
|
||||
metadata: {
|
||||
name: "nested_components",
|
||||
description: "nested components example",
|
||||
},
|
||||
spec: {
|
||||
components: [
|
||||
{
|
||||
id: "parent",
|
||||
type: "core/v1/router",
|
||||
properties: {
|
||||
routerPolicy: [
|
||||
{
|
||||
type: "route",
|
||||
path: "/1",
|
||||
cid: "child1",
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
path: "/2",
|
||||
cid: "child2",
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: "child1",
|
||||
type: "core/v1/router",
|
||||
properties: {
|
||||
routerPolicy: [
|
||||
{
|
||||
type: "route",
|
||||
path: "/1",
|
||||
cid: "grandchild1_1",
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
path: "/2",
|
||||
cid: "grandchild1_2",
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
path: "/3",
|
||||
cid: "grandchild1_3",
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "parent",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "child2",
|
||||
type: "core/v1/router",
|
||||
properties: {
|
||||
routerPolicy: [
|
||||
{
|
||||
type: "route",
|
||||
path: "/1",
|
||||
cid: "grandchild2_1",
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
path: "/2",
|
||||
cid: "grandchild2_2",
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
path: "/3",
|
||||
cid: "grandchild2_3",
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "parent",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "grandchild1_1",
|
||||
type: "core/v1/text",
|
||||
properties: {
|
||||
value: {
|
||||
raw: "1_1",
|
||||
format: "plain",
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "child1",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "grandchild1_2",
|
||||
type: "core/v1/text",
|
||||
properties: {
|
||||
value: {
|
||||
raw: "1_2",
|
||||
format: "plain",
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "child1",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "grandchild1_3",
|
||||
type: "core/v1/text",
|
||||
properties: {
|
||||
value: {
|
||||
raw: "1_3",
|
||||
format: "plain",
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "child1",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "grandchild2_1",
|
||||
type: "core/v1/text",
|
||||
properties: {
|
||||
value: {
|
||||
raw: "2_1",
|
||||
format: "plain",
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "child2",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "grandchild2_2",
|
||||
type: "core/v1/text",
|
||||
properties: {
|
||||
value: {
|
||||
raw: "2_2",
|
||||
format: "plain",
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "child2",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "grandchild2_3",
|
||||
type: "core/v1/text",
|
||||
properties: {
|
||||
value: {
|
||||
raw: "2_3",
|
||||
format: "plain",
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/route",
|
||||
properties: {
|
||||
routerId: "child2",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -233,7 +233,7 @@ export type SlotsMap = Map<
|
||||
>;
|
||||
|
||||
export type RouterComponentsMap = Map<string, RouterComponentMap>;
|
||||
export type RouterComponentMap = Map<string, React.FC>;
|
||||
export type RouterComponentMap = Map<string, React.FC<any>>;
|
||||
|
||||
export function resolveAppComponents(
|
||||
app: RuntimeApplication
|
||||
|
@ -1,10 +1,4 @@
|
||||
import React, {
|
||||
useEffect,
|
||||
useMemo,
|
||||
createElement,
|
||||
useState,
|
||||
useRef,
|
||||
} from "react";
|
||||
import React, { useEffect, useMemo, useState, useRef } from "react";
|
||||
import { createComponent } from "@meta-ui/core";
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { ComponentImplementation } from "../../registry";
|
||||
@ -47,14 +41,10 @@ const matcher = makeCachedMatcher((path: string) => {
|
||||
return { keys, regexp };
|
||||
});
|
||||
|
||||
export const RouterProvider: React.FC<{ useRouter: boolean }> = ({
|
||||
useRouter,
|
||||
children,
|
||||
}) => {
|
||||
// TODO: use history api here;
|
||||
const hook =
|
||||
//useRef(useHashLocation);
|
||||
useRef(window.history ? undefined : useHashLocation);
|
||||
export const RouterProvider: React.FC<{
|
||||
useRouter: boolean;
|
||||
}> = ({ useRouter, children }) => {
|
||||
const hook = useRef(window.history ? undefined : useHashLocation);
|
||||
const base = useRef(location.pathname);
|
||||
return useRouter ? (
|
||||
<Wouter base={base.current} hook={hook.current} matcher={matcher}>
|
||||
@ -65,10 +55,37 @@ export const RouterProvider: React.FC<{ useRouter: boolean }> = ({
|
||||
);
|
||||
};
|
||||
|
||||
// all route-like component must have path property, router use path to determined if a component match the route
|
||||
const NestedWouter: React.FC<{ path: string; base: string }> = ({
|
||||
children,
|
||||
path,
|
||||
base,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const [parentLocation] = useLocation();
|
||||
|
||||
const nestedBase = `${router.base}${base}`;
|
||||
|
||||
// don't render anything outside of the scope
|
||||
if (!parentLocation.startsWith(base)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// we need key to make sure the router will remount if the base changes
|
||||
return (
|
||||
<Wouter base={nestedBase} key={nestedBase}>
|
||||
{children}
|
||||
</Wouter>
|
||||
);
|
||||
};
|
||||
|
||||
// const Default = React.FC<{}>
|
||||
|
||||
const Router: ComponentImplementation<{
|
||||
routerPolicy: Static<typeof RouterPolicyPropertySchema>;
|
||||
}> = ({ routerMap, routerPolicy, subscribeMethods }) => {
|
||||
const [parentPath, naviagte] = useLocation();
|
||||
const [, naviagte] = useLocation();
|
||||
const router = useRouter();
|
||||
|
||||
const routes = useMemo(() => {
|
||||
let defaultPath: string | undefined = undefined;
|
||||
@ -81,7 +98,7 @@ const Router: ComponentImplementation<{
|
||||
switch (type.toUpperCase()) {
|
||||
case RouteType.REDIRECT:
|
||||
return (
|
||||
<Woute path={path}>
|
||||
<Woute key={path} path={path}>
|
||||
<Redirect href={href || path} />
|
||||
</Woute>
|
||||
);
|
||||
@ -92,15 +109,18 @@ const Router: ComponentImplementation<{
|
||||
}
|
||||
if (C.displayName === "router") {
|
||||
return (
|
||||
<Woute path={path}>
|
||||
<Wouter base={`${parentPath}/${path}`}>
|
||||
<C key={cid}></C>
|
||||
</Wouter>
|
||||
</Woute>
|
||||
// it should match both itself and its children path, so we need to match its path itself
|
||||
<NestedWouter
|
||||
path={`(${path}|${path}/.*)`}
|
||||
base={path}
|
||||
key={path}
|
||||
>
|
||||
<C key={cid}></C>
|
||||
</NestedWouter>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Woute path={path}>
|
||||
<Woute key={path} path={path}>
|
||||
<C key={cid}></C>
|
||||
</Woute>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user