@mantou/gem 1.7.1 → 1.7.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 (85) hide show
  1. package/dist/gem.es.js +357 -362
  2. package/dist/gem.umd.js +24 -28
  3. package/elements/base/dialog.d.ts +7 -7
  4. package/elements/base/dialog.d.ts.map +1 -1
  5. package/elements/base/dialog.js +10 -3
  6. package/elements/base/dialog.js.map +1 -1
  7. package/elements/base/gesture.d.ts +4 -13
  8. package/elements/base/gesture.d.ts.map +1 -1
  9. package/elements/base/gesture.js +151 -134
  10. package/elements/base/gesture.js.map +1 -1
  11. package/elements/base/link.d.ts +10 -10
  12. package/elements/base/link.d.ts.map +1 -1
  13. package/elements/base/link.js +69 -63
  14. package/elements/base/link.js.map +1 -1
  15. package/elements/base/modal-factory.d.ts +106 -83
  16. package/elements/base/modal-factory.d.ts.map +1 -1
  17. package/elements/base/modal-factory.js +12 -8
  18. package/elements/base/modal-factory.js.map +1 -1
  19. package/elements/base/reflect.js.map +1 -1
  20. package/elements/base/route.d.ts +12 -5
  21. package/elements/base/route.d.ts.map +1 -1
  22. package/elements/base/route.js +16 -4
  23. package/elements/base/route.js.map +1 -1
  24. package/elements/base/title.d.ts +3 -1
  25. package/elements/base/title.d.ts.map +1 -1
  26. package/elements/base/title.js +14 -16
  27. package/elements/base/title.js.map +1 -1
  28. package/elements/base/unsafe.js.map +1 -1
  29. package/elements/base/use.d.ts +1 -1
  30. package/elements/base/use.d.ts.map +1 -1
  31. package/elements/base/use.js +27 -17
  32. package/elements/base/use.js.map +1 -1
  33. package/helper/i18n.d.ts +2 -2
  34. package/helper/i18n.d.ts.map +1 -1
  35. package/helper/i18n.js.map +1 -1
  36. package/helper/mediaquery.d.ts +16 -18
  37. package/helper/mediaquery.d.ts.map +1 -1
  38. package/helper/mediaquery.js +42 -41
  39. package/helper/mediaquery.js.map +1 -1
  40. package/helper/request.d.ts +1 -1
  41. package/helper/request.d.ts.map +1 -1
  42. package/helper/request.js.map +1 -1
  43. package/helper/ssr-shim.js.map +1 -1
  44. package/helper/theme.d.ts +2 -2
  45. package/helper/theme.d.ts.map +1 -1
  46. package/helper/theme.js +20 -24
  47. package/helper/theme.js.map +1 -1
  48. package/lib/decorators.d.ts +4 -4
  49. package/lib/decorators.d.ts.map +1 -1
  50. package/lib/decorators.js +1 -2
  51. package/lib/decorators.js.map +1 -1
  52. package/lib/element.d.ts +5 -7
  53. package/lib/element.d.ts.map +1 -1
  54. package/lib/element.js +41 -69
  55. package/lib/element.js.map +1 -1
  56. package/lib/history.d.ts +1 -1
  57. package/lib/history.d.ts.map +1 -1
  58. package/lib/history.js +2 -2
  59. package/lib/history.js.map +1 -1
  60. package/lib/store.d.ts +2 -2
  61. package/lib/store.d.ts.map +1 -1
  62. package/lib/store.js.map +1 -1
  63. package/lib/utils.d.ts +8 -32
  64. package/lib/utils.d.ts.map +1 -1
  65. package/lib/utils.js +6 -21
  66. package/lib/utils.js.map +1 -1
  67. package/lib/version.d.ts +1 -1
  68. package/lib/version.js +1 -1
  69. package/package.json +2 -2
  70. package/src/elements/base/dialog.ts +8 -3
  71. package/src/elements/base/gesture.ts +51 -45
  72. package/src/elements/base/link.ts +64 -62
  73. package/src/elements/base/modal-factory.ts +5 -0
  74. package/src/elements/base/route.ts +21 -4
  75. package/src/elements/base/title.ts +8 -11
  76. package/src/elements/base/use.ts +3 -3
  77. package/src/helper/mediaquery.ts +43 -42
  78. package/src/helper/theme.ts +22 -24
  79. package/src/lib/decorators.ts +1 -2
  80. package/src/lib/element.ts +29 -58
  81. package/src/lib/history.ts +2 -1
  82. package/src/lib/utils.ts +10 -42
  83. package/src/lib/version.ts +1 -1
  84. package/src/test/history.test.ts +3 -1
  85. package/src/test/utils.test.ts +8 -1
@@ -27,26 +27,23 @@ export class GemTitleElement extends GemElement {
27
27
  // 没有后缀的标题
28
28
  static title = document.title;
29
29
  static defaultTitle = document.title;
30
+ static defaultPrefix = `${document.title} | `;
30
31
  static defaultSuffix = ` - ${document.title}`;
31
32
 
32
33
  static setTitle(title: string) {
33
34
  updateStore(titleStore, { title });
34
35
  }
35
36
 
36
- static updateTitle(str = '', suffix = '') {
37
- const { title } = titleStore;
38
- if (title && title !== GemTitleElement.defaultTitle) {
39
- GemTitleElement.title = title;
40
- document.title = GemTitleElement.title + suffix;
41
- } else if (str) {
42
- GemTitleElement.title = str;
43
- document.title = GemTitleElement.title + suffix;
37
+ static updateTitle(title = titleStore.title, prefix = '', suffix = '') {
38
+ if (title === GemTitleElement.defaultTitle) {
39
+ document.title = GemTitleElement.title = title;
44
40
  } else {
45
- GemTitleElement.title = GemTitleElement.defaultTitle;
46
- document.title = GemTitleElement.title;
41
+ GemTitleElement.title = title;
42
+ document.title = prefix + GemTitleElement.title + suffix;
47
43
  }
48
44
  }
49
45
 
46
+ @attribute prefix: string;
50
47
  @attribute suffix: string;
51
48
 
52
49
  constructor() {
@@ -56,7 +53,7 @@ export class GemTitleElement extends GemElement {
56
53
 
57
54
  render() {
58
55
  // 多个 <gem-title> 时,最终 document.title 按执行顺序决定
59
- GemTitleElement.updateTitle(this.textContent || '', this.suffix);
56
+ GemTitleElement.updateTitle(this.textContent || undefined, this.prefix, this.suffix);
60
57
 
61
58
  if (this.hidden) {
62
59
  return html``;
@@ -18,7 +18,7 @@ export class GemUseElement extends GemElement {
18
18
 
19
19
  @state active: boolean;
20
20
 
21
- private getContent() {
21
+ #getContent = () => {
22
22
  const ele = this.element || (this.selector ? (this.root || document).querySelector(this.selector) : null);
23
23
  if (typeof ele === 'string') {
24
24
  let temp = eleCache.get(ele);
@@ -33,7 +33,7 @@ export class GemUseElement extends GemElement {
33
33
  } else {
34
34
  return ele?.cloneNode(true);
35
35
  }
36
- }
36
+ };
37
37
 
38
38
  render() {
39
39
  return html`
@@ -48,7 +48,7 @@ export class GemUseElement extends GemElement {
48
48
  height: 100%;
49
49
  }
50
50
  </style>
51
- ${this.getContent()}
51
+ ${this.#getContent()}
52
52
  <slot></slot>
53
53
  `;
54
54
  }
@@ -1,77 +1,78 @@
1
1
  // https://gist.github.com/gokulkrishh/242e68d1ee94ad05f488
2
2
  // https://mediag.com/news/popular-screen-resolutions-designing-for-all/
3
3
 
4
- const matche = (query: string) => window.matchMedia(query).matches;
4
+ const match = (query: string) => window.matchMedia(query).matches;
5
5
 
6
6
  export const mediaQuery = {
7
7
  PRINT: 'print',
8
8
  get isPrint() {
9
- return matche(this.PRINT);
9
+ return match(this.PRINT);
10
10
  },
11
+
11
12
  HOVER: '(hover: hover)',
12
13
  get isHover() {
13
- return matche(this.HOVER);
14
- },
15
-
16
- PHONE: '(min-width: 319px) and (max-width: 480px)',
17
- get isPhone() {
18
- return matche(this.PHONE);
14
+ return match(this.HOVER);
19
15
  },
20
16
 
21
- LAPTOP: '(min-width: 1023px) and (max-width: 1280px) and (orientation: landscape)',
22
- get isLaptop() {
23
- return matche(this.LAPTOP);
17
+ PWA: '(display-mode: standalone)',
18
+ // PWA: '(display-mode: browser)', // debugging
19
+ get isPWA() {
20
+ return match(this.PWA);
24
21
  },
25
22
 
26
- DESKTOP: '(min-width: 1279px) and (orientation: landscape)',
27
- get isDesktop() {
28
- return matche(this.DESKTOP);
23
+ MOTION_REDUCE: '(prefers-reduced-motion: reduce)',
24
+ get isMotionReduce() {
25
+ return match(this.MOTION_REDUCE);
29
26
  },
30
27
 
31
- WIDTHSCREEN: '(min-width: 1919px) and (orientation: landscape)',
32
- get isWidthScreen() {
33
- return matche(this.WIDTHSCREEN);
28
+ DATA_REDUCE: '(prefers-reduced-data: reduce)',
29
+ get isDataReduce() {
30
+ return match(this.DATA_REDUCE);
34
31
  },
35
32
 
36
- PHONE_LANDSCAPE: '(min-width: 479px) and (max-width: 959px) and (orientation: landscape)',
37
- // PHONE_LANDSCAPE: '(min-width: 481px) and (max-width: 959px)',
38
- get isPhoneLandscape() {
39
- return matche(this.PHONE_LANDSCAPE);
33
+ WATCH: '(width < 320px)',
34
+ get isWatch() {
35
+ return match(this.WATCH);
40
36
  },
41
37
 
42
- TABLET: '(min-width: 768px) and (max-width: 1024px)',
43
- get isTablet() {
44
- return matche(this.TABLET);
38
+ SMALL_PHONE: '(320px <= width <= 480px) and (height <= 640px)',
39
+ get isSmallPhone() {
40
+ return match(this.SMALL_PHONE);
45
41
  },
46
42
 
47
- SMALL_PHONE: '(min-width: 319px) and (max-width: 480px) and (max-height: 640px)',
48
- get isSmallPhone() {
49
- return matche(this.SMALL_PHONE);
43
+ PHONE: '(320px <= width <= 480px)',
44
+ get isPhone() {
45
+ return match(this.PHONE);
50
46
  },
51
47
 
52
- WATCH: '(max-width: 319px)',
53
- get isWatch() {
54
- return matche(this.WATCH);
48
+ PHONE_LANDSCAPE: '(480px < width < 960px) and (orientation: landscape)',
49
+ // PHONE_LANDSCAPE: '(480px < width < 960px)',
50
+ get isPhoneLandscape() {
51
+ return match(this.PHONE_LANDSCAPE);
55
52
  },
56
53
 
57
- SHORT: '(min-width: 479px) and (max-height: 320px)',
54
+ // Widget
55
+ SHORT: '(width >= 480px) and (height <= 320px)',
58
56
  get isShort() {
59
- return matche(this.SHORT);
57
+ return match(this.SHORT);
60
58
  },
61
59
 
62
- PWA: '(display-mode: standalone)',
63
- // PWA: '(display-mode: browser)', // debugging
64
- get isPWA() {
65
- return matche(this.PWA);
60
+ // 1280 x 850
61
+ // 1024 x 768
62
+ TABLET: '(480px < width <= 1280px)',
63
+ get isTablet() {
64
+ return match(this.TABLET);
66
65
  },
67
66
 
68
- MOTION_REDUCE: '(prefers-reduced-motion: reduce)',
69
- get isMotionReduce() {
70
- return matche(this.MOTION_REDUCE);
67
+ // 1366x768
68
+ DESKTOP: '(width > 1280px) and (orientation: landscape)',
69
+ get isDesktop() {
70
+ return match(this.DESKTOP);
71
71
  },
72
72
 
73
- DATA_REDUCE: '(prefers-reduced-data: reduce)',
74
- get isDataReduce() {
75
- return matche(this.DATA_REDUCE);
73
+ // 1920x1080
74
+ WIDTHSCREEN: '(width >= 1920px) and (orientation: landscape)',
75
+ get isWidthScreen() {
76
+ return match(this.WIDTHSCREEN);
76
77
  },
77
78
  };
@@ -11,21 +11,13 @@ export function getThemeStore<T>(theme: SomeType<T>) {
11
11
  return themeStoreMap.get(theme) as Store<T>;
12
12
  }
13
13
 
14
- const themePropMap = new WeakMap();
14
+ const themePropsMap = new WeakMap();
15
15
 
16
- export function getThemeProp<T>(theme: SomeType<T>) {
17
- return themePropMap.get(theme) as SomeType<T>;
16
+ export function getThemeProps<T>(theme: SomeType<T>) {
17
+ return themePropsMap.get(theme) as SomeType<T>;
18
18
  }
19
19
 
20
- function replaceStyle(style: HTMLStyleElement, theme: Record<string, unknown>) {
21
- const themeStore = themeStoreMap.get(theme);
22
- const themeProp = themePropMap.get(theme);
23
- const rules = Object.keys(themeStore).reduce((prev, key) => {
24
- if (!themeStore[key] || !themeProp[key]) return prev;
25
- return prev + `${themeProp[key]}:${themeStore[key]};`;
26
- }, '');
27
- style.textContent = `:root, :host {${rules}}`;
28
- }
20
+ const setThemeFnMap = new WeakMap();
29
21
 
30
22
  /**
31
23
  * 创建主题,插入 `document.head`
@@ -39,17 +31,23 @@ function replaceStyle(style: HTMLStyleElement, theme: Record<string, unknown>) {
39
31
  export function createTheme<T extends Record<string, unknown>>(themeObj: T) {
40
32
  const salt = randomStr();
41
33
  const style = document.createElement('style');
42
- const themeStore = createStore<T>(themeObj);
34
+ const store = createStore<T>(themeObj);
43
35
  const theme: Record<string, string> = {};
44
- const themeProp: Record<string, string> = {};
45
- themePropMap.set(theme, themeProp);
46
- themeStoreMap.set(theme, themeStore);
47
- Object.keys(themeStore).forEach((key) => {
48
- themeProp[key] = `--${camelToKebabCase(key)}-${salt}`;
49
- theme[key] = `var(${themeProp[key]})`;
50
- });
51
- const replace = () => replaceStyle(style, theme);
52
- connect(themeStore, replace);
36
+ const props: Record<string, string> = {};
37
+ themePropsMap.set(theme, props);
38
+ themeStoreMap.set(theme, store);
39
+ const setTheme = () =>
40
+ Object.keys(store).forEach((key) => {
41
+ if (props[key]) return;
42
+ props[key] = `--${camelToKebabCase(key)}-${salt}`;
43
+ theme[key] = `var(${props[key]})`;
44
+ });
45
+ setThemeFnMap.set(theme, setTheme);
46
+ setTheme();
47
+ const getStyle = () =>
48
+ `:root, :host {${Object.keys(store).reduce((prev, key) => prev + `${props[key]}:${store[key]};`, '')}}`;
49
+ const replace = () => (style.textContent = getStyle());
50
+ connect(store, replace);
53
51
  replace();
54
52
  (document.head || document.documentElement).append(style);
55
53
  return theme as SomeType<T>;
@@ -61,6 +59,6 @@ export function createTheme<T extends Record<string, unknown>>(themeObj: T) {
61
59
  * @param newThemeObj 新主题
62
60
  */
63
61
  export function updateTheme<T = Record<string, unknown>>(theme: SomeType<T>, newThemeObj: Partial<T>) {
64
- const store = getThemeStore(theme);
65
- updateStore(store, newThemeObj);
62
+ updateStore(getThemeStore(theme), newThemeObj);
63
+ setThemeFnMap.get(theme)();
66
64
  }
@@ -191,7 +191,6 @@ export function adoptedStyle(style: Sheet<unknown>) {
191
191
  * ```
192
192
  */
193
193
  export function connectStore(store: Store<unknown>) {
194
- // 这里的签名该怎么写?
195
194
  return function (cls: unknown) {
196
195
  const con = cls as GemElementConstructor;
197
196
  pushStaticField(con.prototype, 'observedStores', store);
@@ -203,7 +202,7 @@ export function connectStore(store: Store<unknown>) {
203
202
  *
204
203
  * For example
205
204
  * ```ts
206
- * @rootElement(MyElement)
205
+ * @rootElement('my-element')
207
206
  * class App extends GemElement {}
208
207
  * ```
209
208
  */
@@ -13,7 +13,6 @@ import {
13
13
  kebabToCamelCase,
14
14
  PropProxyMap,
15
15
  removeItems,
16
- useNativeCSSStyleSheet,
17
16
  } from './utils';
18
17
  import * as GemExports from './element';
19
18
  import * as VersionExports from './version';
@@ -30,16 +29,13 @@ declare global {
30
29
  interface ElementInternals extends ARIAMixin {
31
30
  // https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet
32
31
  states: Set<string>;
33
- role?: string | null;
34
32
  }
35
33
  // 用于 css 选择器选择元素,使用 @refobject 自动选择获取
36
34
  // 必须使用 attr 赋值
37
35
  /**
38
36
  * @attr ref
39
- * @attr inert
40
37
  */
41
38
  interface HTMLElement {
42
- inert: boolean;
43
39
  ref: string;
44
40
  }
45
41
  }
@@ -88,6 +84,10 @@ export interface GemElementOptions {
88
84
  }
89
85
 
90
86
  export abstract class GemElement<T = Record<string, unknown>> extends HTMLElement {
87
+ // 禁止覆盖自定义元素原生生命周期方法
88
+ // https://github.com/microsoft/TypeScript/issues/21388#issuecomment-934345226
89
+ static #final = Symbol();
90
+
91
91
  // 这里只是字段申明,不能赋值,否则子类会继承被共享该字段
92
92
  static observedAttributes?: string[]; // WebAPI 中是实时检查这个列表
93
93
  static booleanAttributes?: Set<string>;
@@ -119,16 +119,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
119
119
 
120
120
  constructor({ isAsync, isLight, delegatesFocus, slotAssignment }: GemElementOptions = {}) {
121
121
  super();
122
- (this as any)[constructorSymbol] = true;
123
122
 
124
123
  // 外部不可见,但允许类外面使用
125
- addMicrotask(() => ((this as any)[initSymbol] = false));
126
- (this as any)[initSymbol] = true;
127
- (this as any)[updateSymbol] = () => {
124
+ addMicrotask(() => Reflect.set(this, initSymbol, false));
125
+ Reflect.set(this, constructorSymbol, true);
126
+ Reflect.set(this, initSymbol, true);
127
+ Reflect.set(this, updateSymbol, () => {
128
128
  if (this.#isMounted) {
129
129
  addMicrotask(this.#update);
130
130
  }
131
- };
131
+ });
132
132
 
133
133
  this.#isAsync = isAsync;
134
134
  this.#renderRoot = isLight ? this : this.attachShadow({ mode: 'open', delegatesFocus, slotAssignment });
@@ -142,34 +142,10 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
142
142
  this.effect(
143
143
  () => {
144
144
  const root = this.getRootNode() as ShadowRoot | Document;
145
- if (!useNativeCSSStyleSheet) {
146
- const ele: any = root === document ? document.body : root;
147
- ele._sheets = ele._sheets || {};
148
- sheets.forEach(({ style, media }: any) => {
149
- if (ele._sheets[style]) {
150
- ele._sheets[style].count++;
151
- } else {
152
- const s = document.createElement('style');
153
- s.innerHTML = style;
154
- s.media = media.mediaText;
155
- ele.append(s);
156
- ele._sheets[style] = { ele: s, count: 1 };
157
- }
158
- });
159
- return () => {
160
- sheets.forEach(({ style }: any) => {
161
- ele._sheets[style].count--;
162
- if (!ele._sheets[style].count) {
163
- delete ele._sheets[style];
164
- }
165
- });
166
- };
167
- } else {
168
- root.adoptedStyleSheets = [...root.adoptedStyleSheets, ...sheets];
169
- return () => {
170
- root.adoptedStyleSheets = removeItems(root.adoptedStyleSheets, sheets);
171
- };
172
- }
145
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, ...sheets];
146
+ return () => {
147
+ root.adoptedStyleSheets = removeItems(root.adoptedStyleSheets, sheets);
148
+ };
173
149
  },
174
150
  () => [],
175
151
  );
@@ -320,20 +296,8 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
320
296
 
321
297
  #render = () => {
322
298
  this.#execMemo();
323
- const styles = useNativeCSSStyleSheet
324
- ? ''
325
- : html`${this.shadowRoot?.adoptedStyleSheets?.map(
326
- (e: any) => html`
327
- <style media=${e.media.mediaText}>
328
- ${e.style}
329
- </style>
330
- `,
331
- )}`;
332
- if (this.render) {
333
- const r = this.render();
334
- return r && html`${r}${styles}`;
335
- }
336
- return this.#renderRoot === this ? undefined : html`<slot></slot>${styles}`;
299
+ if (this.render) return this.render();
300
+ return this.#renderRoot === this ? undefined : html`<slot></slot>`;
337
301
  };
338
302
 
339
303
  /**@lifecycle */
@@ -392,15 +356,18 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
392
356
  if (this.#isMounted) {
393
357
  addMicrotask(this.#update);
394
358
  }
359
+ return GemElement.#final;
395
360
  }
396
361
 
397
362
  #connectedCallback = () => {
398
- // 似乎这是最早的判断不在 `constructor` 中的地方
399
- (this as any)[constructorSymbol] = false;
400
363
  if (this.#isAppendReason) {
401
364
  this.#isAppendReason = false;
402
365
  return;
403
366
  }
367
+
368
+ // 似乎这是最早的判断不在 `constructor` 中的地方
369
+ Reflect.set(this, constructorSymbol, false);
370
+
404
371
  this.willMount?.();
405
372
  const { observedStores, rootElement } = this.constructor as typeof GemElement;
406
373
  observedStores?.forEach((store) => {
@@ -447,13 +414,16 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
447
414
  } else {
448
415
  this.#connectedCallback();
449
416
  }
417
+ return GemElement.#final;
450
418
  }
451
419
 
452
420
  /**
453
421
  * @private
454
422
  * @final
455
423
  */
456
- // adoptedCallback() {}
424
+ adoptedCallback() {
425
+ return GemElement.#final;
426
+ }
457
427
 
458
428
  /**
459
429
  * @private
@@ -477,6 +447,7 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
477
447
  });
478
448
  this.#effectList = this.#effectList?.filter(({ inConstructor }) => inConstructor);
479
449
  this.#memoList = this.#memoList?.filter(({ inConstructor }) => inConstructor);
450
+ return GemElement.#final;
480
451
  }
481
452
  }
482
453
 
@@ -503,7 +474,7 @@ export function defineAttribute(target: GemElement, prop: string, attr: string)
503
474
  },
504
475
  set(v: string | null | undefined | number | boolean) {
505
476
  const that = this as GemElement;
506
- const proxy = gemElementProxyMap.get(this) as any;
477
+ const proxy = gemElementProxyMap.get(this);
507
478
  const hasSet = proxy[prop];
508
479
  const value = that.getAttribute(attr);
509
480
  // https://github.com/whatwg/dom/issues/922
@@ -544,7 +515,7 @@ export function defineProperty(
544
515
  },
545
516
  set(v) {
546
517
  const that = this as GemElement;
547
- const proxy = gemElementProxyMap.get(that) as any;
518
+ const proxy = gemElementProxyMap.get(that);
548
519
  if (v !== proxy[prop]) {
549
520
  if (event) {
550
521
  proxy[prop] = v?.[isEventHandleSymbol]
@@ -554,7 +525,7 @@ export function defineProperty(
554
525
  that.dispatchEvent(evt);
555
526
  v(detail, options);
556
527
  };
557
- proxy[prop][isEventHandleSymbol] = true;
528
+ Reflect.set(proxy[prop]!, isEventHandleSymbol, true);
558
529
  // emitter 不触发元素更新
559
530
  } else {
560
531
  proxy[prop] = v;
@@ -627,7 +598,7 @@ customElements.define = (name: string, cls: CustomElementConstructor, options?:
627
598
  defineRefs?.forEach((ref) => defineRef(cls.prototype, kebabToCamelCase(ref), ref));
628
599
  }
629
600
 
630
- nativeDefineElement(name, cls as CustomElementConstructor, options);
601
+ nativeDefineElement(name, cls, options);
631
602
  };
632
603
 
633
604
  declare global {
@@ -1,3 +1,5 @@
1
+ // https://github.com/WICG/navigation-api#stakeholder-feedback
2
+
1
3
  import { createStore, updateStore, connect } from './store';
2
4
  import { QueryString, cleanObject, GemError, absoluteLocation } from './utils';
3
5
 
@@ -38,7 +40,6 @@ export interface UpdateHistoryParams {
38
40
  // 实际应用值
39
41
  type HistoryParams = UpdateHistoryParams & { title: string; path: string; query: QueryString; hash: string };
40
42
 
41
- // TODO: WeakRef
42
43
  const paramsMap = new Map<string, HistoryParams>();
43
44
 
44
45
  function validData(data: any) {
package/src/lib/utils.ts CHANGED
@@ -23,7 +23,7 @@ function execMicrotaskStack() {
23
23
 
24
24
  /**
25
25
  * 添加回调函数到微任务队列栈;
26
- * 先进后执行;
26
+ * 先进后执行,使用这个函数可以改变嵌套的元素 `mounted` 的顺序;
27
27
  */
28
28
  export function addMicrotaskToStack(func: () => void) {
29
29
  if (!microtaskStack.length) {
@@ -50,8 +50,8 @@ interface LinkedListItem<T> {
50
50
  next?: LinkedListItem<T>;
51
51
  }
52
52
  // work on nodejs
53
- export class LinkedList<T = any> extends (globalThis.EventTarget || Object) {
54
- addEventListener: <K extends keyof LinkedListEventMap>(
53
+ export class LinkedList<T = any> extends EventTarget {
54
+ declare addEventListener: <K extends keyof LinkedListEventMap>(
55
55
  type: K,
56
56
  listener: (this: LinkedList<T>, ev: LinkedListEventMap[K]) => any,
57
57
  options?: boolean | AddEventListenerOptions,
@@ -131,11 +131,6 @@ export class PropProxyMap<T extends NonPrimitive, V = unknown> extends WeakMap<T
131
131
  }
132
132
  }
133
133
 
134
- declare global {
135
- interface URLSearchParams {
136
- entries(): Iterable<readonly [string | number | symbol, any]>;
137
- }
138
- }
139
134
  export class QueryString extends URLSearchParams {
140
135
  constructor(param?: any) {
141
136
  super(param);
@@ -216,22 +211,6 @@ export type Sheet<T> = {
216
211
  [P in keyof T]: P;
217
212
  } & { [SheetToken]: CSSStyleSheet };
218
213
 
219
- declare global {
220
- interface CSSStyleSheet {
221
- replaceSync: (str: string) => void;
222
- }
223
-
224
- interface CSSRuleList {
225
- item(index: number): CSSStyleRule;
226
- }
227
- interface ShadowRoot {
228
- adoptedStyleSheets: CSSStyleSheet[];
229
- }
230
- interface Document {
231
- adoptedStyleSheets: CSSStyleSheet[];
232
- }
233
- }
234
-
235
214
  export type StyledType = 'id' | 'class' | 'keyframes';
236
215
  export interface StyledValueObject {
237
216
  styledContent: string;
@@ -241,22 +220,6 @@ export interface StyledKeyValuePair {
241
220
  [key: string]: StyledValueObject;
242
221
  }
243
222
 
244
- // !!! 目前只有 Chrome/FirefoxNightly 支持
245
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1520690
246
- // https://bugs.webkit.org/show_bug.cgi?id=228684
247
- export let useNativeCSSStyleSheet = true;
248
- let CSSStyleSheet = globalThis.CSSStyleSheet;
249
- try {
250
- new (CSSStyleSheet as any)();
251
- } catch {
252
- useNativeCSSStyleSheet = false;
253
- CSSStyleSheet = class {
254
- media = { mediaText: '' };
255
- style = '';
256
- replaceSync = (style: string) => (this.style = style);
257
- } as any;
258
- }
259
-
260
223
  /**
261
224
  *
262
225
  * 创建 style sheet 用于 `adoptedStyleSheets`,不支持样式更新
@@ -293,6 +256,8 @@ export function randomStr(number = 5, origin = '0123456789abcdefghijklmnopqrstuv
293
256
  const nestingRuleRegExp = new RegExp('&.*{((.|\n)*)}', 'g');
294
257
  // 只支持一层嵌套
295
258
  // https://drafts.csswg.org/css-nesting-1/
259
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1648037
260
+ // https://bugs.webkit.org/show_bug.cgi?id=223497
296
261
  function flatStyled(style: string, type: StyledType): StyledValueObject {
297
262
  const nestingRules: string[] = [];
298
263
  let styledContent =
@@ -404,6 +369,9 @@ export function classMap(object: Record<string, boolean>) {
404
369
 
405
370
  export const partMap = classMap;
406
371
 
407
- export function exportPartsMap(object: Record<string, string | undefined>) {
408
- return objectMapToString(object, ',', (key, value) => (value !== undefined ? `${key}:${value}` : ''));
372
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/exportparts
373
+ export function exportPartsMap(object: Record<string, string | undefined | boolean>) {
374
+ return objectMapToString(object, ',', (key, value) =>
375
+ value === true || key === value ? key : value ? `${key}:${value}` : '',
376
+ );
409
377
  }
@@ -1 +1 @@
1
- export const version = '1.7.1';
1
+ export const version = '1.7.2';
@@ -6,11 +6,13 @@ describe('history 测试', () => {
6
6
  it('hash', async () => {
7
7
  const historyLength = window.history.length;
8
8
  const hash = window.location.hash;
9
+ // 等待浏览器就绪
10
+ await aTimeout(1000);
9
11
  history.push({ path: '/a', hash: '#a' });
10
12
  await aTimeout(10);
11
13
  expect(window.location.hash).to.equal('#a');
12
14
  history.back();
13
- await aTimeout(600);
15
+ await aTimeout(10);
14
16
  expect(window.location.hash).to.equal(hash);
15
17
  history.push({ path: '/a', hash: '#b' });
16
18
  await aTimeout(10);
@@ -14,6 +14,12 @@ import {
14
14
  absoluteLocation,
15
15
  } from '../lib/utils';
16
16
 
17
+ declare global {
18
+ interface CSSRuleList {
19
+ item(index: number): CSSStyleRule;
20
+ }
21
+ }
22
+
17
23
  describe('utils 测试', () => {
18
24
  it('absoluteLocation', () => {
19
25
  expect(absoluteLocation('/a', '/a/b')).to.equal('/a/b');
@@ -101,6 +107,7 @@ describe('utils 测试', () => {
101
107
  `;--x:1px;font-size:14px;content:'*';`,
102
108
  );
103
109
  expect(classMap({ foo: true, content: false })).to.equal(` foo `);
104
- expect(exportPartsMap({ foo: 'bar', content: 'content' })).to.equal(`,foo:bar,content:content,`);
110
+ expect(exportPartsMap({ foo: 'bar', content: 'content', false: false })).to.equal(`,foo:bar,content,`);
111
+ expect(exportPartsMap({ foo: 'bar', content: true })).to.equal(`,foo:bar,content,`);
105
112
  });
106
113
  });