@rue-js/router 0.0.20

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.
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @rue-js/router v0.0.20
3
+ * (c) 2025-present Xiangmin Liu and Rue contributors
4
+ * @license MIT
5
+ **/
6
+ 'use strict';
7
+
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+
10
+ var rueJs = require('rue-js');
11
+ var shared = require('@rue-js/shared');
12
+
13
+ const __routerByContainer = /* @__PURE__ */ new WeakMap();
14
+ let __activeRouter = null;
15
+ const attachRouter = (router) => {
16
+ const c = rueJs.getCurrentContainer();
17
+ if (c) __routerByContainer.set(c, router);
18
+ __activeRouter = router;
19
+ };
20
+ const createWebHashHistory = () => {
21
+ const g = globalThis;
22
+ if (g && g.location) {
23
+ if (!g.location.hash) g.location.hash = "#/";
24
+ }
25
+ const loc = () => {
26
+ const s = g && g.location && g.location.hash ? String(g.location.hash).replace(/^#/, "") : "";
27
+ return s || "/";
28
+ };
29
+ const listen = (cb) => {
30
+ if (g && g.addEventListener) g.addEventListener("hashchange", cb);
31
+ };
32
+ return {
33
+ location: loc,
34
+ push: (p) => {
35
+ const next = p.startsWith("#") ? p.slice(1) : p;
36
+ if (next === loc()) return;
37
+ if (g && g.location) {
38
+ g.location.hash = next;
39
+ }
40
+ if (g && g.dispatchEvent && g.HashChangeEvent) {
41
+ g.dispatchEvent(new g.HashChangeEvent("hashchange"));
42
+ }
43
+ },
44
+ replace: (p) => {
45
+ const next = p.startsWith("#") ? p.slice(1) : p;
46
+ if (next === loc()) return;
47
+ const href = "#" + next;
48
+ if (g && g.location && typeof g.location.replace === "function") {
49
+ g.location.replace(href);
50
+ }
51
+ if (g && g.dispatchEvent && g.HashChangeEvent) {
52
+ g.dispatchEvent(new g.HashChangeEvent("hashchange"));
53
+ }
54
+ },
55
+ listen,
56
+ back: () => {
57
+ if (g && g.history && typeof g.history.back === "function") g.history.back();
58
+ }
59
+ };
60
+ };
61
+ const createRouter = (options) => {
62
+ const currentPath = rueJs.signal(options.history.location(), {}, true);
63
+ const compilePath = (path) => {
64
+ const keys = [];
65
+ const reStr = "^" + path.replace(/\/:([^/()]+)(?:\(([^)]+)\))?/g, (_m, name, pattern) => {
66
+ keys.push(name);
67
+ const group = pattern ? `(${pattern})` : "([^/]+)";
68
+ return `/${group}`;
69
+ }) + "$";
70
+ return { re: new RegExp(reStr), keys };
71
+ };
72
+ const compiled = options.routes.map(
73
+ (r) => shared.extend(r, {
74
+ _c: compilePath(r.path)
75
+ })
76
+ );
77
+ const match = (path) => {
78
+ for (let i = 0; i < compiled.length; i++) {
79
+ const r = compiled[i];
80
+ const m = r._c.re.exec(path);
81
+ if (m) {
82
+ const params = {};
83
+ r._c.keys.forEach((k, idx) => {
84
+ params[k] = decodeURIComponent(m[idx + 1] || "");
85
+ });
86
+ return { record: r, params, path };
87
+ }
88
+ }
89
+ return null;
90
+ };
91
+ const matchRoute = match(currentPath.get());
92
+ if (null === matchRoute) {
93
+ throw new Error("No route matched path " + currentPath.get());
94
+ }
95
+ const route = rueJs.signal(matchRoute, {}, true);
96
+ options.history.listen(() => {
97
+ const p = options.history.location();
98
+ if (p === currentPath.get()) {
99
+ return;
100
+ }
101
+ const matchRoute2 = match(p);
102
+ if (null === matchRoute2) {
103
+ throw new Error("No route matched path " + p);
104
+ }
105
+ currentPath.set(p);
106
+ route.set(matchRoute2);
107
+ });
108
+ const router = {
109
+ currentPath,
110
+ route,
111
+ push: (p) => options.history.push(p),
112
+ replace: (p) => options.history.replace(p),
113
+ back: () => {
114
+ if (options.history.back) return options.history.back();
115
+ const gg = globalThis;
116
+ if (gg.history && typeof gg.history.back === "function") gg.history.back();
117
+ },
118
+ routes: options.routes,
119
+ history: options.history,
120
+ /** 插件安装:绑定当前 Router 到容器上下文 */
121
+ install: (_app, _options) => {
122
+ attachRouter(router);
123
+ }
124
+ };
125
+ return router;
126
+ };
127
+ const useRouter = () => {
128
+ const c = rueJs.getCurrentContainer();
129
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
130
+ if (!r) throw new Error("Router not installed for current application/container");
131
+ return r;
132
+ };
133
+ const RouterView = () => {
134
+ const { container } = rueJs.useSetup(() => {
135
+ const r = useRouter();
136
+ const container2 = document.createDocumentFragment();
137
+ const startEl = document.createComment("rue-router-view-start");
138
+ const endEl = document.createComment("rue-router-view-end");
139
+ container2.appendChild(startEl);
140
+ container2.appendChild(endEl);
141
+ const clearRange = () => {
142
+ const vnodeLike = rueJs.vapor(() => ({ vaporElement: document.createDocumentFragment() }));
143
+ const parent = startEl.parentNode || container2;
144
+ rueJs.renderBetween(vnodeLike, parent, startEl, endEl);
145
+ };
146
+ let lastComponent = null;
147
+ rueJs.watchEffect(() => {
148
+ const data = r.route.get();
149
+ if (!data) {
150
+ clearRange();
151
+ lastComponent = null;
152
+ } else {
153
+ const comp = data.record.component;
154
+ if (lastComponent && comp === lastComponent) {
155
+ return;
156
+ }
157
+ lastComponent = comp;
158
+ const vnodeLike = rueJs.h(comp, { params: data.params });
159
+ const parent = startEl.parentNode || container2;
160
+ rueJs.renderBetween(vnodeLike, parent, startEl, endEl);
161
+ }
162
+ });
163
+ return { container: container2 };
164
+ });
165
+ return rueJs.vapor(() => ({ vaporElement: container }));
166
+ };
167
+ const RouterLink = (props) => {
168
+ const { container } = rueJs.useSetup(() => {
169
+ const c = rueJs.getCurrentContainer();
170
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
171
+ if (!r) throw new Error("Router not installed for current application/container");
172
+ const container2 = document.createDocumentFragment();
173
+ const startEl = document.createComment("rue-router-link-start");
174
+ const endEl = document.createComment("rue-router-link-end");
175
+ container2.appendChild(startEl);
176
+ container2.appendChild(endEl);
177
+ rueJs.watchEffect(() => {
178
+ const to = String(props.to || "");
179
+ const replace = !!props.replace;
180
+ const { children, to: _to, replace: _replace, ...rest } = props;
181
+ const click = (e) => {
182
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
183
+ return;
184
+ }
185
+ e.preventDefault();
186
+ const nav = replace ? r.replace : r.push;
187
+ nav(to);
188
+ };
189
+ const childList = Array.isArray(children) ? children : children != null ? [children] : [];
190
+ const vnodeLike = rueJs.h("a", { href: "#" + to, onClick: click, ...rest }, ...childList);
191
+ const parent = startEl.parentNode || container2;
192
+ rueJs.renderBetween(vnodeLike, parent, startEl, endEl);
193
+ });
194
+ return { container: container2 };
195
+ });
196
+ return rueJs.vapor(() => ({ vaporElement: container }));
197
+ };
198
+ const useRoute = () => {
199
+ const c = rueJs.getCurrentContainer();
200
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
201
+ if (!r) throw new Error("Router not installed for current application/container");
202
+ return r.route;
203
+ };
204
+
205
+ exports.RouterLink = RouterLink;
206
+ exports.RouterView = RouterView;
207
+ exports.attachRouter = attachRouter;
208
+ exports.createRouter = createRouter;
209
+ exports.createWebHashHistory = createWebHashHistory;
210
+ exports.useRoute = useRoute;
211
+ exports.useRouter = useRouter;
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @rue-js/router v0.0.20
3
+ * (c) 2025-present Xiangmin Liu and Rue contributors
4
+ * @license MIT
5
+ **/
6
+ 'use strict';
7
+
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+
10
+ var rueJs = require('rue-js');
11
+ var shared = require('@rue-js/shared');
12
+
13
+ const __routerByContainer = /* @__PURE__ */ new WeakMap();
14
+ let __activeRouter = null;
15
+ const attachRouter = (router) => {
16
+ const c = rueJs.getCurrentContainer();
17
+ if (c) __routerByContainer.set(c, router);
18
+ __activeRouter = router;
19
+ };
20
+ const createWebHashHistory = () => {
21
+ const g = globalThis;
22
+ if (g && g.location) {
23
+ if (!g.location.hash) g.location.hash = "#/";
24
+ }
25
+ const loc = () => {
26
+ const s = g && g.location && g.location.hash ? String(g.location.hash).replace(/^#/, "") : "";
27
+ return s || "/";
28
+ };
29
+ const listen = (cb) => {
30
+ if (g && g.addEventListener) g.addEventListener("hashchange", cb);
31
+ };
32
+ return {
33
+ location: loc,
34
+ push: (p) => {
35
+ const next = p.startsWith("#") ? p.slice(1) : p;
36
+ if (next === loc()) return;
37
+ if (g && g.location) {
38
+ g.location.hash = next;
39
+ }
40
+ if (g && g.dispatchEvent && g.HashChangeEvent) {
41
+ g.dispatchEvent(new g.HashChangeEvent("hashchange"));
42
+ }
43
+ },
44
+ replace: (p) => {
45
+ const next = p.startsWith("#") ? p.slice(1) : p;
46
+ if (next === loc()) return;
47
+ const href = "#" + next;
48
+ if (g && g.location && typeof g.location.replace === "function") {
49
+ g.location.replace(href);
50
+ }
51
+ if (g && g.dispatchEvent && g.HashChangeEvent) {
52
+ g.dispatchEvent(new g.HashChangeEvent("hashchange"));
53
+ }
54
+ },
55
+ listen,
56
+ back: () => {
57
+ if (g && g.history && typeof g.history.back === "function") g.history.back();
58
+ }
59
+ };
60
+ };
61
+ const createRouter = (options) => {
62
+ const currentPath = rueJs.signal(options.history.location(), {}, true);
63
+ const compilePath = (path) => {
64
+ const keys = [];
65
+ const reStr = "^" + path.replace(/\/:([^/()]+)(?:\(([^)]+)\))?/g, (_m, name, pattern) => {
66
+ keys.push(name);
67
+ const group = pattern ? `(${pattern})` : "([^/]+)";
68
+ return `/${group}`;
69
+ }) + "$";
70
+ return { re: new RegExp(reStr), keys };
71
+ };
72
+ const compiled = options.routes.map(
73
+ (r) => shared.extend(r, {
74
+ _c: compilePath(r.path)
75
+ })
76
+ );
77
+ const match = (path) => {
78
+ for (let i = 0; i < compiled.length; i++) {
79
+ const r = compiled[i];
80
+ const m = r._c.re.exec(path);
81
+ if (m) {
82
+ const params = {};
83
+ r._c.keys.forEach((k, idx) => {
84
+ params[k] = decodeURIComponent(m[idx + 1] || "");
85
+ });
86
+ return { record: r, params, path };
87
+ }
88
+ }
89
+ return null;
90
+ };
91
+ const matchRoute = match(currentPath.get());
92
+ if (null === matchRoute) {
93
+ throw new Error("No route matched path " + currentPath.get());
94
+ }
95
+ const route = rueJs.signal(matchRoute, {}, true);
96
+ options.history.listen(() => {
97
+ const p = options.history.location();
98
+ if (p === currentPath.get()) {
99
+ return;
100
+ }
101
+ const matchRoute2 = match(p);
102
+ if (null === matchRoute2) {
103
+ throw new Error("No route matched path " + p);
104
+ }
105
+ currentPath.set(p);
106
+ route.set(matchRoute2);
107
+ });
108
+ const router = {
109
+ currentPath,
110
+ route,
111
+ push: (p) => options.history.push(p),
112
+ replace: (p) => options.history.replace(p),
113
+ back: () => {
114
+ if (options.history.back) return options.history.back();
115
+ const gg = globalThis;
116
+ if (gg.history && typeof gg.history.back === "function") gg.history.back();
117
+ },
118
+ routes: options.routes,
119
+ history: options.history,
120
+ /** 插件安装:绑定当前 Router 到容器上下文 */
121
+ install: (_app, _options) => {
122
+ attachRouter(router);
123
+ }
124
+ };
125
+ return router;
126
+ };
127
+ const useRouter = () => {
128
+ const c = rueJs.getCurrentContainer();
129
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
130
+ if (!r) throw new Error("Router not installed for current application/container");
131
+ return r;
132
+ };
133
+ const RouterView = () => {
134
+ const { container } = rueJs.useSetup(() => {
135
+ const r = useRouter();
136
+ const container2 = document.createDocumentFragment();
137
+ const startEl = document.createComment("rue-router-view-start");
138
+ const endEl = document.createComment("rue-router-view-end");
139
+ container2.appendChild(startEl);
140
+ container2.appendChild(endEl);
141
+ const clearRange = () => {
142
+ const vnodeLike = rueJs.vapor(() => ({ vaporElement: document.createDocumentFragment() }));
143
+ const parent = startEl.parentNode || container2;
144
+ rueJs.renderBetween(vnodeLike, parent, startEl, endEl);
145
+ };
146
+ let lastComponent = null;
147
+ rueJs.watchEffect(() => {
148
+ const data = r.route.get();
149
+ if (!data) {
150
+ clearRange();
151
+ lastComponent = null;
152
+ } else {
153
+ const comp = data.record.component;
154
+ if (lastComponent && comp === lastComponent) {
155
+ return;
156
+ }
157
+ lastComponent = comp;
158
+ const vnodeLike = rueJs.h(comp, { params: data.params });
159
+ const parent = startEl.parentNode || container2;
160
+ rueJs.renderBetween(vnodeLike, parent, startEl, endEl);
161
+ }
162
+ });
163
+ return { container: container2 };
164
+ });
165
+ return rueJs.vapor(() => ({ vaporElement: container }));
166
+ };
167
+ const RouterLink = (props) => {
168
+ const { container } = rueJs.useSetup(() => {
169
+ const c = rueJs.getCurrentContainer();
170
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
171
+ if (!r) throw new Error("Router not installed for current application/container");
172
+ const container2 = document.createDocumentFragment();
173
+ const startEl = document.createComment("rue-router-link-start");
174
+ const endEl = document.createComment("rue-router-link-end");
175
+ container2.appendChild(startEl);
176
+ container2.appendChild(endEl);
177
+ rueJs.watchEffect(() => {
178
+ const to = String(props.to || "");
179
+ const replace = !!props.replace;
180
+ const { children, to: _to, replace: _replace, ...rest } = props;
181
+ const click = (e) => {
182
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
183
+ return;
184
+ }
185
+ e.preventDefault();
186
+ const nav = replace ? r.replace : r.push;
187
+ nav(to);
188
+ };
189
+ const childList = Array.isArray(children) ? children : children != null ? [children] : [];
190
+ const vnodeLike = rueJs.h("a", { href: "#" + to, onClick: click, ...rest }, ...childList);
191
+ const parent = startEl.parentNode || container2;
192
+ rueJs.renderBetween(vnodeLike, parent, startEl, endEl);
193
+ });
194
+ return { container: container2 };
195
+ });
196
+ return rueJs.vapor(() => ({ vaporElement: container }));
197
+ };
198
+ const useRoute = () => {
199
+ const c = rueJs.getCurrentContainer();
200
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
201
+ if (!r) throw new Error("Router not installed for current application/container");
202
+ return r.route;
203
+ };
204
+
205
+ exports.RouterLink = RouterLink;
206
+ exports.RouterView = RouterView;
207
+ exports.attachRouter = attachRouter;
208
+ exports.createRouter = createRouter;
209
+ exports.createWebHashHistory = createWebHashHistory;
210
+ exports.useRoute = useRoute;
211
+ exports.useRouter = useRouter;
@@ -0,0 +1,81 @@
1
+ import { FC, SignalHandle } from 'rue-js';
2
+
3
+ /** 路由静态记录:
4
+ * - path:形如 '/users/:id(\\d+)' 的匹配模式(支持命名参数与可选正则)
5
+ * - component:匹配成功时渲染的组件(接收 { params })
6
+ */
7
+ export type RouteRecord = {
8
+ path: string;
9
+ component: FC<any>;
10
+ };
11
+ /** 路由参数对象:命名参数的解码后字串映射 */
12
+ export type RouteParams = Record<string, string>;
13
+ /** 当前路由匹配结果:
14
+ * - record:命中的路由记录
15
+ * - params:从路径中提取的参数
16
+ * - path:当前匹配的原始路径
17
+ * - 为 null 表示无匹配(RouterView 将清空渲染区域)
18
+ */
19
+ export type Route = {
20
+ record: RouteRecord;
21
+ params: RouteParams;
22
+ path: string;
23
+ } | null;
24
+ /** Router 核心接口:
25
+ * - currentPath:当前历史位置(字符串)信号
26
+ * - route:当前匹配结果信号(Route 或 null)
27
+ * - push/replace/back:导航 API,委托给历史实现
28
+ * - routes:注册的路由表(顺序即匹配优先级)
29
+ * - history:历史实现(HistoryLike)
30
+ * - install:把 Router 绑定到当前容器上下文
31
+ */
32
+ export type Router = {
33
+ currentPath: SignalHandle<string>;
34
+ route: SignalHandle<Route>;
35
+ push: (p: string) => void;
36
+ replace: (p: string) => void;
37
+ back: () => void;
38
+ routes: RouteRecord[];
39
+ history: HistoryLike;
40
+ install: (app: unknown, options: unknown[]) => void;
41
+ };
42
+ /** 历史实现抽象:
43
+ * - location:返回当前位置的字符串(不含井号的路径)
44
+ * - push/replace:更新位置并通知监听者
45
+ * - listen:订阅位置变化(用于驱动信号)
46
+ * - back:可选,后退一步(Web 环境委托给 window.history)
47
+ */
48
+ export type HistoryLike = {
49
+ location: () => string;
50
+ push: (p: string) => void;
51
+ replace: (p: string) => void;
52
+ listen: (cb: () => void) => void;
53
+ back?: () => void;
54
+ };
55
+ /** 将 Router 绑定到当前容器并设置为活动路由 */
56
+ export declare const attachRouter: (router: Router) => void;
57
+ /** 创建基于 hash 的 Web 历史实现 */
58
+ export declare const createWebHashHistory: () => HistoryLike;
59
+ /** 创建 Router
60
+ * - 编译所有路由规则为正则与键列表
61
+ * - 监听历史变化更新 currentPath 与 route
62
+ * @param options {history, routes}
63
+ * @returns Router 实例
64
+ */
65
+ export declare const createRouter: (options: {
66
+ history: HistoryLike;
67
+ routes: RouteRecord[];
68
+ }) => Router;
69
+ /** 获取当前上下文的 Router(优先容器绑定,其次活动路由) */
70
+ export declare const useRouter: () => Router;
71
+ /** RouterView:在区间锚点间渲染当前匹配组件 */
72
+ export declare const RouterView: FC;
73
+ /** RouterLink:渲染链接并处理导航 */
74
+ export declare const RouterLink: FC<{
75
+ to: string;
76
+ replace?: boolean;
77
+ } & Record<string, unknown>>;
78
+ /** 获取当前路由信号 */
79
+ export declare const useRoute: () => SignalHandle<Route>;
80
+
81
+
@@ -0,0 +1,201 @@
1
+ /**
2
+ * @rue-js/router v0.0.20
3
+ * (c) 2025-present Xiangmin Liu and Rue contributors
4
+ * @license MIT
5
+ **/
6
+ import { getCurrentContainer, signal, useSetup, watchEffect, h, renderBetween, vapor } from 'rue-js';
7
+ import { extend } from '@rue-js/shared';
8
+
9
+ const __routerByContainer = /* @__PURE__ */ new WeakMap();
10
+ let __activeRouter = null;
11
+ const attachRouter = (router) => {
12
+ const c = getCurrentContainer();
13
+ if (c) __routerByContainer.set(c, router);
14
+ __activeRouter = router;
15
+ };
16
+ const createWebHashHistory = () => {
17
+ const g = globalThis;
18
+ if (g && g.location) {
19
+ if (!g.location.hash) g.location.hash = "#/";
20
+ }
21
+ const loc = () => {
22
+ const s = g && g.location && g.location.hash ? String(g.location.hash).replace(/^#/, "") : "";
23
+ return s || "/";
24
+ };
25
+ const listen = (cb) => {
26
+ if (g && g.addEventListener) g.addEventListener("hashchange", cb);
27
+ };
28
+ return {
29
+ location: loc,
30
+ push: (p) => {
31
+ const next = p.startsWith("#") ? p.slice(1) : p;
32
+ if (next === loc()) return;
33
+ if (g && g.location) {
34
+ g.location.hash = next;
35
+ }
36
+ if (g && g.dispatchEvent && g.HashChangeEvent) {
37
+ g.dispatchEvent(new g.HashChangeEvent("hashchange"));
38
+ }
39
+ },
40
+ replace: (p) => {
41
+ const next = p.startsWith("#") ? p.slice(1) : p;
42
+ if (next === loc()) return;
43
+ const href = "#" + next;
44
+ if (g && g.location && typeof g.location.replace === "function") {
45
+ g.location.replace(href);
46
+ }
47
+ if (g && g.dispatchEvent && g.HashChangeEvent) {
48
+ g.dispatchEvent(new g.HashChangeEvent("hashchange"));
49
+ }
50
+ },
51
+ listen,
52
+ back: () => {
53
+ if (g && g.history && typeof g.history.back === "function") g.history.back();
54
+ }
55
+ };
56
+ };
57
+ const createRouter = (options) => {
58
+ const currentPath = signal(options.history.location(), {}, true);
59
+ const compilePath = (path) => {
60
+ const keys = [];
61
+ const reStr = "^" + path.replace(/\/:([^/()]+)(?:\(([^)]+)\))?/g, (_m, name, pattern) => {
62
+ keys.push(name);
63
+ const group = pattern ? `(${pattern})` : "([^/]+)";
64
+ return `/${group}`;
65
+ }) + "$";
66
+ return { re: new RegExp(reStr), keys };
67
+ };
68
+ const compiled = options.routes.map(
69
+ (r) => extend(r, {
70
+ _c: compilePath(r.path)
71
+ })
72
+ );
73
+ const match = (path) => {
74
+ for (let i = 0; i < compiled.length; i++) {
75
+ const r = compiled[i];
76
+ const m = r._c.re.exec(path);
77
+ if (m) {
78
+ const params = {};
79
+ r._c.keys.forEach((k, idx) => {
80
+ params[k] = decodeURIComponent(m[idx + 1] || "");
81
+ });
82
+ return { record: r, params, path };
83
+ }
84
+ }
85
+ return null;
86
+ };
87
+ const matchRoute = match(currentPath.get());
88
+ if (null === matchRoute) {
89
+ throw new Error("No route matched path " + currentPath.get());
90
+ }
91
+ const route = signal(matchRoute, {}, true);
92
+ options.history.listen(() => {
93
+ const p = options.history.location();
94
+ if (p === currentPath.get()) {
95
+ return;
96
+ }
97
+ const matchRoute2 = match(p);
98
+ if (null === matchRoute2) {
99
+ throw new Error("No route matched path " + p);
100
+ }
101
+ currentPath.set(p);
102
+ route.set(matchRoute2);
103
+ });
104
+ const router = {
105
+ currentPath,
106
+ route,
107
+ push: (p) => options.history.push(p),
108
+ replace: (p) => options.history.replace(p),
109
+ back: () => {
110
+ if (options.history.back) return options.history.back();
111
+ const gg = globalThis;
112
+ if (gg.history && typeof gg.history.back === "function") gg.history.back();
113
+ },
114
+ routes: options.routes,
115
+ history: options.history,
116
+ /** 插件安装:绑定当前 Router 到容器上下文 */
117
+ install: (_app, _options) => {
118
+ attachRouter(router);
119
+ }
120
+ };
121
+ return router;
122
+ };
123
+ const useRouter = () => {
124
+ const c = getCurrentContainer();
125
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
126
+ if (!r) throw new Error("Router not installed for current application/container");
127
+ return r;
128
+ };
129
+ const RouterView = () => {
130
+ const { container } = useSetup(() => {
131
+ const r = useRouter();
132
+ const container2 = document.createDocumentFragment();
133
+ const startEl = document.createComment("rue-router-view-start");
134
+ const endEl = document.createComment("rue-router-view-end");
135
+ container2.appendChild(startEl);
136
+ container2.appendChild(endEl);
137
+ const clearRange = () => {
138
+ const vnodeLike = vapor(() => ({ vaporElement: document.createDocumentFragment() }));
139
+ const parent = startEl.parentNode || container2;
140
+ renderBetween(vnodeLike, parent, startEl, endEl);
141
+ };
142
+ let lastComponent = null;
143
+ watchEffect(() => {
144
+ const data = r.route.get();
145
+ if (!data) {
146
+ clearRange();
147
+ lastComponent = null;
148
+ } else {
149
+ const comp = data.record.component;
150
+ if (lastComponent && comp === lastComponent) {
151
+ return;
152
+ }
153
+ lastComponent = comp;
154
+ const vnodeLike = h(comp, { params: data.params });
155
+ const parent = startEl.parentNode || container2;
156
+ renderBetween(vnodeLike, parent, startEl, endEl);
157
+ }
158
+ });
159
+ return { container: container2 };
160
+ });
161
+ return vapor(() => ({ vaporElement: container }));
162
+ };
163
+ const RouterLink = (props) => {
164
+ const { container } = useSetup(() => {
165
+ const c = getCurrentContainer();
166
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
167
+ if (!r) throw new Error("Router not installed for current application/container");
168
+ const container2 = document.createDocumentFragment();
169
+ const startEl = document.createComment("rue-router-link-start");
170
+ const endEl = document.createComment("rue-router-link-end");
171
+ container2.appendChild(startEl);
172
+ container2.appendChild(endEl);
173
+ watchEffect(() => {
174
+ const to = String(props.to || "");
175
+ const replace = !!props.replace;
176
+ const { children, to: _to, replace: _replace, ...rest } = props;
177
+ const click = (e) => {
178
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
179
+ return;
180
+ }
181
+ e.preventDefault();
182
+ const nav = replace ? r.replace : r.push;
183
+ nav(to);
184
+ };
185
+ const childList = Array.isArray(children) ? children : children != null ? [children] : [];
186
+ const vnodeLike = h("a", { href: "#" + to, onClick: click, ...rest }, ...childList);
187
+ const parent = startEl.parentNode || container2;
188
+ renderBetween(vnodeLike, parent, startEl, endEl);
189
+ });
190
+ return { container: container2 };
191
+ });
192
+ return vapor(() => ({ vaporElement: container }));
193
+ };
194
+ const useRoute = () => {
195
+ const c = getCurrentContainer();
196
+ const r = (c ? __routerByContainer.get(c) || null : null) || __activeRouter;
197
+ if (!r) throw new Error("Router not installed for current application/container");
198
+ return r.route;
199
+ };
200
+
201
+ export { RouterLink, RouterView, attachRouter, createRouter, createWebHashHistory, useRoute, useRouter };
package/index.js ADDED
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ if (process.env.NODE_ENV === 'production') {
4
+ module.exports = require('./dist/router.cjs.prod.js')
5
+ } else {
6
+ module.exports = require('./dist/router.cjs.js')
7
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@rue-js/router",
3
+ "version": "0.0.20",
4
+ "description": "@rue-js/router",
5
+ "keywords": [
6
+ "rue"
7
+ ],
8
+ "homepage": "https://github.com/hunzhiwange/ruejs/tree/main/packages/runtime#readme",
9
+ "bugs": {
10
+ "url": "https://github.com/hunzhiwange/ruejs/issues"
11
+ },
12
+ "license": "MIT",
13
+ "author": "Xiangmin Liu",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/hunzhiwange/ruejs.git",
17
+ "directory": "packages/router"
18
+ },
19
+ "files": [
20
+ "index.js",
21
+ "dist"
22
+ ],
23
+ "sideEffects": false,
24
+ "main": "index.js",
25
+ "module": "dist/router.esm-bundler.js",
26
+ "types": "dist/router.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/router.d.ts",
30
+ "development": "./src/index.ts",
31
+ "node": {
32
+ "production": "./dist/router.cjs.prod.js",
33
+ "development": "./dist/router.cjs.js",
34
+ "default": "./index.js"
35
+ },
36
+ "module": "./dist/router.esm-bundler.js",
37
+ "import": "./dist/router.esm-bundler.js",
38
+ "require": "./index.js"
39
+ },
40
+ "./*": "./*"
41
+ },
42
+ "dependencies": {
43
+ "rue-js": "0.0.20"
44
+ },
45
+ "buildOptions": {
46
+ "name": "RueRouterCore",
47
+ "formats": [
48
+ "esm-bundler",
49
+ "cjs"
50
+ ]
51
+ }
52
+ }