@mantou/gem 1.7.6 → 1.7.8
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 +65 -56
- package/dist/gem.umd.js +23 -23
- package/elements/base/gesture.d.ts.map +1 -1
- package/elements/base/gesture.js +1 -0
- package/elements/base/gesture.js.map +1 -1
- package/elements/base/modal-factory.d.ts +6 -17
- package/elements/base/modal-factory.d.ts.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 +15 -16
- package/elements/base/title.js.map +1 -1
- package/helper/theme.d.ts +3 -0
- package/helper/theme.d.ts.map +1 -1
- package/helper/theme.js +6 -0
- package/helper/theme.js.map +1 -1
- package/lib/element.d.ts +5 -3
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +23 -25
- package/lib/element.js.map +1 -1
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +18 -13
- package/lib/history.js.map +1 -1
- package/lib/store.d.ts +2 -9
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +7 -9
- package/lib/store.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/elements/base/gesture.ts +1 -0
- package/src/elements/base/title.ts +14 -11
- package/src/helper/theme.ts +7 -0
- package/src/lib/element.ts +21 -19
- package/src/lib/history.ts +18 -13
- package/src/lib/store.ts +7 -17
- package/src/lib/version.ts +1 -1
- package/src/test/gem-element/advance.test.ts +12 -1
- package/src/test/gem-element/decorators.test.ts +17 -21
- package/src/test/gem-element/multi.test.ts +8 -5
- package/src/test/store.test.ts +1 -3
package/lib/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/lib/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAE/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAAiC,CAAC;AAK7E,MAAM,UAAU,WAAW,CAAyB,WAAc;IAChE,IAAI,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACvC,CAAC;IACD,gBAAgB,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,EAAc,CAAC,CAAC;IACzD,OAAO,WAAuB,CAAC;AACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/lib/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAE/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAAiC,CAAC;AAK7E,MAAM,UAAU,WAAW,CAAyB,WAAc;IAChE,IAAI,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACvC,CAAC;IACD,gBAAgB,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,EAAc,CAAC,CAAC;IACzD,OAAO,WAAuB,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,WAAW,CAAyB,KAAe,EAAE,KAAkB;;IACrF,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5B,MAAA,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC5C,YAAY,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAyB,WAAc;IAC7D,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IACvC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAkB,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAU,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,OAAO,CAAyB,KAAe,EAAE,IAAgB;IAC/E,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACrB,OAAO,GAAG,EAAE,CAAC,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAyB,KAAe,EAAE,IAAgB;IAClF,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
package/lib/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.7.
|
|
1
|
+
export declare const version = "1.7.8";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/lib/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.8';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -75,6 +75,7 @@ export class GemGestureElement extends GemElement {
|
|
|
75
75
|
this.addEventListener('pointerdown', this.#onStart);
|
|
76
76
|
this.addEventListener('pointermove', this.#onMoveSet);
|
|
77
77
|
this.addEventListener('pointerup', this.#onEnd);
|
|
78
|
+
this.addEventListener('pointerleave', this.#onEnd); // 有时候 up 没有触发?
|
|
78
79
|
this.addEventListener('pointercancel', this.#onEnd);
|
|
79
80
|
this.addEventListener('dragstart', (evt) => evt.preventDefault());
|
|
80
81
|
}
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { GemElement, html } from '../../lib/element';
|
|
17
|
-
import { attribute,
|
|
17
|
+
import { attribute, boolattribute } from '../../lib/decorators';
|
|
18
18
|
import { updateStore, connect } from '../../lib/store';
|
|
19
19
|
import { titleStore } from '../../lib/history';
|
|
20
20
|
|
|
21
21
|
const defaultTitle = document.title;
|
|
22
22
|
|
|
23
|
-
function
|
|
23
|
+
function setDocumentTitle(str?: string | null, prefix = '', suffix = '') {
|
|
24
24
|
const title = titleStore.title || str;
|
|
25
25
|
if (title && title !== defaultTitle) {
|
|
26
26
|
GemTitleElement.title = title;
|
|
@@ -31,18 +31,20 @@ function updateTitle(str?: string | null, prefix = '', suffix = '') {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
connect(titleStore, setDocumentTitle);
|
|
35
|
+
|
|
34
36
|
export const PREFIX = `${defaultTitle} | `;
|
|
35
37
|
export const SUFFIX = ` - ${defaultTitle}`;
|
|
36
38
|
|
|
37
39
|
/**
|
|
38
|
-
*
|
|
40
|
+
* 映射到 `document.title`
|
|
39
41
|
* @attr prefix
|
|
40
42
|
* @attr suffix
|
|
41
43
|
*/
|
|
42
|
-
@connectStore(titleStore)
|
|
43
44
|
export class GemTitleElement extends GemElement {
|
|
44
45
|
@attribute prefix: string;
|
|
45
46
|
@attribute suffix: string;
|
|
47
|
+
@boolattribute inert: boolean;
|
|
46
48
|
|
|
47
49
|
// 没有后缀的当前标题
|
|
48
50
|
static title = document.title;
|
|
@@ -64,15 +66,16 @@ export class GemTitleElement extends GemElement {
|
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
mounted = () => {
|
|
70
|
+
this.effect(
|
|
71
|
+
() => !this.inert && connect(titleStore, this.update),
|
|
72
|
+
() => [this.inert],
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
67
76
|
render() {
|
|
68
77
|
// 多个 <gem-title> 时,最终 document.title 按执行顺序决定
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (this.hidden) {
|
|
72
|
-
return html``;
|
|
73
|
-
}
|
|
78
|
+
setDocumentTitle(this.textContent?.trim(), this.prefix, this.suffix);
|
|
74
79
|
return html`${GemTitleElement.title}`;
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
|
-
|
|
78
|
-
connect(titleStore, updateTitle);
|
package/src/helper/theme.ts
CHANGED
|
@@ -7,12 +7,14 @@ type SomeType<T> = {
|
|
|
7
7
|
|
|
8
8
|
const themeStoreMap = new WeakMap();
|
|
9
9
|
|
|
10
|
+
/**获取主题原始值 */
|
|
10
11
|
export function getThemeStore<T>(theme: SomeType<T>) {
|
|
11
12
|
return themeStoreMap.get(theme) as Store<T>;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const themePropsMap = new WeakMap();
|
|
15
16
|
|
|
17
|
+
/**获取 css 变量名 */
|
|
16
18
|
export function getThemeProps<T>(theme: SomeType<T>) {
|
|
17
19
|
return themePropsMap.get(theme) as SomeType<T>;
|
|
18
20
|
}
|
|
@@ -62,3 +64,8 @@ export function updateTheme<T = Record<string, unknown>>(theme: SomeType<T>, new
|
|
|
62
64
|
updateStore(getThemeStore(theme), newThemeObj);
|
|
63
65
|
setThemeFnMap.get(theme)();
|
|
64
66
|
}
|
|
67
|
+
|
|
68
|
+
export function useTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
69
|
+
const theme = createTheme(themeObj);
|
|
70
|
+
return [theme, (newThemeObj: Partial<T>) => updateTheme(theme, newThemeObj)] as const;
|
|
71
|
+
}
|
package/src/lib/element.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { html, render, TemplateResult } from 'lit-html';
|
|
|
2
2
|
|
|
3
3
|
import type { GemReflectElement } from '../elements/reflect';
|
|
4
4
|
|
|
5
|
-
import { connect,
|
|
5
|
+
import { connect, Store } from './store';
|
|
6
6
|
import {
|
|
7
7
|
LinkedList,
|
|
8
8
|
addMicrotask,
|
|
@@ -289,15 +289,19 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
289
289
|
|
|
290
290
|
/**
|
|
291
291
|
* @lifecycle
|
|
292
|
-
*
|
|
293
|
-
*
|
|
292
|
+
*
|
|
293
|
+
* - 不提供 `render` 时显示子内容
|
|
294
|
+
* - 返回 `null` 时渲染空内容
|
|
295
|
+
* - 返回 `undefined` 时不会调用 `render()`, 也就是不会更新以前的内容
|
|
294
296
|
* */
|
|
295
297
|
render?(): TemplateResult | null | undefined;
|
|
296
298
|
|
|
297
299
|
#render = () => {
|
|
298
300
|
this.#execMemo();
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
const isLight = this.#renderRoot === this;
|
|
302
|
+
const temp = this.render ? this.render() : isLight ? undefined : html`<slot></slot>`;
|
|
303
|
+
if (temp === undefined) return;
|
|
304
|
+
render(temp, this.#renderRoot);
|
|
301
305
|
};
|
|
302
306
|
|
|
303
307
|
/**@lifecycle */
|
|
@@ -311,8 +315,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
311
315
|
|
|
312
316
|
#updateCallback = () => {
|
|
313
317
|
if (this.#isMounted && this.#shouldUpdate()) {
|
|
314
|
-
|
|
315
|
-
temp !== undefined && render(temp, this.#renderRoot);
|
|
318
|
+
this.#render();
|
|
316
319
|
addMicrotask(this.#updated);
|
|
317
320
|
addMicrotask(this.#execEffect);
|
|
318
321
|
}
|
|
@@ -359,6 +362,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
359
362
|
return GemElement.#final;
|
|
360
363
|
}
|
|
361
364
|
|
|
365
|
+
#disconnectStore?: (() => void)[];
|
|
362
366
|
#connectedCallback = () => {
|
|
363
367
|
if (this.#isAppendReason) {
|
|
364
368
|
this.#isAppendReason = false;
|
|
@@ -370,15 +374,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
370
374
|
|
|
371
375
|
this.willMount?.();
|
|
372
376
|
const { observedStores, rootElement } = this.constructor as typeof GemElement;
|
|
373
|
-
observedStores?.
|
|
374
|
-
|
|
375
|
-
});
|
|
376
|
-
const temp = this.#render();
|
|
377
|
-
temp !== undefined && render(temp, this.#renderRoot);
|
|
377
|
+
this.#disconnectStore = observedStores?.map((store) => connect(store, this.#update));
|
|
378
|
+
this.#render();
|
|
378
379
|
this.#isMounted = true;
|
|
379
380
|
this.#unmountCallback = this.mounted?.();
|
|
380
381
|
this.#initEffect();
|
|
381
|
-
if (
|
|
382
|
+
if (
|
|
383
|
+
rootElement &&
|
|
384
|
+
this.isConnected &&
|
|
385
|
+
(this.getRootNode() as ShadowRoot).host?.tagName !== rootElement.toUpperCase()
|
|
386
|
+
) {
|
|
382
387
|
throw new GemError(`not allow current root type`);
|
|
383
388
|
}
|
|
384
389
|
};
|
|
@@ -406,10 +411,10 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
406
411
|
/**
|
|
407
412
|
* @private
|
|
408
413
|
* @final
|
|
409
|
-
* use `mounted`
|
|
414
|
+
* use `mounted`; 允许手动调用 `connectedCallback` 以清除装饰器定义的字段
|
|
410
415
|
*/
|
|
411
416
|
connectedCallback() {
|
|
412
|
-
if (this.#isAsync) {
|
|
417
|
+
if (this.isConnected && this.#isAsync) {
|
|
413
418
|
asyncRenderTaskList.add(this.#connectedCallback);
|
|
414
419
|
} else {
|
|
415
420
|
this.#connectedCallback();
|
|
@@ -436,10 +441,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
436
441
|
return;
|
|
437
442
|
}
|
|
438
443
|
this.#isMounted = false;
|
|
439
|
-
|
|
440
|
-
observedStores?.forEach((store) => {
|
|
441
|
-
disconnect(store, this.#update);
|
|
442
|
-
});
|
|
444
|
+
this.#disconnectStore?.forEach((disconnect) => disconnect());
|
|
443
445
|
execCallback(this.#unmountCallback);
|
|
444
446
|
this.unmounted?.();
|
|
445
447
|
this.#effectList?.forEach(({ preCallback }) => execCallback(preCallback));
|
package/src/lib/history.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// https://github.com/WICG/navigation-api#stakeholder-feedback
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { connect, useStore } from './store';
|
|
4
4
|
import { QueryString, cleanObject, GemError, absoluteLocation } from './utils';
|
|
5
5
|
|
|
6
6
|
const nativeHistory = window.history;
|
|
@@ -18,7 +18,7 @@ export interface HistoryState {
|
|
|
18
18
|
[index: string]: any;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const store =
|
|
21
|
+
const [store, updateHistoryStore] = useStore<HistoryState>({
|
|
22
22
|
$hasCloseHandle: false,
|
|
23
23
|
$hasOpenHandle: false,
|
|
24
24
|
$hasShouldCloseHandle: false,
|
|
@@ -85,10 +85,12 @@ function updateHistory(p: UpdateHistoryParams, native: typeof nativeHistory.push
|
|
|
85
85
|
$hasOpenHandle: !!open,
|
|
86
86
|
$hasShouldCloseHandle: !!shouldClose,
|
|
87
87
|
$key: getKey(),
|
|
88
|
+
$title: title,
|
|
88
89
|
...data,
|
|
89
90
|
};
|
|
90
91
|
paramsMap.set(state.$key, params);
|
|
91
|
-
|
|
92
|
+
cleanObject(store);
|
|
93
|
+
updateHistoryStore(state);
|
|
92
94
|
const url = getUrlBarPath(path) + new QueryString(query) + hash;
|
|
93
95
|
const prevHash = decodeURIComponent(location.hash);
|
|
94
96
|
native(state, title, url);
|
|
@@ -100,12 +102,14 @@ function updateHistoryByNative(data: any, title: string, originUrl: string, nati
|
|
|
100
102
|
validData(data);
|
|
101
103
|
const state = {
|
|
102
104
|
$key: getKey(),
|
|
105
|
+
$title: title,
|
|
103
106
|
...(data || {}),
|
|
104
107
|
};
|
|
105
108
|
const { pathname, search, hash } = new URL(originUrl, location.origin + location.pathname);
|
|
106
109
|
const params = normalizeParams({ path: pathname, query: new QueryString(search), hash, title, data });
|
|
107
110
|
paramsMap.set(state.$key, params);
|
|
108
|
-
|
|
111
|
+
cleanObject(store);
|
|
112
|
+
updateHistoryStore(state);
|
|
109
113
|
const url = getUrlBarPath(pathname) + params.query + hash;
|
|
110
114
|
const prevHash = location.hash;
|
|
111
115
|
native(state, title, url);
|
|
@@ -113,7 +117,7 @@ function updateHistoryByNative(data: any, title: string, originUrl: string, nati
|
|
|
113
117
|
if (prevHash !== hash) window.dispatchEvent(new CustomEvent('hashchange'));
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
const gemBasePathStore =
|
|
120
|
+
const [gemBasePathStore, updateBasePathStore] = useStore({
|
|
117
121
|
basePath: '',
|
|
118
122
|
});
|
|
119
123
|
|
|
@@ -126,7 +130,7 @@ class GemHistory {
|
|
|
126
130
|
}
|
|
127
131
|
set basePath(basePath: string) {
|
|
128
132
|
// 应用初始化的时候设置
|
|
129
|
-
|
|
133
|
+
updateBasePathStore({ basePath });
|
|
130
134
|
// paramsMap 更新后 ui 才会更新
|
|
131
135
|
Object.assign(paramsMap.get(store.$key)!, { path: getInternalPath(location.pathname) });
|
|
132
136
|
}
|
|
@@ -135,7 +139,7 @@ class GemHistory {
|
|
|
135
139
|
}
|
|
136
140
|
updateParams(params: UpdateHistoryParams) {
|
|
137
141
|
Object.assign(paramsMap.get(store.$key)!, params);
|
|
138
|
-
|
|
142
|
+
updateHistoryStore();
|
|
139
143
|
}
|
|
140
144
|
push(params: UpdateHistoryParams) {
|
|
141
145
|
updateHistory(params, nativePushState);
|
|
@@ -162,7 +166,7 @@ class GemHistory {
|
|
|
162
166
|
// `<gem-**>` 只读写父应用 `basePath`
|
|
163
167
|
const gemHistory = new GemHistory();
|
|
164
168
|
|
|
165
|
-
const gemTitleStore =
|
|
169
|
+
const [gemTitleStore, updateTitleStore] = useStore({ title: '' });
|
|
166
170
|
|
|
167
171
|
const _GEMHISTORY = { history: gemHistory, titleStore: gemTitleStore, basePathStore: gemBasePathStore };
|
|
168
172
|
|
|
@@ -195,7 +199,7 @@ if (!window._GEMHISTORY) {
|
|
|
195
199
|
const { pathname, search, hash } = location;
|
|
196
200
|
gemHistory.replace({ path: pathname, query: search, hash });
|
|
197
201
|
} else if (nativeHistory.state.$hasCloseHandle) {
|
|
198
|
-
|
|
202
|
+
updateHistoryStore(nativeHistory.state);
|
|
199
203
|
const params = normalizeParams({ title: document.title });
|
|
200
204
|
paramsMap.set(store.$key, params);
|
|
201
205
|
// 有 handle 返回键的页面刷新需要清除返回 handler
|
|
@@ -203,7 +207,7 @@ if (!window._GEMHISTORY) {
|
|
|
203
207
|
} else {
|
|
204
208
|
// 有 gem 历史的正常普通刷新, 储存 params
|
|
205
209
|
const params = normalizeParams({ title: document.title, hash: location.hash });
|
|
206
|
-
|
|
210
|
+
updateHistoryStore({
|
|
207
211
|
$key: getKey(),
|
|
208
212
|
...(nativeHistory.state || {}),
|
|
209
213
|
});
|
|
@@ -220,7 +224,7 @@ if (!window._GEMHISTORY) {
|
|
|
220
224
|
connect(store, () => {
|
|
221
225
|
const { title } = gemHistory.getParams();
|
|
222
226
|
if (title !== gemTitleStore.title) {
|
|
223
|
-
|
|
227
|
+
updateTitleStore({ title });
|
|
224
228
|
}
|
|
225
229
|
});
|
|
226
230
|
|
|
@@ -251,7 +255,7 @@ if (!window._GEMHISTORY) {
|
|
|
251
255
|
path: pathname,
|
|
252
256
|
query: new QueryString(search),
|
|
253
257
|
hash,
|
|
254
|
-
title:
|
|
258
|
+
title: newState.$title, // document.title 是导航前的
|
|
255
259
|
data: newState,
|
|
256
260
|
});
|
|
257
261
|
}
|
|
@@ -288,7 +292,8 @@ if (!window._GEMHISTORY) {
|
|
|
288
292
|
}
|
|
289
293
|
}
|
|
290
294
|
|
|
291
|
-
|
|
295
|
+
cleanObject(store);
|
|
296
|
+
updateHistoryStore(newState);
|
|
292
297
|
});
|
|
293
298
|
}
|
|
294
299
|
|
package/src/lib/store.ts
CHANGED
|
@@ -13,32 +13,22 @@ export function createStore<T extends NonPrimitive>(originStore: T) {
|
|
|
13
13
|
return originStore as Store<T>;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
interface StoreObjectSet {
|
|
17
|
-
[store: string]: NonPrimitive;
|
|
18
|
-
}
|
|
19
|
-
export type StoreSet<T> = {
|
|
20
|
-
[P in keyof T]: T[P] & Store<T[P]>;
|
|
21
|
-
};
|
|
22
|
-
export function createStoreSet<T extends StoreObjectSet>(originStoreSet: T) {
|
|
23
|
-
const keys = Object.keys(originStoreSet);
|
|
24
|
-
keys.forEach((key) => {
|
|
25
|
-
createStore(originStoreSet[key]);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return originStoreSet as StoreSet<T>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
16
|
export function updateStore<T extends NonPrimitive>(store: Store<T>, value?: Partial<T>) {
|
|
32
17
|
Object.assign(store, value);
|
|
33
|
-
|
|
34
|
-
listeners?.forEach((func) => {
|
|
18
|
+
StoreListenerMap.get(store)?.forEach((func) => {
|
|
35
19
|
addMicrotask(func);
|
|
36
20
|
});
|
|
37
21
|
}
|
|
38
22
|
|
|
23
|
+
export function useStore<T extends NonPrimitive>(originStore: T) {
|
|
24
|
+
const store = createStore(originStore);
|
|
25
|
+
return [store, (value?: Partial<T>) => updateStore(store, value)] as const;
|
|
26
|
+
}
|
|
27
|
+
|
|
39
28
|
export function connect<T extends NonPrimitive>(store: Store<T>, func: () => void) {
|
|
40
29
|
const listeners = StoreListenerMap.get(store);
|
|
41
30
|
listeners?.add(func);
|
|
31
|
+
return () => listeners?.delete(func);
|
|
42
32
|
}
|
|
43
33
|
|
|
44
34
|
export function disconnect<T extends NonPrimitive>(store: Store<T>, func: () => void) {
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.8';
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 测试 HTMLElement 没有的特性或者不常用的特性
|
|
3
|
+
* - 异步渲染
|
|
4
|
+
* - Light DOM 自定义元素
|
|
5
|
+
* - 生命周期以及 Effect/Memo
|
|
6
|
+
* - 派生元素(类扩展)
|
|
7
|
+
* - 无渲染内容 Gem 元素
|
|
8
|
+
*/
|
|
1
9
|
import { fixture, expect, nextFrame } from '@open-wc/testing';
|
|
2
10
|
|
|
3
11
|
import { GemElement, html } from '../../lib/element';
|
|
@@ -120,7 +128,10 @@ describe('gem element 生命周期', () => {
|
|
|
120
128
|
const el = container.firstElementChild as LifecycleGemElement;
|
|
121
129
|
expect(el.appTitle).to.equal('title');
|
|
122
130
|
expect(el.renderCount).to.equal(1);
|
|
123
|
-
|
|
131
|
+
const clone = el.cloneNode() as LifecycleGemElement;
|
|
132
|
+
// v2 BUG
|
|
133
|
+
clone.connectedCallback();
|
|
134
|
+
expect(clone.appTitle).to.equal('title');
|
|
124
135
|
|
|
125
136
|
const el2 = new LifecycleGemElement('', '2');
|
|
126
137
|
expect(el2.appTitle).to.equal('');
|
|
@@ -51,20 +51,24 @@ class DecoratorGemElement extends GemElement {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
@connectStore(store)
|
|
55
|
-
@adoptedStyle(styles)
|
|
56
|
-
@customElement('decorator-gem-demo2')
|
|
57
|
-
class DecoratorGemElement2 extends GemElement {
|
|
58
|
-
static observedStores = [];
|
|
59
|
-
static adoptedStyleSheets = [];
|
|
60
|
-
renderCount = 0;
|
|
61
|
-
render() {
|
|
62
|
-
this.renderCount++;
|
|
63
|
-
return html``;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
54
|
describe('装饰器', () => {
|
|
55
|
+
it('使用装饰器定义的未插入文档元素', async () => {
|
|
56
|
+
const el = new DecoratorGemElement();
|
|
57
|
+
expect(el.propData).to.eql({ value: '' });
|
|
58
|
+
expect(el.getAttribute('rank-attr')).to.equal(null);
|
|
59
|
+
// v2 BUG
|
|
60
|
+
expect(el.rankAttr).to.equal('');
|
|
61
|
+
el.connectedCallback();
|
|
62
|
+
expect(el.getAttribute('rank-attr')).to.equal(null);
|
|
63
|
+
expect(el.rankAttr).to.equal('');
|
|
64
|
+
|
|
65
|
+
el.rankAttr = 'attr';
|
|
66
|
+
el.propData = { value: '1' };
|
|
67
|
+
const el2 = el.cloneNode() as DecoratorGemElement;
|
|
68
|
+
expect(el2.getAttribute('rank-attr')).to.equal('attr');
|
|
69
|
+
expect(el2.rankAttr).to.equal('attr');
|
|
70
|
+
expect(el2.propData).to.eql({ value: '' });
|
|
71
|
+
});
|
|
68
72
|
it('装饰器定义的自定义元素', async () => {
|
|
69
73
|
let a = 1;
|
|
70
74
|
const el: DecoratorGemElement = await fixture(html`
|
|
@@ -104,12 +108,4 @@ describe('装饰器', () => {
|
|
|
104
108
|
expect(el.renderCount).to.equal(3);
|
|
105
109
|
expect(a).to.equal(2);
|
|
106
110
|
});
|
|
107
|
-
|
|
108
|
-
it('装饰器和静态属性共存', async () => {
|
|
109
|
-
const el: DecoratorGemElement2 = await fixture(html`<decorator-gem-demo2></decorator-gem-demo2>`);
|
|
110
|
-
updateStore(store, { a: 3 });
|
|
111
|
-
await Promise.resolve();
|
|
112
|
-
expect(el.renderCount).to.equal(2);
|
|
113
|
-
expect(el.shadowRoot?.adoptedStyleSheets.length).to.equal(1);
|
|
114
|
-
});
|
|
115
111
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { expect, fixture } from '@open-wc/testing';
|
|
2
2
|
|
|
3
|
-
import { customElement, property, RefObject, refobject } from '../../lib/decorators';
|
|
3
|
+
import { attribute, customElement, property, RefObject, refobject } from '../../lib/decorators';
|
|
4
4
|
import { GemElement, html } from '../../lib/element';
|
|
5
5
|
|
|
6
6
|
@customElement('app-children')
|
|
7
7
|
export class Children extends GemElement {
|
|
8
8
|
@refobject inputRef: RefObject<HTMLInputElement>;
|
|
9
9
|
@property value?: { value: number };
|
|
10
|
+
@attribute attr: string;
|
|
10
11
|
|
|
11
12
|
render() {
|
|
12
13
|
return html`<input ref=${this.inputRef.ref} />`;
|
|
@@ -19,13 +20,13 @@ export class App extends GemElement {
|
|
|
19
20
|
@refobject childrenRef2: RefObject<Children>;
|
|
20
21
|
render() {
|
|
21
22
|
return html`
|
|
22
|
-
<app-children ref=${this.childrenRef1.ref} .value=${{ value: 1 }}></app-children>
|
|
23
|
-
<app-children ref=${this.childrenRef2.ref} .value=${{ value: 2 }}></app-children>
|
|
23
|
+
<app-children ref=${this.childrenRef1.ref} .value=${{ value: 1 }} attr="1"></app-children>
|
|
24
|
+
<app-children ref=${this.childrenRef2.ref} .value=${{ value: 2 }} attr="2"></app-children>
|
|
24
25
|
`;
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
describe('多个 gem element', () => {
|
|
28
|
-
it('ref & prop', async () => {
|
|
28
|
+
describe('多个 gem element 一起工作', () => {
|
|
29
|
+
it('ref & prop & attr', async () => {
|
|
29
30
|
const el: App = await fixture(html`<app-root></app-root>`);
|
|
30
31
|
const children1 = el.childrenRef1.element!;
|
|
31
32
|
const children2 = el.childrenRef2.element!;
|
|
@@ -34,5 +35,7 @@ describe('多个 gem element', () => {
|
|
|
34
35
|
expect(input1 !== input2).to.equal(true);
|
|
35
36
|
expect(children1.value).to.eql({ value: 1 });
|
|
36
37
|
expect(children2.value).to.eql({ value: 2 });
|
|
38
|
+
expect(children1.attr).to.eql('1');
|
|
39
|
+
expect(children2.attr).to.eql('2');
|
|
37
40
|
});
|
|
38
41
|
});
|
package/src/test/store.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { expect, aTimeout } from '@open-wc/testing';
|
|
2
2
|
|
|
3
|
-
import { StoreListenerMap, createStore,
|
|
3
|
+
import { StoreListenerMap, createStore, updateStore, connect, disconnect } from '../lib/store';
|
|
4
4
|
|
|
5
5
|
describe('store 测试', () => {
|
|
6
6
|
it('create store', () => {
|
|
@@ -8,8 +8,6 @@ describe('store 测试', () => {
|
|
|
8
8
|
const store = createStore(origin);
|
|
9
9
|
expect(store).to.equal(origin);
|
|
10
10
|
expect(!!StoreListenerMap.get(store)).to.equal(true);
|
|
11
|
-
const stores = createStoreSet({ a: {} });
|
|
12
|
-
expect(!!StoreListenerMap.get(stores.a)).to.equal(true);
|
|
13
11
|
});
|
|
14
12
|
it('update store', async () => {
|
|
15
13
|
const store = createStore({ a: 1 });
|