@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.
- package/dist/gem.es.js +2082 -2153
- package/dist/gem.umd.js +25 -199
- package/elements/base/dialog.d.ts +1 -5
- package/elements/base/dialog.d.ts.map +1 -1
- package/elements/base/dialog.js +2 -6
- package/elements/base/dialog.js.map +1 -1
- package/elements/base/gesture.d.ts +6 -15
- package/elements/base/gesture.d.ts.map +1 -1
- package/elements/base/gesture.js +38 -34
- package/elements/base/gesture.js.map +1 -1
- package/elements/base/link.d.ts +1 -17
- package/elements/base/link.d.ts.map +1 -1
- package/elements/base/link.js +12 -37
- package/elements/base/link.js.map +1 -1
- package/elements/base/modal-factory.d.ts +48 -38
- package/elements/base/modal-factory.d.ts.map +1 -1
- package/elements/base/modal-factory.js +14 -14
- package/elements/base/modal-factory.js.map +1 -1
- package/elements/base/reflect.d.ts +1 -5
- package/elements/base/reflect.d.ts.map +1 -1
- package/elements/base/reflect.js +8 -13
- package/elements/base/reflect.js.map +1 -1
- package/elements/base/route.d.ts +17 -17
- package/elements/base/route.d.ts.map +1 -1
- package/elements/base/route.js +15 -27
- package/elements/base/route.js.map +1 -1
- package/elements/base/title.d.ts +1 -6
- package/elements/base/title.d.ts.map +1 -1
- package/elements/base/title.js +3 -8
- package/elements/base/title.js.map +1 -1
- package/elements/base/unsafe.d.ts +1 -6
- package/elements/base/unsafe.d.ts.map +1 -1
- package/elements/base/unsafe.js +3 -9
- package/elements/base/unsafe.js.map +1 -1
- package/elements/base/use.d.ts +1 -4
- package/elements/base/use.d.ts.map +1 -1
- package/elements/base/use.js +4 -11
- package/elements/base/use.js.map +1 -1
- package/elements/link.js +1 -1
- package/elements/link.js.map +1 -1
- package/elements/route.js +1 -1
- package/elements/route.js.map +1 -1
- package/helper/hmr.d.ts +11 -0
- package/helper/hmr.d.ts.map +1 -0
- package/helper/hmr.js +255 -0
- package/helper/hmr.js.map +1 -0
- package/helper/i18n.d.ts +2 -2
- package/helper/i18n.d.ts.map +1 -1
- package/helper/i18n.js +5 -4
- package/helper/i18n.js.map +1 -1
- package/helper/logger.d.ts +1 -1
- package/helper/logger.d.ts.map +1 -1
- package/helper/logger.js +8 -5
- package/helper/logger.js.map +1 -1
- package/helper/mediaquery.js +1 -1
- package/helper/mediaquery.js.map +1 -1
- package/helper/ssr-shim.d.ts.map +1 -1
- package/helper/ssr-shim.js +2 -0
- package/helper/ssr-shim.js.map +1 -1
- package/helper/theme.d.ts +4 -5
- package/helper/theme.d.ts.map +1 -1
- package/helper/theme.js +3 -3
- package/helper/theme.js.map +1 -1
- package/index.d.ts +1 -3
- package/index.d.ts.map +1 -1
- package/index.js +1 -4
- package/index.js.map +1 -1
- package/lib/decorators.d.ts +9 -16
- package/lib/decorators.d.ts.map +1 -1
- package/lib/decorators.js +84 -71
- package/lib/decorators.js.map +1 -1
- package/lib/directive.d.ts +65 -0
- package/lib/directive.d.ts.map +1 -0
- package/lib/directive.js +58 -0
- package/lib/directive.js.map +1 -0
- package/lib/element.d.ts +10 -153
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +19 -480
- package/lib/element.js.map +1 -1
- package/lib/history.d.ts +67 -9
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +12 -12
- package/lib/history.js.map +1 -1
- package/lib/lit-html.d.ts +232 -0
- package/lib/lit-html.d.ts.map +1 -0
- package/lib/lit-html.js +987 -0
- package/lib/lit-html.js.map +1 -0
- package/lib/reactive.d.ts +123 -0
- package/lib/reactive.d.ts.map +1 -0
- package/lib/reactive.js +478 -0
- package/lib/reactive.js.map +1 -0
- package/lib/repeat.d.ts +126 -0
- package/lib/repeat.d.ts.map +1 -0
- package/lib/repeat.js +533 -0
- package/lib/repeat.js.map +1 -0
- package/lib/store.d.ts +13 -2
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +5 -4
- package/lib/store.js.map +1 -1
- package/lib/utils.d.ts +24 -15
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +25 -30
- package/lib/utils.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +8 -9
- package/src/dist.ts +6 -8
- package/src/elements/base/dialog.ts +2 -6
- package/src/elements/base/gesture.ts +35 -36
- package/src/elements/base/link.ts +20 -46
- package/src/elements/base/modal-factory.ts +14 -14
- package/src/elements/base/reflect.ts +2 -6
- package/src/elements/base/route.ts +22 -33
- package/src/elements/base/title.ts +4 -9
- package/src/elements/base/unsafe.ts +4 -9
- package/src/elements/base/use.ts +4 -11
- package/src/elements/link.ts +1 -1
- package/src/elements/route.ts +1 -1
- package/src/helper/hmr.ts +305 -0
- package/src/helper/i18n.ts +7 -7
- package/src/helper/logger.ts +9 -5
- package/src/helper/mediaquery.ts +1 -1
- package/src/helper/ssr-shim.ts +3 -0
- package/src/helper/theme.ts +6 -6
- package/src/index.ts +1 -5
- package/src/lib/decorators.ts +101 -100
- package/src/lib/directive.ts +137 -0
- package/src/lib/element.ts +26 -614
- package/src/lib/history.ts +14 -15
- package/src/lib/lit-html.ts +1269 -0
- package/src/lib/reactive.ts +596 -0
- package/src/lib/repeat.ts +580 -0
- package/src/lib/store.ts +5 -4
- package/src/lib/utils.ts +40 -46
- package/src/lib/version.ts +1 -1
- package/src/test/elements/link.test.ts +2 -3
- package/src/test/elements/reflect.test.ts +13 -3
- package/src/test/elements/title.test.ts +2 -3
- package/src/test/gem-element/advance.test.ts +22 -14
- package/src/test/gem-element/basic.test.ts +23 -11
- package/src/test/gem-element/decorators.test.ts +14 -17
- package/src/test/gem-element/multi.test.ts +20 -11
- package/src/test/history.test.ts +1 -2
- package/src/test/store.test.ts +3 -4
- package/src/test/utils.test.ts +12 -14
- package/src/test/utils.ts +22 -0
- package/lib/directives.d.ts +0 -4
- package/lib/directives.d.ts.map +0 -1
- package/lib/directives.js +0 -5
- package/lib/directives.js.map +0 -1
- package/src/lib/directives.ts +0 -6
package/src/helper/logger.ts
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
export class Logger {
|
|
2
|
-
|
|
2
|
+
#type: string;
|
|
3
|
+
|
|
4
|
+
get #prefix() {
|
|
5
|
+
return `[${this.#type}]`;
|
|
6
|
+
}
|
|
3
7
|
|
|
4
8
|
constructor(type: string) {
|
|
5
|
-
this
|
|
9
|
+
this.#type = type;
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
info = (...args: any[]) => {
|
|
9
|
-
console.log(
|
|
13
|
+
console.log(this.#prefix, ...args);
|
|
10
14
|
};
|
|
11
15
|
|
|
12
16
|
warn = (...args: any[]) => {
|
|
13
|
-
console.warn(
|
|
17
|
+
console.warn(this.#prefix, ...args);
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
error = (...args: any[]) => {
|
|
17
|
-
console.error(
|
|
21
|
+
console.error(this.#prefix, ...args);
|
|
18
22
|
};
|
|
19
23
|
}
|
|
20
24
|
|
package/src/helper/mediaquery.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// https://gist.github.com/gokulkrishh/242e68d1ee94ad05f488
|
|
2
2
|
// https://mediag.com/news/popular-screen-resolutions-designing-for-all/
|
|
3
3
|
|
|
4
|
-
const match = (query: string) =>
|
|
4
|
+
const match = (query: string) => matchMedia(query).matches;
|
|
5
5
|
|
|
6
6
|
export const mediaQuery = {
|
|
7
7
|
PRINT: 'print',
|
package/src/helper/ssr-shim.ts
CHANGED
package/src/helper/theme.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import type { GemElement, Sheet } from '../lib/reactive';
|
|
2
|
+
import { css, SheetToken } from '../lib/reactive';
|
|
1
3
|
import type { Store } from '../lib/store';
|
|
2
4
|
import { connect, createStore } from '../lib/store';
|
|
3
5
|
import { camelToKebabCase, createUpdater, randomStr } from '../lib/utils';
|
|
4
|
-
import type { GemElement } from '../lib/element';
|
|
5
|
-
import { SheetToken, createCSSSheet } from '../lib/element';
|
|
6
6
|
|
|
7
7
|
export type Theme<T> = ReturnType<typeof createUpdater<T>> &
|
|
8
|
-
|
|
8
|
+
Sheet<unknown> & {
|
|
9
9
|
[K in keyof T as K extends `${string}Color`
|
|
10
10
|
? `${string & K}${'' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900}`
|
|
11
|
-
: K]:
|
|
11
|
+
: K]: string;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
const themeStoreMap = new WeakMap();
|
|
@@ -26,7 +26,7 @@ export function getThemeProps<T>(theme: Theme<T>) {
|
|
|
26
26
|
|
|
27
27
|
function createThemeFromProps<T extends Record<string, unknown>>(themeObj: T, props: Record<string, string> = {}) {
|
|
28
28
|
const salt = randomStr();
|
|
29
|
-
const styleSheet =
|
|
29
|
+
const styleSheet = css({})[SheetToken];
|
|
30
30
|
const store = createStore<T>(themeObj);
|
|
31
31
|
const theme: any = new Proxy(
|
|
32
32
|
createUpdater({ [SheetToken]: styleSheet }, (payload: Partial<T>) => store(payload)),
|
|
@@ -63,7 +63,7 @@ function createThemeFromProps<T extends Record<string, unknown>>(themeObj: T, pr
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
* 用于 `@adoptedStyle(theme)`,类似 `
|
|
66
|
+
* 用于 `@adoptedStyle(theme)`,类似 `css`
|
|
67
67
|
*/
|
|
68
68
|
export function createScopedTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
69
69
|
return createThemeFromProps(themeObj);
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
export * from './lib/decorators';
|
|
2
1
|
export * from './lib/element';
|
|
2
|
+
export * from './lib/history';
|
|
3
3
|
export * from './lib/store';
|
|
4
4
|
export * from './lib/utils';
|
|
5
5
|
export * from './lib/version';
|
|
6
|
-
|
|
7
|
-
// 使用路径时可选模块
|
|
8
|
-
export * from './lib/history';
|
|
9
|
-
export * from './lib/directives';
|
package/src/lib/decorators.ts
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type { TemplateResult } from './lit-html';
|
|
2
|
+
import type { Metadata, Sheet } from './reactive';
|
|
3
|
+
import { _createTemplate, _RenderErrorEvent, GemElement, render, UpdateToken } from './reactive';
|
|
4
4
|
import type { Store } from './store';
|
|
5
|
-
import
|
|
6
|
-
import * as decoratorsExports from './decorators';
|
|
7
|
-
import * as storeExports from './store';
|
|
8
|
-
import * as versionExports from './version';
|
|
5
|
+
import { camelToKebabCase, GemError, PropProxyMap } from './utils';
|
|
9
6
|
|
|
10
|
-
type GemElementPrototype = GemElement;
|
|
7
|
+
type GemElementPrototype = GemElement & { '': never };
|
|
11
8
|
type StaticField = Exclude<keyof Metadata, keyof ShadowRootInit | 'aria' | 'noBlocking' | 'penetrable'>;
|
|
12
9
|
|
|
13
10
|
const { deleteProperty, getOwnPropertyDescriptor, defineProperty } = Reflect;
|
|
14
|
-
const { getPrototypeOf, assign } = Object;
|
|
11
|
+
const { getPrototypeOf, assign, hasOwn } = Object;
|
|
15
12
|
const gemElementProxyMap = new PropProxyMap<GemElement>();
|
|
16
13
|
|
|
17
14
|
function pushStaticField(context: ClassFieldDecoratorContext | ClassDecoratorContext, field: StaticField, member: any) {
|
|
18
15
|
const metadata = context.metadata as Metadata;
|
|
19
16
|
if (!getOwnPropertyDescriptor(metadata, field)) {
|
|
20
17
|
// 继承基类
|
|
21
|
-
const current = new Set<unknown>(metadata[field]);
|
|
22
|
-
current.delete(member);
|
|
23
18
|
defineProperty(metadata, field, {
|
|
24
|
-
value: [
|
|
19
|
+
value: metadata[field]?.filter((e) => e !== member) || [],
|
|
25
20
|
});
|
|
26
21
|
}
|
|
27
22
|
|
|
@@ -29,7 +24,8 @@ function pushStaticField(context: ClassFieldDecoratorContext | ClassDecoratorCon
|
|
|
29
24
|
}
|
|
30
25
|
|
|
31
26
|
function clearField<T extends GemElement>(instance: T, prop: string) {
|
|
32
|
-
|
|
27
|
+
// hmr 支持不存在属性
|
|
28
|
+
const { value } = getOwnPropertyDescriptor(instance, prop) || {};
|
|
33
29
|
deleteProperty(instance, prop);
|
|
34
30
|
(instance as any)[prop] = value;
|
|
35
31
|
}
|
|
@@ -39,18 +35,19 @@ const observedTargetAttributes = new WeakMap<GemElementPrototype, Map<string, st
|
|
|
39
35
|
// 不在 Devtools 中工作 https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#dom_access
|
|
40
36
|
// 使用 Gem DevTools 注入脚本监听 attribute 变化
|
|
41
37
|
const { setAttribute, toggleAttribute, removeAttribute } = Element.prototype;
|
|
38
|
+
const getObservedPropName = (i: GemElement, n: string) => observedTargetAttributes.get(getPrototypeOf(i))?.get(n);
|
|
42
39
|
GemElement.prototype.setAttribute = function (n: string, v: string) {
|
|
43
|
-
const prop =
|
|
40
|
+
const prop = getObservedPropName(this, n);
|
|
44
41
|
if (!prop) return setAttribute.call(this, n, v);
|
|
45
42
|
(this as any)[prop] = v;
|
|
46
43
|
};
|
|
47
44
|
GemElement.prototype.removeAttribute = function (n: string) {
|
|
48
|
-
const prop =
|
|
45
|
+
const prop = getObservedPropName(this, n);
|
|
49
46
|
if (!prop) return removeAttribute.call(this, n);
|
|
50
47
|
(this as any)[prop] = null;
|
|
51
48
|
};
|
|
52
49
|
GemElement.prototype.toggleAttribute = function (n: string, force?: boolean) {
|
|
53
|
-
const prop =
|
|
50
|
+
const prop = getObservedPropName(this, n);
|
|
54
51
|
if (!prop) return toggleAttribute.call(this, n, force);
|
|
55
52
|
return ((this as any)[prop] = force ?? !this.hasAttribute(n));
|
|
56
53
|
};
|
|
@@ -96,10 +93,13 @@ function defineProp(
|
|
|
96
93
|
if (event) {
|
|
97
94
|
proxy[prop] = v?.[isEventHandleSymbol]
|
|
98
95
|
? v
|
|
99
|
-
: (detail: any, options: any) => {
|
|
96
|
+
: async (detail: any, options: any) => {
|
|
97
|
+
// 事件如果同步触发,则祖先元素可能还没有挂载好,其中就不能更新 state
|
|
98
|
+
// https://github.com/mantou132/gem/issues/203
|
|
99
|
+
await Promise.resolve();
|
|
100
100
|
const evt = new CustomEvent(event, { ...options, ...eventOptions, detail });
|
|
101
101
|
that.dispatchEvent(evt);
|
|
102
|
-
v(detail, options);
|
|
102
|
+
await v(detail, options);
|
|
103
103
|
};
|
|
104
104
|
(proxy[prop] as any)[isEventHandleSymbol] = true;
|
|
105
105
|
// emitter 不触发元素更新
|
|
@@ -111,21 +111,35 @@ function defineProp(
|
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
// https://github.com/tc39/proposal-decorators/issues/517
|
|
115
|
+
const targetCache = new WeakMap<DecoratorMetadataObject, GemElementPrototype>();
|
|
116
|
+
function getDecoratorTarget(element: GemElement, { metadata }: ClassMemberDecoratorContext) {
|
|
117
|
+
const target = targetCache.get(metadata);
|
|
118
|
+
if (target) return target;
|
|
119
|
+
let result = element as GemElementPrototype;
|
|
120
|
+
do {
|
|
121
|
+
result = getPrototypeOf(result);
|
|
122
|
+
} while (result.constructor[Symbol.metadata] !== metadata);
|
|
123
|
+
targetCache.set(metadata, result);
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
114
127
|
type AttrType = BooleanConstructor | NumberConstructor | StringConstructor;
|
|
115
128
|
function decoratorAttr<T extends GemElement>(context: ClassFieldDecoratorContext<T>, attrType: AttrType) {
|
|
116
129
|
const prop = context.name as string;
|
|
117
130
|
const attr = camelToKebabCase(prop);
|
|
118
131
|
context.addInitializer(function (this: T) {
|
|
119
|
-
const target =
|
|
120
|
-
if (!target
|
|
132
|
+
const target = getDecoratorTarget(this, context);
|
|
133
|
+
if (!hasOwn(target, prop)) {
|
|
121
134
|
pushStaticField(context, 'observedAttributes', attr); // 没有 observe 的效果
|
|
122
135
|
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
136
|
}
|
|
128
137
|
clearField(this, prop);
|
|
138
|
+
// 记录观察的 attribute, 用于 hack 的 setAttribute
|
|
139
|
+
const proto = getPrototypeOf(this);
|
|
140
|
+
const attrMap = observedTargetAttributes.get(proto) || new Map<string, string>();
|
|
141
|
+
attrMap.set(attr, prop);
|
|
142
|
+
observedTargetAttributes.set(proto, attrMap);
|
|
129
143
|
});
|
|
130
144
|
// 延时定义的元素需要继承原实例属性值
|
|
131
145
|
return function (this: any, initValue: any) {
|
|
@@ -166,8 +180,8 @@ export function numattribute<T extends GemElement>(_: undefined, context: ClassF
|
|
|
166
180
|
export function property<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T>) {
|
|
167
181
|
const prop = context.name as string;
|
|
168
182
|
context.addInitializer(function (this: T) {
|
|
169
|
-
const target =
|
|
170
|
-
if (!target
|
|
183
|
+
const target = getDecoratorTarget(this, context);
|
|
184
|
+
if (!hasOwn(target, prop)) {
|
|
171
185
|
pushStaticField(context, 'observedProperties', prop);
|
|
172
186
|
defineProp(target, prop);
|
|
173
187
|
}
|
|
@@ -195,33 +209,42 @@ export function property<T extends GemElement>(_: undefined, context: ClassField
|
|
|
195
209
|
export function memo<T extends GemElement, V = any, K = any[] | undefined>(
|
|
196
210
|
getDep?: K extends readonly any[] ? (instance: T) => K : undefined,
|
|
197
211
|
) {
|
|
198
|
-
return
|
|
212
|
+
return (
|
|
199
213
|
_: any,
|
|
200
214
|
context: ClassGetterDecoratorContext<T, V> | ClassFieldDecoratorContext<T> | ClassMethodDecoratorContext<T>,
|
|
201
|
-
) {
|
|
215
|
+
) => {
|
|
202
216
|
const { addInitializer, name, access, kind } = context;
|
|
203
217
|
addInitializer(function (this: T) {
|
|
204
218
|
const dep = getDep && (() => getDep(this) as any);
|
|
205
219
|
if (kind === 'getter') {
|
|
206
220
|
// 不能设置私有字段 https://github.com/tc39/proposal-decorators/issues/509
|
|
207
221
|
if (context.private) throw new GemError('not support');
|
|
208
|
-
|
|
222
|
+
const target = getDecoratorTarget(this, context as any);
|
|
223
|
+
// 不能直接用 `access.get.bind(this)` 是现有 builder 工具的 bug?
|
|
224
|
+
const getter = getOwnPropertyDescriptor(target, name)!.get!.bind(this);
|
|
225
|
+
this.memo(() => {
|
|
226
|
+
defineProperty(this, name, {
|
|
227
|
+
configurable: true,
|
|
228
|
+
value: getter(),
|
|
229
|
+
});
|
|
230
|
+
}, dep);
|
|
209
231
|
} else {
|
|
210
|
-
this.memo((access.get(this) as any).bind(this)
|
|
232
|
+
this.memo((access.get.call(this, this) as any).bind(this), dep);
|
|
211
233
|
}
|
|
212
234
|
});
|
|
213
235
|
};
|
|
214
236
|
}
|
|
215
237
|
|
|
216
238
|
/**
|
|
217
|
-
* 依赖 `GemElement.effect`
|
|
218
|
-
* 方法执行在字段前面
|
|
239
|
+
* - 依赖 `GemElement.effect`
|
|
240
|
+
* - 方法执行在字段前面
|
|
241
|
+
* - 如果没有 oldValue,在为首次执行
|
|
219
242
|
*
|
|
220
243
|
* For example
|
|
221
244
|
* ```ts
|
|
222
245
|
* class App extends GemElement {
|
|
223
246
|
* @effect(() => [])
|
|
224
|
-
* #fetchData() {
|
|
247
|
+
* #fetchData(newValue, oldValue) {
|
|
225
248
|
* console.log('fetch')
|
|
226
249
|
* }
|
|
227
250
|
* }
|
|
@@ -230,24 +253,18 @@ export function memo<T extends GemElement, V = any, K = any[] | undefined>(
|
|
|
230
253
|
export function effect<T extends GemElement, V extends (depValues: K, oldDepValues?: K) => any, K = any[] | undefined>(
|
|
231
254
|
getDep?: K extends readonly any[] ? (instance: T) => K : undefined,
|
|
232
255
|
) {
|
|
233
|
-
return
|
|
234
|
-
_: any,
|
|
235
|
-
{ addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
|
|
236
|
-
) {
|
|
256
|
+
return (_: any, { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>) => {
|
|
237
257
|
addInitializer(function (this: T) {
|
|
238
|
-
this.effect(access.get(this).bind(this) as any, getDep && (() => getDep(this) as any));
|
|
258
|
+
this.effect(access.get.call(this, this).bind(this) as any, getDep && (() => getDep(this) as any));
|
|
239
259
|
});
|
|
240
260
|
};
|
|
241
261
|
}
|
|
242
262
|
|
|
243
263
|
export function unmounted<T extends GemElement, V extends () => any>() {
|
|
244
|
-
return
|
|
245
|
-
_: any,
|
|
246
|
-
{ addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
|
|
247
|
-
) {
|
|
264
|
+
return (_: any, { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>) => {
|
|
248
265
|
addInitializer(function (this: T) {
|
|
249
266
|
this.effect(
|
|
250
|
-
() => access.get(this).bind(this) as any,
|
|
267
|
+
() => access.get.call(this, this).bind(this) as any,
|
|
251
268
|
() => [],
|
|
252
269
|
);
|
|
253
270
|
});
|
|
@@ -268,13 +285,10 @@ export function template<T extends GemElement, V extends () => TemplateResult |
|
|
|
268
285
|
/** 当所有 `template` 返回 `false` 时不进行更新,包括 `memo` */
|
|
269
286
|
condition?: (instance: T) => boolean,
|
|
270
287
|
) {
|
|
271
|
-
return
|
|
272
|
-
_: any,
|
|
273
|
-
{ addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
|
|
274
|
-
) {
|
|
288
|
+
return (_: any, { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>) => {
|
|
275
289
|
addInitializer(function (this: T) {
|
|
276
290
|
_createTemplate(this, {
|
|
277
|
-
render: access.get(this).bind(this),
|
|
291
|
+
render: access.get.call(this, this).bind(this),
|
|
278
292
|
condition: condition && (() => condition(this) as any),
|
|
279
293
|
});
|
|
280
294
|
});
|
|
@@ -282,13 +296,10 @@ export function template<T extends GemElement, V extends () => TemplateResult |
|
|
|
282
296
|
}
|
|
283
297
|
|
|
284
298
|
export function fallback<T extends GemElement, V extends (err: any) => TemplateResult | null | undefined>() {
|
|
285
|
-
return
|
|
286
|
-
_: any,
|
|
287
|
-
{ addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>,
|
|
288
|
-
) {
|
|
299
|
+
return (_: any, { addInitializer, access }: ClassFieldDecoratorContext<T, V> | ClassMethodDecoratorContext<T, V>) => {
|
|
289
300
|
addInitializer(function (this: T) {
|
|
290
301
|
this.addEventListener(_RenderErrorEvent, ({ detail }: CustomEvent) => {
|
|
291
|
-
render(access.get(this).apply(this, [detail]), this.internals.shadowRoot || this);
|
|
302
|
+
render(access.get.call(this, this).apply(this, [detail]), this.internals.shadowRoot || this);
|
|
292
303
|
});
|
|
293
304
|
});
|
|
294
305
|
};
|
|
@@ -328,11 +339,11 @@ function defineCSSState(target: GemElementPrototype, prop: string, stateStr: str
|
|
|
328
339
|
* ```
|
|
329
340
|
*/
|
|
330
341
|
export function state<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, boolean>) {
|
|
342
|
+
const prop = context.name as string;
|
|
343
|
+
const attr = camelToKebabCase(prop);
|
|
331
344
|
context.addInitializer(function (this: T) {
|
|
332
|
-
const target =
|
|
333
|
-
|
|
334
|
-
if (!target.hasOwnProperty(prop)) {
|
|
335
|
-
const attr = camelToKebabCase(prop);
|
|
345
|
+
const target = getDecoratorTarget(this, context);
|
|
346
|
+
if (!hasOwn(target, prop)) {
|
|
336
347
|
pushStaticField(context, 'definedCSSStates', attr);
|
|
337
348
|
defineCSSState(target, prop, attr);
|
|
338
349
|
}
|
|
@@ -394,7 +405,17 @@ export function part(_: undefined, context: ClassFieldDecoratorContext<any, stri
|
|
|
394
405
|
};
|
|
395
406
|
}
|
|
396
407
|
|
|
397
|
-
|
|
408
|
+
type EmitterHandler<T> = (evt: CustomEvent<T>) => void;
|
|
409
|
+
|
|
410
|
+
export type Emitter<T = any> = ((
|
|
411
|
+
detail?: T,
|
|
412
|
+
options?: Omit<CustomEventInit<unknown>, 'detail'>,
|
|
413
|
+
) => Promise<void> | void) & {
|
|
414
|
+
/**
|
|
415
|
+
* @internal 用来为 ts plugin 提供类型签名,没有值
|
|
416
|
+
*/
|
|
417
|
+
handler?: EmitterHandler<T> | (AddEventListenerOptions & { handleEvent: EmitterHandler<T> });
|
|
418
|
+
};
|
|
398
419
|
|
|
399
420
|
/**
|
|
400
421
|
* 定义一个事件发射器,类似 `HTMLElement.click`,
|
|
@@ -408,28 +429,25 @@ export type Emitter<T = any> = (detail?: T, options?: Omit<CustomEventInit<unkno
|
|
|
408
429
|
* ```
|
|
409
430
|
*/
|
|
410
431
|
export function emitter<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, Emitter>) {
|
|
411
|
-
context
|
|
412
|
-
defineEmitter(context, this, context.name as string);
|
|
413
|
-
});
|
|
432
|
+
defineEmitter(context);
|
|
414
433
|
}
|
|
415
434
|
export function globalemitter<T extends GemElement>(_: undefined, context: ClassFieldDecoratorContext<T, Emitter>) {
|
|
416
|
-
context
|
|
417
|
-
defineEmitter(context, this, context.name as string, { bubbles: true, composed: true });
|
|
418
|
-
});
|
|
435
|
+
defineEmitter(context, { bubbles: true, composed: true });
|
|
419
436
|
}
|
|
420
|
-
function defineEmitter(
|
|
437
|
+
function defineEmitter<T extends GemElement>(
|
|
421
438
|
context: ClassFieldDecoratorContext,
|
|
422
|
-
t: GemElement,
|
|
423
|
-
prop: string,
|
|
424
439
|
eventOptions?: Omit<CustomEventInit<unknown>, 'detail'>,
|
|
425
440
|
) {
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
441
|
+
const prop = context.name as string;
|
|
442
|
+
const event = camelToKebabCase(prop);
|
|
443
|
+
context.addInitializer(function (this: T) {
|
|
444
|
+
const target = getDecoratorTarget(this, context);
|
|
445
|
+
if (!hasOwn(target, prop)) {
|
|
446
|
+
pushStaticField(context, 'definedEvents', event);
|
|
447
|
+
defineProp(target, prop, { event, eventOptions });
|
|
448
|
+
}
|
|
449
|
+
clearField(this, prop);
|
|
450
|
+
});
|
|
433
451
|
}
|
|
434
452
|
|
|
435
453
|
/**
|
|
@@ -441,8 +459,8 @@ function defineEmitter(
|
|
|
441
459
|
* class App extends GemElement {}
|
|
442
460
|
* ```
|
|
443
461
|
*/
|
|
444
|
-
export function adoptedStyle(sheet:
|
|
445
|
-
return
|
|
462
|
+
export function adoptedStyle(sheet: Sheet<unknown>) {
|
|
463
|
+
return (_: unknown, context: ClassDecoratorContext) => {
|
|
446
464
|
pushStaticField(context, 'adoptedStyleSheets', sheet);
|
|
447
465
|
};
|
|
448
466
|
}
|
|
@@ -457,7 +475,7 @@ export function adoptedStyle(sheet: ReturnType<typeof createCSSSheet>) {
|
|
|
457
475
|
* ```
|
|
458
476
|
*/
|
|
459
477
|
export function connectStore(store: Store<any>) {
|
|
460
|
-
return
|
|
478
|
+
return (_: unknown, context: ClassDecoratorContext) => {
|
|
461
479
|
pushStaticField(context, 'observedStores', store);
|
|
462
480
|
};
|
|
463
481
|
}
|
|
@@ -468,14 +486,14 @@ export function shadow({
|
|
|
468
486
|
delegatesFocus,
|
|
469
487
|
slotAssignment,
|
|
470
488
|
}: Partial<ShadowRootInit> = {}) {
|
|
471
|
-
return
|
|
489
|
+
return (_: any, context: ClassDecoratorContext) => {
|
|
472
490
|
const metadata = context.metadata as Metadata;
|
|
473
491
|
assign(metadata, { mode, serializable, delegatesFocus, slotAssignment });
|
|
474
492
|
};
|
|
475
493
|
}
|
|
476
494
|
|
|
477
495
|
export function light({ penetrable }: Pick<Metadata, 'penetrable'>) {
|
|
478
|
-
return
|
|
496
|
+
return (_: any, context: ClassDecoratorContext) => {
|
|
479
497
|
const metadata = context.metadata as Metadata;
|
|
480
498
|
metadata.penetrable = penetrable;
|
|
481
499
|
};
|
|
@@ -486,7 +504,7 @@ export function light({ penetrable }: Pick<Metadata, 'penetrable'>) {
|
|
|
486
504
|
* 例如:https://examples.gemjs.org/async
|
|
487
505
|
*/
|
|
488
506
|
export function async() {
|
|
489
|
-
return
|
|
507
|
+
return (_: any, context: ClassDecoratorContext) => {
|
|
490
508
|
const metadata = context.metadata as Metadata;
|
|
491
509
|
metadata.noBlocking = true;
|
|
492
510
|
};
|
|
@@ -496,7 +514,7 @@ export function async() {
|
|
|
496
514
|
* 定义元素的可访问性属性
|
|
497
515
|
*/
|
|
498
516
|
export function aria(info: Metadata['aria']) {
|
|
499
|
-
return
|
|
517
|
+
return (_: any, context: ClassDecoratorContext) => {
|
|
500
518
|
const metadata = context.metadata as Metadata;
|
|
501
519
|
metadata.aria = { ...metadata.aria, ...info };
|
|
502
520
|
};
|
|
@@ -512,26 +530,9 @@ export function aria(info: Metadata['aria']) {
|
|
|
512
530
|
* ```
|
|
513
531
|
*/
|
|
514
532
|
export function customElement(name: string) {
|
|
515
|
-
return
|
|
516
|
-
addInitializer(
|
|
533
|
+
return (cls: new (...args: any) => any, { addInitializer }: ClassDecoratorContext) => {
|
|
534
|
+
addInitializer(() => {
|
|
517
535
|
customElements.define(name, cls);
|
|
518
536
|
});
|
|
519
537
|
};
|
|
520
538
|
}
|
|
521
|
-
|
|
522
|
-
declare global {
|
|
523
|
-
interface Window {
|
|
524
|
-
__GEM_DEVTOOLS__HOOK__?:
|
|
525
|
-
| (typeof elementExports & typeof decoratorsExports & typeof storeExports & typeof versionExports)
|
|
526
|
-
| Record<string, never>;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
if (window.__GEM_DEVTOOLS__HOOK__ && !window.__GEM_DEVTOOLS__HOOK__.GemElement) {
|
|
531
|
-
assign(window.__GEM_DEVTOOLS__HOOK__, {
|
|
532
|
-
...elementExports,
|
|
533
|
-
...decoratorsExports,
|
|
534
|
-
...storeExports,
|
|
535
|
-
...versionExports,
|
|
536
|
-
});
|
|
537
|
-
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2017 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Disconnectable, Part } from './lit-html.js';
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
AttributePart,
|
|
11
|
+
BooleanAttributePart,
|
|
12
|
+
ChildPart,
|
|
13
|
+
ElementPart,
|
|
14
|
+
EventPart,
|
|
15
|
+
Part,
|
|
16
|
+
PropertyPart,
|
|
17
|
+
} from './lit-html.js';
|
|
18
|
+
|
|
19
|
+
export interface DirectiveClass {
|
|
20
|
+
new (part: PartInfo): Directive;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* This utility type extracts the signature of a directive class's render()
|
|
25
|
+
* method so we can use it for the type of the generated directive function.
|
|
26
|
+
*/
|
|
27
|
+
export type DirectiveParameters<C extends Directive> = Parameters<C['render']>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A generated directive function doesn't evaluate the directive, but just
|
|
31
|
+
* returns a DirectiveResult object that captures the arguments.
|
|
32
|
+
*/
|
|
33
|
+
export interface DirectiveResult<C extends DirectiveClass = DirectiveClass> {
|
|
34
|
+
/**
|
|
35
|
+
* This property needs to remain unminified.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
_$litDirective$: C;
|
|
39
|
+
/** @internal */
|
|
40
|
+
values: DirectiveParameters<InstanceType<C>>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const PartType = {
|
|
44
|
+
ATTRIBUTE: 1,
|
|
45
|
+
CHILD: 2,
|
|
46
|
+
PROPERTY: 3,
|
|
47
|
+
BOOLEAN_ATTRIBUTE: 4,
|
|
48
|
+
EVENT: 5,
|
|
49
|
+
ELEMENT: 6,
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
52
|
+
export type PartType = (typeof PartType)[keyof typeof PartType];
|
|
53
|
+
|
|
54
|
+
export interface ChildPartInfo {
|
|
55
|
+
readonly type: typeof PartType.CHILD;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface AttributePartInfo {
|
|
59
|
+
readonly type:
|
|
60
|
+
| typeof PartType.ATTRIBUTE
|
|
61
|
+
| typeof PartType.PROPERTY
|
|
62
|
+
| typeof PartType.BOOLEAN_ATTRIBUTE
|
|
63
|
+
| typeof PartType.EVENT;
|
|
64
|
+
readonly strings?: ReadonlyArray<string>;
|
|
65
|
+
readonly name: string;
|
|
66
|
+
readonly tagName: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ElementPartInfo {
|
|
70
|
+
readonly type: typeof PartType.ELEMENT;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Information about the part a directive is bound to.
|
|
75
|
+
*
|
|
76
|
+
* This is useful for checking that a directive is attached to a valid part,
|
|
77
|
+
* such as with directive that can only be used on attribute bindings.
|
|
78
|
+
*/
|
|
79
|
+
export type PartInfo = ChildPartInfo | AttributePartInfo | ElementPartInfo;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates a user-facing directive function from a Directive class. This
|
|
83
|
+
* function has the same parameters as the directive's render() method.
|
|
84
|
+
*/
|
|
85
|
+
export const directive =
|
|
86
|
+
<C extends DirectiveClass>(c: C) =>
|
|
87
|
+
(...values: DirectiveParameters<InstanceType<C>>): DirectiveResult<C> => ({
|
|
88
|
+
// This property needs to remain unminified.
|
|
89
|
+
_$litDirective$: c,
|
|
90
|
+
values,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Base class for creating custom directives. Users should extend this class,
|
|
95
|
+
* implement `render` and/or `update`, and then pass their subclass to
|
|
96
|
+
* `directive`.
|
|
97
|
+
*/
|
|
98
|
+
export abstract class Directive implements Disconnectable {
|
|
99
|
+
//@internal
|
|
100
|
+
__part!: Part;
|
|
101
|
+
//@internal
|
|
102
|
+
__attributeIndex: number | undefined;
|
|
103
|
+
//@internal
|
|
104
|
+
__directive?: Directive;
|
|
105
|
+
|
|
106
|
+
//@internal
|
|
107
|
+
_$parent!: Disconnectable;
|
|
108
|
+
|
|
109
|
+
// These will only exist on the AsyncDirective subclass
|
|
110
|
+
//@internal
|
|
111
|
+
_$disconnectableChildren?: Set<Disconnectable>;
|
|
112
|
+
// This property needs to remain unminified.
|
|
113
|
+
//@internal
|
|
114
|
+
_$notifyDirectiveConnectionChanged?(isConnected: boolean): void;
|
|
115
|
+
|
|
116
|
+
// See comment in Disconnectable interface for why this is a getter
|
|
117
|
+
get _$isConnected() {
|
|
118
|
+
return this._$parent._$isConnected;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @internal */
|
|
122
|
+
_$initialize(part: Part, parent: Disconnectable, attributeIndex: number | undefined) {
|
|
123
|
+
this.__part = part;
|
|
124
|
+
this._$parent = parent;
|
|
125
|
+
this.__attributeIndex = attributeIndex;
|
|
126
|
+
}
|
|
127
|
+
/** @internal */
|
|
128
|
+
_$resolve(part: Part, props: Array<unknown>): unknown {
|
|
129
|
+
return this.update(part, props);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
abstract render(...props: Array<unknown>): unknown;
|
|
133
|
+
|
|
134
|
+
update(_part: Part, props: Array<unknown>): unknown {
|
|
135
|
+
return this.render(...props);
|
|
136
|
+
}
|
|
137
|
+
}
|