@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/lib/element.js
CHANGED
|
@@ -1,348 +1,408 @@
|
|
|
1
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
-
};
|
|
6
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
-
};
|
|
12
|
-
var _a, _GemElement_final, _GemElement_renderRoot, _GemElement_internals, _GemElement_isAppendReason, _GemElement_isMounted, _GemElement_isAsync, _GemElement_effectList, _GemElement_memoList, _GemElement_unmountCallback, _GemElement_exec, _GemElement_execEffect, _GemElement_execMemo, _GemElement_initEffect, _GemElement_render, _GemElement_shouldUpdate, _GemElement_updateCallback, _GemElement_update, _GemElement_updated, _GemElement_disconnectStore, _GemElement_connectedCallback, _GemElement_clearEffect;
|
|
13
1
|
import { html, render } from 'lit-html';
|
|
14
2
|
import { connect } from './store';
|
|
15
|
-
import { LinkedList, addMicrotask,
|
|
16
|
-
import * as GemExports from './element';
|
|
17
|
-
import * as VersionExports from './version';
|
|
3
|
+
import { LinkedList, addMicrotask, isArrayChange, addListener, randomStr } from './utils';
|
|
18
4
|
export { html, svg, render, directive, TemplateResult, SVGTemplateResult } from 'lit-html';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
5
|
+
const { assign, defineProperty, setPrototypeOf } = Object;
|
|
6
|
+
defineProperty(Symbol, 'metadata', { value: Symbol.for('Symbol.metadata') });
|
|
7
|
+
const execCallback = (fun) => typeof fun === 'function' && fun();
|
|
8
|
+
// 跨多个 gem 工作
|
|
9
|
+
export const SheetToken = Symbol.for('gem@sheetToken');
|
|
10
|
+
// proto prop
|
|
11
|
+
export const UpdateToken = Symbol.for('gem@update');
|
|
12
|
+
export const BoundaryCSSState = 'gem-style-boundary';
|
|
13
|
+
export const RenderErrorEvent = 'gem@render-error';
|
|
14
|
+
// fix modal-factory type error
|
|
15
|
+
const updateTokenAlias = UpdateToken;
|
|
16
|
+
const rootStyleSheetInfo = new WeakMap();
|
|
17
|
+
const rootUpdateFnMap = new WeakMap();
|
|
18
|
+
const getReflectTargets = (ele) => [...ele.querySelectorAll('[data-gem-reflect]')].map((e) => e.target);
|
|
19
|
+
class RefObject {
|
|
20
|
+
refSelector;
|
|
21
|
+
ele;
|
|
22
|
+
ref;
|
|
23
|
+
constructor(current) {
|
|
24
|
+
const ref = `ref-${randomStr()}`;
|
|
25
|
+
this.refSelector = `[ref=${ref}]`;
|
|
26
|
+
this.ele = current.internals.shadowRoot || current;
|
|
27
|
+
this.ref = ref;
|
|
28
|
+
}
|
|
29
|
+
get element() {
|
|
30
|
+
for (const e of [this.ele, ...getReflectTargets(this.ele)]) {
|
|
31
|
+
// 在 LightDOM 中可能工作很慢?
|
|
32
|
+
const result = e.querySelector(this.refSelector);
|
|
33
|
+
if (result)
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
get elements() {
|
|
38
|
+
return [this.ele, ...getReflectTargets(this.ele)]
|
|
39
|
+
.map((e) => [...e.querySelectorAll(this.refSelector)])
|
|
40
|
+
.flat();
|
|
41
|
+
}
|
|
42
|
+
toString() {
|
|
43
|
+
return this.ref;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**必须使用在字段中,否则会读取到错误的实例 */
|
|
47
|
+
export let createRef;
|
|
48
|
+
class GemCSSStyleSheet extends CSSStyleSheet {
|
|
49
|
+
#ele;
|
|
50
|
+
cssText = '';
|
|
51
|
+
get element() {
|
|
52
|
+
if (!this.#ele) {
|
|
53
|
+
this.#ele = document.createElement('style');
|
|
54
|
+
this.#ele.textContent = this.cssText;
|
|
55
|
+
this.#ele.dataset.gemStyle = '';
|
|
56
|
+
}
|
|
57
|
+
return this.#ele;
|
|
58
|
+
}
|
|
59
|
+
replaceSync(text) {
|
|
60
|
+
this.cssText = text;
|
|
61
|
+
if (this.#ele)
|
|
62
|
+
this.#ele.textContent = text;
|
|
63
|
+
super.replaceSync(text);
|
|
64
|
+
}
|
|
25
65
|
}
|
|
26
|
-
|
|
27
|
-
|
|
66
|
+
class GemCSSSheet {
|
|
67
|
+
#content = '';
|
|
68
|
+
#media = '';
|
|
69
|
+
constructor(media = '') {
|
|
70
|
+
this.#media = media;
|
|
71
|
+
}
|
|
72
|
+
setContent(v) {
|
|
73
|
+
this.#content = v;
|
|
74
|
+
}
|
|
75
|
+
// 不需要 GC
|
|
76
|
+
#record = new Map();
|
|
77
|
+
#used = new Map();
|
|
78
|
+
getStyle(host) {
|
|
79
|
+
const isLight = host && !host.internals?.shadowRoot;
|
|
80
|
+
// 对同一类 dom 只使用同一个样式表
|
|
81
|
+
const key = isLight ? host.constructor : this;
|
|
82
|
+
if (!this.#record.has(key)) {
|
|
83
|
+
const sheet = new GemCSSStyleSheet({ media: this.#media });
|
|
84
|
+
this.#record.set(key, sheet);
|
|
85
|
+
}
|
|
86
|
+
const sheet = this.#record.get(key);
|
|
87
|
+
// 只执行一次
|
|
88
|
+
if (!this.#used.has(sheet)) {
|
|
89
|
+
let style = this.#content;
|
|
90
|
+
let scope = '';
|
|
91
|
+
if (isLight) {
|
|
92
|
+
// light dom 嵌套时需要选择子元素
|
|
93
|
+
// `> *` 实际上是多范围?是否存在性能问题
|
|
94
|
+
scope = `@scope (${host.tagName}) to (:state(${BoundaryCSSState}) > *)`;
|
|
95
|
+
// 不能使用 @layer,两个 @layer 不能覆盖,只有顺序起作用
|
|
96
|
+
// 所以外部不能通过元素名称选择器来覆盖样式,除非样式在之前插入(会自动反转应用到尾部, see `appleCSSStyleSheet`)
|
|
97
|
+
style = `${scope}{ ${style} }`;
|
|
98
|
+
}
|
|
99
|
+
sheet.replaceSync(style);
|
|
100
|
+
this.#used.set(sheet, scope);
|
|
101
|
+
}
|
|
102
|
+
return sheet;
|
|
103
|
+
}
|
|
104
|
+
// 一般用于主题更新,不支持 layer
|
|
105
|
+
updateStyle() {
|
|
106
|
+
this.#used.forEach((scope, sheet) => {
|
|
107
|
+
sheet.replaceSync(scope ? `${scope}{${this.#content}}` : this.#content);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
export function createCSSSheet(mediaOrRules, rulesValue) {
|
|
112
|
+
const media = rulesValue ? mediaOrRules : '';
|
|
113
|
+
const rules = rulesValue || mediaOrRules;
|
|
114
|
+
const styleSheet = new GemCSSSheet(media);
|
|
115
|
+
const sheet = { [SheetToken]: styleSheet };
|
|
116
|
+
let style = '';
|
|
117
|
+
if (typeof rules === 'string') {
|
|
118
|
+
style = rules;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
Object.keys(rules).forEach((key) => {
|
|
122
|
+
const isScope = key === '$';
|
|
123
|
+
// 对于已经有 `-` 的保留原始 key,支持覆盖修改
|
|
124
|
+
sheet[key] = isScope || key.includes('-') ? key : `${key}-${randomStr()}`;
|
|
125
|
+
style += `${isScope ? ':scope,:host' : `.${sheet[key]}`} {${rules[key]}}`;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
styleSheet.setContent(style);
|
|
129
|
+
return sheet;
|
|
130
|
+
}
|
|
131
|
+
const updateStyleSheets = (map, sheets, value) => {
|
|
132
|
+
let needUpdate = false;
|
|
133
|
+
sheets.forEach((e) => {
|
|
134
|
+
const count = map.get(e) || 0;
|
|
135
|
+
needUpdate ||= (value === 1 && count === 0) || (value === -1 && count === 1);
|
|
136
|
+
// count 为 0 时不立即删除,以便更新时识别是否外部样式
|
|
137
|
+
// 但是只要挂载 document 的样式表就不会被 GC 了, 是否要在闲时 GC?
|
|
138
|
+
map.set(e, count + value);
|
|
139
|
+
});
|
|
140
|
+
if (needUpdate) {
|
|
141
|
+
// 避免重复更新,例如 list 元素增删,全 light dom 时 document 更新
|
|
142
|
+
addMicrotask(rootUpdateFnMap.get(map));
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const appleCSSStyleSheet = (ele, sheets) => {
|
|
146
|
+
const root = ele.getRootNode();
|
|
147
|
+
if (!rootStyleSheetInfo.has(root)) {
|
|
148
|
+
const map = new Map();
|
|
149
|
+
rootStyleSheetInfo.set(root, map);
|
|
150
|
+
rootUpdateFnMap.set(map, () => {
|
|
151
|
+
// 先找到外部样式表
|
|
152
|
+
const newSheets = root.adoptedStyleSheets.filter((e) => !map.has(e));
|
|
153
|
+
map.forEach((count, sheet) => count && newSheets.push(sheet));
|
|
154
|
+
// 外层元素的样式要放到最后,以提升优先级,但是只考虑第一次出现样式表的位置
|
|
155
|
+
root.adoptedStyleSheets = newSheets.reverse();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const map = rootStyleSheetInfo.get(root);
|
|
159
|
+
updateStyleSheets(map, sheets, 1);
|
|
160
|
+
return () => updateStyleSheets(map, sheets, -1);
|
|
161
|
+
};
|
|
162
|
+
/**必须使用在字段中,否则会读取到错误的实例 */
|
|
163
|
+
export let createState;
|
|
164
|
+
function execEffectList(list) {
|
|
165
|
+
list?.forEach((effectItem) => {
|
|
166
|
+
const { callback, getDep, values, preCallback } = effectItem;
|
|
167
|
+
const newValues = getDep?.();
|
|
168
|
+
if (!getDep || !values || isArrayChange(values, newValues)) {
|
|
169
|
+
execCallback(preCallback);
|
|
170
|
+
effectItem.preCallback = callback(newValues, values);
|
|
171
|
+
effectItem.values = newValues;
|
|
172
|
+
// 更新时也要设置,避免异步的 `#initEffect` 重复执行
|
|
173
|
+
effectItem.initialized = true;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function clearEffect(list) {
|
|
178
|
+
return list.filter((e) => {
|
|
179
|
+
execCallback(e.preCallback);
|
|
180
|
+
e.initialized = false;
|
|
181
|
+
e.values = undefined;
|
|
182
|
+
return e.fixed;
|
|
183
|
+
});
|
|
28
184
|
}
|
|
185
|
+
export let createTemplate;
|
|
29
186
|
// global render task pool
|
|
30
|
-
const
|
|
187
|
+
const noBlockingTaskList = new LinkedList();
|
|
31
188
|
const tick = (timeStamp = performance.now()) => {
|
|
32
189
|
if (performance.now() > timeStamp + 16)
|
|
33
190
|
return requestAnimationFrame(tick);
|
|
34
|
-
const task =
|
|
191
|
+
const task = noBlockingTaskList.get();
|
|
35
192
|
if (task) {
|
|
36
193
|
task();
|
|
37
194
|
tick(timeStamp);
|
|
38
195
|
}
|
|
39
196
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const initSymbol = Symbol('init');
|
|
43
|
-
const updateSymbol = Symbol('update');
|
|
197
|
+
noBlockingTaskList.addEventListener('start', () => addMicrotask(tick));
|
|
198
|
+
let currentConstructGemElement;
|
|
44
199
|
export class GemElement extends HTMLElement {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
};
|
|
74
|
-
_GemElement_exec.set(this, (list) => {
|
|
75
|
-
list === null || list === void 0 ? void 0 : list.forEach((effectItem) => {
|
|
76
|
-
const { callback, getDep, values, preCallback } = effectItem;
|
|
77
|
-
const newValues = getDep === null || getDep === void 0 ? void 0 : getDep();
|
|
78
|
-
if (!getDep || !values || isArrayChange(values, newValues)) {
|
|
79
|
-
execCallback(preCallback);
|
|
80
|
-
effectItem.preCallback = callback(newValues, values);
|
|
81
|
-
effectItem.values = newValues;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
/**
|
|
86
|
-
* 每次更新完检查依赖,执行对应的副作用回调
|
|
87
|
-
* */
|
|
88
|
-
_GemElement_execEffect.set(this, () => {
|
|
89
|
-
__classPrivateFieldGet(this, _GemElement_exec, "f").call(this, __classPrivateFieldGet(this, _GemElement_effectList, "f"));
|
|
90
|
-
});
|
|
91
|
-
_GemElement_execMemo.set(this, () => {
|
|
92
|
-
__classPrivateFieldGet(this, _GemElement_exec, "f").call(this, __classPrivateFieldGet(this, _GemElement_memoList, "f"));
|
|
93
|
-
});
|
|
94
|
-
/**
|
|
95
|
-
* @helper
|
|
96
|
-
* 记录副作用回调和值,在 `constructor`/`mounted` 中使用
|
|
97
|
-
* 回调到返回值如果是函数将再卸载时执行
|
|
98
|
-
* 第一次执行时 `oldDeps` 为空
|
|
99
|
-
*
|
|
100
|
-
* ```js
|
|
101
|
-
* class App extends GemElement {
|
|
102
|
-
* mounted() {
|
|
103
|
-
* this.effect(callback, () => [this.attrName]);
|
|
104
|
-
* }
|
|
105
|
-
* }
|
|
106
|
-
* ```
|
|
107
|
-
* */
|
|
108
|
-
this.effect = (callback, getDep) => {
|
|
109
|
-
if (!__classPrivateFieldGet(this, _GemElement_effectList, "f"))
|
|
110
|
-
__classPrivateFieldSet(this, _GemElement_effectList, [], "f");
|
|
111
|
-
const effectItem = {
|
|
112
|
-
callback,
|
|
113
|
-
getDep,
|
|
114
|
-
initialized: __classPrivateFieldGet(this, _GemElement_isMounted, "f"),
|
|
115
|
-
inConstructor: this[constructorSymbol],
|
|
200
|
+
// 禁止覆盖自定义元素原生生命周期方法
|
|
201
|
+
// https://github.com/microsoft/TypeScript/issues/21388#issuecomment-934345226
|
|
202
|
+
static #final = Symbol();
|
|
203
|
+
#renderRoot;
|
|
204
|
+
#internals;
|
|
205
|
+
#effectList = [];
|
|
206
|
+
#memoList = [];
|
|
207
|
+
#renderList = [];
|
|
208
|
+
#isAppendReason;
|
|
209
|
+
#isMounted;
|
|
210
|
+
// not in constructor 的近似值
|
|
211
|
+
#isConnected;
|
|
212
|
+
#rendering;
|
|
213
|
+
#clearStyle;
|
|
214
|
+
[updateTokenAlias]() {
|
|
215
|
+
// 避免 `connectedCallback` 中的 property 赋值造成多余更新
|
|
216
|
+
if (this.#isMounted) {
|
|
217
|
+
addMicrotask(this.#update);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
static {
|
|
221
|
+
createState = (initState) => {
|
|
222
|
+
const ele = currentConstructGemElement;
|
|
223
|
+
const state = (payload) => {
|
|
224
|
+
assign(state, payload);
|
|
225
|
+
// 避免无限刷新
|
|
226
|
+
if (!ele.#rendering)
|
|
227
|
+
addMicrotask(ele.#update);
|
|
116
228
|
};
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
};
|
|
124
|
-
/**
|
|
125
|
-
* @helper
|
|
126
|
-
* 在 `render` 前执行回调,不要在里面使用 `setState`
|
|
127
|
-
* 和 `effect` 一样接受依赖数组参数,在 `constructor`/`willMount` 中使用;
|
|
128
|
-
* 第一次执行时 `oldDeps` 为空
|
|
129
|
-
*
|
|
130
|
-
* ```js
|
|
131
|
-
* class App extends GemElement {
|
|
132
|
-
* willMount() {
|
|
133
|
-
* this.memo(() => {
|
|
134
|
-
* this.a = exec(this.attrName);
|
|
135
|
-
* }), () => [this.attrName]);
|
|
136
|
-
* }
|
|
137
|
-
* }
|
|
138
|
-
* ```
|
|
139
|
-
* */
|
|
140
|
-
this.memo = (callback, getDep) => {
|
|
141
|
-
if (!__classPrivateFieldGet(this, _GemElement_memoList, "f"))
|
|
142
|
-
__classPrivateFieldSet(this, _GemElement_memoList, [], "f");
|
|
143
|
-
__classPrivateFieldGet(this, _GemElement_memoList, "f").push({
|
|
144
|
-
callback,
|
|
145
|
-
getDep,
|
|
146
|
-
inConstructor: this[constructorSymbol],
|
|
147
|
-
});
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* 元素挂载后执行还未初始化的副作用
|
|
151
|
-
* */
|
|
152
|
-
_GemElement_initEffect.set(this, () => {
|
|
153
|
-
var _b;
|
|
154
|
-
(_b = __classPrivateFieldGet(this, _GemElement_effectList, "f")) === null || _b === void 0 ? void 0 : _b.forEach((effectItem) => {
|
|
155
|
-
const { callback, getDep, initialized } = effectItem;
|
|
156
|
-
if (!initialized) {
|
|
157
|
-
effectItem.values = getDep === null || getDep === void 0 ? void 0 : getDep();
|
|
158
|
-
effectItem.preCallback = callback(effectItem.values);
|
|
159
|
-
effectItem.initialized = true;
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
_GemElement_render.set(this, () => {
|
|
164
|
-
__classPrivateFieldGet(this, _GemElement_execMemo, "f").call(this);
|
|
165
|
-
const isLight = __classPrivateFieldGet(this, _GemElement_renderRoot, "f") === this;
|
|
166
|
-
const temp = this.render ? this.render() : isLight ? undefined : html `<slot></slot>`;
|
|
167
|
-
if (temp === undefined)
|
|
168
|
-
return;
|
|
169
|
-
render(temp, __classPrivateFieldGet(this, _GemElement_renderRoot, "f"));
|
|
170
|
-
});
|
|
171
|
-
_GemElement_shouldUpdate.set(this, () => {
|
|
172
|
-
return this.shouldUpdate ? this.shouldUpdate() : true;
|
|
173
|
-
});
|
|
174
|
-
_GemElement_updateCallback.set(this, () => {
|
|
175
|
-
if (__classPrivateFieldGet(this, _GemElement_isMounted, "f") && __classPrivateFieldGet(this, _GemElement_shouldUpdate, "f").call(this)) {
|
|
176
|
-
__classPrivateFieldGet(this, _GemElement_render, "f").call(this);
|
|
177
|
-
addMicrotask(__classPrivateFieldGet(this, _GemElement_updated, "f"));
|
|
178
|
-
addMicrotask(__classPrivateFieldGet(this, _GemElement_execEffect, "f"));
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
_GemElement_update.set(this, () => {
|
|
182
|
-
if (__classPrivateFieldGet(this, _GemElement_isAsync, "f")) {
|
|
183
|
-
asyncRenderTaskList.add(__classPrivateFieldGet(this, _GemElement_updateCallback, "f"));
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
__classPrivateFieldGet(this, _GemElement_updateCallback, "f").call(this);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
/**
|
|
190
|
-
* @helper
|
|
191
|
-
* async
|
|
192
|
-
*/
|
|
193
|
-
this.update = () => {
|
|
194
|
-
addMicrotask(__classPrivateFieldGet(this, _GemElement_update, "f"));
|
|
229
|
+
setPrototypeOf(state, null);
|
|
230
|
+
delete state.name;
|
|
231
|
+
delete state.length;
|
|
232
|
+
ele.#internals.stateList.push(state);
|
|
233
|
+
assign(state, initState);
|
|
234
|
+
return state;
|
|
195
235
|
};
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
__classPrivateFieldSet(this, _GemElement_unmountCallback, (_c = this.mounted) === null || _c === void 0 ? void 0 : _c.call(this), "f");
|
|
215
|
-
__classPrivateFieldGet(this, _GemElement_initEffect, "f").call(this);
|
|
216
|
-
if (rootElement &&
|
|
217
|
-
this.isConnected &&
|
|
218
|
-
((_d = this.getRootNode().host) === null || _d === void 0 ? void 0 : _d.tagName) !== rootElement.toUpperCase()) {
|
|
219
|
-
throw new GemError(`not allow current root type`);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
_GemElement_clearEffect.set(this, (list) => {
|
|
223
|
-
return list === null || list === void 0 ? void 0 : list.filter((e) => {
|
|
224
|
-
execCallback(e.preCallback);
|
|
225
|
-
e.initialized = false;
|
|
226
|
-
return e.inConstructor;
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
// 外部不可见,但允许类外面使用
|
|
230
|
-
addMicrotask(() => Reflect.set(this, initSymbol, false));
|
|
231
|
-
Reflect.set(this, constructorSymbol, true);
|
|
232
|
-
Reflect.set(this, initSymbol, true);
|
|
233
|
-
Reflect.set(this, updateSymbol, () => {
|
|
234
|
-
if (__classPrivateFieldGet(this, _GemElement_isMounted, "f")) {
|
|
235
|
-
addMicrotask(__classPrivateFieldGet(this, _GemElement_update, "f"));
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
__classPrivateFieldSet(this, _GemElement_isAsync, options.isAsync, "f");
|
|
239
|
-
__classPrivateFieldSet(this, _GemElement_renderRoot, options.isLight
|
|
240
|
-
? this
|
|
241
|
-
: this.attachShadow({
|
|
242
|
-
mode: options.mode || 'open',
|
|
243
|
-
delegatesFocus: options.delegatesFocus,
|
|
244
|
-
slotAssignment: options.slotAssignment,
|
|
245
|
-
}), "f");
|
|
236
|
+
createRef = () => new RefObject(currentConstructGemElement);
|
|
237
|
+
createTemplate = (ele, item) => ele.#renderList.push(item);
|
|
238
|
+
}
|
|
239
|
+
constructor() {
|
|
240
|
+
super();
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
242
|
+
currentConstructGemElement = this;
|
|
243
|
+
const { mode, serializable, delegatesFocus, slotAssignment, aria } = this.#metadata;
|
|
244
|
+
const { focusable, ...internalsAria } = aria || {};
|
|
245
|
+
this.#renderRoot = !mode ? this : this.attachShadow({ mode, serializable, delegatesFocus, slotAssignment });
|
|
246
|
+
this.#internals = this.attachInternals();
|
|
247
|
+
this.#internals.stateList = [];
|
|
248
|
+
this.#internals.sheets = [];
|
|
249
|
+
assign(this.#internals, internalsAria);
|
|
250
|
+
// light dom 添加边界,防止内容被外部样式化
|
|
251
|
+
// 特殊情况下需要手动 `delete` 边界,以应该外部样式
|
|
252
|
+
if (!mode)
|
|
253
|
+
this.#internals.states.add(BoundaryCSSState);
|
|
246
254
|
// https://stackoverflow.com/questions/43836886/failed-to-construct-customelement-error-when-javascript-file-is-placed-in-head
|
|
247
255
|
// focusable 元素一般同时具备 disabled 属性
|
|
248
256
|
// 和原生元素行为保持一致,disabled 时不触发 click 事件
|
|
249
257
|
let hasInitTabIndex;
|
|
250
|
-
this.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
root.adoptedStyleSheets = [...root.adoptedStyleSheets, ...sheets];
|
|
273
|
-
return () => {
|
|
274
|
-
root.adoptedStyleSheets = removeItems(root.adoptedStyleSheets, sheets);
|
|
275
|
-
};
|
|
276
|
-
}, () => []);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
258
|
+
this.#effectList.push({
|
|
259
|
+
fixed: true,
|
|
260
|
+
getDep: () => [this.disabled],
|
|
261
|
+
callback: ([disabled = false]) => {
|
|
262
|
+
if (hasInitTabIndex === undefined)
|
|
263
|
+
hasInitTabIndex = this.hasAttribute('tabindex');
|
|
264
|
+
this.#internals.ariaDisabled = String(disabled);
|
|
265
|
+
if (focusable && !hasInitTabIndex)
|
|
266
|
+
this.tabIndex = -Number(disabled);
|
|
267
|
+
if ((focusable || delegatesFocus) && disabled) {
|
|
268
|
+
return addListener(this, 'click', (e) => e.isTrusted && e.stopImmediatePropagation(), {
|
|
269
|
+
capture: true,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
get #metadata() {
|
|
276
|
+
return this.constructor[Symbol.metadata];
|
|
277
|
+
}
|
|
278
|
+
get #renderItem() {
|
|
279
|
+
return this.#renderList.find((e) => !e.condition || e.condition());
|
|
279
280
|
}
|
|
280
281
|
get internals() {
|
|
281
|
-
|
|
282
|
-
__classPrivateFieldSet(this, _GemElement_internals, this.attachInternals(), "f");
|
|
283
|
-
// https://groups.google.com/a/chromium.org/g/blink-dev/c/JvpHoUfhJYE?pli=1
|
|
284
|
-
// https://bugs.webkit.org/show_bug.cgi?id=215911
|
|
285
|
-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1588763
|
|
286
|
-
try {
|
|
287
|
-
__classPrivateFieldGet(this, _GemElement_internals, "f").states.add('foo');
|
|
288
|
-
__classPrivateFieldGet(this, _GemElement_internals, "f").states.delete('foo');
|
|
289
|
-
}
|
|
290
|
-
catch (_b) {
|
|
291
|
-
Reflect.defineProperty(__classPrivateFieldGet(this, _GemElement_internals, "f"), 'states', {
|
|
292
|
-
value: {
|
|
293
|
-
has: (v) => kebabToCamelCase(v) in this.dataset,
|
|
294
|
-
add: (v) => (this.dataset[kebabToCamelCase(v)] = ''),
|
|
295
|
-
delete: (v) => delete this.dataset[kebabToCamelCase(v)],
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return __classPrivateFieldGet(this, _GemElement_internals, "f");
|
|
282
|
+
return this.#internals;
|
|
301
283
|
}
|
|
302
284
|
/**
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
285
|
+
* 每次更新完检查依赖,执行对应的副作用回调
|
|
286
|
+
* */
|
|
287
|
+
#execEffect = () => {
|
|
288
|
+
execEffectList(this.#effectList);
|
|
289
|
+
};
|
|
290
|
+
#execMemo = () => {
|
|
291
|
+
execEffectList(this.#memoList);
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* - 条件渲染
|
|
295
|
+
* - 不提供 `render` 时显示子内容
|
|
296
|
+
* - 返回 `null` 时渲染空的子内容
|
|
297
|
+
* - 返回 `undefined` 时不会更新现有内容
|
|
298
|
+
* */
|
|
299
|
+
#render = (item) => {
|
|
300
|
+
try {
|
|
301
|
+
this.#rendering = true;
|
|
302
|
+
this.#execMemo();
|
|
303
|
+
const isLight = this.#renderRoot === this;
|
|
304
|
+
const temp = item ? item.render() : isLight ? undefined : html `<slot></slot>`;
|
|
305
|
+
this.#rendering = false;
|
|
306
|
+
if (temp === undefined)
|
|
307
|
+
return;
|
|
308
|
+
render(temp, this.#renderRoot);
|
|
310
309
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
closestElement(constructorOrTag) {
|
|
314
|
-
const isConstructor = typeof constructorOrTag === 'function';
|
|
315
|
-
const tagName = typeof constructorOrTag === 'string' && constructorOrTag.toUpperCase();
|
|
316
|
-
const is = (ele) => (isConstructor ? ele.constructor === constructorOrTag : ele.tagName === tagName);
|
|
317
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
318
|
-
let node = this;
|
|
319
|
-
while (node) {
|
|
320
|
-
if (is(node))
|
|
321
|
-
break;
|
|
322
|
-
node = node.parentElement || node.getRootNode().host;
|
|
310
|
+
catch (err) {
|
|
311
|
+
this.dispatchEvent(new CustomEvent(RenderErrorEvent, { bubbles: true, composed: true, detail: err }));
|
|
323
312
|
}
|
|
324
|
-
|
|
325
|
-
|
|
313
|
+
};
|
|
314
|
+
#updateCallback = () => {
|
|
315
|
+
const item = this.#renderItem;
|
|
316
|
+
if (this.#isMounted &&
|
|
317
|
+
// 当有渲染函数,但是没一个符合条件时跳过
|
|
318
|
+
(item || !this.#renderList.length)) {
|
|
319
|
+
this.#render(item);
|
|
320
|
+
addMicrotask(this.#execEffect);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
#update = () => {
|
|
324
|
+
if (this.#metadata.noBlocking) {
|
|
325
|
+
noBlockingTaskList.add(this.#updateCallback);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
this.#updateCallback();
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
#prepareStyle = () => {
|
|
332
|
+
const { adoptedStyleSheets = [] } = this.#metadata;
|
|
333
|
+
const { shadowRoot, sheets } = this.#internals;
|
|
334
|
+
const clsSheets = adoptedStyleSheets.map((item) => item[SheetToken].getStyle(this));
|
|
335
|
+
if (shadowRoot) {
|
|
336
|
+
shadowRoot.adoptedStyleSheets = clsSheets.concat(sheets);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
this.prepend(...sheets.map((e) => e.element));
|
|
340
|
+
return appleCSSStyleSheet(this, clsSheets);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* 元素挂载后执行还未初始化的副作用
|
|
345
|
+
* */
|
|
346
|
+
#initEffect = () => {
|
|
347
|
+
this.#effectList?.forEach((effectItem) => {
|
|
348
|
+
const { callback, getDep, initialized } = effectItem;
|
|
349
|
+
if (!initialized) {
|
|
350
|
+
effectItem.values = getDep?.();
|
|
351
|
+
effectItem.preCallback = callback(effectItem.values);
|
|
352
|
+
effectItem.initialized = true;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
#compat = () => {
|
|
357
|
+
if (this.willMount)
|
|
358
|
+
this.memo(this.willMount.bind(this), () => []);
|
|
359
|
+
if (this.mounted)
|
|
360
|
+
this.effect(this.mounted.bind(this), () => []);
|
|
361
|
+
if (this.updated)
|
|
362
|
+
this.effect((_, old) => old && this.updated.apply(this));
|
|
363
|
+
if (this.unmounted)
|
|
364
|
+
this.effect(() => this.unmounted.bind(this), () => []);
|
|
365
|
+
if (!this.#renderList.length && this.render)
|
|
366
|
+
this.#renderList.push({ render: this.render.bind(this), condition: this.shouldUpdate?.bind(this) });
|
|
367
|
+
};
|
|
368
|
+
#disconnectStore;
|
|
369
|
+
#connectedCallback = async () => {
|
|
370
|
+
if (this.#isAppendReason) {
|
|
371
|
+
this.#isAppendReason = false;
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
this.#compat();
|
|
375
|
+
const { observedStores } = this.#metadata;
|
|
376
|
+
this.#isConnected = true;
|
|
377
|
+
this.#disconnectStore = observedStores?.map((store) => connect(store, this.#update));
|
|
378
|
+
this.#render(this.#renderItem);
|
|
379
|
+
this.#isMounted = true;
|
|
380
|
+
this.#clearStyle = this.#prepareStyle();
|
|
381
|
+
// 等待所有元素的样式被应用,再执行回调
|
|
382
|
+
// 这让 mounted 和 effect 回调和其他回调一样保持一样的异步行为
|
|
383
|
+
await Promise.resolve();
|
|
384
|
+
this.#initEffect();
|
|
385
|
+
};
|
|
326
386
|
/**
|
|
327
387
|
* @private
|
|
328
388
|
* @final
|
|
329
|
-
* use `mounted
|
|
389
|
+
* use `mounted`
|
|
330
390
|
*/
|
|
331
391
|
connectedCallback() {
|
|
332
|
-
if (this.
|
|
333
|
-
|
|
392
|
+
if (this.#metadata.noBlocking) {
|
|
393
|
+
noBlockingTaskList.add(this.#connectedCallback);
|
|
334
394
|
}
|
|
335
395
|
else {
|
|
336
|
-
|
|
396
|
+
this.#connectedCallback();
|
|
337
397
|
}
|
|
338
|
-
return
|
|
398
|
+
return GemElement.#final;
|
|
339
399
|
}
|
|
340
400
|
/**
|
|
341
401
|
* @private
|
|
342
402
|
* @final
|
|
343
403
|
*/
|
|
344
404
|
adoptedCallback() {
|
|
345
|
-
return
|
|
405
|
+
return GemElement.#final;
|
|
346
406
|
}
|
|
347
407
|
/**
|
|
348
408
|
* @private
|
|
@@ -350,173 +410,76 @@ export class GemElement extends HTMLElement {
|
|
|
350
410
|
* use `unmounted`
|
|
351
411
|
*/
|
|
352
412
|
disconnectedCallback() {
|
|
353
|
-
var _b, _c;
|
|
354
413
|
if (this.isConnected) {
|
|
355
|
-
|
|
414
|
+
this.#isAppendReason = true;
|
|
356
415
|
return;
|
|
357
416
|
}
|
|
358
|
-
|
|
359
|
-
(
|
|
360
|
-
|
|
361
|
-
(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
417
|
+
noBlockingTaskList.delete(this.#connectedCallback);
|
|
418
|
+
noBlockingTaskList.delete(this.#updateCallback);
|
|
419
|
+
this.#isMounted = false;
|
|
420
|
+
this.#disconnectStore?.forEach((disconnect) => disconnect());
|
|
421
|
+
// 是否要异步执行回调?
|
|
422
|
+
this.#effectList = clearEffect(this.#effectList);
|
|
423
|
+
this.#memoList = clearEffect(this.#memoList);
|
|
424
|
+
execCallback(this.#clearStyle);
|
|
425
|
+
return GemElement.#final;
|
|
365
426
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const value = gemElementProxyMap.get(this)[prop];
|
|
424
|
-
if (value || !event) {
|
|
425
|
-
return value;
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
this[prop] = emptyFunction;
|
|
429
|
-
return this[prop];
|
|
430
|
-
}
|
|
431
|
-
},
|
|
432
|
-
set(v) {
|
|
433
|
-
const that = this;
|
|
434
|
-
const proxy = gemElementProxyMap.get(that);
|
|
435
|
-
if (v !== proxy[prop]) {
|
|
436
|
-
if (event) {
|
|
437
|
-
proxy[prop] = (v === null || v === void 0 ? void 0 : v[isEventHandleSymbol])
|
|
438
|
-
? v
|
|
439
|
-
: (detail, options) => {
|
|
440
|
-
const evt = new CustomEvent(event, { ...options, ...eventOptions, detail });
|
|
441
|
-
that.dispatchEvent(evt);
|
|
442
|
-
v(detail, options);
|
|
443
|
-
};
|
|
444
|
-
Reflect.set(proxy[prop], isEventHandleSymbol, true);
|
|
445
|
-
// emitter 不触发元素更新
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
proxy[prop] = v;
|
|
449
|
-
this[updateSymbol]();
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
},
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
const getReflectTargets = (ele) => [...ele.querySelectorAll('[data-gem-reflect]')].map((e) => e.target);
|
|
456
|
-
export function defineRef(target, prop, ref) {
|
|
457
|
-
const refSelector = `[ref=${ref}]`;
|
|
458
|
-
Object.defineProperty(target, prop, {
|
|
459
|
-
configurable: true,
|
|
460
|
-
get() {
|
|
461
|
-
const proxy = gemElementProxyMap.get(this);
|
|
462
|
-
let refobject = proxy[prop];
|
|
463
|
-
if (!refobject) {
|
|
464
|
-
const that = this;
|
|
465
|
-
const ele = that.shadowRoot || that;
|
|
466
|
-
refobject = {
|
|
467
|
-
get ref() {
|
|
468
|
-
return ref;
|
|
469
|
-
},
|
|
470
|
-
get element() {
|
|
471
|
-
for (const e of [ele, ...getReflectTargets(ele)]) {
|
|
472
|
-
const result = e.querySelector(refSelector);
|
|
473
|
-
if (result)
|
|
474
|
-
return result;
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
get elements() {
|
|
478
|
-
return [ele, ...getReflectTargets(ele)].map((e) => [...e.querySelectorAll(refSelector)]).flat();
|
|
479
|
-
},
|
|
480
|
-
};
|
|
481
|
-
proxy[prop] = refobject;
|
|
482
|
-
}
|
|
483
|
-
return refobject;
|
|
484
|
-
},
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
export function defineCSSState(target, prop, state) {
|
|
488
|
-
Object.defineProperty(target, prop, {
|
|
489
|
-
configurable: true,
|
|
490
|
-
get() {
|
|
491
|
-
const that = this;
|
|
492
|
-
const { states } = that.internals;
|
|
493
|
-
return states === null || states === void 0 ? void 0 : states.has(state);
|
|
494
|
-
},
|
|
495
|
-
set(v) {
|
|
496
|
-
const that = this;
|
|
497
|
-
const { states } = that.internals;
|
|
498
|
-
if (v) {
|
|
499
|
-
states === null || states === void 0 ? void 0 : states.add(state);
|
|
500
|
-
}
|
|
501
|
-
else {
|
|
502
|
-
states === null || states === void 0 ? void 0 : states.delete(state);
|
|
503
|
-
}
|
|
504
|
-
},
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
export const nativeDefineElement = customElements.define.bind(customElements);
|
|
508
|
-
customElements.define = (name, cls, options) => {
|
|
509
|
-
if (cls.prototype instanceof GemElement) {
|
|
510
|
-
const { observedAttributes, observedProperties, defineEvents, defineCSSStates, defineRefs } = cls;
|
|
511
|
-
observedAttributes === null || observedAttributes === void 0 ? void 0 : observedAttributes.forEach((attr) => defineAttribute(cls.prototype, kebabToCamelCase(attr), attr));
|
|
512
|
-
observedProperties === null || observedProperties === void 0 ? void 0 : observedProperties.forEach((prop) => defineProperty(cls.prototype, prop));
|
|
513
|
-
defineEvents === null || defineEvents === void 0 ? void 0 : defineEvents.forEach((event) => defineProperty(cls.prototype, kebabToCamelCase(event), event));
|
|
514
|
-
defineCSSStates === null || defineCSSStates === void 0 ? void 0 : defineCSSStates.forEach((state) => defineCSSState(cls.prototype, kebabToCamelCase(state), state));
|
|
515
|
-
defineRefs === null || defineRefs === void 0 ? void 0 : defineRefs.forEach((ref) => defineRef(cls.prototype, kebabToCamelCase(ref), ref));
|
|
516
|
-
}
|
|
517
|
-
nativeDefineElement(name, cls, options);
|
|
518
|
-
};
|
|
519
|
-
if (window.__GEM_DEVTOOLS__HOOK__) {
|
|
520
|
-
Object.assign(window.__GEM_DEVTOOLS__HOOK__, { ...GemExports, ...VersionExports });
|
|
427
|
+
/**
|
|
428
|
+
* @helper
|
|
429
|
+
* 记录副作用回调和值;
|
|
430
|
+
* 回调到返回值如果是函数将再卸载时执行;
|
|
431
|
+
* 第一次执行时 `oldDeps` 为空;
|
|
432
|
+
*
|
|
433
|
+
* ```js
|
|
434
|
+
* class App extends GemElement {
|
|
435
|
+
* mounted() {
|
|
436
|
+
* this.effect(callback, () => [this.attrName]);
|
|
437
|
+
* }
|
|
438
|
+
* }
|
|
439
|
+
* ```
|
|
440
|
+
* */
|
|
441
|
+
effect = (callback, getDep) => {
|
|
442
|
+
const effectItem = {
|
|
443
|
+
callback,
|
|
444
|
+
getDep,
|
|
445
|
+
initialized: this.#isMounted,
|
|
446
|
+
fixed: !this.#isConnected,
|
|
447
|
+
};
|
|
448
|
+
// 已挂载时立即执行副作用,未挂载时等挂载后执行
|
|
449
|
+
if (this.#isMounted) {
|
|
450
|
+
effectItem.values = getDep?.();
|
|
451
|
+
effectItem.preCallback = callback(effectItem.values);
|
|
452
|
+
}
|
|
453
|
+
this.#effectList.push(effectItem);
|
|
454
|
+
};
|
|
455
|
+
/**
|
|
456
|
+
* @helper
|
|
457
|
+
* 在 `render` 前执行回调;
|
|
458
|
+
* 和 `effect` 一样接受依赖数组参数,在 `constructor` 中使用;
|
|
459
|
+
* 第一次执行时 `oldDeps` 为空;
|
|
460
|
+
*
|
|
461
|
+
* ```js
|
|
462
|
+
* class App extends GemElement {
|
|
463
|
+
* constructor() {
|
|
464
|
+
* super();
|
|
465
|
+
* this.memo(() => {
|
|
466
|
+
* this.a = exec(this.attrName);
|
|
467
|
+
* }), () => [this.attrName]);
|
|
468
|
+
* }
|
|
469
|
+
* }
|
|
470
|
+
* ```
|
|
471
|
+
* */
|
|
472
|
+
memo = (callback, getDep) => {
|
|
473
|
+
this.#memoList.push({
|
|
474
|
+
callback,
|
|
475
|
+
getDep,
|
|
476
|
+
fixed: !this.#isConnected,
|
|
477
|
+
});
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* @helper
|
|
481
|
+
* async
|
|
482
|
+
*/
|
|
483
|
+
update = () => addMicrotask(this.#update);
|
|
521
484
|
}
|
|
522
485
|
//# sourceMappingURL=element.js.map
|