@mantou/gem 1.7.11 → 1.7.12
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/dist/gem.es.js +1164 -1136
- package/dist/gem.umd.js +23 -24
- package/elements/base/modal-factory.d.ts +3 -1
- package/elements/base/modal-factory.d.ts.map +1 -1
- 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/lib/decorators.d.ts +1 -0
- package/lib/decorators.d.ts.map +1 -1
- package/lib/element.d.ts.map +1 -1
- package/lib/element.js +16 -18
- package/lib/element.js.map +1 -1
- package/lib/utils.d.ts +5 -5
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +18 -29
- package/lib/utils.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -3
- package/src/helper/request.ts +122 -53
- package/src/lib/decorators.ts +1 -1
- package/src/lib/element.ts +18 -17
- package/src/lib/utils.ts +27 -34
- package/src/lib/version.ts +1 -1
- package/src/test/utils.test.ts +12 -4
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/lib/decorators.ts
CHANGED
|
@@ -19,7 +19,7 @@ function pushStaticField(target: GemElementPrototype, field: StaticField, member
|
|
|
19
19
|
(cls[field] as any)[isSet ? 'add' : 'push'](member);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export type RefObject<T = HTMLElement> = { ref: string; element: T | undefined };
|
|
22
|
+
export type RefObject<T = HTMLElement> = { ref: string; element: T | undefined; elements: T[] };
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* 引用元素,只有第一个标记 ref 的元素有效
|
package/src/lib/element.ts
CHANGED
|
@@ -419,22 +419,17 @@ export abstract class GemElement<T = Record<string, unknown>> extends HTMLElemen
|
|
|
419
419
|
|
|
420
420
|
closestElement<K extends keyof HTMLElementTagNameMap>(tag: K): HTMLElementTagNameMap[K] | null;
|
|
421
421
|
closestElement<K extends abstract new (...args: any) => any>(constructor: K): InstanceType<K> | null;
|
|
422
|
-
closestElement<K extends abstract new (...args: any) => any>(constructorOrTag: K | string)
|
|
422
|
+
closestElement<K extends abstract new (...args: any) => any>(constructorOrTag: K | string) {
|
|
423
423
|
const isConstructor = typeof constructorOrTag === 'function';
|
|
424
424
|
const tagName = typeof constructorOrTag === 'string' && constructorOrTag.toUpperCase();
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
return rootEle;
|
|
434
|
-
}
|
|
435
|
-
return getRootElement(rootEle);
|
|
436
|
-
};
|
|
437
|
-
return getRootElement(this);
|
|
425
|
+
const is = (ele: Element) => (isConstructor ? ele.constructor === constructorOrTag : ele.tagName === tagName);
|
|
426
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
427
|
+
let node: Element | null = this;
|
|
428
|
+
while (node) {
|
|
429
|
+
if (is(node)) break;
|
|
430
|
+
node = node.parentElement || (node.getRootNode() as ShadowRoot).host;
|
|
431
|
+
}
|
|
432
|
+
return node;
|
|
438
433
|
}
|
|
439
434
|
|
|
440
435
|
/**
|
|
@@ -572,7 +567,11 @@ export function defineProperty(
|
|
|
572
567
|
});
|
|
573
568
|
}
|
|
574
569
|
|
|
570
|
+
const getReflectTargets = (ele: ShadowRoot | GemElement) =>
|
|
571
|
+
[...ele.querySelectorAll<GemReflectElement>('[data-gem-reflect]')].map((e) => e.target);
|
|
572
|
+
|
|
575
573
|
export function defineRef(target: GemElement, prop: string, ref: string) {
|
|
574
|
+
const refSelector = `[ref=${ref}]`;
|
|
576
575
|
Object.defineProperty(target, prop, {
|
|
577
576
|
configurable: true,
|
|
578
577
|
get() {
|
|
@@ -586,12 +585,14 @@ export function defineRef(target: GemElement, prop: string, ref: string) {
|
|
|
586
585
|
return ref;
|
|
587
586
|
},
|
|
588
587
|
get element() {
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
const result = e.querySelector(`[ref=${ref}]`);
|
|
588
|
+
for (const e of [ele, ...getReflectTargets(ele)]) {
|
|
589
|
+
const result = e.querySelector(refSelector);
|
|
592
590
|
if (result) return result;
|
|
593
591
|
}
|
|
594
592
|
},
|
|
593
|
+
get elements() {
|
|
594
|
+
return [ele, ...getReflectTargets(ele)].map((e) => [...e.querySelectorAll(refSelector)]).flat();
|
|
595
|
+
},
|
|
595
596
|
};
|
|
596
597
|
proxy[prop] = refobject;
|
|
597
598
|
}
|
package/src/lib/utils.ts
CHANGED
|
@@ -257,21 +257,29 @@ export interface StyledKeyValuePair {
|
|
|
257
257
|
|
|
258
258
|
/**
|
|
259
259
|
*
|
|
260
|
-
* 创建 style sheet 用于 `adoptedStyleSheets
|
|
261
|
-
* @param rules string | Record<string, string>
|
|
262
|
-
* @param
|
|
260
|
+
* 创建 style sheet 用于 `adoptedStyleSheets`,不支持样式更新,只支持自定义 CSS 属性
|
|
261
|
+
* @param rules string | Record<string, string>
|
|
262
|
+
* @param media string 媒体查询
|
|
263
263
|
*/
|
|
264
|
-
export function createCSSSheet<T extends StyledKeyValuePair>(rules: T | string,
|
|
265
|
-
const styleSheet = new CSSStyleSheet();
|
|
264
|
+
export function createCSSSheet<T extends StyledKeyValuePair>(rules: T | string, media?: string): Sheet<T> {
|
|
265
|
+
const styleSheet = new CSSStyleSheet({ media });
|
|
266
266
|
const sheet: any = {};
|
|
267
|
-
styleSheet.media.mediaText = mediaQuery;
|
|
268
267
|
let style = '';
|
|
269
268
|
if (typeof rules === 'string') {
|
|
270
269
|
style = rules;
|
|
271
270
|
} else {
|
|
272
271
|
Object.keys(rules).forEach((key: keyof T) => {
|
|
273
272
|
sheet[key] = `${key as string}-${randomStr()}`;
|
|
274
|
-
|
|
273
|
+
switch (rules[key].type) {
|
|
274
|
+
case 'class':
|
|
275
|
+
style += `.${sheet[key]} {${rules[key].styledContent}}`;
|
|
276
|
+
break;
|
|
277
|
+
case 'id':
|
|
278
|
+
style += `#${sheet[key]} {${rules[key].styledContent}}`;
|
|
279
|
+
break;
|
|
280
|
+
default:
|
|
281
|
+
style += `@keyframes ${key as string} {${rules[key].styledContent}}`;
|
|
282
|
+
}
|
|
275
283
|
});
|
|
276
284
|
}
|
|
277
285
|
styleSheet.replaceSync(style);
|
|
@@ -285,24 +293,7 @@ export function randomStr(len = 5): string {
|
|
|
285
293
|
return str;
|
|
286
294
|
}
|
|
287
295
|
|
|
288
|
-
const nestingRuleRegExp = new RegExp('&.*{((.|\n)*)}', 'g');
|
|
289
|
-
// 只支持一层嵌套
|
|
290
|
-
// https://drafts.csswg.org/css-nesting-1/
|
|
291
|
-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1648037
|
|
292
|
-
// https://bugs.webkit.org/show_bug.cgi?id=223497
|
|
293
|
-
function flatStyled(style: string, type: StyledType): StyledValueObject {
|
|
294
|
-
const nestingRules: string[] = [];
|
|
295
|
-
let styledContent =
|
|
296
|
-
`& {${style.replace(nestingRuleRegExp, (substr) => {
|
|
297
|
-
nestingRules.push(substr);
|
|
298
|
-
return '';
|
|
299
|
-
})}}` + nestingRules.join('');
|
|
300
|
-
styledContent = styledContent.replace(/&/g, type === 'class' ? '.&' : '#&');
|
|
301
|
-
return { styledContent, type };
|
|
302
|
-
}
|
|
303
|
-
|
|
304
296
|
// 写 css 文本,在 CSSStyleSheet 中使用,使用 styed-components 高亮
|
|
305
|
-
// 暂时不支持 `at` 规则
|
|
306
297
|
//
|
|
307
298
|
// createCSSSheet({
|
|
308
299
|
// red: styled.class`
|
|
@@ -313,18 +304,14 @@ function flatStyled(style: string, type: StyledType): StyledValueObject {
|
|
|
313
304
|
// `,
|
|
314
305
|
// });
|
|
315
306
|
export const styled = {
|
|
316
|
-
class: (arr: TemplateStringsArray, ...args: any[]) => {
|
|
317
|
-
|
|
318
|
-
return flatStyled(style, 'class');
|
|
307
|
+
class: (arr: TemplateStringsArray, ...args: any[]): StyledValueObject => {
|
|
308
|
+
return { styledContent: raw(arr, ...args), type: 'class' };
|
|
319
309
|
},
|
|
320
|
-
id: (arr: TemplateStringsArray, ...args: any[]) => {
|
|
321
|
-
|
|
322
|
-
return flatStyled(style, 'id');
|
|
310
|
+
id: (arr: TemplateStringsArray, ...args: any[]): StyledValueObject => {
|
|
311
|
+
return { styledContent: raw(arr, ...args), type: 'id' };
|
|
323
312
|
},
|
|
324
313
|
keyframes: (arr: TemplateStringsArray, ...args: any[]): StyledValueObject => {
|
|
325
|
-
|
|
326
|
-
const styledContent = `@keyframes & {${keyframesContent}}`;
|
|
327
|
-
return { styledContent, type: 'keyframes' };
|
|
314
|
+
return { styledContent: raw(arr, ...args), type: 'keyframes' };
|
|
328
315
|
},
|
|
329
316
|
};
|
|
330
317
|
|
|
@@ -385,7 +372,13 @@ export function objectMapToString<T = any>(
|
|
|
385
372
|
}
|
|
386
373
|
|
|
387
374
|
// Wait: Typescript lib dom CSSStyleDeclaration anchor position
|
|
388
|
-
type StyleProp =
|
|
375
|
+
type StyleProp =
|
|
376
|
+
| keyof CSSStyleDeclaration
|
|
377
|
+
| `--${string}`
|
|
378
|
+
| 'scrollbarWidth'
|
|
379
|
+
| 'scrollbarColor'
|
|
380
|
+
| 'anchorDefault'
|
|
381
|
+
| 'anchorName';
|
|
389
382
|
|
|
390
383
|
export type StyleObject = Partial<Record<StyleProp, string | number | false | undefined | null>>;
|
|
391
384
|
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.12';
|
package/src/test/utils.test.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
|
|
17
17
|
declare global {
|
|
18
18
|
interface CSSRuleList {
|
|
19
|
+
// only test style rule
|
|
19
20
|
item(index: number): CSSStyleRule;
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -106,15 +107,22 @@ describe('utils 测试', () => {
|
|
|
106
107
|
`,
|
|
107
108
|
wrap: styled.id`
|
|
108
109
|
position: fixed;
|
|
110
|
+
animation: 3s infinite alternate slideIn;
|
|
111
|
+
`,
|
|
112
|
+
slideIn: styled.keyframes`
|
|
113
|
+
from {
|
|
114
|
+
transform: translateX(0%);
|
|
115
|
+
}
|
|
109
116
|
`,
|
|
110
117
|
});
|
|
111
118
|
expect(cssSheet.scroll.startsWith('scroll')).to.true;
|
|
112
119
|
const rules = cssSheet[SheetToken].cssRules;
|
|
113
120
|
expect(rules.item(0).selectorText.startsWith('.scroll')).to.true;
|
|
114
|
-
expect(rules.item(0).style.background.
|
|
115
|
-
expect(
|
|
116
|
-
expect(rules.item(
|
|
117
|
-
expect(rules.item(
|
|
121
|
+
expect(rules.item(0).style.background).to.equal('red');
|
|
122
|
+
expect(rules.item(0).cssRules.item(0).selectorText).to.equal('&:hover *');
|
|
123
|
+
expect(rules.item(0).cssRules.item(0).style.background).to.equal('blue');
|
|
124
|
+
expect(rules.item(1).selectorText.startsWith('#wrap')).to.true;
|
|
125
|
+
expect((rules.item(2) as any).name).to.equal('slideIn');
|
|
118
126
|
});
|
|
119
127
|
it('styleMap/classMap/exportPartsMap', () => {
|
|
120
128
|
expect(styleMap({ '--x': '1px', fontSize: '14px', content: `'*'` })).to.equal(
|