@mantou/gem 1.6.8 → 1.6.12
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 +3266 -0
- package/dist/gem.umd.js +229 -0
- 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 +34 -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/element.d.ts.map +1 -1
- package/lib/element.js +1 -1
- package/lib/element.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 +3 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +16 -16
- package/lib/utils.js.map +1 -1
- package/package.json +9 -6
- package/src/{all.ts → dist.ts} +6 -3
- 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 +30 -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/element.ts +3 -1
- package/src/lib/history.ts +182 -194
- package/src/lib/utils.ts +24 -16
- package/src/test/history.test.ts +15 -10
- package/src/test/utils.test.ts +6 -2
- package/all.d.ts +0 -14
- package/all.d.ts.map +0 -1
- package/all.js +0 -14
- package/all.js.map +0 -1
- 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
package/src/elements/link.ts
CHANGED
|
@@ -1,181 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { attribute, property, customElement, state, part, connectStore } from '../lib/decorators';
|
|
3
|
-
import { history, basePathStore } from '../lib/history';
|
|
4
|
-
import { absoluteLocation } from '../lib/utils';
|
|
1
|
+
import { GemLinkElement, GemActiveLinkElement } from './base/link';
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
export * from './base/link';
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* @attr href
|
|
11
|
-
* @attr target
|
|
12
|
-
* @attr doc-title
|
|
13
|
-
* @attr path
|
|
14
|
-
* @attr query
|
|
15
|
-
* @attr hash
|
|
16
|
-
* @attr pattern
|
|
17
|
-
* @attr hint
|
|
18
|
-
* @part link
|
|
19
|
-
*
|
|
20
|
-
* print bug: https://github.com/mantou132/gem/issues/36
|
|
21
|
-
*/
|
|
22
|
-
@customElement('gem-link')
|
|
23
|
-
@connectStore(basePathStore)
|
|
24
|
-
export class GemLinkElement extends GemElement {
|
|
25
|
-
@attribute href: string;
|
|
26
|
-
@attribute target: string;
|
|
27
|
-
@attribute path: string;
|
|
28
|
-
@attribute query: string;
|
|
29
|
-
@attribute hash: string;
|
|
30
|
-
@attribute docTitle: string;
|
|
31
|
-
@attribute hint: 'on' | 'off';
|
|
32
|
-
|
|
33
|
-
// 动态路由,根据 route.pattern 和 options.params 计算出 path
|
|
34
|
-
@property route: RouteItem | undefined;
|
|
35
|
-
@property options: RouteOptions | undefined;
|
|
36
|
-
@property prepare: (() => void | Promise<void>) | undefined;
|
|
37
|
-
|
|
38
|
-
@part link: string;
|
|
39
|
-
|
|
40
|
-
constructor() {
|
|
41
|
-
super();
|
|
42
|
-
this.addEventListener('click', this.clickHandle);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 不包含 basePath
|
|
46
|
-
getPathInfo() {
|
|
47
|
-
if (this.route) {
|
|
48
|
-
const queryProp = this.options?.query || '';
|
|
49
|
-
const hashProp = this.options?.hash || '';
|
|
50
|
-
return createPath(this.route, this.options) + queryProp + hashProp;
|
|
51
|
-
} else {
|
|
52
|
-
const url = this.href || this.path + this.query + this.hash;
|
|
53
|
-
const { path, query } = history.getParams();
|
|
54
|
-
if (url.startsWith('#')) {
|
|
55
|
-
return `${path}${query}${url}`;
|
|
56
|
-
} else if (url.startsWith('?')) {
|
|
57
|
-
return `${path}${url}`;
|
|
58
|
-
} else if (url.startsWith('.')) {
|
|
59
|
-
return absoluteLocation(path, url);
|
|
60
|
-
} else {
|
|
61
|
-
return url;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
isExternal(pathInfo: string) {
|
|
67
|
-
return !pathInfo.startsWith('/');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
clickHandle = async (e: MouseEvent) => {
|
|
71
|
-
const pathInfo = this.getPathInfo();
|
|
72
|
-
|
|
73
|
-
if (!pathInfo) return;
|
|
74
|
-
|
|
75
|
-
// 外部链接使用 `window.open`
|
|
76
|
-
if (this.isExternal(pathInfo)) {
|
|
77
|
-
switch (this.target) {
|
|
78
|
-
case '_self':
|
|
79
|
-
window.location.href = pathInfo;
|
|
80
|
-
return;
|
|
81
|
-
case '_parent':
|
|
82
|
-
window.parent.location.href = pathInfo;
|
|
83
|
-
return;
|
|
84
|
-
case '_top':
|
|
85
|
-
window.top!.location.href = pathInfo;
|
|
86
|
-
return;
|
|
87
|
-
default:
|
|
88
|
-
window.open(pathInfo);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const { path, query, hash } = history.getParams();
|
|
94
|
-
if (path + query + hash === pathInfo) {
|
|
95
|
-
// 点击当前路由链接时,什么也没做
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
e.stopPropagation();
|
|
100
|
-
|
|
101
|
-
await this.prepare?.();
|
|
102
|
-
|
|
103
|
-
if (this.route) {
|
|
104
|
-
history.pushIgnoreCloseHandle({
|
|
105
|
-
...createHistoryParams(this.route, this.options),
|
|
106
|
-
title: this.route.title || this.docTitle,
|
|
107
|
-
});
|
|
108
|
-
} else if (this.href) {
|
|
109
|
-
const { pathname, search, hash } = new URL(pathInfo, location.origin);
|
|
110
|
-
history.pushIgnoreCloseHandle({
|
|
111
|
-
path: pathname,
|
|
112
|
-
query: search,
|
|
113
|
-
hash: hash,
|
|
114
|
-
title: this.docTitle,
|
|
115
|
-
});
|
|
116
|
-
} else {
|
|
117
|
-
history.pushIgnoreCloseHandle({ path: this.path, query: this.query, hash: this.hash, title: this.docTitle });
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
preventDefault = (e: MouseEvent) => {
|
|
122
|
-
e.preventDefault();
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
render(pathInfo = this.getPathInfo()) {
|
|
126
|
-
return html`
|
|
127
|
-
<style>
|
|
128
|
-
:host {
|
|
129
|
-
/* link default style */
|
|
130
|
-
cursor: pointer;
|
|
131
|
-
color: blue;
|
|
132
|
-
text-decoration: underline;
|
|
133
|
-
}
|
|
134
|
-
a {
|
|
135
|
-
all: unset;
|
|
136
|
-
display: contents;
|
|
137
|
-
}
|
|
138
|
-
a:visited {
|
|
139
|
-
color: unset;
|
|
140
|
-
}
|
|
141
|
-
</style>
|
|
142
|
-
<a
|
|
143
|
-
part=${this.link}
|
|
144
|
-
@click=${this.preventDefault}
|
|
145
|
-
href=${ifDefined(
|
|
146
|
-
this.hint === 'off'
|
|
147
|
-
? undefined
|
|
148
|
-
: this.isExternal(pathInfo)
|
|
149
|
-
? pathInfo
|
|
150
|
-
: new URL(history.basePath + pathInfo, location.origin).toString(),
|
|
151
|
-
)}
|
|
152
|
-
>
|
|
153
|
-
<slot></slot>
|
|
154
|
-
</a>
|
|
155
|
-
`;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* @customElement gem-active-link
|
|
161
|
-
* @attr pattern
|
|
162
|
-
* @state active
|
|
163
|
-
*/
|
|
164
|
-
@customElement('gem-active-link')
|
|
165
|
-
@connectStore(history.store)
|
|
166
|
-
export class GemActiveLinkElement extends GemLinkElement {
|
|
167
|
-
@attribute pattern: string; // 使用匹配模式设定 active
|
|
168
|
-
@state active: boolean;
|
|
169
|
-
|
|
170
|
-
render() {
|
|
171
|
-
const { path, query, hash } = history.getParams();
|
|
172
|
-
const isMatchPattern = this.pattern && matchPath(this.pattern, path);
|
|
173
|
-
const pathInfo = this.getPathInfo();
|
|
174
|
-
if (isMatchPattern || path + query + hash === pathInfo) {
|
|
175
|
-
this.active = true;
|
|
176
|
-
} else {
|
|
177
|
-
this.active = false;
|
|
178
|
-
}
|
|
179
|
-
return super.render(pathInfo);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
5
|
+
customElements.define('gem-link', GemLinkElement);
|
|
6
|
+
customElements.define('gem-active-link', GemActiveLinkElement);
|
package/src/elements/reflect.ts
CHANGED
|
@@ -1,33 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { property, customElement } from '../lib/decorators';
|
|
1
|
+
import { GemReflectElement } from './base/reflect';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
document.querySelectorAll('[data-reflect]').forEach((e) => e.remove());
|
|
3
|
+
export * from './base/reflect';
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
* @customElement gem-reflect
|
|
9
|
-
*/
|
|
10
|
-
@customElement('gem-reflect')
|
|
11
|
-
export class GemReflectElement extends GemElement {
|
|
12
|
-
@property target: HTMLElement = document.head;
|
|
13
|
-
|
|
14
|
-
constructor() {
|
|
15
|
-
super({ isLight: true });
|
|
16
|
-
this.hidden = true;
|
|
17
|
-
this.effect(
|
|
18
|
-
() => {
|
|
19
|
-
const childNodes = [...this.childNodes];
|
|
20
|
-
childNodes.forEach((node) => {
|
|
21
|
-
if (node instanceof HTMLElement) {
|
|
22
|
-
node.dataset.reflect = '';
|
|
23
|
-
}
|
|
24
|
-
this.target.append(node);
|
|
25
|
-
});
|
|
26
|
-
return () => {
|
|
27
|
-
childNodes.forEach((node) => node.remove());
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
|
-
() => [this.target],
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
5
|
+
customElements.define('gem-reflect', GemReflectElement);
|
package/src/elements/route.ts
CHANGED
|
@@ -1,250 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { property, customElement, connectStore, emitter, Emitter } from '../lib/decorators';
|
|
3
|
-
import { createStore, updateStore, Store } from '../lib/store';
|
|
4
|
-
import { titleStore, history, UpdateHistoryParams } from '../lib/history';
|
|
5
|
-
import { QueryString } from '../lib/utils';
|
|
1
|
+
import { GemRouteElement, GemLightRouteElement } from './base/route';
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
[index: string]: number;
|
|
9
|
-
}
|
|
3
|
+
export * from './base/route';
|
|
10
4
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
namePosition: NamePostition;
|
|
14
|
-
constructor(pattern: string) {
|
|
15
|
-
const namePosition: NamePostition = {};
|
|
16
|
-
let i = 0;
|
|
17
|
-
super(
|
|
18
|
-
`^${pattern
|
|
19
|
-
.replace(/:([^/$]+)/g, (_m, name: string) => {
|
|
20
|
-
namePosition[name] = i++;
|
|
21
|
-
return `([^/]+)`;
|
|
22
|
-
})
|
|
23
|
-
.replace('*', '.*')}$`,
|
|
24
|
-
'i',
|
|
25
|
-
);
|
|
26
|
-
this.namePosition = namePosition;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
type Params = Record<string, string>;
|
|
31
|
-
|
|
32
|
-
// `/a/b/:c/:d` `/a/b/1/2`
|
|
33
|
-
// 匹配成功时返回 params
|
|
34
|
-
export function matchPath(pattern: string, path: string) {
|
|
35
|
-
const reg = new ParamsRegExp(pattern);
|
|
36
|
-
const matchResult = path.match(reg) || `${path}/`.match(reg);
|
|
37
|
-
if (!matchResult) return null;
|
|
38
|
-
const params: Params = {};
|
|
39
|
-
if (matchResult) {
|
|
40
|
-
Object.keys(reg.namePosition).forEach((name) => {
|
|
41
|
-
params[name] = matchResult[reg.namePosition[name] + 1];
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
return params;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface RouteItem<T = unknown> {
|
|
48
|
-
// 支持 *
|
|
49
|
-
// 支持 /a/*
|
|
50
|
-
// 不支持相对路径
|
|
51
|
-
// 不能匹配查询字符串
|
|
52
|
-
pattern: string;
|
|
53
|
-
redirect?: string;
|
|
54
|
-
content?: TemplateResult;
|
|
55
|
-
getContent?: (params: Params) => TemplateResult | Promise<TemplateResult>;
|
|
56
|
-
title?: string;
|
|
57
|
-
// 用来传递数据
|
|
58
|
-
data?: T;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
type RoutesObject = Record<string, RouteItem>;
|
|
62
|
-
|
|
63
|
-
// params 中的成员不会验证
|
|
64
|
-
export interface RouteOptions extends Omit<UpdateHistoryParams, 'path'> {
|
|
65
|
-
params?: Params;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// 从路由创建路径
|
|
69
|
-
// 不包含 basePath
|
|
70
|
-
export function createPath(route: RouteItem, options?: RouteOptions) {
|
|
71
|
-
let path = route.pattern;
|
|
72
|
-
const params = options?.params;
|
|
73
|
-
if (params) {
|
|
74
|
-
Object.keys(params).forEach((key) => {
|
|
75
|
-
path = path.replace(new RegExp(`:${key}`, 'g'), params[key]);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return path;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function createHistoryParams(route: RouteItem, options?: RouteOptions): UpdateHistoryParams {
|
|
82
|
-
const path = createPath(route, options);
|
|
83
|
-
return {
|
|
84
|
-
path,
|
|
85
|
-
...options,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
interface ConstructorOptions {
|
|
90
|
-
isLight?: boolean;
|
|
91
|
-
routes?: RouteItem[] | RoutesObject;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
type State = {
|
|
95
|
-
content?: TemplateResult;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* @customElement gem-route
|
|
100
|
-
* @attr inert 暂停路由更新
|
|
101
|
-
* @fires routechange
|
|
102
|
-
* @fires error
|
|
103
|
-
* @fires loading
|
|
104
|
-
*/
|
|
105
|
-
@connectStore(history.store)
|
|
106
|
-
@customElement('gem-route')
|
|
107
|
-
export class GemRouteElement extends GemElement<State> {
|
|
108
|
-
@property routes?: RouteItem[] | RoutesObject;
|
|
109
|
-
/**
|
|
110
|
-
* @example
|
|
111
|
-
* const locationStore = GemRouteElement.createLocationStore()
|
|
112
|
-
* html`<gem-route .locationStore=${locationStore}>`
|
|
113
|
-
*/
|
|
114
|
-
@property locationStore?: Store<{ path: string; params: Params; query: QueryString; data?: any }>;
|
|
115
|
-
@property key: any; // 除了 href 提供另外一种方式来更新,比如语言更新也需要刷新 <gem-route>
|
|
116
|
-
@emitter routechange: Emitter<RouteItem | null>; // path 改变或者 key 改变,包含初始渲染
|
|
117
|
-
@emitter loading: Emitter<RouteItem>;
|
|
118
|
-
@emitter error: Emitter<any>;
|
|
119
|
-
|
|
120
|
-
currentRoute: RouteItem | null;
|
|
121
|
-
// 当前匹配的路由的 params
|
|
122
|
-
currentParams: Params = {};
|
|
123
|
-
|
|
124
|
-
#lastLoader?: Promise<TemplateResult>;
|
|
125
|
-
|
|
126
|
-
static createLocationStore = () => {
|
|
127
|
-
const { path, query, data } = history.getParams();
|
|
128
|
-
return createStore({ path, query, data, params: {} as Record<string, string> });
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
static findRoute = (target: RouteItem[] | RoutesObject = [], path: string) => {
|
|
132
|
-
let defaultRoute: RouteItem | null = null;
|
|
133
|
-
let routes: RouteItem[];
|
|
134
|
-
if (target instanceof Array) {
|
|
135
|
-
routes = target;
|
|
136
|
-
} else {
|
|
137
|
-
routes = Object.values(target);
|
|
138
|
-
}
|
|
139
|
-
for (const route of routes) {
|
|
140
|
-
if ('*' === route.pattern) {
|
|
141
|
-
defaultRoute = route;
|
|
142
|
-
} else {
|
|
143
|
-
const params = matchPath(route.pattern, path);
|
|
144
|
-
if (params) {
|
|
145
|
-
return { route, params };
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return { route: defaultRoute };
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
constructor({ isLight, routes }: ConstructorOptions = {}) {
|
|
153
|
-
super({ isLight });
|
|
154
|
-
this.routes = routes;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
state: State = {
|
|
158
|
-
content: undefined,
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
#updateLocationStore = () => {
|
|
162
|
-
if (this.locationStore) {
|
|
163
|
-
const { path, query, data } = history.getParams();
|
|
164
|
-
updateStore(this.locationStore, {
|
|
165
|
-
path,
|
|
166
|
-
params: this.currentParams,
|
|
167
|
-
query,
|
|
168
|
-
data,
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
#setContent = (route: RouteItem | null, params: Params, content?: TemplateResult) => {
|
|
174
|
-
this.#lastLoader = undefined;
|
|
175
|
-
this.currentRoute = route;
|
|
176
|
-
this.currentParams = params;
|
|
177
|
-
this.setState({ content });
|
|
178
|
-
this.routechange(this.currentRoute);
|
|
179
|
-
const title = route?.title;
|
|
180
|
-
if (title) updateStore(titleStore, { title });
|
|
181
|
-
this.#updateLocationStore();
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
mounted() {
|
|
185
|
-
this.effect(
|
|
186
|
-
([key, path], old) => {
|
|
187
|
-
// 只有查询参数改变
|
|
188
|
-
if (old && key === old[0] && path === old[1]) {
|
|
189
|
-
this.#updateLocationStore();
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
const { route, params = {} } = GemRouteElement.findRoute(this.routes, path);
|
|
193
|
-
const { redirect, content, getContent } = route || {};
|
|
194
|
-
if (redirect) {
|
|
195
|
-
history.replace({ path: redirect });
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
const contentOrLoader = content || getContent?.(params);
|
|
199
|
-
if (contentOrLoader instanceof Promise) {
|
|
200
|
-
this.loading(route!);
|
|
201
|
-
this.#lastLoader = contentOrLoader;
|
|
202
|
-
const isSomeLoader = () => this.#lastLoader === contentOrLoader;
|
|
203
|
-
contentOrLoader
|
|
204
|
-
.then((content) => {
|
|
205
|
-
if (isSomeLoader()) this.#setContent(route, params, content);
|
|
206
|
-
})
|
|
207
|
-
.catch((err) => {
|
|
208
|
-
if (isSomeLoader()) this.error(err);
|
|
209
|
-
});
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
this.#setContent(route, params, contentOrLoader);
|
|
213
|
-
},
|
|
214
|
-
() => {
|
|
215
|
-
const { path } = history.getParams();
|
|
216
|
-
return [this.key, path, location.search];
|
|
217
|
-
},
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
shouldUpdate() {
|
|
222
|
-
if (this.inert) return false;
|
|
223
|
-
return true;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
render() {
|
|
227
|
-
const { content } = this.state;
|
|
228
|
-
if (!this.shadowRoot) return html`${content}`;
|
|
229
|
-
|
|
230
|
-
return html`
|
|
231
|
-
<style>
|
|
232
|
-
:host,
|
|
233
|
-
:not(:defined) {
|
|
234
|
-
display: contents;
|
|
235
|
-
}
|
|
236
|
-
</style>
|
|
237
|
-
${content ?? html`<slot></slot>`}
|
|
238
|
-
`;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* @customElement gem-light-route
|
|
244
|
-
*/
|
|
245
|
-
@customElement('gem-light-route')
|
|
246
|
-
export class GemLightRouteElement extends GemRouteElement {
|
|
247
|
-
constructor(options: ConstructorOptions = {}) {
|
|
248
|
-
super({ ...options, isLight: true });
|
|
249
|
-
}
|
|
250
|
-
}
|
|
5
|
+
customElements.define('gem-route', GemRouteElement);
|
|
6
|
+
customElements.define('gem-light-route', GemLightRouteElement);
|
package/src/elements/title.ts
CHANGED
|
@@ -1,70 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
* 标题显示在:
|
|
3
|
-
*
|
|
4
|
-
* - 桌面端 Tab 的 title
|
|
5
|
-
* - 移动端 Appbar 的 title
|
|
6
|
-
*
|
|
7
|
-
* 修改标题:
|
|
8
|
-
*
|
|
9
|
-
* - `<gem-route>` 匹配路由时自动设置 `route.title`
|
|
10
|
-
* - `<gem-link>` 的 `doc-title` 属性和 `route.title`
|
|
11
|
-
* - 修改路径时,`history` 默认设置 `title` 为空
|
|
12
|
-
* - 数据获取后,手动调用 `Title.setTitle`
|
|
13
|
-
* - `<gem-title>` 作为默认值设置
|
|
14
|
-
*/
|
|
1
|
+
import { GemTitleElement } from './base/title';
|
|
15
2
|
|
|
16
|
-
|
|
17
|
-
import { attribute, customElement, connectStore } from '../lib/decorators';
|
|
18
|
-
import { updateStore, connect } from '../lib/store';
|
|
19
|
-
import { titleStore } from '../lib/history';
|
|
3
|
+
export * from './base/title';
|
|
20
4
|
|
|
21
|
-
|
|
22
|
-
* 允许声明式设置 `document.title`
|
|
23
|
-
* @customElement gem-title
|
|
24
|
-
* @attr suffix
|
|
25
|
-
*/
|
|
26
|
-
@connectStore(titleStore)
|
|
27
|
-
@customElement('gem-title')
|
|
28
|
-
export class GemTitleElement extends GemElement {
|
|
29
|
-
// 没有后缀的标题
|
|
30
|
-
static title = document.title;
|
|
31
|
-
static defaultTitle = document.title;
|
|
32
|
-
static defaultSuffix = ` - ${document.title}`;
|
|
33
|
-
|
|
34
|
-
static setTitle(title: string) {
|
|
35
|
-
updateStore(titleStore, { title });
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static updateTitle(str = '', suffix = '') {
|
|
39
|
-
const { title } = titleStore;
|
|
40
|
-
if (title && title !== GemTitleElement.defaultTitle) {
|
|
41
|
-
GemTitleElement.title = title;
|
|
42
|
-
document.title = GemTitleElement.title + suffix;
|
|
43
|
-
} else if (str) {
|
|
44
|
-
GemTitleElement.title = str;
|
|
45
|
-
document.title = GemTitleElement.title + suffix;
|
|
46
|
-
} else {
|
|
47
|
-
GemTitleElement.title = GemTitleElement.defaultTitle;
|
|
48
|
-
document.title = GemTitleElement.title;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
@attribute suffix: string;
|
|
53
|
-
|
|
54
|
-
constructor() {
|
|
55
|
-
super();
|
|
56
|
-
new MutationObserver(() => this.update()).observe(this, { childList: true, characterData: true, subtree: true });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
render() {
|
|
60
|
-
// 多个 <gem-title> 时,最终 document.title 按执行顺序决定
|
|
61
|
-
GemTitleElement.updateTitle(this.textContent || '', this.suffix);
|
|
62
|
-
|
|
63
|
-
if (this.hidden) {
|
|
64
|
-
return html``;
|
|
65
|
-
}
|
|
66
|
-
return html`${GemTitleElement.title}`;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
connect(titleStore, GemTitleElement.updateTitle);
|
|
5
|
+
customElements.define('gem-title', GemTitleElement);
|
package/src/elements/unsafe.ts
CHANGED
|
@@ -1,39 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { attribute, customElement } from '../lib/decorators';
|
|
1
|
+
import { GemUnsafeElement } from './base/unsafe';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
* 直接写会被解释成固定属性,需要使用变量赋值
|
|
6
|
-
*
|
|
7
|
-
* @customElement gem-unsafe
|
|
8
|
-
* @attr content
|
|
9
|
-
* @attr contentcss
|
|
10
|
-
*/
|
|
11
|
-
@customElement('gem-unsafe')
|
|
12
|
-
export class GemUnsafeElement extends GemElement {
|
|
13
|
-
@attribute content: string;
|
|
14
|
-
@attribute contentcss: string;
|
|
3
|
+
export * from './base/unsafe';
|
|
15
4
|
|
|
16
|
-
|
|
17
|
-
super();
|
|
18
|
-
this.effect(
|
|
19
|
-
() => {
|
|
20
|
-
if (this.shadowRoot) {
|
|
21
|
-
this.shadowRoot.innerHTML = `
|
|
22
|
-
<style>
|
|
23
|
-
:host {
|
|
24
|
-
display: contents;
|
|
25
|
-
}
|
|
26
|
-
${this.contentcss}
|
|
27
|
-
</style>
|
|
28
|
-
${this.content}
|
|
29
|
-
`;
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
() => [this.content, this.contentcss],
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
render() {
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
5
|
+
customElements.define('gem-unsafe', GemUnsafeElement);
|
package/src/elements/use.ts
CHANGED
|
@@ -1,59 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { attribute, property, customElement, state } from '../lib/decorators';
|
|
1
|
+
import { GemUseElement } from './base/use';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* svg 中的 `<use>` 不能穿透 ShadowDOM,
|
|
7
|
-
* 此元素用来模拟 `<use>`,
|
|
8
|
-
* 由于是复制元素,所以不能像 `<use>` 一样自动更新
|
|
9
|
-
*
|
|
10
|
-
* slot 支持为 icon 添加效果,如涟漪,徽章
|
|
11
|
-
*
|
|
12
|
-
* @customElement gem-use
|
|
13
|
-
* @attr selector
|
|
14
|
-
*/
|
|
15
|
-
@customElement('gem-use')
|
|
16
|
-
export class GemUseElement extends GemElement {
|
|
17
|
-
@attribute selector: string; // CSS 选择器
|
|
18
|
-
@property root?: HTMLElement | Document | ShadowRoot;
|
|
19
|
-
@property element?: string | DocumentFragment | Element;
|
|
3
|
+
export * from './base/use';
|
|
20
4
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
private getContent() {
|
|
24
|
-
const ele = this.element || (this.selector ? (this.root || document).querySelector(this.selector) : null);
|
|
25
|
-
if (typeof ele === 'string') {
|
|
26
|
-
let temp = eleCache.get(ele);
|
|
27
|
-
if (!temp) {
|
|
28
|
-
temp = document.createElement('template');
|
|
29
|
-
temp.innerHTML = ele;
|
|
30
|
-
eleCache.set(ele, temp);
|
|
31
|
-
}
|
|
32
|
-
return temp.content.cloneNode(true);
|
|
33
|
-
} else if (ele instanceof HTMLTemplateElement) {
|
|
34
|
-
return ele.content.cloneNode(true);
|
|
35
|
-
} else {
|
|
36
|
-
return ele?.cloneNode(true);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
render() {
|
|
41
|
-
return html`
|
|
42
|
-
<style>
|
|
43
|
-
:host {
|
|
44
|
-
position: relative;
|
|
45
|
-
}
|
|
46
|
-
:host(:not([hidden])) {
|
|
47
|
-
display: inline-flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
}
|
|
50
|
-
svg {
|
|
51
|
-
width: 100%;
|
|
52
|
-
height: 100%;
|
|
53
|
-
}
|
|
54
|
-
</style>
|
|
55
|
-
${this.getContent()}
|
|
56
|
-
<slot></slot>
|
|
57
|
-
`;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
5
|
+
customElements.define('gem-use', GemUseElement);
|
package/src/lib/element.ts
CHANGED
|
@@ -574,7 +574,9 @@ export function defineRef(target: GemElement, prop: string, ref: string) {
|
|
|
574
574
|
return ref;
|
|
575
575
|
},
|
|
576
576
|
get element() {
|
|
577
|
-
const gemReflects = ([...ele.querySelectorAll('
|
|
577
|
+
const gemReflects = ([...ele.querySelectorAll('[data-gemreflect]')] as GemReflectElement[]).map(
|
|
578
|
+
(e) => e.target,
|
|
579
|
+
);
|
|
578
580
|
for (const e of [ele, ...gemReflects]) {
|
|
579
581
|
const result = e.querySelector(`[ref=${ref}]`);
|
|
580
582
|
if (result) return result;
|