@mantou/gem 1.6.5 → 1.6.11

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 (155) hide show
  1. package/README.md +6 -38
  2. package/dist/gem.es.js +3261 -0
  3. package/dist/gem.umd.js +229 -0
  4. package/elements/{dialog-base.d.ts → base/dialog.d.ts} +4 -4
  5. package/elements/base/dialog.d.ts.map +1 -0
  6. package/elements/{dialog-base.js → base/dialog.js} +26 -28
  7. package/elements/base/dialog.js.map +1 -0
  8. package/elements/base/gesture.d.ts +66 -0
  9. package/elements/base/gesture.d.ts.map +1 -0
  10. package/elements/base/gesture.js +214 -0
  11. package/elements/base/gesture.js.map +1 -0
  12. package/elements/base/link.d.ts +44 -0
  13. package/elements/base/link.d.ts.map +1 -0
  14. package/elements/base/link.js +206 -0
  15. package/elements/base/link.js.map +1 -0
  16. package/elements/{modal-base.d.ts → base/modal-factory.d.ts} +20 -20
  17. package/elements/base/modal-factory.d.ts.map +1 -0
  18. package/elements/{modal-base.js → base/modal-factory.js} +10 -7
  19. package/elements/base/modal-factory.js.map +1 -0
  20. package/elements/base/reflect.d.ts +6 -0
  21. package/elements/base/reflect.d.ts.map +1 -0
  22. package/elements/base/reflect.js +34 -0
  23. package/elements/base/reflect.js.map +1 -0
  24. package/elements/base/route.d.ts +78 -0
  25. package/elements/base/route.d.ts.map +1 -0
  26. package/elements/base/route.js +220 -0
  27. package/elements/base/route.js.map +1 -0
  28. package/elements/base/title.d.ts +30 -0
  29. package/elements/base/title.d.ts.map +1 -0
  30. package/elements/base/title.js +74 -0
  31. package/elements/base/title.js.map +1 -0
  32. package/elements/base/unsafe.d.ts +14 -0
  33. package/elements/base/unsafe.d.ts.map +1 -0
  34. package/elements/base/unsafe.js +42 -0
  35. package/elements/base/unsafe.js.map +1 -0
  36. package/elements/base/use.d.ts +19 -0
  37. package/elements/base/use.d.ts.map +1 -0
  38. package/elements/base/use.js +70 -0
  39. package/elements/base/use.js.map +1 -0
  40. package/elements/gesture.d.ts +1 -67
  41. package/elements/gesture.d.ts.map +1 -1
  42. package/elements/gesture.js +3 -219
  43. package/elements/gesture.js.map +1 -1
  44. package/elements/link.d.ts +1 -45
  45. package/elements/link.d.ts.map +1 -1
  46. package/elements/link.js +4 -215
  47. package/elements/link.js.map +1 -1
  48. package/elements/reflect.d.ts +1 -8
  49. package/elements/reflect.d.ts.map +1 -1
  50. package/elements/reflect.js +3 -39
  51. package/elements/reflect.js.map +1 -1
  52. package/elements/route.d.ts +1 -81
  53. package/elements/route.d.ts.map +1 -1
  54. package/elements/route.js +4 -225
  55. package/elements/route.js.map +1 -1
  56. package/elements/title.d.ts +1 -30
  57. package/elements/title.d.ts.map +1 -1
  58. package/elements/title.js +3 -75
  59. package/elements/title.js.map +1 -1
  60. package/elements/unsafe.d.ts +1 -14
  61. package/elements/unsafe.d.ts.map +1 -1
  62. package/elements/unsafe.js +3 -46
  63. package/elements/unsafe.js.map +1 -1
  64. package/elements/use.d.ts +1 -19
  65. package/elements/use.d.ts.map +1 -1
  66. package/elements/use.js +3 -74
  67. package/elements/use.js.map +1 -1
  68. package/helper/i18n.js +47 -58
  69. package/helper/i18n.js.map +1 -1
  70. package/helper/request.js +11 -19
  71. package/helper/request.js.map +1 -1
  72. package/index.d.ts +5 -4
  73. package/index.d.ts.map +1 -1
  74. package/index.js +4 -2
  75. package/index.js.map +1 -1
  76. package/lib/element.d.ts.map +1 -1
  77. package/lib/element.js +2 -2
  78. package/lib/element.js.map +1 -1
  79. package/lib/history.d.ts +28 -16
  80. package/lib/history.d.ts.map +1 -1
  81. package/lib/history.js +179 -169
  82. package/lib/history.js.map +1 -1
  83. package/lib/utils.d.ts +3 -1
  84. package/lib/utils.d.ts.map +1 -1
  85. package/lib/utils.js +7 -5
  86. package/lib/utils.js.map +1 -1
  87. package/package.json +25 -53
  88. package/src/{umd.ts → dist.ts} +4 -5
  89. package/src/elements/{dialog-base.ts → base/dialog.ts} +6 -7
  90. package/src/elements/base/gesture.ts +256 -0
  91. package/src/elements/base/link.ts +178 -0
  92. package/src/elements/{modal-base.ts → base/modal-factory.ts} +3 -3
  93. package/src/elements/base/reflect.ts +30 -0
  94. package/src/elements/base/route.ts +244 -0
  95. package/src/elements/base/title.ts +68 -0
  96. package/src/elements/base/unsafe.ts +37 -0
  97. package/src/elements/base/use.ts +57 -0
  98. package/src/elements/gesture.ts +3 -257
  99. package/src/elements/link.ts +4 -179
  100. package/src/elements/reflect.ts +3 -31
  101. package/src/elements/route.ts +4 -248
  102. package/src/elements/title.ts +3 -68
  103. package/src/elements/unsafe.ts +3 -37
  104. package/src/elements/use.ts +3 -57
  105. package/src/index.ts +4 -6
  106. package/src/lib/element.ts +5 -2
  107. package/src/lib/history.ts +183 -195
  108. package/src/lib/utils.ts +11 -5
  109. package/src/test/gem-element/advance.test.ts +1 -0
  110. package/src/test/gem-element/basic.test.ts +1 -0
  111. package/src/test/gem-element/decorators.test.ts +1 -0
  112. package/src/test/gem-element/multi.test.ts +1 -0
  113. package/src/test/history.test.ts +16 -10
  114. package/src/test/store.test.ts +1 -0
  115. package/src/test/utils.test.ts +1 -0
  116. package/elements/dialog-base.d.ts.map +0 -1
  117. package/elements/dialog-base.js.map +0 -1
  118. package/elements/modal-base.d.ts.map +0 -1
  119. package/elements/modal-base.js.map +0 -1
  120. package/src/examples/base-path/index.ts +0 -44
  121. package/src/examples/controlled/index.ts +0 -75
  122. package/src/examples/decorator/chidren.ts +0 -77
  123. package/src/examples/decorator/index.ts +0 -110
  124. package/src/examples/dialog/index.ts +0 -148
  125. package/src/examples/effect/index.ts +0 -45
  126. package/src/examples/elements/env.ts +0 -7
  127. package/src/examples/elements/layout.ts +0 -53
  128. package/src/examples/elements/nav.ts +0 -71
  129. package/src/examples/elements/source.ts +0 -68
  130. package/src/examples/gesture/canvas.ts +0 -69
  131. package/src/examples/gesture/index.ts +0 -97
  132. package/src/examples/gesture/manifest.json +0 -3
  133. package/src/examples/hash/index.ts +0 -55
  134. package/src/examples/i18n/index.ts +0 -63
  135. package/src/examples/index/index.ts +0 -33
  136. package/src/examples/index/manifest.json +0 -5
  137. package/src/examples/light-dom/index.ts +0 -31
  138. package/src/examples/multi-page/api.ts +0 -9
  139. package/src/examples/multi-page/index.ts +0 -78
  140. package/src/examples/multi-page/page-a.ts +0 -16
  141. package/src/examples/multi-page/page-b.ts +0 -12
  142. package/src/examples/multi-page/page-c.ts +0 -40
  143. package/src/examples/multi-page/store.ts +0 -10
  144. package/src/examples/perf-demo/index.ts +0 -136
  145. package/src/examples/ref-route/index.ts +0 -109
  146. package/src/examples/reflect/index.ts +0 -61
  147. package/src/examples/styled/index.ts +0 -39
  148. package/src/examples/svg-icon/index.ts +0 -31
  149. package/src/examples/theme/index.ts +0 -56
  150. package/src/examples/unsafe/index.ts +0 -29
  151. package/umd.d.ts +0 -18
  152. package/umd.d.ts.map +0 -1
  153. package/umd.js +0 -54
  154. package/umd.js.LICENSE.txt +0 -13
  155. package/umd.js.map +0 -1
@@ -1,181 +1,6 @@
1
- import { GemElement, html, ifDefined } from '../lib/element';
2
- import { attribute, property, customElement, state, part, connectStore } from '../lib/decorators';
3
- import { history, basePathStore } from '../lib/history';
4
- import { absoluteLocation } from '../lib/utils';
5
- import { matchPath, RouteItem, RouteOptions, createHistoryParams, createPath } from './route';
1
+ import { GemLinkElement, GemActiveLinkElement } from './base/link';
6
2
 
7
- /**
8
- * @customElement gem-link
9
- * @attr href
10
- * @attr target
11
- * @attr doc-title
12
- * @attr path
13
- * @attr query
14
- * @attr hash
15
- * @attr pattern
16
- * @attr hint
17
- * @part link
18
- *
19
- * print bug: https://github.com/mantou132/gem/issues/36
20
- */
21
- @customElement('gem-link')
22
- @connectStore(basePathStore)
23
- export class GemLinkElement extends GemElement {
24
- @attribute href: string;
25
- @attribute target: string;
26
- @attribute path: string;
27
- @attribute query: string;
28
- @attribute hash: string;
29
- @attribute docTitle: string;
30
- @attribute hint: 'on' | 'off';
3
+ export * from './base/link';
31
4
 
32
- // 动态路由,根据 route.pattern 和 options.params 计算出 path
33
- @property route: RouteItem | undefined;
34
- @property options: RouteOptions | undefined;
35
- @property prepare: (() => void | Promise<void>) | undefined;
36
-
37
- @part link: string;
38
-
39
- constructor() {
40
- super();
41
- this.addEventListener('click', this.clickHandle);
42
- }
43
-
44
- // 不包含 basePath
45
- getPathInfo() {
46
- if (this.route) {
47
- const queryProp = this.options?.query || '';
48
- const hashProp = this.options?.hash || '';
49
- return createPath(this.route, this.options) + queryProp + hashProp;
50
- } else {
51
- const url = this.href || this.path + this.query + this.hash;
52
- const { path, query } = history.getParams();
53
- if (url.startsWith('#')) {
54
- return `${path}${query}${url}`;
55
- } else if (url.startsWith('?')) {
56
- return `${path}${url}`;
57
- } else if (url.startsWith('.')) {
58
- return absoluteLocation(path, url);
59
- } else {
60
- return url;
61
- }
62
- }
63
- }
64
-
65
- isExternal(pathInfo: string) {
66
- return !pathInfo.startsWith('/');
67
- }
68
-
69
- clickHandle = async (e: MouseEvent) => {
70
- const pathInfo = this.getPathInfo();
71
-
72
- if (!pathInfo) return;
73
-
74
- // 外部链接使用 `window.open`
75
- if (this.isExternal(pathInfo)) {
76
- switch (this.target) {
77
- case '_self':
78
- window.location.href = pathInfo;
79
- return;
80
- case '_parent':
81
- window.parent.location.href = pathInfo;
82
- return;
83
- case '_top':
84
- window.top!.location.href = pathInfo;
85
- return;
86
- default:
87
- window.open(pathInfo);
88
- return;
89
- }
90
- }
91
-
92
- const { path, query, hash } = history.getParams();
93
- if (path + query + hash === pathInfo) {
94
- // 点击当前路由链接时,什么也没做
95
- return;
96
- }
97
-
98
- e.stopPropagation();
99
-
100
- await this.prepare?.();
101
-
102
- if (this.route) {
103
- history.pushIgnoreCloseHandle({
104
- ...createHistoryParams(this.route, this.options),
105
- title: this.route.title || this.docTitle,
106
- });
107
- } else if (this.href) {
108
- const { pathname, search, hash } = new URL(pathInfo, location.origin);
109
- history.pushIgnoreCloseHandle({
110
- path: pathname,
111
- query: search,
112
- // 解码,方便 `<gem-active-link>` CJK hash 比较
113
- hash: decodeURIComponent(hash),
114
- title: this.docTitle,
115
- });
116
- } else {
117
- history.pushIgnoreCloseHandle({ path: this.path, query: this.query, hash: this.hash, title: this.docTitle });
118
- }
119
- };
120
-
121
- preventDefault = (e: MouseEvent) => {
122
- e.preventDefault();
123
- };
124
-
125
- render(pathInfo = this.getPathInfo()) {
126
- return html`
127
- <style>
128
- :host {
129
- /* link default style */
130
- cursor: pointer;
131
- color: blue;
132
- text-decoration: underline;
133
- }
134
- a {
135
- all: unset;
136
- display: contents;
137
- }
138
- a:visited {
139
- color: unset;
140
- }
141
- </style>
142
- <a
143
- part=${this.link}
144
- @click=${this.preventDefault}
145
- href=${ifDefined(
146
- this.hint === 'off'
147
- ? undefined
148
- : this.isExternal(pathInfo)
149
- ? pathInfo
150
- : new URL(history.basePath + pathInfo, location.origin).toString(),
151
- )}
152
- >
153
- <slot></slot>
154
- </a>
155
- `;
156
- }
157
- }
158
-
159
- /**
160
- * @customElement gem-active-link
161
- * @attr pattern
162
- * @state active
163
- */
164
- @customElement('gem-active-link')
165
- @connectStore(history.store)
166
- export class GemActiveLinkElement extends GemLinkElement {
167
- @attribute pattern: string; // 使用匹配模式设定 active
168
- @state active: boolean;
169
-
170
- render() {
171
- const { path, query, hash } = history.getParams();
172
- const isMatchPattern = this.pattern && matchPath(this.pattern, path);
173
- const pathInfo = this.getPathInfo();
174
- if (isMatchPattern || path + query + hash === pathInfo) {
175
- this.active = true;
176
- } else {
177
- this.active = false;
178
- }
179
- return super.render(pathInfo);
180
- }
181
- }
5
+ customElements.define('gem-link', GemLinkElement);
6
+ customElements.define('gem-active-link', GemActiveLinkElement);
@@ -1,33 +1,5 @@
1
- import { GemElement } from '../lib/element';
2
- import { property, customElement } from '../lib/decorators';
1
+ import { GemReflectElement } from './base/reflect';
3
2
 
4
- // support prerender
5
- document.querySelectorAll('[data-reflect]').forEach((e) => e.remove());
3
+ export * from './base/reflect';
6
4
 
7
- /**
8
- * @customElement gem-reflect
9
- */
10
- @customElement('gem-reflect')
11
- export class GemReflectElement extends GemElement {
12
- @property target: HTMLElement = document.head;
13
-
14
- constructor() {
15
- super({ isLight: true });
16
- this.hidden = true;
17
- this.effect(
18
- () => {
19
- const childNodes = [...this.childNodes];
20
- childNodes.forEach((node) => {
21
- if (node instanceof HTMLElement) {
22
- node.dataset.reflect = '';
23
- }
24
- this.target.append(node);
25
- });
26
- return () => {
27
- childNodes.forEach((node) => node.remove());
28
- };
29
- },
30
- () => [this.target],
31
- );
32
- }
33
- }
5
+ customElements.define('gem-reflect', GemReflectElement);
@@ -1,250 +1,6 @@
1
- import { GemElement, html, TemplateResult } from '../lib/element';
2
- import { property, customElement, connectStore, emitter, Emitter } from '../lib/decorators';
3
- import { createStore, updateStore, Store } from '../lib/store';
4
- import { titleStore, history, UpdateHistoryParams } from '../lib/history';
5
- import { QueryString } from '../lib/utils';
1
+ import { GemRouteElement, GemLightRouteElement } from './base/route';
6
2
 
7
- interface NamePostition {
8
- [index: string]: number;
9
- }
3
+ export * from './base/route';
10
4
 
11
- // TODO: use `URLPattern`
12
- class ParamsRegExp extends RegExp {
13
- namePosition: NamePostition;
14
- constructor(pattern: string) {
15
- const namePosition: NamePostition = {};
16
- let i = 0;
17
- super(
18
- `^${pattern
19
- .replace(/:([^/$]+)/g, (_m, name: string) => {
20
- namePosition[name] = i++;
21
- return `([^/]+)`;
22
- })
23
- .replace('*', '.*')}$`,
24
- 'i',
25
- );
26
- this.namePosition = namePosition;
27
- }
28
- }
29
-
30
- type Params = Record<string, string>;
31
-
32
- // `/a/b/:c/:d` `/a/b/1/2`
33
- // 匹配成功时返回 params
34
- export function matchPath(pattern: string, path: string) {
35
- const reg = new ParamsRegExp(pattern);
36
- const matchResult = path.match(reg) || `${path}/`.match(reg);
37
- if (!matchResult) return null;
38
- const params: Params = {};
39
- if (matchResult) {
40
- Object.keys(reg.namePosition).forEach((name) => {
41
- params[name] = matchResult[reg.namePosition[name] + 1];
42
- });
43
- }
44
- return params;
45
- }
46
-
47
- export interface RouteItem<T = unknown> {
48
- // 支持 *
49
- // 支持 /a/*
50
- // 不支持相对路径
51
- // 不能匹配查询字符串
52
- pattern: string;
53
- redirect?: string;
54
- content?: TemplateResult;
55
- getContent?: (params: Params) => TemplateResult | Promise<TemplateResult>;
56
- title?: string;
57
- // 用来传递数据
58
- data?: T;
59
- }
60
-
61
- type RoutesObject = Record<string, RouteItem>;
62
-
63
- // params 中的成员不会验证
64
- export interface RouteOptions extends Omit<UpdateHistoryParams, 'path'> {
65
- params?: Params;
66
- }
67
-
68
- // 从路由创建路径
69
- // 不包含 basePath
70
- export function createPath(route: RouteItem, options?: RouteOptions) {
71
- let path = route.pattern;
72
- const params = options?.params;
73
- if (params) {
74
- Object.keys(params).forEach((key) => {
75
- path = path.replace(new RegExp(`:${key}`, 'g'), params[key]);
76
- });
77
- }
78
- return path;
79
- }
80
-
81
- export function createHistoryParams(route: RouteItem, options?: RouteOptions): UpdateHistoryParams {
82
- const path = createPath(route, options);
83
- return {
84
- path,
85
- ...options,
86
- };
87
- }
88
-
89
- interface ConstructorOptions {
90
- isLight?: boolean;
91
- routes?: RouteItem[] | RoutesObject;
92
- }
93
-
94
- type State = {
95
- content?: TemplateResult;
96
- };
97
-
98
- /**
99
- * @customElement gem-route
100
- * @attr inert 暂停路由更新
101
- * @fires routechange
102
- * @fires error
103
- * @fires loading
104
- */
105
- @connectStore(history.store)
106
- @customElement('gem-route')
107
- export class GemRouteElement extends GemElement<State> {
108
- @property routes?: RouteItem[] | RoutesObject;
109
- /**
110
- * @example
111
- * const locationStore = GemRouteElement.createLocationStore()
112
- * html`<gem-route .locationStore=${locationStore}>`
113
- */
114
- @property locationStore?: Store<{ path: string; params: Params; query: QueryString; data?: any }>;
115
- @property key: any; // 除了 href 提供另外一种方式来更新,比如语言更新也需要刷新 <gem-route>
116
- @emitter routechange: Emitter<RouteItem | null>; // path 改变或者 key 改变,包含初始渲染
117
- @emitter loading: Emitter<RouteItem>;
118
- @emitter error: Emitter<any>;
119
-
120
- currentRoute: RouteItem | null;
121
- // 当前匹配的路由的 params
122
- currentParams: Params = {};
123
-
124
- #lastLoader?: Promise<TemplateResult>;
125
-
126
- static createLocationStore = () => {
127
- const { path, query, data } = history.getParams();
128
- return createStore({ path, query, data, params: {} as Record<string, string> });
129
- };
130
-
131
- static findRoute = (target: RouteItem[] | RoutesObject = [], path: string) => {
132
- let defaultRoute: RouteItem | null = null;
133
- let routes: RouteItem[];
134
- if (target instanceof Array) {
135
- routes = target;
136
- } else {
137
- routes = Object.values(target);
138
- }
139
- for (const route of routes) {
140
- if ('*' === route.pattern) {
141
- defaultRoute = route;
142
- } else {
143
- const params = matchPath(route.pattern, path);
144
- if (params) {
145
- return { route, params };
146
- }
147
- }
148
- }
149
- return { route: defaultRoute };
150
- };
151
-
152
- constructor({ isLight, routes }: ConstructorOptions = {}) {
153
- super({ isLight });
154
- this.routes = routes;
155
- }
156
-
157
- state: State = {
158
- content: undefined,
159
- };
160
-
161
- #updateLocationStore = () => {
162
- if (this.locationStore) {
163
- const { path, query, data } = history.getParams();
164
- updateStore(this.locationStore, {
165
- path,
166
- params: this.currentParams,
167
- query,
168
- data,
169
- });
170
- }
171
- };
172
-
173
- #setContent = (route: RouteItem | null, params: Params, content?: TemplateResult) => {
174
- this.#lastLoader = undefined;
175
- this.currentRoute = route;
176
- this.currentParams = params;
177
- this.setState({ content });
178
- this.routechange(this.currentRoute);
179
- const title = route?.title;
180
- if (title) updateStore(titleStore, { title });
181
- this.#updateLocationStore();
182
- };
183
-
184
- mounted() {
185
- this.effect(
186
- ([key, path], old) => {
187
- // 只有查询参数改变
188
- if (old && key === old[0] && path === old[1]) {
189
- this.#updateLocationStore();
190
- return;
191
- }
192
- const { route, params = {} } = GemRouteElement.findRoute(this.routes, path);
193
- const { redirect, content, getContent } = route || {};
194
- if (redirect) {
195
- history.replace({ path: redirect });
196
- return;
197
- }
198
- const contentOrLoader = content || getContent?.(params);
199
- if (contentOrLoader instanceof Promise) {
200
- this.loading(route!);
201
- this.#lastLoader = contentOrLoader;
202
- const isSomeLoader = () => this.#lastLoader === contentOrLoader;
203
- contentOrLoader
204
- .then((content) => {
205
- if (isSomeLoader()) this.#setContent(route, params, content);
206
- })
207
- .catch((err) => {
208
- if (isSomeLoader()) this.error(err);
209
- });
210
- return;
211
- }
212
- this.#setContent(route, params, contentOrLoader);
213
- },
214
- () => {
215
- const { path } = history.getParams();
216
- return [this.key, path, location.search];
217
- },
218
- );
219
- }
220
-
221
- shouldUpdate() {
222
- if (this.inert) return false;
223
- return true;
224
- }
225
-
226
- render() {
227
- const { content } = this.state;
228
- if (!this.shadowRoot) return html`${content}`;
229
-
230
- return html`
231
- <style>
232
- :host,
233
- :not(:defined) {
234
- display: contents;
235
- }
236
- </style>
237
- ${content ?? html`<slot></slot>`}
238
- `;
239
- }
240
- }
241
-
242
- /**
243
- * @customElement gem-light-route
244
- */
245
- @customElement('gem-light-route')
246
- export class GemLightRouteElement extends GemRouteElement {
247
- constructor(options: ConstructorOptions = {}) {
248
- super({ ...options, isLight: true });
249
- }
250
- }
5
+ customElements.define('gem-route', GemRouteElement);
6
+ customElements.define('gem-light-route', GemLightRouteElement);
@@ -1,70 +1,5 @@
1
- /**
2
- * 标题显示在:
3
- *
4
- * - 桌面端 Tab 的 title
5
- * - 移动端 Appbar 的 title
6
- *
7
- * 修改标题:
8
- *
9
- * - `<gem-route>` 匹配路由时自动设置 `route.title`
10
- * - `<gem-link>` 的 `doc-title` 属性和 `route.title`
11
- * - 修改路径时,`history` 默认设置 `title` 为空
12
- * - 数据获取后,手动调用 `Title.setTitle`
13
- * - `<gem-title>` 作为默认值设置
14
- */
1
+ import { GemTitleElement } from './base/title';
15
2
 
16
- import { GemElement, html } from '../lib/element';
17
- import { attribute, customElement, connectStore } from '../lib/decorators';
18
- import { updateStore, connect } from '../lib/store';
19
- import { titleStore } from '../lib/history';
3
+ export * from './base/title';
20
4
 
21
- /**
22
- * 允许声明式设置 `document.title`
23
- * @customElement gem-title
24
- * @attr suffix
25
- */
26
- @connectStore(titleStore)
27
- @customElement('gem-title')
28
- export class GemTitleElement extends GemElement {
29
- // 没有后缀的标题
30
- static title = document.title;
31
- static defaultTitle = document.title;
32
- static defaultSuffix = ` - ${document.title}`;
33
-
34
- static setTitle(title: string) {
35
- updateStore(titleStore, { title });
36
- }
37
-
38
- static updateTitle(str = '', suffix = '') {
39
- const { title } = titleStore;
40
- if (title && title !== GemTitleElement.defaultTitle) {
41
- GemTitleElement.title = title;
42
- document.title = GemTitleElement.title + suffix;
43
- } else if (str) {
44
- GemTitleElement.title = str;
45
- document.title = GemTitleElement.title + suffix;
46
- } else {
47
- GemTitleElement.title = GemTitleElement.defaultTitle;
48
- document.title = GemTitleElement.title;
49
- }
50
- }
51
-
52
- @attribute suffix: string;
53
-
54
- constructor() {
55
- super();
56
- new MutationObserver(() => this.update()).observe(this, { childList: true, characterData: true, subtree: true });
57
- }
58
-
59
- render() {
60
- // 多个 <gem-title> 时,最终 document.title 按执行顺序决定
61
- GemTitleElement.updateTitle(this.textContent || '', this.suffix);
62
-
63
- if (this.hidden) {
64
- return html``;
65
- }
66
- return html`${GemTitleElement.title}`;
67
- }
68
- }
69
-
70
- connect(titleStore, GemTitleElement.updateTitle);
5
+ customElements.define('gem-title', GemTitleElement);
@@ -1,39 +1,5 @@
1
- import { GemElement } from '../lib/element';
2
- import { attribute, customElement } from '../lib/decorators';
1
+ import { GemUnsafeElement } from './base/unsafe';
3
2
 
4
- /**
5
- * 直接写会被解释成固定属性,需要使用变量赋值
6
- *
7
- * @customElement gem-unsafe
8
- * @attr content
9
- * @attr contentcss
10
- */
11
- @customElement('gem-unsafe')
12
- export class GemUnsafeElement extends GemElement {
13
- @attribute content: string;
14
- @attribute contentcss: string;
3
+ export * from './base/unsafe';
15
4
 
16
- constructor() {
17
- super();
18
- this.effect(
19
- () => {
20
- if (this.shadowRoot) {
21
- this.shadowRoot.innerHTML = `
22
- <style>
23
- :host {
24
- display: contents;
25
- }
26
- ${this.contentcss}
27
- </style>
28
- ${this.content}
29
- `;
30
- }
31
- },
32
- () => [this.content, this.contentcss],
33
- );
34
- }
35
-
36
- render() {
37
- return undefined;
38
- }
39
- }
5
+ customElements.define('gem-unsafe', GemUnsafeElement);
@@ -1,59 +1,5 @@
1
- import { GemElement, html } from '../lib/element';
2
- import { attribute, property, customElement, state } from '../lib/decorators';
1
+ import { GemUseElement } from './base/use';
3
2
 
4
- const eleCache = new Map<string, HTMLTemplateElement>();
5
- /**
6
- * svg 中的 `<use>` 不能穿透 ShadowDOM,
7
- * 此元素用来模拟 `<use>`,
8
- * 由于是复制元素,所以不能像 `<use>` 一样自动更新
9
- *
10
- * slot 支持为 icon 添加效果,如涟漪,徽章
11
- *
12
- * @customElement gem-use
13
- * @attr selector
14
- */
15
- @customElement('gem-use')
16
- export class GemUseElement extends GemElement {
17
- @attribute selector: string; // CSS 选择器
18
- @property root?: HTMLElement | Document | ShadowRoot;
19
- @property element?: string | DocumentFragment | Element;
3
+ export * from './base/use';
20
4
 
21
- @state active: boolean;
22
-
23
- private getContent() {
24
- const ele = this.element || (this.selector ? (this.root || document).querySelector(this.selector) : null);
25
- if (typeof ele === 'string') {
26
- let temp = eleCache.get(ele);
27
- if (!temp) {
28
- temp = document.createElement('template');
29
- temp.innerHTML = ele;
30
- eleCache.set(ele, temp);
31
- }
32
- return temp.content.cloneNode(true);
33
- } else if (ele instanceof HTMLTemplateElement) {
34
- return ele.content.cloneNode(true);
35
- } else {
36
- return ele?.cloneNode(true);
37
- }
38
- }
39
-
40
- render() {
41
- return html`
42
- <style>
43
- :host {
44
- position: relative;
45
- }
46
- :host(:not([hidden])) {
47
- display: inline-flex;
48
- align-items: center;
49
- }
50
- svg {
51
- width: 100%;
52
- height: 100%;
53
- }
54
- </style>
55
- ${this.getContent()}
56
- <slot></slot>
57
- `;
58
- }
59
- }
5
+ customElements.define('gem-use', GemUseElement);
package/src/index.ts CHANGED
@@ -1,10 +1,9 @@
1
- import { updateStore } from './lib/store';
1
+ /**
2
+ * 不支持多个 gem
3
+ */
2
4
  import * as Gem from './';
3
5
 
4
- export interface DevToolsHook {
5
- updateStore: typeof updateStore;
6
- }
7
-
6
+ export type DevToolsHook = typeof Gem;
8
7
  declare global {
9
8
  interface Window {
10
9
  __GEM_DEVTOOLS__HOOK__?: DevToolsHook;
@@ -12,7 +11,6 @@ declare global {
12
11
  }
13
12
 
14
13
  if (window.__GEM_DEVTOOLS__HOOK__) {
15
- // 不支持多个 gem
16
14
  Object.assign(window.__GEM_DEVTOOLS__HOOK__, { ...Gem });
17
15
  }
18
16
 
@@ -1,6 +1,7 @@
1
+ import { html, render, TemplateResult } from 'lit-html';
2
+
1
3
  import type { GemReflectElement } from '../elements/reflect';
2
4
 
3
- import { html, render, TemplateResult } from 'lit-html';
4
5
  import { connect, disconnect, Store } from './store';
5
6
  import {
6
7
  LinkedList,
@@ -573,7 +574,9 @@ export function defineRef(target: GemElement, prop: string, ref: string) {
573
574
  return ref;
574
575
  },
575
576
  get element() {
576
- const gemReflects = ([...ele.querySelectorAll('gem-reflect')] as GemReflectElement[]).map((e) => e.target);
577
+ const gemReflects = ([...ele.querySelectorAll('[data-gemreflect]')] as GemReflectElement[]).map(
578
+ (e) => e.target,
579
+ );
577
580
  for (const e of [ele, ...gemReflects]) {
578
581
  const result = e.querySelector(`[ref=${ref}]`);
579
582
  if (result) return result;