@mantou/gem 2.1.1 → 2.2.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.
Files changed (151) hide show
  1. package/dist/gem.es.js +2082 -2153
  2. package/dist/gem.umd.js +25 -199
  3. package/elements/base/dialog.d.ts +1 -5
  4. package/elements/base/dialog.d.ts.map +1 -1
  5. package/elements/base/dialog.js +2 -6
  6. package/elements/base/dialog.js.map +1 -1
  7. package/elements/base/gesture.d.ts +6 -15
  8. package/elements/base/gesture.d.ts.map +1 -1
  9. package/elements/base/gesture.js +38 -34
  10. package/elements/base/gesture.js.map +1 -1
  11. package/elements/base/link.d.ts +1 -17
  12. package/elements/base/link.d.ts.map +1 -1
  13. package/elements/base/link.js +12 -37
  14. package/elements/base/link.js.map +1 -1
  15. package/elements/base/modal-factory.d.ts +48 -38
  16. package/elements/base/modal-factory.d.ts.map +1 -1
  17. package/elements/base/modal-factory.js +14 -14
  18. package/elements/base/modal-factory.js.map +1 -1
  19. package/elements/base/reflect.d.ts +1 -5
  20. package/elements/base/reflect.d.ts.map +1 -1
  21. package/elements/base/reflect.js +8 -13
  22. package/elements/base/reflect.js.map +1 -1
  23. package/elements/base/route.d.ts +17 -17
  24. package/elements/base/route.d.ts.map +1 -1
  25. package/elements/base/route.js +15 -27
  26. package/elements/base/route.js.map +1 -1
  27. package/elements/base/title.d.ts +1 -6
  28. package/elements/base/title.d.ts.map +1 -1
  29. package/elements/base/title.js +3 -8
  30. package/elements/base/title.js.map +1 -1
  31. package/elements/base/unsafe.d.ts +1 -6
  32. package/elements/base/unsafe.d.ts.map +1 -1
  33. package/elements/base/unsafe.js +3 -9
  34. package/elements/base/unsafe.js.map +1 -1
  35. package/elements/base/use.d.ts +1 -4
  36. package/elements/base/use.d.ts.map +1 -1
  37. package/elements/base/use.js +4 -11
  38. package/elements/base/use.js.map +1 -1
  39. package/elements/link.js +1 -1
  40. package/elements/link.js.map +1 -1
  41. package/elements/route.js +1 -1
  42. package/elements/route.js.map +1 -1
  43. package/helper/hmr.d.ts +11 -0
  44. package/helper/hmr.d.ts.map +1 -0
  45. package/helper/hmr.js +255 -0
  46. package/helper/hmr.js.map +1 -0
  47. package/helper/i18n.d.ts +2 -2
  48. package/helper/i18n.d.ts.map +1 -1
  49. package/helper/i18n.js +5 -4
  50. package/helper/i18n.js.map +1 -1
  51. package/helper/logger.d.ts +1 -1
  52. package/helper/logger.d.ts.map +1 -1
  53. package/helper/logger.js +8 -5
  54. package/helper/logger.js.map +1 -1
  55. package/helper/mediaquery.js +1 -1
  56. package/helper/mediaquery.js.map +1 -1
  57. package/helper/ssr-shim.d.ts.map +1 -1
  58. package/helper/ssr-shim.js +2 -0
  59. package/helper/ssr-shim.js.map +1 -1
  60. package/helper/theme.d.ts +4 -5
  61. package/helper/theme.d.ts.map +1 -1
  62. package/helper/theme.js +3 -3
  63. package/helper/theme.js.map +1 -1
  64. package/index.d.ts +1 -3
  65. package/index.d.ts.map +1 -1
  66. package/index.js +1 -4
  67. package/index.js.map +1 -1
  68. package/lib/decorators.d.ts +9 -16
  69. package/lib/decorators.d.ts.map +1 -1
  70. package/lib/decorators.js +84 -71
  71. package/lib/decorators.js.map +1 -1
  72. package/lib/directive.d.ts +65 -0
  73. package/lib/directive.d.ts.map +1 -0
  74. package/lib/directive.js +58 -0
  75. package/lib/directive.js.map +1 -0
  76. package/lib/element.d.ts +10 -153
  77. package/lib/element.d.ts.map +1 -1
  78. package/lib/element.js +19 -480
  79. package/lib/element.js.map +1 -1
  80. package/lib/history.d.ts +67 -9
  81. package/lib/history.d.ts.map +1 -1
  82. package/lib/history.js +12 -12
  83. package/lib/history.js.map +1 -1
  84. package/lib/lit-html.d.ts +232 -0
  85. package/lib/lit-html.d.ts.map +1 -0
  86. package/lib/lit-html.js +987 -0
  87. package/lib/lit-html.js.map +1 -0
  88. package/lib/reactive.d.ts +123 -0
  89. package/lib/reactive.d.ts.map +1 -0
  90. package/lib/reactive.js +478 -0
  91. package/lib/reactive.js.map +1 -0
  92. package/lib/repeat.d.ts +126 -0
  93. package/lib/repeat.d.ts.map +1 -0
  94. package/lib/repeat.js +533 -0
  95. package/lib/repeat.js.map +1 -0
  96. package/lib/store.d.ts +13 -2
  97. package/lib/store.d.ts.map +1 -1
  98. package/lib/store.js +5 -4
  99. package/lib/store.js.map +1 -1
  100. package/lib/utils.d.ts +24 -15
  101. package/lib/utils.d.ts.map +1 -1
  102. package/lib/utils.js +25 -30
  103. package/lib/utils.js.map +1 -1
  104. package/lib/version.d.ts +1 -1
  105. package/lib/version.js +1 -1
  106. package/package.json +8 -9
  107. package/src/dist.ts +6 -8
  108. package/src/elements/base/dialog.ts +2 -6
  109. package/src/elements/base/gesture.ts +35 -36
  110. package/src/elements/base/link.ts +20 -46
  111. package/src/elements/base/modal-factory.ts +14 -14
  112. package/src/elements/base/reflect.ts +2 -6
  113. package/src/elements/base/route.ts +22 -33
  114. package/src/elements/base/title.ts +4 -9
  115. package/src/elements/base/unsafe.ts +4 -9
  116. package/src/elements/base/use.ts +4 -11
  117. package/src/elements/link.ts +1 -1
  118. package/src/elements/route.ts +1 -1
  119. package/src/helper/hmr.ts +305 -0
  120. package/src/helper/i18n.ts +7 -7
  121. package/src/helper/logger.ts +9 -5
  122. package/src/helper/mediaquery.ts +1 -1
  123. package/src/helper/ssr-shim.ts +3 -0
  124. package/src/helper/theme.ts +6 -6
  125. package/src/index.ts +1 -5
  126. package/src/lib/decorators.ts +101 -100
  127. package/src/lib/directive.ts +137 -0
  128. package/src/lib/element.ts +26 -614
  129. package/src/lib/history.ts +14 -15
  130. package/src/lib/lit-html.ts +1269 -0
  131. package/src/lib/reactive.ts +596 -0
  132. package/src/lib/repeat.ts +580 -0
  133. package/src/lib/store.ts +5 -4
  134. package/src/lib/utils.ts +40 -46
  135. package/src/lib/version.ts +1 -1
  136. package/src/test/elements/link.test.ts +2 -3
  137. package/src/test/elements/reflect.test.ts +13 -3
  138. package/src/test/elements/title.test.ts +2 -3
  139. package/src/test/gem-element/advance.test.ts +22 -14
  140. package/src/test/gem-element/basic.test.ts +23 -11
  141. package/src/test/gem-element/decorators.test.ts +14 -17
  142. package/src/test/gem-element/multi.test.ts +20 -11
  143. package/src/test/history.test.ts +1 -2
  144. package/src/test/store.test.ts +3 -4
  145. package/src/test/utils.test.ts +12 -14
  146. package/src/test/utils.ts +22 -0
  147. package/lib/directives.d.ts +0 -4
  148. package/lib/directives.d.ts.map +0 -1
  149. package/lib/directives.js +0 -5
  150. package/lib/directives.js.map +0 -1
  151. package/src/lib/directives.ts +0 -6
package/src/lib/utils.ts CHANGED
@@ -1,24 +1,45 @@
1
- const { assign, setPrototypeOf, fromEntries, entries, keys } = Object;
1
+ const { assign, fromEntries, entries, keys } = Object;
2
2
 
3
3
  const microtaskSet = new Set<() => void>();
4
- export function addMicrotask(func: () => void) {
4
+ export function addMicrotask(func: () => void, isNodeForceMicrotask?: boolean) {
5
5
  if (microtaskSet.has(func)) return;
6
- queueMicrotask(() => {
6
+ const next = () => {
7
7
  microtaskSet.delete(func);
8
8
  func();
9
- });
9
+ };
10
+ if (isNodeForceMicrotask) {
11
+ process.nextTick(next);
12
+ } else {
13
+ Promise.resolve().then(next);
14
+ }
10
15
  microtaskSet.add(func);
11
16
  }
12
17
 
18
+ type OverrideFn = {
19
+ name: never;
20
+ apply: never;
21
+ call: never;
22
+ bind: never;
23
+ toString: never;
24
+ prototype: never;
25
+ length: never;
26
+ arguments: never;
27
+ caller: never;
28
+ [Symbol.hasInstance]: never;
29
+ [Symbol.metadata]: never;
30
+ };
31
+
13
32
  // 注意 typeof state === 'function' 但是没有 Function 的方法和属性
14
33
  export function createUpdater<T, Fn = (payload?: Partial<T>) => any>(initState: T, fn: Fn) {
15
34
  const state: any = fn;
16
- setPrototypeOf(state, null);
35
+ // https://github.com/vitejs/vite/issues/18540 现在覆盖 call 也一样会报错
36
+ // setPrototypeOf(state, null);
17
37
  delete state.name;
18
38
  delete state.length;
19
39
  assign(state, initState);
20
- // TODO: type
21
- return state as Fn & T;
40
+ // ts 不允许直接 Omit 掉 Fn 上的属性
41
+ // 只能利用 ts plugin 移除多余的自动完成项
42
+ return state as Fn & Omit<OverrideFn, keyof T> & T;
22
43
  }
23
44
 
24
45
  // 不编码 hash 用于比较
@@ -106,8 +127,10 @@ export class LinkedList<T = any> extends EventTarget {
106
127
  return this.#map.get(value);
107
128
  }
108
129
 
109
- // 添加到尾部,已存在时会删除老的项目
110
- // 如果是添加第一个,start 事件会在添加前触发,避免处理事件重复的逻辑
130
+ /**
131
+ * 添加到尾部,已存在时会删除老的项目
132
+ * 如果是添加第一个,start 事件会在添加前触发,避免处理事件重复的逻辑
133
+ */
111
134
  add(value: T) {
112
135
  if (!this.#lastItem) {
113
136
  this.dispatchEvent(new CustomEvent('start'));
@@ -125,7 +148,7 @@ export class LinkedList<T = any> extends EventTarget {
125
148
  this.#map.set(value, item);
126
149
  }
127
150
 
128
- // 删除这个元素后没有其他元素时立即出发 end 事件
151
+ /** 删除这个元素后没有其他元素时立即出发 end 事件 */
129
152
  delete(value: T) {
130
153
  const deleteItem = this.#delete(value);
131
154
  if (!this.#firstItem) {
@@ -134,8 +157,7 @@ export class LinkedList<T = any> extends EventTarget {
134
157
  return deleteItem;
135
158
  }
136
159
 
137
- // 获取头部元素
138
- // 会从链表删除
160
+ /** 获取头部元素,会从链表删除 */
139
161
  get(): T | undefined {
140
162
  const firstItem = this.#firstItem;
141
163
  if (!firstItem) return;
@@ -156,10 +178,6 @@ export class PropProxyMap<T extends NonPrimitive, V = unknown> extends WeakMap<T
156
178
  }
157
179
 
158
180
  export class QueryString extends URLSearchParams {
159
- constructor(param?: any) {
160
- super(param);
161
- }
162
-
163
181
  // support `{ key: ObjectValue }`
164
182
  concat(param: any) {
165
183
  let query: any;
@@ -223,8 +241,8 @@ export function raw(arr: TemplateStringsArray, ...args: any[]) {
223
241
  return arr.reduce((prev, current, index) => prev + (args[index - 1] ?? '') + current);
224
242
  }
225
243
 
226
- // 写 css 文本,在 CSSStyleSheet 中使用
227
- export const css = raw;
244
+ // 在 html 中引用 class 时使用,仅提供高亮功能
245
+ export const styled = raw;
228
246
 
229
247
  export function randomStr(len = 5): string {
230
248
  const str = Math.random()
@@ -234,20 +252,8 @@ export function randomStr(len = 5): string {
234
252
  return str;
235
253
  }
236
254
 
237
- // 写 css 文本,在 CSSStyleSheet 中使用,使用 styed-components 高亮
238
- //
239
- // createCSSSheet({
240
- // red: styled.class`
241
- // background: red;
242
- // &:hover {
243
- // background: blue;
244
- // }
245
- // `,
246
- // });
247
- export const styled = { class: raw };
248
-
249
255
  export function camelToKebabCase(str: string) {
250
- return str.replace(/[A-Z]/g, ($1: string) => '-' + $1.toLowerCase());
256
+ return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
251
257
  }
252
258
 
253
259
  export function kebabToCamelCase(str: string) {
@@ -280,25 +286,18 @@ export function isArrayChange(newValues: any[], oldValues: any[]) {
280
286
  export function objectMapToString<T = any>(
281
287
  object: Record<string, T>,
282
288
  separate: string,
283
- toString: (key: string, value: T) => string,
289
+ toStr: (key: string, value: T) => string,
284
290
  ) {
285
291
  let result = separate;
286
292
  for (const key in object) {
287
- const s = toString(key, object[key]);
293
+ const s = toStr(key, object[key]);
288
294
  result += s ? s + separate : '';
289
295
  }
290
296
  return result;
291
297
  }
292
298
 
293
299
  // Wait: Typescript lib dom CSSStyleDeclaration anchor position
294
- type StyleProp =
295
- | keyof CSSStyleDeclaration
296
- | `--${string}`
297
- | 'scrollbarWidth'
298
- | 'scrollbarColor'
299
- | 'positionAnchor'
300
- | 'anchorDefault'
301
- | 'anchorName';
300
+ type StyleProp = keyof CSSStyleDeclaration | `--${string}` | 'positionAnchor' | 'anchorDefault' | 'anchorName';
302
301
 
303
302
  export type StyleObject = Partial<Record<StyleProp, string | number | false | undefined | null>>;
304
303
 
@@ -321,8 +320,3 @@ export function exportPartsMap(object: Record<string, string | boolean | undefin
321
320
  value === true || key === value ? key : value ? `${key}:${value}` : '',
322
321
  );
323
322
  }
324
-
325
- declare global {
326
- interface PropertyIndexedKeyframes extends StyleObject {}
327
- interface Keyframe extends StyleObject {}
328
- }
@@ -1 +1 @@
1
- export const version = '2.1.1';
1
+ export const version = '2.2.1';
@@ -1,7 +1,6 @@
1
- import { fixture, expect } from '@open-wc/testing';
2
-
3
- import { html } from '../../lib/element';
4
1
  import type { GemActiveLinkElement } from '../../elements/link';
2
+ import { html } from '../../lib/element';
3
+ import { expect, fixture } from '../utils';
5
4
 
6
5
  import '../../elements/link';
7
6
 
@@ -1,16 +1,25 @@
1
- import { fixture, expect, nextFrame } from '@open-wc/testing';
2
-
3
- import { html } from '../../lib/element';
4
1
  import type { GemReflectElement } from '../../elements/reflect';
2
+ import { adoptedStyle, customElement } from '../../lib/decorators';
3
+ import { css, GemElement, html } from '../../lib/element';
4
+ import { expect, fixture, nextFrame } from '../utils';
5
5
 
6
6
  import '../../elements/reflect';
7
7
 
8
+ @adoptedStyle(css`
9
+ :scope {
10
+ color: rgb(255, 0, 0);
11
+ }
12
+ `)
13
+ @customElement('light-dom')
14
+ export class Children extends GemElement {}
15
+
8
16
  describe('GemReflectElement', () => {
9
17
  it('basic', async () => {
10
18
  const reflect: GemReflectElement = await fixture(html`
11
19
  <gem-reflect>
12
20
  <div id="one"></div>
13
21
  <div id="two"></div>
22
+ <light-dom></light-dom>
14
23
  </gem-reflect>
15
24
  `);
16
25
  const div = document.head.querySelector('#one');
@@ -20,6 +29,7 @@ describe('GemReflectElement', () => {
20
29
  reflect.target = document.body;
21
30
  await nextFrame();
22
31
  expect(document.body.querySelector('#one')).to.equal(div);
32
+ expect(getComputedStyle(document.body.querySelector('light-dom')!).color).to.equal('rgb(255, 0, 0)');
23
33
  expect(div?.nextSibling).to.equal(comment);
24
34
  reflect.remove();
25
35
  expect(!!document.querySelector('#one')).to.equal(false);
@@ -1,7 +1,6 @@
1
- import { fixture, expect, nextFrame } from '@open-wc/testing';
2
-
3
- import { html } from '../../lib/element';
4
1
  import type { GemTitleElement } from '../../elements/title';
2
+ import { html } from '../../lib/element';
3
+ import { expect, fixture, nextFrame } from '../utils';
5
4
 
6
5
  import '../../elements/title';
7
6
 
@@ -6,23 +6,22 @@
6
6
  * - 派生元素(类扩展)
7
7
  * - 无渲染内容 Gem 元素
8
8
  */
9
- import { fixture, expect, nextFrame } from '@open-wc/testing';
10
9
 
11
- import type { Metadata } from '../../lib/element';
12
- import { createCSSSheet, createState, GemElement, html, createRef } from '../../lib/element';
13
- import { createStore } from '../../lib/store';
14
10
  import {
11
+ adoptedStyle,
12
+ async,
15
13
  attribute,
16
- property,
14
+ connectStore,
17
15
  customElement,
18
16
  emitter,
19
- adoptedStyle,
20
- connectStore,
21
- async,
22
- shadow,
23
17
  mounted,
18
+ property,
19
+ shadow,
24
20
  } from '../../lib/decorators';
25
- import { css } from '../../lib/utils';
21
+ import type { Metadata } from '../../lib/element';
22
+ import { createRef, createState, css, GemElement, html } from '../../lib/element';
23
+ import { createStore } from '../../lib/store';
24
+ import { expect, fixture, nextFrame } from '../utils';
26
25
 
27
26
  const store = createStore({
28
27
  a: 1,
@@ -54,11 +53,11 @@ describe('异步 gem element 测试', () => {
54
53
  });
55
54
  });
56
55
 
57
- const lightStyle = createCSSSheet(css`
56
+ const lightStyle = css`
58
57
  div {
59
58
  font-size: 18.1px;
60
59
  }
61
- `);
60
+ `;
62
61
 
63
62
  @customElement('light-gem-demo')
64
63
  @adoptedStyle(lightStyle)
@@ -100,7 +99,7 @@ class LifecycleGemElement extends GemElement {
100
99
  this.appTitle2 = appTitle2 ?? this.appTitle2;
101
100
  this.effect(
102
101
  () => {
103
- this.refInConstructor = this.divRef.element;
102
+ this.refInConstructor = this.divRef.value;
104
103
  },
105
104
  () => [],
106
105
  );
@@ -118,7 +117,7 @@ class LifecycleGemElement extends GemElement {
118
117
 
119
118
  render() {
120
119
  this.renderCount++;
121
- return html`<div ref=${this.divRef.ref}></div>`;
120
+ return html`<div ${this.divRef}></div>`;
122
121
  }
123
122
  }
124
123
  describe('gem element 生命周期', () => {
@@ -304,12 +303,20 @@ class InheritGem extends I {
304
303
  @attribute appTitle = '1';
305
304
  @attribute appTitle2 = '2';
306
305
  }
306
+
307
+ @customElement('inherit-gem1')
308
+ class InheritGem1 extends I {}
309
+
307
310
  describe('gem element 继承', () => {
308
311
  it('静态字段继承', async () => {
309
312
  new I();
310
313
  new InheritGem(); // 触发装饰器自定义初始化函数
311
314
  const metadata: Metadata = Reflect.get(InheritGem, Symbol.metadata);
312
315
  expect(metadata.observedAttributes).to.eql(['app-title', 'app-title2']);
316
+
317
+ new InheritGem1(); // 触发装饰器自定义初始化函数
318
+ const metadata1: Metadata = Reflect.get(InheritGem1, Symbol.metadata);
319
+ expect(metadata1.observedAttributes).to.eql(['app-title']);
313
320
  });
314
321
  it('attr/prop/emitter 继承', async () => {
315
322
  const name = window.name;
@@ -333,6 +340,7 @@ describe('gem element 继承', () => {
333
340
  window.name += '2';
334
341
  });
335
342
  el.sayHi();
343
+ await Promise.resolve();
336
344
  expect(window.name).to.equal(name + '21');
337
345
  });
338
346
  });
@@ -1,28 +1,27 @@
1
- import { fixture, expect, nextFrame } from '@open-wc/testing';
2
-
3
- import { createCSSSheet, createState, GemElement, html } from '../../lib/element';
4
- import { createStore } from '../../lib/store';
5
- import { css } from '../../lib/utils';
6
1
  import {
7
2
  adoptedStyle,
8
3
  attribute,
9
4
  boolattribute,
10
5
  connectStore,
11
6
  customElement,
7
+ fallback,
12
8
  numattribute,
13
9
  property,
14
10
  shadow,
15
11
  } from '../../lib/decorators';
12
+ import { createState, css, GemElement, html } from '../../lib/element';
13
+ import { createStore } from '../../lib/store';
14
+ import { expect, fixture, nextFrame } from '../utils';
16
15
 
17
16
  const store = createStore({
18
17
  a: 1,
19
18
  });
20
19
 
21
- const styles = createCSSSheet(css`
20
+ const styles = css`
22
21
  :host {
23
22
  background: rgb(255, 0, 0);
24
23
  }
25
- `);
24
+ `;
26
25
 
27
26
  @connectStore(store)
28
27
  @adoptedStyle(styles)
@@ -40,11 +39,15 @@ class GemDemo extends GemElement {
40
39
  renderCount = 0;
41
40
 
42
41
  render() {
42
+ if (this.attr === 'error') throw new Error();
43
43
  const { attr, disabled, count, prop } = this;
44
44
  const { value } = this.#state;
45
45
  this.renderCount++;
46
46
  return html`attr: ${attr}, disabled: ${disabled}, count: ${count}, prop: ${prop.value}, state: ${value}`;
47
47
  }
48
+
49
+ @fallback()
50
+ #error = () => html`Error`;
48
51
  }
49
52
 
50
53
  describe('基本 gem element 测试', () => {
@@ -68,12 +71,14 @@ describe('基本 gem element 测试', () => {
68
71
  });
69
72
  it('渲染 gem element', async () => {
70
73
  const el: GemDemo = await fixture(html`<gem-demo attr="attr" .prop=${{ value: 'prop' }}></gem-demo>`);
71
- expect(el).shadowDom.to.equal('attr: attr, disabled: false, count: 0, prop: prop, state: ');
74
+ expect(el.shadowRoot?.textContent).to.equal('attr: attr, disabled: false, count: 0, prop: prop, state: ');
72
75
  await Promise.resolve();
73
76
  expect(el.renderCount).to.equal(1);
74
77
  el.update();
75
78
  await Promise.resolve();
76
79
  expect(el.renderCount).to.equal(2);
80
+ const errEl: GemDemo = await fixture(html`<gem-demo attr="error"></gem-demo>`);
81
+ expect(errEl.shadowRoot?.textContent).to.equal('Error');
77
82
  });
78
83
  it('读取 attr', async () => {
79
84
  const el: GemDemo = await fixture(html`
@@ -102,7 +107,7 @@ describe('基本 gem element 测试', () => {
102
107
  expect(el.attr).to.equal('value');
103
108
  expect(el.disabled).to.equal(true);
104
109
  expect(el.count).to.equal(2);
105
- expect(el).shadowDom.to.equal('attr: value, disabled: true, count: 2, prop: , state: ');
110
+ expect(el.shadowRoot?.textContent).to.equal('attr: value, disabled: true, count: 2, prop: , state: ');
106
111
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
107
112
  // @ts-ignore
108
113
  el.attr = null;
@@ -124,7 +129,14 @@ describe('基本 gem element 测试', () => {
124
129
  await Promise.resolve();
125
130
  expect(el.renderCount).to.equal(2);
126
131
  expect(el.prop).to.deep.equal({ value: 'value' });
127
- expect(el).shadowDom.to.equal('attr: , disabled: false, count: 0, prop: value, state: ');
132
+ expect(el.shadowRoot?.textContent).to.equal('attr: , disabled: false, count: 0, prop: value, state: ');
133
+ });
134
+
135
+ it('只能在 initEffect 前修改 state', async () => {
136
+ const syncUpdateEle = new GemDemo();
137
+ expect(() => syncUpdateEle.internals.stateList[0]()).to.not.throw();
138
+ document.body.append(syncUpdateEle);
139
+ expect(() => syncUpdateEle.internals.stateList[0]()).to.throw();
128
140
  });
129
141
 
130
142
  it('修改 state', async () => {
@@ -136,7 +148,7 @@ describe('基本 gem element 测试', () => {
136
148
  await Promise.resolve();
137
149
  expect(el.renderCount).to.equal(2);
138
150
  expect({ ...el.internals.stateList[0] }).to.deep.equal({ value: 'state' });
139
- expect(el).shadowDom.to.equal('attr: , disabled: false, count: 0, prop: , state: state');
151
+ expect(el.shadowRoot?.textContent).to.equal('attr: , disabled: false, count: 0, prop: , state: state');
140
152
  });
141
153
 
142
154
  it('更新 store', async () => {
@@ -1,34 +1,32 @@
1
- import { fixture, expect } from '@open-wc/testing';
2
-
3
- import type { Metadata } from '../../lib/element';
4
- import { createCSSSheet, GemElement, html, createRef } from '../../lib/element';
5
- import { createStore } from '../../lib/store';
6
- import { css } from '../../lib/utils';
7
1
  import type { Emitter } from '../../lib/decorators';
8
2
  import {
3
+ adoptedStyle,
9
4
  attribute,
10
- property,
11
- customElement,
5
+ boolattribute,
12
6
  connectStore,
13
- adoptedStyle,
7
+ customElement,
14
8
  emitter,
15
- boolattribute,
16
9
  numattribute,
17
10
  part,
11
+ property,
12
+ shadow,
18
13
  slot,
19
14
  state,
20
- shadow,
21
15
  } from '../../lib/decorators';
16
+ import type { Metadata } from '../../lib/element';
17
+ import { css, GemElement, html } from '../../lib/element';
18
+ import { createStore } from '../../lib/store';
19
+ import { expect, fixture } from '../utils';
22
20
 
23
21
  const store = createStore({
24
22
  a: 1,
25
23
  });
26
24
 
27
- const styles = createCSSSheet(css`
25
+ const styles = css`
28
26
  :host {
29
27
  background: rgb(255, 0, 0);
30
28
  }
31
- `);
29
+ `;
32
30
 
33
31
  @connectStore(store)
34
32
  @adoptedStyle(styles)
@@ -47,7 +45,6 @@ class DecoratorGemElement extends GemElement {
47
45
  @state openState: boolean;
48
46
  @part headerPart: string;
49
47
  @slot bodySlot: string;
50
- inputRef = createRef<HTMLElement>();
51
48
  renderCount = 0;
52
49
  render() {
53
50
  this.renderCount++;
@@ -84,7 +81,7 @@ describe('装饰器', () => {
84
81
  store({ a: 1 });
85
82
  await Promise.resolve();
86
83
  const metadata: Metadata = Reflect.get(DecoratorGemElement, Symbol.metadata);
87
- expect({ ...metadata.observedStores.at(0) }).to.eql({ a: 1 });
84
+ expect({ ...metadata.observedStores?.at(0) }).to.eql({ a: 1 });
88
85
  expect(metadata.observedAttributes).to.eql(['rank-attr', 'rank-disabled', 'rank-count']);
89
86
  expect(metadata.definedEvents).to.eql(['say-hi']);
90
87
  expect(metadata.definedCSSStates).to.eql(['open-state']);
@@ -99,13 +96,13 @@ describe('装饰器', () => {
99
96
  expect(el.propData).to.eql({ value: 'prop' });
100
97
  expect(el.openState).to.equal(false);
101
98
  expect(el.headerPart).to.equal('header-part');
102
- expect(el.inputRef.ref.startsWith('ref-')).to.equal(true);
103
99
  expect(el.bodySlot).to.equal('body-slot');
104
- expect(el).shadowDom.to.equal('attr: attr, disabled: true, count: 2, prop: prop');
100
+ expect(el.shadowRoot?.textContent).to.equal('attr: attr, disabled: true, count: 2, prop: prop');
105
101
  store({ a: 3 });
106
102
  await Promise.resolve();
107
103
  expect(el.renderCount).to.equal(3);
108
104
  el.sayHi(2);
105
+ await Promise.resolve();
109
106
  expect(el.renderCount).to.equal(3);
110
107
  expect(a).to.equal(2);
111
108
  });
@@ -1,16 +1,20 @@
1
- import { expect, fixture } from '@open-wc/testing';
2
-
3
- import { attribute, customElement, property } from '../../lib/decorators';
4
- import { GemElement, html, createRef } from '../../lib/element';
1
+ import { attribute, customElement, type Emitter, emitter, mounted, property } from '../../lib/decorators';
2
+ import { createRef, createState, GemElement, html } from '../../lib/element';
3
+ import { expect, fixture } from '../utils';
5
4
 
6
5
  @customElement('app-children')
7
6
  export class Children extends GemElement {
8
7
  @property value?: { value: number };
9
8
  @attribute attr: string;
9
+ @emitter sayHi: Emitter<null>;
10
+
10
11
  inputRef = createRef<HTMLInputElement>();
11
12
 
13
+ @mounted()
14
+ #init = () => this.sayHi();
15
+
12
16
  render() {
13
- return html`<input ref=${this.inputRef.ref} />`;
17
+ return html`<input ${this.inputRef} />`;
14
18
  }
15
19
  }
16
20
 
@@ -18,20 +22,25 @@ export class Children extends GemElement {
18
22
  export class App extends GemElement {
19
23
  childrenRef1 = createRef<Children>();
20
24
  childrenRef2 = createRef<Children>();
25
+
26
+ // 还未 mounted, 不应该发生错误
27
+ #state = createState({});
28
+ #onSayHi = () => this.#state();
29
+
21
30
  render() {
22
31
  return html`
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>
32
+ <app-children ${this.childrenRef1} .value=${{ value: 1 }} attr="1" @say-hi=${this.#onSayHi}></app-children>
33
+ <app-children ${this.childrenRef2} .value=${{ value: 2 }} attr="2"></app-children>
25
34
  `;
26
35
  }
27
36
  }
28
37
  describe('多个 gem element 一起工作', () => {
29
38
  it('ref & prop & attr', async () => {
30
39
  const el: App = await fixture(html`<app-root></app-root>`);
31
- const children1 = el.childrenRef1.element!;
32
- const children2 = el.childrenRef2.element!;
33
- const input1 = children1.inputRef.element!;
34
- const input2 = children2.inputRef.element!;
40
+ const children1 = el.childrenRef1.value!;
41
+ const children2 = el.childrenRef2.value!;
42
+ const input1 = children1.inputRef.value!;
43
+ const input2 = children2.inputRef.value!;
35
44
  expect(input1 !== input2).to.equal(true);
36
45
  expect(children1.value).to.eql({ value: 1 });
37
46
  expect(children2.value).to.eql({ value: 2 });
@@ -1,6 +1,5 @@
1
- import { expect, aTimeout } from '@open-wc/testing';
2
-
3
1
  import { history } from '../lib/history';
2
+ import { aTimeout, expect } from './utils';
4
3
 
5
4
  describe('history 测试', () => {
6
5
  it('hash', async () => {
@@ -1,13 +1,12 @@
1
- import { expect, aTimeout } from '@open-wc/testing';
2
-
3
- import { StoreListenerMap, createStore, connect } from '../lib/store';
1
+ import { _StoreListenerMap, connect, createStore } from '../lib/store';
2
+ import { aTimeout, expect } from './utils';
4
3
 
5
4
  describe('store 测试', () => {
6
5
  it('create store', () => {
7
6
  const origin = { a: 1 };
8
7
  const store = createStore(origin);
9
8
  expect({ ...store }).to.deep.equal(origin);
10
- expect(!!StoreListenerMap.get(store)).to.equal(true);
9
+ expect(!!_StoreListenerMap.get(store)).to.equal(true);
11
10
  });
12
11
  it('update store', async () => {
13
12
  const store = createStore({ a: 1 });
@@ -1,17 +1,15 @@
1
- import { expect } from '@open-wc/testing';
2
-
3
- import { createCSSSheet, SheetToken } from '../lib/element';
1
+ import { css, SheetToken } from '../lib/element';
4
2
  import {
3
+ absoluteLocation,
4
+ classMap,
5
+ exportPartsMap,
5
6
  LinkedList,
6
7
  QueryString,
7
- css,
8
8
  raw,
9
9
  styled,
10
10
  styleMap,
11
- classMap,
12
- exportPartsMap,
13
- absoluteLocation,
14
11
  } from '../lib/utils';
12
+ import { expect } from './utils';
15
13
 
16
14
  declare global {
17
15
  interface CSSRuleList {
@@ -78,15 +76,15 @@ describe('utils 测试', () => {
78
76
  query.setAny('obj', [{ a: 1, b: 2 }]);
79
77
  expect(query.getAny('obj')).to.deep.equal({ a: 1, b: 2 });
80
78
  expect(query.getAnyAll('obj')).to.deep.equal([{ a: 1, b: 2 }]);
81
- expect(new QueryString({ a: 1 }).toString()).to.equal('?a=1');
79
+ expect(new QueryString({ a: '1' }).toString()).to.equal('?a=1');
82
80
  expect(new QueryString(query).toString()).to.equal(query.toString());
83
81
  });
84
- it('createCSSSheet', () => {
85
- const cssSheet = createCSSSheet(css`
82
+ it('css', () => {
83
+ const cssSheet = css`
86
84
  div {
87
85
  background: red;
88
86
  }
89
- `);
87
+ `;
90
88
  const rules = cssSheet[SheetToken].getStyle().cssRules;
91
89
  expect(rules.item(0).selectorText).to.equal('div');
92
90
  expect(rules.item(0).style.background).to.equal('red');
@@ -101,9 +99,9 @@ describe('utils 测试', () => {
101
99
  expect(raw`<div>${'str'}</div>`).to.equal('<div>str</div>');
102
100
  });
103
101
  it('styled', () => {
104
- const cssSheet = createCSSSheet({
105
- $: styled.class``,
106
- scroll: styled.class`
102
+ const cssSheet = css({
103
+ $: styled``,
104
+ scroll: styled`
107
105
  background: red;
108
106
  &:hover * {
109
107
  background: blue;
@@ -0,0 +1,22 @@
1
+ import { assert, expect, should } from 'chai';
2
+
3
+ import type { TemplateResult } from '../lib/element';
4
+ import { render } from '../lib/element';
5
+
6
+ export { expect, should, assert };
7
+
8
+ export function nextFrame() {
9
+ return new Promise((resolve) => requestAnimationFrame(() => resolve(null)));
10
+ }
11
+
12
+ export function aTimeout(ms = 0) {
13
+ return new Promise((resolve) => setTimeout(() => resolve(null), ms));
14
+ }
15
+
16
+ export async function fixture(template: TemplateResult) {
17
+ const wrapper = document.createElement('div');
18
+ document.body.appendChild(wrapper);
19
+ render(template, wrapper);
20
+ await nextFrame();
21
+ return wrapper.firstElementChild as any;
22
+ }
@@ -1,4 +0,0 @@
1
- export { repeat } from 'lit-html/directives/repeat';
2
- export { guard } from 'lit-html/directives/guard';
3
- export { ifDefined } from 'lit-html/directives/if-defined';
4
- //# sourceMappingURL=directives.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../src/lib/directives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC"}