@mantou/gem 1.7.1 → 1.7.2
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 +357 -362
- 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 +106 -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 +41 -69
- 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 +6 -21
- 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 +29 -58
- package/src/lib/history.ts +2 -1
- package/src/lib/utils.ts +10 -42
- package/src/lib/version.ts +1 -1
- package/src/test/history.test.ts +3 -1
- package/src/test/utils.test.ts +8 -1
|
@@ -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
|
);
|
|
@@ -320,20 +296,8 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
320
296
|
|
|
321
297
|
#render = () => {
|
|
322
298
|
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}`;
|
|
299
|
+
if (this.render) return this.render();
|
|
300
|
+
return this.#renderRoot === this ? undefined : html`<slot></slot>`;
|
|
337
301
|
};
|
|
338
302
|
|
|
339
303
|
/**@lifecycle */
|
|
@@ -392,15 +356,18 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
392
356
|
if (this.#isMounted) {
|
|
393
357
|
addMicrotask(this.#update);
|
|
394
358
|
}
|
|
359
|
+
return GemElement.#final;
|
|
395
360
|
}
|
|
396
361
|
|
|
397
362
|
#connectedCallback = () => {
|
|
398
|
-
// 似乎这是最早的判断不在 `constructor` 中的地方
|
|
399
|
-
(this as any)[constructorSymbol] = false;
|
|
400
363
|
if (this.#isAppendReason) {
|
|
401
364
|
this.#isAppendReason = false;
|
|
402
365
|
return;
|
|
403
366
|
}
|
|
367
|
+
|
|
368
|
+
// 似乎这是最早的判断不在 `constructor` 中的地方
|
|
369
|
+
Reflect.set(this, constructorSymbol, false);
|
|
370
|
+
|
|
404
371
|
this.willMount?.();
|
|
405
372
|
const { observedStores, rootElement } = this.constructor as typeof GemElement;
|
|
406
373
|
observedStores?.forEach((store) => {
|
|
@@ -447,13 +414,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
447
414
|
} else {
|
|
448
415
|
this.#connectedCallback();
|
|
449
416
|
}
|
|
417
|
+
return GemElement.#final;
|
|
450
418
|
}
|
|
451
419
|
|
|
452
420
|
/**
|
|
453
421
|
* @private
|
|
454
422
|
* @final
|
|
455
423
|
*/
|
|
456
|
-
|
|
424
|
+
adoptedCallback() {
|
|
425
|
+
return GemElement.#final;
|
|
426
|
+
}
|
|
457
427
|
|
|
458
428
|
/**
|
|
459
429
|
* @private
|
|
@@ -477,6 +447,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
477
447
|
});
|
|
478
448
|
this.#effectList = this.#effectList?.filter(({ inConstructor }) => inConstructor);
|
|
479
449
|
this.#memoList = this.#memoList?.filter(({ inConstructor }) => inConstructor);
|
|
450
|
+
return GemElement.#final;
|
|
480
451
|
}
|
|
481
452
|
}
|
|
482
453
|
|
|
@@ -503,7 +474,7 @@ export function defineAttribute(target: GemElement, prop: string, attr: string)
|
|
|
503
474
|
},
|
|
504
475
|
set(v: string | null | undefined | number | boolean) {
|
|
505
476
|
const that = this as GemElement;
|
|
506
|
-
const proxy = gemElementProxyMap.get(this)
|
|
477
|
+
const proxy = gemElementProxyMap.get(this);
|
|
507
478
|
const hasSet = proxy[prop];
|
|
508
479
|
const value = that.getAttribute(attr);
|
|
509
480
|
// https://github.com/whatwg/dom/issues/922
|
|
@@ -544,7 +515,7 @@ export function defineProperty(
|
|
|
544
515
|
},
|
|
545
516
|
set(v) {
|
|
546
517
|
const that = this as GemElement;
|
|
547
|
-
const proxy = gemElementProxyMap.get(that)
|
|
518
|
+
const proxy = gemElementProxyMap.get(that);
|
|
548
519
|
if (v !== proxy[prop]) {
|
|
549
520
|
if (event) {
|
|
550
521
|
proxy[prop] = v?.[isEventHandleSymbol]
|
|
@@ -554,7 +525,7 @@ export function defineProperty(
|
|
|
554
525
|
that.dispatchEvent(evt);
|
|
555
526
|
v(detail, options);
|
|
556
527
|
};
|
|
557
|
-
proxy[prop]
|
|
528
|
+
Reflect.set(proxy[prop]!, isEventHandleSymbol, true);
|
|
558
529
|
// emitter 不触发元素更新
|
|
559
530
|
} else {
|
|
560
531
|
proxy[prop] = v;
|
|
@@ -627,7 +598,7 @@ customElements.define = (name: string, cls: CustomElementConstructor, options?:
|
|
|
627
598
|
defineRefs?.forEach((ref) => defineRef(cls.prototype, kebabToCamelCase(ref), ref));
|
|
628
599
|
}
|
|
629
600
|
|
|
630
|
-
nativeDefineElement(name, cls
|
|
601
|
+
nativeDefineElement(name, cls, options);
|
|
631
602
|
};
|
|
632
603
|
|
|
633
604
|
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,
|
|
@@ -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
|
}
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.2';
|
package/src/test/history.test.ts
CHANGED
|
@@ -6,11 +6,13 @@ describe('history 测试', () => {
|
|
|
6
6
|
it('hash', async () => {
|
|
7
7
|
const historyLength = window.history.length;
|
|
8
8
|
const hash = window.location.hash;
|
|
9
|
+
// 等待浏览器就绪
|
|
10
|
+
await aTimeout(1000);
|
|
9
11
|
history.push({ path: '/a', hash: '#a' });
|
|
10
12
|
await aTimeout(10);
|
|
11
13
|
expect(window.location.hash).to.equal('#a');
|
|
12
14
|
history.back();
|
|
13
|
-
await aTimeout(
|
|
15
|
+
await aTimeout(10);
|
|
14
16
|
expect(window.location.hash).to.equal(hash);
|
|
15
17
|
history.push({ path: '/a', hash: '#b' });
|
|
16
18
|
await aTimeout(10);
|
package/src/test/utils.test.ts
CHANGED
|
@@ -14,6 +14,12 @@ import {
|
|
|
14
14
|
absoluteLocation,
|
|
15
15
|
} from '../lib/utils';
|
|
16
16
|
|
|
17
|
+
declare global {
|
|
18
|
+
interface CSSRuleList {
|
|
19
|
+
item(index: number): CSSStyleRule;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
describe('utils 测试', () => {
|
|
18
24
|
it('absoluteLocation', () => {
|
|
19
25
|
expect(absoluteLocation('/a', '/a/b')).to.equal('/a/b');
|
|
@@ -101,6 +107,7 @@ describe('utils 测试', () => {
|
|
|
101
107
|
`;--x:1px;font-size:14px;content:'*';`,
|
|
102
108
|
);
|
|
103
109
|
expect(classMap({ foo: true, content: false })).to.equal(` foo `);
|
|
104
|
-
expect(exportPartsMap({ foo: 'bar', content: 'content' })).to.equal(`,foo:bar,content
|
|
110
|
+
expect(exportPartsMap({ foo: 'bar', content: 'content', false: false })).to.equal(`,foo:bar,content,`);
|
|
111
|
+
expect(exportPartsMap({ foo: 'bar', content: true })).to.equal(`,foo:bar,content,`);
|
|
105
112
|
});
|
|
106
113
|
});
|