]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
chore: add nested and layouts
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 25 Jul 2025 12:35:13 +0000 (14:35 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Fri, 25 Jul 2025 12:35:13 +0000 (14:35 +0200)
packages/experiments-playground/src/App.vue
packages/experiments-playground/src/assets/main.css
packages/experiments-playground/src/pages/nested.vue [new file with mode: 0644]
packages/experiments-playground/src/router/index.ts
packages/router/src/experimental/index.ts

index db6d3c358371c9d96c01869a0340c5975e4db938..3518cfd5e923eb52365c824482eb4be3279f1a94 100644 (file)
@@ -1,7 +1,10 @@
 <script setup lang="ts">
-import { useRoute } from 'vue-router'
+import { ref } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
 
 const route = useRoute()
+const router = useRouter()
+const url = ref('')
 </script>
 
 <template>
@@ -10,7 +13,19 @@ const route = useRoute()
       <RouterLink to="/">Home</RouterLink>
       |
       <RouterLink to="/about">About</RouterLink>
+      |
+      <RouterLink to="/nested">Nested</RouterLink>
     </nav>
+    <form @submit.prevent="router.push(url)">
+      <label for="path">Path:</label>
+      <input
+        id="path"
+        type="text"
+        v-model="url"
+        placeholder="/go/somewhere?nice"
+      />
+      <button type="submit">Go</button>
+    </form>
   </header>
 
   <p>
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4b9521c7d7793c4b003d20674af426ed482ef1a8 100644 (file)
@@ -0,0 +1,3 @@
+:root {
+  color-scheme: light dark;
+}
diff --git a/packages/experiments-playground/src/pages/nested.vue b/packages/experiments-playground/src/pages/nested.vue
new file mode 100644 (file)
index 0000000..f0984a0
--- /dev/null
@@ -0,0 +1,9 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div>
+    <h1>Nested.vue</h1>
+
+    <RouterView />
+  </div>
+</template>
index 078ba57b7bf9ce11786746452a0507c9b51798ca..64db4029d70b06c1bd3d0b67afe34f2e88933b4b 100644 (file)
@@ -12,6 +12,18 @@ import type {
 } from 'vue-router/experimental'
 import PageHome from '../pages/(home).vue'
 
+type ExtractMatcherQueryParams<T> =
+  T extends MatcherPatternQuery<infer P> ? P : never
+
+// type CombineMatcherParams<T extends readonly MatcherPatternQuery[]> =
+//   T extends readonly [infer First, ...infer Rest]
+//     ? First extends MatcherPatternQuery
+//       ? Rest extends readonly MatcherPatternQuery[]
+//         ? ExtractMatcherQueryParams<First> & CombineMatcherParams<Rest>
+//         : ExtractMatcherQueryParams<First>
+//       : never
+//     : {}
+
 const PAGE_QUERY_PATTERN_MATCHER: MatcherPatternQuery<{ page: number }> = {
   match: query => {
     const page = Number(query.page)
@@ -22,16 +34,77 @@ const PAGE_QUERY_PATTERN_MATCHER: MatcherPatternQuery<{ page: number }> = {
   build: params => ({ page: String(params.page) }),
 }
 
+const QUERY_PATTERN_MATCHER: MatcherPatternQuery<{ q: string }> = {
+  match: query => {
+    return {
+      q: typeof query.q === 'string' ? query.q : '',
+    }
+  },
+  build: params => {
+    return { q: params.q || '' }
+  },
+}
+
+// function combineQueryMatchers<const T extends MatcherPatternQuery[]>(
+//   ...matchers: T
+// ): MatcherPatternQuery<CombineMatcherParams<T>> {
+//   return {
+//     match: (query: MatcherQueryParams): CombineMatcherParams<T> => {
+//       return matchers.reduce((acc, matcher) => {
+//         return { ...acc, ...matcher.match(query) }
+//       }, {} as CombineMatcherParams<T>)
+//     },
+//     build: (
+//       params: CombineMatcherParams<T>
+//     ): Record<string, string | string[]> => {
+//       return matchers.reduce(
+//         (acc, matcher) => {
+//           return { ...acc, ...matcher.build(params) }
+//         },
+//         {} as Record<string, string | string[]>
+//       )
+//     },
+//   }
+// }
+//
+// const a = combineQueryMatchers(
+//   PAGE_QUERY_PATTERN_MATCHER,
+//   QUERY_PATTERN_MATCHER
+// )
+
+const QUERY_MATCHER_COMBINED: MatcherPatternQuery<{
+  page: number
+  q: string
+}> = {
+  match: query => {
+    return {
+      ...PAGE_QUERY_PATTERN_MATCHER.match(query),
+      ...QUERY_PATTERN_MATCHER.match(query),
+    }
+  },
+  build: params => ({
+    ...PAGE_QUERY_PATTERN_MATCHER.build(params),
+    ...QUERY_PATTERN_MATCHER.build(params),
+  }),
+}
+
 const ANY_HASH_PATTERN_MATCHER: MatcherPatternHash<// hash could be named anything, in this case it creates a param named hash
 { hash: string | null }> = {
   match: hash => ({ hash: hash ? hash.slice(1) : null }),
   build: ({ hash }) => (hash ? `#${hash}` : ''),
 }
 
+const r_group = normalizeRouteRecord({
+  meta: {
+    fromGroup: 'r_group',
+  },
+})
+
 const r_home = normalizeRouteRecord({
   name: 'home',
   path: new MatcherPatternPathStatic('/'),
-  query: PAGE_QUERY_PATTERN_MATCHER,
+  query: QUERY_MATCHER_COMBINED,
+  parent: r_group,
   components: { default: PageHome },
 })
 
@@ -42,10 +115,32 @@ const r_about = normalizeRouteRecord({
   components: { default: () => import('../pages/about.vue') },
 })
 
+const r_profile_layout = normalizeRouteRecord({
+  components: {},
+  meta: {
+    layout: 'profile',
+  },
+})
+
+const r_nested = normalizeRouteRecord({
+  name: 'nested',
+  components: { default: () => import('../pages/nested.vue') },
+  path: new MatcherPatternPathStatic('/nested'),
+})
+
+const r_nested_a = normalizeRouteRecord({
+  name: 'nested-a',
+  components: { default: () => import('../pages/nested/a.vue') },
+  parent: r_nested,
+  path: new MatcherPatternPathStatic('/nested/a'),
+})
+
 export const router = experimental_createRouter({
-  history: createWebHistory(import.meta.env.BASE_URL),
+  history: createWebHistory(),
   resolver: createStaticResolver<EXPERIMENTAL_RouteRecordNormalized_Matchable>([
     r_home,
     r_about,
+    r_nested,
+    r_nested_a,
   ]),
 })
index 30ec7c68e7b41791b27836401c0bfa8ab8318c1c..8af1615a3647ac93644699bb70d1368f44383a9e 100644 (file)
@@ -14,6 +14,10 @@ export type {
 } from './router'
 
 export { createStaticResolver } from './route-resolver/resolver-static'
+export type {
+  MatcherQueryParams,
+  MatcherQueryParamsValue,
+} from './route-resolver/resolver'
 export {
   MatcherPatternPathDynamic,
   MatcherPatternPathStatic,