@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.
Files changed (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/gem.es.js +2010 -1765
  4. package/dist/gem.umd.js +52 -53
  5. package/elements/base/dialog.d.ts +0 -11
  6. package/elements/base/dialog.d.ts.map +1 -1
  7. package/elements/base/dialog.js +93 -66
  8. package/elements/base/dialog.js.map +1 -1
  9. package/elements/base/gesture.d.ts +1 -2
  10. package/elements/base/gesture.d.ts.map +1 -1
  11. package/elements/base/gesture.js +157 -96
  12. package/elements/base/gesture.js.map +1 -1
  13. package/elements/base/link.d.ts +5 -5
  14. package/elements/base/link.d.ts.map +1 -1
  15. package/elements/base/link.js +249 -145
  16. package/elements/base/link.js.map +1 -1
  17. package/elements/base/modal-factory.d.ts +145 -139
  18. package/elements/base/modal-factory.d.ts.map +1 -1
  19. package/elements/base/modal-factory.js +84 -25
  20. package/elements/base/modal-factory.js.map +1 -1
  21. package/elements/base/reflect.d.ts +0 -1
  22. package/elements/base/reflect.d.ts.map +1 -1
  23. package/elements/base/reflect.js +83 -38
  24. package/elements/base/reflect.js.map +1 -1
  25. package/elements/base/route.d.ts +12 -24
  26. package/elements/base/route.d.ts.map +1 -1
  27. package/elements/base/route.js +263 -164
  28. package/elements/base/route.js.map +1 -1
  29. package/elements/base/title.d.ts +3 -11
  30. package/elements/base/title.d.ts.map +1 -1
  31. package/elements/base/title.js +110 -59
  32. package/elements/base/title.js.map +1 -1
  33. package/elements/base/unsafe.d.ts +0 -1
  34. package/elements/base/unsafe.d.ts.map +1 -1
  35. package/elements/base/unsafe.js +82 -33
  36. package/elements/base/unsafe.js.map +1 -1
  37. package/elements/base/use.d.ts.map +1 -1
  38. package/elements/base/use.js +95 -47
  39. package/elements/base/use.js.map +1 -1
  40. package/helper/i18n.d.ts +4 -9
  41. package/helper/i18n.d.ts.map +1 -1
  42. package/helper/i18n.js +69 -65
  43. package/helper/i18n.js.map +1 -1
  44. package/helper/logger.js +10 -9
  45. package/helper/logger.js.map +1 -1
  46. package/helper/react-shim.d.ts +15 -0
  47. package/helper/react-shim.d.ts.map +1 -0
  48. package/helper/react-shim.js +56 -0
  49. package/helper/react-shim.js.map +1 -0
  50. package/helper/react-utils.d.ts +15 -0
  51. package/helper/react-utils.d.ts.map +1 -0
  52. package/helper/react-utils.js +50 -0
  53. package/helper/react-utils.js.map +1 -0
  54. package/helper/request.d.ts +4 -4
  55. package/helper/request.d.ts.map +1 -1
  56. package/helper/request.js +1 -1
  57. package/helper/request.js.map +1 -1
  58. package/helper/ssr-shim.d.ts.map +1 -1
  59. package/helper/ssr-shim.js +8 -1
  60. package/helper/ssr-shim.js.map +1 -1
  61. package/helper/theme.d.ts +14 -21
  62. package/helper/theme.d.ts.map +1 -1
  63. package/helper/theme.js +55 -38
  64. package/helper/theme.js.map +1 -1
  65. package/index.d.ts +4 -3
  66. package/index.d.ts.map +1 -1
  67. package/index.js +5 -3
  68. package/index.js.map +1 -1
  69. package/lib/decorators.d.ts +74 -42
  70. package/lib/decorators.d.ts.map +1 -1
  71. package/lib/decorators.js +324 -84
  72. package/lib/decorators.js.map +1 -1
  73. package/lib/directives.d.ts +4 -0
  74. package/lib/directives.d.ts.map +1 -0
  75. package/lib/directives.js +5 -0
  76. package/lib/directives.js.map +1 -0
  77. package/lib/element.d.ts +112 -110
  78. package/lib/element.d.ts.map +1 -1
  79. package/lib/element.js +431 -468
  80. package/lib/element.js.map +1 -1
  81. package/lib/history.d.ts +4 -0
  82. package/lib/history.d.ts.map +1 -1
  83. package/lib/history.js +12 -13
  84. package/lib/history.js.map +1 -1
  85. package/lib/store.d.ts +1 -1
  86. package/lib/store.d.ts.map +1 -1
  87. package/lib/store.js +4 -5
  88. package/lib/store.js.map +1 -1
  89. package/lib/utils.d.ts +3 -43
  90. package/lib/utils.d.ts.map +1 -1
  91. package/lib/utils.js +61 -235
  92. package/lib/utils.js.map +1 -1
  93. package/lib/version.d.ts +1 -1
  94. package/lib/version.d.ts.map +1 -1
  95. package/lib/version.js +2 -1
  96. package/lib/version.js.map +1 -1
  97. package/package.json +13 -11
  98. package/src/dist.ts +3 -2
  99. package/src/elements/base/dialog.ts +10 -20
  100. package/src/elements/base/gesture.ts +16 -14
  101. package/src/elements/base/link.ts +65 -44
  102. package/src/elements/base/modal-factory.ts +14 -14
  103. package/src/elements/base/reflect.ts +24 -32
  104. package/src/elements/base/route.ts +55 -68
  105. package/src/elements/base/title.ts +25 -42
  106. package/src/elements/base/unsafe.ts +12 -21
  107. package/src/elements/base/use.ts +17 -13
  108. package/src/helper/i18n.ts +20 -14
  109. package/src/helper/react-utils.ts +66 -0
  110. package/src/helper/ssr-shim.ts +8 -1
  111. package/src/helper/theme.ts +72 -45
  112. package/src/index.ts +6 -4
  113. package/src/lib/decorators.ts +394 -93
  114. package/src/lib/directives.ts +6 -0
  115. package/src/lib/element.ts +473 -500
  116. package/src/lib/history.ts +4 -3
  117. package/src/lib/store.ts +2 -1
  118. package/src/lib/utils.ts +12 -191
  119. package/src/lib/version.ts +2 -1
  120. package/src/test/elements/link.test.ts +1 -1
  121. package/src/test/elements/title.test.ts +1 -0
  122. package/src/test/gem-element/advance.test.ts +72 -49
  123. package/src/test/gem-element/basic.test.ts +37 -50
  124. package/src/test/gem-element/decorators.test.ts +22 -21
  125. package/src/test/gem-element/multi.test.ts +5 -5
  126. package/src/test/utils.test.ts +15 -45
@@ -1,90 +1,317 @@
1
- import { defineAttribute, defineCSSState, defineProperty, defineRef, GemElement, nativeDefineElement } from './element';
2
- import { Store } from './store';
3
- import { Sheet, camelToKebabCase, randomStr } from './utils';
4
-
5
- type GemElementPrototype = GemElement<any>;
6
- type GemElementConstructor = typeof GemElement;
7
- type StaticField = Exclude<keyof GemElementConstructor, 'prototype' | 'rootElement'>;
8
- type StaticFieldMember = string | Store<unknown> | Sheet<unknown>;
9
-
10
- function pushStaticField(target: GemElementPrototype, field: StaticField, member: StaticFieldMember, isSet = false) {
11
- const cls = target.constructor as GemElementConstructor;
12
- const current = cls[field];
13
- if (!cls.hasOwnProperty(field)) {
14
- Object.defineProperty(cls, field, {
15
- value: isSet ? new Set<unknown>(current) : current ? Array.from<any>(current) : [],
1
+ import type { createCSSSheet, Metadata, TemplateResult } from './element';
2
+ import { GemElement, UpdateToken, createTemplate, RenderErrorEvent, render } from './element';
3
+ import { camelToKebabCase, PropProxyMap, GemError } from './utils';
4
+ import type { Store } from './store';
5
+ import * as elementExports from './element';
6
+ import * as decoratorsExports from './decorators';
7
+ import * as storeExports from './store';
8
+ import * as versionExports from './version';
9
+
10
+ type GemElementPrototype = GemElement;
11
+ type StaticField = Exclude<keyof Metadata, keyof ShadowRootInit | 'aria' | 'noBlocking'>;
12
+
13
+ const { deleteProperty, getOwnPropertyDescriptor, defineProperty } = Reflect;
14
+ const { getPrototypeOf, assign } = Object;
15
+ const gemElementProxyMap = new PropProxyMap<GemElement>();
16
+
17
+ function pushStaticField(context: ClassFieldDecoratorContext | ClassDecoratorContext, field: StaticField, member: any) {
18
+ const metadata = context.metadata as Metadata;
19
+ if (!getOwnPropertyDescriptor(metadata, field)) {
20
+ // 继承基类
21
+ const current = new Set<unknown>(metadata[field]);
22
+ current.delete(member);
23
+ defineProperty(metadata, field, {
24
+ value: [...current],
16
25
  });
17
26
  }
18
27
 
19
- (cls[field] as any)[isSet ? 'add' : 'push'](member);
28
+ metadata[field]!.push(member);
20
29
  }
21
30
 
22
- export type RefObject<T = HTMLElement> = { ref: string; element: T | undefined; elements: T[] };
31
+ function clearField<T extends GemElement>(instance: T, prop: string) {
32
+ const { value } = getOwnPropertyDescriptor(instance, prop)!;
33
+ deleteProperty(instance, prop);
34
+ (instance as any)[prop] = value;
35
+ }
36
+
37
+ const observedTargetAttributes = new WeakMap<GemElementPrototype, Map<string, string>>();
38
+ // hack 修改 attribute 行为,如果是观察的,就使用 `setter`
39
+ // 不在 Devtools 中工作 https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#dom_access
40
+ // 使用 Gem DevTools 注入脚本监听 attribute 变化
41
+ const { setAttribute, toggleAttribute, removeAttribute } = Element.prototype;
42
+ GemElement.prototype.setAttribute = function (n: string, v: string) {
43
+ const prop = observedTargetAttributes.get(getPrototypeOf(this))?.get(n);
44
+ if (!prop) return setAttribute.call(this, n, v);
45
+ (this as any)[prop] = v;
46
+ };
47
+ GemElement.prototype.removeAttribute = function (n: string) {
48
+ const prop = observedTargetAttributes.get(getPrototypeOf(this))?.get(n);
49
+ if (!prop) return removeAttribute.call(this, n);
50
+ (this as any)[prop] = null;
51
+ };
52
+ GemElement.prototype.toggleAttribute = function (n: string, force?: boolean) {
53
+ const prop = observedTargetAttributes.get(getPrototypeOf(this))?.get(n);
54
+ if (!prop) return toggleAttribute.call(this, n, force);
55
+ return ((this as any)[prop] = force ?? !this.hasAttribute(n));
56
+ };
57
+
58
+ function emptyFunction() {
59
+ // 用于占位的空函数
60
+ }
61
+
62
+ type DefinePropOptions = {
63
+ attr?: string;
64
+ attrType?: (v?: any) => any;
65
+ event?: string;
66
+ eventOptions?: Omit<CustomEventInit<unknown>, 'detail'>;
67
+ };
68
+ const isEventHandleSymbol = Symbol('event handle');
69
+ function defineProp(
70
+ target: GemElementPrototype,
71
+ prop: string,
72
+ { attr, attrType, event, eventOptions }: DefinePropOptions = {},
73
+ ) {
74
+ defineProperty(target, prop, {
75
+ configurable: true,
76
+ get() {
77
+ const value = gemElementProxyMap.get(this)[prop];
78
+ if (event && !value) {
79
+ this[prop] = emptyFunction;
80
+ return this[prop];
81
+ }
82
+ return value;
83
+ },
84
+ set(v) {
85
+ const that = this as GemElement;
86
+ const proxy = gemElementProxyMap.get(that);
87
+ if (attr) {
88
+ v = attrType === Boolean && v === '' ? true : attrType!(v || '');
89
+ if (!v) {
90
+ removeAttribute.call(this, attr);
91
+ } else {
92
+ setAttribute.call(this, attr, attrType === Boolean ? '' : v);
93
+ }
94
+ }
95
+ if (v === proxy[prop]) return;
96
+ if (event) {
97
+ proxy[prop] = v?.[isEventHandleSymbol]
98
+ ? v
99
+ : (detail: any, options: any) => {
100
+ const evt = new CustomEvent(event, { ...options, ...eventOptions, detail });
101
+ that.dispatchEvent(evt);
102
+ v(detail, options);
103
+ };
104
+ (proxy[prop] as any)[isEventHandleSymbol] = true;
105
+ // emitter 不触发元素更新
106
+ } else {
107
+ proxy[prop] = v;
108
+ this[UpdateToken]();
109
+ }
110
+ },
111
+ });
112
+ }
113
+
114
+ type AttrType = BooleanConstructor | NumberConstructor | StringConstructor;
115
+ function decoratorAttr<T extends GemElement>(context: ClassFieldDecoratorContext<T>, attrType: AttrType) {
116
+ const prop = context.name as string;
117
+ const attr = camelToKebabCase(prop);
118
+ context.addInitializer(function (this: T) {
119
+ const target = getPrototypeOf(this);
120
+ if (!target.hasOwnProperty(prop)) {
121
+ pushStaticField(context, 'observedAttributes', attr); // 没有 observe 的效果
122
+ defineProp(target, prop, { attr, attrType });
123
+ // 记录观察的 attribute
124
+ const attrMap = observedTargetAttributes.get(target) || new Map<string, string>();
125
+ attrMap.set(attr, prop);
126
+ observedTargetAttributes.set(target, attrMap);
127
+ }
128
+ clearField(this, prop);
129
+ });
130
+ // 延时定义的元素需要继承原实例属性值
131
+ return function (this: any, initValue: any) {
132
+ return this.getAttribute(attr) ?? initValue;
133
+ };
134
+ }
23
135
 
24
136
  /**
25
- * 引用元素,只有第一个标记 ref 的元素有效
137
+ * 定义一个响应式的 attribute,驼峰字段名将自动映射到烤串 attribute,默认值为空字符串;不要覆盖定义
26
138
  *
27
139
  * For example
28
140
  * ```ts
29
141
  * class App extends GemElement {
30
- * @refobject childRef: RefObject<Children>;
31
- * loadHandle = () => {
32
- * const { element } = this.childRef;
33
- * console.log(element);
34
- * };
35
- * render() {
36
- * render html`<div ref=${this.childRef.ref}><div>`;
37
- * }
142
+ * @attribute attr: string;
38
143
  * }
39
144
  * ```
40
145
  */
41
- export function refobject(target: GemElementPrototype, prop: string) {
42
- const ref = `${camelToKebabCase(prop)}-${randomStr()}`;
43
- pushStaticField(target, 'defineRefs', ref);
44
- defineRef(target, prop, ref);
146
+ export function attribute<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, string>) {
147
+ return decoratorAttr(context, String);
148
+ }
149
+ export function boolattribute<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, boolean>) {
150
+ return decoratorAttr(context, Boolean);
151
+ }
152
+ export function numattribute<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, number>) {
153
+ return decoratorAttr(context, Number);
45
154
  }
46
155
 
47
156
  /**
48
- * 定义一个响应式的 attribute,驼峰字段名将自动映射到烤串 attribute,默认值为空字符串
157
+ * 定义一个响应式的 property,注意值可能为 `undefined`;不要覆盖定义
49
158
  *
50
159
  * For example
51
160
  * ```ts
52
161
  * class App extends GemElement {
53
- * @attribute attr: string;
162
+ * @property prop: Data | undefined;
54
163
  * }
55
164
  * ```
56
165
  */
57
- function defineAttr(target: GemElementPrototype, prop: string, attr: string) {
58
- pushStaticField(target, 'observedAttributes', attr);
59
- defineAttribute(target, prop, attr);
60
- }
61
- export function attribute(target: GemElementPrototype, prop: string) {
62
- defineAttr(target, prop, camelToKebabCase(prop));
63
- }
64
- export function boolattribute(target: GemElementPrototype, prop: string) {
65
- const attr = camelToKebabCase(prop);
66
- pushStaticField(target, 'booleanAttributes', attr, true);
67
- defineAttr(target, prop, attr);
166
+ export function property<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T>) {
167
+ const prop = context.name as string;
168
+ context.addInitializer(function (this: T) {
169
+ const target = getPrototypeOf(this);
170
+ if (!target.hasOwnProperty(prop)) {
171
+ pushStaticField(context, 'observedProperties', prop);
172
+ defineProp(target, prop);
173
+ }
174
+ clearField(this, prop);
175
+ });
176
+ // 延时定义的元素需要继承原实例属性值
177
+ return function (this: any, initValue: any) {
178
+ return this[prop] ?? initValue;
179
+ };
68
180
  }
69
- export function numattribute(target: GemElementPrototype, prop: string) {
70
- const attr = camelToKebabCase(prop);
71
- pushStaticField(target, 'numberAttributes', attr, true);
72
- defineAttr(target, prop, attr);
181
+
182
+ /**
183
+ * 依赖 `GemElement.memo`
184
+ *
185
+ * For example
186
+ * ```ts
187
+ * class App extends GemElement {
188
+ * @memo(() => [])
189
+ * get data() {
190
+ * return 1;
191
+ * }
192
+ * }
193
+ * ```
194
+ */
195
+ export function memo<T extends GemElement, V = any, K = any[] | undefined>(
196
+ getDep?: K extends readonly any[] ? (instance: T) => K : undefined,
197
+ ) {
198
+ return function (
199
+ _: any,
200
+ context: ClassGetterDecoratorContext<T, V> | ClassFieldDecoratorContext<T> | ClassMethodDecoratorContext<T>,
201
+ ) {
202
+ const { addInitializer, name, access, kind } = context;
203
+ addInitializer(function (this: T) {
204
+ const dep = getDep && (() => getDep(this) as any);
205
+ if (kind === 'getter') {
206
+ // 不能设置私有字段 https://github.com/tc39/proposal-decorators/issues/509
207
+ if (context.private) throw new GemError('not support');
208
+ this.memo(() => defineProperty(this, name, { configurable: true, value: access.get(this) }), dep);
209
+ } else {
210
+ this.memo((access.get(this) as any).bind(this) as any, dep);
211
+ }
212
+ });
213
+ };
73
214
  }
74
215
 
75
216
  /**
76
- * 定义一个响应式的 property,注意值可能为 `undefined`
217
+ * 依赖 `GemElement.effect`
218
+ * 方法执行在字段前面
77
219
  *
78
220
  * For example
79
221
  * ```ts
80
222
  * class App extends GemElement {
81
- * @property prop: Data | undefined;
223
+ * @effect(() => [])
224
+ * #fetchData() {
225
+ * console.log('fetch')
226
+ * }
82
227
  * }
83
228
  * ```
84
229
  */
85
- export function property(target: GemElementPrototype, prop: string) {
86
- pushStaticField(target, 'observedProperties', prop);
87
- defineProperty(target, prop);
230
+ export function effect<T extends GemElement, V extends (depValues: K, oldDepValues?: K) => any, K = any[] | undefined>(
231
+ getDep?: K extends readonly any[] ? (instance: T) => K : undefined,
232
+ ) {
233
+ return function (
234
+ _: any,
235
+ { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
236
+ ) {
237
+ addInitializer(function (this: T) {
238
+ this.effect(access.get(this).bind(this) as any, getDep && (() => getDep(this) as any));
239
+ });
240
+ };
241
+ }
242
+
243
+ export function unmounted<T extends GemElement, V extends () => any>() {
244
+ return function (
245
+ _: any,
246
+ { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
247
+ ) {
248
+ addInitializer(function (this: T) {
249
+ this.effect(
250
+ () => access.get(this).bind(this) as any,
251
+ () => [],
252
+ );
253
+ });
254
+ };
255
+ }
256
+
257
+ /**`@memo` 别名,不能再在回调中使用 `this.memo` */
258
+ export function willMount() {
259
+ return memo(() => []);
260
+ }
261
+
262
+ /**`@effect` 别名,不能再在回调中使用 `this.effect` */
263
+ export function mounted() {
264
+ return effect(() => []);
265
+ }
266
+
267
+ export function template<T extends GemElement, V extends () => TemplateResult | null | undefined>(
268
+ /** 当所有 `template` 返回 `false` 时不进行更新,包括 `memo` */
269
+ condition?: (instance: T) => boolean,
270
+ ) {
271
+ return function (
272
+ _: any,
273
+ { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
274
+ ) {
275
+ addInitializer(function (this: T) {
276
+ createTemplate(this, {
277
+ render: access.get(this).bind(this),
278
+ condition: condition && (() => condition(this) as any),
279
+ });
280
+ });
281
+ };
282
+ }
283
+
284
+ export function fallback<T extends GemElement, V extends (err: any) => TemplateResult | null | undefined>() {
285
+ return function (
286
+ _: any,
287
+ { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
288
+ ) {
289
+ addInitializer(function (this: T) {
290
+ this.addEventListener(RenderErrorEvent, ({ detail }: CustomEvent) => {
291
+ render(access.get(this).apply(this, [detail]), this.internals.shadowRoot || this);
292
+ });
293
+ });
294
+ };
295
+ }
296
+
297
+ function defineCSSState(target: GemElementPrototype, prop: string, stateStr: string) {
298
+ defineProperty(target, prop, {
299
+ configurable: true,
300
+ get() {
301
+ const that = this as GemElement;
302
+ const { states } = that.internals;
303
+ return states?.has(stateStr);
304
+ },
305
+ set(v: boolean) {
306
+ const that = this as GemElement;
307
+ const { states } = that.internals;
308
+ if (v) {
309
+ states?.add(stateStr);
310
+ } else {
311
+ states?.delete(stateStr);
312
+ }
313
+ },
314
+ });
88
315
  }
89
316
 
90
317
  /**
@@ -100,10 +327,37 @@ export function property(target: GemElementPrototype, prop: string) {
100
327
  * }
101
328
  * ```
102
329
  */
103
- export function state(target: GemElementPrototype, prop: string) {
330
+ export function state<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, boolean>) {
331
+ context.addInitializer(function (this: T) {
332
+ const target = getPrototypeOf(this);
333
+ const prop = context.name as string;
334
+ if (!target.hasOwnProperty(prop)) {
335
+ const attr = camelToKebabCase(prop);
336
+ pushStaticField(context, 'definedCSSStates', attr);
337
+ defineCSSState(target, prop, attr);
338
+ }
339
+ clearField(this, prop);
340
+ });
341
+ }
342
+
343
+ function defineStaticField(
344
+ context: ClassFieldDecoratorContext<any, string>,
345
+ target: any,
346
+ field: StaticField,
347
+ value: string,
348
+ ) {
349
+ const prop = context.name as string;
104
350
  const attr = camelToKebabCase(prop);
105
- pushStaticField(target, 'defineCSSStates', attr);
106
- defineCSSState(target, prop, attr);
351
+ if (context.static) {
352
+ pushStaticField(context, field, attr);
353
+ } else {
354
+ const proto = getPrototypeOf(target);
355
+ if (!proto[prop]) {
356
+ proto[prop] = attr;
357
+ pushStaticField(context, field, attr);
358
+ }
359
+ }
360
+ return value || attr;
107
361
  }
108
362
 
109
363
  /**
@@ -117,10 +371,10 @@ export function state(target: GemElementPrototype, prop: string) {
117
371
  * }
118
372
  * ```
119
373
  */
120
- export function slot(target: any, prop: string) {
121
- const attr = camelToKebabCase((target as any)[prop] || prop);
122
- (target as any)[prop] = attr;
123
- pushStaticField(target instanceof GemElement ? target : target.prototype, 'defineSlots', attr);
374
+ export function slot(_: undefined, context: ClassFieldDecoratorContext<any, string>) {
375
+ return function (this: any, value: string) {
376
+ return defineStaticField(context, this, 'definedSlots', value);
377
+ };
124
378
  }
125
379
 
126
380
  /**
@@ -134,13 +388,13 @@ export function slot(target: any, prop: string) {
134
388
  * }
135
389
  * ```
136
390
  */
137
- export function part(target: any, prop: string) {
138
- const attr = camelToKebabCase((target as any)[prop] || prop);
139
- (target as any)[prop] = attr;
140
- pushStaticField(target instanceof GemElement ? target : target.prototype, 'defineParts', attr);
391
+ export function part(_: undefined, context: ClassFieldDecoratorContext<any, string>) {
392
+ return function (this: any, value: string) {
393
+ return defineStaticField(context, this, 'definedParts', value);
394
+ };
141
395
  }
142
396
 
143
- export type Emitter<T = any> = (detail: T, options?: Omit<CustomEventInit<unknown>, 'detail'>) => void;
397
+ export type Emitter<T = any> = (detail?: T, options?: Omit<CustomEventInit<unknown>, 'detail'>) => void;
144
398
 
145
399
  /**
146
400
  * 定义一个事件发射器,类似 `HTMLElement.click`,
@@ -153,20 +407,33 @@ export type Emitter<T = any> = (detail: T, options?: Omit<CustomEventInit<unknow
153
407
  * }
154
408
  * ```
155
409
  */
156
- export function emitter(target: GemElementPrototype, prop: string) {
157
- defineEmitter(target, prop);
410
+ export function emitter<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, Emitter>) {
411
+ context.addInitializer(function (this: T) {
412
+ defineEmitter(context, this, context.name as string);
413
+ });
158
414
  }
159
- export function globalemitter(target: GemElementPrototype, prop: string) {
160
- defineEmitter(target, prop, { bubbles: true, composed: true });
415
+ export function globalemitter<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, Emitter>) {
416
+ context.addInitializer(function (this: T) {
417
+ defineEmitter(context, this, context.name as string, { bubbles: true, composed: true });
418
+ });
161
419
  }
162
- function defineEmitter(target: GemElementPrototype, prop: string, options?: Omit<CustomEventInit<unknown>, 'detail'>) {
163
- const event = camelToKebabCase(prop);
164
- pushStaticField(target, 'defineEvents', event);
165
- defineProperty(target, prop, event, options);
420
+ function defineEmitter(
421
+ context: ClassFieldDecoratorContext,
422
+ t: GemElement,
423
+ prop: string,
424
+ eventOptions?: Omit<CustomEventInit<unknown>, 'detail'>,
425
+ ) {
426
+ const target = getPrototypeOf(t);
427
+ if (!target.hasOwnProperty(prop)) {
428
+ const event = camelToKebabCase(prop);
429
+ pushStaticField(context, 'definedEvents', event);
430
+ defineProp(target, prop, { event, eventOptions });
431
+ }
432
+ clearField(t, prop);
166
433
  }
167
434
 
168
435
  /**
169
- * 分配一个构造的样式表,如果元素是 lightDOM,则将样式表挂载到 RootNode 上
436
+ * 分配一个构造的样式表,前面的优先级越高(因为装饰器是越近越早执行)
170
437
  *
171
438
  * For example
172
439
  * ```ts
@@ -174,10 +441,9 @@ function defineEmitter(target: GemElementPrototype, prop: string, options?: Omit
174
441
  * class App extends GemElement {}
175
442
  * ```
176
443
  */
177
- export function adoptedStyle(style: Sheet<unknown>) {
178
- return function (cls: unknown) {
179
- const con = cls as GemElementConstructor;
180
- pushStaticField(con.prototype, 'adoptedStyleSheets', style);
444
+ export function adoptedStyle(sheet: ReturnType<typeof createCSSSheet>) {
445
+ return function (_: unknown, context: ClassDecoratorContext) {
446
+ pushStaticField(context, 'adoptedStyleSheets', sheet);
181
447
  };
182
448
  }
183
449
 
@@ -191,25 +457,41 @@ export function adoptedStyle(style: Sheet<unknown>) {
191
457
  * ```
192
458
  */
193
459
  export function connectStore(store: Store<unknown>) {
194
- return function (cls: unknown) {
195
- const con = cls as GemElementConstructor;
196
- pushStaticField(con.prototype, 'observedStores', store);
460
+ return function (_: unknown, context: ClassDecoratorContext) {
461
+ pushStaticField(context, 'observedStores', store);
462
+ };
463
+ }
464
+
465
+ export function shadow({
466
+ mode = 'open',
467
+ serializable = true,
468
+ delegatesFocus,
469
+ slotAssignment,
470
+ }: Partial<ShadowRootInit> = {}) {
471
+ return function (_: any, context: ClassDecoratorContext) {
472
+ const metadata = context.metadata as Metadata;
473
+ assign(metadata, { mode, serializable, delegatesFocus, slotAssignment });
197
474
  };
198
475
  }
199
476
 
200
477
  /**
201
- * 限制元素的 root 节点类型
202
- *
203
- * For example
204
- * ```ts
205
- * @rootElement('my-element')
206
- * class App extends GemElement {}
207
- * ```
478
+ * 将元素标记为可中断异步渲染
479
+ * 例如:https://examples.gemjs.org/async
480
+ */
481
+ export function async() {
482
+ return function (_: any, context: ClassDecoratorContext) {
483
+ const metadata = context.metadata as Metadata;
484
+ metadata.noBlocking = true;
485
+ };
486
+ }
487
+
488
+ /**
489
+ * 定义元素的可访问性属性
208
490
  */
209
- export function rootElement(rootType: string) {
210
- return function (cls: unknown) {
211
- const con = cls as GemElementConstructor;
212
- con.rootElement = rootType;
491
+ export function aria(info: Metadata['aria']) {
492
+ return function (_: any, context: ClassDecoratorContext) {
493
+ const metadata = context.metadata as Metadata;
494
+ metadata.aria = { ...metadata.aria, ...info };
213
495
  };
214
496
  }
215
497
 
@@ -223,7 +505,26 @@ export function rootElement(rootType: string) {
223
505
  * ```
224
506
  */
225
507
  export function customElement(name: string) {
226
- return function (cls: unknown) {
227
- nativeDefineElement(name, cls as CustomElementConstructor);
508
+ return function (cls: new (...args: any) => any, { addInitializer }: ClassDecoratorContext) {
509
+ addInitializer(function () {
510
+ customElements.define(name, cls);
511
+ });
228
512
  };
229
513
  }
514
+
515
+ declare global {
516
+ interface Window {
517
+ __GEM_DEVTOOLS__HOOK__?:
518
+ | (typeof elementExports & typeof decoratorsExports & typeof storeExports & typeof versionExports)
519
+ | Record<string, never>;
520
+ }
521
+ }
522
+
523
+ if (window.__GEM_DEVTOOLS__HOOK__ && !window.__GEM_DEVTOOLS__HOOK__.GemElement) {
524
+ assign(window.__GEM_DEVTOOLS__HOOK__, {
525
+ ...elementExports,
526
+ ...decoratorsExports,
527
+ ...storeExports,
528
+ ...versionExports,
529
+ });
530
+ }
@@ -0,0 +1,6 @@
1
+ export { repeat } from 'lit-html/directives/repeat';
2
+
3
+ // https://github.com/Polymer/lit-html/issues/1048
4
+ export { guard } from 'lit-html/directives/guard';
5
+
6
+ export { ifDefined } from 'lit-html/directives/if-defined';