@mantou/gem 2.0.0-alpha.1 → 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 (55) hide show
  1. package/dist/gem.es.js +1159 -1166
  2. package/dist/gem.umd.js +25 -25
  3. package/elements/base/modal-factory.d.ts +12 -7
  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 +21 -16
  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 +2 -1
  21. package/lib/decorators.d.ts.map +1 -1
  22. package/lib/decorators.js +6 -0
  23. package/lib/decorators.js.map +1 -1
  24. package/lib/element.d.ts +6 -4
  25. package/lib/element.d.ts.map +1 -1
  26. package/lib/element.js +12 -15
  27. package/lib/element.js.map +1 -1
  28. package/lib/history.d.ts +20 -8
  29. package/lib/history.d.ts.map +1 -1
  30. package/lib/history.js +12 -12
  31. package/lib/history.js.map +1 -1
  32. package/lib/store.d.ts +5 -10
  33. package/lib/store.d.ts.map +1 -1
  34. package/lib/store.js +7 -22
  35. package/lib/store.js.map +1 -1
  36. package/lib/utils.d.ts +1 -0
  37. package/lib/utils.d.ts.map +1 -1
  38. package/lib/utils.js +19 -14
  39. package/lib/utils.js.map +1 -1
  40. package/package.json +4 -4
  41. package/src/elements/base/modal-factory.ts +3 -3
  42. package/src/elements/base/route.ts +7 -9
  43. package/src/elements/base/title.ts +2 -2
  44. package/src/helper/i18n.ts +11 -8
  45. package/src/helper/theme.ts +27 -26
  46. package/src/lib/decorators.ts +9 -2
  47. package/src/lib/element.ts +18 -19
  48. package/src/lib/history.ts +12 -12
  49. package/src/lib/store.ts +11 -31
  50. package/src/lib/utils.ts +21 -14
  51. package/src/test/gem-element/advance.test.ts +2 -2
  52. package/src/test/gem-element/basic.test.ts +3 -3
  53. package/src/test/gem-element/decorators.test.ts +4 -4
  54. package/src/test/store.test.ts +7 -7
  55. package/src/test/utils.test.ts +1 -1
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 *');