@mantou/gem 1.7.1 → 1.7.3
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 +367 -369
- package/dist/gem.umd.js +24 -28
- package/elements/base/dialog.d.ts +7 -7
- package/elements/base/dialog.d.ts.map +1 -1
- package/elements/base/dialog.js +10 -3
- package/elements/base/dialog.js.map +1 -1
- package/elements/base/gesture.d.ts +4 -13
- package/elements/base/gesture.d.ts.map +1 -1
- package/elements/base/gesture.js +151 -134
- package/elements/base/gesture.js.map +1 -1
- package/elements/base/link.d.ts +10 -10
- package/elements/base/link.d.ts.map +1 -1
- package/elements/base/link.js +69 -63
- package/elements/base/link.js.map +1 -1
- package/elements/base/modal-factory.d.ts +117 -83
- package/elements/base/modal-factory.d.ts.map +1 -1
- package/elements/base/modal-factory.js +12 -8
- package/elements/base/modal-factory.js.map +1 -1
- package/elements/base/reflect.js.map +1 -1
- package/elements/base/route.d.ts +12 -5
- package/elements/base/route.d.ts.map +1 -1
- package/elements/base/route.js +16 -4
- package/elements/base/route.js.map +1 -1
- package/elements/base/title.d.ts +3 -1
- package/elements/base/title.d.ts.map +1 -1
- package/elements/base/title.js +14 -16
- package/elements/base/title.js.map +1 -1
- package/elements/base/unsafe.js.map +1 -1
- package/elements/base/use.d.ts +1 -1
- package/elements/base/use.d.ts.map +1 -1
- package/elements/base/use.js +27 -17
- package/elements/base/use.js.map +1 -1
- package/helper/i18n.d.ts +2 -2
- package/helper/i18n.d.ts.map +1 -1
- package/helper/i18n.js.map +1 -1
- package/helper/mediaquery.d.ts +16 -18
- package/helper/mediaquery.d.ts.map +1 -1
- package/helper/mediaquery.js +42 -41
- package/helper/mediaquery.js.map +1 -1
- package/helper/request.d.ts +1 -1
- package/helper/request.d.ts.map +1 -1
- package/helper/request.js.map +1 -1
- package/helper/ssr-shim.js.map +1 -1
- package/helper/theme.d.ts +2 -2
- package/helper/theme.d.ts.map +1 -1
- package/helper/theme.js +20 -24
- package/helper/theme.js.map +1 -1
- package/lib/decorators.d.ts +4 -4
- package/lib/decorators.d.ts.map +1 -1
- package/lib/decorators.js +1 -2
- package/lib/decorators.js.map +1 -1
- package/lib/element.d.ts +5 -7
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +46 -71
- package/lib/element.js.map +1 -1
- package/lib/history.d.ts +1 -1
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +2 -2
- package/lib/history.js.map +1 -1
- package/lib/store.d.ts +2 -2
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js.map +1 -1
- package/lib/utils.d.ts +8 -32
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +7 -22
- package/lib/utils.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -2
- package/src/elements/base/dialog.ts +8 -3
- package/src/elements/base/gesture.ts +51 -45
- package/src/elements/base/link.ts +64 -62
- package/src/elements/base/modal-factory.ts +5 -0
- package/src/elements/base/route.ts +21 -4
- package/src/elements/base/title.ts +8 -11
- package/src/elements/base/use.ts +3 -3
- package/src/helper/mediaquery.ts +43 -42
- package/src/helper/theme.ts +22 -24
- package/src/lib/decorators.ts +1 -2
- package/src/lib/element.ts +38 -63
- package/src/lib/history.ts +2 -1
- package/src/lib/utils.ts +11 -43
- package/src/lib/version.ts +1 -1
- package/src/test/gem-element/advance.test.ts +16 -8
- package/src/test/history.test.ts +3 -1
- package/src/test/utils.test.ts +8 -1
|
@@ -8,7 +8,6 @@ interface NamePosition {
|
|
|
8
8
|
[index: string]: number;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
// TODO: use `URLPattern`
|
|
12
11
|
class ParamsRegExp extends RegExp {
|
|
13
12
|
namePosition: NamePosition;
|
|
14
13
|
constructor(pattern: string) {
|
|
@@ -28,10 +27,27 @@ class ParamsRegExp extends RegExp {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
type Params = Record<string, string>;
|
|
30
|
+
declare global {
|
|
31
|
+
interface Window {
|
|
32
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1731418
|
|
33
|
+
// https://github.com/WebKit/standards-positions/issues/61
|
|
34
|
+
URLPattern: any;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
31
37
|
|
|
32
|
-
//
|
|
38
|
+
// URLPattern 大小写敏感
|
|
33
39
|
// 匹配成功时返回 params
|
|
40
|
+
// `/a/b/:c/:d` `/a/b/1/2`
|
|
41
|
+
// pattern 以 / 结尾时能匹配 2 中路径
|
|
42
|
+
// `/a/b/:c/:d/` `/a/b/1/2`
|
|
43
|
+
// `/a/b/:c/:d/` `/a/b/1/2/`
|
|
34
44
|
export function matchPath(pattern: string, path: string) {
|
|
45
|
+
if (window.URLPattern) {
|
|
46
|
+
const urLPattern = new window.URLPattern({ pathname: pattern });
|
|
47
|
+
const matchResult = urLPattern.exec({ pathname: path }) || urLPattern.exec({ pathname: `${path}/` });
|
|
48
|
+
if (!matchResult) return null;
|
|
49
|
+
return matchResult.pathname.groups as Params;
|
|
50
|
+
}
|
|
35
51
|
const reg = new ParamsRegExp(pattern);
|
|
36
52
|
const matchResult = path.match(reg) || `${path}/`.match(reg);
|
|
37
53
|
if (!matchResult) return null;
|
|
@@ -111,13 +127,14 @@ export class GemRouteElement extends GemElement<State> {
|
|
|
111
127
|
* html`<gem-route .locationStore=${locationStore}>`
|
|
112
128
|
*/
|
|
113
129
|
@property locationStore?: Store<{ path: string; params: Params; query: QueryString; data?: any }>;
|
|
114
|
-
@property key
|
|
130
|
+
@property key?: any; // 除了 href 提供另外一种方式来更新,比如语言更新也需要刷新 <gem-route>
|
|
115
131
|
@emitter routechange: Emitter<RouteItem | null>; // path 改变或者 key 改变,包含初始渲染
|
|
116
132
|
@emitter loading: Emitter<RouteItem>;
|
|
117
133
|
@emitter error: Emitter<any>;
|
|
118
134
|
|
|
135
|
+
/**当前使用的路由对象 */
|
|
119
136
|
currentRoute: RouteItem | null;
|
|
120
|
-
|
|
137
|
+
/**当前匹配的路由的 params */
|
|
121
138
|
currentParams: Params = {};
|
|
122
139
|
|
|
123
140
|
#lastLoader?: Promise<TemplateResult>;
|
|
@@ -27,26 +27,23 @@ export class GemTitleElement extends GemElement {
|
|
|
27
27
|
// 没有后缀的标题
|
|
28
28
|
static title = document.title;
|
|
29
29
|
static defaultTitle = document.title;
|
|
30
|
+
static defaultPrefix = `${document.title} | `;
|
|
30
31
|
static defaultSuffix = ` - ${document.title}`;
|
|
31
32
|
|
|
32
33
|
static setTitle(title: string) {
|
|
33
34
|
updateStore(titleStore, { title });
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
static updateTitle(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
GemTitleElement.title = title;
|
|
40
|
-
document.title = GemTitleElement.title + suffix;
|
|
41
|
-
} else if (str) {
|
|
42
|
-
GemTitleElement.title = str;
|
|
43
|
-
document.title = GemTitleElement.title + suffix;
|
|
37
|
+
static updateTitle(title = titleStore.title, prefix = '', suffix = '') {
|
|
38
|
+
if (title === GemTitleElement.defaultTitle) {
|
|
39
|
+
document.title = GemTitleElement.title = title;
|
|
44
40
|
} else {
|
|
45
|
-
GemTitleElement.title =
|
|
46
|
-
document.title = GemTitleElement.title;
|
|
41
|
+
GemTitleElement.title = title;
|
|
42
|
+
document.title = prefix + GemTitleElement.title + suffix;
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
45
|
|
|
46
|
+
@attribute prefix: string;
|
|
50
47
|
@attribute suffix: string;
|
|
51
48
|
|
|
52
49
|
constructor() {
|
|
@@ -56,7 +53,7 @@ export class GemTitleElement extends GemElement {
|
|
|
56
53
|
|
|
57
54
|
render() {
|
|
58
55
|
// 多个 <gem-title> 时,最终 document.title 按执行顺序决定
|
|
59
|
-
GemTitleElement.updateTitle(this.textContent ||
|
|
56
|
+
GemTitleElement.updateTitle(this.textContent || undefined, this.prefix, this.suffix);
|
|
60
57
|
|
|
61
58
|
if (this.hidden) {
|
|
62
59
|
return html``;
|
package/src/elements/base/use.ts
CHANGED
|
@@ -18,7 +18,7 @@ export class GemUseElement extends GemElement {
|
|
|
18
18
|
|
|
19
19
|
@state active: boolean;
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
#getContent = () => {
|
|
22
22
|
const ele = this.element || (this.selector ? (this.root || document).querySelector(this.selector) : null);
|
|
23
23
|
if (typeof ele === 'string') {
|
|
24
24
|
let temp = eleCache.get(ele);
|
|
@@ -33,7 +33,7 @@ export class GemUseElement extends GemElement {
|
|
|
33
33
|
} else {
|
|
34
34
|
return ele?.cloneNode(true);
|
|
35
35
|
}
|
|
36
|
-
}
|
|
36
|
+
};
|
|
37
37
|
|
|
38
38
|
render() {
|
|
39
39
|
return html`
|
|
@@ -48,7 +48,7 @@ export class GemUseElement extends GemElement {
|
|
|
48
48
|
height: 100%;
|
|
49
49
|
}
|
|
50
50
|
</style>
|
|
51
|
-
${this
|
|
51
|
+
${this.#getContent()}
|
|
52
52
|
<slot></slot>
|
|
53
53
|
`;
|
|
54
54
|
}
|
package/src/helper/mediaquery.ts
CHANGED
|
@@ -1,77 +1,78 @@
|
|
|
1
1
|
// https://gist.github.com/gokulkrishh/242e68d1ee94ad05f488
|
|
2
2
|
// https://mediag.com/news/popular-screen-resolutions-designing-for-all/
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const match = (query: string) => window.matchMedia(query).matches;
|
|
5
5
|
|
|
6
6
|
export const mediaQuery = {
|
|
7
7
|
PRINT: 'print',
|
|
8
8
|
get isPrint() {
|
|
9
|
-
return
|
|
9
|
+
return match(this.PRINT);
|
|
10
10
|
},
|
|
11
|
+
|
|
11
12
|
HOVER: '(hover: hover)',
|
|
12
13
|
get isHover() {
|
|
13
|
-
return
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
PHONE: '(min-width: 319px) and (max-width: 480px)',
|
|
17
|
-
get isPhone() {
|
|
18
|
-
return matche(this.PHONE);
|
|
14
|
+
return match(this.HOVER);
|
|
19
15
|
},
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
PWA: '(display-mode: standalone)',
|
|
18
|
+
// PWA: '(display-mode: browser)', // debugging
|
|
19
|
+
get isPWA() {
|
|
20
|
+
return match(this.PWA);
|
|
24
21
|
},
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
get
|
|
28
|
-
return
|
|
23
|
+
MOTION_REDUCE: '(prefers-reduced-motion: reduce)',
|
|
24
|
+
get isMotionReduce() {
|
|
25
|
+
return match(this.MOTION_REDUCE);
|
|
29
26
|
},
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
get
|
|
33
|
-
return
|
|
28
|
+
DATA_REDUCE: '(prefers-reduced-data: reduce)',
|
|
29
|
+
get isDataReduce() {
|
|
30
|
+
return match(this.DATA_REDUCE);
|
|
34
31
|
},
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return matche(this.PHONE_LANDSCAPE);
|
|
33
|
+
WATCH: '(width < 320px)',
|
|
34
|
+
get isWatch() {
|
|
35
|
+
return match(this.WATCH);
|
|
40
36
|
},
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
get
|
|
44
|
-
return
|
|
38
|
+
SMALL_PHONE: '(320px <= width <= 480px) and (height <= 640px)',
|
|
39
|
+
get isSmallPhone() {
|
|
40
|
+
return match(this.SMALL_PHONE);
|
|
45
41
|
},
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
get
|
|
49
|
-
return
|
|
43
|
+
PHONE: '(320px <= width <= 480px)',
|
|
44
|
+
get isPhone() {
|
|
45
|
+
return match(this.PHONE);
|
|
50
46
|
},
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
PHONE_LANDSCAPE: '(480px < width < 960px) and (orientation: landscape)',
|
|
49
|
+
// PHONE_LANDSCAPE: '(480px < width < 960px)',
|
|
50
|
+
get isPhoneLandscape() {
|
|
51
|
+
return match(this.PHONE_LANDSCAPE);
|
|
55
52
|
},
|
|
56
53
|
|
|
57
|
-
|
|
54
|
+
// Widget
|
|
55
|
+
SHORT: '(width >= 480px) and (height <= 320px)',
|
|
58
56
|
get isShort() {
|
|
59
|
-
return
|
|
57
|
+
return match(this.SHORT);
|
|
60
58
|
},
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
// 1280 x 850
|
|
61
|
+
// 1024 x 768
|
|
62
|
+
TABLET: '(480px < width <= 1280px)',
|
|
63
|
+
get isTablet() {
|
|
64
|
+
return match(this.TABLET);
|
|
66
65
|
},
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
// 1366x768
|
|
68
|
+
DESKTOP: '(width > 1280px) and (orientation: landscape)',
|
|
69
|
+
get isDesktop() {
|
|
70
|
+
return match(this.DESKTOP);
|
|
71
71
|
},
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
// 1920x1080
|
|
74
|
+
WIDTHSCREEN: '(width >= 1920px) and (orientation: landscape)',
|
|
75
|
+
get isWidthScreen() {
|
|
76
|
+
return match(this.WIDTHSCREEN);
|
|
76
77
|
},
|
|
77
78
|
};
|
package/src/helper/theme.ts
CHANGED
|
@@ -11,21 +11,13 @@ export function getThemeStore<T>(theme: SomeType<T>) {
|
|
|
11
11
|
return themeStoreMap.get(theme) as Store<T>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const themePropsMap = new WeakMap();
|
|
15
15
|
|
|
16
|
-
export function
|
|
17
|
-
return
|
|
16
|
+
export function getThemeProps<T>(theme: SomeType<T>) {
|
|
17
|
+
return themePropsMap.get(theme) as SomeType<T>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const themeStore = themeStoreMap.get(theme);
|
|
22
|
-
const themeProp = themePropMap.get(theme);
|
|
23
|
-
const rules = Object.keys(themeStore).reduce((prev, key) => {
|
|
24
|
-
if (!themeStore[key] || !themeProp[key]) return prev;
|
|
25
|
-
return prev + `${themeProp[key]}:${themeStore[key]};`;
|
|
26
|
-
}, '');
|
|
27
|
-
style.textContent = `:root, :host {${rules}}`;
|
|
28
|
-
}
|
|
20
|
+
const setThemeFnMap = new WeakMap();
|
|
29
21
|
|
|
30
22
|
/**
|
|
31
23
|
* 创建主题,插入 `document.head`
|
|
@@ -39,17 +31,23 @@ function replaceStyle(style: HTMLStyleElement, theme: Record<string, unknown>) {
|
|
|
39
31
|
export function createTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
40
32
|
const salt = randomStr();
|
|
41
33
|
const style = document.createElement('style');
|
|
42
|
-
const
|
|
34
|
+
const store = createStore<T>(themeObj);
|
|
43
35
|
const theme: Record<string, string> = {};
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
themeStoreMap.set(theme,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
const props: Record<string, string> = {};
|
|
37
|
+
themePropsMap.set(theme, props);
|
|
38
|
+
themeStoreMap.set(theme, store);
|
|
39
|
+
const setTheme = () =>
|
|
40
|
+
Object.keys(store).forEach((key) => {
|
|
41
|
+
if (props[key]) return;
|
|
42
|
+
props[key] = `--${camelToKebabCase(key)}-${salt}`;
|
|
43
|
+
theme[key] = `var(${props[key]})`;
|
|
44
|
+
});
|
|
45
|
+
setThemeFnMap.set(theme, setTheme);
|
|
46
|
+
setTheme();
|
|
47
|
+
const getStyle = () =>
|
|
48
|
+
`:root, :host {${Object.keys(store).reduce((prev, key) => prev + `${props[key]}:${store[key]};`, '')}}`;
|
|
49
|
+
const replace = () => (style.textContent = getStyle());
|
|
50
|
+
connect(store, replace);
|
|
53
51
|
replace();
|
|
54
52
|
(document.head || document.documentElement).append(style);
|
|
55
53
|
return theme as SomeType<T>;
|
|
@@ -61,6 +59,6 @@ export function createTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
|
61
59
|
* @param newThemeObj 新主题
|
|
62
60
|
*/
|
|
63
61
|
export function updateTheme<T = Record<string, unknown>>(theme: SomeType<T>, newThemeObj: Partial<T>) {
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
updateStore(getThemeStore(theme), newThemeObj);
|
|
63
|
+
setThemeFnMap.get(theme)();
|
|
66
64
|
}
|
package/src/lib/decorators.ts
CHANGED
|
@@ -191,7 +191,6 @@ export function adoptedStyle(style: Sheet<unknown>) {
|
|
|
191
191
|
* ```
|
|
192
192
|
*/
|
|
193
193
|
export function connectStore(store: Store<unknown>) {
|
|
194
|
-
// 这里的签名该怎么写?
|
|
195
194
|
return function (cls: unknown) {
|
|
196
195
|
const con = cls as GemElementConstructor;
|
|
197
196
|
pushStaticField(con.prototype, 'observedStores', store);
|
|
@@ -203,7 +202,7 @@ export function connectStore(store: Store<unknown>) {
|
|
|
203
202
|
*
|
|
204
203
|
* For example
|
|
205
204
|
* ```ts
|
|
206
|
-
* @rootElement(
|
|
205
|
+
* @rootElement('my-element')
|
|
207
206
|
* class App extends GemElement {}
|
|
208
207
|
* ```
|
|
209
208
|
*/
|
package/src/lib/element.ts
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
kebabToCamelCase,
|
|
14
14
|
PropProxyMap,
|
|
15
15
|
removeItems,
|
|
16
|
-
useNativeCSSStyleSheet,
|
|
17
16
|
} from './utils';
|
|
18
17
|
import * as GemExports from './element';
|
|
19
18
|
import * as VersionExports from './version';
|
|
@@ -30,16 +29,13 @@ declare global {
|
|
|
30
29
|
interface ElementInternals extends ARIAMixin {
|
|
31
30
|
// https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet
|
|
32
31
|
states: Set<string>;
|
|
33
|
-
role?: string | null;
|
|
34
32
|
}
|
|
35
33
|
// 用于 css 选择器选择元素,使用 @refobject 自动选择获取
|
|
36
34
|
// 必须使用 attr 赋值
|
|
37
35
|
/**
|
|
38
36
|
* @attr ref
|
|
39
|
-
* @attr inert
|
|
40
37
|
*/
|
|
41
38
|
interface HTMLElement {
|
|
42
|
-
inert: boolean;
|
|
43
39
|
ref: string;
|
|
44
40
|
}
|
|
45
41
|
}
|
|
@@ -88,6 +84,10 @@ export interface GemElementOptions {
|
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
export abstract class GemElement<T = Record<string, unknown>> extends HTMLElement {
|
|
87
|
+
// 禁止覆盖自定义元素原生生命周期方法
|
|
88
|
+
// https://github.com/microsoft/TypeScript/issues/21388#issuecomment-934345226
|
|
89
|
+
static #final = Symbol();
|
|
90
|
+
|
|
91
91
|
// 这里只是字段申明,不能赋值,否则子类会继承被共享该字段
|
|
92
92
|
static observedAttributes?: string[]; // WebAPI 中是实时检查这个列表
|
|
93
93
|
static booleanAttributes?: Set<string>;
|
|
@@ -119,16 +119,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
119
119
|
|
|
120
120
|
constructor({ isAsync, isLight, delegatesFocus, slotAssignment }: GemElementOptions = {}) {
|
|
121
121
|
super();
|
|
122
|
-
(this as any)[constructorSymbol] = true;
|
|
123
122
|
|
|
124
123
|
// 外部不可见,但允许类外面使用
|
|
125
|
-
addMicrotask(() => (
|
|
126
|
-
(this
|
|
127
|
-
(this
|
|
124
|
+
addMicrotask(() => Reflect.set(this, initSymbol, false));
|
|
125
|
+
Reflect.set(this, constructorSymbol, true);
|
|
126
|
+
Reflect.set(this, initSymbol, true);
|
|
127
|
+
Reflect.set(this, updateSymbol, () => {
|
|
128
128
|
if (this.#isMounted) {
|
|
129
129
|
addMicrotask(this.#update);
|
|
130
130
|
}
|
|
131
|
-
};
|
|
131
|
+
});
|
|
132
132
|
|
|
133
133
|
this.#isAsync = isAsync;
|
|
134
134
|
this.#renderRoot = isLight ? this : this.attachShadow({ mode: 'open', delegatesFocus, slotAssignment });
|
|
@@ -142,34 +142,10 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
142
142
|
this.effect(
|
|
143
143
|
() => {
|
|
144
144
|
const root = this.getRootNode() as ShadowRoot | Document;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (ele._sheets[style]) {
|
|
150
|
-
ele._sheets[style].count++;
|
|
151
|
-
} else {
|
|
152
|
-
const s = document.createElement('style');
|
|
153
|
-
s.innerHTML = style;
|
|
154
|
-
s.media = media.mediaText;
|
|
155
|
-
ele.append(s);
|
|
156
|
-
ele._sheets[style] = { ele: s, count: 1 };
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
return () => {
|
|
160
|
-
sheets.forEach(({ style }: any) => {
|
|
161
|
-
ele._sheets[style].count--;
|
|
162
|
-
if (!ele._sheets[style].count) {
|
|
163
|
-
delete ele._sheets[style];
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
} else {
|
|
168
|
-
root.adoptedStyleSheets = [...root.adoptedStyleSheets, ...sheets];
|
|
169
|
-
return () => {
|
|
170
|
-
root.adoptedStyleSheets = removeItems(root.adoptedStyleSheets, sheets);
|
|
171
|
-
};
|
|
172
|
-
}
|
|
145
|
+
root.adoptedStyleSheets = [...root.adoptedStyleSheets, ...sheets];
|
|
146
|
+
return () => {
|
|
147
|
+
root.adoptedStyleSheets = removeItems(root.adoptedStyleSheets, sheets);
|
|
148
|
+
};
|
|
173
149
|
},
|
|
174
150
|
() => [],
|
|
175
151
|
);
|
|
@@ -289,6 +265,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
289
265
|
this.#memoList.push({
|
|
290
266
|
callback,
|
|
291
267
|
getDep,
|
|
268
|
+
// 这里为什么跟 effect 不同???
|
|
292
269
|
values: [Symbol()],
|
|
293
270
|
inConstructor: (this as any)[constructorSymbol],
|
|
294
271
|
});
|
|
@@ -320,20 +297,8 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
320
297
|
|
|
321
298
|
#render = () => {
|
|
322
299
|
this.#execMemo();
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
: html`${this.shadowRoot?.adoptedStyleSheets?.map(
|
|
326
|
-
(e: any) => html`
|
|
327
|
-
<style media=${e.media.mediaText}>
|
|
328
|
-
${e.style}
|
|
329
|
-
</style>
|
|
330
|
-
`,
|
|
331
|
-
)}`;
|
|
332
|
-
if (this.render) {
|
|
333
|
-
const r = this.render();
|
|
334
|
-
return r && html`${r}${styles}`;
|
|
335
|
-
}
|
|
336
|
-
return this.#renderRoot === this ? undefined : html`<slot></slot>${styles}`;
|
|
300
|
+
if (this.render) return this.render();
|
|
301
|
+
return this.#renderRoot === this ? undefined : html`<slot></slot>`;
|
|
337
302
|
};
|
|
338
303
|
|
|
339
304
|
/**@lifecycle */
|
|
@@ -392,15 +357,18 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
392
357
|
if (this.#isMounted) {
|
|
393
358
|
addMicrotask(this.#update);
|
|
394
359
|
}
|
|
360
|
+
return GemElement.#final;
|
|
395
361
|
}
|
|
396
362
|
|
|
397
363
|
#connectedCallback = () => {
|
|
398
|
-
// 似乎这是最早的判断不在 `constructor` 中的地方
|
|
399
|
-
(this as any)[constructorSymbol] = false;
|
|
400
364
|
if (this.#isAppendReason) {
|
|
401
365
|
this.#isAppendReason = false;
|
|
402
366
|
return;
|
|
403
367
|
}
|
|
368
|
+
|
|
369
|
+
// 似乎这是最早的判断不在 `constructor` 中的地方
|
|
370
|
+
Reflect.set(this, constructorSymbol, false);
|
|
371
|
+
|
|
404
372
|
this.willMount?.();
|
|
405
373
|
const { observedStores, rootElement } = this.constructor as typeof GemElement;
|
|
406
374
|
observedStores?.forEach((store) => {
|
|
@@ -447,13 +415,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
447
415
|
} else {
|
|
448
416
|
this.#connectedCallback();
|
|
449
417
|
}
|
|
418
|
+
return GemElement.#final;
|
|
450
419
|
}
|
|
451
420
|
|
|
452
421
|
/**
|
|
453
422
|
* @private
|
|
454
423
|
* @final
|
|
455
424
|
*/
|
|
456
|
-
|
|
425
|
+
adoptedCallback() {
|
|
426
|
+
return GemElement.#final;
|
|
427
|
+
}
|
|
457
428
|
|
|
458
429
|
/**
|
|
459
430
|
* @private
|
|
@@ -472,12 +443,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
472
443
|
});
|
|
473
444
|
execCallback(this.#unmountCallback);
|
|
474
445
|
this.unmounted?.();
|
|
475
|
-
this.#effectList?.forEach((
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
this.#memoList = this.#memoList?.filter(({ inConstructor }) => inConstructor);
|
|
446
|
+
this.#effectList?.forEach(({ preCallback }) => execCallback(preCallback));
|
|
447
|
+
this.#effectList = this.#effectList?.filter(this.#filterEffect);
|
|
448
|
+
this.#memoList = this.#memoList?.filter(this.#filterEffect);
|
|
449
|
+
return GemElement.#final;
|
|
480
450
|
}
|
|
451
|
+
|
|
452
|
+
#filterEffect = (e: EffectItem<any>) => {
|
|
453
|
+
e.initialized = false;
|
|
454
|
+
return e.inConstructor;
|
|
455
|
+
};
|
|
481
456
|
}
|
|
482
457
|
|
|
483
458
|
const gemElementProxyMap = new PropProxyMap<GemElement>();
|
|
@@ -503,7 +478,7 @@ export function defineAttribute(target: GemElement, prop: string, attr: string)
|
|
|
503
478
|
},
|
|
504
479
|
set(v: string | null | undefined | number | boolean) {
|
|
505
480
|
const that = this as GemElement;
|
|
506
|
-
const proxy = gemElementProxyMap.get(this)
|
|
481
|
+
const proxy = gemElementProxyMap.get(this);
|
|
507
482
|
const hasSet = proxy[prop];
|
|
508
483
|
const value = that.getAttribute(attr);
|
|
509
484
|
// https://github.com/whatwg/dom/issues/922
|
|
@@ -544,7 +519,7 @@ export function defineProperty(
|
|
|
544
519
|
},
|
|
545
520
|
set(v) {
|
|
546
521
|
const that = this as GemElement;
|
|
547
|
-
const proxy = gemElementProxyMap.get(that)
|
|
522
|
+
const proxy = gemElementProxyMap.get(that);
|
|
548
523
|
if (v !== proxy[prop]) {
|
|
549
524
|
if (event) {
|
|
550
525
|
proxy[prop] = v?.[isEventHandleSymbol]
|
|
@@ -554,7 +529,7 @@ export function defineProperty(
|
|
|
554
529
|
that.dispatchEvent(evt);
|
|
555
530
|
v(detail, options);
|
|
556
531
|
};
|
|
557
|
-
proxy[prop]
|
|
532
|
+
Reflect.set(proxy[prop]!, isEventHandleSymbol, true);
|
|
558
533
|
// emitter 不触发元素更新
|
|
559
534
|
} else {
|
|
560
535
|
proxy[prop] = v;
|
|
@@ -627,7 +602,7 @@ customElements.define = (name: string, cls: CustomElementConstructor, options?:
|
|
|
627
602
|
defineRefs?.forEach((ref) => defineRef(cls.prototype, kebabToCamelCase(ref), ref));
|
|
628
603
|
}
|
|
629
604
|
|
|
630
|
-
nativeDefineElement(name, cls
|
|
605
|
+
nativeDefineElement(name, cls, options);
|
|
631
606
|
};
|
|
632
607
|
|
|
633
608
|
declare global {
|
package/src/lib/history.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// https://github.com/WICG/navigation-api#stakeholder-feedback
|
|
2
|
+
|
|
1
3
|
import { createStore, updateStore, connect } from './store';
|
|
2
4
|
import { QueryString, cleanObject, GemError, absoluteLocation } from './utils';
|
|
3
5
|
|
|
@@ -38,7 +40,6 @@ export interface UpdateHistoryParams {
|
|
|
38
40
|
// 实际应用值
|
|
39
41
|
type HistoryParams = UpdateHistoryParams & { title: string; path: string; query: QueryString; hash: string };
|
|
40
42
|
|
|
41
|
-
// TODO: WeakRef
|
|
42
43
|
const paramsMap = new Map<string, HistoryParams>();
|
|
43
44
|
|
|
44
45
|
function validData(data: any) {
|
package/src/lib/utils.ts
CHANGED
|
@@ -23,7 +23,7 @@ function execMicrotaskStack() {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* 添加回调函数到微任务队列栈;
|
|
26
|
-
*
|
|
26
|
+
* 先进后执行,使用这个函数可以改变嵌套的元素 `mounted` 的顺序;
|
|
27
27
|
*/
|
|
28
28
|
export function addMicrotaskToStack(func: () => void) {
|
|
29
29
|
if (!microtaskStack.length) {
|
|
@@ -50,8 +50,8 @@ interface LinkedListItem<T> {
|
|
|
50
50
|
next?: LinkedListItem<T>;
|
|
51
51
|
}
|
|
52
52
|
// work on nodejs
|
|
53
|
-
export class LinkedList<T = any> extends
|
|
54
|
-
addEventListener: <K extends keyof LinkedListEventMap>(
|
|
53
|
+
export class LinkedList<T = any> extends EventTarget {
|
|
54
|
+
declare addEventListener: <K extends keyof LinkedListEventMap>(
|
|
55
55
|
type: K,
|
|
56
56
|
listener: (this: LinkedList<T>, ev: LinkedListEventMap[K]) => any,
|
|
57
57
|
options?: boolean | AddEventListenerOptions,
|
|
@@ -115,7 +115,7 @@ export class LinkedList<T = any> extends (globalThis.EventTarget || Object) {
|
|
|
115
115
|
get(): T | undefined {
|
|
116
116
|
const firstItem = this.#firstItem;
|
|
117
117
|
if (!firstItem) return;
|
|
118
|
-
this
|
|
118
|
+
this.delete(firstItem.value);
|
|
119
119
|
return firstItem.value;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -131,11 +131,6 @@ export class PropProxyMap<T extends NonPrimitive, V = unknown> extends WeakMap<T
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
declare global {
|
|
135
|
-
interface URLSearchParams {
|
|
136
|
-
entries(): Iterable<readonly [string | number | symbol, any]>;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
134
|
export class QueryString extends URLSearchParams {
|
|
140
135
|
constructor(param?: any) {
|
|
141
136
|
super(param);
|
|
@@ -216,22 +211,6 @@ export type Sheet<T> = {
|
|
|
216
211
|
[P in keyof T]: P;
|
|
217
212
|
} & { [SheetToken]: CSSStyleSheet };
|
|
218
213
|
|
|
219
|
-
declare global {
|
|
220
|
-
interface CSSStyleSheet {
|
|
221
|
-
replaceSync: (str: string) => void;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
interface CSSRuleList {
|
|
225
|
-
item(index: number): CSSStyleRule;
|
|
226
|
-
}
|
|
227
|
-
interface ShadowRoot {
|
|
228
|
-
adoptedStyleSheets: CSSStyleSheet[];
|
|
229
|
-
}
|
|
230
|
-
interface Document {
|
|
231
|
-
adoptedStyleSheets: CSSStyleSheet[];
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
214
|
export type StyledType = 'id' | 'class' | 'keyframes';
|
|
236
215
|
export interface StyledValueObject {
|
|
237
216
|
styledContent: string;
|
|
@@ -241,22 +220,6 @@ export interface StyledKeyValuePair {
|
|
|
241
220
|
[key: string]: StyledValueObject;
|
|
242
221
|
}
|
|
243
222
|
|
|
244
|
-
// !!! 目前只有 Chrome/FirefoxNightly 支持
|
|
245
|
-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1520690
|
|
246
|
-
// https://bugs.webkit.org/show_bug.cgi?id=228684
|
|
247
|
-
export let useNativeCSSStyleSheet = true;
|
|
248
|
-
let CSSStyleSheet = globalThis.CSSStyleSheet;
|
|
249
|
-
try {
|
|
250
|
-
new (CSSStyleSheet as any)();
|
|
251
|
-
} catch {
|
|
252
|
-
useNativeCSSStyleSheet = false;
|
|
253
|
-
CSSStyleSheet = class {
|
|
254
|
-
media = { mediaText: '' };
|
|
255
|
-
style = '';
|
|
256
|
-
replaceSync = (style: string) => (this.style = style);
|
|
257
|
-
} as any;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
223
|
/**
|
|
261
224
|
*
|
|
262
225
|
* 创建 style sheet 用于 `adoptedStyleSheets`,不支持样式更新
|
|
@@ -293,6 +256,8 @@ export function randomStr(number = 5, origin = '0123456789abcdefghijklmnopqrstuv
|
|
|
293
256
|
const nestingRuleRegExp = new RegExp('&.*{((.|\n)*)}', 'g');
|
|
294
257
|
// 只支持一层嵌套
|
|
295
258
|
// https://drafts.csswg.org/css-nesting-1/
|
|
259
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1648037
|
|
260
|
+
// https://bugs.webkit.org/show_bug.cgi?id=223497
|
|
296
261
|
function flatStyled(style: string, type: StyledType): StyledValueObject {
|
|
297
262
|
const nestingRules: string[] = [];
|
|
298
263
|
let styledContent =
|
|
@@ -404,6 +369,9 @@ export function classMap(object: Record<string, boolean>) {
|
|
|
404
369
|
|
|
405
370
|
export const partMap = classMap;
|
|
406
371
|
|
|
407
|
-
|
|
408
|
-
|
|
372
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/exportparts
|
|
373
|
+
export function exportPartsMap(object: Record<string, string | undefined | boolean>) {
|
|
374
|
+
return objectMapToString(object, ',', (key, value) =>
|
|
375
|
+
value === true || key === value ? key : value ? `${key}:${value}` : '',
|
|
376
|
+
);
|
|
409
377
|
}
|