@mantou/gem 2.0.0 → 2.1.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.
Files changed (54) hide show
  1. package/dist/gem.es.js +1023 -1038
  2. package/dist/gem.umd.js +25 -25
  3. package/elements/base/modal-factory.d.ts +6 -4
  4. package/elements/base/modal-factory.d.ts.map +1 -1
  5. package/elements/base/modal-factory.js +3 -3
  6. package/elements/base/modal-factory.js.map +1 -1
  7. package/elements/base/route.d.ts +8 -2
  8. package/elements/base/route.d.ts.map +1 -1
  9. package/elements/base/route.js +4 -4
  10. package/elements/base/route.js.map +1 -1
  11. package/elements/base/title.js +2 -2
  12. package/elements/base/title.js.map +1 -1
  13. package/helper/i18n.d.ts.map +1 -1
  14. package/helper/i18n.js +11 -11
  15. package/helper/i18n.js.map +1 -1
  16. package/helper/theme.d.ts +8 -7
  17. package/helper/theme.d.ts.map +1 -1
  18. package/helper/theme.js +21 -21
  19. package/helper/theme.js.map +1 -1
  20. package/lib/decorators.d.ts +1 -1
  21. package/lib/decorators.d.ts.map +1 -1
  22. package/lib/decorators.js.map +1 -1
  23. package/lib/element.d.ts +3 -2
  24. package/lib/element.d.ts.map +1 -1
  25. package/lib/element.js +6 -9
  26. package/lib/element.js.map +1 -1
  27. package/lib/history.d.ts +20 -8
  28. package/lib/history.d.ts.map +1 -1
  29. package/lib/history.js +12 -12
  30. package/lib/history.js.map +1 -1
  31. package/lib/store.d.ts +5 -10
  32. package/lib/store.d.ts.map +1 -1
  33. package/lib/store.js +7 -22
  34. package/lib/store.js.map +1 -1
  35. package/lib/utils.d.ts +1 -0
  36. package/lib/utils.d.ts.map +1 -1
  37. package/lib/utils.js +19 -14
  38. package/lib/utils.js.map +1 -1
  39. package/package.json +3 -3
  40. package/src/elements/base/modal-factory.ts +3 -3
  41. package/src/elements/base/route.ts +4 -4
  42. package/src/elements/base/title.ts +2 -2
  43. package/src/helper/i18n.ts +11 -8
  44. package/src/helper/theme.ts +27 -26
  45. package/src/lib/decorators.ts +1 -1
  46. package/src/lib/element.ts +9 -12
  47. package/src/lib/history.ts +12 -12
  48. package/src/lib/store.ts +11 -31
  49. package/src/lib/utils.ts +21 -14
  50. package/src/test/gem-element/advance.test.ts +2 -2
  51. package/src/test/gem-element/basic.test.ts +3 -3
  52. package/src/test/gem-element/decorators.test.ts +4 -4
  53. package/src/test/store.test.ts +7 -7
  54. package/src/test/utils.test.ts +1 -1
@@ -14,7 +14,7 @@
14
14
 
15
15
  import { GemElement, html } from '../../lib/element';
16
16
  import { attribute, boolattribute, effect, mounted, shadow } from '../../lib/decorators';
17
- import { updateStore, connect } from '../../lib/store';
17
+ import { connect } from '../../lib/store';
18
18
  import { titleStore } from '../../lib/history';
19
19
 
20
20
  // 避免重定向时的中间状态标题
@@ -50,7 +50,7 @@ export class GemTitleElement extends GemElement {
50
50
  static title = document.title;
51
51
 
52
52
  static setTitle(title: string) {
53
- updateStore(titleStore, { title });
53
+ titleStore({ title });
54
54
  }
55
55
 
56
56
  @effect((i) => [i.inert])
@@ -113,6 +113,7 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
113
113
  this.onChange?.(lang);
114
114
  }
115
115
 
116
+ #inConstructor = true;
116
117
  constructor(options: I18nOptions<T>) {
117
118
  if (!options.resources[options.fallbackLanguage]) {
118
119
  throw new GemError('i18n: fallbackLanguage invalid');
@@ -139,6 +140,7 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
139
140
  } else {
140
141
  this.resetLanguage();
141
142
  }
143
+ this.#inConstructor = false;
142
144
  }
143
145
 
144
146
  get(s: keyof T): string;
@@ -207,14 +209,15 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
207
209
  }
208
210
  this.resources[lang] = pack;
209
211
 
210
- // update all element
211
- const temp: Element[] = [document.documentElement];
212
- while (!!temp.length) {
213
- const element = temp.pop()!;
214
- (element as any)[UpdateToken]?.();
215
- if (element.shadowRoot?.firstElementChild) temp.push(element.shadowRoot.firstElementChild);
216
- if (element.firstElementChild) temp.push(element.firstElementChild);
217
- if (element.nextElementSibling) temp.push(element.nextElementSibling);
212
+ if (!this.#inConstructor) {
213
+ // 更新所有元素,可能会更新许多不必要的元素
214
+ const temp: Element[] = [document.documentElement];
215
+ while (!!temp.length) {
216
+ const element = temp.pop()!;
217
+ (element as any)[UpdateToken]?.();
218
+ // 和 gem 更新机制一样使用深度优先
219
+ temp.push(...[...element.children, ...(element.shadowRoot?.children || [])].reverse());
220
+ }
218
221
  }
219
222
 
220
223
  if (lang !== this.currentLanguage) {
@@ -1,14 +1,15 @@
1
1
  import type { Store } from '../lib/store';
2
- import { connect, useStore } from '../lib/store';
3
- import { camelToKebabCase, randomStr } from '../lib/utils';
2
+ import { connect, createStore } from '../lib/store';
3
+ import { camelToKebabCase, createUpdater, randomStr } from '../lib/utils';
4
4
  import type { GemElement } from '../lib/element';
5
5
  import { SheetToken, createCSSSheet } from '../lib/element';
6
6
 
7
- export type Theme<T> = ReturnType<typeof createCSSSheet> & {
8
- [K in keyof T as K extends `${string}Color`
9
- ? `${string & K}${'' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900}`
10
- : K]: T[K];
11
- };
7
+ export type Theme<T> = ReturnType<typeof createUpdater<T>> &
8
+ ReturnType<typeof createCSSSheet> & {
9
+ [K in keyof T as K extends `${string}Color`
10
+ ? `${string & K}${'' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900}`
11
+ : K]: T[K];
12
+ };
12
13
 
13
14
  const themeStoreMap = new WeakMap();
14
15
  const themePropsMap = new WeakMap();
@@ -23,12 +24,12 @@ export function getThemeProps<T>(theme: Theme<T>) {
23
24
  return themePropsMap.get(theme) as Theme<T>;
24
25
  }
25
26
 
26
- function useThemeFromProps<T extends Record<string, unknown>>(themeObj: T, props: Record<string, string> = {}) {
27
+ function createThemeFromProps<T extends Record<string, unknown>>(themeObj: T, props: Record<string, string> = {}) {
27
28
  const salt = randomStr();
28
29
  const styleSheet = createCSSSheet({})[SheetToken];
29
- const [store, updateStore] = useStore<T>(themeObj);
30
+ const store = createStore<T>(themeObj);
30
31
  const theme: any = new Proxy(
31
- { [SheetToken]: styleSheet },
32
+ createUpdater({ [SheetToken]: styleSheet }, (payload: Partial<T>) => store(payload)),
32
33
  {
33
34
  get(target: any, key: string) {
34
35
  if (!target[key]) {
@@ -58,41 +59,41 @@ function useThemeFromProps<T extends Record<string, unknown>>(themeObj: T, props
58
59
  updateContent();
59
60
  styleSheet.updateStyle();
60
61
  });
61
- return [theme as Theme<T>, updateStore] as const;
62
+ return theme as Theme<T>;
62
63
  }
63
64
 
64
65
  /**
65
66
  * 用于 `@adoptedStyle(theme)`,类似 `createCSSSheet`
66
67
  */
67
- export function useScopedTheme<T extends Record<string, unknown>>(themeObj: T) {
68
- return useThemeFromProps(themeObj);
68
+ export function createScopedTheme<T extends Record<string, unknown>>(themeObj: T) {
69
+ return createThemeFromProps(themeObj);
69
70
  }
70
71
 
71
- /**全局主题 */
72
- export function useTheme<T extends Record<string, unknown>>(themeObj: T) {
73
- const result = useScopedTheme(themeObj);
74
- document.adoptedStyleSheets.push(result[0][SheetToken].getStyle());
72
+ /** 全局主题 */
73
+ export function createTheme<T extends Record<string, unknown>>(themeObj: T) {
74
+ const result = createScopedTheme(themeObj);
75
+ document.adoptedStyleSheets.push(result[SheetToken].getStyle());
75
76
  return result;
76
77
  }
77
78
 
78
- /**用来覆盖全局主题 */
79
- export function useOverrideTheme<T extends Record<string, unknown>>(theme: Theme<T>, themeObj: Partial<T>) {
80
- return useThemeFromProps(themeObj, getThemeProps(theme));
79
+ /** 用来覆盖全局主题 */
80
+ export function createOverrideTheme<T extends Record<string, unknown>>(theme: Theme<T>, themeObj: Partial<T>) {
81
+ return createThemeFromProps(themeObj, getThemeProps(theme));
81
82
  }
82
83
 
83
- export function useDecoratorTheme<T extends Record<string, unknown>>(themeObj: T) {
84
- const [themeAsKeys] = useThemeFromProps(themeObj);
84
+ export function createDecoratorTheme<T extends Record<string, unknown>>(themeObj: T) {
85
+ const themeAsKeys = createThemeFromProps<T>(themeObj);
85
86
  const props = getThemeProps(themeAsKeys);
86
- const updateDecorator =
87
+ const update =
87
88
  <E extends GemElement, V extends () => T, K = any[] | undefined>(
88
89
  getDep?: K extends readonly any[] ? (instance: E) => K : undefined,
89
90
  ) =>
90
91
  (_: any, { addInitializer, access }: ClassFieldDecoratorContext<E, V> | ClassMethodDecoratorContext<E, V>) => {
91
92
  addInitializer(function (this: E) {
92
- const [theme, update] = useThemeFromProps({ ...themeObj }, props);
93
+ const theme = createThemeFromProps({ ...themeObj }, props);
93
94
  this.internals.sheets.push(theme[SheetToken].getStyle(this));
94
- this.memo(() => update(access.get(this).apply(this)), getDep && (() => getDep(this) as any));
95
+ this.memo(() => theme(access.get(this).apply(this)), getDep && (() => getDep(this) as any));
95
96
  });
96
97
  };
97
- return [themeAsKeys, updateDecorator] as const;
98
+ return createUpdater(themeAsKeys, update) as ReturnType<typeof createUpdater<typeof themeAsKeys, typeof update>>;
98
99
  }
@@ -456,7 +456,7 @@ export function adoptedStyle(sheet: ReturnType<typeof createCSSSheet>) {
456
456
  * class App extends GemElement {}
457
457
  * ```
458
458
  */
459
- export function connectStore(store: Store<unknown>) {
459
+ export function connectStore(store: Store<any>) {
460
460
  return function (_: unknown, context: ClassDecoratorContext) {
461
461
  pushStaticField(context, 'observedStores', store);
462
462
  };
@@ -5,7 +5,7 @@ import type { GemReflectElement } from '../elements/reflect';
5
5
 
6
6
  import type { Store } from './store';
7
7
  import { connect } from './store';
8
- import { LinkedList, addMicrotask, isArrayChange, addListener, randomStr } from './utils';
8
+ import { LinkedList, addMicrotask, isArrayChange, addListener, randomStr, createUpdater } from './utils';
9
9
 
10
10
  export { html, svg, render, directive, TemplateResult, SVGTemplateResult } from 'lit-html';
11
11
 
@@ -29,7 +29,7 @@ declare global {
29
29
  }
30
30
  }
31
31
 
32
- const { assign, defineProperty, setPrototypeOf } = Object;
32
+ const { assign, defineProperty } = Object;
33
33
 
34
34
  defineProperty(Symbol, 'metadata', { value: Symbol.for('Symbol.metadata') });
35
35
 
@@ -177,8 +177,9 @@ export function createCSSSheet<T extends Record<string, string>>(
177
177
  Object.keys(rules).forEach((key) => {
178
178
  const isScope = key === '$';
179
179
  // 对于已经有 `-` 的保留原始 key,支持覆盖修改
180
+ // :scope 下可以写嵌套样式 &:xxx,:host() 下不行(子内容可以)
180
181
  sheet[key] = isScope || key.includes('-') ? key : `${key}-${randomStr()}`;
181
- style += `${isScope ? ':scope,:host' : `.${sheet[key]}`} {${rules[key]}}`;
182
+ style += `${isScope ? ':where(:scope:not([hidden])),:host(:where(:not([hidden])))' : `.${sheet[key]}`} {${rules[key]}}`;
182
183
  });
183
184
  }
184
185
  styleSheet.setContent(style);
@@ -221,7 +222,7 @@ const appleCSSStyleSheet = (ele: HTMLElement, sheets: CSSStyleSheet[]) => {
221
222
  };
222
223
 
223
224
  /**必须使用在字段中,否则会读取到错误的实例 */
224
- export let createState: <T>(initState: T) => T & ((state: Partial<T>) => void);
225
+ export let createState: <T>(initState: T) => ReturnType<typeof createUpdater<T>>;
225
226
 
226
227
  type GetDepFun<T> = () => T;
227
228
  type EffectCallback<T> = (depValues: T, oldDepValues?: T) => any;
@@ -273,7 +274,7 @@ export type Metadata = Partial<ShadowRootInit> & {
273
274
  }
274
275
  >;
275
276
  // 实例化时使用到,DevTools 需要读取
276
- observedStores: Store<unknown>[];
277
+ observedStores: Store<any>[];
277
278
  adoptedStyleSheets?: Sheet<unknown>[];
278
279
  // 以下静态字段仅供外部读取,没有实际作用
279
280
  observedProperties?: string[];
@@ -331,17 +332,13 @@ export abstract class GemElement extends HTMLElement {
331
332
  static {
332
333
  createState = <T>(initState: T) => {
333
334
  const ele = currentConstructGemElement;
334
- const state: any = (payload: Partial<T>) => {
335
+ const state = createUpdater(initState, (payload) => {
335
336
  assign(state, payload);
336
337
  // 避免无限刷新
337
338
  if (!ele.#rendering) addMicrotask(ele.#update);
338
- };
339
- setPrototypeOf(state, null);
340
- delete state.name;
341
- delete state.length;
339
+ });
342
340
  ele.#internals.stateList.push(state);
343
- assign(state, initState);
344
- return state as T & ((this: GemElement, state: Partial<T>) => void);
341
+ return state;
345
342
  };
346
343
  createRef = () => new RefObject(currentConstructGemElement);
347
344
  createTemplate = (ele, item) => ele.#renderList.push(item);
@@ -1,6 +1,6 @@
1
1
  // https://github.com/WICG/navigation-api#stakeholder-feedback
2
2
 
3
- import { connect, useStore } from './store';
3
+ import { connect, createStore } from './store';
4
4
  import { QueryString, cleanObject, GemError, absoluteLocation } from './utils';
5
5
 
6
6
  const nativeHistory = window.history;
@@ -18,7 +18,7 @@ export interface HistoryState {
18
18
  [index: string]: any;
19
19
  }
20
20
 
21
- const [store, updateHistoryStore] = useStore<HistoryState>({
21
+ const store = createStore<HistoryState>({
22
22
  $hasCloseHandle: false,
23
23
  $hasOpenHandle: false,
24
24
  $hasShouldCloseHandle: false,
@@ -103,7 +103,7 @@ function updateHistory(p: UpdateHistoryParams, native: typeof nativeHistory.push
103
103
  paramsMap.set(state.$key, params);
104
104
  dispatchBeforeChangeEvent();
105
105
  cleanObject(store);
106
- updateHistoryStore(state);
106
+ store(state);
107
107
  const url = getUrlBarPath(path) + new QueryString(query) + hash;
108
108
  const prevHash = decodeURIComponent(location.hash);
109
109
  native(state, title, url);
@@ -123,7 +123,7 @@ function updateHistoryByNative(data: any, title: string, originUrl: string, nati
123
123
  paramsMap.set(state.$key, params);
124
124
  dispatchBeforeChangeEvent();
125
125
  cleanObject(store);
126
- updateHistoryStore(state);
126
+ store(state);
127
127
  const url = getUrlBarPath(pathname) + params.query + hash;
128
128
  const prevHash = location.hash;
129
129
  native(state, title, url);
@@ -131,7 +131,7 @@ function updateHistoryByNative(data: any, title: string, originUrl: string, nati
131
131
  if (prevHash !== hash) window.dispatchEvent(new CustomEvent('hashchange'));
132
132
  }
133
133
 
134
- const [gemBasePathStore, updateBasePathStore] = useStore({
134
+ const gemBasePathStore = createStore({
135
135
  basePath: '',
136
136
  });
137
137
 
@@ -147,7 +147,7 @@ class GemHistory extends EventTarget {
147
147
  }
148
148
  set basePath(basePath: string) {
149
149
  // 应用初始化的时候设置
150
- updateBasePathStore({ basePath });
150
+ gemBasePathStore({ basePath });
151
151
  // paramsMap 更新后 ui 才会更新
152
152
  Object.assign(paramsMap.get(store.$key)!, { path: getInternalPath(location.pathname) });
153
153
  }
@@ -156,7 +156,7 @@ class GemHistory extends EventTarget {
156
156
  }
157
157
  updateParams(params: UpdateHistoryParams) {
158
158
  Object.assign(paramsMap.get(store.$key)!, params);
159
- updateHistoryStore();
159
+ store();
160
160
  }
161
161
  push(params: UpdateHistoryParams) {
162
162
  updateHistory(params, nativePushState);
@@ -183,7 +183,7 @@ class GemHistory extends EventTarget {
183
183
  // `<gem-**>` 只读写父应用 `basePath`
184
184
  const gemHistory = new GemHistory();
185
185
 
186
- const [gemTitleStore, updateTitleStore] = useStore({ defaultTitle: document.title, url: '', title: '' });
186
+ const gemTitleStore = createStore({ defaultTitle: document.title, url: '', title: '' });
187
187
 
188
188
  const _GEMHISTORY = { history: gemHistory, titleStore: gemTitleStore, basePathStore: gemBasePathStore };
189
189
 
@@ -217,7 +217,7 @@ if (!window._GEMHISTORY) {
217
217
  // 支持在 `data:` `blob:` 中 `import`
218
218
  if (protocol.startsWith('http')) gemHistory.replace({ path: pathname, query: search, hash });
219
219
  } else if (nativeHistory.state.$hasCloseHandle) {
220
- updateHistoryStore(nativeHistory.state);
220
+ store(nativeHistory.state);
221
221
  const params = normalizeParams({ title: document.title });
222
222
  paramsMap.set(store.$key, params);
223
223
  // 有 handle 返回键的页面刷新需要清除返回 handler
@@ -225,7 +225,7 @@ if (!window._GEMHISTORY) {
225
225
  } else {
226
226
  // 有 gem 历史的正常普通刷新, 储存 params
227
227
  const params = normalizeParams({ title: document.title, hash: location.hash });
228
- updateHistoryStore({
228
+ store({
229
229
  $key: getKey(),
230
230
  ...(nativeHistory.state || {}),
231
231
  });
@@ -242,7 +242,7 @@ if (!window._GEMHISTORY) {
242
242
  connect(store, () => {
243
243
  const { title } = gemHistory.getParams();
244
244
  if (title !== gemTitleStore.title) {
245
- updateTitleStore({ title });
245
+ gemTitleStore({ title });
246
246
  }
247
247
  });
248
248
 
@@ -312,7 +312,7 @@ if (!window._GEMHISTORY) {
312
312
 
313
313
  dispatchBeforeChangeEvent();
314
314
  cleanObject(store);
315
- updateHistoryStore(newState);
315
+ store(newState);
316
316
  });
317
317
  }
318
318
 
package/src/lib/store.ts CHANGED
@@ -1,40 +1,20 @@
1
- import type { NonPrimitive } from './utils';
2
- import { addMicrotask, GemError } from './utils';
1
+ import { addMicrotask, createUpdater } from './utils';
3
2
 
4
- export const StoreListenerMap = new WeakMap<NonPrimitive, Set<() => void>>();
3
+ export type Store<T = any> = ReturnType<typeof createUpdater<T>>;
5
4
 
6
- // 限制 `updateStore` 的参数类型
7
- export type Store<T> = T & { '': string };
5
+ export const StoreListenerMap = new WeakMap<Store<any>, Set<() => void>>();
8
6
 
9
- export function createStore<T extends NonPrimitive>(originStore: T) {
10
- if (StoreListenerMap.has(originStore)) {
11
- throw new GemError('argument error');
12
- }
13
- StoreListenerMap.set(originStore, new Set<() => void>());
14
- return originStore as Store<T>;
15
- }
16
-
17
- export function updateStore<T extends NonPrimitive>(store: Store<T>, value?: Partial<T>) {
18
- Object.assign(store, value);
19
- StoreListenerMap.get(store)?.forEach((func) => {
20
- addMicrotask(func);
7
+ export function createStore<T = any>(originStore: T) {
8
+ const store = createUpdater(originStore, (value?: Partial<T>) => {
9
+ Object.assign(store, value);
10
+ StoreListenerMap.get(store)?.forEach((func) => addMicrotask(func));
21
11
  });
12
+ StoreListenerMap.set(store, new Set<() => void>());
13
+ return store;
22
14
  }
23
15
 
24
- export function useStore<T extends NonPrimitive>(originStore: T) {
25
- const store = createStore(originStore);
26
- return [store, (value?: Partial<T>) => updateStore(store, value)] as const;
27
- }
28
-
29
- export function connect<T extends NonPrimitive>(store: Store<T>, func: () => void) {
16
+ export function connect(store: Store<any>, func: () => void) {
30
17
  const listeners = StoreListenerMap.get(store);
31
18
  listeners?.add(func);
32
- return () => {
33
- listeners?.delete(func);
34
- };
35
- }
36
-
37
- export function disconnect<T extends NonPrimitive>(store: Store<T>, func: () => void) {
38
- const listeners = StoreListenerMap.get(store);
39
- listeners?.delete(func);
19
+ return () => listeners?.delete(func);
40
20
  }
package/src/lib/utils.ts CHANGED
@@ -1,18 +1,25 @@
1
- let microtaskSet = new Set<() => void>();
1
+ const { assign, setPrototypeOf, fromEntries, entries, keys } = Object;
2
+
3
+ const microtaskSet = new Set<() => void>();
2
4
  export function addMicrotask(func: () => void) {
3
- if (typeof func !== 'function') return;
4
- if (!microtaskSet.size) {
5
- // delayed execution callback after updating store
6
- globalThis.queueMicrotask(() => {
7
- const set = microtaskSet;
8
- microtaskSet = new Set();
9
- set.forEach((f) => f());
10
- });
11
- }
12
- microtaskSet.delete(func);
5
+ if (microtaskSet.has(func)) return;
6
+ queueMicrotask(() => {
7
+ microtaskSet.delete(func);
8
+ func();
9
+ });
13
10
  microtaskSet.add(func);
14
11
  }
15
12
 
13
+ export function createUpdater<T, Fn = (payload?: Partial<T>) => any>(initState: T, fn: Fn) {
14
+ const state: any = fn;
15
+ setPrototypeOf(state, null);
16
+ delete state.name;
17
+ delete state.length;
18
+ assign(state, initState);
19
+ // TODO: type
20
+ return state as Fn & T;
21
+ }
22
+
16
23
  // 不编码 hash 用于比较
17
24
  export function absoluteLocation(currentPath = '', relativePath = '') {
18
25
  const { pathname, search, hash } = new URL(relativePath, location.origin + currentPath);
@@ -156,11 +163,11 @@ export class QueryString extends URLSearchParams {
156
163
  concat(param: any) {
157
164
  let query: any;
158
165
  if (typeof param === 'string') {
159
- query = Object.fromEntries(new URLSearchParams(param).entries());
166
+ query = fromEntries(new URLSearchParams(param).entries());
160
167
  } else {
161
168
  query = param;
162
169
  }
163
- Object.entries(query).forEach(([key, value]) => {
170
+ entries(query).forEach(([key, value]) => {
164
171
  this.append(key, this.#stringify(value));
165
172
  });
166
173
  }
@@ -247,7 +254,7 @@ export function kebabToCamelCase(str: string) {
247
254
  }
248
255
 
249
256
  export function cleanObject<T extends Record<string, unknown>>(o: T) {
250
- Object.keys(o).forEach((key: keyof T) => {
257
+ keys(o).forEach((key: keyof T) => {
251
258
  delete o[key];
252
259
  });
253
260
  return o;
@@ -10,7 +10,7 @@ import { fixture, expect, nextFrame } from '@open-wc/testing';
10
10
 
11
11
  import type { Metadata } from '../../lib/element';
12
12
  import { createCSSSheet, createState, GemElement, html, createRef } from '../../lib/element';
13
- import { createStore, updateStore } from '../../lib/store';
13
+ import { createStore } from '../../lib/store';
14
14
  import {
15
15
  attribute,
16
16
  property,
@@ -45,7 +45,7 @@ describe('异步 gem element 测试', () => {
45
45
  it('异步 gem element 更新', async () => {
46
46
  const el: AsyncGemDemo = await fixture(html`<async-gem-demo></async-gem-demo>`);
47
47
  expect(el.renderCount).to.equal(1);
48
- updateStore(store, { a: ++store.a });
48
+ store({ a: ++store.a });
49
49
  el.internals.stateList[0]({ a: ++(el.internals.stateList[0] as any).a });
50
50
  await nextFrame();
51
51
  expect(el.renderCount).to.equal(2);
@@ -1,7 +1,7 @@
1
1
  import { fixture, expect, nextFrame } from '@open-wc/testing';
2
2
 
3
3
  import { createCSSSheet, createState, GemElement, html } from '../../lib/element';
4
- import { createStore, updateStore } from '../../lib/store';
4
+ import { createStore } from '../../lib/store';
5
5
  import { css } from '../../lib/utils';
6
6
  import {
7
7
  adoptedStyle,
@@ -142,8 +142,8 @@ describe('基本 gem element 测试', () => {
142
142
  it('更新 store', async () => {
143
143
  const a = store.a;
144
144
  const el: GemDemo = await fixture(html`<gem-demo></gem-demo>`);
145
- updateStore(store, { a: ++store.a });
146
- updateStore(store, { a: ++store.a });
145
+ store({ a: ++store.a });
146
+ store({ a: ++store.a });
147
147
  expect(store.a).to.equal(a + 2);
148
148
  expect(el.renderCount).to.equal(1);
149
149
  await Promise.resolve();
@@ -2,7 +2,7 @@ import { fixture, expect } from '@open-wc/testing';
2
2
 
3
3
  import type { Metadata } from '../../lib/element';
4
4
  import { createCSSSheet, GemElement, html, createRef } from '../../lib/element';
5
- import { createStore, updateStore } from '../../lib/store';
5
+ import { createStore } from '../../lib/store';
6
6
  import { css } from '../../lib/utils';
7
7
  import type { Emitter } from '../../lib/decorators';
8
8
  import {
@@ -81,10 +81,10 @@ describe('装饰器', () => {
81
81
  rank-count="2"
82
82
  ></decorator-gem-demo>
83
83
  `);
84
- updateStore(store, { a: 1 });
84
+ store({ a: 1 });
85
85
  await Promise.resolve();
86
86
  const metadata: Metadata = Reflect.get(DecoratorGemElement, Symbol.metadata);
87
- expect(metadata.observedStores).to.eql([{ a: 1 }]);
87
+ expect({ ...metadata.observedStores.at(0) }).to.eql({ a: 1 });
88
88
  expect(metadata.observedAttributes).to.eql(['rank-attr', 'rank-disabled', 'rank-count']);
89
89
  expect(metadata.definedEvents).to.eql(['say-hi']);
90
90
  expect(metadata.definedCSSStates).to.eql(['open-state']);
@@ -102,7 +102,7 @@ describe('装饰器', () => {
102
102
  expect(el.inputRef.ref.startsWith('ref-')).to.equal(true);
103
103
  expect(el.bodySlot).to.equal('body-slot');
104
104
  expect(el).shadowDom.to.equal('attr: attr, disabled: true, count: 2, prop: prop');
105
- updateStore(store, { a: 3 });
105
+ store({ a: 3 });
106
106
  await Promise.resolve();
107
107
  expect(el.renderCount).to.equal(3);
108
108
  el.sayHi(2);
@@ -1,27 +1,27 @@
1
1
  import { expect, aTimeout } from '@open-wc/testing';
2
2
 
3
- import { StoreListenerMap, createStore, updateStore, connect, disconnect } from '../lib/store';
3
+ import { StoreListenerMap, createStore, connect } from '../lib/store';
4
4
 
5
5
  describe('store 测试', () => {
6
6
  it('create store', () => {
7
7
  const origin = { a: 1 };
8
8
  const store = createStore(origin);
9
- expect(store).to.equal(origin);
9
+ expect({ ...store }).to.deep.equal(origin);
10
10
  expect(!!StoreListenerMap.get(store)).to.equal(true);
11
11
  });
12
12
  it('update store', async () => {
13
13
  const store = createStore({ a: 1 });
14
14
  let flag = true;
15
15
  const update = () => (flag = !flag);
16
- connect(store, update);
17
- updateStore(store, { a: 1 });
16
+ const disconnect = connect(store, update);
17
+ store({ a: 1 });
18
18
  await aTimeout(0);
19
19
  expect(flag).to.equal(false);
20
- updateStore(store);
20
+ store();
21
21
  await aTimeout(0);
22
22
  expect(flag).to.equal(true);
23
- disconnect(store, update);
24
- updateStore(store, { a: 1 });
23
+ disconnect();
24
+ store({ a: 1 });
25
25
  await aTimeout(0);
26
26
  expect(flag).to.equal(true);
27
27
  });
@@ -112,7 +112,7 @@ describe('utils 测试', () => {
112
112
  });
113
113
  expect(cssSheet.scroll.startsWith('scroll')).to.true;
114
114
  const rules = cssSheet[SheetToken].getStyle().cssRules;
115
- expect(rules.item(0).selectorText).to.equal(':scope, :host');
115
+ expect(rules.item(0).selectorText).to.equal(':where(:scope:not([hidden])), :host(:where(:not([hidden])))');
116
116
  expect(rules.item(1).selectorText.startsWith('.scroll')).to.true;
117
117
  expect(rules.item(1).style.background).to.equal('red');
118
118
  expect(rules.item(1).cssRules.item(0).selectorText).to.equal('&:hover *');