@mantou/gem 1.7.12 → 2.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/gem.es.js +2010 -1765
- package/dist/gem.umd.js +52 -53
- package/elements/base/dialog.d.ts +0 -11
- package/elements/base/dialog.d.ts.map +1 -1
- package/elements/base/dialog.js +93 -66
- package/elements/base/dialog.js.map +1 -1
- package/elements/base/gesture.d.ts +1 -2
- package/elements/base/gesture.d.ts.map +1 -1
- package/elements/base/gesture.js +157 -96
- package/elements/base/gesture.js.map +1 -1
- package/elements/base/link.d.ts +5 -5
- package/elements/base/link.d.ts.map +1 -1
- package/elements/base/link.js +249 -145
- package/elements/base/link.js.map +1 -1
- package/elements/base/modal-factory.d.ts +145 -139
- package/elements/base/modal-factory.d.ts.map +1 -1
- package/elements/base/modal-factory.js +84 -25
- package/elements/base/modal-factory.js.map +1 -1
- package/elements/base/reflect.d.ts +0 -1
- package/elements/base/reflect.d.ts.map +1 -1
- package/elements/base/reflect.js +83 -38
- package/elements/base/reflect.js.map +1 -1
- package/elements/base/route.d.ts +12 -24
- package/elements/base/route.d.ts.map +1 -1
- package/elements/base/route.js +263 -164
- package/elements/base/route.js.map +1 -1
- package/elements/base/title.d.ts +3 -11
- package/elements/base/title.d.ts.map +1 -1
- package/elements/base/title.js +110 -59
- package/elements/base/title.js.map +1 -1
- package/elements/base/unsafe.d.ts +0 -1
- package/elements/base/unsafe.d.ts.map +1 -1
- package/elements/base/unsafe.js +82 -33
- package/elements/base/unsafe.js.map +1 -1
- package/elements/base/use.d.ts.map +1 -1
- package/elements/base/use.js +95 -47
- package/elements/base/use.js.map +1 -1
- package/helper/i18n.d.ts +4 -9
- package/helper/i18n.d.ts.map +1 -1
- package/helper/i18n.js +69 -65
- package/helper/i18n.js.map +1 -1
- package/helper/logger.js +10 -9
- package/helper/logger.js.map +1 -1
- package/helper/react-shim.d.ts +15 -0
- package/helper/react-shim.d.ts.map +1 -0
- package/helper/react-shim.js +56 -0
- package/helper/react-shim.js.map +1 -0
- package/helper/react-utils.d.ts +15 -0
- package/helper/react-utils.d.ts.map +1 -0
- package/helper/react-utils.js +50 -0
- package/helper/react-utils.js.map +1 -0
- package/helper/request.d.ts +4 -4
- package/helper/request.d.ts.map +1 -1
- package/helper/request.js +1 -1
- package/helper/request.js.map +1 -1
- package/helper/ssr-shim.d.ts.map +1 -1
- package/helper/ssr-shim.js +8 -1
- package/helper/ssr-shim.js.map +1 -1
- package/helper/theme.d.ts +14 -21
- package/helper/theme.d.ts.map +1 -1
- package/helper/theme.js +55 -38
- package/helper/theme.js.map +1 -1
- package/index.d.ts +4 -3
- package/index.d.ts.map +1 -1
- package/index.js +5 -3
- package/index.js.map +1 -1
- package/lib/decorators.d.ts +74 -42
- package/lib/decorators.d.ts.map +1 -1
- package/lib/decorators.js +324 -84
- package/lib/decorators.js.map +1 -1
- package/lib/directives.d.ts +4 -0
- package/lib/directives.d.ts.map +1 -0
- package/lib/directives.js +5 -0
- package/lib/directives.js.map +1 -0
- package/lib/element.d.ts +112 -110
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +431 -468
- package/lib/element.js.map +1 -1
- package/lib/history.d.ts +4 -0
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +12 -13
- package/lib/history.js.map +1 -1
- package/lib/store.d.ts +1 -1
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +4 -5
- package/lib/store.js.map +1 -1
- package/lib/utils.d.ts +3 -43
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +61 -235
- package/lib/utils.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.d.ts.map +1 -1
- package/lib/version.js +2 -1
- package/lib/version.js.map +1 -1
- package/package.json +13 -11
- package/src/dist.ts +3 -2
- package/src/elements/base/dialog.ts +10 -20
- package/src/elements/base/gesture.ts +16 -14
- package/src/elements/base/link.ts +65 -44
- package/src/elements/base/modal-factory.ts +14 -14
- package/src/elements/base/reflect.ts +24 -32
- package/src/elements/base/route.ts +55 -68
- package/src/elements/base/title.ts +25 -42
- package/src/elements/base/unsafe.ts +12 -21
- package/src/elements/base/use.ts +17 -13
- package/src/helper/i18n.ts +20 -14
- package/src/helper/react-utils.ts +66 -0
- package/src/helper/ssr-shim.ts +8 -1
- package/src/helper/theme.ts +72 -45
- package/src/index.ts +6 -4
- package/src/lib/decorators.ts +394 -93
- package/src/lib/directives.ts +6 -0
- package/src/lib/element.ts +473 -500
- package/src/lib/history.ts +4 -3
- package/src/lib/store.ts +2 -1
- package/src/lib/utils.ts +12 -191
- package/src/lib/version.ts +2 -1
- package/src/test/elements/link.test.ts +1 -1
- package/src/test/elements/title.test.ts +1 -0
- package/src/test/gem-element/advance.test.ts +72 -49
- package/src/test/gem-element/basic.test.ts +37 -50
- package/src/test/gem-element/decorators.test.ts +22 -21
- package/src/test/gem-element/multi.test.ts +5 -5
- package/src/test/utils.test.ts +15 -45
package/src/lib/history.ts
CHANGED
|
@@ -183,7 +183,7 @@ class GemHistory extends EventTarget {
|
|
|
183
183
|
// `<gem-**>` 只读写父应用 `basePath`
|
|
184
184
|
const gemHistory = new GemHistory();
|
|
185
185
|
|
|
186
|
-
const [gemTitleStore, updateTitleStore] = useStore({ title: '' });
|
|
186
|
+
const [gemTitleStore, updateTitleStore] = useStore({ defaultTitle: document.title, url: '', title: '' });
|
|
187
187
|
|
|
188
188
|
const _GEMHISTORY = { history: gemHistory, titleStore: gemTitleStore, basePathStore: gemBasePathStore };
|
|
189
189
|
|
|
@@ -213,8 +213,9 @@ if (!window._GEMHISTORY) {
|
|
|
213
213
|
|
|
214
214
|
if (!nativeHistory.state) {
|
|
215
215
|
// 初始化 historyState
|
|
216
|
-
const { pathname, search, hash } = location;
|
|
217
|
-
|
|
216
|
+
const { protocol, pathname, search, hash } = location;
|
|
217
|
+
// 支持在 `data:` `blob:` 中 `import`
|
|
218
|
+
if (protocol.startsWith('http')) gemHistory.replace({ path: pathname, query: search, hash });
|
|
218
219
|
} else if (nativeHistory.state.$hasCloseHandle) {
|
|
219
220
|
updateHistoryStore(nativeHistory.state);
|
|
220
221
|
const params = normalizeParams({ title: document.title });
|
package/src/lib/store.ts
CHANGED
package/src/lib/utils.ts
CHANGED
|
@@ -1,37 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
let microtaskSet = new Set<() => void>();
|
|
2
2
|
export function addMicrotask(func: () => void) {
|
|
3
3
|
if (typeof func !== 'function') return;
|
|
4
4
|
if (!microtaskSet.size) {
|
|
5
5
|
// delayed execution callback after updating store
|
|
6
6
|
globalThis.queueMicrotask(() => {
|
|
7
|
-
|
|
8
|
-
microtaskSet
|
|
7
|
+
const set = microtaskSet;
|
|
8
|
+
microtaskSet = new Set();
|
|
9
|
+
set.forEach((f) => f());
|
|
9
10
|
});
|
|
10
11
|
}
|
|
11
12
|
microtaskSet.delete(func);
|
|
12
13
|
microtaskSet.add(func);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
const microtaskStack: (() => void)[] = [];
|
|
16
|
-
|
|
17
|
-
function execMicrotaskStack() {
|
|
18
|
-
for (let i = microtaskStack.length - 1; i >= 0; i--) {
|
|
19
|
-
microtaskStack[i]();
|
|
20
|
-
}
|
|
21
|
-
microtaskStack.length = 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 添加回调函数到微任务队列栈;
|
|
26
|
-
* 先进后执行,使用这个函数可以改变嵌套的元素 `mounted` 的顺序;
|
|
27
|
-
*/
|
|
28
|
-
export function addMicrotaskToStack(func: () => void) {
|
|
29
|
-
if (!microtaskStack.length) {
|
|
30
|
-
addMicrotask(execMicrotaskStack);
|
|
31
|
-
}
|
|
32
|
-
microtaskStack.push(func);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
16
|
// 不编码 hash 用于比较
|
|
36
17
|
export function absoluteLocation(currentPath = '', relativePath = '') {
|
|
37
18
|
const { pathname, search, hash } = new URL(relativePath, location.origin + currentPath);
|
|
@@ -235,60 +216,12 @@ export function raw(arr: TemplateStringsArray, ...args: any[]) {
|
|
|
235
216
|
}
|
|
236
217
|
|
|
237
218
|
// 写 css 文本,在 CSSStyleSheet 中使用
|
|
238
|
-
export
|
|
239
|
-
return raw(arr, ...args);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// 跨多个 gem 工作
|
|
243
|
-
export const SheetToken = Symbol.for('gem@sheetToken');
|
|
244
|
-
|
|
245
|
-
export type Sheet<T> = {
|
|
246
|
-
[P in keyof T]: P;
|
|
247
|
-
} & { [SheetToken]: CSSStyleSheet };
|
|
248
|
-
|
|
249
|
-
export type StyledType = 'id' | 'class' | 'keyframes';
|
|
250
|
-
export interface StyledValueObject {
|
|
251
|
-
styledContent: string;
|
|
252
|
-
type: StyledType;
|
|
253
|
-
}
|
|
254
|
-
export interface StyledKeyValuePair {
|
|
255
|
-
[key: string]: StyledValueObject;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
*
|
|
260
|
-
* 创建 style sheet 用于 `adoptedStyleSheets`,不支持样式更新,只支持自定义 CSS 属性
|
|
261
|
-
* @param rules string | Record<string, string>
|
|
262
|
-
* @param media string 媒体查询
|
|
263
|
-
*/
|
|
264
|
-
export function createCSSSheet<T extends StyledKeyValuePair>(rules: T | string, media?: string): Sheet<T> {
|
|
265
|
-
const styleSheet = new CSSStyleSheet({ media });
|
|
266
|
-
const sheet: any = {};
|
|
267
|
-
let style = '';
|
|
268
|
-
if (typeof rules === 'string') {
|
|
269
|
-
style = rules;
|
|
270
|
-
} else {
|
|
271
|
-
Object.keys(rules).forEach((key: keyof T) => {
|
|
272
|
-
sheet[key] = `${key as string}-${randomStr()}`;
|
|
273
|
-
switch (rules[key].type) {
|
|
274
|
-
case 'class':
|
|
275
|
-
style += `.${sheet[key]} {${rules[key].styledContent}}`;
|
|
276
|
-
break;
|
|
277
|
-
case 'id':
|
|
278
|
-
style += `#${sheet[key]} {${rules[key].styledContent}}`;
|
|
279
|
-
break;
|
|
280
|
-
default:
|
|
281
|
-
style += `@keyframes ${key as string} {${rules[key].styledContent}}`;
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
styleSheet.replaceSync(style);
|
|
286
|
-
sheet[SheetToken] = styleSheet;
|
|
287
|
-
return sheet as Sheet<T>;
|
|
288
|
-
}
|
|
219
|
+
export const css = raw;
|
|
289
220
|
|
|
290
221
|
export function randomStr(len = 5): string {
|
|
291
|
-
const str = Math.random()
|
|
222
|
+
const str = Math.random()
|
|
223
|
+
.toString(36)
|
|
224
|
+
.slice(2, 2 + len);
|
|
292
225
|
if (str.length < len) return str + randomStr(len - str.length);
|
|
293
226
|
return str;
|
|
294
227
|
}
|
|
@@ -303,17 +236,7 @@ export function randomStr(len = 5): string {
|
|
|
303
236
|
// }
|
|
304
237
|
// `,
|
|
305
238
|
// });
|
|
306
|
-
export const styled = {
|
|
307
|
-
class: (arr: TemplateStringsArray, ...args: any[]): StyledValueObject => {
|
|
308
|
-
return { styledContent: raw(arr, ...args), type: 'class' };
|
|
309
|
-
},
|
|
310
|
-
id: (arr: TemplateStringsArray, ...args: any[]): StyledValueObject => {
|
|
311
|
-
return { styledContent: raw(arr, ...args), type: 'id' };
|
|
312
|
-
},
|
|
313
|
-
keyframes: (arr: TemplateStringsArray, ...args: any[]): StyledValueObject => {
|
|
314
|
-
return { styledContent: raw(arr, ...args), type: 'keyframes' };
|
|
315
|
-
},
|
|
316
|
-
};
|
|
239
|
+
export const styled = { class: raw };
|
|
317
240
|
|
|
318
241
|
export function camelToKebabCase(str: string) {
|
|
319
242
|
return str.replace(/[A-Z]/g, ($1: string) => '-' + $1.toLowerCase());
|
|
@@ -324,9 +247,8 @@ export function kebabToCamelCase(str: string) {
|
|
|
324
247
|
}
|
|
325
248
|
|
|
326
249
|
export function cleanObject<T extends Record<string, unknown>>(o: T) {
|
|
327
|
-
Object.keys(o).forEach((key:
|
|
328
|
-
|
|
329
|
-
delete o[k];
|
|
250
|
+
Object.keys(o).forEach((key: keyof T) => {
|
|
251
|
+
delete o[key];
|
|
330
252
|
});
|
|
331
253
|
return o;
|
|
332
254
|
}
|
|
@@ -347,17 +269,6 @@ export function isArrayChange(newValues: any[], oldValues: any[]) {
|
|
|
347
269
|
return false;
|
|
348
270
|
}
|
|
349
271
|
|
|
350
|
-
export function removeItems(target: any[], items: any[]) {
|
|
351
|
-
const set = new Set(items);
|
|
352
|
-
return target.filter((e) => {
|
|
353
|
-
if (set.has(e)) {
|
|
354
|
-
set.delete(e);
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
return true;
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
|
|
361
272
|
export function objectMapToString<T = any>(
|
|
362
273
|
object: Record<string, T>,
|
|
363
274
|
separate: string,
|
|
@@ -377,6 +288,7 @@ type StyleProp =
|
|
|
377
288
|
| `--${string}`
|
|
378
289
|
| 'scrollbarWidth'
|
|
379
290
|
| 'scrollbarColor'
|
|
291
|
+
| 'positionAnchor'
|
|
380
292
|
| 'anchorDefault'
|
|
381
293
|
| 'anchorName';
|
|
382
294
|
|
|
@@ -406,94 +318,3 @@ declare global {
|
|
|
406
318
|
interface PropertyIndexedKeyframes extends StyleObject {}
|
|
407
319
|
interface Keyframe extends StyleObject {}
|
|
408
320
|
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* @example
|
|
412
|
-
* ```css
|
|
413
|
-
* animation: 150ms ease 0ms showMask;`
|
|
414
|
-
* @keyframes showMask {
|
|
415
|
-
* from {
|
|
416
|
-
* opacity: 0;
|
|
417
|
-
* }
|
|
418
|
-
* }
|
|
419
|
-
* ```
|
|
420
|
-
*/
|
|
421
|
-
// export function createCSSAnimation(
|
|
422
|
-
// keyframes: PropertyIndexedKeyframes | Keyframe[],
|
|
423
|
-
// options?: number | (KeyframeEffectOptions & { name: string }),
|
|
424
|
-
// ) {
|
|
425
|
-
// const frames = new Map<number, StyleObject>();
|
|
426
|
-
// if (Array.isArray(keyframes)) {
|
|
427
|
-
// keyframes.forEach((keyframe, index) => {
|
|
428
|
-
// const offset = keyframes.length === 1 ? 1 : keyframe.offset || index / (keyframes.length - 1);
|
|
429
|
-
// frames.set(offset, {
|
|
430
|
-
// ...keyframe,
|
|
431
|
-
// // https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Keyframe_Formats#attributes
|
|
432
|
-
// cssOffset: undefined,
|
|
433
|
-
// offset: keyframe.cssOffset,
|
|
434
|
-
// composite: undefined,
|
|
435
|
-
// animationComposition: keyframe.composite,
|
|
436
|
-
// easing: undefined,
|
|
437
|
-
// animationTimingFunction: keyframe.easing,
|
|
438
|
-
// } as StyleObject);
|
|
439
|
-
// });
|
|
440
|
-
// } else {
|
|
441
|
-
// const offsetList: (number | null)[] = Array.isArray(keyframes.offset)
|
|
442
|
-
// ? keyframes.offset
|
|
443
|
-
// : keyframes.offset === undefined
|
|
444
|
-
// ? []
|
|
445
|
-
// : [keyframes.offset];
|
|
446
|
-
// if (offsetList.length && offsetList.at(-1) !== 1) offsetList.push(1);
|
|
447
|
-
|
|
448
|
-
// const setStyle = (offset: number, key: string, value: string | number | null | undefined) => {
|
|
449
|
-
// const style = frames.get(offset) || {};
|
|
450
|
-
// switch (key) {
|
|
451
|
-
// case 'offset':
|
|
452
|
-
// break;
|
|
453
|
-
// case 'cssOffset':
|
|
454
|
-
// Reflect.set(style, 'offset', value);
|
|
455
|
-
// break;
|
|
456
|
-
// case 'composite':
|
|
457
|
-
// Reflect.set(style, 'animationComposition', value);
|
|
458
|
-
// break;
|
|
459
|
-
// case 'easing':
|
|
460
|
-
// Reflect.set(style, 'animationTimingFunction', value);
|
|
461
|
-
// break;
|
|
462
|
-
// default:
|
|
463
|
-
// Reflect.set(style, key, value);
|
|
464
|
-
// }
|
|
465
|
-
// frames.set(offset, style);
|
|
466
|
-
// };
|
|
467
|
-
// for (const key in keyframes) {
|
|
468
|
-
// const framesValue = keyframes[key];
|
|
469
|
-
// !Array.isArray(framesValue)
|
|
470
|
-
// ? setStyle(1, key, framesValue)
|
|
471
|
-
// : framesValue.length === 1
|
|
472
|
-
// ? setStyle(1, key, framesValue[0])
|
|
473
|
-
// : framesValue.forEach((value, index) =>
|
|
474
|
-
// setStyle(offsetList[index] ?? index / (framesValue.length - 1), key, value),
|
|
475
|
-
// );
|
|
476
|
-
// }
|
|
477
|
-
// }
|
|
478
|
-
|
|
479
|
-
// let framesStr = '';
|
|
480
|
-
// frames.forEach((rules, offset) => {
|
|
481
|
-
// framesStr += `${(offset * 100).toFixed()}%{${styleMap(rules)}}`;
|
|
482
|
-
// });
|
|
483
|
-
|
|
484
|
-
// if (options) {
|
|
485
|
-
// const {
|
|
486
|
-
// // 只能使用 ms 数字
|
|
487
|
-
// duration = 0,
|
|
488
|
-
// easing = '',
|
|
489
|
-
// delay = 0,
|
|
490
|
-
// iterations = 1,
|
|
491
|
-
// direction = '',
|
|
492
|
-
// fill = '',
|
|
493
|
-
// name = `ani-${randomStr()}`,
|
|
494
|
-
// } = typeof options === 'number' ? ({ duration: options } as Exclude<typeof options, number>) : options;
|
|
495
|
-
// return `${duration}ms ${easing} ${delay}ms ${iterations} ${direction} ${fill} ${name};@keyframes ${name}{${framesStr}}`;
|
|
496
|
-
// }
|
|
497
|
-
|
|
498
|
-
// return framesStr;
|
|
499
|
-
// }
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
// Do not modify manually
|
|
2
|
+
export const version = '0.0.0';
|
|
@@ -5,7 +5,7 @@ import type { GemActiveLinkElement } from '../../elements/link';
|
|
|
5
5
|
|
|
6
6
|
import '../../elements/link';
|
|
7
7
|
|
|
8
|
-
describe('
|
|
8
|
+
describe('GemLinkElement', () => {
|
|
9
9
|
it('basic', async () => {
|
|
10
10
|
const ele: GemActiveLinkElement = await fixture(
|
|
11
11
|
html`<gem-active-link pattern="/*" href="/#测试">active-link</gem-active-link>`,
|
|
@@ -8,6 +8,7 @@ import '../../elements/title';
|
|
|
8
8
|
describe('GemTitleElement', () => {
|
|
9
9
|
it('basic', async () => {
|
|
10
10
|
const ele: GemTitleElement = await fixture(html`<gem-title>title</gem-title>`);
|
|
11
|
+
await nextFrame();
|
|
11
12
|
expect(document.title).to.equal('title');
|
|
12
13
|
ele.textContent = 'title2';
|
|
13
14
|
await nextFrame();
|
|
@@ -8,35 +8,45 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { fixture, expect, nextFrame } from '@open-wc/testing';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import type { Metadata } from '../../lib/element';
|
|
12
|
+
import { createCSSSheet, createState, GemElement, html, createRef } from '../../lib/element';
|
|
12
13
|
import { createStore, updateStore } from '../../lib/store';
|
|
13
|
-
import {
|
|
14
|
-
|
|
14
|
+
import {
|
|
15
|
+
attribute,
|
|
16
|
+
property,
|
|
17
|
+
customElement,
|
|
18
|
+
emitter,
|
|
19
|
+
adoptedStyle,
|
|
20
|
+
connectStore,
|
|
21
|
+
async,
|
|
22
|
+
shadow,
|
|
23
|
+
mounted,
|
|
24
|
+
} from '../../lib/decorators';
|
|
25
|
+
import { css } from '../../lib/utils';
|
|
15
26
|
|
|
16
27
|
const store = createStore({
|
|
17
28
|
a: 1,
|
|
18
29
|
});
|
|
19
30
|
|
|
31
|
+
@connectStore(store)
|
|
32
|
+
@async()
|
|
33
|
+
@shadow()
|
|
34
|
+
@customElement('async-gem-demo')
|
|
20
35
|
class AsyncGemDemo extends GemElement {
|
|
21
|
-
|
|
22
|
-
constructor() {
|
|
23
|
-
super({ isAsync: true });
|
|
24
|
-
}
|
|
25
|
-
state = { a: 0 };
|
|
36
|
+
#state = createState({ a: 0 });
|
|
26
37
|
renderCount = 0;
|
|
27
38
|
render() {
|
|
28
39
|
this.renderCount++;
|
|
29
40
|
return null;
|
|
30
41
|
}
|
|
31
42
|
}
|
|
32
|
-
customElements.define('async-gem-demo', AsyncGemDemo);
|
|
33
43
|
|
|
34
44
|
describe('异步 gem element 测试', () => {
|
|
35
45
|
it('异步 gem element 更新', async () => {
|
|
36
46
|
const el: AsyncGemDemo = await fixture(html`<async-gem-demo></async-gem-demo>`);
|
|
37
47
|
expect(el.renderCount).to.equal(1);
|
|
38
48
|
updateStore(store, { a: ++store.a });
|
|
39
|
-
el.
|
|
49
|
+
el.internals.stateList[0]({ a: ++(el.internals.stateList[0] as any).a });
|
|
40
50
|
await nextFrame();
|
|
41
51
|
expect(el.renderCount).to.equal(2);
|
|
42
52
|
await nextFrame();
|
|
@@ -45,7 +55,7 @@ describe('异步 gem element 测试', () => {
|
|
|
45
55
|
});
|
|
46
56
|
|
|
47
57
|
const lightStyle = createCSSSheet(css`
|
|
48
|
-
|
|
58
|
+
div {
|
|
49
59
|
font-size: 18.1px;
|
|
50
60
|
}
|
|
51
61
|
`);
|
|
@@ -53,37 +63,41 @@ const lightStyle = createCSSSheet(css`
|
|
|
53
63
|
@customElement('light-gem-demo')
|
|
54
64
|
@adoptedStyle(lightStyle)
|
|
55
65
|
class LightGemDemo extends GemElement {
|
|
56
|
-
constructor() {
|
|
57
|
-
super({ isLight: true });
|
|
58
|
-
}
|
|
59
66
|
render() {
|
|
60
67
|
return html`<div>hi</div>`;
|
|
61
68
|
}
|
|
62
69
|
}
|
|
63
70
|
describe('没有 Shadow DOM 的 gem 元素', () => {
|
|
64
71
|
it('渲染没有 Shadow DOM 的 gem 元素', async () => {
|
|
72
|
+
const el0: LightGemDemo = await fixture(html`<div></div>`);
|
|
65
73
|
const el1: LightGemDemo = await fixture(html`<light-gem-demo></light-gem-demo>`);
|
|
66
74
|
const el2: LightGemDemo = await fixture(html`<light-gem-demo></light-gem-demo>`);
|
|
67
75
|
expect(el1.shadowRoot).to.equal(null);
|
|
68
76
|
expect(el1.innerHTML.includes('hi')).to.equal(true);
|
|
69
|
-
expect(getComputedStyle(
|
|
77
|
+
expect(getComputedStyle(el0).fontSize).not.to.equal('18.1px');
|
|
78
|
+
expect(getComputedStyle(el2.firstElementChild!).fontSize).to.equal('18.1px');
|
|
70
79
|
el1.remove();
|
|
71
|
-
|
|
80
|
+
await Promise.resolve();
|
|
81
|
+
expect(getComputedStyle(el2.firstElementChild!).fontSize).to.equal('18.1px');
|
|
72
82
|
el2.remove();
|
|
73
|
-
|
|
83
|
+
// 样式在队列末尾执行
|
|
84
|
+
await Promise.resolve();
|
|
85
|
+
expect(getComputedStyle(el0).fontSize).not.to.equal('18.1px');
|
|
74
86
|
});
|
|
75
87
|
});
|
|
76
88
|
|
|
77
89
|
class LifecycleGemElement extends GemElement {
|
|
78
90
|
@attribute appTitle = 'default';
|
|
79
91
|
@attribute appTitle2 = 'default2';
|
|
80
|
-
@refobject divRef: RefObject<HTMLElement>;
|
|
81
92
|
refInConstructor?: HTMLElement;
|
|
82
93
|
|
|
94
|
+
divRef = createRef<HTMLDivElement>();
|
|
95
|
+
|
|
83
96
|
constructor(appTitle: string, appTitle2: string) {
|
|
84
97
|
super();
|
|
85
|
-
|
|
86
|
-
this.
|
|
98
|
+
// 字段优先执行于构造函数
|
|
99
|
+
this.appTitle = appTitle ?? this.appTitle;
|
|
100
|
+
this.appTitle2 = appTitle2 ?? this.appTitle2;
|
|
87
101
|
this.effect(
|
|
88
102
|
() => {
|
|
89
103
|
this.refInConstructor = this.divRef.element;
|
|
@@ -93,18 +107,14 @@ class LifecycleGemElement extends GemElement {
|
|
|
93
107
|
}
|
|
94
108
|
renderCount = 0;
|
|
95
109
|
mountedCount = 0;
|
|
96
|
-
updatedCount = 0;
|
|
97
|
-
|
|
98
|
-
updated() {
|
|
99
|
-
this.updatedCount++;
|
|
100
|
-
}
|
|
101
110
|
|
|
102
|
-
mounted()
|
|
111
|
+
@mounted()
|
|
112
|
+
#init = () => {
|
|
103
113
|
this.mountedCount++;
|
|
104
114
|
return () => {
|
|
105
115
|
this.renderCount = 0;
|
|
106
116
|
};
|
|
107
|
-
}
|
|
117
|
+
};
|
|
108
118
|
|
|
109
119
|
render() {
|
|
110
120
|
this.renderCount++;
|
|
@@ -116,6 +126,7 @@ describe('gem element 生命周期', () => {
|
|
|
116
126
|
const el: LifecycleGemElement = await fixture(html`<lifecycle-gem-demo></lifecycle-gem-demo>`);
|
|
117
127
|
// test #isMounted
|
|
118
128
|
customElements.define('lifecycle-gem-demo', LifecycleGemElement);
|
|
129
|
+
await Promise.resolve();
|
|
119
130
|
expect(!!el.refInConstructor).to.equal(true);
|
|
120
131
|
expect(el.renderCount).to.equal(1);
|
|
121
132
|
el.remove();
|
|
@@ -129,8 +140,6 @@ describe('gem element 生命周期', () => {
|
|
|
129
140
|
expect(el.appTitle).to.equal('title');
|
|
130
141
|
expect(el.renderCount).to.equal(1);
|
|
131
142
|
const clone = el.cloneNode() as LifecycleGemElement;
|
|
132
|
-
// v2 BUG
|
|
133
|
-
clone.connectedCallback();
|
|
134
143
|
expect(clone.appTitle).to.equal('title');
|
|
135
144
|
|
|
136
145
|
const el2 = new LifecycleGemElement('', '2');
|
|
@@ -142,20 +151,20 @@ describe('gem element 生命周期', () => {
|
|
|
142
151
|
|
|
143
152
|
// disconnectedCallback, connectedCallback
|
|
144
153
|
container.append(el2);
|
|
154
|
+
await Promise.resolve();
|
|
145
155
|
expect(el2.mountedCount).to.equal(1);
|
|
146
156
|
expect(el2.renderCount).to.equal(1);
|
|
147
157
|
el2.remove();
|
|
148
158
|
expect(el2.mountedCount).to.equal(1);
|
|
149
159
|
expect(el2.renderCount).to.equal(0);
|
|
150
160
|
container.append(el2);
|
|
161
|
+
await Promise.resolve();
|
|
151
162
|
expect(el2.mountedCount).to.equal(2);
|
|
152
163
|
expect(el2.renderCount).to.equal(1);
|
|
153
|
-
expect(el2.updatedCount).to.equal(0);
|
|
154
164
|
el2.update();
|
|
155
165
|
el2.update();
|
|
156
166
|
await Promise.resolve();
|
|
157
167
|
expect(el2.renderCount).to.equal(2);
|
|
158
|
-
expect(el2.updatedCount).to.equal(1);
|
|
159
168
|
|
|
160
169
|
const el3 = new LifecycleGemElement('test1', 'test2');
|
|
161
170
|
expect(el3.appTitle).to.equal('test1');
|
|
@@ -166,6 +175,7 @@ describe('gem element 生命周期', () => {
|
|
|
166
175
|
});
|
|
167
176
|
});
|
|
168
177
|
|
|
178
|
+
@customElement('effect-gem-demo')
|
|
169
179
|
class EffectGemDemo extends GemElement {
|
|
170
180
|
@attribute attr = 'a';
|
|
171
181
|
@property prop = {};
|
|
@@ -186,7 +196,8 @@ class EffectGemDemo extends GemElement {
|
|
|
186
196
|
},
|
|
187
197
|
);
|
|
188
198
|
}
|
|
189
|
-
mounted()
|
|
199
|
+
@mounted()
|
|
200
|
+
#mounted = () => {
|
|
190
201
|
this.effect(
|
|
191
202
|
(_arr) => {
|
|
192
203
|
this.effectCallCount++;
|
|
@@ -197,9 +208,8 @@ class EffectGemDemo extends GemElement {
|
|
|
197
208
|
this.effect(() => {
|
|
198
209
|
this.effectCallCount++;
|
|
199
210
|
});
|
|
200
|
-
}
|
|
211
|
+
};
|
|
201
212
|
}
|
|
202
|
-
customElements.define('effect-gem-demo', EffectGemDemo);
|
|
203
213
|
describe('gem element 副作用', () => {
|
|
204
214
|
it('依赖当前值', async () => {
|
|
205
215
|
const el: EffectGemDemo = await fixture(html`<effect-gem-demo></effect-gem-demo>`);
|
|
@@ -230,57 +240,58 @@ describe('gem element 副作用', () => {
|
|
|
230
240
|
expect(el.effectCallCount).to.equal(0);
|
|
231
241
|
expect(el.hasConstructorEffect).to.equal(false);
|
|
232
242
|
document.body.append(el);
|
|
243
|
+
await Promise.resolve();
|
|
233
244
|
expect(el.hasConstructorEffect).to.equal(true);
|
|
234
245
|
});
|
|
235
246
|
});
|
|
236
247
|
|
|
248
|
+
@customElement('memo-gem-demo')
|
|
237
249
|
class MemoGemDemo extends GemElement {
|
|
238
250
|
@attribute attr = 'a';
|
|
239
251
|
@property prop = {};
|
|
240
|
-
|
|
252
|
+
memoNum = 0;
|
|
241
253
|
constructor() {
|
|
242
254
|
super();
|
|
243
255
|
this.memo(
|
|
244
|
-
() => (this.
|
|
256
|
+
() => (this.memoNum += 1),
|
|
245
257
|
() => [this.attr, this.prop],
|
|
246
258
|
);
|
|
247
|
-
}
|
|
248
|
-
willMount() {
|
|
249
259
|
this.memo(
|
|
250
260
|
(_arr) => {
|
|
251
|
-
this.
|
|
261
|
+
this.memoNum += 2;
|
|
252
262
|
},
|
|
253
263
|
() => [],
|
|
254
264
|
);
|
|
255
265
|
this.memo(() => {
|
|
256
|
-
this.
|
|
266
|
+
this.memoNum += 4;
|
|
257
267
|
});
|
|
258
268
|
}
|
|
259
269
|
}
|
|
260
|
-
customElements.define('memo-gem-demo', MemoGemDemo);
|
|
261
270
|
describe('gem element Memo', () => {
|
|
262
271
|
it('依赖当前值', async () => {
|
|
263
272
|
const el: MemoGemDemo = await fixture(html`<memo-gem-demo></memo-gem-demo>`);
|
|
264
|
-
expect(el.
|
|
273
|
+
expect(el.memoNum).to.equal(7);
|
|
265
274
|
el.attr = 'b';
|
|
266
275
|
el.prop = {};
|
|
267
276
|
await nextFrame();
|
|
268
|
-
expect(el.
|
|
277
|
+
expect(el.memoNum).to.equal(12);
|
|
269
278
|
|
|
270
279
|
el.update();
|
|
271
280
|
await Promise.resolve();
|
|
272
|
-
expect(el.
|
|
281
|
+
expect(el.memoNum).to.equal(16);
|
|
273
282
|
|
|
274
283
|
document.body.append(el);
|
|
275
|
-
expect(el.
|
|
284
|
+
expect(el.memoNum).to.equal(16);
|
|
276
285
|
|
|
277
286
|
el.remove();
|
|
278
287
|
await Promise.resolve();
|
|
279
288
|
document.body.append(el);
|
|
280
|
-
expect(el.
|
|
289
|
+
expect(el.memoNum).to.equal(23);
|
|
281
290
|
});
|
|
282
291
|
});
|
|
283
292
|
|
|
293
|
+
@customElement('i-gem')
|
|
294
|
+
@shadow()
|
|
284
295
|
class I extends GemElement {
|
|
285
296
|
@attribute appTitle = 'string';
|
|
286
297
|
@property appData = { a: 1 };
|
|
@@ -295,13 +306,24 @@ class InheritGem extends I {
|
|
|
295
306
|
}
|
|
296
307
|
describe('gem element 继承', () => {
|
|
297
308
|
it('静态字段继承', async () => {
|
|
298
|
-
|
|
299
|
-
|
|
309
|
+
new I();
|
|
310
|
+
new InheritGem(); // 触发装饰器自定义初始化函数
|
|
311
|
+
const metadata: Metadata = Reflect.get(InheritGem, Symbol.metadata);
|
|
312
|
+
expect(metadata.observedAttributes).to.eql(['app-title', 'app-title2']);
|
|
300
313
|
});
|
|
301
314
|
it('attr/prop/emitter 继承', async () => {
|
|
302
315
|
const name = window.name;
|
|
303
316
|
const el: InheritGem = await fixture(html`<inherit-gem></inherit-gem>`);
|
|
304
|
-
|
|
317
|
+
/**
|
|
318
|
+
* NOTE: 默认值不能覆盖,可以在 `constructor` 中重新定义默认值
|
|
319
|
+
*
|
|
320
|
+
* 原因:
|
|
321
|
+
*
|
|
322
|
+
* 1. 执行装饰器时必须保留之前设置的 prop 值,所以 prop 的字段默认值不能覆盖,统一 attr 和 prop 的行为
|
|
323
|
+
* 2. 很难区分是基类中设置的 attr 还是模版中指定的 attr
|
|
324
|
+
*/
|
|
325
|
+
expect(el.appTitle).to.equal('string');
|
|
326
|
+
expect(el.appTitle2).to.equal('2');
|
|
305
327
|
expect(el.appData.a).to.equal(1);
|
|
306
328
|
el.appTitle = 'b';
|
|
307
329
|
el.appData = { a: 2 };
|
|
@@ -315,6 +337,7 @@ describe('gem element 继承', () => {
|
|
|
315
337
|
});
|
|
316
338
|
});
|
|
317
339
|
@customElement('render-empty')
|
|
340
|
+
@shadow()
|
|
318
341
|
class RenderEmpty extends GemElement {
|
|
319
342
|
render() {
|
|
320
343
|
return undefined;
|