@mantou/gem 1.7.7 → 1.7.9
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 +239 -107
- package/dist/gem.umd.js +24 -24
- package/elements/base/dialog.d.ts.map +1 -1
- package/elements/base/dialog.js +1 -1
- package/elements/base/dialog.js.map +1 -1
- 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/link.d.ts.map +1 -1
- package/elements/base/link.js +8 -4
- package/elements/base/link.js.map +1 -1
- package/elements/base/modal-factory.d.ts +13 -3
- package/elements/base/modal-factory.d.ts.map +1 -1
- package/elements/base/reflect.d.ts +8 -0
- package/elements/base/reflect.d.ts.map +1 -1
- package/elements/base/reflect.js +36 -9
- package/elements/base/reflect.js.map +1 -1
- package/elements/base/route.d.ts +25 -10
- package/elements/base/route.d.ts.map +1 -1
- package/elements/base/route.js +90 -56
- package/elements/base/route.js.map +1 -1
- package/elements/base/title.d.ts.map +1 -1
- package/elements/base/title.js +8 -2
- package/elements/base/title.js.map +1 -1
- package/helper/i18n.d.ts +8 -1
- package/helper/i18n.d.ts.map +1 -1
- package/helper/i18n.js +6 -2
- package/helper/i18n.js.map +1 -1
- package/helper/logger.d.ts +9 -0
- package/helper/logger.d.ts.map +1 -0
- package/helper/logger.js +16 -0
- package/helper/logger.js.map +1 -0
- package/helper/ssr-shim.d.ts.map +1 -1
- package/helper/ssr-shim.js +12 -4
- package/helper/ssr-shim.js.map +1 -1
- package/lib/element.d.ts +9 -7
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +47 -21
- package/lib/element.js.map +1 -1
- package/lib/history.d.ts +3 -2
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +22 -9
- package/lib/history.js.map +1 -1
- package/lib/utils.d.ts +2 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +10 -8
- package/lib/utils.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/dialog.ts +4 -1
- package/src/elements/base/gesture.ts +1 -0
- package/src/elements/base/link.ts +8 -4
- package/src/elements/base/reflect.ts +43 -9
- package/src/elements/base/route.ts +102 -51
- package/src/elements/base/title.ts +9 -2
- package/src/helper/i18n.ts +11 -3
- package/src/helper/logger.ts +21 -0
- package/src/helper/ssr-shim.ts +14 -4
- package/src/lib/element.ts +57 -26
- package/src/lib/history.ts +30 -12
- package/src/lib/utils.ts +16 -9
- package/src/lib/version.ts +1 -1
- package/src/test/elements/link.test.ts +15 -0
- package/src/test/elements/reflect.test.ts +27 -0
- package/src/test/elements/title.test.ts +25 -0
- package/src/test/gem-element/advance.test.ts +1 -1
- package/src/test/gem-element/decorators.test.ts +2 -2
- package/src/test/utils.test.ts +14 -0
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,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
kebabToCamelCase,
|
|
14
14
|
PropProxyMap,
|
|
15
15
|
removeItems,
|
|
16
|
+
addListener,
|
|
16
17
|
} from './utils';
|
|
17
18
|
import * as GemExports from './element';
|
|
18
19
|
import * as VersionExports from './version';
|
|
@@ -75,12 +76,10 @@ const constructorSymbol = Symbol('constructor');
|
|
|
75
76
|
const initSymbol = Symbol('init');
|
|
76
77
|
const updateSymbol = Symbol('update');
|
|
77
78
|
|
|
78
|
-
export interface GemElementOptions {
|
|
79
|
+
export interface GemElementOptions extends Partial<ShadowRootInit> {
|
|
79
80
|
isLight?: boolean;
|
|
80
81
|
isAsync?: boolean;
|
|
81
|
-
|
|
82
|
-
delegatesFocus?: boolean;
|
|
83
|
-
slotAssignment?: 'named' | 'manual';
|
|
82
|
+
focusable?: boolean;
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
export abstract class GemElement<T = Record<string, unknown>> extends HTMLElement {
|
|
@@ -117,7 +116,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
117
116
|
#memoList?: EffectItem<any>[];
|
|
118
117
|
#unmountCallback?: any;
|
|
119
118
|
|
|
120
|
-
constructor(
|
|
119
|
+
constructor(options: GemElementOptions = {}) {
|
|
121
120
|
super();
|
|
122
121
|
|
|
123
122
|
// 外部不可见,但允许类外面使用
|
|
@@ -130,8 +129,37 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
130
129
|
}
|
|
131
130
|
});
|
|
132
131
|
|
|
133
|
-
this.#isAsync = isAsync;
|
|
134
|
-
this.#renderRoot = isLight
|
|
132
|
+
this.#isAsync = options.isAsync;
|
|
133
|
+
this.#renderRoot = options.isLight
|
|
134
|
+
? this
|
|
135
|
+
: this.attachShadow({
|
|
136
|
+
mode: options.mode || 'open',
|
|
137
|
+
delegatesFocus: options.delegatesFocus,
|
|
138
|
+
slotAssignment: options.slotAssignment,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// https://stackoverflow.com/questions/43836886/failed-to-construct-customelement-error-when-javascript-file-is-placed-in-head
|
|
142
|
+
// focusable 元素一般同时具备 disabled 属性
|
|
143
|
+
// 和原生元素行为保持一致,disabled 时不触发 click 事件
|
|
144
|
+
let hasInitTabIndex: boolean | undefined;
|
|
145
|
+
this.effect(
|
|
146
|
+
([disabled = false]) => {
|
|
147
|
+
if (hasInitTabIndex === undefined) hasInitTabIndex = this.hasAttribute('tabindex');
|
|
148
|
+
|
|
149
|
+
this.internals.ariaDisabled = String(disabled);
|
|
150
|
+
|
|
151
|
+
if (options.focusable && !hasInitTabIndex) {
|
|
152
|
+
this.tabIndex = -Number(disabled);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if ((options.focusable || options.delegatesFocus) && disabled) {
|
|
156
|
+
return addListener(this, 'click', (e: Event) => e.isTrusted && e.stopImmediatePropagation(), {
|
|
157
|
+
capture: true,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
() => [Reflect.get(this, 'disabled')],
|
|
162
|
+
);
|
|
135
163
|
|
|
136
164
|
const { adoptedStyleSheets } = new.target;
|
|
137
165
|
if (adoptedStyleSheets) {
|
|
@@ -248,7 +276,8 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
248
276
|
|
|
249
277
|
/**
|
|
250
278
|
* @helper
|
|
251
|
-
* 在 `render`
|
|
279
|
+
* 在 `render` 前执行回调,不要在里面使用 `setState`
|
|
280
|
+
* 和 `effect` 一样接受依赖数组参数,在 `constructor`/`willMount` 中使用;
|
|
252
281
|
* 第一次执行时 `oldDeps` 为空
|
|
253
282
|
*
|
|
254
283
|
* ```js
|
|
@@ -289,15 +318,19 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
289
318
|
|
|
290
319
|
/**
|
|
291
320
|
* @lifecycle
|
|
292
|
-
*
|
|
293
|
-
*
|
|
321
|
+
*
|
|
322
|
+
* - 不提供 `render` 时显示子内容
|
|
323
|
+
* - 返回 `null` 时渲染空内容
|
|
324
|
+
* - 返回 `undefined` 时不会调用 `render()`, 也就是不会更新以前的内容
|
|
294
325
|
* */
|
|
295
326
|
render?(): TemplateResult | null | undefined;
|
|
296
327
|
|
|
297
328
|
#render = () => {
|
|
298
329
|
this.#execMemo();
|
|
299
|
-
|
|
300
|
-
|
|
330
|
+
const isLight = this.#renderRoot === this;
|
|
331
|
+
const temp = this.render ? this.render() : isLight ? undefined : html`<slot></slot>`;
|
|
332
|
+
if (temp === undefined) return;
|
|
333
|
+
render(temp, this.#renderRoot);
|
|
301
334
|
};
|
|
302
335
|
|
|
303
336
|
/**@lifecycle */
|
|
@@ -311,8 +344,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
311
344
|
|
|
312
345
|
#updateCallback = () => {
|
|
313
346
|
if (this.#isMounted && this.#shouldUpdate()) {
|
|
314
|
-
|
|
315
|
-
temp !== undefined && render(temp, this.#renderRoot);
|
|
347
|
+
this.#render();
|
|
316
348
|
addMicrotask(this.#updated);
|
|
317
349
|
addMicrotask(this.#execEffect);
|
|
318
350
|
}
|
|
@@ -372,8 +404,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
372
404
|
this.willMount?.();
|
|
373
405
|
const { observedStores, rootElement } = this.constructor as typeof GemElement;
|
|
374
406
|
this.#disconnectStore = observedStores?.map((store) => connect(store, this.#update));
|
|
375
|
-
|
|
376
|
-
temp !== undefined && render(temp, this.#renderRoot);
|
|
407
|
+
this.#render();
|
|
377
408
|
this.#isMounted = true;
|
|
378
409
|
this.#unmountCallback = this.mounted?.();
|
|
379
410
|
this.#initEffect();
|
|
@@ -442,15 +473,17 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
442
473
|
this.#disconnectStore?.forEach((disconnect) => disconnect());
|
|
443
474
|
execCallback(this.#unmountCallback);
|
|
444
475
|
this.unmounted?.();
|
|
445
|
-
this.#effectList
|
|
446
|
-
this.#
|
|
447
|
-
this.#memoList = this.#memoList?.filter(this.#filterEffect);
|
|
476
|
+
this.#effectList = this.#clearEffect(this.#effectList);
|
|
477
|
+
this.#memoList = this.#clearEffect(this.#memoList);
|
|
448
478
|
return GemElement.#final;
|
|
449
479
|
}
|
|
450
480
|
|
|
451
|
-
#
|
|
452
|
-
e
|
|
453
|
-
|
|
481
|
+
#clearEffect = (list?: EffectItem<any>[]) => {
|
|
482
|
+
return list?.filter((e) => {
|
|
483
|
+
execCallback(e.preCallback);
|
|
484
|
+
e.initialized = false;
|
|
485
|
+
return e.inConstructor;
|
|
486
|
+
});
|
|
454
487
|
};
|
|
455
488
|
}
|
|
456
489
|
|
|
@@ -553,9 +586,7 @@ export function defineRef(target: GemElement, prop: string, ref: string) {
|
|
|
553
586
|
return ref;
|
|
554
587
|
},
|
|
555
588
|
get element() {
|
|
556
|
-
const gemReflects =
|
|
557
|
-
(e) => e.target,
|
|
558
|
-
);
|
|
589
|
+
const gemReflects = [...ele.querySelectorAll<GemReflectElement>('[data-gem-reflect]')].map((e) => e.target);
|
|
559
590
|
for (const e of [ele, ...gemReflects]) {
|
|
560
591
|
const result = e.querySelector(`[ref=${ref}]`);
|
|
561
592
|
if (result) return result;
|
package/src/lib/history.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface UpdateHistoryParams {
|
|
|
29
29
|
title?: string;
|
|
30
30
|
path?: string; // 不包括 basePath,只有根目录储存末尾斜杠
|
|
31
31
|
query?: string | QueryString; // 包含 `?`
|
|
32
|
-
hash?: string; // 包含
|
|
32
|
+
hash?: string; // 包含 `#`,不进行编码,方便比较
|
|
33
33
|
// 以下为看不见的状态
|
|
34
34
|
open?: () => void; // 按下前进键时执行
|
|
35
35
|
close?: () => void; // 按下返回键时执行
|
|
@@ -38,7 +38,12 @@ export interface UpdateHistoryParams {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// 实际应用值
|
|
41
|
-
type HistoryParams = UpdateHistoryParams & {
|
|
41
|
+
type HistoryParams = Omit<UpdateHistoryParams, 'query'> & {
|
|
42
|
+
title: string;
|
|
43
|
+
path: string;
|
|
44
|
+
query: QueryString;
|
|
45
|
+
hash: string;
|
|
46
|
+
};
|
|
42
47
|
|
|
43
48
|
const paramsMap = new Map<string, HistoryParams>();
|
|
44
49
|
|
|
@@ -60,19 +65,26 @@ function getInternalPath(urlBarPath: string) {
|
|
|
60
65
|
return urlBarPath.replace(new RegExp(`^${gemHistory.basePath}/`), '/');
|
|
61
66
|
}
|
|
62
67
|
|
|
68
|
+
function dispatchBeforeChangeEvent() {
|
|
69
|
+
gemHistory.dispatchEvent(new CustomEvent('beforechange'));
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
function normalizeParams(params: UpdateHistoryParams): HistoryParams {
|
|
64
|
-
const current =
|
|
73
|
+
const current =
|
|
74
|
+
paramsMap.get(store.$key) ||
|
|
75
|
+
({ path: getInternalPath(location.pathname), query: new QueryString() } as HistoryParams);
|
|
65
76
|
// 没提供 path 使用当前 path
|
|
66
77
|
const path = params.path ? absoluteLocation(current.path, params.path) : getInternalPath(location.pathname);
|
|
67
78
|
// 没提供 query 又没有提供 path 时使用当前 search
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
79
|
+
const newQueryObject = new QueryString(params.query ?? (params.path ? '' : location.search));
|
|
80
|
+
const queryChanged = String(newQueryObject) !== String(current.query);
|
|
81
|
+
const query = queryChanged ? newQueryObject : current.query;
|
|
82
|
+
const urlChanged = path !== current.path || queryChanged;
|
|
71
83
|
// 没提供 title 又没有改变 URL 时使用当前 document.title
|
|
72
|
-
const title = params.title || (
|
|
84
|
+
const title = params.title || (urlChanged ? '' : document.title);
|
|
73
85
|
const statusChanged = params.close || params.data || params.open || params.shouldClose;
|
|
74
|
-
// 没提供 hash 又没有改变 URL
|
|
75
|
-
const hash = params.hash
|
|
86
|
+
// 没提供 hash 又没有改变 URL 仅仅是状态更新时使用当前 hash
|
|
87
|
+
const hash = decodeURIComponent(params.hash ?? (!urlChanged && statusChanged ? location.hash : ''));
|
|
76
88
|
return { ...params, title, path, query, hash };
|
|
77
89
|
}
|
|
78
90
|
|
|
@@ -89,6 +101,7 @@ function updateHistory(p: UpdateHistoryParams, native: typeof nativeHistory.push
|
|
|
89
101
|
...data,
|
|
90
102
|
};
|
|
91
103
|
paramsMap.set(state.$key, params);
|
|
104
|
+
dispatchBeforeChangeEvent();
|
|
92
105
|
cleanObject(store);
|
|
93
106
|
updateHistoryStore(state);
|
|
94
107
|
const url = getUrlBarPath(path) + new QueryString(query) + hash;
|
|
@@ -108,6 +121,7 @@ function updateHistoryByNative(data: any, title: string, originUrl: string, nati
|
|
|
108
121
|
const { pathname, search, hash } = new URL(originUrl, location.origin + location.pathname);
|
|
109
122
|
const params = normalizeParams({ path: pathname, query: new QueryString(search), hash, title, data });
|
|
110
123
|
paramsMap.set(state.$key, params);
|
|
124
|
+
dispatchBeforeChangeEvent();
|
|
111
125
|
cleanObject(store);
|
|
112
126
|
updateHistoryStore(state);
|
|
113
127
|
const url = getUrlBarPath(pathname) + params.query + hash;
|
|
@@ -121,10 +135,13 @@ const [gemBasePathStore, updateBasePathStore] = useStore({
|
|
|
121
135
|
basePath: '',
|
|
122
136
|
});
|
|
123
137
|
|
|
124
|
-
class GemHistory {
|
|
138
|
+
class GemHistory extends EventTarget {
|
|
125
139
|
get store() {
|
|
126
140
|
return store;
|
|
127
141
|
}
|
|
142
|
+
get currentKey() {
|
|
143
|
+
return store.$key;
|
|
144
|
+
}
|
|
128
145
|
get basePath() {
|
|
129
146
|
return gemBasePathStore.basePath;
|
|
130
147
|
}
|
|
@@ -190,7 +207,7 @@ if (!window._GEMHISTORY) {
|
|
|
190
207
|
// 点击 `<a>`
|
|
191
208
|
window.addEventListener('hashchange', ({ isTrusted }) => {
|
|
192
209
|
if (isTrusted) {
|
|
193
|
-
gemHistory.replace({ hash:
|
|
210
|
+
gemHistory.replace({ hash: location.hash });
|
|
194
211
|
}
|
|
195
212
|
});
|
|
196
213
|
|
|
@@ -254,7 +271,7 @@ if (!window._GEMHISTORY) {
|
|
|
254
271
|
paramsMap.set(newState.$key, {
|
|
255
272
|
path: pathname,
|
|
256
273
|
query: new QueryString(search),
|
|
257
|
-
hash,
|
|
274
|
+
hash: decodeURIComponent(hash),
|
|
258
275
|
title: newState.$title, // document.title 是导航前的
|
|
259
276
|
data: newState,
|
|
260
277
|
});
|
|
@@ -292,6 +309,7 @@ if (!window._GEMHISTORY) {
|
|
|
292
309
|
}
|
|
293
310
|
}
|
|
294
311
|
|
|
312
|
+
dispatchBeforeChangeEvent();
|
|
295
313
|
cleanObject(store);
|
|
296
314
|
updateHistoryStore(newState);
|
|
297
315
|
});
|
package/src/lib/utils.ts
CHANGED
|
@@ -32,14 +32,24 @@ export function addMicrotaskToStack(func: () => void) {
|
|
|
32
32
|
microtaskStack.push(func);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// 不编码 hash 用于比较
|
|
35
36
|
export function absoluteLocation(currentPath = '', relativePath = '') {
|
|
36
37
|
const { pathname, search, hash } = new URL(relativePath, location.origin + currentPath);
|
|
37
|
-
return pathname + search + hash;
|
|
38
|
+
return pathname + search + decodeURIComponent(hash);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
41
41
|
export type NonPrimitive = object;
|
|
42
42
|
|
|
43
|
+
export function addListener<T extends EventTarget, A extends Parameters<T['addEventListener']>>(
|
|
44
|
+
target: T,
|
|
45
|
+
type: A[0],
|
|
46
|
+
listener: A[1],
|
|
47
|
+
options?: A[2],
|
|
48
|
+
) {
|
|
49
|
+
target.addEventListener(type, listener, options);
|
|
50
|
+
return () => target.removeEventListener(type, listener, options);
|
|
51
|
+
}
|
|
52
|
+
|
|
43
53
|
interface LinkedListEventMap {
|
|
44
54
|
start: Event;
|
|
45
55
|
end: Event;
|
|
@@ -49,7 +59,7 @@ export interface LinkedListItem<T> {
|
|
|
49
59
|
prev?: LinkedListItem<T>;
|
|
50
60
|
next?: LinkedListItem<T>;
|
|
51
61
|
}
|
|
52
|
-
|
|
62
|
+
|
|
53
63
|
export class LinkedList<T = any> extends EventTarget {
|
|
54
64
|
declare addEventListener: <K extends keyof LinkedListEventMap>(
|
|
55
65
|
type: K,
|
|
@@ -269,12 +279,9 @@ export function createCSSSheet<T extends StyledKeyValuePair>(rules: T | string,
|
|
|
269
279
|
return sheet as Sheet<T>;
|
|
270
280
|
}
|
|
271
281
|
|
|
272
|
-
export function randomStr(
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
for (let i = 0; i < number; i++) {
|
|
276
|
-
str += origin[Math.floor(Math.random() * len)];
|
|
277
|
-
}
|
|
282
|
+
export function randomStr(len = 5): string {
|
|
283
|
+
const str = Math.random().toString(36).slice(2).slice(0, len);
|
|
284
|
+
if (str.length < len) return str + randomStr(len - str.length);
|
|
278
285
|
return str;
|
|
279
286
|
}
|
|
280
287
|
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.9';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { fixture, expect } from '@open-wc/testing';
|
|
2
|
+
|
|
3
|
+
import { html } from '../../lib/element';
|
|
4
|
+
import type { GemActiveLinkElement } from '../../elements/link';
|
|
5
|
+
|
|
6
|
+
import '../../elements/link';
|
|
7
|
+
|
|
8
|
+
describe('GemTitleElement', () => {
|
|
9
|
+
it('basic', async () => {
|
|
10
|
+
const ele: GemActiveLinkElement = await fixture(
|
|
11
|
+
html`<gem-active-link pattern="/*" href="/#测试">active-link</gem-active-link>`,
|
|
12
|
+
);
|
|
13
|
+
expect(ele.active).to.equal(true);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { fixture, expect, nextFrame } from '@open-wc/testing';
|
|
2
|
+
|
|
3
|
+
import { html } from '../../lib/element';
|
|
4
|
+
import type { GemReflectElement } from '../../elements/reflect';
|
|
5
|
+
|
|
6
|
+
import '../../elements/reflect';
|
|
7
|
+
|
|
8
|
+
describe('GemReflectElement', () => {
|
|
9
|
+
it('basic', async () => {
|
|
10
|
+
const reflect: GemReflectElement = await fixture(html`
|
|
11
|
+
<gem-reflect>
|
|
12
|
+
<div id="one"></div>
|
|
13
|
+
<div id="two"></div>
|
|
14
|
+
</gem-reflect>
|
|
15
|
+
`);
|
|
16
|
+
const div = document.head.querySelector('#one');
|
|
17
|
+
expect(!!div).to.equal(true);
|
|
18
|
+
const comment = new Comment();
|
|
19
|
+
div?.after(comment);
|
|
20
|
+
reflect.target = document.body;
|
|
21
|
+
await nextFrame();
|
|
22
|
+
expect(document.body.querySelector('#one')).to.equal(div);
|
|
23
|
+
expect(div?.nextSibling).to.equal(comment);
|
|
24
|
+
reflect.remove();
|
|
25
|
+
expect(!!document.querySelector('#one')).to.equal(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { fixture, expect, nextFrame } from '@open-wc/testing';
|
|
2
|
+
|
|
3
|
+
import { html } from '../../lib/element';
|
|
4
|
+
import type { GemTitleElement } from '../../elements/title';
|
|
5
|
+
|
|
6
|
+
import '../../elements/title';
|
|
7
|
+
|
|
8
|
+
describe('GemTitleElement', () => {
|
|
9
|
+
it('basic', async () => {
|
|
10
|
+
const ele: GemTitleElement = await fixture(html`<gem-title>title</gem-title>`);
|
|
11
|
+
expect(document.title).to.equal('title');
|
|
12
|
+
ele.textContent = 'title2';
|
|
13
|
+
await nextFrame();
|
|
14
|
+
expect(document.title).to.equal('title2');
|
|
15
|
+
|
|
16
|
+
ele.prefix = 'prefix-';
|
|
17
|
+
await nextFrame();
|
|
18
|
+
expect(document.title).to.equal('prefix-title2');
|
|
19
|
+
|
|
20
|
+
history.pushState(null, 'Page', '/');
|
|
21
|
+
await nextFrame();
|
|
22
|
+
expect(document.title).to.equal('prefix-Page');
|
|
23
|
+
expect(ele.shadowRoot!.textContent).to.equal('Page');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -129,7 +129,7 @@ describe('gem element 生命周期', () => {
|
|
|
129
129
|
expect(el.appTitle).to.equal('title');
|
|
130
130
|
expect(el.renderCount).to.equal(1);
|
|
131
131
|
const clone = el.cloneNode() as LifecycleGemElement;
|
|
132
|
-
// BUG
|
|
132
|
+
// v2 BUG
|
|
133
133
|
clone.connectedCallback();
|
|
134
134
|
expect(clone.appTitle).to.equal('title');
|
|
135
135
|
|
|
@@ -56,8 +56,8 @@ describe('装饰器', () => {
|
|
|
56
56
|
const el = new DecoratorGemElement();
|
|
57
57
|
expect(el.propData).to.eql({ value: '' });
|
|
58
58
|
expect(el.getAttribute('rank-attr')).to.equal(null);
|
|
59
|
-
// BUG
|
|
60
|
-
expect(el.rankAttr).to.equal(
|
|
59
|
+
// v2 BUG
|
|
60
|
+
expect(el.rankAttr).to.equal('');
|
|
61
61
|
el.connectedCallback();
|
|
62
62
|
expect(el.getAttribute('rank-attr')).to.equal(null);
|
|
63
63
|
expect(el.rankAttr).to.equal('');
|
package/src/test/utils.test.ts
CHANGED
|
@@ -25,6 +25,8 @@ describe('utils 测试', () => {
|
|
|
25
25
|
expect(absoluteLocation('/a', '/a/b')).to.equal('/a/b');
|
|
26
26
|
expect(absoluteLocation('/a/c', './b')).to.equal('/a/b');
|
|
27
27
|
expect(absoluteLocation('/a/c/d', '../b')).to.equal('/a/b');
|
|
28
|
+
expect(absoluteLocation('/a/c/d', '../b?a=a#a')).to.equal('/a/b?a=a#a');
|
|
29
|
+
expect(absoluteLocation('/a/c/d', '../b?a=测试#测试#')).to.equal('/a/b?a=%E6%B5%8B%E8%AF%95#测试#');
|
|
28
30
|
});
|
|
29
31
|
it('LinkedList', () => {
|
|
30
32
|
const linkedList = new LinkedList<() => void>();
|
|
@@ -36,6 +38,18 @@ describe('utils 测试', () => {
|
|
|
36
38
|
const fun2 = () => 2;
|
|
37
39
|
linkedList.add(fun1);
|
|
38
40
|
linkedList.add(fun2);
|
|
41
|
+
expect(linkedList.first?.value).to.equal(fun1);
|
|
42
|
+
expect(linkedList.last?.value).to.equal(fun2);
|
|
43
|
+
expect(linkedList.find(fun1)).to.equal(linkedList.first);
|
|
44
|
+
expect(linkedList.find(fun2)).to.equal(linkedList.last);
|
|
45
|
+
expect(linkedList.find(fun1)?.next).to.equal(linkedList.last);
|
|
46
|
+
const subLinked = new LinkedList();
|
|
47
|
+
subLinked.add(fun1);
|
|
48
|
+
subLinked.add(fun2);
|
|
49
|
+
expect(linkedList.isSuperLinkOf(subLinked)).to.equal(true);
|
|
50
|
+
expect(new LinkedList().isSuperLinkOf(subLinked)).to.equal(false);
|
|
51
|
+
expect(subLinked.isSuperLinkOf(new LinkedList())).to.equal(true);
|
|
52
|
+
|
|
39
53
|
linkedList.delete(fun2);
|
|
40
54
|
expect(linkedList.size).to.equal(1);
|
|
41
55
|
linkedList.add(fun2);
|