@mantou/gem 1.7.11 → 2.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/gem.es.js +1962 -1689
- package/dist/gem.umd.js +52 -54
- package/elements/base/dialog.d.ts +0 -11
- package/elements/base/dialog.d.ts.map +1 -1
- package/elements/base/dialog.js +93 -66
- package/elements/base/dialog.js.map +1 -1
- package/elements/base/gesture.d.ts +1 -2
- package/elements/base/gesture.d.ts.map +1 -1
- package/elements/base/gesture.js +157 -96
- package/elements/base/gesture.js.map +1 -1
- package/elements/base/link.d.ts +5 -5
- package/elements/base/link.d.ts.map +1 -1
- package/elements/base/link.js +249 -145
- package/elements/base/link.js.map +1 -1
- package/elements/base/modal-factory.d.ts +147 -139
- package/elements/base/modal-factory.d.ts.map +1 -1
- package/elements/base/modal-factory.js +84 -25
- package/elements/base/modal-factory.js.map +1 -1
- package/elements/base/reflect.d.ts +0 -1
- package/elements/base/reflect.d.ts.map +1 -1
- package/elements/base/reflect.js +83 -38
- package/elements/base/reflect.js.map +1 -1
- package/elements/base/route.d.ts +12 -24
- package/elements/base/route.d.ts.map +1 -1
- package/elements/base/route.js +263 -164
- package/elements/base/route.js.map +1 -1
- package/elements/base/title.d.ts +3 -11
- package/elements/base/title.d.ts.map +1 -1
- package/elements/base/title.js +110 -59
- package/elements/base/title.js.map +1 -1
- package/elements/base/unsafe.d.ts +0 -1
- package/elements/base/unsafe.d.ts.map +1 -1
- package/elements/base/unsafe.js +82 -33
- package/elements/base/unsafe.js.map +1 -1
- package/elements/base/use.d.ts.map +1 -1
- package/elements/base/use.js +95 -47
- package/elements/base/use.js.map +1 -1
- package/helper/i18n.d.ts +4 -9
- package/helper/i18n.d.ts.map +1 -1
- package/helper/i18n.js +69 -65
- package/helper/i18n.js.map +1 -1
- package/helper/logger.js +10 -9
- package/helper/logger.js.map +1 -1
- package/helper/react-shim.d.ts +15 -0
- package/helper/react-shim.d.ts.map +1 -0
- package/helper/react-shim.js +56 -0
- package/helper/react-shim.js.map +1 -0
- package/helper/react-utils.d.ts +15 -0
- package/helper/react-utils.d.ts.map +1 -0
- package/helper/react-utils.js +50 -0
- package/helper/react-utils.js.map +1 -0
- package/helper/request.d.ts +17 -7
- package/helper/request.d.ts.map +1 -1
- package/helper/request.js +103 -53
- package/helper/request.js.map +1 -1
- package/helper/ssr-shim.d.ts.map +1 -1
- package/helper/ssr-shim.js +8 -1
- package/helper/ssr-shim.js.map +1 -1
- package/helper/theme.d.ts +14 -21
- package/helper/theme.d.ts.map +1 -1
- package/helper/theme.js +55 -38
- package/helper/theme.js.map +1 -1
- package/index.d.ts +4 -3
- package/index.d.ts.map +1 -1
- package/index.js +5 -3
- package/index.js.map +1 -1
- package/lib/decorators.d.ts +74 -41
- package/lib/decorators.d.ts.map +1 -1
- package/lib/decorators.js +324 -84
- package/lib/decorators.js.map +1 -1
- package/lib/directives.d.ts +4 -0
- package/lib/directives.d.ts.map +1 -0
- package/lib/directives.js +5 -0
- package/lib/directives.js.map +1 -0
- package/lib/element.d.ts +112 -110
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +431 -470
- package/lib/element.js.map +1 -1
- package/lib/history.d.ts +4 -0
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +12 -13
- package/lib/history.js.map +1 -1
- package/lib/store.d.ts +1 -1
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +4 -5
- package/lib/store.js.map +1 -1
- package/lib/utils.d.ts +3 -43
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +61 -246
- package/lib/utils.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.d.ts.map +1 -1
- package/lib/version.js +2 -1
- package/lib/version.js.map +1 -1
- package/package.json +12 -11
- package/src/dist.ts +3 -2
- package/src/elements/base/dialog.ts +10 -20
- package/src/elements/base/gesture.ts +16 -14
- package/src/elements/base/link.ts +65 -44
- package/src/elements/base/modal-factory.ts +14 -14
- package/src/elements/base/reflect.ts +24 -32
- package/src/elements/base/route.ts +55 -68
- package/src/elements/base/title.ts +25 -42
- package/src/elements/base/unsafe.ts +12 -21
- package/src/elements/base/use.ts +17 -13
- package/src/helper/i18n.ts +20 -14
- package/src/helper/react-utils.ts +66 -0
- package/src/helper/request.ts +122 -53
- package/src/helper/ssr-shim.ts +8 -1
- package/src/helper/theme.ts +72 -45
- package/src/index.ts +6 -4
- package/src/lib/decorators.ts +394 -93
- package/src/lib/directives.ts +6 -0
- package/src/lib/element.ts +473 -499
- package/src/lib/history.ts +4 -3
- package/src/lib/store.ts +2 -1
- package/src/lib/utils.ts +19 -205
- package/src/lib/version.ts +2 -1
- package/src/test/elements/link.test.ts +1 -1
- package/src/test/elements/title.test.ts +1 -0
- package/src/test/gem-element/advance.test.ts +72 -49
- package/src/test/gem-element/basic.test.ts +37 -50
- package/src/test/gem-element/decorators.test.ts +22 -21
- package/src/test/gem-element/multi.test.ts +5 -5
- package/src/test/utils.test.ts +16 -38
|
@@ -1,36 +1,27 @@
|
|
|
1
1
|
import { GemElement } from '../../lib/element';
|
|
2
|
-
import { attribute } from '../../lib/decorators';
|
|
2
|
+
import { attribute, shadow } from '../../lib/decorators';
|
|
3
|
+
import { raw } from '../../lib/utils';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @customElement gem-unsafe
|
|
6
7
|
* @attr content
|
|
7
8
|
* @attr contentcss
|
|
8
9
|
*/
|
|
10
|
+
@shadow()
|
|
9
11
|
export class GemUnsafeElement extends GemElement {
|
|
10
12
|
@attribute content: string;
|
|
11
13
|
@attribute contentcss: string;
|
|
12
14
|
|
|
13
|
-
constructor() {
|
|
14
|
-
super();
|
|
15
|
-
this.effect(
|
|
16
|
-
() => {
|
|
17
|
-
if (this.shadowRoot) {
|
|
18
|
-
this.shadowRoot.innerHTML = `
|
|
19
|
-
<style>
|
|
20
|
-
:host(:where(:not([hidden]))) {
|
|
21
|
-
display: contents;
|
|
22
|
-
}
|
|
23
|
-
${this.contentcss}
|
|
24
|
-
</style>
|
|
25
|
-
${this.content}
|
|
26
|
-
`;
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
() => [this.content, this.contentcss],
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
15
|
render() {
|
|
16
|
+
this.shadowRoot!.innerHTML = raw`
|
|
17
|
+
<style>
|
|
18
|
+
:host(:where(:not([hidden]))) {
|
|
19
|
+
display: contents;
|
|
20
|
+
}
|
|
21
|
+
${this.contentcss}
|
|
22
|
+
</style>
|
|
23
|
+
${this.content}
|
|
24
|
+
`;
|
|
34
25
|
return undefined;
|
|
35
26
|
}
|
|
36
27
|
}
|
package/src/elements/base/use.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import { GemElement, html } from '../../lib/element';
|
|
2
|
-
import { attribute, property, state } from '../../lib/decorators';
|
|
1
|
+
import { createCSSSheet, GemElement, html } from '../../lib/element';
|
|
2
|
+
import { adoptedStyle, attribute, property, shadow, state } from '../../lib/decorators';
|
|
3
|
+
import { css } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
const styles = createCSSSheet(css`
|
|
6
|
+
:host(:where(:not([hidden]))) {
|
|
7
|
+
position: relative;
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
}
|
|
11
|
+
svg {
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
}
|
|
15
|
+
`);
|
|
3
16
|
|
|
4
17
|
const eleCache = new Map<string, HTMLTemplateElement>();
|
|
5
18
|
/**
|
|
@@ -11,6 +24,8 @@ const eleCache = new Map<string, HTMLTemplateElement>();
|
|
|
11
24
|
* @customElement gem-use
|
|
12
25
|
* @attr selector
|
|
13
26
|
*/
|
|
27
|
+
@shadow()
|
|
28
|
+
@adoptedStyle(styles)
|
|
14
29
|
export class GemUseElement extends GemElement {
|
|
15
30
|
@attribute selector: string; // CSS 选择器
|
|
16
31
|
@property root?: HTMLElement | Document | ShadowRoot;
|
|
@@ -37,17 +52,6 @@ export class GemUseElement extends GemElement {
|
|
|
37
52
|
|
|
38
53
|
render() {
|
|
39
54
|
return html`
|
|
40
|
-
<style>
|
|
41
|
-
:host(:where(:not([hidden]))) {
|
|
42
|
-
position: relative;
|
|
43
|
-
display: inline-flex;
|
|
44
|
-
align-items: center;
|
|
45
|
-
}
|
|
46
|
-
svg {
|
|
47
|
-
width: 100%;
|
|
48
|
-
height: 100%;
|
|
49
|
-
}
|
|
50
|
-
</style>
|
|
51
55
|
${this.#getContent()}
|
|
52
56
|
<slot></slot>
|
|
53
57
|
`;
|
package/src/helper/i18n.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { UpdateHistoryParams } from '../lib/history';
|
|
2
|
+
import type { TemplateResult } from '../lib/element';
|
|
3
|
+
import { html, UpdateToken } from '../lib/element';
|
|
3
4
|
import { GemError } from '../lib/utils';
|
|
4
5
|
import type { RouteTrigger } from '../elements/base/route';
|
|
5
6
|
|
|
@@ -72,10 +73,8 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
72
73
|
urlParamsName?: string;
|
|
73
74
|
onChange?: (currentLanguage: string) => void;
|
|
74
75
|
|
|
75
|
-
store: Store<any>;
|
|
76
|
-
|
|
77
76
|
// 兼容 `<gem-route>`
|
|
78
|
-
replace = ({ path }:
|
|
77
|
+
replace = ({ path }: UpdateHistoryParams) => this.setLanguage(path!);
|
|
79
78
|
getParams = () => ({ path: this.currentLanguage });
|
|
80
79
|
|
|
81
80
|
get #cacheCurrentKey() {
|
|
@@ -119,7 +118,6 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
119
118
|
throw new GemError('i18n: fallbackLanguage invalid');
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
this.store = createStore(this as any);
|
|
123
121
|
Object.assign<I18n<T>, I18nOptions<T>>(this as I18n<T>, options);
|
|
124
122
|
|
|
125
123
|
let currentLanguage = this.#urlParamsLang || this.currentLanguage || this.#cacheLang;
|
|
@@ -144,8 +142,8 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
144
142
|
}
|
|
145
143
|
|
|
146
144
|
get(s: keyof T): string;
|
|
147
|
-
get(s: keyof T, ...rest: (((
|
|
148
|
-
get(s: keyof T, ...rest: (((
|
|
145
|
+
get(s: keyof T, ...rest: (((str: string) => TemplateResult) | string)[]): TemplateResult;
|
|
146
|
+
get(s: keyof T, ...rest: (((str: string) => TemplateResult) | string)[]) {
|
|
149
147
|
const currentLanguagePack = this.resources[this.currentLanguage] as any;
|
|
150
148
|
const fallbackLanguagePack = this.resources[this.fallbackLanguage] as any;
|
|
151
149
|
const msg = currentLanguagePack[s] || fallbackLanguagePack[s];
|
|
@@ -181,7 +179,7 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
181
179
|
const localPackString = localStorage.getItem(localKey);
|
|
182
180
|
|
|
183
181
|
const fetchPack = async () => {
|
|
184
|
-
const
|
|
182
|
+
const pkg = await (await fetch(data)).json();
|
|
185
183
|
if (this.cache) {
|
|
186
184
|
// 移除之前的版本缓存
|
|
187
185
|
for (let i = 0; i < localStorage.length; i++) {
|
|
@@ -190,9 +188,9 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
190
188
|
localStorage.removeItem(key);
|
|
191
189
|
}
|
|
192
190
|
}
|
|
193
|
-
localStorage.setItem(localKey, JSON.stringify(
|
|
191
|
+
localStorage.setItem(localKey, JSON.stringify(pkg));
|
|
194
192
|
}
|
|
195
|
-
return
|
|
193
|
+
return pkg;
|
|
196
194
|
};
|
|
197
195
|
|
|
198
196
|
if (localPackString) {
|
|
@@ -208,7 +206,17 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
208
206
|
pack = data;
|
|
209
207
|
}
|
|
210
208
|
this.resources[lang] = pack;
|
|
211
|
-
|
|
209
|
+
|
|
210
|
+
// update all element
|
|
211
|
+
const temp: Element[] = [document.documentElement];
|
|
212
|
+
while (!!temp.length) {
|
|
213
|
+
const element = temp.pop()!;
|
|
214
|
+
(element as any)[UpdateToken]?.();
|
|
215
|
+
if (element.shadowRoot?.firstElementChild) temp.push(element.shadowRoot.firstElementChild);
|
|
216
|
+
if (element.firstElementChild) temp.push(element.firstElementChild);
|
|
217
|
+
if (element.nextElementSibling) temp.push(element.nextElementSibling);
|
|
218
|
+
}
|
|
219
|
+
|
|
212
220
|
if (lang !== this.currentLanguage) {
|
|
213
221
|
this.#lang = lang;
|
|
214
222
|
}
|
|
@@ -251,8 +259,6 @@ export class I18n<T = Record<string, Msg>> implements RouteTrigger {
|
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
/**
|
|
254
|
-
* prepare: @connectStore(i18n.store)
|
|
255
|
-
*
|
|
256
262
|
* @example
|
|
257
263
|
*
|
|
258
264
|
* html`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
|
|
4
|
+
import type { ReactNode } from 'react';
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
|
|
8
|
+
import { useEffect, useRef, useState } from 'react';
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
|
|
12
|
+
import type { Root } from 'react-dom/client';
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
|
|
16
|
+
import { createRoot } from 'react-dom/client';
|
|
17
|
+
|
|
18
|
+
import type { Store } from '../lib/store';
|
|
19
|
+
import { connect } from '../lib/store';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* `<gem-route>.routes.getContent`
|
|
23
|
+
*/
|
|
24
|
+
export function renderReactNode(ele: any, node: ReactNode) {
|
|
25
|
+
ele.react?.unmount();
|
|
26
|
+
ele.react = createRoot(ele);
|
|
27
|
+
// async
|
|
28
|
+
ele.react.render(node);
|
|
29
|
+
|
|
30
|
+
const routeEle = ele instanceof HTMLElement ? ele : ele.host;
|
|
31
|
+
if (!routeEle.reactCallback) {
|
|
32
|
+
routeEle.effect(
|
|
33
|
+
() => () => ele.react.unmount(),
|
|
34
|
+
() => [],
|
|
35
|
+
);
|
|
36
|
+
routeEle.reactCallback = true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Same as `@connectStore`
|
|
42
|
+
*/
|
|
43
|
+
export function connectStore<T extends object>(store: Store<T>) {
|
|
44
|
+
const [_, update] = useState({});
|
|
45
|
+
useEffect(() => connect(store, () => update({})), []);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Warning: https://github.com/facebook/react/issues/25675
|
|
50
|
+
*/
|
|
51
|
+
export function useReactNode(node: ReactNode) {
|
|
52
|
+
const ref = useRef<{ root: Root; container: HTMLElement }>();
|
|
53
|
+
// Warning: Attempted to synchronously unmount a root while React was already rendering. React cannot finish unmounting the root until the current render has completed, which may lead to a race condition.
|
|
54
|
+
useEffect(() => () => ref.current?.root.unmount(), []);
|
|
55
|
+
if (ref.current) {
|
|
56
|
+
ref.current.root.render(node);
|
|
57
|
+
return ref.current.container;
|
|
58
|
+
}
|
|
59
|
+
const container = document.createElement('div');
|
|
60
|
+
container.style.display = 'contents';
|
|
61
|
+
const root = createRoot(container);
|
|
62
|
+
ref.current = { root, container };
|
|
63
|
+
// Warning: Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate.
|
|
64
|
+
root.render(node);
|
|
65
|
+
return container;
|
|
66
|
+
}
|
package/src/helper/request.ts
CHANGED
|
@@ -1,60 +1,129 @@
|
|
|
1
|
-
|
|
2
|
-
headers: {
|
|
3
|
-
'Content-Type': 'application/json',
|
|
4
|
-
},
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export async function request<T>(uri: string, options: RequestInit = {}): Promise<T> {
|
|
8
|
-
const res = await fetch(uri, {
|
|
9
|
-
...defaultReqInit,
|
|
10
|
-
...options,
|
|
11
|
-
});
|
|
12
|
-
if (res.status === 0) throw new Error('Request fail');
|
|
13
|
-
if (res.status >= 500) throw new Error(res.statusText);
|
|
14
|
-
try {
|
|
15
|
-
const data = await res.json();
|
|
16
|
-
if (res.status >= 400) throw new (Error as any)(data?.message || res.statusText, { cause: data });
|
|
17
|
-
return data;
|
|
18
|
-
} catch {
|
|
19
|
-
throw new Error('Server error');
|
|
20
|
-
}
|
|
21
|
-
}
|
|
1
|
+
import { GemError } from '../lib/utils';
|
|
22
2
|
|
|
23
3
|
type ReqBody = Record<string, unknown> | BodyInit;
|
|
4
|
+
type ReqParams = Record<string, string | number>;
|
|
24
5
|
const TypedArray = Object.getPrototypeOf(Object.getPrototypeOf(new Int8Array())).constructor;
|
|
25
6
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
) {
|
|
35
|
-
return body as BodyInit;
|
|
36
|
-
}
|
|
37
|
-
if (typeof body === 'object') {
|
|
38
|
-
return JSON.stringify(body);
|
|
39
|
-
}
|
|
40
|
-
return body;
|
|
41
|
-
}
|
|
7
|
+
type Options = {
|
|
8
|
+
origin?: string;
|
|
9
|
+
base?: string;
|
|
10
|
+
// only for get/del/put/post
|
|
11
|
+
appendHeaders?: (input?: any) => HeadersInit;
|
|
12
|
+
transformInput?: (input?: any) => any;
|
|
13
|
+
transformOutput?: (output: any, req: Request) => any;
|
|
14
|
+
} & RequestInit;
|
|
42
15
|
|
|
43
|
-
function
|
|
44
|
-
const {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
16
|
+
function initRequest(options: Options = {}) {
|
|
17
|
+
const {
|
|
18
|
+
origin = location.origin,
|
|
19
|
+
base = '',
|
|
20
|
+
appendHeaders = () => ({}),
|
|
21
|
+
transformInput = (p?: any) => p,
|
|
22
|
+
transformOutput = (p?: any) => p,
|
|
23
|
+
...reqInit
|
|
24
|
+
} = options;
|
|
48
25
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
26
|
+
const serializationBody = (body?: ReqBody): BodyInit | undefined => {
|
|
27
|
+
if (
|
|
28
|
+
body instanceof FormData ||
|
|
29
|
+
body instanceof Blob ||
|
|
30
|
+
body instanceof TypedArray ||
|
|
31
|
+
body instanceof URLSearchParams ||
|
|
32
|
+
body instanceof ReadableStream ||
|
|
33
|
+
body instanceof ArrayBuffer
|
|
34
|
+
) {
|
|
35
|
+
return body as BodyInit;
|
|
36
|
+
}
|
|
37
|
+
if (typeof body === 'object') {
|
|
38
|
+
return JSON.stringify(body);
|
|
39
|
+
}
|
|
40
|
+
return body;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const serializationUrl = (path: string, params?: ReqParams) => {
|
|
44
|
+
if (new URL(path, location.origin).pathname !== path) {
|
|
45
|
+
throw new GemError('`path` format is incorrect');
|
|
46
|
+
}
|
|
47
|
+
const query = new URLSearchParams(params as Record<string, string>).toString();
|
|
48
|
+
return `${origin}${base}${path}${query ? '?' : ''}${query}`;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const serializationHeaders = (headers?: HeadersInit) => {
|
|
52
|
+
if (!headers) return {};
|
|
53
|
+
// auto `toLowerCase`
|
|
54
|
+
if (headers instanceof Headers) return Object.fromEntries(headers);
|
|
55
|
+
const entries = Array.isArray(headers) ? headers : Object.entries(headers);
|
|
56
|
+
return Object.fromEntries(entries.map(([key, value]) => [key.toLowerCase(), value]));
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const request = async <T>(uri: string, reqOptions: RequestInit = {}): Promise<T> => {
|
|
60
|
+
const req = new Request(uri, {
|
|
61
|
+
...reqInit,
|
|
62
|
+
...reqOptions,
|
|
63
|
+
headers: new Headers({
|
|
64
|
+
'content-type': 'application/json',
|
|
65
|
+
...serializationHeaders(reqInit.headers),
|
|
66
|
+
...serializationHeaders(reqOptions.headers),
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
const res = await fetch(req);
|
|
70
|
+
|
|
71
|
+
if (res.status === 0) throw new Error('Request fail');
|
|
72
|
+
if (res.status >= 500) throw new Error(res.statusText);
|
|
73
|
+
|
|
74
|
+
const contentType = req.headers.get('content-type')!;
|
|
75
|
+
const isClientError = res.status >= 400;
|
|
76
|
+
try {
|
|
77
|
+
let data: any;
|
|
78
|
+
if (contentType.includes('json')) {
|
|
79
|
+
data = await res.json();
|
|
80
|
+
} else if (contentType.includes('octet-stream')) {
|
|
81
|
+
data = await res.arrayBuffer();
|
|
82
|
+
} else {
|
|
83
|
+
data = await res.text();
|
|
84
|
+
}
|
|
85
|
+
if (isClientError) throw new (Error as any)(res.statusText, { cause: data });
|
|
86
|
+
return transformOutput(data, req);
|
|
87
|
+
} catch {
|
|
88
|
+
throw new Error('Parse error');
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
request,
|
|
94
|
+
get<T>(path: string, params?: ReqParams) {
|
|
95
|
+
const i = transformInput(params);
|
|
96
|
+
return request<T>(serializationUrl(path, i), {
|
|
97
|
+
method: 'GET',
|
|
98
|
+
headers: appendHeaders(i),
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
del<T>(path: string, params?: ReqParams) {
|
|
102
|
+
const i = transformInput(params);
|
|
103
|
+
return request<T>(serializationUrl(path, i), {
|
|
104
|
+
method: 'DELETE',
|
|
105
|
+
headers: appendHeaders(i),
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
put<T>(path: string, body?: ReqBody) {
|
|
109
|
+
const i = transformInput(body);
|
|
110
|
+
return request<T>(serializationUrl(path), {
|
|
111
|
+
method: 'PUT',
|
|
112
|
+
headers: appendHeaders(i),
|
|
113
|
+
body: serializationBody(i),
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
post<T>(path: string, body?: ReqBody) {
|
|
117
|
+
const i = transformInput(body);
|
|
118
|
+
return request<T>(serializationUrl(path), {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: appendHeaders(i),
|
|
121
|
+
body: serializationBody(i),
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
};
|
|
60
125
|
}
|
|
126
|
+
|
|
127
|
+
const { request, del, get, post, put } = initRequest();
|
|
128
|
+
|
|
129
|
+
export { initRequest, request, del, get, post, put };
|
package/src/helper/ssr-shim.ts
CHANGED
|
@@ -26,7 +26,6 @@ if (typeof window === 'undefined') {
|
|
|
26
26
|
globalThis.document = any;
|
|
27
27
|
globalThis.addEventListener = any;
|
|
28
28
|
globalThis.history = any;
|
|
29
|
-
globalThis.navigator = any;
|
|
30
29
|
globalThis.customElements = any;
|
|
31
30
|
|
|
32
31
|
// duoyun-ui
|
|
@@ -34,6 +33,14 @@ if (typeof window === 'undefined') {
|
|
|
34
33
|
globalThis.Document = any;
|
|
35
34
|
globalThis.Element = any;
|
|
36
35
|
globalThis.MutationObserver = any;
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// gem dist i18n
|
|
39
|
+
// https://nodejs.org/api/globals.html#navigator_1
|
|
40
|
+
globalThis.navigator = any;
|
|
41
|
+
} catch {
|
|
42
|
+
//
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
export {};
|
package/src/helper/theme.ts
CHANGED
|
@@ -1,71 +1,98 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Store } from '../lib/store';
|
|
2
|
+
import { connect, useStore } from '../lib/store';
|
|
2
3
|
import { camelToKebabCase, randomStr } from '../lib/utils';
|
|
4
|
+
import type { GemElement } from '../lib/element';
|
|
5
|
+
import { SheetToken, createCSSSheet } from '../lib/element';
|
|
3
6
|
|
|
4
|
-
type
|
|
5
|
-
[
|
|
7
|
+
export type Theme<T> = ReturnType<typeof createCSSSheet> & {
|
|
8
|
+
[K in keyof T as K extends `${string}Color`
|
|
9
|
+
? `${string & K}${'' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900}`
|
|
10
|
+
: K]: T[K];
|
|
6
11
|
};
|
|
7
12
|
|
|
8
13
|
const themeStoreMap = new WeakMap();
|
|
14
|
+
const themePropsMap = new WeakMap();
|
|
9
15
|
|
|
10
16
|
/**获取主题原始值 */
|
|
11
|
-
export function getThemeStore<T>(theme:
|
|
17
|
+
export function getThemeStore<T>(theme: Theme<T>) {
|
|
12
18
|
return themeStoreMap.get(theme) as Store<T>;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
|
-
const themePropsMap = new WeakMap();
|
|
16
|
-
|
|
17
21
|
/**获取 css 变量名 */
|
|
18
|
-
export function getThemeProps<T>(theme:
|
|
19
|
-
return themePropsMap.get(theme) as
|
|
22
|
+
export function getThemeProps<T>(theme: Theme<T>) {
|
|
23
|
+
return themePropsMap.get(theme) as Theme<T>;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 创建主题,插入 `document.head`
|
|
26
|
-
* https://github.com/mantou132/gem/issues/33
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* createTheme({
|
|
30
|
-
* primaryColor: '#eee',
|
|
31
|
-
* });
|
|
32
|
-
*/
|
|
33
|
-
export function createTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
26
|
+
function useThemeFromProps<T extends Record<string, unknown>>(themeObj: T, props: Record<string, string> = {}) {
|
|
34
27
|
const salt = randomStr();
|
|
35
|
-
const
|
|
36
|
-
const store =
|
|
37
|
-
const theme:
|
|
38
|
-
|
|
28
|
+
const styleSheet = createCSSSheet({})[SheetToken];
|
|
29
|
+
const [store, updateStore] = useStore<T>(themeObj);
|
|
30
|
+
const theme: any = new Proxy(
|
|
31
|
+
{ [SheetToken]: styleSheet },
|
|
32
|
+
{
|
|
33
|
+
get(target: any, key: string) {
|
|
34
|
+
if (!target[key]) {
|
|
35
|
+
const [_, origin, weight] = key.match(/^(\w*Color)(\d+)$/) || [];
|
|
36
|
+
if (origin) target[key] = `oklch(from ${target[origin]} calc(l - ${(Number(weight) - 400) / 1000}) c h)`;
|
|
37
|
+
}
|
|
38
|
+
return target[key];
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
39
42
|
themePropsMap.set(theme, props);
|
|
40
43
|
themeStoreMap.set(theme, store);
|
|
41
|
-
|
|
44
|
+
|
|
45
|
+
const updateContent = () => {
|
|
46
|
+
let rules = '';
|
|
42
47
|
Object.keys(store).forEach((key) => {
|
|
43
|
-
if (props[key])
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
if (!props[key]) {
|
|
49
|
+
props[key] = `--${camelToKebabCase(key)}-${salt}`;
|
|
50
|
+
theme[key] = `var(${props[key]})`;
|
|
51
|
+
}
|
|
52
|
+
rules += `${props[key]}:${store[key]};`;
|
|
46
53
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return theme as SomeType<T>;
|
|
54
|
+
styleSheet.setContent(`:scope,:host{${rules}}`);
|
|
55
|
+
};
|
|
56
|
+
updateContent();
|
|
57
|
+
connect(store, () => {
|
|
58
|
+
updateContent();
|
|
59
|
+
styleSheet.updateStyle();
|
|
60
|
+
});
|
|
61
|
+
return [theme as Theme<T>, updateStore] as const;
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/**
|
|
59
|
-
*
|
|
60
|
-
* @param theme 主题
|
|
61
|
-
* @param newThemeObj 新主题
|
|
65
|
+
* 用于 `@adoptedStyle(theme)`,类似 `createCSSSheet`
|
|
62
66
|
*/
|
|
63
|
-
export function
|
|
64
|
-
|
|
65
|
-
setThemeFnMap.get(theme)();
|
|
67
|
+
export function useScopedTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
68
|
+
return useThemeFromProps(themeObj);
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/**全局主题 */
|
|
68
72
|
export function useTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
69
|
-
const
|
|
70
|
-
|
|
73
|
+
const result = useScopedTheme(themeObj);
|
|
74
|
+
document.adoptedStyleSheets.push(result[0][SheetToken].getStyle());
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**用来覆盖全局主题 */
|
|
79
|
+
export function useOverrideTheme<T extends Record<string, unknown>>(theme: Theme<T>, themeObj: Partial<T>) {
|
|
80
|
+
return useThemeFromProps(themeObj, getThemeProps(theme));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function useDecoratorTheme<T extends Record<string, unknown>>(themeObj: T) {
|
|
84
|
+
const [themeAsKeys] = useThemeFromProps(themeObj);
|
|
85
|
+
const props = getThemeProps(themeAsKeys);
|
|
86
|
+
const updateDecorator =
|
|
87
|
+
<E extends GemElement, V extends () => T, K = any[] | undefined>(
|
|
88
|
+
getDep?: K extends readonly any[] ? (instance: E) => K : undefined,
|
|
89
|
+
) =>
|
|
90
|
+
(_: any, { addInitializer, access }: ClassFieldDecoratorContext<E, V> | ClassMethodDecoratorContext<E, V>) => {
|
|
91
|
+
addInitializer(function (this: E) {
|
|
92
|
+
const [theme, update] = useThemeFromProps({ ...themeObj }, props);
|
|
93
|
+
this.internals.sheets.push(theme[SheetToken].getStyle(this));
|
|
94
|
+
this.memo(() => update(access.get(this).apply(this)), getDep && (() => getDep(this) as any));
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
return [themeAsKeys, updateDecorator] as const;
|
|
71
98
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export * from './lib/store';
|
|
2
|
-
export * from './lib/history';
|
|
3
|
-
export * from './lib/element';
|
|
4
1
|
export * from './lib/decorators';
|
|
2
|
+
export * from './lib/element';
|
|
3
|
+
export * from './lib/store';
|
|
5
4
|
export * from './lib/utils';
|
|
6
|
-
|
|
7
5
|
export * from './lib/version';
|
|
6
|
+
|
|
7
|
+
// 使用路径时可选模块
|
|
8
|
+
export * from './lib/history';
|
|
9
|
+
export * from './lib/directives';
|