@mantou/gem 2.3.0 → 2.3.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 (74) hide show
  1. package/AGENTS.md +150 -0
  2. package/dist/gem.js +6 -6
  3. package/dist/gem.mjs +6 -6
  4. package/elements/base/dialog.d.ts.map +1 -1
  5. package/elements/base/gesture.d.ts.map +1 -1
  6. package/elements/base/gesture.js +20 -1
  7. package/elements/base/gesture.js.map +1 -1
  8. package/elements/base/link.d.ts.map +1 -1
  9. package/elements/base/link.js +1 -1
  10. package/elements/base/link.js.map +1 -1
  11. package/elements/base/modal-factory.d.ts +20 -511
  12. package/elements/base/modal-factory.d.ts.map +1 -1
  13. package/elements/base/modal-factory.js +3 -2
  14. package/elements/base/modal-factory.js.map +1 -1
  15. package/elements/base/reflect.d.ts +7 -4
  16. package/elements/base/reflect.d.ts.map +1 -1
  17. package/elements/base/reflect.js +30 -4
  18. package/elements/base/reflect.js.map +1 -1
  19. package/elements/base/route.d.ts +3 -6
  20. package/elements/base/route.d.ts.map +1 -1
  21. package/elements/base/route.js +1 -1
  22. package/elements/base/route.js.map +1 -1
  23. package/elements/base/title.d.ts.map +1 -1
  24. package/elements/base/title.js +1 -1
  25. package/elements/base/title.js.map +1 -1
  26. package/helper/hmr.js.map +1 -1
  27. package/helper/i18n.d.ts +21 -17
  28. package/helper/i18n.d.ts.map +1 -1
  29. package/helper/i18n.js +172 -116
  30. package/helper/i18n.js.map +1 -1
  31. package/helper/logger.d.ts.map +1 -1
  32. package/helper/mediaquery.d.ts.map +1 -1
  33. package/helper/request.d.ts +7 -1
  34. package/helper/request.d.ts.map +1 -1
  35. package/helper/request.js.map +1 -1
  36. package/helper/theme.d.ts.map +1 -1
  37. package/helper/theme.js.map +1 -1
  38. package/lib/decorators.d.ts +3 -2
  39. package/lib/decorators.d.ts.map +1 -1
  40. package/lib/decorators.js +2 -1
  41. package/lib/decorators.js.map +1 -1
  42. package/lib/directive.d.ts.map +1 -1
  43. package/lib/element.d.ts +5 -1
  44. package/lib/element.d.ts.map +1 -1
  45. package/lib/element.js.map +1 -1
  46. package/lib/history.d.ts +46 -42
  47. package/lib/history.d.ts.map +1 -1
  48. package/lib/lit-html.d.ts.map +1 -1
  49. package/lib/lit-html.js.map +1 -1
  50. package/lib/reactive.d.ts +1 -4
  51. package/lib/reactive.d.ts.map +1 -1
  52. package/lib/reactive.js +1 -3
  53. package/lib/reactive.js.map +1 -1
  54. package/lib/repeat.d.ts +1 -1
  55. package/lib/repeat.d.ts.map +1 -1
  56. package/lib/repeat.js.map +1 -1
  57. package/lib/utils.d.ts.map +1 -1
  58. package/lib/version.d.ts +1 -1
  59. package/lib/version.js +1 -1
  60. package/package.json +6 -5
  61. package/src/elements/base/gesture.ts +20 -1
  62. package/src/elements/base/modal-factory.ts +22 -6
  63. package/src/elements/base/reflect.ts +30 -4
  64. package/src/elements/base/route.ts +2 -7
  65. package/src/helper/i18n.ts +184 -127
  66. package/src/lib/decorators.ts +2 -1
  67. package/src/lib/element.ts +5 -4
  68. package/src/lib/reactive.ts +1 -6
  69. package/src/lib/version.ts +1 -1
  70. package/src/test/elements/link.test.ts +12 -2
  71. package/src/test/elements/reflect.test.ts +20 -1
  72. package/src/test/elements/unsafe.test.ts +22 -0
  73. package/src/test/gem-element/advance.test.ts +87 -0
  74. package/src/test/utils.test.ts +4 -0
@@ -50,9 +50,6 @@ const ElementCSSState = 'gem-element';
50
50
  /** 渲染出错时在元素上派发,`@fallback` 处理时取消,SSR 时 `@server` 方法出错也会派发 */
51
51
  export const _RenderErrorEvent = 'gem@render-error';
52
52
 
53
- // fix modal-factory type error
54
- const updateTokenAlias = UpdateToken;
55
-
56
53
  // 渲染根中 light DOM 元素使用的样式表和使用次数,以及更新渲染根样式表的函数
57
54
  type RootSheets = { counts: Map<CSSStyleSheet, number>; update: () => void };
58
55
  const rootSheetsMap = new WeakMap<Document | ShadowRoot, RootSheets>();
@@ -268,8 +265,6 @@ export type Metadata = Partial<ShadowRootInit> & {
268
265
  definedCSSStates?: string[];
269
266
  definedParts?: string[];
270
267
  definedSlots?: string[];
271
- /**@deprecated GemDevtools 在使用*/
272
- definedRefs?: string[];
273
268
  };
274
269
 
275
270
  // global render task pool
@@ -323,7 +318,7 @@ export abstract class GemElement extends HTMLElement {
323
318
  #rendering?: boolean;
324
319
  #clearStyle?: (() => void) | undefined;
325
320
 
326
- [updateTokenAlias]() {
321
+ [UpdateToken]() {
327
322
  this.#scheduleUpdate();
328
323
  }
329
324
 
@@ -1 +1 @@
1
- export const version = '2.3.0';
1
+ export const version = '2.3.2';
@@ -1,6 +1,7 @@
1
- import type { GemActiveLinkElement } from '../../elements/link';
1
+ import type { GemActiveLinkElement, GemLinkElement } from '../../elements/link';
2
2
  import { html } from '../../lib/element';
3
- import { expect, fixture } from '../utils';
3
+ import { history } from '../../lib/history';
4
+ import { expect, fixture, nextFrame } from '../utils';
4
5
 
5
6
  import '../../elements/link';
6
7
 
@@ -11,4 +12,13 @@ describe('GemLinkElement', () => {
11
12
  );
12
13
  expect(ele.active).to.equal(true);
13
14
  });
15
+ it('basePath', async () => {
16
+ const ele: GemLinkElement = await fixture(html`<gem-link href="/a">a</gem-link>`);
17
+ const getHref = () => new URL(ele.shadowRoot!.querySelector('a')!.href).pathname;
18
+ expect(getHref()).to.equal('/a');
19
+ history.basePath = '/base';
20
+ await nextFrame();
21
+ expect(getHref()).to.equal('/base/a');
22
+ history.basePath = '';
23
+ });
14
24
  });
@@ -1,4 +1,4 @@
1
- import type { GemReflectElement } from '../../elements/reflect';
1
+ import { type GemReflectElement, getLogicalParent } from '../../elements/reflect';
2
2
  import { adoptedStyle, customElement } from '../../lib/decorators';
3
3
  import { css, GemElement, html } from '../../lib/element';
4
4
  import { expect, fixture, nextFrame } from '../utils';
@@ -34,4 +34,23 @@ describe('GemReflectElement', () => {
34
34
  reflect.remove();
35
35
  expect(!!document.querySelector('#one')).to.equal(false);
36
36
  });
37
+
38
+ it('logical parent', async () => {
39
+ const reflect: GemReflectElement = await fixture(html`
40
+ <gem-reflect .target=${document.body}><div id="three"><span></span></div></gem-reflect>
41
+ `);
42
+ const div = document.body.querySelector('#three')!;
43
+ expect(getLogicalParent(div)).to.equal(reflect);
44
+ expect(getLogicalParent(div.firstElementChild!)).to.equal(div);
45
+ // 移动后插入片段的节点
46
+ const added = document.createElement('p');
47
+ div.after(added);
48
+ expect(getLogicalParent(added)).to.equal(reflect);
49
+ // 片段外的节点
50
+ expect(getLogicalParent(reflect.parentElement!)).to.equal(document.body);
51
+ const host = document.createElement('div');
52
+ const child = host.attachShadow({ mode: 'open' }).appendChild(document.createElement('p'));
53
+ expect(getLogicalParent(child)).to.equal(host);
54
+ reflect.remove();
55
+ });
37
56
  });
@@ -0,0 +1,22 @@
1
+ import type { GemUnsafeElement } from '../../elements/unsafe';
2
+ import { css, html } from '../../lib/element';
3
+ import { expect, fixture, nextFrame } from '../utils';
4
+
5
+ import '../../elements/unsafe';
6
+
7
+ describe('GemUnsafeElement', () => {
8
+ it('渲染 HTML 字符串,应用样式', async () => {
9
+ const ele: GemUnsafeElement = await fixture(
10
+ html`<gem-unsafe html="<p>a</p>" .styles=${css`p { color: rgb(255, 0, 0); }`}></gem-unsafe>`,
11
+ );
12
+ const color = () => getComputedStyle(ele.shadowRoot!.querySelector('p')!).color;
13
+ expect(ele.shadowRoot!.querySelector('p')!.textContent).to.equal('a');
14
+ expect(color()).to.equal('rgb(255, 0, 0)');
15
+ ele.styles = 'p { color: rgb(0, 0, 255); }';
16
+ await nextFrame();
17
+ expect(color()).to.equal('rgb(0, 0, 255)');
18
+ ele.html = '<b>b</b>';
19
+ await nextFrame();
20
+ expect(ele.shadowRoot!.innerHTML).to.equal('<b>b</b>');
21
+ });
22
+ });
@@ -13,6 +13,7 @@ import {
13
13
  attribute,
14
14
  connectStore,
15
15
  customElement,
16
+ effect,
16
17
  emitter,
17
18
  mounted,
18
19
  property,
@@ -85,6 +86,92 @@ describe('没有 Shadow DOM 的 gem 元素', () => {
85
86
  });
86
87
  });
87
88
 
89
+ const scopeStyle = css`
90
+ p {
91
+ text-decoration: underline;
92
+ }
93
+ `;
94
+
95
+ @customElement('scope-child-demo')
96
+ class _ScopeChildDemo extends GemElement {
97
+ render() {
98
+ return html`<p>child</p>`;
99
+ }
100
+ }
101
+
102
+ @customElement('scope-gem-demo')
103
+ @adoptedStyle(scopeStyle)
104
+ class ScopeGemDemo extends GemElement {
105
+ render() {
106
+ return html`<p>own</p><article><p>nested</p></article><scope-child-demo></scope-child-demo>`;
107
+ }
108
+ }
109
+
110
+ @customElement('closed-gem-demo')
111
+ @adoptedStyle(css`
112
+ div {
113
+ color: rgb(255, 0, 0);
114
+ }
115
+ `)
116
+ @shadow({ mode: 'closed' })
117
+ class ClosedGemDemo extends GemElement {
118
+ render() {
119
+ return html`<div>closed</div>`;
120
+ }
121
+ }
122
+
123
+ describe('元素样式的作用域', () => {
124
+ it('Light DOM 的样式不影响有模版的子元素', async () => {
125
+ const el: ScopeGemDemo = await fixture(html`<scope-gem-demo></scope-gem-demo>`);
126
+ const decoration = (selector: string) => getComputedStyle(el.querySelector(selector)!).textDecorationLine;
127
+ expect(decoration(':scope > p')).to.equal('underline');
128
+ expect(decoration('article > p')).to.equal('underline');
129
+ expect(decoration('scope-child-demo > p')).to.equal('none');
130
+ });
131
+ it('closed Shadow DOM', async () => {
132
+ const el: ClosedGemDemo = await fixture(html`<closed-gem-demo></closed-gem-demo>`);
133
+ expect(el.shadowRoot).to.equal(null);
134
+ const div = el.internals.shadowRoot!.querySelector('div')!;
135
+ expect(getComputedStyle(div).color).to.equal('rgb(255, 0, 0)');
136
+ });
137
+ });
138
+
139
+ @customElement('effect-ref-demo')
140
+ class EffectRefDemo extends GemElement {
141
+ #state = createState({ hidden: false });
142
+ ref = createRef<HTMLTextAreaElement>();
143
+ values: (HTMLTextAreaElement | undefined)[] = [];
144
+
145
+ @effect((i) => [i.ref.value])
146
+ #observe = ([ele]: [HTMLTextAreaElement | undefined]) => {
147
+ this.values.push(ele);
148
+ };
149
+
150
+ toggle = () => this.#state({ hidden: !this.#state.hidden });
151
+
152
+ render() {
153
+ return this.#state.hidden ? null : html`<textarea ${this.ref}></textarea>`;
154
+ }
155
+ }
156
+
157
+ describe('effect 依赖 ref', () => {
158
+ it('元素重新创建时执行', async () => {
159
+ const el: EffectRefDemo = await fixture(html`<effect-ref-demo></effect-ref-demo>`);
160
+ const [first] = el.values;
161
+ expect(first).to.be.instanceOf(HTMLTextAreaElement);
162
+ // 元素移除时 ref 不会清空,保留最后的元素
163
+ el.toggle();
164
+ await nextFrame();
165
+ expect(el.ref.value).to.equal(first);
166
+ expect(el.values).to.eql([first]);
167
+ el.toggle();
168
+ await nextFrame();
169
+ expect(el.values.length).to.equal(2);
170
+ expect(el.values[1]).to.be.instanceOf(HTMLTextAreaElement);
171
+ expect(el.values[1]).not.to.equal(first);
172
+ });
173
+ });
174
+
88
175
  class LifecycleGemElement extends GemElement {
89
176
  @attribute appTitle = 'default';
90
177
  @attribute appTitle2 = 'default2';
@@ -145,6 +145,10 @@ describe('utils 测试', () => {
145
145
  expect(rules.item(1).style.background).to.equal('red');
146
146
  expect(rules.item(1).cssRules.item(0).selectorText).to.equal('&:hover *');
147
147
  expect(rules.item(1).cssRules.item(0).style.background).to.equal('blue');
148
+ // 有 `-` 的 key 保留原样,可以用来扩展其他样式表的类名
149
+ const extended = css({ [cssSheet.scroll]: styled`font-weight: bold;` });
150
+ expect(extended[cssSheet.scroll]).to.equal(cssSheet.scroll);
151
+ expect(extended[SheetToken].getStyle().cssRules.item(0).selectorText).to.equal(`.${cssSheet.scroll}`);
148
152
  });
149
153
  it('styleMap/classMap/exportPartsMap', () => {
150
154
  expect(styleMap({ '--x': '1px', fontSize: '14px', content: `'*'` })).to.equal(