@esmx/router-vue 3.0.0-rc.24 → 3.0.0-rc.26
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/router-link.d.ts +56 -2
- package/dist/router-link.mjs +72 -16
- package/dist/use.mjs +1 -1
- package/dist/use.test.mjs +4 -4
- package/dist/util.test.mjs +7 -2
- package/package.json +9 -9
- package/src/router-link.ts +86 -20
package/dist/router-link.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export declare const RouterLink: import("vue").DefineComponent<import("vue").Ext
|
|
|
70
70
|
};
|
|
71
71
|
/**
|
|
72
72
|
* @deprecated Use 'type="replace"' instead
|
|
73
|
-
* @example replace={true} → type="replace"
|
|
73
|
+
* @example :replace={true} → type="replace"
|
|
74
74
|
*/
|
|
75
75
|
replace: {
|
|
76
76
|
type: BooleanConstructor;
|
|
@@ -120,6 +120,33 @@ export declare const RouterLink: import("vue").DefineComponent<import("vue").Ext
|
|
|
120
120
|
layerOptions: {
|
|
121
121
|
type: PropType<RouteLayerOptions>;
|
|
122
122
|
};
|
|
123
|
+
/**
|
|
124
|
+
* Custom event handler to control navigation behavior.
|
|
125
|
+
* Should return `true` to allow router to navigate, otherwise to prevent it.
|
|
126
|
+
*
|
|
127
|
+
* @Note you need to call `e.preventDefault()` to prevent default browser navigation.
|
|
128
|
+
* @default
|
|
129
|
+
*
|
|
130
|
+
* (event: Event & Partial<MouseEvent>): boolean => {
|
|
131
|
+
* // don't redirect with control keys
|
|
132
|
+
* if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
|
|
133
|
+
* // don't redirect when preventDefault called
|
|
134
|
+
* if (e.defaultPrevented) return false;
|
|
135
|
+
* // don't redirect on right click
|
|
136
|
+
* if (e.button !== undefined && e.button !== 0) return false;
|
|
137
|
+
* // don't redirect if `target="_blank"`
|
|
138
|
+
* const target = e.currentTarget?.getAttribute?.('target') ?? '';
|
|
139
|
+
* if (/\b_blank\b/i.test(target)) return false;
|
|
140
|
+
* // Prevent default browser navigation to enable SPA routing
|
|
141
|
+
* // Note: this may be a Weex event which doesn't have this method
|
|
142
|
+
* if (e.preventDefault) e.preventDefault();
|
|
143
|
+
*
|
|
144
|
+
* return true;
|
|
145
|
+
* }
|
|
146
|
+
*/
|
|
147
|
+
eventHandler: {
|
|
148
|
+
type: PropType<(event: Event) => boolean | undefined | void>;
|
|
149
|
+
};
|
|
123
150
|
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
124
151
|
[key: string]: any;
|
|
125
152
|
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -143,7 +170,7 @@ export declare const RouterLink: import("vue").DefineComponent<import("vue").Ext
|
|
|
143
170
|
};
|
|
144
171
|
/**
|
|
145
172
|
* @deprecated Use 'type="replace"' instead
|
|
146
|
-
* @example replace={true} → type="replace"
|
|
173
|
+
* @example :replace={true} → type="replace"
|
|
147
174
|
*/
|
|
148
175
|
replace: {
|
|
149
176
|
type: BooleanConstructor;
|
|
@@ -193,6 +220,33 @@ export declare const RouterLink: import("vue").DefineComponent<import("vue").Ext
|
|
|
193
220
|
layerOptions: {
|
|
194
221
|
type: PropType<RouteLayerOptions>;
|
|
195
222
|
};
|
|
223
|
+
/**
|
|
224
|
+
* Custom event handler to control navigation behavior.
|
|
225
|
+
* Should return `true` to allow router to navigate, otherwise to prevent it.
|
|
226
|
+
*
|
|
227
|
+
* @Note you need to call `e.preventDefault()` to prevent default browser navigation.
|
|
228
|
+
* @default
|
|
229
|
+
*
|
|
230
|
+
* (event: Event & Partial<MouseEvent>): boolean => {
|
|
231
|
+
* // don't redirect with control keys
|
|
232
|
+
* if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
|
|
233
|
+
* // don't redirect when preventDefault called
|
|
234
|
+
* if (e.defaultPrevented) return false;
|
|
235
|
+
* // don't redirect on right click
|
|
236
|
+
* if (e.button !== undefined && e.button !== 0) return false;
|
|
237
|
+
* // don't redirect if `target="_blank"`
|
|
238
|
+
* const target = e.currentTarget?.getAttribute?.('target') ?? '';
|
|
239
|
+
* if (/\b_blank\b/i.test(target)) return false;
|
|
240
|
+
* // Prevent default browser navigation to enable SPA routing
|
|
241
|
+
* // Note: this may be a Weex event which doesn't have this method
|
|
242
|
+
* if (e.preventDefault) e.preventDefault();
|
|
243
|
+
*
|
|
244
|
+
* return true;
|
|
245
|
+
* }
|
|
246
|
+
*/
|
|
247
|
+
eventHandler: {
|
|
248
|
+
type: PropType<(event: Event) => boolean | undefined | void>;
|
|
249
|
+
};
|
|
196
250
|
}>> & Readonly<{}>, {
|
|
197
251
|
type: RouterLinkType;
|
|
198
252
|
replace: boolean;
|
package/dist/router-link.mjs
CHANGED
|
@@ -21,7 +21,7 @@ export const RouterLink = defineComponent({
|
|
|
21
21
|
type: { type: String, default: "push" },
|
|
22
22
|
/**
|
|
23
23
|
* @deprecated Use 'type="replace"' instead
|
|
24
|
-
* @example replace={true} → type="replace"
|
|
24
|
+
* @example :replace={true} → type="replace"
|
|
25
25
|
*/
|
|
26
26
|
replace: { type: Boolean, default: false },
|
|
27
27
|
/**
|
|
@@ -57,28 +57,84 @@ export const RouterLink = defineComponent({
|
|
|
57
57
|
* Only used when type='pushLayer'.
|
|
58
58
|
* @example { zIndex: 1000, autoPush: false, routerOptions: { mode: 'memory' } }
|
|
59
59
|
*/
|
|
60
|
-
layerOptions: { type: Object }
|
|
60
|
+
layerOptions: { type: Object },
|
|
61
|
+
/**
|
|
62
|
+
* Custom event handler to control navigation behavior.
|
|
63
|
+
* Should return `true` to allow router to navigate, otherwise to prevent it.
|
|
64
|
+
*
|
|
65
|
+
* @Note you need to call `e.preventDefault()` to prevent default browser navigation.
|
|
66
|
+
* @default
|
|
67
|
+
*
|
|
68
|
+
* (event: Event & Partial<MouseEvent>): boolean => {
|
|
69
|
+
* // don't redirect with control keys
|
|
70
|
+
* if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
|
|
71
|
+
* // don't redirect when preventDefault called
|
|
72
|
+
* if (e.defaultPrevented) return false;
|
|
73
|
+
* // don't redirect on right click
|
|
74
|
+
* if (e.button !== undefined && e.button !== 0) return false;
|
|
75
|
+
* // don't redirect if `target="_blank"`
|
|
76
|
+
* const target = e.currentTarget?.getAttribute?.('target') ?? '';
|
|
77
|
+
* if (/\b_blank\b/i.test(target)) return false;
|
|
78
|
+
* // Prevent default browser navigation to enable SPA routing
|
|
79
|
+
* // Note: this may be a Weex event which doesn't have this method
|
|
80
|
+
* if (e.preventDefault) e.preventDefault();
|
|
81
|
+
*
|
|
82
|
+
* return true;
|
|
83
|
+
* }
|
|
84
|
+
*/
|
|
85
|
+
eventHandler: {
|
|
86
|
+
type: Function
|
|
87
|
+
}
|
|
61
88
|
},
|
|
62
|
-
setup(props,
|
|
89
|
+
setup(props, context) {
|
|
90
|
+
const { slots, attrs } = context;
|
|
63
91
|
const link = useLink(props);
|
|
64
|
-
|
|
92
|
+
const wrapHandler = (externalHandler, internalHandler) => !internalHandler ? externalHandler : async (e) => {
|
|
93
|
+
try {
|
|
94
|
+
await externalHandler(e);
|
|
95
|
+
} finally {
|
|
96
|
+
await internalHandler(e);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const vue3renderer = () => {
|
|
65
100
|
var _a;
|
|
66
101
|
const data = link.value;
|
|
67
|
-
const
|
|
68
|
-
|
|
102
|
+
const genEventName = (name) => "on".concat(name.charAt(0).toUpperCase()).concat(name.slice(1));
|
|
103
|
+
const eventHandlers = data.getEventHandlers(genEventName);
|
|
104
|
+
Object.entries(attrs).forEach(([key, listener]) => {
|
|
105
|
+
if (!key.startsWith("on") || typeof listener !== "function")
|
|
106
|
+
return;
|
|
107
|
+
eventHandlers[key] = wrapHandler(listener, eventHandlers[key]);
|
|
108
|
+
});
|
|
109
|
+
return h(
|
|
110
|
+
data.tag,
|
|
111
|
+
{
|
|
112
|
+
...data.attributes,
|
|
113
|
+
...eventHandlers
|
|
114
|
+
},
|
|
115
|
+
(_a = slots.default) == null ? void 0 : _a.call(slots)
|
|
69
116
|
);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
117
|
+
};
|
|
118
|
+
const vue2renderer = () => {
|
|
119
|
+
var _a;
|
|
120
|
+
const data = link.value;
|
|
121
|
+
const eventHandlers = data.getEventHandlers();
|
|
122
|
+
const $listeners = context.listeners || {};
|
|
123
|
+
Object.entries($listeners).forEach(([key, listener]) => {
|
|
124
|
+
if (typeof listener !== "function") return;
|
|
125
|
+
eventHandlers[key] = wrapHandler(listener, eventHandlers[key]);
|
|
126
|
+
});
|
|
127
|
+
const { class: className, ...attrs2 } = data.attributes;
|
|
128
|
+
return h(
|
|
129
|
+
data.tag,
|
|
130
|
+
{
|
|
131
|
+
attrs: attrs2,
|
|
77
132
|
class: className,
|
|
78
133
|
on: eventHandlers
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
134
|
+
},
|
|
135
|
+
(_a = slots.default) == null ? void 0 : _a.call(slots)
|
|
136
|
+
);
|
|
82
137
|
};
|
|
138
|
+
return isVue3 ? vue3renderer : vue2renderer;
|
|
83
139
|
}
|
|
84
140
|
});
|
package/dist/use.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { createSymbolProperty } from "./util.mjs";
|
|
|
10
10
|
const ROUTER_CONTEXT_KEY = Symbol("router-context");
|
|
11
11
|
const ROUTER_INJECT_KEY = Symbol("router-inject");
|
|
12
12
|
const ERROR_MESSAGES = {
|
|
13
|
-
SETUP_ONLY: (fnName) =>
|
|
13
|
+
SETUP_ONLY: (fnName) => "[@esmx/router-vue] ".concat(fnName, "() can only be called during setup()"),
|
|
14
14
|
CONTEXT_NOT_FOUND: "[@esmx/router-vue] Router context not found. Please ensure useProvideRouter() is called in a parent component."
|
|
15
15
|
};
|
|
16
16
|
const routerContextProperty = createSymbolProperty(ROUTER_CONTEXT_KEY);
|
package/dist/use.test.mjs
CHANGED
|
@@ -75,7 +75,7 @@ describe("use.ts - Vue Router Integration", () => {
|
|
|
75
75
|
}
|
|
76
76
|
];
|
|
77
77
|
contextErrorTestCases.forEach(({ name, test }) => {
|
|
78
|
-
it(
|
|
78
|
+
it("should throw error when ".concat(name), () => {
|
|
79
79
|
expect(test()).toThrow(contextNotFoundError);
|
|
80
80
|
});
|
|
81
81
|
});
|
|
@@ -106,7 +106,7 @@ describe("use.ts - Vue Router Integration", () => {
|
|
|
106
106
|
}
|
|
107
107
|
];
|
|
108
108
|
compositionContextErrorTestCases.forEach(({ name, setupFn }) => {
|
|
109
|
-
it(
|
|
109
|
+
it("should throw error when ".concat(name), () => {
|
|
110
110
|
const TestComponent = defineComponent({
|
|
111
111
|
setup() {
|
|
112
112
|
setupFn();
|
|
@@ -147,7 +147,7 @@ describe("use.ts - Vue Router Integration", () => {
|
|
|
147
147
|
}
|
|
148
148
|
];
|
|
149
149
|
setupOnlyTestCases.forEach(({ name, fn, expectedError }) => {
|
|
150
|
-
it(
|
|
150
|
+
it("should throw error when ".concat(name), () => {
|
|
151
151
|
expect(fn).toThrow(expectedError);
|
|
152
152
|
});
|
|
153
153
|
});
|
|
@@ -385,7 +385,7 @@ describe("use.ts - Vue Router Integration", () => {
|
|
|
385
385
|
useProvideRouter(router);
|
|
386
386
|
const route = useRoute();
|
|
387
387
|
routeRef = route;
|
|
388
|
-
return () =>
|
|
388
|
+
return () => "<div>Current: ".concat(route.path, "</div>");
|
|
389
389
|
}
|
|
390
390
|
});
|
|
391
391
|
const app = createApp(TestComponent);
|
package/dist/util.test.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
5
|
import { version } from "vue";
|
|
3
6
|
import {
|
|
@@ -202,7 +205,7 @@ describe("util.ts - Utility Functions", () => {
|
|
|
202
205
|
describe("should return null for falsy inputs", () => {
|
|
203
206
|
const falsyValues = [null, void 0, false, 0, "", Number.NaN];
|
|
204
207
|
falsyValues.forEach((value) => {
|
|
205
|
-
it(
|
|
208
|
+
it("should return null for ".concat(value), () => {
|
|
206
209
|
expect(resolveComponent(value)).toBeNull();
|
|
207
210
|
});
|
|
208
211
|
});
|
|
@@ -272,7 +275,9 @@ describe("util.ts - Utility Functions", () => {
|
|
|
272
275
|
});
|
|
273
276
|
it("should return class components directly", () => {
|
|
274
277
|
class ClassComponent {
|
|
275
|
-
|
|
278
|
+
constructor() {
|
|
279
|
+
__publicField(this, "name", "ClassComponent");
|
|
280
|
+
}
|
|
276
281
|
}
|
|
277
282
|
const result = resolveComponent(ClassComponent);
|
|
278
283
|
expect(result).toBe(ClassComponent);
|
package/package.json
CHANGED
|
@@ -50,21 +50,21 @@
|
|
|
50
50
|
"vue": "^3.5.0 || ^2.7.0"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@esmx/router": "3.0.0-rc.
|
|
53
|
+
"@esmx/router": "3.0.0-rc.26"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@biomejs/biome": "1.9.4",
|
|
57
|
-
"@esmx/lint": "3.0.0-rc.
|
|
58
|
-
"@types/node": "
|
|
59
|
-
"@vitest/coverage-v8": "3.
|
|
60
|
-
"stylelint": "16.
|
|
61
|
-
"typescript": "5.8.
|
|
57
|
+
"@esmx/lint": "3.0.0-rc.26",
|
|
58
|
+
"@types/node": "^24.0.10",
|
|
59
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
60
|
+
"stylelint": "16.21.0",
|
|
61
|
+
"typescript": "5.8.3",
|
|
62
62
|
"unbuild": "3.5.0",
|
|
63
|
-
"vitest": "3.
|
|
63
|
+
"vitest": "3.2.4",
|
|
64
64
|
"vue": "3.5.13",
|
|
65
65
|
"vue2": "npm:vue@2.7.16"
|
|
66
66
|
},
|
|
67
|
-
"version": "3.0.0-rc.
|
|
67
|
+
"version": "3.0.0-rc.26",
|
|
68
68
|
"type": "module",
|
|
69
69
|
"private": false,
|
|
70
70
|
"exports": {
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"template",
|
|
84
84
|
"public"
|
|
85
85
|
],
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "2f52f94c8ac27aca32ef3148afd109d0f0470d52"
|
|
87
87
|
}
|
package/src/router-link.ts
CHANGED
|
@@ -77,7 +77,7 @@ export const RouterLink = defineComponent({
|
|
|
77
77
|
type: { type: String as PropType<RouterLinkType>, default: 'push' },
|
|
78
78
|
/**
|
|
79
79
|
* @deprecated Use 'type="replace"' instead
|
|
80
|
-
* @example replace={true} → type="replace"
|
|
80
|
+
* @example :replace={true} → type="replace"
|
|
81
81
|
*/
|
|
82
82
|
replace: { type: Boolean, default: false },
|
|
83
83
|
/**
|
|
@@ -113,36 +113,102 @@ export const RouterLink = defineComponent({
|
|
|
113
113
|
* Only used when type='pushLayer'.
|
|
114
114
|
* @example { zIndex: 1000, autoPush: false, routerOptions: { mode: 'memory' } }
|
|
115
115
|
*/
|
|
116
|
-
layerOptions: { type: Object as PropType<RouteLayerOptions> }
|
|
116
|
+
layerOptions: { type: Object as PropType<RouteLayerOptions> },
|
|
117
|
+
/**
|
|
118
|
+
* Custom event handler to control navigation behavior.
|
|
119
|
+
* Should return `true` to allow router to navigate, otherwise to prevent it.
|
|
120
|
+
*
|
|
121
|
+
* @Note you need to call `e.preventDefault()` to prevent default browser navigation.
|
|
122
|
+
* @default
|
|
123
|
+
*
|
|
124
|
+
* (event: Event & Partial<MouseEvent>): boolean => {
|
|
125
|
+
* // don't redirect with control keys
|
|
126
|
+
* if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
|
|
127
|
+
* // don't redirect when preventDefault called
|
|
128
|
+
* if (e.defaultPrevented) return false;
|
|
129
|
+
* // don't redirect on right click
|
|
130
|
+
* if (e.button !== undefined && e.button !== 0) return false;
|
|
131
|
+
* // don't redirect if `target="_blank"`
|
|
132
|
+
* const target = e.currentTarget?.getAttribute?.('target') ?? '';
|
|
133
|
+
* if (/\b_blank\b/i.test(target)) return false;
|
|
134
|
+
* // Prevent default browser navigation to enable SPA routing
|
|
135
|
+
* // Note: this may be a Weex event which doesn't have this method
|
|
136
|
+
* if (e.preventDefault) e.preventDefault();
|
|
137
|
+
*
|
|
138
|
+
* return true;
|
|
139
|
+
* }
|
|
140
|
+
*/
|
|
141
|
+
eventHandler: {
|
|
142
|
+
type: Function as PropType<
|
|
143
|
+
(event: Event) => boolean | undefined | void
|
|
144
|
+
>
|
|
145
|
+
}
|
|
117
146
|
},
|
|
118
147
|
|
|
119
|
-
setup(props,
|
|
148
|
+
setup(props, context) {
|
|
149
|
+
const { slots, attrs } = context;
|
|
120
150
|
const link = useLink(props);
|
|
121
151
|
|
|
122
|
-
|
|
152
|
+
const wrapHandler = (
|
|
153
|
+
externalHandler: Function,
|
|
154
|
+
internalHandler: Function | undefined
|
|
155
|
+
) =>
|
|
156
|
+
!internalHandler
|
|
157
|
+
? (externalHandler as (e: Event) => Promise<void>)
|
|
158
|
+
: async (e: Event) => {
|
|
159
|
+
try {
|
|
160
|
+
await externalHandler(e);
|
|
161
|
+
} finally {
|
|
162
|
+
await internalHandler(e);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const vue3renderer = () => {
|
|
123
167
|
const data = link.value;
|
|
168
|
+
const genEventName = (name: string): string =>
|
|
169
|
+
`on${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
124
170
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
171
|
+
const eventHandlers = data.getEventHandlers(genEventName);
|
|
172
|
+
Object.entries(attrs).forEach(([key, listener]) => {
|
|
173
|
+
// In Vue 3, external event handlers are in attrs with 'on' prefix
|
|
174
|
+
if (!key.startsWith('on') || typeof listener !== 'function')
|
|
175
|
+
return;
|
|
176
|
+
eventHandlers[key] = wrapHandler(listener, eventHandlers[key]);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return h(
|
|
180
|
+
data.tag,
|
|
181
|
+
{
|
|
182
|
+
...data.attributes,
|
|
183
|
+
...eventHandlers
|
|
184
|
+
},
|
|
185
|
+
slots.default?.()
|
|
131
186
|
);
|
|
187
|
+
};
|
|
132
188
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
189
|
+
const vue2renderer = () => {
|
|
190
|
+
const data = link.value;
|
|
191
|
+
|
|
192
|
+
const eventHandlers = data.getEventHandlers();
|
|
193
|
+
// Vue 2: get external listeners from context
|
|
194
|
+
const $listeners = (context as any).listeners || {};
|
|
195
|
+
Object.entries($listeners).forEach(([key, listener]) => {
|
|
196
|
+
if (typeof listener !== 'function') return;
|
|
197
|
+
eventHandlers[key] = wrapHandler(listener, eventHandlers[key]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const { class: className, ...attrs } = data.attributes;
|
|
201
|
+
return h(
|
|
202
|
+
data.tag,
|
|
203
|
+
{
|
|
139
204
|
attrs,
|
|
140
205
|
class: className,
|
|
141
206
|
on: eventHandlers
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return h(data.tag, props, slots.default?.());
|
|
207
|
+
},
|
|
208
|
+
slots.default?.()
|
|
209
|
+
);
|
|
146
210
|
};
|
|
211
|
+
|
|
212
|
+
return isVue3 ? vue3renderer : vue2renderer;
|
|
147
213
|
}
|
|
148
214
|
});
|