@mantou/gem 1.6.9 → 1.6.10
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/gem.es.js +170 -182
- package/dist/gem.umd.js +23 -23
- package/elements/{dialog-base.d.ts → base/dialog.d.ts} +3 -3
- package/elements/base/dialog.d.ts.map +1 -0
- package/elements/{dialog-base.js → base/dialog.js} +24 -24
- package/elements/base/dialog.js.map +1 -0
- package/elements/base/gesture.d.ts +66 -0
- package/elements/base/gesture.d.ts.map +1 -0
- package/elements/base/gesture.js +214 -0
- package/elements/base/gesture.js.map +1 -0
- package/elements/base/link.d.ts +44 -0
- package/elements/base/link.d.ts.map +1 -0
- package/elements/base/link.js +206 -0
- package/elements/base/link.js.map +1 -0
- package/elements/{modal-base.d.ts → base/modal-factory.d.ts} +17 -8
- package/elements/base/modal-factory.d.ts.map +1 -0
- package/elements/{modal-base.js → base/modal-factory.js} +4 -4
- package/elements/base/modal-factory.js.map +1 -0
- package/elements/base/reflect.d.ts +6 -0
- package/elements/base/reflect.d.ts.map +1 -0
- package/elements/base/reflect.js +33 -0
- package/elements/base/reflect.js.map +1 -0
- package/elements/base/route.d.ts +78 -0
- package/elements/base/route.d.ts.map +1 -0
- package/elements/base/route.js +220 -0
- package/elements/base/route.js.map +1 -0
- package/elements/base/title.d.ts +30 -0
- package/elements/base/title.d.ts.map +1 -0
- package/elements/base/title.js +74 -0
- package/elements/base/title.js.map +1 -0
- package/elements/base/unsafe.d.ts +14 -0
- package/elements/base/unsafe.d.ts.map +1 -0
- package/elements/base/unsafe.js +42 -0
- package/elements/base/unsafe.js.map +1 -0
- package/elements/base/use.d.ts +19 -0
- package/elements/base/use.d.ts.map +1 -0
- package/elements/base/use.js +70 -0
- package/elements/base/use.js.map +1 -0
- package/elements/gesture.d.ts +1 -67
- package/elements/gesture.d.ts.map +1 -1
- package/elements/gesture.js +3 -219
- package/elements/gesture.js.map +1 -1
- package/elements/link.d.ts +1 -45
- package/elements/link.d.ts.map +1 -1
- package/elements/link.js +4 -208
- package/elements/link.js.map +1 -1
- package/elements/reflect.d.ts +1 -8
- package/elements/reflect.d.ts.map +1 -1
- package/elements/reflect.js +3 -39
- package/elements/reflect.js.map +1 -1
- package/elements/route.d.ts +1 -81
- package/elements/route.d.ts.map +1 -1
- package/elements/route.js +4 -228
- package/elements/route.js.map +1 -1
- package/elements/title.d.ts +1 -30
- package/elements/title.d.ts.map +1 -1
- package/elements/title.js +3 -75
- package/elements/title.js.map +1 -1
- package/elements/unsafe.d.ts +1 -14
- package/elements/unsafe.d.ts.map +1 -1
- package/elements/unsafe.js +3 -46
- package/elements/unsafe.js.map +1 -1
- package/elements/use.d.ts +1 -19
- package/elements/use.d.ts.map +1 -1
- package/elements/use.js +3 -74
- package/elements/use.js.map +1 -1
- package/lib/history.d.ts +28 -16
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +166 -168
- package/lib/history.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +2 -1
- package/lib/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/dist.ts +5 -2
- package/src/elements/{dialog-base.ts → base/dialog.ts} +4 -4
- package/src/elements/base/gesture.ts +256 -0
- package/src/elements/base/link.ts +178 -0
- package/src/elements/{modal-base.ts → base/modal-factory.ts} +3 -3
- package/src/elements/base/reflect.ts +29 -0
- package/src/elements/base/route.ts +244 -0
- package/src/elements/base/title.ts +68 -0
- package/src/elements/base/unsafe.ts +37 -0
- package/src/elements/base/use.ts +57 -0
- package/src/elements/gesture.ts +3 -257
- package/src/elements/link.ts +4 -179
- package/src/elements/reflect.ts +3 -31
- package/src/elements/route.ts +4 -248
- package/src/elements/title.ts +3 -68
- package/src/elements/unsafe.ts +3 -37
- package/src/elements/use.ts +3 -57
- package/src/lib/history.ts +182 -194
- package/src/lib/utils.ts +2 -1
- package/src/test/history.test.ts +15 -10
- package/elements/dialog-base.d.ts.map +0 -1
- package/elements/dialog-base.js.map +0 -1
- package/elements/modal-base.d.ts.map +0 -1
- package/elements/modal-base.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { GemElement } from '
|
|
2
|
-
import { attribute, state, connectStore } from '
|
|
3
|
-
import { history } from '
|
|
1
|
+
import { GemElement } from '../../lib/element';
|
|
2
|
+
import { attribute, state, connectStore } from '../../lib/decorators';
|
|
3
|
+
import { history } from '../../lib/history';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 在模版中声明的 dialog,使用 `open` 方法 打开;
|
|
@@ -10,7 +10,7 @@ import { history } from '../lib/history';
|
|
|
10
10
|
* @attr label
|
|
11
11
|
*/
|
|
12
12
|
@connectStore(history.store)
|
|
13
|
-
export abstract class
|
|
13
|
+
export abstract class GemDialogBaseElement extends GemElement {
|
|
14
14
|
@attribute label: string;
|
|
15
15
|
@state opened: boolean;
|
|
16
16
|
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { GemElement, html } from '../../lib/element';
|
|
2
|
+
import { attribute, emitter, Emitter } from '../../lib/decorators';
|
|
3
|
+
|
|
4
|
+
export type PanEventDetail = {
|
|
5
|
+
// movement
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
clientX: number;
|
|
9
|
+
clientY: number;
|
|
10
|
+
timeStamp: number;
|
|
11
|
+
isPrimary: boolean;
|
|
12
|
+
pointerId: number;
|
|
13
|
+
};
|
|
14
|
+
export interface SwipeEventDetail {
|
|
15
|
+
direction: 'top' | 'right' | 'bottom' | 'left';
|
|
16
|
+
speed: number; // px/ms
|
|
17
|
+
}
|
|
18
|
+
export interface PinchEventDetail {
|
|
19
|
+
// center base viewport
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
scale: number;
|
|
23
|
+
}
|
|
24
|
+
export interface RotateEventDetail {
|
|
25
|
+
// center base viewport
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
rotate: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function angleAB(
|
|
32
|
+
a: number,
|
|
33
|
+
b: number,
|
|
34
|
+
c: number,
|
|
35
|
+
{ clientX: x1, clientY: y1 }: PanEventDetail,
|
|
36
|
+
{ clientX: x2, clientY: y2 }: PanEventDetail,
|
|
37
|
+
{ clientX: x3, clientY: y3 }: PanEventDetail,
|
|
38
|
+
) {
|
|
39
|
+
// https://en.wikipedia.org/wiki/Law_of_cosines
|
|
40
|
+
// https://blog.csdn.net/z278930050/article/details/53319091
|
|
41
|
+
return (
|
|
42
|
+
Math.sign((x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2)) * Math.acos((a ** 2 + b ** 2 - c ** 2) / (2 * a * b)) * 180
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 块级元素,如果要设置成 `contents`,则内容块要设置 `touch-action: none`
|
|
48
|
+
* https://javascript.info/pointer-events#event-pointercancel
|
|
49
|
+
*
|
|
50
|
+
* 在移动端上,必须设置 `touch-action` 以允许滚动等原生动作
|
|
51
|
+
*
|
|
52
|
+
* 为什么空白区域会自动触发 `pointercancel`?
|
|
53
|
+
*
|
|
54
|
+
* @event pan
|
|
55
|
+
* @event pinch
|
|
56
|
+
* @event rotate
|
|
57
|
+
* @event swipe
|
|
58
|
+
* @event press
|
|
59
|
+
* @event end
|
|
60
|
+
*
|
|
61
|
+
* @attr touch-action
|
|
62
|
+
*/
|
|
63
|
+
export class GemGestureElement extends GemElement {
|
|
64
|
+
@emitter pan: Emitter<PanEventDetail>;
|
|
65
|
+
@emitter pinch: Emitter<PinchEventDetail>;
|
|
66
|
+
@emitter rotate: Emitter<RotateEventDetail>;
|
|
67
|
+
@emitter swipe: Emitter<SwipeEventDetail>;
|
|
68
|
+
@emitter press: Emitter<null>;
|
|
69
|
+
@emitter end: Emitter<null>;
|
|
70
|
+
|
|
71
|
+
@attribute touchAction: string;
|
|
72
|
+
|
|
73
|
+
pressed = false; // 触发 press 之后不触发其他事件
|
|
74
|
+
pressTimer = 0;
|
|
75
|
+
|
|
76
|
+
startEventMap: Map<number, PointerEvent> = new Map();
|
|
77
|
+
movesMap: Map<number, PanEventDetail[]> = new Map();
|
|
78
|
+
|
|
79
|
+
constructor() {
|
|
80
|
+
super();
|
|
81
|
+
this.addEventListener('pointerdown', this.onStart);
|
|
82
|
+
this.addEventListener('pointermove', this.onMove);
|
|
83
|
+
this.addEventListener('pointerup', this.onEnd);
|
|
84
|
+
this.addEventListener('pointercancel', this.onEnd);
|
|
85
|
+
this.addEventListener('dragstart', (evt) => evt.preventDefault());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getMoves(pointerId: number) {
|
|
89
|
+
return this.movesMap.get(pointerId) || [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getStartEvent(pointerId: number) {
|
|
93
|
+
return this.startEventMap.get(pointerId) as PointerEvent;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getOtherLastmove(pointerId: number) {
|
|
97
|
+
for (const id of this.movesMap.keys()) {
|
|
98
|
+
if (id !== pointerId) {
|
|
99
|
+
const moves = this.getMoves(id);
|
|
100
|
+
return moves[moves.length - 1] || this.getStartEvent(id);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getMovementX(x: number, y: number) {
|
|
106
|
+
const touchAction = this.touchAction;
|
|
107
|
+
if (
|
|
108
|
+
(touchAction.includes('pan-right') && x > 0) ||
|
|
109
|
+
(touchAction.includes('pan-left') && x < 0) ||
|
|
110
|
+
touchAction.includes('pan-x') ||
|
|
111
|
+
(((touchAction.includes('pan-down') && y > 0) ||
|
|
112
|
+
(touchAction.includes('pan-up') && y < 0) ||
|
|
113
|
+
touchAction.includes('pan-y')) &&
|
|
114
|
+
Math.abs(y) > Math.abs(x)) // horizontally scrolling
|
|
115
|
+
) {
|
|
116
|
+
return 0;
|
|
117
|
+
}
|
|
118
|
+
return x;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getMovementY(x: number, y: number) {
|
|
122
|
+
const touchAction = this.touchAction;
|
|
123
|
+
if (
|
|
124
|
+
(touchAction.includes('pan-down') && y > 0) ||
|
|
125
|
+
(touchAction.includes('pan-up') && y < 0) ||
|
|
126
|
+
touchAction.includes('pan-y') ||
|
|
127
|
+
(((touchAction.includes('pan-right') && x > 0) ||
|
|
128
|
+
(touchAction.includes('pan-left') && x < 0) ||
|
|
129
|
+
touchAction.includes('pan-x')) &&
|
|
130
|
+
Math.abs(x) > Math.abs(y)) // vertical scrolling
|
|
131
|
+
) {
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
return y;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
onStart(evt: PointerEvent) {
|
|
138
|
+
evt.stopPropagation();
|
|
139
|
+
this.setPointerCapture(evt.pointerId);
|
|
140
|
+
this.movesMap.set(evt.pointerId, []);
|
|
141
|
+
this.startEventMap.set(evt.pointerId, evt);
|
|
142
|
+
if (evt.isPrimary) {
|
|
143
|
+
this.pressed = false;
|
|
144
|
+
this.pressTimer = window.setTimeout(() => {
|
|
145
|
+
this.press(null);
|
|
146
|
+
this.pressed = true;
|
|
147
|
+
}, 251);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
onMove(evt: PointerEvent) {
|
|
152
|
+
evt.stopPropagation();
|
|
153
|
+
const { pointerId, clientX, clientY, isPrimary, pointerType, timeStamp } = evt;
|
|
154
|
+
if (!this.pressed && this.hasPointerCapture(pointerId)) {
|
|
155
|
+
const moves = this.getMoves(pointerId);
|
|
156
|
+
const startEvent = this.getStartEvent(pointerId);
|
|
157
|
+
const lastMove = moves[moves.length - 1] || startEvent;
|
|
158
|
+
// https://bugs.webkit.org/show_bug.cgi?id=220194
|
|
159
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=1092358
|
|
160
|
+
const movementX = clientX - lastMove.clientX;
|
|
161
|
+
const movementY = clientY - lastMove.clientY;
|
|
162
|
+
const move = {
|
|
163
|
+
x: this.getMovementX(movementX, movementY),
|
|
164
|
+
y: this.getMovementY(movementX, movementY),
|
|
165
|
+
clientX,
|
|
166
|
+
clientY,
|
|
167
|
+
timeStamp,
|
|
168
|
+
isPrimary,
|
|
169
|
+
pointerId,
|
|
170
|
+
};
|
|
171
|
+
moves.push(move);
|
|
172
|
+
this.pan(move);
|
|
173
|
+
|
|
174
|
+
if (this.movesMap.size !== 1) {
|
|
175
|
+
const secondaryPoint = this.getOtherLastmove(pointerId) as PanEventDetail;
|
|
176
|
+
const moveLen = Math.sqrt(movementX ** 2 + movementY ** 2);
|
|
177
|
+
const distanceLen = Math.sqrt(
|
|
178
|
+
(lastMove.clientX - secondaryPoint.clientX) ** 2 + (lastMove.clientY - secondaryPoint.clientY) ** 2,
|
|
179
|
+
);
|
|
180
|
+
const newDistanceLen = Math.sqrt(
|
|
181
|
+
(clientX - secondaryPoint.clientX) ** 2 + (clientY - secondaryPoint.clientY) ** 2,
|
|
182
|
+
);
|
|
183
|
+
const x = (lastMove.clientX + secondaryPoint.clientX) / 2;
|
|
184
|
+
const y = (lastMove.clientY + secondaryPoint.clientY) / 2;
|
|
185
|
+
this.pinch({ x, y, scale: newDistanceLen / distanceLen });
|
|
186
|
+
this.rotate({ x, y, rotate: angleAB(newDistanceLen, distanceLen, moveLen, secondaryPoint, lastMove, move) });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const accuracy = pointerType === 'touch' ? 5 : 0;
|
|
190
|
+
if (
|
|
191
|
+
Math.abs(movementX) > accuracy ||
|
|
192
|
+
Math.abs(movementY) > accuracy ||
|
|
193
|
+
Math.abs(move.clientX - startEvent.clientX) > accuracy ||
|
|
194
|
+
Math.abs(move.clientY - startEvent.clientY) > accuracy
|
|
195
|
+
) {
|
|
196
|
+
window.clearTimeout(this.pressTimer);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
onEnd(evt: PointerEvent) {
|
|
202
|
+
evt.stopPropagation();
|
|
203
|
+
const { pointerId } = evt;
|
|
204
|
+
window.clearTimeout(this.pressTimer);
|
|
205
|
+
|
|
206
|
+
if (this.movesMap.size === 1) {
|
|
207
|
+
this.end(null);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// auto release: https://javascript.info/pointer-events#pointer-capturing
|
|
211
|
+
if (!this.pressed && this.hasPointerCapture(pointerId)) {
|
|
212
|
+
const moves = this.getMoves(pointerId);
|
|
213
|
+
|
|
214
|
+
if (moves.length > 2) {
|
|
215
|
+
const { x, y, timeStamp, clientX, clientY } = moves[moves.length - 1];
|
|
216
|
+
const move2 = moves[moves.length - 3];
|
|
217
|
+
if (Math.abs(x) > 2) {
|
|
218
|
+
if (Math.abs(x) > Math.abs(y)) {
|
|
219
|
+
const speed = Math.abs(move2.clientX - clientX) / (timeStamp - move2.timeStamp);
|
|
220
|
+
if (x > 0) {
|
|
221
|
+
this.swipe({ direction: 'right', speed });
|
|
222
|
+
} else {
|
|
223
|
+
this.swipe({ direction: 'left', speed });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (Math.abs(y) > 2) {
|
|
228
|
+
const speed = Math.abs(move2.clientY - clientY) / (timeStamp - move2.timeStamp);
|
|
229
|
+
if (Math.abs(y) > Math.abs(x)) {
|
|
230
|
+
if (y > 0) {
|
|
231
|
+
this.swipe({ direction: 'bottom', speed });
|
|
232
|
+
} else {
|
|
233
|
+
this.swipe({ direction: 'top', speed });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.movesMap.delete(pointerId);
|
|
241
|
+
this.startEventMap.delete(pointerId);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
render() {
|
|
245
|
+
return html`
|
|
246
|
+
<style>
|
|
247
|
+
:host {
|
|
248
|
+
display: block;
|
|
249
|
+
user-select: none;
|
|
250
|
+
touch-action: ${this.touchAction || 'none'};
|
|
251
|
+
}
|
|
252
|
+
</style>
|
|
253
|
+
<slot></slot>
|
|
254
|
+
`;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { GemElement, html, ifDefined } from '../../lib/element';
|
|
2
|
+
import { attribute, property, state, part, connectStore } from '../../lib/decorators';
|
|
3
|
+
import { history, basePathStore } from '../../lib/history';
|
|
4
|
+
import { absoluteLocation } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
import { matchPath, RouteItem, RouteOptions, createHistoryParams, createPath } from './route';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @attr href
|
|
10
|
+
* @attr target
|
|
11
|
+
* @attr doc-title
|
|
12
|
+
* @attr path
|
|
13
|
+
* @attr query
|
|
14
|
+
* @attr hash
|
|
15
|
+
* @attr pattern
|
|
16
|
+
* @attr hint
|
|
17
|
+
* @part link
|
|
18
|
+
*
|
|
19
|
+
* print bug: https://github.com/mantou132/gem/issues/36
|
|
20
|
+
*/
|
|
21
|
+
@connectStore(basePathStore)
|
|
22
|
+
export class GemLinkElement extends GemElement {
|
|
23
|
+
@attribute href: string;
|
|
24
|
+
@attribute target: string;
|
|
25
|
+
@attribute path: string;
|
|
26
|
+
@attribute query: string;
|
|
27
|
+
@attribute hash: string;
|
|
28
|
+
@attribute docTitle: string;
|
|
29
|
+
@attribute hint: 'on' | 'off';
|
|
30
|
+
|
|
31
|
+
// 动态路由,根据 route.pattern 和 options.params 计算出 path
|
|
32
|
+
@property route: RouteItem | undefined;
|
|
33
|
+
@property options: RouteOptions | undefined;
|
|
34
|
+
@property prepare: (() => void | Promise<void>) | undefined;
|
|
35
|
+
|
|
36
|
+
@part link: string;
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
this.tabIndex = 0;
|
|
41
|
+
this.addEventListener('click', this.clickHandle);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 不包含 basePath
|
|
45
|
+
getPathInfo() {
|
|
46
|
+
if (this.route) {
|
|
47
|
+
const queryProp = this.options?.query || '';
|
|
48
|
+
const hashProp = this.options?.hash || '';
|
|
49
|
+
return createPath(this.route, this.options) + queryProp + hashProp;
|
|
50
|
+
} else {
|
|
51
|
+
const url = this.href || this.path + this.query + this.hash;
|
|
52
|
+
const { path, query } = history.getParams();
|
|
53
|
+
if (url.startsWith('#')) {
|
|
54
|
+
return `${path}${query}${url}`;
|
|
55
|
+
} else if (url.startsWith('?')) {
|
|
56
|
+
return `${path}${url}`;
|
|
57
|
+
} else if (url.startsWith('.')) {
|
|
58
|
+
return absoluteLocation(path, url);
|
|
59
|
+
} else {
|
|
60
|
+
return url;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
isExternal(pathInfo: string) {
|
|
66
|
+
return !pathInfo.startsWith('/');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
clickHandle = async (e: MouseEvent) => {
|
|
70
|
+
const pathInfo = this.getPathInfo();
|
|
71
|
+
|
|
72
|
+
if (!pathInfo) return;
|
|
73
|
+
|
|
74
|
+
// 外部链接使用 `window.open`
|
|
75
|
+
if (this.isExternal(pathInfo)) {
|
|
76
|
+
switch (this.target) {
|
|
77
|
+
case '_self':
|
|
78
|
+
window.location.href = pathInfo;
|
|
79
|
+
return;
|
|
80
|
+
case '_parent':
|
|
81
|
+
window.parent.location.href = pathInfo;
|
|
82
|
+
return;
|
|
83
|
+
case '_top':
|
|
84
|
+
window.top!.location.href = pathInfo;
|
|
85
|
+
return;
|
|
86
|
+
default:
|
|
87
|
+
window.open(pathInfo);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const { path, query, hash } = history.getParams();
|
|
93
|
+
if (path + query + hash === pathInfo) {
|
|
94
|
+
// 点击当前路由链接时,什么也没做
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
|
|
100
|
+
await this.prepare?.();
|
|
101
|
+
|
|
102
|
+
if (this.route) {
|
|
103
|
+
history.pushIgnoreCloseHandle({
|
|
104
|
+
...createHistoryParams(this.route, this.options),
|
|
105
|
+
title: this.route.title || this.docTitle,
|
|
106
|
+
});
|
|
107
|
+
} else if (this.href) {
|
|
108
|
+
const { pathname, search, hash } = new URL(pathInfo, location.origin);
|
|
109
|
+
history.pushIgnoreCloseHandle({
|
|
110
|
+
path: pathname,
|
|
111
|
+
query: search,
|
|
112
|
+
hash: hash,
|
|
113
|
+
title: this.docTitle,
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
history.pushIgnoreCloseHandle({ path: this.path, query: this.query, hash: this.hash, title: this.docTitle });
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
preventDefault = (e: MouseEvent) => {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
render(pathInfo = this.getPathInfo()) {
|
|
125
|
+
return html`
|
|
126
|
+
<style>
|
|
127
|
+
:host {
|
|
128
|
+
/* link default style */
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
color: blue;
|
|
131
|
+
text-decoration: underline;
|
|
132
|
+
}
|
|
133
|
+
a {
|
|
134
|
+
all: unset;
|
|
135
|
+
display: contents;
|
|
136
|
+
}
|
|
137
|
+
a:visited {
|
|
138
|
+
color: unset;
|
|
139
|
+
}
|
|
140
|
+
</style>
|
|
141
|
+
<a
|
|
142
|
+
part=${this.link}
|
|
143
|
+
@click=${this.preventDefault}
|
|
144
|
+
href=${ifDefined(
|
|
145
|
+
this.hint === 'off'
|
|
146
|
+
? undefined
|
|
147
|
+
: this.isExternal(pathInfo)
|
|
148
|
+
? pathInfo
|
|
149
|
+
: new URL(history.basePath + pathInfo, location.origin).toString(),
|
|
150
|
+
)}
|
|
151
|
+
>
|
|
152
|
+
<slot></slot>
|
|
153
|
+
</a>
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @attr pattern
|
|
160
|
+
* @state active
|
|
161
|
+
*/
|
|
162
|
+
@connectStore(history.store)
|
|
163
|
+
export class GemActiveLinkElement extends GemLinkElement {
|
|
164
|
+
@attribute pattern: string; // 使用匹配模式设定 active
|
|
165
|
+
@state active: boolean;
|
|
166
|
+
|
|
167
|
+
render() {
|
|
168
|
+
const { path, query, hash } = history.getParams();
|
|
169
|
+
const isMatchPattern = this.pattern && matchPath(this.pattern, path);
|
|
170
|
+
const pathInfo = this.getPathInfo();
|
|
171
|
+
if (isMatchPattern || path + query + hash === pathInfo) {
|
|
172
|
+
this.active = true;
|
|
173
|
+
} else {
|
|
174
|
+
this.active = false;
|
|
175
|
+
}
|
|
176
|
+
return super.render(pathInfo);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { GemElement } from '
|
|
2
|
-
import { createStore, updateStore } from '
|
|
3
|
-
import { history } from '
|
|
1
|
+
import { GemElement } from '../../lib/element';
|
|
2
|
+
import { createStore, updateStore } from '../../lib/store';
|
|
3
|
+
import { history } from '../../lib/history';
|
|
4
4
|
|
|
5
5
|
const open = Symbol('open mark');
|
|
6
6
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { GemElement } from '../../lib/element';
|
|
2
|
+
import { property } from '../../lib/decorators';
|
|
3
|
+
|
|
4
|
+
// support prerender
|
|
5
|
+
document.querySelectorAll('[data-reflect]').forEach((e) => e.remove());
|
|
6
|
+
|
|
7
|
+
export class GemReflectElement extends GemElement {
|
|
8
|
+
@property target: HTMLElement = document.head;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
super({ isLight: true });
|
|
12
|
+
this.hidden = true;
|
|
13
|
+
this.effect(
|
|
14
|
+
() => {
|
|
15
|
+
const childNodes = [...this.childNodes];
|
|
16
|
+
childNodes.forEach((node) => {
|
|
17
|
+
if (node instanceof HTMLElement) {
|
|
18
|
+
node.dataset.reflect = '';
|
|
19
|
+
}
|
|
20
|
+
this.target.append(node);
|
|
21
|
+
});
|
|
22
|
+
return () => {
|
|
23
|
+
childNodes.forEach((node) => node.remove());
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
() => [this.target],
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|