@mantou/gem 1.7.12 → 2.0.0-alpha.0
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 +12 -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/decorators.ts
CHANGED
|
@@ -1,90 +1,317 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
28
|
+
metadata[field]!.push(member);
|
|
20
29
|
}
|
|
21
30
|
|
|
22
|
-
|
|
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
|
-
*
|
|
137
|
+
* 定义一个响应式的 attribute,驼峰字段名将自动映射到烤串 attribute,默认值为空字符串;不要覆盖定义
|
|
26
138
|
*
|
|
27
139
|
* For example
|
|
28
140
|
* ```ts
|
|
29
141
|
* class App extends GemElement {
|
|
30
|
-
* @
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
* 定义一个响应式的
|
|
157
|
+
* 定义一个响应式的 property,注意值可能为 `undefined`;不要覆盖定义
|
|
49
158
|
*
|
|
50
159
|
* For example
|
|
51
160
|
* ```ts
|
|
52
161
|
* class App extends GemElement {
|
|
53
|
-
* @
|
|
162
|
+
* @property prop: Data | undefined;
|
|
54
163
|
* }
|
|
55
164
|
* ```
|
|
56
165
|
*/
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
*
|
|
217
|
+
* 依赖 `GemElement.effect`
|
|
218
|
+
* 方法执行在字段前面
|
|
77
219
|
*
|
|
78
220
|
* For example
|
|
79
221
|
* ```ts
|
|
80
222
|
* class App extends GemElement {
|
|
81
|
-
* @
|
|
223
|
+
* @effect(() => [])
|
|
224
|
+
* #fetchData() {
|
|
225
|
+
* console.log('fetch')
|
|
226
|
+
* }
|
|
82
227
|
* }
|
|
83
228
|
* ```
|
|
84
229
|
*/
|
|
85
|
-
export function
|
|
86
|
-
|
|
87
|
-
|
|
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(
|
|
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
|
-
|
|
106
|
-
|
|
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(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
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(
|
|
157
|
-
|
|
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(
|
|
160
|
-
|
|
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(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
*
|
|
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(
|
|
178
|
-
return function (
|
|
179
|
-
|
|
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 (
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
*
|
|
202
|
-
*
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
|
210
|
-
return function (
|
|
211
|
-
const
|
|
212
|
-
|
|
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:
|
|
227
|
-
|
|
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
|
+
}
|