lupine.components 1.1.11 → 1.1.14
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/README.md +3 -3
- package/package.json +42 -42
- package/src/components/action-sheet.tsx +419 -419
- package/src/components/button-push-animation.tsx +147 -138
- package/src/components/button.tsx +55 -55
- package/src/components/desktop-footer.tsx +17 -17
- package/src/components/desktop-header.tsx +52 -52
- package/src/components/drag-refresh.tsx +129 -129
- package/src/components/editable-label.tsx +83 -83
- package/src/components/float-window.tsx +233 -233
- package/src/components/grid.tsx +18 -18
- package/src/components/html-load.tsx +41 -41
- package/src/components/html-var.tsx +81 -81
- package/src/components/index.ts +43 -44
- package/src/components/input-with-title.tsx +24 -24
- package/src/components/link-item.tsx +13 -13
- package/src/components/link-list.tsx +62 -62
- package/src/components/menu-bar.tsx +219 -219
- package/src/components/menu-item-props.tsx +13 -13
- package/src/components/menu-sidebar.tsx +325 -318
- package/src/components/message-box.tsx +44 -44
- package/src/components/meta-data.tsx +36 -36
- package/src/components/meta-description.tsx +12 -12
- package/src/components/mobile-components/icon-menu-item-props.ts +6 -6
- package/src/components/mobile-components/index.ts +8 -9
- package/src/components/mobile-components/mobile-footer-menu.tsx +95 -95
- package/src/components/mobile-components/mobile-header-component.tsx +101 -101
- package/src/components/mobile-components/mobile-header-title-icon.tsx +109 -95
- package/src/components/mobile-components/mobile-header-with-back.tsx +127 -104
- package/src/components/mobile-components/mobile-side-menu.tsx +154 -154
- package/src/components/mobile-components/mobile-top-sys-icon.tsx +18 -18
- package/src/components/mobile-components/mobile-top-sys-menu.tsx +62 -62
- package/src/components/modal.tsx +33 -33
- package/src/components/notice-message.tsx +118 -118
- package/src/components/page-title.tsx +6 -6
- package/src/components/paging-link.tsx +175 -175
- package/src/components/panel.tsx +21 -21
- package/src/components/popup-menu.tsx +289 -289
- package/src/components/progress.tsx +91 -91
- package/src/components/radio-label-component.tsx +36 -36
- package/src/components/redirect.tsx +19 -19
- package/src/components/resizable-splitter.tsx +128 -128
- package/src/components/select-angle-component.tsx +127 -127
- package/src/components/select-with-title.tsx +37 -37
- package/src/components/slide-tab-component.tsx +144 -149
- package/src/components/spinner.tsx +106 -100
- package/src/components/stars-component.tsx +66 -66
- package/src/components/svg.tsx +24 -24
- package/src/components/tabs.tsx +279 -279
- package/src/components/text-glow.tsx +37 -37
- package/src/components/text-scale.tsx +42 -42
- package/src/components/text-wave.tsx +55 -55
- package/src/components/theme-selector.tsx +28 -28
- package/src/components/toggle-base.tsx +269 -269
- package/src/components/toggle-switch.tsx +160 -160
- package/src/frames/index.ts +3 -3
- package/src/frames/responsive-frame.tsx +83 -83
- package/src/frames/slider-frame.tsx +111 -111
- package/src/frames/top-frame.tsx +30 -30
- package/src/index.ts +5 -5
- package/src/lib/back-action-helper.ts +54 -54
- package/src/lib/base62.ts +23 -23
- package/src/lib/blob-utils.ts +23 -23
- package/src/lib/calculate-text-width.ts +13 -13
- package/src/lib/date-utils.ts +317 -317
- package/src/lib/deep-merge.ts +37 -37
- package/src/lib/document-ready.ts +34 -34
- package/src/lib/dom-utils.ts +32 -32
- package/src/lib/download-file.ts +118 -118
- package/src/lib/download-link.ts +12 -12
- package/src/lib/download-stream.ts +19 -19
- package/src/lib/drag-util.ts +118 -118
- package/src/lib/dynamical-load.ts +134 -134
- package/src/lib/encode-html.ts +27 -0
- package/src/lib/find-parent-tag.ts +8 -8
- package/src/lib/format-bytes.ts +11 -11
- package/src/lib/index.ts +24 -24
- package/src/lib/lite-dom.ts +225 -225
- package/src/lib/message-hub.ts +103 -104
- package/src/lib/observable.ts +188 -188
- package/src/lib/path-utils.ts +42 -42
- package/src/lib/promise-timeout.ts +1 -1
- package/src/lib/simple-storage.ts +40 -40
- package/src/lib/stop-propagation.ts +7 -7
- package/src/lib/upload-file.ts +101 -101
- package/src/styles/base-themes.ts +17 -17
- package/src/styles/dark-themes.ts +99 -99
- package/src/styles/index.ts +5 -5
- package/src/styles/light-themes.ts +106 -106
- package/src/styles/media-query.ts +93 -93
- package/src/styles/shared-themes.ts +57 -57
- package/tsconfig.json +113 -113
- package/src/lib/escape-html.ts +0 -9
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
/* frame component to show pages (sliders) from right or bottom
|
|
2
|
-
const sliderFrameHook: SliderFrameHookProps = {};
|
|
3
|
-
const onClick = (event: Event) => {
|
|
4
|
-
sliderFrameHook.load!(<... />);
|
|
5
|
-
or
|
|
6
|
-
sliderFrameHook.close!(event);
|
|
7
|
-
};
|
|
8
|
-
return (
|
|
9
|
-
<div onClick={onClick}>
|
|
10
|
-
<SliderFrame hook={sliderFrameHook} />
|
|
11
|
-
...
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
*/
|
|
15
|
-
import { VNode, CssProps, HtmlVar, RefProps, stopPropagation, MediaQueryRange } from 'lupine.components';
|
|
16
|
-
|
|
17
|
-
export type SliderFramePosition = 'desktop-slide-left' | 'desktop-slide-right';
|
|
18
|
-
export type SliderFrameHookProps = {
|
|
19
|
-
load?: (children: VNode<any>) => void;
|
|
20
|
-
close?: (event: Event) => void;
|
|
21
|
-
addClass?: (className: SliderFramePosition) => void;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export type SliderFrameProps = {
|
|
25
|
-
defaultContent?: VNode<any> | string;
|
|
26
|
-
direction?: 'right' | 'bottom';
|
|
27
|
-
hook?: SliderFrameHookProps;
|
|
28
|
-
afterClose?: () => void | Promise<void>;
|
|
29
|
-
};
|
|
30
|
-
export const SliderFrame = (props: SliderFrameProps) => {
|
|
31
|
-
if (props.hook) {
|
|
32
|
-
props.hook.load = (children) => {
|
|
33
|
-
dom.value = children;
|
|
34
|
-
ref.current?.classList.remove('d-none');
|
|
35
|
-
setTimeout(() => {
|
|
36
|
-
ref.current?.classList.add('show');
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
props.hook.close = (event: Event) => {
|
|
40
|
-
stopPropagation(event);
|
|
41
|
-
ref.current?.classList.remove('show');
|
|
42
|
-
setTimeout(async () => {
|
|
43
|
-
ref.current?.classList.add('d-none');
|
|
44
|
-
dom.value = '';
|
|
45
|
-
if (props.afterClose) {
|
|
46
|
-
await props.afterClose();
|
|
47
|
-
}
|
|
48
|
-
}, 400);
|
|
49
|
-
};
|
|
50
|
-
props.hook.addClass = (className) => {
|
|
51
|
-
ref.current?.classList.add(className);
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
const dom = new HtmlVar(<div class='slider-frame-default'>{props.defaultContent || '(No Content)'}</div>);
|
|
55
|
-
const ref: RefProps = {};
|
|
56
|
-
const css: CssProps = {
|
|
57
|
-
display: 'flex',
|
|
58
|
-
flexDirection: 'column',
|
|
59
|
-
position: 'fixed',
|
|
60
|
-
top: '0',
|
|
61
|
-
left: '0',
|
|
62
|
-
right: '0',
|
|
63
|
-
bottom: '0',
|
|
64
|
-
zIndex: 'var(--layer-slider)',
|
|
65
|
-
transform: props.direction === 'bottom' ? 'translateY(100%)' : 'translateX(100%)',
|
|
66
|
-
transition: 'transform 0.4s ease-in-out',
|
|
67
|
-
backgroundColor: 'var(--primary-bg-color)',
|
|
68
|
-
'&.show': {
|
|
69
|
-
transform: props.direction === 'bottom' ? 'translateY(0)' : 'translateX(0)',
|
|
70
|
-
},
|
|
71
|
-
'& > fragment': {
|
|
72
|
-
height: '100%',
|
|
73
|
-
},
|
|
74
|
-
'&.desktop-slide-left': {
|
|
75
|
-
[MediaQueryRange.TabletAbove]: {
|
|
76
|
-
'.header-back-content': {
|
|
77
|
-
width: '30%',
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
'&.desktop-slide-right': {
|
|
82
|
-
[MediaQueryRange.TabletAbove]: {
|
|
83
|
-
top: '59px',
|
|
84
|
-
left: '30%',
|
|
85
|
-
transform: 'translateX(0)',
|
|
86
|
-
// notice: here is connected with mobile-header-title-icon.tsx
|
|
87
|
-
'.mobile-header-title-icon-top': {
|
|
88
|
-
width: '100%',
|
|
89
|
-
boxShadow: 'unset',
|
|
90
|
-
},
|
|
91
|
-
'.header-back-content': {
|
|
92
|
-
width: '100%',
|
|
93
|
-
},
|
|
94
|
-
'.mhti-title': {
|
|
95
|
-
fontSize: '15px',
|
|
96
|
-
},
|
|
97
|
-
'.mhti-left, .mhti-right': {
|
|
98
|
-
display: 'none',
|
|
99
|
-
},
|
|
100
|
-
'&.d-none': {
|
|
101
|
-
display: 'unset !important',
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
return (
|
|
107
|
-
<div ref={ref} css={css} class='slider-frame d-none'>
|
|
108
|
-
{dom.node}
|
|
109
|
-
</div>
|
|
110
|
-
);
|
|
111
|
-
};
|
|
1
|
+
/* frame component to show pages (sliders) from right or bottom
|
|
2
|
+
const sliderFrameHook: SliderFrameHookProps = {};
|
|
3
|
+
const onClick = (event: Event) => {
|
|
4
|
+
sliderFrameHook.load!(<... />);
|
|
5
|
+
or
|
|
6
|
+
sliderFrameHook.close!(event);
|
|
7
|
+
};
|
|
8
|
+
return (
|
|
9
|
+
<div onClick={onClick}>
|
|
10
|
+
<SliderFrame hook={sliderFrameHook} />
|
|
11
|
+
...
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
*/
|
|
15
|
+
import { VNode, CssProps, HtmlVar, RefProps, stopPropagation, MediaQueryRange } from 'lupine.components';
|
|
16
|
+
|
|
17
|
+
export type SliderFramePosition = 'desktop-slide-left' | 'desktop-slide-right';
|
|
18
|
+
export type SliderFrameHookProps = {
|
|
19
|
+
load?: (children: VNode<any>) => void;
|
|
20
|
+
close?: (event: Event) => void;
|
|
21
|
+
addClass?: (className: SliderFramePosition) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type SliderFrameProps = {
|
|
25
|
+
defaultContent?: VNode<any> | string;
|
|
26
|
+
direction?: 'right' | 'bottom';
|
|
27
|
+
hook?: SliderFrameHookProps;
|
|
28
|
+
afterClose?: () => void | Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
export const SliderFrame = (props: SliderFrameProps) => {
|
|
31
|
+
if (props.hook) {
|
|
32
|
+
props.hook.load = (children) => {
|
|
33
|
+
dom.value = children;
|
|
34
|
+
ref.current?.classList.remove('d-none');
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
ref.current?.classList.add('show');
|
|
37
|
+
}, 100);
|
|
38
|
+
};
|
|
39
|
+
props.hook.close = (event: Event) => {
|
|
40
|
+
stopPropagation(event);
|
|
41
|
+
ref.current?.classList.remove('show');
|
|
42
|
+
setTimeout(async () => {
|
|
43
|
+
ref.current?.classList.add('d-none');
|
|
44
|
+
dom.value = '';
|
|
45
|
+
if (props.afterClose) {
|
|
46
|
+
await props.afterClose();
|
|
47
|
+
}
|
|
48
|
+
}, 400);
|
|
49
|
+
};
|
|
50
|
+
props.hook.addClass = (className) => {
|
|
51
|
+
ref.current?.classList.add(className);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const dom = new HtmlVar(<div class='slider-frame-default'>{props.defaultContent || '(No Content)'}</div>);
|
|
55
|
+
const ref: RefProps = {};
|
|
56
|
+
const css: CssProps = {
|
|
57
|
+
display: 'flex',
|
|
58
|
+
flexDirection: 'column',
|
|
59
|
+
position: 'fixed',
|
|
60
|
+
top: '0',
|
|
61
|
+
left: '0',
|
|
62
|
+
right: '0',
|
|
63
|
+
bottom: '0',
|
|
64
|
+
zIndex: 'var(--layer-slider)',
|
|
65
|
+
transform: props.direction === 'bottom' ? 'translateY(100%)' : 'translateX(100%)',
|
|
66
|
+
transition: 'transform 0.4s ease-in-out',
|
|
67
|
+
backgroundColor: 'var(--primary-bg-color)',
|
|
68
|
+
'&.show': {
|
|
69
|
+
transform: props.direction === 'bottom' ? 'translateY(0)' : 'translateX(0)',
|
|
70
|
+
},
|
|
71
|
+
'& > fragment': {
|
|
72
|
+
height: '100%',
|
|
73
|
+
},
|
|
74
|
+
'&.desktop-slide-left': {
|
|
75
|
+
[MediaQueryRange.TabletAbove]: {
|
|
76
|
+
'.header-back-content': {
|
|
77
|
+
width: '30%',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
'&.desktop-slide-right': {
|
|
82
|
+
[MediaQueryRange.TabletAbove]: {
|
|
83
|
+
top: '59px',
|
|
84
|
+
left: '30%',
|
|
85
|
+
transform: 'translateX(0)',
|
|
86
|
+
// notice: here is connected with mobile-header-title-icon.tsx
|
|
87
|
+
'.mobile-header-title-icon-top': {
|
|
88
|
+
width: '100%',
|
|
89
|
+
boxShadow: 'unset',
|
|
90
|
+
},
|
|
91
|
+
'.header-back-content': {
|
|
92
|
+
width: '100%',
|
|
93
|
+
},
|
|
94
|
+
'.mhti-title': {
|
|
95
|
+
fontSize: '15px',
|
|
96
|
+
},
|
|
97
|
+
'.mhti-left, .mhti-right': {
|
|
98
|
+
display: 'none',
|
|
99
|
+
},
|
|
100
|
+
'&.d-none': {
|
|
101
|
+
display: 'unset !important',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
return (
|
|
107
|
+
<div ref={ref} css={css} class='slider-frame d-none'>
|
|
108
|
+
{dom.node}
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
};
|
package/src/frames/top-frame.tsx
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
/* most top-frame for all other pages
|
|
2
|
-
place to set safe-area-inset-top and other common styles
|
|
3
|
-
*/
|
|
4
|
-
import { VNode, CssProps } from 'lupine.components';
|
|
5
|
-
|
|
6
|
-
export const TopFrame = async (placeholderClassname: string, vnode: VNode<any>) => {
|
|
7
|
-
const cssContainer: CssProps = {
|
|
8
|
-
display: 'flex',
|
|
9
|
-
flexDirection: 'column',
|
|
10
|
-
width: '100%',
|
|
11
|
-
height: '100%',
|
|
12
|
-
position: 'relative',
|
|
13
|
-
'.top-frame-box': {
|
|
14
|
-
display: 'flex',
|
|
15
|
-
flex: '1',
|
|
16
|
-
flexDirection: 'column',
|
|
17
|
-
height: '100%',
|
|
18
|
-
// trick: to put two padding-top properties
|
|
19
|
-
'padding-top ': 'constant(safe-area-inset-top)',
|
|
20
|
-
'padding-top': 'env(safe-area-inset-top)',
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<div css={cssContainer}>
|
|
26
|
-
{/* Can't put css on this placeholder node! */}
|
|
27
|
-
<div class={'top-frame-box ' + placeholderClassname}>{vnode}</div>
|
|
28
|
-
</div>
|
|
29
|
-
);
|
|
30
|
-
};
|
|
1
|
+
/* most top-frame for all other pages
|
|
2
|
+
place to set safe-area-inset-top and other common styles
|
|
3
|
+
*/
|
|
4
|
+
import { VNode, CssProps } from 'lupine.components';
|
|
5
|
+
|
|
6
|
+
export const TopFrame = async (placeholderClassname: string, vnode: VNode<any>) => {
|
|
7
|
+
const cssContainer: CssProps = {
|
|
8
|
+
display: 'flex',
|
|
9
|
+
flexDirection: 'column',
|
|
10
|
+
width: '100%',
|
|
11
|
+
height: '100%',
|
|
12
|
+
position: 'relative',
|
|
13
|
+
'.top-frame-box': {
|
|
14
|
+
display: 'flex',
|
|
15
|
+
flex: '1',
|
|
16
|
+
flexDirection: 'column',
|
|
17
|
+
height: '100%',
|
|
18
|
+
// trick: to put two padding-top properties
|
|
19
|
+
'padding-top ': 'constant(safe-area-inset-top)',
|
|
20
|
+
'padding-top': 'env(safe-area-inset-top)',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div css={cssContainer}>
|
|
26
|
+
{/* Can't put css on this placeholder node! */}
|
|
27
|
+
<div class={'top-frame-box ' + placeholderClassname}>{vnode}</div>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from 'lupine.web';
|
|
2
|
-
export * from './lib';
|
|
3
|
-
export * from './styles';
|
|
4
|
-
export * from './components';
|
|
5
|
-
export * from './frames';
|
|
1
|
+
export * from 'lupine.web';
|
|
2
|
+
export * from './lib';
|
|
3
|
+
export * from './styles';
|
|
4
|
+
export * from './components';
|
|
5
|
+
export * from './frames';
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import { uniqueIdGenerator } from 'lupine.web';
|
|
2
|
-
|
|
3
|
-
type BackFn = () => void | Promise<void>;
|
|
4
|
-
|
|
5
|
-
export const backActionUniqueId = uniqueIdGenerator('bb-'); // bb means back button
|
|
6
|
-
class BackActionHelper {
|
|
7
|
-
private backFn?: BackFn;
|
|
8
|
-
|
|
9
|
-
genBackActionId() {
|
|
10
|
-
return backActionUniqueId();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
getAllBackActionButtons() {
|
|
14
|
-
const nodes = document.querySelectorAll('[data-back-action^="bb-"]');
|
|
15
|
-
const buttons = Array.from(nodes)
|
|
16
|
-
.map((el) => {
|
|
17
|
-
const act = el.getAttribute('data-back-action') || '';
|
|
18
|
-
return { el, ind: act.substring(3) };
|
|
19
|
-
})
|
|
20
|
-
.filter(Boolean)
|
|
21
|
-
.sort((a, b) => b.ind.localeCompare(a.ind)) // desc
|
|
22
|
-
.map((item) => item.el);
|
|
23
|
-
return buttons;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
clear() {
|
|
27
|
-
this.backFn = undefined;
|
|
28
|
-
}
|
|
29
|
-
attach(back: BackFn) {
|
|
30
|
-
this.backFn = back;
|
|
31
|
-
}
|
|
32
|
-
async processBackAction(): Promise<boolean> {
|
|
33
|
-
if (this.backFn) {
|
|
34
|
-
try {
|
|
35
|
-
await this.backFn();
|
|
36
|
-
this.clear();
|
|
37
|
-
return true;
|
|
38
|
-
} catch (e) {
|
|
39
|
-
console.error('back button back failed', e);
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const buttons = this.getAllBackActionButtons();
|
|
45
|
-
if (buttons.length) {
|
|
46
|
-
const button = buttons[0];
|
|
47
|
-
button.dispatchEvent(new Event('click'));
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const backActionHelper = /* @__PURE__ */ new BackActionHelper();
|
|
1
|
+
import { uniqueIdGenerator } from 'lupine.web';
|
|
2
|
+
|
|
3
|
+
type BackFn = () => void | Promise<void>;
|
|
4
|
+
|
|
5
|
+
export const backActionUniqueId = uniqueIdGenerator('bb-'); // bb means back button
|
|
6
|
+
class BackActionHelper {
|
|
7
|
+
private backFn?: BackFn;
|
|
8
|
+
|
|
9
|
+
genBackActionId() {
|
|
10
|
+
return backActionUniqueId();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getAllBackActionButtons() {
|
|
14
|
+
const nodes = document.querySelectorAll('[data-back-action^="bb-"]');
|
|
15
|
+
const buttons = Array.from(nodes)
|
|
16
|
+
.map((el) => {
|
|
17
|
+
const act = el.getAttribute('data-back-action') || '';
|
|
18
|
+
return { el, ind: act.substring(3) };
|
|
19
|
+
})
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.sort((a, b) => b.ind.localeCompare(a.ind)) // desc
|
|
22
|
+
.map((item) => item.el);
|
|
23
|
+
return buttons;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
clear() {
|
|
27
|
+
this.backFn = undefined;
|
|
28
|
+
}
|
|
29
|
+
attach(back: BackFn) {
|
|
30
|
+
this.backFn = back;
|
|
31
|
+
}
|
|
32
|
+
async processBackAction(): Promise<boolean> {
|
|
33
|
+
if (this.backFn) {
|
|
34
|
+
try {
|
|
35
|
+
await this.backFn();
|
|
36
|
+
this.clear();
|
|
37
|
+
return true;
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.error('back button back failed', e);
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const buttons = this.getAllBackActionButtons();
|
|
45
|
+
if (buttons.length) {
|
|
46
|
+
const button = buttons[0];
|
|
47
|
+
button.dispatchEvent(new Event('click'));
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const backActionHelper = /* @__PURE__ */ new BackActionHelper();
|
package/src/lib/base62.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
export class Base62 {
|
|
2
|
-
private static ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
3
|
-
private static BASE = 62;
|
|
4
|
-
static toString(num: number) {
|
|
5
|
-
if (num === 0) return Base62.ALPHABET[0];
|
|
6
|
-
|
|
7
|
-
let result = '';
|
|
8
|
-
while (num > 0) {
|
|
9
|
-
const rem = num % Base62.BASE;
|
|
10
|
-
result = Base62.ALPHABET[rem] + result;
|
|
11
|
-
num = Math.floor(num / Base62.BASE);
|
|
12
|
-
}
|
|
13
|
-
return result;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static fromString(str: string) {
|
|
17
|
-
let result = 0;
|
|
18
|
-
for (let i = 0; i < str.length; i++) {
|
|
19
|
-
result = result * Base62.BASE + Base62.ALPHABET.indexOf(str[i]);
|
|
20
|
-
}
|
|
21
|
-
return result;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
export class Base62 {
|
|
2
|
+
private static ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
3
|
+
private static BASE = 62;
|
|
4
|
+
static toString(num: number) {
|
|
5
|
+
if (num === 0) return Base62.ALPHABET[0];
|
|
6
|
+
|
|
7
|
+
let result = '';
|
|
8
|
+
while (num > 0) {
|
|
9
|
+
const rem = num % Base62.BASE;
|
|
10
|
+
result = Base62.ALPHABET[rem] + result;
|
|
11
|
+
num = Math.floor(num / Base62.BASE);
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static fromString(str: string) {
|
|
17
|
+
let result = 0;
|
|
18
|
+
for (let i = 0; i < str.length; i++) {
|
|
19
|
+
result = result * Base62.BASE + Base62.ALPHABET.indexOf(str[i]);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/lib/blob-utils.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
export const blobToBase64 = (blob: Blob): Promise<string> => {
|
|
2
|
-
return new Promise((resolve, reject) => {
|
|
3
|
-
const reader = new FileReader();
|
|
4
|
-
reader.onloadend = () => resolve(reader.result as string); // data:audio/mpeg;base64,...
|
|
5
|
-
reader.onerror = reject;
|
|
6
|
-
reader.readAsDataURL(blob);
|
|
7
|
-
});
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const blobFromBase64 = (base64: string) => {
|
|
11
|
-
const [header, base64Data] = base64.split(','); // remove data:... prefix
|
|
12
|
-
const mimeMatch = header.match(/data:(.*);base64/);
|
|
13
|
-
const mimeType = mimeMatch ? mimeMatch[1] : 'application/octet-stream';
|
|
14
|
-
const byteCharacters = atob(base64Data);
|
|
15
|
-
const byteNumbers = Array.from(byteCharacters).map((c) => c.charCodeAt(0));
|
|
16
|
-
const byteArray = new Uint8Array(byteNumbers);
|
|
17
|
-
return new Blob([byteArray], { type: mimeType });
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const base64ToUrl = (base64: string) => {
|
|
21
|
-
const blob = blobFromBase64(base64);
|
|
22
|
-
return URL.createObjectURL(blob);
|
|
23
|
-
};
|
|
1
|
+
export const blobToBase64 = (blob: Blob, removeMeta?: boolean): Promise<string> => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
const reader = new FileReader();
|
|
4
|
+
reader.onloadend = () => resolve(removeMeta ? (reader.result as string).split(',')[1] : (reader.result as string)); // data:audio/mpeg;base64,...
|
|
5
|
+
reader.onerror = reject;
|
|
6
|
+
reader.readAsDataURL(blob);
|
|
7
|
+
});
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const blobFromBase64 = (base64: string) => {
|
|
11
|
+
const [header, base64Data] = base64.split(','); // remove data:... prefix
|
|
12
|
+
const mimeMatch = header.match(/data:(.*);base64/);
|
|
13
|
+
const mimeType = mimeMatch ? mimeMatch[1] : 'application/octet-stream';
|
|
14
|
+
const byteCharacters = atob(base64Data);
|
|
15
|
+
const byteNumbers = Array.from(byteCharacters).map((c) => c.charCodeAt(0));
|
|
16
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
17
|
+
return new Blob([byteArray], { type: mimeType });
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const base64ToUrl = (base64: string) => {
|
|
21
|
+
const blob = blobFromBase64(base64);
|
|
22
|
+
return URL.createObjectURL(blob);
|
|
23
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param text
|
|
3
|
-
* @param font, sample: italic/normal 19pt Times New Roman
|
|
4
|
-
* @returns width
|
|
5
|
-
*/
|
|
6
|
-
const calculateTextWidthSaved: { canvas: any } = { canvas: null };
|
|
7
|
-
export function calculateTextWidth(text: string, font: string) {
|
|
8
|
-
let canvas = calculateTextWidthSaved.canvas || (calculateTextWidthSaved.canvas = document.createElement('canvas'));
|
|
9
|
-
let context = canvas.getContext('2d');
|
|
10
|
-
context.font = font;
|
|
11
|
-
let metrics = context.measureText(text);
|
|
12
|
-
return metrics.width;
|
|
13
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @param text
|
|
3
|
+
* @param font, sample: italic/normal 19pt Times New Roman
|
|
4
|
+
* @returns width
|
|
5
|
+
*/
|
|
6
|
+
const calculateTextWidthSaved: { canvas: any } = { canvas: null };
|
|
7
|
+
export function calculateTextWidth(text: string, font: string) {
|
|
8
|
+
let canvas = calculateTextWidthSaved.canvas || (calculateTextWidthSaved.canvas = document.createElement('canvas'));
|
|
9
|
+
let context = canvas.getContext('2d');
|
|
10
|
+
context.font = font;
|
|
11
|
+
let metrics = context.measureText(text);
|
|
12
|
+
return metrics.width;
|
|
13
|
+
}
|