@mantou/gem 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/gem.es.js +2039 -2051
  2. package/dist/gem.umd.js +12 -32
  3. package/elements/base/dialog.d.ts +1 -1
  4. package/elements/base/dialog.d.ts.map +1 -1
  5. package/elements/base/dialog.js +2 -2
  6. package/elements/base/dialog.js.map +1 -1
  7. package/elements/base/gesture.d.ts +1 -1
  8. package/elements/base/gesture.d.ts.map +1 -1
  9. package/elements/base/gesture.js +5 -5
  10. package/elements/base/gesture.js.map +1 -1
  11. package/elements/base/link.d.ts +1 -1
  12. package/elements/base/link.d.ts.map +1 -1
  13. package/elements/base/link.js +18 -19
  14. package/elements/base/link.js.map +1 -1
  15. package/elements/base/modal-factory.d.ts +93 -57
  16. package/elements/base/modal-factory.d.ts.map +1 -1
  17. package/elements/base/modal-factory.js +4 -3
  18. package/elements/base/modal-factory.js.map +1 -1
  19. package/elements/base/reflect.d.ts +1 -2
  20. package/elements/base/reflect.d.ts.map +1 -1
  21. package/elements/base/reflect.js +8 -10
  22. package/elements/base/reflect.js.map +1 -1
  23. package/elements/base/route.d.ts +18 -8
  24. package/elements/base/route.d.ts.map +1 -1
  25. package/elements/base/route.js +17 -21
  26. package/elements/base/route.js.map +1 -1
  27. package/elements/base/title.d.ts +1 -1
  28. package/elements/base/title.d.ts.map +1 -1
  29. package/elements/base/title.js +5 -7
  30. package/elements/base/title.js.map +1 -1
  31. package/elements/base/unsafe.d.ts +4 -3
  32. package/elements/base/unsafe.d.ts.map +1 -1
  33. package/elements/base/unsafe.js +45 -24
  34. package/elements/base/unsafe.js.map +1 -1
  35. package/elements/base/use.d.ts +1 -1
  36. package/elements/base/use.d.ts.map +1 -1
  37. package/elements/base/use.js +1 -1
  38. package/elements/base/use.js.map +1 -1
  39. package/elements/link.js +1 -1
  40. package/elements/link.js.map +1 -1
  41. package/elements/route.js +1 -1
  42. package/elements/route.js.map +1 -1
  43. package/helper/hmr.d.ts +11 -0
  44. package/helper/hmr.d.ts.map +1 -0
  45. package/helper/hmr.js +255 -0
  46. package/helper/hmr.js.map +1 -0
  47. package/helper/i18n.d.ts +2 -2
  48. package/helper/i18n.d.ts.map +1 -1
  49. package/helper/i18n.js +5 -4
  50. package/helper/i18n.js.map +1 -1
  51. package/helper/logger.d.ts +1 -1
  52. package/helper/logger.d.ts.map +1 -1
  53. package/helper/logger.js +8 -5
  54. package/helper/logger.js.map +1 -1
  55. package/helper/mediaquery.js +1 -1
  56. package/helper/mediaquery.js.map +1 -1
  57. package/helper/react-utils.d.ts.map +1 -1
  58. package/helper/react-utils.js +2 -6
  59. package/helper/react-utils.js.map +1 -1
  60. package/helper/ssr-shim.d.ts.map +1 -1
  61. package/helper/ssr-shim.js +2 -1
  62. package/helper/ssr-shim.js.map +1 -1
  63. package/helper/theme.d.ts +17 -6
  64. package/helper/theme.d.ts.map +1 -1
  65. package/helper/theme.js +23 -8
  66. package/helper/theme.js.map +1 -1
  67. package/index.d.ts +1 -2
  68. package/index.d.ts.map +1 -1
  69. package/index.js +1 -3
  70. package/index.js.map +1 -1
  71. package/lib/decorators.d.ts +54 -62
  72. package/lib/decorators.d.ts.map +1 -1
  73. package/lib/decorators.js +90 -91
  74. package/lib/decorators.js.map +1 -1
  75. package/lib/directive.d.ts +0 -18
  76. package/lib/directive.d.ts.map +1 -1
  77. package/lib/directive.js +1 -2
  78. package/lib/directive.js.map +1 -1
  79. package/lib/element.d.ts +8 -137
  80. package/lib/element.d.ts.map +1 -1
  81. package/lib/element.js +16 -481
  82. package/lib/element.js.map +1 -1
  83. package/lib/history.d.ts +68 -10
  84. package/lib/history.d.ts.map +1 -1
  85. package/lib/history.js +15 -15
  86. package/lib/history.js.map +1 -1
  87. package/lib/lit-html.d.ts +7 -109
  88. package/lib/lit-html.d.ts.map +1 -1
  89. package/lib/lit-html.js +75 -32
  90. package/lib/lit-html.js.map +1 -1
  91. package/lib/reactive.d.ts +130 -0
  92. package/lib/reactive.d.ts.map +1 -0
  93. package/lib/reactive.js +474 -0
  94. package/lib/reactive.js.map +1 -0
  95. package/lib/repeat.d.ts +3 -3
  96. package/lib/repeat.d.ts.map +1 -1
  97. package/lib/repeat.js +3 -3
  98. package/lib/repeat.js.map +1 -1
  99. package/lib/store.d.ts +15 -4
  100. package/lib/store.d.ts.map +1 -1
  101. package/lib/store.js +2 -0
  102. package/lib/store.js.map +1 -1
  103. package/lib/utils.d.ts +26 -11
  104. package/lib/utils.d.ts.map +1 -1
  105. package/lib/utils.js +21 -14
  106. package/lib/utils.js.map +1 -1
  107. package/package.json +3 -3
  108. package/src/dist.ts +6 -8
  109. package/src/elements/base/dialog.ts +2 -2
  110. package/src/elements/base/gesture.ts +6 -6
  111. package/src/elements/base/link.ts +18 -24
  112. package/src/elements/base/modal-factory.ts +4 -3
  113. package/src/elements/base/reflect.ts +2 -3
  114. package/src/elements/base/route.ts +21 -28
  115. package/src/elements/base/title.ts +6 -8
  116. package/src/elements/base/unsafe.ts +33 -14
  117. package/src/elements/base/use.ts +1 -1
  118. package/src/elements/link.ts +1 -1
  119. package/src/elements/route.ts +1 -1
  120. package/src/helper/hmr.ts +305 -0
  121. package/src/helper/i18n.ts +7 -7
  122. package/src/helper/logger.ts +9 -5
  123. package/src/helper/mediaquery.ts +1 -1
  124. package/src/helper/react-utils.ts +4 -12
  125. package/src/helper/ssr-shim.ts +3 -1
  126. package/src/helper/theme.ts +29 -14
  127. package/src/index.ts +1 -4
  128. package/src/lib/decorators.ts +107 -117
  129. package/src/lib/directive.ts +3 -5
  130. package/src/lib/element.ts +21 -600
  131. package/src/lib/history.ts +16 -18
  132. package/src/lib/lit-html.ts +89 -34
  133. package/src/lib/reactive.ts +620 -0
  134. package/src/lib/repeat.ts +5 -5
  135. package/src/lib/store.ts +4 -2
  136. package/src/lib/utils.ts +41 -29
  137. package/src/test/elements/link.test.ts +2 -2
  138. package/src/test/elements/reflect.test.ts +3 -3
  139. package/src/test/elements/title.test.ts +2 -2
  140. package/src/test/gem-element/advance.test.ts +11 -10
  141. package/src/test/gem-element/basic.test.ts +4 -5
  142. package/src/test/gem-element/decorators.test.ts +10 -10
  143. package/src/test/gem-element/multi.test.ts +2 -2
  144. package/src/test/history.test.ts +1 -2
  145. package/src/test/store.test.ts +2 -3
  146. package/src/test/utils.test.ts +5 -6
  147. package/src/test/utils.ts +2 -2
  148. package/helper/react-shim.d.ts +0 -15
  149. package/helper/react-shim.d.ts.map +0 -1
  150. package/helper/react-shim.js +0 -56
  151. package/helper/react-shim.js.map +0 -1
  152. package/lib/directives.d.ts +0 -4
  153. package/lib/directives.d.ts.map +0 -1
  154. package/lib/directives.js +0 -5
  155. package/lib/directives.js.map +0 -1
  156. package/lib/ref.d.ts +0 -1
  157. package/lib/ref.d.ts.map +0 -1
  158. package/lib/ref.js +0 -2
  159. package/lib/ref.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { GemLinkElement, GemActiveLinkElement } from './base/link';
1
+ import { GemActiveLinkElement, GemLinkElement } from './base/link';
2
2
 
3
3
  export * from './base/link';
4
4
 
@@ -1,4 +1,4 @@
1
- import { GemRouteElement, GemLightRouteElement } from './base/route';
1
+ import { GemLightRouteElement, GemRouteElement } from './base/route';
2
2
 
3
3
  export * from './base/route';
4
4
 
@@ -0,0 +1,305 @@
1
+ import { attribute, boolattribute, emitter, numattribute, property, state } from '../lib/decorators';
2
+ import { GemElement, type Metadata, UpdateToken } from '../lib/reactive';
3
+ import type { Store } from '../lib/store';
4
+ import { Logger } from './logger';
5
+
6
+ const logger = new Logger('HMR');
7
+
8
+ const nativeDefineElement = window.customElements.define.bind(window.customElements);
9
+
10
+ const cache = new Map<string, Element[]>();
11
+ function updateElement(name: string, fn: (ele: Element) => void) {
12
+ if (!cache.has(name)) {
13
+ const elements = [];
14
+ const temp: Element[] = [document.documentElement];
15
+ while (temp.length) {
16
+ const element = temp.pop()!;
17
+ if (element.tagName.toLowerCase() === name) elements.push(element);
18
+ temp.push(...[...element.children, ...(element.shadowRoot?.children || [])].reverse());
19
+ }
20
+ cache.set(name, elements);
21
+ }
22
+ const elements = cache.get(name)!;
23
+ if (elements.length === 0) {
24
+ const ele = document.createElement(name);
25
+ Element.prototype.remove.apply(ele);
26
+ fn(ele);
27
+ } else {
28
+ elements.forEach(fn);
29
+ }
30
+ queueMicrotask(() => cache.delete(name));
31
+ }
32
+
33
+ function getMetadata(cons: any): Metadata {
34
+ return (cons as any)[Symbol.metadata] || {};
35
+ }
36
+
37
+ function getHmrMethodKeys(obj: any) {
38
+ return Object.getOwnPropertyNames(obj).filter((key) => key.startsWith('_hmr_'));
39
+ }
40
+
41
+ /** 不支持修改 store */
42
+ function checkMetadataNeedReload({ mode, penetrable, noBlocking, observedStores }: Metadata, newMetadata: Metadata) {
43
+ const stringifyStores = (stores?: Store<any>[]) =>
44
+ JSON.stringify(
45
+ stores?.map((store) => JSON.stringify({ ...store }, (_, v) => (typeof v === 'function' ? v.toString() : v))),
46
+ );
47
+ if (
48
+ mode !== newMetadata.mode ||
49
+ penetrable !== newMetadata.penetrable ||
50
+ noBlocking !== newMetadata.noBlocking ||
51
+ stringifyStores(observedStores) !== stringifyStores(newMetadata.observedStores)
52
+ ) {
53
+ return true;
54
+ }
55
+ }
56
+
57
+ /** 不支持删减函数字段,因为原函数可能已经被绑定 */
58
+ function checkClassNeedReload(existed: CustomElementConstructor, newClass: CustomElementConstructor) {
59
+ if (
60
+ getHmrMethodKeys(existed).join() !== getHmrMethodKeys(newClass).join() ||
61
+ getHmrMethodKeys(existed.prototype).join() !== getHmrMethodKeys(newClass.prototype).join()
62
+ ) {
63
+ return true;
64
+ }
65
+ }
66
+
67
+ /** 不支持删减实例其他字段,因为新实例总是使用老 Class 定义 */
68
+ function checkFieldsNeedReload({ instanceFields }: ReturnType<typeof getFields>) {
69
+ if (instanceFields.other?.add?.length || instanceFields.other?.remove?.length) {
70
+ return true;
71
+ }
72
+ }
73
+
74
+ function diffArr<T>(oldList: T[], newList: T[], fn: (i: T) => string = (e) => String(e)) {
75
+ const getMap = (list: T[]) => new Map(list.map((e) => [fn(e), e]));
76
+ const oldMap = getMap(oldList);
77
+ const newMap = getMap(newList);
78
+ const result = { remove: [] as T[], add: [] as T[], some: [] as T[], all: [] as T[] };
79
+ getMap([...oldList, ...newList]).forEach((e, k) => {
80
+ result.all.push(e);
81
+ if (newMap.has(k) && oldMap.has(k)) {
82
+ result.some.push(e);
83
+ } else if (!newMap.has(k)) {
84
+ result.remove.push(e);
85
+ } else if (!oldMap.has(k)) {
86
+ result.add.push(e);
87
+ }
88
+ });
89
+ return result;
90
+ }
91
+
92
+ function diffRecord<T>(oldRecord: Partial<Record<string, T[]>>, newRecord: Partial<Record<string, T[]>>) {
93
+ const oldKeys = Object.keys(oldRecord);
94
+ const newKeys = Object.keys(newRecord);
95
+ return diffArr(oldKeys, newKeys);
96
+ }
97
+
98
+ type HasFieldsRecordClass = { _defined_fields_?: [string, string, boolean][] };
99
+ function getFields(existed: CustomElementConstructor, newClass: CustomElementConstructor) {
100
+ const translate = (cls: HasFieldsRecordClass) => {
101
+ const fieldList = (cls._defined_fields_ || []).map(([name, type, isStatic]) => ({ name, type, isStatic }));
102
+ const fieldGroup = Object.groupBy(fieldList, ({ isStatic }) => (isStatic ? 'staticFields' : 'instanceFields'));
103
+ const groupBy = (list: typeof fieldGroup.staticFields) => Object.groupBy(list || [], ({ type }) => type);
104
+ return {
105
+ staticFields: groupBy(fieldGroup.staticFields),
106
+ instanceFields: groupBy(fieldGroup.instanceFields),
107
+ };
108
+ };
109
+ const oldFields = translate(existed as unknown as HasFieldsRecordClass);
110
+ const newFields = translate(newClass as unknown as HasFieldsRecordClass);
111
+ const result = Object.fromEntries(
112
+ Object.entries(oldFields).map(([classFieldType]: [keyof typeof oldFields, any]) => [
113
+ classFieldType,
114
+ Object.fromEntries(
115
+ diffRecord(oldFields[classFieldType], newFields[classFieldType]).all.map((type) => [
116
+ type,
117
+ diffArr(oldFields[classFieldType][type] || [], newFields[classFieldType][type] || [], ({ name }) => name),
118
+ ]),
119
+ ),
120
+ ]),
121
+ );
122
+ return result as Record<keyof typeof oldFields, (typeof result)[0]>;
123
+ }
124
+
125
+ const deleteProperty = Reflect.deleteProperty;
126
+ const getProperty = Reflect.get;
127
+ const getPrototypeOf = Reflect.getPrototypeOf;
128
+ const setProperty = (target: any, propertyKey: string | symbol, value: any) =>
129
+ Reflect.defineProperty(target, propertyKey, {
130
+ configurable: true,
131
+ enumerable: true,
132
+ writable: true,
133
+ value,
134
+ });
135
+ const safeProp = new Set(['part', 'slot', 'other']);
136
+ const descMap = {
137
+ attribute,
138
+ boolattribute,
139
+ numattribute,
140
+ property,
141
+ state,
142
+ emitter,
143
+ };
144
+
145
+ function setArrValue<T>(obj: any, field: string, val: T[] = []) {
146
+ if (!Object.getOwnPropertyDescriptor(obj, field)) {
147
+ setProperty(obj, field, val);
148
+ } else {
149
+ const old = obj[field] as T[];
150
+ old.length = 0;
151
+ old.push(...val);
152
+ }
153
+ }
154
+
155
+ declare global {
156
+ interface Window {
157
+ _hmrClassRegistry: Map<string, any>;
158
+ _hmrRegisterClass: (name: string) => (cls: HasFieldsRecordClass, ctx: ClassDecoratorContext) => void;
159
+ }
160
+ }
161
+
162
+ window._hmrClassRegistry = new Map();
163
+ window._hmrRegisterClass =
164
+ (name: string) =>
165
+ (cls: HasFieldsRecordClass, { addInitializer }: ClassDecoratorContext) => {
166
+ addInitializer(() => {
167
+ const existed = window._hmrClassRegistry.get(name);
168
+
169
+ if (!existed) {
170
+ window._hmrClassRegistry.set(name, cls);
171
+ return;
172
+ }
173
+
174
+ logger.info(`class <${name}> update,`, { existed, cls });
175
+
176
+ let current: any[] = [existed, cls];
177
+ while (current) {
178
+ const [oldClass, newClass] = current;
179
+ if (oldClass === newClass || current.some((e) => e === GemElement || e === Function.prototype)) break;
180
+ if (current.some((e) => !e) || checkClassNeedReload(oldClass, newClass)) {
181
+ location.reload();
182
+ return;
183
+ }
184
+
185
+ // 修正 `instanceof`
186
+ setProperty(newClass, Symbol.hasInstance, function hasInstance(instance: any) {
187
+ const isOldInstance = instance instanceof oldClass;
188
+ if (isOldInstance) return true;
189
+ setProperty(newClass, Symbol.hasInstance, undefined);
190
+ const isNew = instance instanceof newClass;
191
+ setProperty(newClass, Symbol.hasInstance, hasInstance);
192
+ return isNew;
193
+ });
194
+
195
+ const oldMetadata = getMetadata(oldClass);
196
+ const newMetadata = getMetadata(newClass);
197
+
198
+ if (checkMetadataNeedReload(oldMetadata, newMetadata)) {
199
+ location.reload();
200
+ return;
201
+ }
202
+
203
+ const fields = getFields(oldClass, newClass);
204
+
205
+ if (checkFieldsNeedReload(fields)) {
206
+ location.reload();
207
+ return;
208
+ }
209
+
210
+ Object.entries(fields.staticFields).forEach(([type, { remove, add }]) => {
211
+ remove.forEach((prop) => {
212
+ if (safeProp.has(type)) {
213
+ deleteProperty(oldClass, prop.name);
214
+ }
215
+ });
216
+ add.forEach((prop) => {
217
+ if (safeProp.has(type)) {
218
+ setProperty(oldClass, prop.name, getProperty(newClass, prop.name));
219
+ }
220
+ });
221
+ });
222
+
223
+ const instanceFieldsEntries = Object.entries(fields.instanceFields);
224
+ // 删除的属性重新加回来要先清除占位值
225
+ instanceFieldsEntries.forEach(([type, { add }]) => {
226
+ add.forEach((prop) => {
227
+ if (type in descMap) {
228
+ deleteProperty(oldClass.prototype, prop.name);
229
+ }
230
+ });
231
+ });
232
+ updateElement(name, (element) => {
233
+ instanceFieldsEntries.forEach(([type, { add, remove }]) => {
234
+ add.forEach((prop) => {
235
+ if (type in descMap) {
236
+ (descMap as any)[type](undefined, {
237
+ name: prop.name,
238
+ metadata: oldMetadata,
239
+ addInitializer: (fn: () => void) => fn.apply(element),
240
+ } as ClassMemberDecoratorContext);
241
+ }
242
+ });
243
+ remove.forEach((prop) => {
244
+ setProperty(element, prop.name, undefined);
245
+ });
246
+ });
247
+ });
248
+ // 删除的属性在 proto 上添加占位符
249
+ instanceFieldsEntries.forEach(([type, { remove }]) => {
250
+ remove.forEach((prop) => {
251
+ if (type in descMap) {
252
+ // attribute 映射 prop 没有移除
253
+ setProperty(oldClass.prototype, prop.name, undefined);
254
+ }
255
+ });
256
+ });
257
+
258
+ setArrValue(oldMetadata, 'definedParts', newMetadata.definedParts);
259
+ setArrValue(oldMetadata, 'definedSlots', newMetadata.definedSlots);
260
+ setArrValue(oldMetadata, 'observedProperties', newMetadata.observedProperties);
261
+ setArrValue(oldMetadata, 'observedAttributes', newMetadata.observedAttributes);
262
+ setArrValue(oldMetadata, 'definedEvents', newMetadata.definedEvents);
263
+ setArrValue(oldMetadata, 'definedCSSStates', newMetadata.definedCSSStates);
264
+ setArrValue(oldMetadata, 'adoptedStyleSheets', newMetadata.adoptedStyleSheets);
265
+ setArrValue(oldClass, '_defined_fields_', newClass._defined_fields_);
266
+
267
+ [
268
+ [oldClass, newClass],
269
+ [oldClass.prototype, newClass.prototype],
270
+ ].forEach(([existedObj, newObj]) => {
271
+ Object.assign(
272
+ existedObj,
273
+ Object.fromEntries(
274
+ getHmrMethodKeys(newObj)
275
+ .filter((key) => existedObj[key].toString() !== newObj[key].toString())
276
+ .map((key) => [key, newObj[key]]),
277
+ ),
278
+ );
279
+ });
280
+
281
+ current = [getPrototypeOf(oldClass), getPrototypeOf(newClass)];
282
+ }
283
+ });
284
+ };
285
+
286
+ window.customElements.define = (name: string, cls: CustomElementConstructor) => {
287
+ const existed = customElements.get(name);
288
+
289
+ if (!existed) {
290
+ nativeDefineElement(name, cls);
291
+ return;
292
+ }
293
+
294
+ // 等待类更新
295
+ queueMicrotask(() => {
296
+ logger.info(`<${name}> update,`, { cls });
297
+
298
+ updateElement(name, (element) => {
299
+ // 触发样式更新,支持 Light DOM
300
+ element.after(element);
301
+ // 重新渲染
302
+ (element as any)[UpdateToken]?.();
303
+ });
304
+ });
305
+ };
@@ -1,9 +1,8 @@
1
+ import type { RouteTrigger } from '../elements/base/route';
1
2
  import type { UpdateHistoryParams } from '../lib/history';
2
- import type { TemplateResult } from '../lib/element';
3
- import { html, UpdateToken } from '../lib/element';
3
+ import type { TemplateResult } from '../lib/lit-html';
4
+ import { html, UpdateToken } from '../lib/reactive';
4
5
  import { GemError } from '../lib/utils';
5
- import type { RouteTrigger } from '../elements/base/route';
6
-
7
6
  import { logger } from './logger';
8
7
 
9
8
  // Hello, $1
@@ -91,9 +90,10 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
91
90
  return parts.shift();
92
91
  case 'path':
93
92
  return pathname.split('/')[1];
94
- default:
93
+ default: {
95
94
  const fragment = (this.urlParamsName && new URLSearchParams(search).get(this.urlParamsName)) || '';
96
95
  return fragment in this.resources ? fragment : '';
96
+ }
97
97
  }
98
98
  }
99
99
 
@@ -198,7 +198,7 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
198
198
  if (localPackString) {
199
199
  try {
200
200
  pack = JSON.parse(localPackString);
201
- } catch (e) {
201
+ } catch {
202
202
  pack = await fetchPack();
203
203
  }
204
204
  } else {
@@ -212,7 +212,7 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
212
212
  if (!this.#inConstructor) {
213
213
  // 更新所有元素,可能会更新许多不必要的元素
214
214
  const temp: Element[] = [document.documentElement];
215
- while (!!temp.length) {
215
+ while (temp.length) {
216
216
  const element = temp.pop()!;
217
217
  (element as any)[UpdateToken]?.();
218
218
  // 和 gem 更新机制一样使用深度优先
@@ -1,20 +1,24 @@
1
1
  export class Logger {
2
- _type: string;
2
+ #type: string;
3
+
4
+ get #prefix() {
5
+ return `[${this.#type}]`;
6
+ }
3
7
 
4
8
  constructor(type: string) {
5
- this._type = type;
9
+ this.#type = type;
6
10
  }
7
11
 
8
12
  info = (...args: any[]) => {
9
- console.log(`[${this._type}]:`, ...args);
13
+ console.log(this.#prefix, ...args);
10
14
  };
11
15
 
12
16
  warn = (...args: any[]) => {
13
- console.warn(`[${this._type}]:`, ...args);
17
+ console.warn(this.#prefix, ...args);
14
18
  };
15
19
 
16
20
  error = (...args: any[]) => {
17
- console.error(`[${this._type}]:`, ...args);
21
+ console.error(this.#prefix, ...args);
18
22
  };
19
23
  }
20
24
 
@@ -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) => window.matchMedia(query).matches;
4
+ const match = (query: string) => matchMedia(query).matches;
5
5
 
6
6
  export const mediaQuery = {
7
7
  PRINT: 'print',
@@ -1,18 +1,10 @@
1
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
- // @ts-ignore
3
- // eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
1
+ // @ts-expect-error
4
2
  import type { ReactNode } from 'react';
5
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
- // @ts-ignore
7
- // eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
3
+ // @ts-expect-error
8
4
  import { useEffect, useRef, useState } from 'react';
9
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
10
- // @ts-ignore
11
- // eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
5
+ // @ts-expect-error
12
6
  import type { Root } from 'react-dom/client';
13
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
14
- // @ts-ignore
15
- // eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
7
+ // @ts-expect-error
16
8
  import { createRoot } from 'react-dom/client';
17
9
 
18
10
  import type { Store } from '../lib/store';
@@ -1,4 +1,6 @@
1
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1
+ /// 简单的垫片,让 GemElement 服务端渲染不报错
2
+ /// 渲染时将忽略 GemElement 内容
3
+
2
4
  // @ts-nocheck
3
5
  if (typeof window === 'undefined') {
4
6
  const getAny = () => {
@@ -1,14 +1,15 @@
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';
5
+ import type { Updater } from '../lib/utils';
3
6
  import { camelToKebabCase, createUpdater, randomStr } from '../lib/utils';
4
- import type { GemElement } from '../lib/element';
5
- import { SheetToken, css } from '../lib/element';
6
7
 
7
- export type Theme<T> = ReturnType<typeof createUpdater<T>> &
8
- ReturnType<typeof css> & {
8
+ export type Theme<T> = Updater<T> &
9
+ Sheet<unknown> & {
9
10
  [K in keyof T as K extends `${string}Color`
10
11
  ? `${string & K}${'' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900}`
11
- : K]: T[K];
12
+ : K]: string;
12
13
  };
13
14
 
14
15
  const themeStoreMap = new WeakMap();
@@ -52,7 +53,7 @@ function createThemeFromProps<T extends Record<string, unknown>>(themeObj: T, pr
52
53
  }
53
54
  rules += `${props[key]}:${store[key]};`;
54
55
  });
55
- styleSheet.setContent(`:scope,:host{${rules}}`);
56
+ styleSheet.setContent(`&,:host{${rules}}`);
56
57
  };
57
58
  updateContent();
58
59
  connect(store, () => {
@@ -81,19 +82,33 @@ export function createOverrideTheme<T extends Record<string, unknown>>(theme: Th
81
82
  return createThemeFromProps(themeObj, getThemeProps(theme));
82
83
  }
83
84
 
85
+ /**
86
+ * 返回一个主题对象,但同时又是一个装饰器函数,用来装饰一个主题更新函数
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * const elementTheme = createDecoratorTheme({ color: '' });
91
+ * class MyElement {
92
+ * @​elementTheme()
93
+ * #theme = () => ({ color: this.color });
94
+ * }
95
+ * ```
96
+ * */
84
97
  export function createDecoratorTheme<T extends Record<string, unknown>>(themeObj: T) {
85
- const themeAsKeys = createThemeFromProps<T>(themeObj);
98
+ const themeAsKeys = createThemeFromProps(themeObj);
86
99
  const props = getThemeProps(themeAsKeys);
87
- const update =
88
- <E extends GemElement, V extends () => T, K = any[] | undefined>(
89
- getDep?: K extends readonly any[] ? (instance: E) => K : undefined,
90
- ) =>
91
- (_: any, { addInitializer, access }: ClassFieldDecoratorContext<E, V> | ClassMethodDecoratorContext<E, V>) => {
100
+ const update = <E extends GemElement, V extends () => T, K = any[] | undefined>(
101
+ getDep?: K extends readonly any[] ? (instance: E) => K : undefined,
102
+ ) => {
103
+ type Ctx = ClassFieldDecoratorContext<E, V> | ClassMethodDecoratorContext<E, V>;
104
+ return (_: any, { addInitializer, access }: Ctx) => {
92
105
  addInitializer(function (this: E) {
93
106
  const theme = createThemeFromProps({ ...themeObj }, props);
94
- this.internals.sheets.push(theme[SheetToken].getStyle(this));
107
+ this.internals.sheets.push(theme[SheetToken].getStyle(this, true));
95
108
  this.memo(() => theme(access.get(this).apply(this)), getDep && (() => getDep(this) as any));
96
109
  });
97
110
  };
98
- return createUpdater(themeAsKeys, update) as ReturnType<typeof createUpdater<typeof themeAsKeys, typeof update>>;
111
+ };
112
+ // 不知道为什么 `as` 能解决外部 `SheetToken` 不能命名的问题
113
+ return createUpdater(themeAsKeys, update) as Updater<Theme<T>, typeof update>;
99
114
  }
package/src/index.ts CHANGED
@@ -1,8 +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';