@esmx/router-vue 3.0.0-rc.16 → 3.0.0-rc.19
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/LICENSE +1 -1
- package/README.md +563 -0
- package/README.zh-CN.md +563 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.mjs +11 -4
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.mjs +206 -0
- package/dist/plugin.d.ts +55 -11
- package/dist/plugin.mjs +32 -16
- package/dist/plugin.test.d.ts +1 -0
- package/dist/plugin.test.mjs +436 -0
- package/dist/router-link.d.ts +202 -0
- package/dist/router-link.mjs +84 -0
- package/dist/router-link.test.d.ts +1 -0
- package/dist/router-link.test.mjs +456 -0
- package/dist/router-view.d.ts +30 -0
- package/dist/router-view.mjs +17 -0
- package/dist/router-view.test.d.ts +1 -0
- package/dist/router-view.test.mjs +459 -0
- package/dist/use.d.ts +198 -3
- package/dist/use.mjs +75 -9
- package/dist/use.test.d.ts +1 -0
- package/dist/use.test.mjs +461 -0
- package/dist/util.d.ts +7 -0
- package/dist/util.mjs +24 -0
- package/dist/util.test.d.ts +1 -0
- package/dist/util.test.mjs +319 -0
- package/dist/vue2.d.ts +13 -0
- package/dist/vue2.mjs +0 -0
- package/dist/vue3.d.ts +13 -0
- package/dist/vue3.mjs +0 -0
- package/package.json +31 -14
- package/src/index.test.ts +263 -0
- package/src/index.ts +16 -4
- package/src/plugin.test.ts +574 -0
- package/src/plugin.ts +86 -31
- package/src/router-link.test.ts +569 -0
- package/src/router-link.ts +148 -0
- package/src/router-view.test.ts +599 -0
- package/src/router-view.ts +61 -0
- package/src/use.test.ts +616 -0
- package/src/use.ts +307 -11
- package/src/util.test.ts +418 -0
- package/src/util.ts +32 -0
- package/src/vue2.ts +16 -0
- package/src/vue3.ts +15 -0
- package/dist/link.d.ts +0 -101
- package/dist/link.mjs +0 -103
- package/dist/symbols.d.ts +0 -3
- package/dist/symbols.mjs +0 -3
- package/dist/view.d.ts +0 -21
- package/dist/view.mjs +0 -75
- package/src/link.ts +0 -177
- package/src/symbols.ts +0 -8
- package/src/view.ts +0 -95
package/src/util.test.ts
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment happy-dom
|
|
3
|
+
*/
|
|
4
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { version } from 'vue';
|
|
6
|
+
import {
|
|
7
|
+
createSymbolProperty,
|
|
8
|
+
isESModule,
|
|
9
|
+
isVue3,
|
|
10
|
+
resolveComponent
|
|
11
|
+
} from './util';
|
|
12
|
+
|
|
13
|
+
describe('util.ts - Utility Functions', () => {
|
|
14
|
+
describe('isVue3', () => {
|
|
15
|
+
it('should correctly identify Vue 3', () => {
|
|
16
|
+
// Since we're testing in a Vue 3 environment, isVue3 should be true
|
|
17
|
+
expect(isVue3).toBe(version.startsWith('3.'));
|
|
18
|
+
expect(typeof isVue3).toBe('boolean');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should be consistent with Vue version check', () => {
|
|
22
|
+
// Verify the logic is correct
|
|
23
|
+
const expectedResult = version.startsWith('3.');
|
|
24
|
+
expect(isVue3).toBe(expectedResult);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('createSymbolProperty', () => {
|
|
29
|
+
let testSymbol: symbol;
|
|
30
|
+
let symbolProperty: ReturnType<typeof createSymbolProperty>;
|
|
31
|
+
let testInstance: Record<string | symbol, unknown>;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
testSymbol = Symbol('test-symbol');
|
|
35
|
+
symbolProperty = createSymbolProperty<string>(testSymbol);
|
|
36
|
+
testInstance = {};
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('set method', () => {
|
|
40
|
+
it('should set value using symbol as key', () => {
|
|
41
|
+
const testValue = 'test-value';
|
|
42
|
+
|
|
43
|
+
symbolProperty.set(testInstance, testValue);
|
|
44
|
+
|
|
45
|
+
expect(testInstance[testSymbol]).toBe(testValue);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should handle different value types', () => {
|
|
49
|
+
const stringValue = 'string-value';
|
|
50
|
+
const numberValue = 42;
|
|
51
|
+
const objectValue = { key: 'value' };
|
|
52
|
+
const arrayValue = [1, 2, 3];
|
|
53
|
+
|
|
54
|
+
const stringProperty = createSymbolProperty<string>(
|
|
55
|
+
Symbol('string')
|
|
56
|
+
);
|
|
57
|
+
const numberProperty = createSymbolProperty<number>(
|
|
58
|
+
Symbol('number')
|
|
59
|
+
);
|
|
60
|
+
const objectProperty = createSymbolProperty<object>(
|
|
61
|
+
Symbol('object')
|
|
62
|
+
);
|
|
63
|
+
const arrayProperty = createSymbolProperty<number[]>(
|
|
64
|
+
Symbol('array')
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
stringProperty.set(testInstance, stringValue);
|
|
68
|
+
numberProperty.set(testInstance, numberValue);
|
|
69
|
+
objectProperty.set(testInstance, objectValue);
|
|
70
|
+
arrayProperty.set(testInstance, arrayValue);
|
|
71
|
+
|
|
72
|
+
expect(stringProperty.get(testInstance)).toBe(stringValue);
|
|
73
|
+
expect(numberProperty.get(testInstance)).toBe(numberValue);
|
|
74
|
+
expect(objectProperty.get(testInstance)).toBe(objectValue);
|
|
75
|
+
expect(arrayProperty.get(testInstance)).toBe(arrayValue);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should overwrite existing value', () => {
|
|
79
|
+
const firstValue = 'first-value';
|
|
80
|
+
const secondValue = 'second-value';
|
|
81
|
+
|
|
82
|
+
symbolProperty.set(testInstance, firstValue);
|
|
83
|
+
expect(symbolProperty.get(testInstance)).toBe(firstValue);
|
|
84
|
+
|
|
85
|
+
symbolProperty.set(testInstance, secondValue);
|
|
86
|
+
expect(symbolProperty.get(testInstance)).toBe(secondValue);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('get method', () => {
|
|
91
|
+
it('should return undefined for non-existent symbol', () => {
|
|
92
|
+
const result = symbolProperty.get(testInstance);
|
|
93
|
+
|
|
94
|
+
expect(result).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should return correct value after setting', () => {
|
|
98
|
+
const testValue = 'retrieved-value';
|
|
99
|
+
|
|
100
|
+
symbolProperty.set(testInstance, testValue);
|
|
101
|
+
const result = symbolProperty.get(testInstance);
|
|
102
|
+
|
|
103
|
+
expect(result).toBe(testValue);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should return undefined after value is deleted', () => {
|
|
107
|
+
const testValue = 'temporary-value';
|
|
108
|
+
|
|
109
|
+
symbolProperty.set(testInstance, testValue);
|
|
110
|
+
delete testInstance[testSymbol];
|
|
111
|
+
const result = symbolProperty.get(testInstance);
|
|
112
|
+
|
|
113
|
+
expect(result).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('symbol isolation', () => {
|
|
118
|
+
it('should not interfere with different symbols', () => {
|
|
119
|
+
const symbol1 = Symbol('symbol1');
|
|
120
|
+
const symbol2 = Symbol('symbol2');
|
|
121
|
+
const property1 = createSymbolProperty<string>(symbol1);
|
|
122
|
+
const property2 = createSymbolProperty<string>(symbol2);
|
|
123
|
+
|
|
124
|
+
const value1 = 'value1';
|
|
125
|
+
const value2 = 'value2';
|
|
126
|
+
|
|
127
|
+
property1.set(testInstance, value1);
|
|
128
|
+
property2.set(testInstance, value2);
|
|
129
|
+
|
|
130
|
+
expect(property1.get(testInstance)).toBe(value1);
|
|
131
|
+
expect(property2.get(testInstance)).toBe(value2);
|
|
132
|
+
expect(property1.get(testInstance)).not.toBe(value2);
|
|
133
|
+
expect(property2.get(testInstance)).not.toBe(value1);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should work with multiple instances', () => {
|
|
137
|
+
const instance1 = {};
|
|
138
|
+
const instance2 = {};
|
|
139
|
+
const testValue1 = 'instance1-value';
|
|
140
|
+
const testValue2 = 'instance2-value';
|
|
141
|
+
|
|
142
|
+
symbolProperty.set(instance1, testValue1);
|
|
143
|
+
symbolProperty.set(instance2, testValue2);
|
|
144
|
+
|
|
145
|
+
expect(symbolProperty.get(instance1)).toBe(testValue1);
|
|
146
|
+
expect(symbolProperty.get(instance2)).toBe(testValue2);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('type safety', () => {
|
|
151
|
+
it('should maintain type information through generic', () => {
|
|
152
|
+
interface TestInterface {
|
|
153
|
+
name: string;
|
|
154
|
+
count: number;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const interfaceSymbol = Symbol('interface');
|
|
158
|
+
const interfaceProperty =
|
|
159
|
+
createSymbolProperty<TestInterface>(interfaceSymbol);
|
|
160
|
+
const testObject: TestInterface = { name: 'test', count: 5 };
|
|
161
|
+
|
|
162
|
+
interfaceProperty.set(testInstance, testObject);
|
|
163
|
+
const result = interfaceProperty.get(testInstance);
|
|
164
|
+
|
|
165
|
+
expect(result).toEqual(testObject);
|
|
166
|
+
expect(result?.name).toBe('test');
|
|
167
|
+
expect(result?.count).toBe(5);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('isESModule', () => {
|
|
173
|
+
describe('should return true for ES modules', () => {
|
|
174
|
+
it('should identify module with __esModule property', () => {
|
|
175
|
+
const esModule = { __esModule: true };
|
|
176
|
+
|
|
177
|
+
expect(isESModule(esModule)).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should identify module with Symbol.toStringTag', () => {
|
|
181
|
+
const esModule = { [Symbol.toStringTag]: 'Module' };
|
|
182
|
+
|
|
183
|
+
expect(isESModule(esModule)).toBe(true);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should identify module with both properties', () => {
|
|
187
|
+
const esModule = {
|
|
188
|
+
__esModule: true,
|
|
189
|
+
[Symbol.toStringTag]: 'Module'
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
expect(isESModule(esModule)).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should handle truthy __esModule values', () => {
|
|
196
|
+
const testCases = [
|
|
197
|
+
{ __esModule: true },
|
|
198
|
+
{ __esModule: 1 },
|
|
199
|
+
{ __esModule: 'true' },
|
|
200
|
+
{ __esModule: {} },
|
|
201
|
+
{ __esModule: [] }
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
testCases.forEach((moduleObj) => {
|
|
205
|
+
expect(isESModule(moduleObj)).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('should return false for non-ES modules', () => {
|
|
211
|
+
it('should return false for null', () => {
|
|
212
|
+
expect(isESModule(null)).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should return false for undefined', () => {
|
|
216
|
+
expect(isESModule(undefined)).toBe(false);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should return false for plain objects', () => {
|
|
220
|
+
const plainObject = { key: 'value' };
|
|
221
|
+
|
|
222
|
+
expect(isESModule(plainObject)).toBe(false);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should return false for objects with falsy __esModule', () => {
|
|
226
|
+
const testCases = [
|
|
227
|
+
{ __esModule: false },
|
|
228
|
+
{ __esModule: 0 },
|
|
229
|
+
{ __esModule: '' },
|
|
230
|
+
{ __esModule: null },
|
|
231
|
+
{ __esModule: undefined }
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
testCases.forEach((moduleObj) => {
|
|
235
|
+
expect(isESModule(moduleObj)).toBe(false);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should return false for objects with wrong Symbol.toStringTag', () => {
|
|
240
|
+
const testCases = [
|
|
241
|
+
{ [Symbol.toStringTag]: 'Object' },
|
|
242
|
+
{ [Symbol.toStringTag]: 'Function' },
|
|
243
|
+
{ [Symbol.toStringTag]: 'Array' },
|
|
244
|
+
{ [Symbol.toStringTag]: '' },
|
|
245
|
+
{ [Symbol.toStringTag]: null }
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
testCases.forEach((moduleObj) => {
|
|
249
|
+
expect(isESModule(moduleObj)).toBe(false);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should return false for primitive values', () => {
|
|
254
|
+
const primitives = ['string', 42, true, false, Symbol('test')];
|
|
255
|
+
|
|
256
|
+
primitives.forEach((primitive) => {
|
|
257
|
+
expect(isESModule(primitive)).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe('resolveComponent', () => {
|
|
264
|
+
describe('should return null for falsy inputs', () => {
|
|
265
|
+
const falsyValues = [null, undefined, false, 0, '', Number.NaN];
|
|
266
|
+
|
|
267
|
+
falsyValues.forEach((value) => {
|
|
268
|
+
it(`should return null for ${value}`, () => {
|
|
269
|
+
expect(resolveComponent(value)).toBeNull();
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe('should handle ES modules', () => {
|
|
275
|
+
it('should return default export when available', () => {
|
|
276
|
+
const defaultComponent = { name: 'DefaultComponent' };
|
|
277
|
+
const esModule = {
|
|
278
|
+
__esModule: true,
|
|
279
|
+
default: defaultComponent,
|
|
280
|
+
namedExport: { name: 'NamedComponent' }
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const result = resolveComponent(esModule);
|
|
284
|
+
|
|
285
|
+
expect(result).toBe(defaultComponent);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('should return the module itself when no default export', () => {
|
|
289
|
+
const esModule = {
|
|
290
|
+
__esModule: true,
|
|
291
|
+
namedExport: { name: 'NamedComponent' }
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const result = resolveComponent(esModule);
|
|
295
|
+
|
|
296
|
+
expect(result).toBe(esModule);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should prefer default export over module when both exist', () => {
|
|
300
|
+
const defaultComponent = { name: 'DefaultComponent' };
|
|
301
|
+
const esModule = {
|
|
302
|
+
__esModule: true,
|
|
303
|
+
default: defaultComponent,
|
|
304
|
+
name: 'ModuleComponent'
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const result = resolveComponent(esModule);
|
|
308
|
+
|
|
309
|
+
expect(result).toBe(defaultComponent);
|
|
310
|
+
expect(result).not.toBe(esModule);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should handle modules with Symbol.toStringTag', () => {
|
|
314
|
+
const defaultComponent = { name: 'SymbolTagComponent' };
|
|
315
|
+
const esModule = {
|
|
316
|
+
[Symbol.toStringTag]: 'Module',
|
|
317
|
+
default: defaultComponent
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const result = resolveComponent(esModule);
|
|
321
|
+
|
|
322
|
+
expect(result).toBe(defaultComponent);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should handle falsy default export', () => {
|
|
326
|
+
const falsyDefaults = [null, undefined, false, 0, ''];
|
|
327
|
+
|
|
328
|
+
falsyDefaults.forEach((falsyDefault) => {
|
|
329
|
+
const esModule = {
|
|
330
|
+
__esModule: true,
|
|
331
|
+
default: falsyDefault,
|
|
332
|
+
fallback: { name: 'FallbackComponent' }
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const result = resolveComponent(esModule);
|
|
336
|
+
|
|
337
|
+
// Should return the module itself when default is falsy
|
|
338
|
+
expect(result).toBe(esModule);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
describe('should handle non-ES modules', () => {
|
|
344
|
+
it('should return component directly for non-ES modules', () => {
|
|
345
|
+
const component = { name: 'RegularComponent' };
|
|
346
|
+
|
|
347
|
+
const result = resolveComponent(component);
|
|
348
|
+
|
|
349
|
+
expect(result).toBe(component);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should return function components directly', () => {
|
|
353
|
+
const functionComponent = () => ({ name: 'FunctionComponent' });
|
|
354
|
+
|
|
355
|
+
const result = resolveComponent(functionComponent);
|
|
356
|
+
|
|
357
|
+
expect(result).toBe(functionComponent);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should return class components directly', () => {
|
|
361
|
+
class ClassComponent {
|
|
362
|
+
name = 'ClassComponent';
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const result = resolveComponent(ClassComponent);
|
|
366
|
+
|
|
367
|
+
expect(result).toBe(ClassComponent);
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
describe('edge cases', () => {
|
|
372
|
+
it('should handle circular references in modules', () => {
|
|
373
|
+
const esModule: Record<string, unknown> = {
|
|
374
|
+
__esModule: true
|
|
375
|
+
};
|
|
376
|
+
esModule.default = esModule; // Circular reference
|
|
377
|
+
|
|
378
|
+
const result = resolveComponent(esModule);
|
|
379
|
+
|
|
380
|
+
expect(result).toBe(esModule);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should handle deeply nested default exports', () => {
|
|
384
|
+
const actualComponent = { name: 'DeepComponent' };
|
|
385
|
+
const esModule = {
|
|
386
|
+
__esModule: true,
|
|
387
|
+
default: {
|
|
388
|
+
default: {
|
|
389
|
+
default: actualComponent
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const result = resolveComponent(esModule);
|
|
395
|
+
|
|
396
|
+
// Should only resolve one level of default
|
|
397
|
+
expect(result).toEqual({
|
|
398
|
+
default: {
|
|
399
|
+
default: actualComponent
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('should handle modules with both __esModule and Symbol.toStringTag', () => {
|
|
405
|
+
const defaultComponent = { name: 'BothPropertiesComponent' };
|
|
406
|
+
const esModule = {
|
|
407
|
+
__esModule: true,
|
|
408
|
+
[Symbol.toStringTag]: 'Module',
|
|
409
|
+
default: defaultComponent
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const result = resolveComponent(esModule);
|
|
413
|
+
|
|
414
|
+
expect(result).toBe(defaultComponent);
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
});
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { version } from 'vue';
|
|
2
|
+
|
|
3
|
+
export const isVue3 = version.startsWith('3.');
|
|
4
|
+
|
|
5
|
+
export function createSymbolProperty<T>(symbol: symbol) {
|
|
6
|
+
return {
|
|
7
|
+
set(instance: any, value: T): void {
|
|
8
|
+
instance[symbol] = value;
|
|
9
|
+
},
|
|
10
|
+
get(instance: any): T | undefined {
|
|
11
|
+
return instance[symbol];
|
|
12
|
+
}
|
|
13
|
+
} as const;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isESModule(obj: unknown): obj is Record<string | symbol, any> {
|
|
17
|
+
if (!obj || typeof obj !== 'object') return false;
|
|
18
|
+
const module = obj as Record<string | symbol, any>;
|
|
19
|
+
return (
|
|
20
|
+
Boolean(module.__esModule) || module[Symbol.toStringTag] === 'Module'
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resolveComponent(component: unknown): unknown {
|
|
25
|
+
if (!component) return null;
|
|
26
|
+
|
|
27
|
+
if (isESModule(component)) {
|
|
28
|
+
return component.default || component;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return component;
|
|
32
|
+
}
|
package/src/vue2.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Route, Router } from '@esmx/router';
|
|
2
|
+
import type Vue from 'vue2';
|
|
3
|
+
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
declare module 'vue/types/vue' {
|
|
6
|
+
interface Vue {
|
|
7
|
+
readonly $router: Router;
|
|
8
|
+
readonly $route: Route;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
declare module 'vue2/types/vue' {
|
|
12
|
+
interface Vue {
|
|
13
|
+
readonly $router: Router;
|
|
14
|
+
readonly $route: Route;
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/vue3.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Route, Router } from '@esmx/router';
|
|
2
|
+
import type { RouterLink } from './router-link';
|
|
3
|
+
import type { RouterView } from './router-view';
|
|
4
|
+
|
|
5
|
+
declare module 'vue' {
|
|
6
|
+
interface ComponentCustomProperties {
|
|
7
|
+
readonly $router: Router;
|
|
8
|
+
readonly $route: Route;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface GlobalComponents {
|
|
12
|
+
RouterLink: typeof RouterLink;
|
|
13
|
+
RouterView: typeof RouterView;
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/link.d.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { type RouterRawLocation } from '@esmx/router';
|
|
2
|
-
import { type PropType } from 'vue';
|
|
3
|
-
export interface RouterLinkProps {
|
|
4
|
-
/**
|
|
5
|
-
* 前往的路由路径
|
|
6
|
-
*/
|
|
7
|
-
to: RouterRawLocation;
|
|
8
|
-
/**
|
|
9
|
-
* 节点使用的标签名
|
|
10
|
-
* @default 'a'
|
|
11
|
-
*/
|
|
12
|
-
tag: string;
|
|
13
|
-
/**
|
|
14
|
-
* 调用 router.replace 以替换 router.push。
|
|
15
|
-
* @default false
|
|
16
|
-
*/
|
|
17
|
-
replace: boolean;
|
|
18
|
-
/**
|
|
19
|
-
* 路径激活匹配规则
|
|
20
|
-
* @example include => 路径包含即激活.
|
|
21
|
-
* 如: 当前路由为/en/news/list 此时router-link 的路径为 /en/news 也会激活
|
|
22
|
-
* @example route => 路由匹配才会激活,需要匹配的路由树一致.
|
|
23
|
-
* 如: 当前路由为/en/news/list/123 此时router-link 的路径为 /en/news/list 也会激活
|
|
24
|
-
* @example exact => 路径全匹配才会激活,不仅需要匹配路由树一致,还需要参数匹配才会激活.
|
|
25
|
-
* 如: 当前路由为/en/news/list/123 此时router-link 的路径为 /en/news/list/123 才会激活,如果配置的路径为/en/news/list/123456 也不会激活
|
|
26
|
-
* @default 'include'
|
|
27
|
-
*/
|
|
28
|
-
exact: 'include' | 'route' | 'exact';
|
|
29
|
-
/**
|
|
30
|
-
* 是否为相对路径
|
|
31
|
-
* 按照 Hanson 要求目前都是绝对路径,因此废弃此属性
|
|
32
|
-
* @default false
|
|
33
|
-
*/
|
|
34
|
-
/**
|
|
35
|
-
* 路由激活时的class
|
|
36
|
-
* @default 'router-link-active'
|
|
37
|
-
*/
|
|
38
|
-
activeClass: string;
|
|
39
|
-
/**
|
|
40
|
-
* 哪些事件触发路由跳转
|
|
41
|
-
* @default 'click'
|
|
42
|
-
*/
|
|
43
|
-
event: string | string[];
|
|
44
|
-
}
|
|
45
|
-
export declare const RouterLink: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
46
|
-
to: {
|
|
47
|
-
type: PropType<RouterLinkProps["to"]>;
|
|
48
|
-
required: true;
|
|
49
|
-
};
|
|
50
|
-
tag: {
|
|
51
|
-
type: PropType<RouterLinkProps["tag"]>;
|
|
52
|
-
default: string;
|
|
53
|
-
};
|
|
54
|
-
replace: {
|
|
55
|
-
type: PropType<RouterLinkProps["replace"]>;
|
|
56
|
-
default: boolean;
|
|
57
|
-
};
|
|
58
|
-
exact: {
|
|
59
|
-
type: PropType<RouterLinkProps["exact"]>;
|
|
60
|
-
default: string;
|
|
61
|
-
};
|
|
62
|
-
activeClass: {
|
|
63
|
-
type: PropType<RouterLinkProps["activeClass"]>;
|
|
64
|
-
default: string;
|
|
65
|
-
};
|
|
66
|
-
event: {
|
|
67
|
-
type: PropType<RouterLinkProps["event"]>;
|
|
68
|
-
default: string;
|
|
69
|
-
};
|
|
70
|
-
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
71
|
-
to: {
|
|
72
|
-
type: PropType<RouterLinkProps["to"]>;
|
|
73
|
-
required: true;
|
|
74
|
-
};
|
|
75
|
-
tag: {
|
|
76
|
-
type: PropType<RouterLinkProps["tag"]>;
|
|
77
|
-
default: string;
|
|
78
|
-
};
|
|
79
|
-
replace: {
|
|
80
|
-
type: PropType<RouterLinkProps["replace"]>;
|
|
81
|
-
default: boolean;
|
|
82
|
-
};
|
|
83
|
-
exact: {
|
|
84
|
-
type: PropType<RouterLinkProps["exact"]>;
|
|
85
|
-
default: string;
|
|
86
|
-
};
|
|
87
|
-
activeClass: {
|
|
88
|
-
type: PropType<RouterLinkProps["activeClass"]>;
|
|
89
|
-
default: string;
|
|
90
|
-
};
|
|
91
|
-
event: {
|
|
92
|
-
type: PropType<RouterLinkProps["event"]>;
|
|
93
|
-
default: string;
|
|
94
|
-
};
|
|
95
|
-
}>> & Readonly<{}>, {
|
|
96
|
-
exact: "include" | "route" | "exact";
|
|
97
|
-
tag: string;
|
|
98
|
-
replace: boolean;
|
|
99
|
-
activeClass: string;
|
|
100
|
-
event: string | string[];
|
|
101
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
package/dist/link.mjs
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isEqualRoute,
|
|
3
|
-
isSameRoute
|
|
4
|
-
} from "@esmx/router";
|
|
5
|
-
import { defineComponent, h } from "vue";
|
|
6
|
-
import { useRoute, useRouter } from "./use.mjs";
|
|
7
|
-
export const RouterLink = defineComponent({
|
|
8
|
-
props: {
|
|
9
|
-
to: {
|
|
10
|
-
type: [String, Object],
|
|
11
|
-
required: true
|
|
12
|
-
},
|
|
13
|
-
tag: {
|
|
14
|
-
type: String,
|
|
15
|
-
default: "a"
|
|
16
|
-
},
|
|
17
|
-
replace: {
|
|
18
|
-
type: Boolean,
|
|
19
|
-
default: false
|
|
20
|
-
},
|
|
21
|
-
exact: {
|
|
22
|
-
type: String,
|
|
23
|
-
default: "include"
|
|
24
|
-
},
|
|
25
|
-
// append: {
|
|
26
|
-
// type: Boolean as PropType<boolean>,
|
|
27
|
-
// default: false
|
|
28
|
-
// },
|
|
29
|
-
activeClass: {
|
|
30
|
-
type: String,
|
|
31
|
-
default: "router-link-active"
|
|
32
|
-
},
|
|
33
|
-
event: {
|
|
34
|
-
type: String,
|
|
35
|
-
default: "click"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
render(props) {
|
|
39
|
-
const { to, tag, replace, exact, activeClass, event } = props;
|
|
40
|
-
const router = useRouter();
|
|
41
|
-
const current = useRoute();
|
|
42
|
-
const resolveRoute = router.resolve(to);
|
|
43
|
-
let compare;
|
|
44
|
-
switch (exact) {
|
|
45
|
-
/* 路由级匹配 */
|
|
46
|
-
case "route":
|
|
47
|
-
compare = isSameRoute;
|
|
48
|
-
break;
|
|
49
|
-
/* 全匹配 */
|
|
50
|
-
case "exact":
|
|
51
|
-
compare = isEqualRoute;
|
|
52
|
-
break;
|
|
53
|
-
/* 是否包含 */
|
|
54
|
-
case "include":
|
|
55
|
-
default:
|
|
56
|
-
compare = (current2, route) => {
|
|
57
|
-
return current2.fullPath.startsWith(route.fullPath);
|
|
58
|
-
};
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
const active = compare(current, resolveRoute);
|
|
62
|
-
const handler = (e) => {
|
|
63
|
-
if (guardEvent(e)) {
|
|
64
|
-
router[replace ? "replace" : "push"](to);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
const on = {};
|
|
68
|
-
const eventTypeList = getEventTypeList(event);
|
|
69
|
-
eventTypeList.forEach((eventName) => {
|
|
70
|
-
on[`on${eventName.toLocaleLowerCase()}`] = handler;
|
|
71
|
-
});
|
|
72
|
-
return h(
|
|
73
|
-
tag,
|
|
74
|
-
{
|
|
75
|
-
class: ["router-link", active ? [activeClass] : ""],
|
|
76
|
-
href: resolveRoute.fullPath,
|
|
77
|
-
...on
|
|
78
|
-
},
|
|
79
|
-
this.$slots
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
function getEventTypeList(eventType) {
|
|
84
|
-
if (eventType instanceof Array) {
|
|
85
|
-
if (eventType.length > 0) {
|
|
86
|
-
return eventType;
|
|
87
|
-
}
|
|
88
|
-
return ["click"];
|
|
89
|
-
}
|
|
90
|
-
return [eventType || "click"];
|
|
91
|
-
}
|
|
92
|
-
function guardEvent(e) {
|
|
93
|
-
var _a;
|
|
94
|
-
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return;
|
|
95
|
-
if (e.defaultPrevented) return;
|
|
96
|
-
if (e.button !== void 0 && e.button !== 0) return;
|
|
97
|
-
if ((_a = e.currentTarget) == null ? void 0 : _a.getAttribute) {
|
|
98
|
-
const target = e.currentTarget.getAttribute("target");
|
|
99
|
-
if (/\b_blank\b/i.test(target)) return;
|
|
100
|
-
}
|
|
101
|
-
if (e.preventDefault) e.preventDefault();
|
|
102
|
-
return true;
|
|
103
|
-
}
|
package/dist/symbols.d.ts
DELETED
package/dist/symbols.mjs
DELETED