@mantou/gem 1.6.9 → 1.6.10

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 (98) hide show
  1. package/dist/gem.es.js +170 -182
  2. package/dist/gem.umd.js +23 -23
  3. package/elements/{dialog-base.d.ts → base/dialog.d.ts} +3 -3
  4. package/elements/base/dialog.d.ts.map +1 -0
  5. package/elements/{dialog-base.js → base/dialog.js} +24 -24
  6. package/elements/base/dialog.js.map +1 -0
  7. package/elements/base/gesture.d.ts +66 -0
  8. package/elements/base/gesture.d.ts.map +1 -0
  9. package/elements/base/gesture.js +214 -0
  10. package/elements/base/gesture.js.map +1 -0
  11. package/elements/base/link.d.ts +44 -0
  12. package/elements/base/link.d.ts.map +1 -0
  13. package/elements/base/link.js +206 -0
  14. package/elements/base/link.js.map +1 -0
  15. package/elements/{modal-base.d.ts → base/modal-factory.d.ts} +17 -8
  16. package/elements/base/modal-factory.d.ts.map +1 -0
  17. package/elements/{modal-base.js → base/modal-factory.js} +4 -4
  18. package/elements/base/modal-factory.js.map +1 -0
  19. package/elements/base/reflect.d.ts +6 -0
  20. package/elements/base/reflect.d.ts.map +1 -0
  21. package/elements/base/reflect.js +33 -0
  22. package/elements/base/reflect.js.map +1 -0
  23. package/elements/base/route.d.ts +78 -0
  24. package/elements/base/route.d.ts.map +1 -0
  25. package/elements/base/route.js +220 -0
  26. package/elements/base/route.js.map +1 -0
  27. package/elements/base/title.d.ts +30 -0
  28. package/elements/base/title.d.ts.map +1 -0
  29. package/elements/base/title.js +74 -0
  30. package/elements/base/title.js.map +1 -0
  31. package/elements/base/unsafe.d.ts +14 -0
  32. package/elements/base/unsafe.d.ts.map +1 -0
  33. package/elements/base/unsafe.js +42 -0
  34. package/elements/base/unsafe.js.map +1 -0
  35. package/elements/base/use.d.ts +19 -0
  36. package/elements/base/use.d.ts.map +1 -0
  37. package/elements/base/use.js +70 -0
  38. package/elements/base/use.js.map +1 -0
  39. package/elements/gesture.d.ts +1 -67
  40. package/elements/gesture.d.ts.map +1 -1
  41. package/elements/gesture.js +3 -219
  42. package/elements/gesture.js.map +1 -1
  43. package/elements/link.d.ts +1 -45
  44. package/elements/link.d.ts.map +1 -1
  45. package/elements/link.js +4 -208
  46. package/elements/link.js.map +1 -1
  47. package/elements/reflect.d.ts +1 -8
  48. package/elements/reflect.d.ts.map +1 -1
  49. package/elements/reflect.js +3 -39
  50. package/elements/reflect.js.map +1 -1
  51. package/elements/route.d.ts +1 -81
  52. package/elements/route.d.ts.map +1 -1
  53. package/elements/route.js +4 -228
  54. package/elements/route.js.map +1 -1
  55. package/elements/title.d.ts +1 -30
  56. package/elements/title.d.ts.map +1 -1
  57. package/elements/title.js +3 -75
  58. package/elements/title.js.map +1 -1
  59. package/elements/unsafe.d.ts +1 -14
  60. package/elements/unsafe.d.ts.map +1 -1
  61. package/elements/unsafe.js +3 -46
  62. package/elements/unsafe.js.map +1 -1
  63. package/elements/use.d.ts +1 -19
  64. package/elements/use.d.ts.map +1 -1
  65. package/elements/use.js +3 -74
  66. package/elements/use.js.map +1 -1
  67. package/lib/history.d.ts +28 -16
  68. package/lib/history.d.ts.map +1 -1
  69. package/lib/history.js +166 -168
  70. package/lib/history.js.map +1 -1
  71. package/lib/utils.d.ts.map +1 -1
  72. package/lib/utils.js +2 -1
  73. package/lib/utils.js.map +1 -1
  74. package/package.json +2 -2
  75. package/src/dist.ts +5 -2
  76. package/src/elements/{dialog-base.ts → base/dialog.ts} +4 -4
  77. package/src/elements/base/gesture.ts +256 -0
  78. package/src/elements/base/link.ts +178 -0
  79. package/src/elements/{modal-base.ts → base/modal-factory.ts} +3 -3
  80. package/src/elements/base/reflect.ts +29 -0
  81. package/src/elements/base/route.ts +244 -0
  82. package/src/elements/base/title.ts +68 -0
  83. package/src/elements/base/unsafe.ts +37 -0
  84. package/src/elements/base/use.ts +57 -0
  85. package/src/elements/gesture.ts +3 -257
  86. package/src/elements/link.ts +4 -179
  87. package/src/elements/reflect.ts +3 -31
  88. package/src/elements/route.ts +4 -248
  89. package/src/elements/title.ts +3 -68
  90. package/src/elements/unsafe.ts +3 -37
  91. package/src/elements/use.ts +3 -57
  92. package/src/lib/history.ts +182 -194
  93. package/src/lib/utils.ts +2 -1
  94. package/src/test/history.test.ts +15 -10
  95. package/elements/dialog-base.d.ts.map +0 -1
  96. package/elements/dialog-base.js.map +0 -1
  97. package/elements/modal-base.d.ts.map +0 -1
  98. package/elements/modal-base.js.map +0 -1
@@ -1,16 +1,14 @@
1
- import { createStore, updateStore, Store, connect } from './store';
1
+ import { createStore, updateStore, connect } from './store';
2
2
  import { QueryString, cleanObject, GemError, absoluteLocation } from './utils';
3
3
 
4
- export const history = window.history;
5
- const location = window.location;
6
- const pushState: typeof history.pushState = history.pushState.bind(history);
7
- const replaceState: typeof history.replaceState = history.replaceState.bind(history);
4
+ const nativeHistory = window.history;
5
+ const nativePushState: typeof nativeHistory.pushState = nativeHistory.pushState.bind(nativeHistory);
6
+ const nativeReplaceState: typeof nativeHistory.replaceState = nativeHistory.replaceState.bind(nativeHistory);
8
7
 
9
8
  let key = 0;
10
9
  const getKey = () => `${performance.now()}-${++key}`;
11
10
 
12
- // history.state
13
- export interface HistoryItem {
11
+ export interface HistoryState {
14
12
  $hasCloseHandle: boolean;
15
13
  $hasOpenHandle: boolean;
16
14
  $hasShouldCloseHandle: boolean;
@@ -18,7 +16,7 @@ export interface HistoryItem {
18
16
  [index: string]: any;
19
17
  }
20
18
 
21
- const store = createStore<HistoryItem>({
19
+ const store = createStore<HistoryState>({
22
20
  $hasCloseHandle: false,
23
21
  $hasOpenHandle: false,
24
22
  $hasShouldCloseHandle: false,
@@ -34,7 +32,7 @@ export interface UpdateHistoryParams {
34
32
  open?: () => void; // 按下前进键时执行
35
33
  close?: () => void; // 按下返回键时执行
36
34
  shouldClose?: () => boolean; // 按下返回键时判断是否执行 close 函数,返回为 false 时不执行,并恢复 history
37
- data?: any;
35
+ data?: any; // 同 history.state
38
36
  }
39
37
 
40
38
  // 实际应用值
@@ -43,27 +41,6 @@ type HistoryParams = UpdateHistoryParams & { title: string; path: string; query:
43
41
  // TODO: WeakRef
44
42
  const paramsMap = new Map<string, HistoryParams>();
45
43
 
46
- declare global {
47
- interface History {
48
- store: Store<HistoryItem>;
49
- // 修改会更改 `history.getParams()` 的值
50
- basePath?: string;
51
- // 返回 `history` 当前储存的值, 是一个可变对象,当修改 `basePath` 时会改变
52
- getParams: () => HistoryParams;
53
-
54
- push: (params: UpdateHistoryParams) => void;
55
- replace: (params: UpdateHistoryParams) => void;
56
- // push 一条历史记录
57
- // 有 close 处理函数时先执行 closeHandle 在 replace
58
- // 比如在 modal 打开时跳转页面
59
- // 不完美:只支持在 1 级 modal 中切换页面
60
- pushIgnoreCloseHandle: (params: UpdateHistoryParams) => void;
61
- updateParams: (params: Omit<UpdateHistoryParams, 'path' | 'query' | 'hash' | 'state'>) => void;
62
- }
63
- }
64
-
65
- type UpdateHistoryType = 'push' | 'replace';
66
-
67
44
  function validData({ $key, $hasCloseHandle, $hasOpenHandle, $hasShouldCloseHandle }: any = {}) {
68
45
  if (store.$key === $key) return;
69
46
  if ($key) throw new GemError('`$key` is not allowed');
@@ -73,15 +50,15 @@ function validData({ $key, $hasCloseHandle, $hasOpenHandle, $hasShouldCloseHandl
73
50
  }
74
51
 
75
52
  function getUrlbarPath(internalPath: string) {
76
- return history.basePath ? history.basePath + internalPath : internalPath;
53
+ return gemHistory.basePath ? gemHistory.basePath + internalPath : internalPath;
77
54
  }
78
55
 
79
56
  function getInternalPath(urlbarPath: string) {
80
- if (urlbarPath === history.basePath) return '/';
81
- return urlbarPath.replace(new RegExp(`^${history.basePath}/`), '/');
57
+ if (urlbarPath === gemHistory.basePath) return '/';
58
+ return urlbarPath.replace(new RegExp(`^${gemHistory.basePath}/`), '/');
82
59
  }
83
60
 
84
- function initParams(params: UpdateHistoryParams): HistoryParams {
61
+ function normalizeParams(params: UpdateHistoryParams): HistoryParams {
85
62
  const current = paramsMap.get(store.$key) || ({} as HistoryParams);
86
63
  // 没提供 path 使用当前 path
87
64
  const path = params.path ? absoluteLocation(current.path, params.path) : getInternalPath(location.pathname);
@@ -89,18 +66,19 @@ function initParams(params: UpdateHistoryParams): HistoryParams {
89
66
  const query = new QueryString(params.query || (params.path ? '' : location.search));
90
67
  const pathChanged =
91
68
  (params.path && params.path !== current.path) || (params.query && String(params.query) !== String(current.query));
69
+ // 没提供 title 又没有改变 URL 时使用当前 document.title
92
70
  const title = params.title || (pathChanged ? '' : document.title);
93
71
  const statusChanged = params.close || params.data || params.open || params.shouldClose;
94
- // 没提供 hash 又没有改变路径又不是状态更新时使用当前 hash
72
+ // 没提供 hash 又没有改变 URL 又不是状态更新时使用当前 hash
95
73
  const hash = params.hash || (!pathChanged && statusChanged ? decodeURIComponent(location.hash) : '');
96
74
  return { ...params, title, path, query, hash };
97
75
  }
98
76
 
99
- function updateHistory(type: UpdateHistoryType, p: UpdateHistoryParams) {
77
+ function updateHistory(p: UpdateHistoryParams, native: typeof nativeHistory.pushState) {
100
78
  validData(p.data);
101
- const params = initParams(p);
79
+ const params = normalizeParams(p);
102
80
  const { title, path, query, hash, close, open, shouldClose, data } = params;
103
- const state: HistoryItem = {
81
+ const state: HistoryState = {
104
82
  $hasCloseHandle: !!close,
105
83
  $hasOpenHandle: !!open,
106
84
  $hasShouldCloseHandle: !!shouldClose,
@@ -110,197 +88,207 @@ function updateHistory(type: UpdateHistoryType, p: UpdateHistoryParams) {
110
88
  paramsMap.set(state.$key, params);
111
89
  updateStore(cleanObject(store), state);
112
90
  const url = getUrlbarPath(path) + new QueryString(query) + hash;
113
- const prevHave = decodeURIComponent(location.hash);
114
- (type === 'push' ? pushState : replaceState)(state, title, url);
115
- if (prevHave !== hash) window.dispatchEvent(new CustomEvent('hashchange'));
91
+ const prevHash = decodeURIComponent(location.hash);
92
+ native(state, title, url);
93
+ if (prevHash !== hash) window.dispatchEvent(new CustomEvent('hashchange'));
116
94
  }
117
95
 
118
96
  // 跨框架时,调用者对 basePath 无感知
119
- function updateHistoryByNative(type: UpdateHistoryType, data: any, title: string, originUrl: string) {
97
+ function updateHistoryByNative(data: any, title: string, originUrl: string, native: typeof nativeHistory.pushState) {
120
98
  validData(data);
121
99
  const state = {
122
100
  $key: getKey(),
123
101
  ...(data || {}),
124
102
  };
125
103
  const { pathname, search, hash } = new URL(originUrl, location.origin + location.pathname);
126
- const params = initParams({ path: pathname, query: new QueryString(search), hash, title, data });
104
+ const params = normalizeParams({ path: pathname, query: new QueryString(search), hash, title, data });
127
105
  paramsMap.set(state.$key, params);
128
106
  updateStore(cleanObject(store), state);
129
107
  const url = getUrlbarPath(pathname) + params.query + hash;
130
108
  const prevHash = location.hash;
131
- (type === 'push' ? pushState : replaceState)(state, title, url);
109
+ native(state, title, url);
132
110
  // `location.hash` 和 `hash` 都已经进行了 url 编码,可以直接进行相等判断
133
111
  if (prevHash !== hash) window.dispatchEvent(new CustomEvent('hashchange'));
134
112
  }
135
113
 
136
- export const basePathStore = createStore({
114
+ const gemBasePathStore = createStore({
137
115
  basePath: '',
138
116
  });
139
117
 
140
- window.addEventListener('hashchange', ({ isTrusted }) => {
141
- if (isTrusted) {
142
- history.replace({ hash: decodeURIComponent(location.hash) });
118
+ class GemHistory {
119
+ get store() {
120
+ return store;
143
121
  }
144
- });
145
- // 不允许其他框架重写
146
- // 保持原有功能
147
- Object.defineProperties(history, {
148
- basePath: {
149
- get() {
150
- return basePathStore.basePath;
151
- },
152
- set(basePath: string) {
153
- // 应用初始化的时候设置
154
- updateStore(basePathStore, { basePath });
155
- // paramsMap 更新后 ui 才会更新
156
- Object.assign(paramsMap.get(store.$key), { path: getInternalPath(location.pathname) });
157
- },
158
- },
159
- getParams: {
160
- value: function () {
161
- return paramsMap.get(store.$key);
162
- },
163
- },
164
- updateParams: {
165
- value: function (params: UpdateHistoryParams) {
166
- Object.assign(paramsMap.get(store.$key), params);
167
- updateStore(store, {});
168
- },
169
- },
170
- store: {
171
- value: store,
172
- },
173
- push: {
174
- value: function (params: UpdateHistoryParams) {
175
- history.pushState(params, '');
176
- },
177
- },
178
- pushIgnoreCloseHandle: {
179
- value: function (params: UpdateHistoryParams) {
180
- if (store.$hasCloseHandle) {
181
- paramsMap.get(store.$key)?.close?.();
182
- history.replace(params);
183
- } else {
184
- history.push(params);
185
- }
186
- },
187
- },
188
- replace: {
189
- value: function (params: UpdateHistoryParams) {
190
- updateHistory('replace', params);
191
- },
192
- },
193
- });
194
-
195
- history.pushState = function (data: any, title: string, path: string) {
196
- if (path) {
197
- updateHistoryByNative('push', data, title, path);
198
- } else {
199
- updateHistory('push', data);
122
+ get basePath() {
123
+ return gemBasePathStore.basePath;
124
+ }
125
+ set basePath(basePath: string) {
126
+ // 应用初始化的时候设置
127
+ updateStore(gemBasePathStore, { basePath });
128
+ // paramsMap 更新后 ui 才会更新
129
+ Object.assign(paramsMap.get(store.$key), { path: getInternalPath(location.pathname) });
130
+ }
131
+ getParams() {
132
+ return paramsMap.get(store.$key)!;
133
+ }
134
+ updateParams(params: UpdateHistoryParams) {
135
+ Object.assign(paramsMap.get(store.$key), params);
136
+ updateStore(store, {});
137
+ }
138
+ push(params: UpdateHistoryParams) {
139
+ updateHistory(params, nativePushState);
140
+ }
141
+ replace(params: UpdateHistoryParams) {
142
+ updateHistory(params, nativeReplaceState);
143
+ }
144
+ pushIgnoreCloseHandle(params: UpdateHistoryParams) {
145
+ if (store.$hasCloseHandle) {
146
+ paramsMap.get(store.$key)?.close?.();
147
+ this.replace(params);
148
+ } else {
149
+ this.push(params);
150
+ }
151
+ }
152
+ forward() {
153
+ nativeHistory.forward();
154
+ }
155
+ back() {
156
+ nativeHistory.back();
200
157
  }
201
- };
202
-
203
- history.replaceState = function (data: any, title: string, path: string) {
204
- updateHistoryByNative('replace', data, title, path);
205
- };
206
-
207
- if (!history.state) {
208
- // 初始化 historyItem
209
- const { pathname, search, hash } = location;
210
- history.replace({ path: pathname, query: search, hash });
211
- } else if (history.state.$hasCloseHandle) {
212
- updateStore(store, history.state);
213
- const params = initParams({ title: document.title });
214
- paramsMap.set(store.$key, params);
215
- // 有 handle 返回键的页面刷新需要清除返回 handler
216
- history.back();
217
- } else {
218
- // 有 gem 历史的正常普通刷新, 储存 params
219
- const params = initParams({ title: document.title, hash: location.hash });
220
- updateStore(store, {
221
- $key: getKey(),
222
- ...(history.state || {}),
223
- });
224
- paramsMap.set(store.$key, params);
225
158
  }
226
159
 
227
- export const titleStore = createStore({ title: '' });
160
+ // `<gem-**>` 只读写父应用 `basePath`
161
+ const gemHistory = new GemHistory();
228
162
 
229
- connect(titleStore, () => {
230
- const params = paramsMap.get(store.$key);
231
- if (params) {
232
- params.title = titleStore.title;
233
- }
234
- });
163
+ const gemTitleStore = createStore({ title: '' });
235
164
 
236
- connect(store, () => {
237
- const { title } = history.getParams();
238
- if (title !== titleStore.title) {
239
- updateStore(titleStore, { title });
240
- }
241
- });
165
+ const _GEMHISTORY = { history: gemHistory, titleStore: gemTitleStore, basePathStore: gemBasePathStore };
242
166
 
243
- /**
244
- * 表示 popstate handler 中正在进行导航
245
- */
246
- let navigating = false;
247
- window.addEventListener('popstate', (event) => {
248
- const newState = event.state as HistoryItem | null;
249
- if (!newState?.$key) {
250
- // 比如作为其他 app 的宿主 app
251
- return;
252
- }
253
- if (navigating) {
254
- navigating = false;
255
- return;
167
+ declare global {
168
+ interface Window {
169
+ _GEMHISTORY?: typeof _GEMHISTORY;
256
170
  }
171
+ }
172
+
173
+ if (!window._GEMHISTORY) {
174
+ window._GEMHISTORY = _GEMHISTORY;
175
+
176
+ nativeHistory.pushState = function (state: any, title: string, path: string) {
177
+ updateHistoryByNative(state, title, path, nativePushState);
178
+ };
257
179
 
258
- // 处理 forward or back
259
- // replace 不会触发
180
+ nativeHistory.replaceState = function (state: any, title: string, path: string) {
181
+ updateHistoryByNative(state, title, path, nativeReplaceState);
182
+ };
183
+
184
+ // 点击 `<a>`
185
+ window.addEventListener('hashchange', ({ isTrusted }) => {
186
+ if (isTrusted) {
187
+ gemHistory.replace({ hash: decodeURIComponent(location.hash) });
188
+ }
189
+ });
260
190
 
261
- // 刷新后再导航需要从当前 state 中构建 params
262
- // 理论上该条历史记录中不会出现事件处理器
263
- if (!paramsMap.has(newState.$key)) {
191
+ if (!nativeHistory.state) {
192
+ // 初始化 historyState
264
193
  const { pathname, search, hash } = location;
265
- paramsMap.set(newState.$key, {
266
- path: pathname,
267
- query: new QueryString(search),
268
- hash,
269
- title: document.title, // 浏览器缓存的 title
270
- data: newState,
194
+ gemHistory.replace({ path: pathname, query: search, hash });
195
+ } else if (nativeHistory.state.$hasCloseHandle) {
196
+ updateStore(store, nativeHistory.state);
197
+ const params = normalizeParams({ title: document.title });
198
+ paramsMap.set(store.$key, params);
199
+ // 有 handle 返回键的页面刷新需要清除返回 handler
200
+ gemHistory.back();
201
+ } else {
202
+ // 有 gem 历史的正常普通刷新, 储存 params
203
+ const params = normalizeParams({ title: document.title, hash: location.hash });
204
+ updateStore(store, {
205
+ $key: getKey(),
206
+ ...(nativeHistory.state || {}),
271
207
  });
208
+ paramsMap.set(store.$key, params);
272
209
  }
273
210
 
274
- // url 变化前 historyItem
275
- const prevState = store;
276
-
277
- if (parseFloat(newState.$key) > parseFloat(prevState.$key) && newState.$hasOpenHandle) {
278
- // 返回键关闭的 modal 能前进键重新打开
279
- // 刷新后不能工作:刷新后 historyItem 中只有 url
280
- paramsMap.get(newState.$key)?.open?.();
281
- } else if (prevState.$hasCloseHandle) {
282
- const prevParams = paramsMap.get(prevState.$key);
283
- const closeHandle = prevParams?.close;
284
- const shouldCloseHandle = prevParams?.shouldClose;
285
- const notAllowClose = shouldCloseHandle && !shouldCloseHandle();
286
- if (notAllowClose) {
287
- navigating = true;
288
- history.forward(); // 将重新触发 popstate
289
- return; // 历史记录栈位置没有变化,不需要后面的 updateStore
290
- } else {
291
- // handle 返回键
292
- if (closeHandle) {
293
- closeHandle();
294
- } else if (newState.$hasCloseHandle) {
295
- // 有 modal 的页面刷新会执行 back 触发 popstate
296
- // 如果是二级 modal 页面刷新
297
- // 则还需要进行一次 back
298
- // !!! 不完美:三级 modal 页面刷新不支持返回到初始页面
211
+ connect(gemTitleStore, () => {
212
+ const params = paramsMap.get(store.$key);
213
+ if (params) {
214
+ params.title = gemTitleStore.title;
215
+ }
216
+ });
217
+
218
+ connect(store, () => {
219
+ const { title } = gemHistory.getParams();
220
+ if (title !== gemTitleStore.title) {
221
+ updateStore(gemTitleStore, { title });
222
+ }
223
+ });
224
+
225
+ /**
226
+ * 表示 popstate handler 中正在进行导航
227
+ */
228
+ let navigating = false;
229
+ window.addEventListener('popstate', (event) => {
230
+ const newState = event.state as HistoryState | null;
231
+ if (!newState?.$key) {
232
+ // 比如作为其他框架 app 的宿主 app
233
+ return;
234
+ }
235
+ if (navigating) {
236
+ navigating = false;
237
+ return;
238
+ }
239
+
240
+ // 处理 forward or back
241
+ // replace 不会触发
242
+
243
+ // 刷新后再导航需要从当前 state 中构建 params
244
+ // 理论上该条历史记录中不会出现事件处理器
245
+ // 子 app 导航也需要从 state 中构建 params
246
+ if (!paramsMap.has(newState.$key)) {
247
+ const { pathname, search, hash } = location;
248
+ paramsMap.set(newState.$key, {
249
+ path: pathname,
250
+ query: new QueryString(search),
251
+ hash,
252
+ title: document.title, // 浏览器缓存的 title
253
+ data: newState,
254
+ });
255
+ }
256
+
257
+ // url 变化前 historyItem
258
+ const prevState = store;
259
+
260
+ if (parseFloat(newState.$key) > parseFloat(prevState.$key) && newState.$hasOpenHandle) {
261
+ // 返回键关闭的 modal 能前进键重新打开
262
+ // 刷新后不能工作:刷新后 historyItem 中只有 url
263
+ // 能在子 app 中工作
264
+ paramsMap.get(newState.$key)?.open?.();
265
+ } else if (prevState.$hasCloseHandle) {
266
+ const prevParams = paramsMap.get(prevState.$key);
267
+ const closeHandle = prevParams?.close;
268
+ const shouldCloseHandle = prevParams?.shouldClose;
269
+ const notAllowClose = shouldCloseHandle && !shouldCloseHandle();
270
+ if (notAllowClose) {
299
271
  navigating = true;
300
- history.back();
272
+ gemHistory.forward(); // 将重新触发 popstate
273
+ return; // 历史记录栈位置没有变化,不需要后面的 updateStore
274
+ } else {
275
+ // handle 返回键
276
+ if (closeHandle) {
277
+ closeHandle();
278
+ } else if (newState.$hasCloseHandle) {
279
+ // 有 modal 的页面刷新会执行 back 触发 popstate
280
+ // 如果是二级 modal 页面刷新
281
+ // 则还需要进行一次 back
282
+ // !!! 不完美:三级 modal 页面刷新不支持返回到初始页面
283
+ navigating = true;
284
+ gemHistory.back();
285
+ }
301
286
  }
302
287
  }
303
- }
304
288
 
305
- updateStore(cleanObject(store), newState);
306
- });
289
+ updateStore(cleanObject(store), newState);
290
+ });
291
+ }
292
+
293
+ const { history, titleStore, basePathStore } = window._GEMHISTORY;
294
+ export { history, titleStore, basePathStore };
package/src/lib/utils.ts CHANGED
@@ -209,7 +209,8 @@ export function css(arr: TemplateStringsArray, ...args: any[]) {
209
209
  return raw(arr, ...args);
210
210
  }
211
211
 
212
- export const SheetToken = Symbol('sheet token');
212
+ // 跨多个 gem 工作
213
+ export const SheetToken = Symbol.for('gem@sheetToken');
213
214
 
214
215
  export type Sheet<T> = {
215
216
  [P in keyof T]: P;
@@ -39,6 +39,10 @@ describe('history 测试', () => {
39
39
  await aTimeout(10);
40
40
  expect(window.location.pathname).to.equal('/');
41
41
  expect(new URLSearchParams(location.search).get('tab')).to.equal('bb');
42
+ expect(() => history.replace({ data: { $key: 'adf' } })).to.throw();
43
+ expect(() => history.replace({ data: { $hasCloseHandle: 'adf' } })).to.throw();
44
+ expect(() => history.replace({ data: { $hasOpenHandle: 'adf' } })).to.throw();
45
+ expect(() => history.replace({ data: { $hasShouldCloseHandle: 'adf' } })).to.throw();
42
46
  });
43
47
  it('getParams/updateParams', async () => {
44
48
  const historyLength = window.history.length;
@@ -50,16 +54,16 @@ describe('history 测试', () => {
50
54
  await aTimeout(10);
51
55
  expect(history.getParams().title).to.equal('321');
52
56
  });
53
- it('pushState/replaceState', async () => {
57
+ it('Native pushState/replaceState', async () => {
54
58
  const historyLength = window.history.length;
55
- history.pushState({}, 'title', '/a');
59
+ window.history.pushState({}, 'title', '/a');
56
60
  await aTimeout(10);
57
61
  expect(window.location.pathname).to.equal('/a');
58
- history.replaceState({}, 'title', '/b?tab=a');
59
- expect(() => history.replaceState({ $key: 'adf' }, '', '')).to.throw();
60
- expect(() => history.replaceState({ $hasCloseHandle: 'adf' }, '', '')).to.throw();
61
- expect(() => history.replaceState({ $hasOpenHandle: 'adf' }, '', '')).to.throw();
62
- expect(() => history.replaceState({ $hasShouldCloseHandle: 'adf' }, '', '')).to.throw();
62
+ window.history.replaceState({}, 'title', '/b?tab=a');
63
+ expect(() => window.history.replaceState({ $key: 'adf' }, '', '')).to.throw();
64
+ expect(() => window.history.replaceState({ $hasCloseHandle: 'adf' }, '', '')).to.throw();
65
+ expect(() => window.history.replaceState({ $hasOpenHandle: 'adf' }, '', '')).to.throw();
66
+ expect(() => window.history.replaceState({ $hasShouldCloseHandle: 'adf' }, '', '')).to.throw();
63
67
  await aTimeout(10);
64
68
  expect(window.location.pathname).to.equal('/b');
65
69
  expect(new URLSearchParams(location.search).get('tab')).to.equal('a');
@@ -84,7 +88,7 @@ describe('history 测试', () => {
84
88
  // 替换 close
85
89
  history.replace({ close, open });
86
90
  await aTimeout(10);
87
- expect(history?.state?.$hasOpenHandle).to.true;
91
+ expect(window.history?.state?.$hasOpenHandle).to.true;
88
92
  await aTimeout(10);
89
93
  expect(window.location.href).to.equal(href);
90
94
  // 跳转页面
@@ -134,14 +138,15 @@ describe('history 测试', () => {
134
138
  expect(window.location.pathname).to.equal('/d/');
135
139
  history.push({ path: '/a' });
136
140
  await aTimeout(10);
141
+ expect(history.getParams().path).to.equal('/a');
137
142
  expect(window.location.pathname).to.equal('/d/a');
138
143
  history.push({ path: '/' });
139
144
  await aTimeout(10);
140
145
  expect(window.location.pathname).to.equal('/d/');
141
- history.pushState({}, '', '/');
146
+ window.history.pushState({}, '', '/');
142
147
  await aTimeout(10);
143
148
  expect(window.location.pathname).to.equal('/d/');
144
- history.pushState({}, '', '/c');
149
+ window.history.pushState({}, '', '/c');
145
150
  await aTimeout(10);
146
151
  expect(window.location.pathname).to.equal('/d/c');
147
152
  history.basePath = '';
@@ -1 +0,0 @@
1
- {"version":3,"file":"dialog-base.d.ts","sourceRoot":"","sources":["../src/elements/dialog-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C;;;;;;GAMG;AACH,8BACsB,iBAAkB,SAAQ,UAAU;;IAC7C,KAAK,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAEvB,KAAK,UAAQ;;IAYb;;;OAGG;IACH,WAAW,aAUT;IAEF;;;OAGG;IACH,UAAU,aAUR;IAEF,YAAY;IACZ,IAAI,aASF;IAEF,WAAW;IAIX,YAAY;IACZ,KAAK,aAEH;IAEF;;;;;OAKG;IACH,UAAU,aAGR;CACH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dialog-base.js","sourceRoot":"","sources":["../src/elements/dialog-base.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"modal-base.d.ts","sourceRoot":"","sources":["../src/elements/modal-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,QAAA,MAAM,IAAI,eAAsB,CAAC;AAEjC;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAEvD,WAAW,EAAE;cACf,UAAU,GAAG,IAAI;IAClC;;;OAGG;;;;IAMH,YAAY;;IAKZ,YAAY;;;;IAKZ;;;;OAIG;eACe,GAAC;IAkBnB;;;OAGG;;IAKH;;;OAGG;;IAOH;;OAEG;;;;;;;;;;;;;EAaN"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"modal-base.js","sourceRoot":"","sources":["../src/elements/modal-base.ts"],"names":[],"mappings":"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"}