@ktjs/router 0.38.0 → 0.38.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -2
- package/dist/index.mjs +30 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -104,8 +104,11 @@ interface NavOptions extends NavBaseOptions {
|
|
|
104
104
|
* Router configuration
|
|
105
105
|
*/
|
|
106
106
|
interface RouterConfig {
|
|
107
|
+
/** Routing mode. Default is history mode */
|
|
108
|
+
mode?: 'history' | 'hash';
|
|
109
|
+
|
|
107
110
|
/**
|
|
108
|
-
*
|
|
111
|
+
* Optional route prefix (for deployments under sub-paths)
|
|
109
112
|
*/
|
|
110
113
|
prefix?: string;
|
|
111
114
|
|
|
@@ -173,7 +176,7 @@ declare function KTRouter({ router }: {
|
|
|
173
176
|
/**
|
|
174
177
|
* Create a new router instance
|
|
175
178
|
*/
|
|
176
|
-
declare const createRouter: ({ beforeEach, afterEach, onNotFound, onError, prefix, routes: rawRoutes, }: RouterConfig) => Router;
|
|
179
|
+
declare const createRouter: ({ beforeEach, afterEach, onNotFound, onError, mode, prefix, routes: rawRoutes, }: RouterConfig) => Router;
|
|
177
180
|
|
|
178
181
|
export { GuardLevel, KTRouter, createRouter };
|
|
179
182
|
export type { NavOptions, RawRouteConfig, RouteConfig, RouteContext, RouteMatch, Router, RouterConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -5,8 +5,8 @@ function KTRouter({router: router}) {
|
|
|
5
5
|
return router.setRouterView(view), view;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach = $emptyFn, onNotFound: onNotFound = $emptyFn, onError: onError = $emptyFn, prefix: prefix = "", routes: rawRoutes}) => {
|
|
9
|
-
const routes = [], matchedMap = new Map, history = [], prefixPath = prefix ? normalizePath(prefix) : "";
|
|
8
|
+
const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach = $emptyFn, onNotFound: onNotFound = $emptyFn, onError: onError = $emptyFn, mode: mode = "history", prefix: prefix = "", routes: rawRoutes}) => {
|
|
9
|
+
const routes = [], matchedMap = new Map, history = [], prefixPath = prefix ? normalizePath(prefix) : "", isHashMode = "hash" === mode;
|
|
10
10
|
let routerView = null, current = null, ignoreNextHashChange = !1;
|
|
11
11
|
const normalize = (rawRoutes, parentPath, parentMatched) => rawRoutes.map(route => {
|
|
12
12
|
const path = normalizePath(parentPath, route.path), normalized = {
|
|
@@ -97,11 +97,15 @@ const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach =
|
|
|
97
97
|
to: to,
|
|
98
98
|
fullPath: fullPath
|
|
99
99
|
};
|
|
100
|
-
}, commit = async (to, fullPath, replaceHistory,
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
}, commit = async (to, fullPath, replaceHistory, urlMode) => {
|
|
101
|
+
if (urlMode) if (isHashMode) {
|
|
102
|
+
if (window.location.hash.slice(1) !== fullPath) {
|
|
103
|
+
ignoreNextHashChange = !0;
|
|
104
|
+
const hashUrl = "#" + fullPath;
|
|
105
|
+
"replace" === urlMode ? window.location.replace(hashUrl) : window.location.hash = fullPath;
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
window.location.pathname + window.location.search !== fullPath && ("replace" === urlMode ? window.history.replaceState(null, "", fullPath) : window.history.pushState(null, "", fullPath));
|
|
105
109
|
}
|
|
106
110
|
const from = current;
|
|
107
111
|
if (current = to, replaceHistory && history.length > 0 ? history[history.length - 1] = to : history.push(to),
|
|
@@ -163,7 +167,16 @@ const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach =
|
|
|
163
167
|
return null;
|
|
164
168
|
}
|
|
165
169
|
};
|
|
166
|
-
})(routes, matchedMap),
|
|
170
|
+
})(routes, matchedMap), handlePopState = async () => {
|
|
171
|
+
const fullPath = window.location.pathname + window.location.search, prep = navigatePrepare(normalizeLocation(fullPath));
|
|
172
|
+
if (!prep) return;
|
|
173
|
+
const {guardLevel: guardLevel, to: to} = prep, guardResult = await guard(to, current, guardLevel);
|
|
174
|
+
if (!guardResult.continue) return guardResult.redirectTo ? void await navigate({
|
|
175
|
+
...guardResult.redirectTo,
|
|
176
|
+
replace: !0
|
|
177
|
+
}) : void (current && window.history.pushState(null, "", current.path + buildQuery(current.query)));
|
|
178
|
+
await commit(to, fullPath, !1, null);
|
|
179
|
+
}, handleHashChange = async () => {
|
|
167
180
|
if (ignoreNextHashChange) return void (ignoreNextHashChange = !1);
|
|
168
181
|
const hash = window.location.hash.slice(1);
|
|
169
182
|
if (!hash) return;
|
|
@@ -176,8 +189,10 @@ const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach =
|
|
|
176
189
|
}) : (ignoreNextHashChange = !0, void (current ? window.location.replace("#" + current.path + buildQuery(current.query)) : window.location.replace(window.location.pathname + window.location.search)));
|
|
177
190
|
await commit(to, fullPath, !1, fullPath === hash ? null : "replace");
|
|
178
191
|
};
|
|
179
|
-
window.addEventListener("hashchange", () => {
|
|
192
|
+
isHashMode ? window.addEventListener("hashchange", () => {
|
|
180
193
|
handleHashChange();
|
|
194
|
+
}) : window.addEventListener("popstate", () => {
|
|
195
|
+
handlePopState();
|
|
181
196
|
});
|
|
182
197
|
const instance = {
|
|
183
198
|
get current() {
|
|
@@ -214,7 +229,12 @@ const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach =
|
|
|
214
229
|
window.history.forward();
|
|
215
230
|
}
|
|
216
231
|
};
|
|
217
|
-
|
|
232
|
+
if (isHashMode) {
|
|
233
|
+
window.location.hash.slice(1) && handleHashChange();
|
|
234
|
+
} else {
|
|
235
|
+
("/" !== window.location.pathname + window.location.search || window.location.search) && handlePopState();
|
|
236
|
+
}
|
|
237
|
+
return instance;
|
|
218
238
|
};
|
|
219
239
|
|
|
220
240
|
export { KTRouter, createRouter };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/core/kt-router.ts","../src/core/index.ts","../src/core/matcher.ts"],"sourcesContent":["import type { JSX } from '@ktjs/core/jsx-runtime';\nimport type { Router } from '../types/router.js';\n\n/**\n * Create a router view container that automatically renders route components\n */\nexport function KTRouter({ router }: { router: Router }): JSX.Element {\n const view = document.createElement('kt-router-view');\n router.setRouterView(view);\n return view as JSX.Element;\n}\n","import { $emptyFn, buildQuery, normalizePath, parseQuery, emplaceParams } from '@ktjs/shared';\n\nimport type { Router, RouterConfig, RouteContext, NavOptions, RawRouteConfig, RouteConfig } from '../types/router.js';\nimport { GuardLevel } from './consts.js';\nimport { createMatcher } from './matcher.js';\n\n/**\n * Create a new router instance\n */\nexport const createRouter = ({\n beforeEach = $emptyFn,\n afterEach = $emptyFn,\n onNotFound = $emptyFn,\n onError = $emptyFn,\n prefix = '',\n routes: rawRoutes,\n}: RouterConfig): Router => {\n // # private values\n const routes: RouteConfig[] = [];\n const matchedMap = new Map<RouteConfig, RouteConfig[]>();\n const history: RouteContext[] = [];\n const prefixPath = prefix ? normalizePath(prefix) : '';\n let routerView: HTMLElement | null = null;\n let current: RouteContext | null = null;\n let ignoreNextHashChange = false;\n\n // # methods\n const normalize = (rawRoutes: RawRouteConfig[], parentPath: string, parentMatched: RouteConfig[]): RouteConfig[] =>\n rawRoutes.map((route) => {\n const path = normalizePath(parentPath, route.path);\n const normalized: RouteConfig = {\n path: prefixPath ? normalizePath(prefixPath, path) : path,\n name: route.name,\n meta: route.meta ?? {},\n beforeEnter: route.beforeEnter ?? $emptyFn,\n after: route.after ?? $emptyFn,\n children: [],\n component: route.component,\n };\n const matched = parentMatched.concat(normalized);\n matchedMap.set(normalized, matched);\n normalized.children = route.children ? normalize(route.children, path, matched) : [];\n\n // directly push the normalized route to the list\n // avoid flatten them again\n routes.push(normalized);\n return normalized;\n });\n\n normalize(rawRoutes, '/', []);\n\n const guard = async (\n to: RouteContext,\n from: RouteContext | null,\n guardLevel: GuardLevel,\n ): Promise<{ continue: boolean; redirectTo?: NavOptions }> => {\n try {\n if (guardLevel === GuardLevel.None) {\n return { continue: true };\n }\n\n if (guardLevel & GuardLevel.Global) {\n const result = await beforeEach(to, from);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n if (guardLevel & GuardLevel.Route) {\n const targetRoute = to.matched[to.matched.length - 1];\n const result = await targetRoute.beforeEnter(to);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n return { continue: true };\n } catch (error) {\n onError(error as Error);\n return { continue: false };\n }\n };\n\n const navigatePrepare = (options: NavOptions) => {\n // Resolve target route\n let targetPath: string;\n\n if (options.name) {\n const targetRoute = findByName(options.name);\n if (!targetRoute) {\n $throw(`Route not found: ${options.name}`);\n }\n targetPath = targetRoute.path;\n } else if (options.path) {\n targetPath = normalizePath(options.path);\n if (prefixPath && targetPath !== prefixPath && !targetPath.startsWith(prefixPath + '/')) {\n targetPath = normalizePath(prefixPath, targetPath);\n }\n } else {\n $throw(`Either path or name must be provided`);\n }\n\n // Substitute params\n if (options.params) {\n targetPath = emplaceParams(targetPath, options.params);\n }\n\n // Match final path\n const matched = match(targetPath);\n if (!matched) {\n onNotFound(targetPath);\n return null;\n }\n\n // Build route context\n const queryString = options.query ? buildQuery(options.query) : '';\n const fullPath = targetPath + queryString;\n\n const to: RouteContext = {\n path: targetPath,\n name: matched.route.name ?? '',\n params: { ...matched.params, ...(options.params ?? {}) },\n query: options.query ?? {},\n meta: matched.route.meta ?? {},\n matched: matched.result,\n };\n\n return {\n guardLevel: options.guardLevel ?? GuardLevel.Default,\n replace: options.replace ?? false,\n to,\n fullPath,\n };\n };\n\n const commit = async (\n to: RouteContext,\n fullPath: string,\n replaceHistory: boolean,\n hashMode: 'push' | 'replace' | null,\n ): Promise<void> => {\n if (hashMode && window.location.hash.slice(1) !== fullPath) {\n ignoreNextHashChange = true;\n const hashUrl = '#' + fullPath;\n if (hashMode === 'replace') {\n window.location.replace(hashUrl);\n } else {\n window.location.hash = fullPath;\n }\n }\n\n const from = current;\n current = to;\n if (replaceHistory) {\n if (history.length > 0) {\n history[history.length - 1] = to;\n } else {\n history.push(to);\n }\n } else {\n history.push(to);\n }\n\n if (routerView && to.matched.length > 0) {\n const route = to.matched[to.matched.length - 1];\n const element = await route.component();\n routerView.innerHTML = '';\n routerView.appendChild(element);\n }\n\n void executeAfterHooks(to, from).catch((error) => {\n onError(error as Error, to.matched[to.matched.length - 1]);\n });\n };\n\n const navigate = async (options: NavOptions, redirectCount = 0): Promise<boolean> => {\n try {\n // Prevent infinite redirect loop\n if (redirectCount > 10) {\n onError(new Error('Maximum redirect count exceeded'));\n return false;\n }\n\n const prep = navigatePrepare(options);\n if (!prep) {\n return false;\n }\n\n const { guardLevel, replace, to, fullPath } = prep;\n\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n // Check if there's a redirect\n if (guardResult.redirectTo) {\n return await navigate(guardResult.redirectTo, redirectCount + 1);\n }\n return false;\n }\n\n // ---- Guards passed ----\n await commit(to, fullPath, replace, replace ? 'replace' : 'push');\n return true;\n } catch (error) {\n onError(error as Error);\n return false;\n }\n };\n\n const executeAfterHooks = async (to: RouteContext, from: RouteContext | null): Promise<void> => {\n const targetRoute = to.matched[to.matched.length - 1];\n await targetRoute.after(to);\n await afterEach(to, from);\n };\n\n /**\n * Normalize navigation argument\n */\n const normalizeLocation = (loc: string | NavOptions): NavOptions => {\n if (typeof loc !== 'string') {\n return loc;\n }\n\n const [path, queryString] = loc.split('?');\n return {\n path,\n query: queryString ? parseQuery(queryString) : undefined,\n };\n };\n\n const { findByName, match } = createMatcher(routes, matchedMap);\n\n const handleHashChange = async () => {\n if (ignoreNextHashChange) {\n ignoreNextHashChange = false;\n return;\n }\n\n const hash = window.location.hash.slice(1);\n if (!hash) {\n return;\n }\n\n const prep = navigatePrepare(normalizeLocation(hash));\n if (!prep) {\n return;\n }\n\n const { guardLevel, to, fullPath } = prep;\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n if (guardResult.redirectTo) {\n await navigate({ ...guardResult.redirectTo, replace: true });\n return;\n }\n\n ignoreNextHashChange = true;\n if (current) {\n window.location.replace('#' + current.path + buildQuery(current.query));\n } else {\n window.location.replace(window.location.pathname + window.location.search);\n }\n return;\n }\n\n await commit(to, fullPath, false, fullPath === hash ? null : 'replace');\n };\n\n // # register events\n window.addEventListener('hashchange', () => {\n void handleHashChange();\n });\n\n // # initialize\n const instance: Router = {\n get current() {\n return current;\n },\n\n get history() {\n return history.concat();\n },\n\n setRouterView(view: HTMLElement) {\n routerView = view;\n },\n\n push(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate(options);\n },\n\n silentPush(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, guardLevel: GuardLevel.Route });\n },\n\n replace(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, replace: true });\n },\n\n back() {\n window.history.back();\n },\n\n forward() {\n window.history.forward();\n },\n };\n const currentHash = window.location.hash.slice(1);\n if (currentHash) {\n void handleHashChange();\n }\n\n return instance;\n};\n\nexport { GuardLevel };\nexport { KTRouter } from './kt-router.js';\n","import type { RouteConfig, RouteMatch } from '../types/router.js';\nimport { extractParams, normalizePath } from '@ktjs/shared';\n\n/**\n * Route matcher for finding matching routes and extracting params\n */\nexport const createMatcher = (routes: RouteConfig[], matchedMap: Map<RouteConfig, RouteConfig[]>) => {\n const nameMap: Record<string, RouteConfig> = {};\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i];\n if (route.name !== undefined) {\n if (route.name in nameMap) {\n $throw(`Duplicate route name detected: '${route.name}'`);\n }\n nameMap[route.name] = route;\n }\n }\n\n /**\n * Find route by name\n */\n const findByName = (name: string): RouteConfig | null => {\n return nameMap[name] ?? null;\n };\n\n /**\n * Match path against all routes\n */\n const match = (path: string): RouteMatch | null => {\n const normalizedPath = normalizePath(path);\n\n // Try exact match first\n for (const route of routes) {\n if (route.path === normalizedPath) {\n return {\n route,\n params: {},\n result: matchedMap.get(route) ?? [route],\n };\n }\n }\n\n // Try dynamic routes\n for (const route of routes) {\n if (route.path.includes(':')) {\n const params = extractParams(route.path, normalizedPath);\n if (params) {\n return {\n route,\n params,\n result: matchedMap.get(route) ?? [route],\n };\n }\n }\n }\n\n return null;\n };\n\n return {\n findByName,\n match,\n };\n};\n"],"names":["KTRouter","router","view","document","createElement","setRouterView","createRouter","beforeEach","$emptyFn","afterEach","onNotFound","onError","prefix","routes","rawRoutes","matchedMap","Map","history","prefixPath","normalizePath","routerView","current","ignoreNextHashChange","normalize","parentPath","parentMatched","map","route","path","normalized","name","meta","beforeEnter","after","children","component","matched","concat","set","push","guard","async","to","from","guardLevel","continue","result","redirectTo","targetRoute","length","error","navigatePrepare","options","targetPath","findByName","Error","startsWith","params","emplaceParams","match","fullPath","query","buildQuery","replace","commit","replaceHistory","hashMode","window","location","hash","slice","hashUrl","element","innerHTML","appendChild","executeAfterHooks","catch","navigate","redirectCount","prep","guardResult","normalizeLocation","loc","queryString","split","parseQuery","undefined","nameMap","i","normalizedPath","get","includes","extractParams","createMatcher","handleHashChange","pathname","search","addEventListener","instance","silentPush","back","forward"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/core/kt-router.ts","../src/core/index.ts","../src/core/matcher.ts"],"sourcesContent":["import type { JSX } from '@ktjs/core/jsx-runtime';\nimport type { Router } from '../types/router.js';\n\n/**\n * Create a router view container that automatically renders route components\n */\nexport function KTRouter({ router }: { router: Router }): JSX.Element {\n const view = document.createElement('kt-router-view');\n router.setRouterView(view);\n return view as JSX.Element;\n}\n","import { $emptyFn, buildQuery, normalizePath, parseQuery, emplaceParams } from '@ktjs/shared';\n\nimport type { Router, RouterConfig, RouteContext, NavOptions, RawRouteConfig, RouteConfig } from '../types/router.js';\nimport { GuardLevel } from './consts.js';\nimport { createMatcher } from './matcher.js';\n\n/**\n * Create a new router instance\n */\nexport const createRouter = ({\n beforeEach = $emptyFn,\n afterEach = $emptyFn,\n onNotFound = $emptyFn,\n onError = $emptyFn,\n mode = 'history',\n prefix = '',\n routes: rawRoutes,\n}: RouterConfig): Router => {\n // # private values\n const routes: RouteConfig[] = [];\n const matchedMap = new Map<RouteConfig, RouteConfig[]>();\n const history: RouteContext[] = [];\n const prefixPath = prefix ? normalizePath(prefix) : '';\n const isHashMode = mode === 'hash';\n let routerView: HTMLElement | null = null;\n let current: RouteContext | null = null;\n let ignoreNextHashChange = false;\n\n // # methods\n const normalize = (rawRoutes: RawRouteConfig[], parentPath: string, parentMatched: RouteConfig[]): RouteConfig[] =>\n rawRoutes.map((route) => {\n const path = normalizePath(parentPath, route.path);\n const normalized: RouteConfig = {\n path: prefixPath ? normalizePath(prefixPath, path) : path,\n name: route.name,\n meta: route.meta ?? {},\n beforeEnter: route.beforeEnter ?? $emptyFn,\n after: route.after ?? $emptyFn,\n children: [],\n component: route.component,\n };\n const matched = parentMatched.concat(normalized);\n matchedMap.set(normalized, matched);\n normalized.children = route.children ? normalize(route.children, path, matched) : [];\n\n // directly push the normalized route to the list\n // avoid flatten them again\n routes.push(normalized);\n return normalized;\n });\n\n normalize(rawRoutes, '/', []);\n\n const guard = async (\n to: RouteContext,\n from: RouteContext | null,\n guardLevel: GuardLevel,\n ): Promise<{ continue: boolean; redirectTo?: NavOptions }> => {\n try {\n if (guardLevel === GuardLevel.None) {\n return { continue: true };\n }\n\n if (guardLevel & GuardLevel.Global) {\n const result = await beforeEach(to, from);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n if (guardLevel & GuardLevel.Route) {\n const targetRoute = to.matched[to.matched.length - 1];\n const result = await targetRoute.beforeEnter(to);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n return { continue: true };\n } catch (error) {\n onError(error as Error);\n return { continue: false };\n }\n };\n\n const navigatePrepare = (options: NavOptions) => {\n // Resolve target route\n let targetPath: string;\n\n if (options.name) {\n const targetRoute = findByName(options.name);\n if (!targetRoute) {\n $throw(`Route not found: ${options.name}`);\n }\n targetPath = targetRoute.path;\n } else if (options.path) {\n targetPath = normalizePath(options.path);\n if (prefixPath && targetPath !== prefixPath && !targetPath.startsWith(prefixPath + '/')) {\n targetPath = normalizePath(prefixPath, targetPath);\n }\n } else {\n $throw(`Either path or name must be provided`);\n }\n\n // Substitute params\n if (options.params) {\n targetPath = emplaceParams(targetPath, options.params);\n }\n\n // Match final path\n const matched = match(targetPath);\n if (!matched) {\n onNotFound(targetPath);\n return null;\n }\n\n // Build route context\n const queryString = options.query ? buildQuery(options.query) : '';\n const fullPath = targetPath + queryString;\n\n const to: RouteContext = {\n path: targetPath,\n name: matched.route.name ?? '',\n params: { ...matched.params, ...(options.params ?? {}) },\n query: options.query ?? {},\n meta: matched.route.meta ?? {},\n matched: matched.result,\n };\n\n return {\n guardLevel: options.guardLevel ?? GuardLevel.Default,\n replace: options.replace ?? false,\n to,\n fullPath,\n };\n };\n\n const commit = async (\n to: RouteContext,\n fullPath: string,\n replaceHistory: boolean,\n urlMode: 'push' | 'replace' | null,\n ): Promise<void> => {\n if (urlMode) {\n if (isHashMode) {\n if (window.location.hash.slice(1) !== fullPath) {\n ignoreNextHashChange = true;\n const hashUrl = '#' + fullPath;\n if (urlMode === 'replace') {\n window.location.replace(hashUrl);\n } else {\n window.location.hash = fullPath;\n }\n }\n } else {\n const currentFullPath = window.location.pathname + window.location.search;\n if (currentFullPath !== fullPath) {\n if (urlMode === 'replace') {\n window.history.replaceState(null, '', fullPath);\n } else {\n window.history.pushState(null, '', fullPath);\n }\n }\n }\n }\n\n const from = current;\n current = to;\n if (replaceHistory) {\n if (history.length > 0) {\n history[history.length - 1] = to;\n } else {\n history.push(to);\n }\n } else {\n history.push(to);\n }\n\n if (routerView && to.matched.length > 0) {\n const route = to.matched[to.matched.length - 1];\n const element = await route.component();\n routerView.innerHTML = '';\n routerView.appendChild(element);\n }\n\n void executeAfterHooks(to, from).catch((error) => {\n onError(error as Error, to.matched[to.matched.length - 1]);\n });\n };\n\n const navigate = async (options: NavOptions, redirectCount = 0): Promise<boolean> => {\n try {\n // Prevent infinite redirect loop\n if (redirectCount > 10) {\n onError(new Error('Maximum redirect count exceeded'));\n return false;\n }\n\n const prep = navigatePrepare(options);\n if (!prep) {\n return false;\n }\n\n const { guardLevel, replace, to, fullPath } = prep;\n\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n // Check if there's a redirect\n if (guardResult.redirectTo) {\n return await navigate(guardResult.redirectTo, redirectCount + 1);\n }\n return false;\n }\n\n // ---- Guards passed ----\n await commit(to, fullPath, replace, replace ? 'replace' : 'push');\n return true;\n } catch (error) {\n onError(error as Error);\n return false;\n }\n };\n\n const executeAfterHooks = async (to: RouteContext, from: RouteContext | null): Promise<void> => {\n const targetRoute = to.matched[to.matched.length - 1];\n await targetRoute.after(to);\n await afterEach(to, from);\n };\n\n /**\n * Normalize navigation argument\n */\n const normalizeLocation = (loc: string | NavOptions): NavOptions => {\n if (typeof loc !== 'string') {\n return loc;\n }\n\n const [path, queryString] = loc.split('?');\n return {\n path,\n query: queryString ? parseQuery(queryString) : undefined,\n };\n };\n\n const { findByName, match } = createMatcher(routes, matchedMap);\n\n const handlePopState = async () => {\n const fullPath = window.location.pathname + window.location.search;\n const prep = navigatePrepare(normalizeLocation(fullPath));\n if (!prep) {\n return;\n }\n\n const { guardLevel, to } = prep;\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n if (guardResult.redirectTo) {\n await navigate({ ...guardResult.redirectTo, replace: true });\n return;\n }\n\n if (current) {\n window.history.pushState(null, '', current.path + buildQuery(current.query));\n }\n return;\n }\n\n await commit(to, fullPath, false, null);\n };\n\n const handleHashChange = async () => {\n if (ignoreNextHashChange) {\n ignoreNextHashChange = false;\n return;\n }\n\n const hash = window.location.hash.slice(1);\n if (!hash) {\n return;\n }\n\n const prep = navigatePrepare(normalizeLocation(hash));\n if (!prep) {\n return;\n }\n\n const { guardLevel, to, fullPath } = prep;\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n if (guardResult.redirectTo) {\n await navigate({ ...guardResult.redirectTo, replace: true });\n return;\n }\n\n ignoreNextHashChange = true;\n if (current) {\n window.location.replace('#' + current.path + buildQuery(current.query));\n } else {\n window.location.replace(window.location.pathname + window.location.search);\n }\n return;\n }\n\n await commit(to, fullPath, false, fullPath === hash ? null : 'replace');\n };\n\n // # register events\n if (isHashMode) {\n window.addEventListener('hashchange', () => {\n void handleHashChange();\n });\n } else {\n window.addEventListener('popstate', () => {\n void handlePopState();\n });\n }\n\n // # initialize\n const instance: Router = {\n get current() {\n return current;\n },\n\n get history() {\n return history.concat();\n },\n\n setRouterView(view: HTMLElement) {\n routerView = view;\n },\n\n push(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate(options);\n },\n\n silentPush(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, guardLevel: GuardLevel.Route });\n },\n\n replace(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, replace: true });\n },\n\n back() {\n window.history.back();\n },\n\n forward() {\n window.history.forward();\n },\n };\n if (isHashMode) {\n const currentHash = window.location.hash.slice(1);\n if (currentHash) {\n void handleHashChange();\n }\n } else {\n const currentPath = window.location.pathname + window.location.search;\n if (currentPath !== '/' || window.location.search) {\n void handlePopState();\n }\n }\n\n return instance;\n};\n\nexport { GuardLevel };\nexport { KTRouter } from './kt-router.js';\n","import type { RouteConfig, RouteMatch } from '../types/router.js';\nimport { extractParams, normalizePath } from '@ktjs/shared';\n\n/**\n * Route matcher for finding matching routes and extracting params\n */\nexport const createMatcher = (routes: RouteConfig[], matchedMap: Map<RouteConfig, RouteConfig[]>) => {\n const nameMap: Record<string, RouteConfig> = {};\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i];\n if (route.name !== undefined) {\n if (route.name in nameMap) {\n $throw(`Duplicate route name detected: '${route.name}'`);\n }\n nameMap[route.name] = route;\n }\n }\n\n /**\n * Find route by name\n */\n const findByName = (name: string): RouteConfig | null => {\n return nameMap[name] ?? null;\n };\n\n /**\n * Match path against all routes\n */\n const match = (path: string): RouteMatch | null => {\n const normalizedPath = normalizePath(path);\n\n // Try exact match first\n for (const route of routes) {\n if (route.path === normalizedPath) {\n return {\n route,\n params: {},\n result: matchedMap.get(route) ?? [route],\n };\n }\n }\n\n // Try dynamic routes\n for (const route of routes) {\n if (route.path.includes(':')) {\n const params = extractParams(route.path, normalizedPath);\n if (params) {\n return {\n route,\n params,\n result: matchedMap.get(route) ?? [route],\n };\n }\n }\n }\n\n return null;\n };\n\n return {\n findByName,\n match,\n };\n};\n"],"names":["KTRouter","router","view","document","createElement","setRouterView","createRouter","beforeEach","$emptyFn","afterEach","onNotFound","onError","mode","prefix","routes","rawRoutes","matchedMap","Map","history","prefixPath","normalizePath","isHashMode","routerView","current","ignoreNextHashChange","normalize","parentPath","parentMatched","map","route","path","normalized","name","meta","beforeEnter","after","children","component","matched","concat","set","push","guard","async","to","from","guardLevel","continue","result","redirectTo","targetRoute","length","error","navigatePrepare","options","targetPath","findByName","Error","startsWith","params","emplaceParams","match","fullPath","query","buildQuery","replace","commit","replaceHistory","urlMode","window","location","hash","slice","hashUrl","pathname","search","replaceState","pushState","element","innerHTML","appendChild","executeAfterHooks","catch","navigate","redirectCount","prep","guardResult","normalizeLocation","loc","queryString","split","parseQuery","undefined","nameMap","i","normalizedPath","get","includes","extractParams","createMatcher","handlePopState","handleHashChange","addEventListener","instance","silentPush","back","forward"],"mappings":"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"}
|