lupine.components 1.1.13 → 1.1.15

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 (92) hide show
  1. package/README.md +3 -3
  2. package/package.json +42 -42
  3. package/src/components/action-sheet.tsx +419 -419
  4. package/src/components/button-push-animation.tsx +147 -138
  5. package/src/components/button.tsx +55 -55
  6. package/src/components/desktop-footer.tsx +17 -17
  7. package/src/components/desktop-header.tsx +52 -52
  8. package/src/components/drag-refresh.tsx +129 -129
  9. package/src/components/editable-label.tsx +83 -83
  10. package/src/components/float-window.tsx +233 -233
  11. package/src/components/grid.tsx +18 -18
  12. package/src/components/html-load.tsx +41 -41
  13. package/src/components/html-var.tsx +81 -81
  14. package/src/components/index.ts +43 -44
  15. package/src/components/input-with-title.tsx +24 -24
  16. package/src/components/link-item.tsx +13 -13
  17. package/src/components/link-list.tsx +62 -62
  18. package/src/components/menu-bar.tsx +219 -219
  19. package/src/components/menu-item-props.tsx +13 -13
  20. package/src/components/menu-sidebar.tsx +325 -318
  21. package/src/components/message-box.tsx +44 -44
  22. package/src/components/meta-data.tsx +36 -36
  23. package/src/components/meta-description.tsx +12 -12
  24. package/src/components/mobile-components/icon-menu-item-props.ts +6 -6
  25. package/src/components/mobile-components/index.ts +8 -9
  26. package/src/components/mobile-components/mobile-footer-menu.tsx +95 -95
  27. package/src/components/mobile-components/mobile-header-component.tsx +101 -101
  28. package/src/components/mobile-components/mobile-header-title-icon.tsx +109 -101
  29. package/src/components/mobile-components/mobile-header-with-back.tsx +127 -117
  30. package/src/components/mobile-components/mobile-side-menu.tsx +154 -154
  31. package/src/components/mobile-components/mobile-top-sys-icon.tsx +18 -18
  32. package/src/components/mobile-components/mobile-top-sys-menu.tsx +62 -62
  33. package/src/components/modal.tsx +33 -33
  34. package/src/components/notice-message.tsx +118 -118
  35. package/src/components/page-title.tsx +6 -6
  36. package/src/components/paging-link.tsx +175 -175
  37. package/src/components/panel.tsx +21 -21
  38. package/src/components/popup-menu.tsx +289 -289
  39. package/src/components/progress.tsx +91 -91
  40. package/src/components/radio-label-component.tsx +36 -36
  41. package/src/components/redirect.tsx +19 -19
  42. package/src/components/resizable-splitter.tsx +128 -128
  43. package/src/components/select-angle-component.tsx +127 -127
  44. package/src/components/select-with-title.tsx +37 -37
  45. package/src/components/slide-tab-component.tsx +144 -149
  46. package/src/components/spinner.tsx +106 -100
  47. package/src/components/stars-component.tsx +66 -66
  48. package/src/components/svg.tsx +24 -24
  49. package/src/components/tabs.tsx +279 -279
  50. package/src/components/text-glow.tsx +37 -37
  51. package/src/components/text-scale.tsx +42 -42
  52. package/src/components/text-wave.tsx +55 -55
  53. package/src/components/theme-selector.tsx +28 -28
  54. package/src/components/toggle-base.tsx +285 -269
  55. package/src/components/toggle-switch.tsx +160 -160
  56. package/src/frames/index.ts +3 -3
  57. package/src/frames/responsive-frame.tsx +83 -83
  58. package/src/frames/slider-frame.tsx +111 -111
  59. package/src/frames/top-frame.tsx +30 -30
  60. package/src/index.ts +5 -5
  61. package/src/lib/back-action-helper.ts +54 -54
  62. package/src/lib/base62.ts +23 -23
  63. package/src/lib/blob-utils.ts +23 -23
  64. package/src/lib/calculate-text-width.ts +13 -13
  65. package/src/lib/date-utils.ts +317 -317
  66. package/src/lib/deep-merge.ts +37 -37
  67. package/src/lib/document-ready.ts +34 -34
  68. package/src/lib/dom-utils.ts +32 -32
  69. package/src/lib/download-file.ts +118 -118
  70. package/src/lib/download-link.ts +12 -12
  71. package/src/lib/download-stream.ts +19 -19
  72. package/src/lib/drag-util.ts +118 -118
  73. package/src/lib/dynamical-load.ts +134 -134
  74. package/src/lib/encode-html.ts +27 -27
  75. package/src/lib/find-parent-tag.ts +8 -8
  76. package/src/lib/format-bytes.ts +11 -11
  77. package/src/lib/index.ts +24 -24
  78. package/src/lib/lite-dom.ts +225 -225
  79. package/src/lib/message-hub.ts +103 -104
  80. package/src/lib/observable.ts +188 -188
  81. package/src/lib/path-utils.ts +42 -42
  82. package/src/lib/promise-timeout.ts +1 -1
  83. package/src/lib/simple-storage.ts +40 -40
  84. package/src/lib/stop-propagation.ts +7 -7
  85. package/src/lib/upload-file.ts +101 -101
  86. package/src/styles/base-themes.ts +17 -17
  87. package/src/styles/dark-themes.ts +99 -99
  88. package/src/styles/index.ts +5 -5
  89. package/src/styles/light-themes.ts +106 -106
  90. package/src/styles/media-query.ts +93 -93
  91. package/src/styles/shared-themes.ts +57 -57
  92. package/tsconfig.json +113 -113
@@ -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
- }, 1);
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
+ };
@@ -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
+ }
@@ -1,23 +1,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
+ 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
+ }