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.
Files changed (93) 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 -95
  29. package/src/components/mobile-components/mobile-header-with-back.tsx +127 -104
  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 +269 -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 -0
  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
  93. package/src/lib/escape-html.ts +0 -9
@@ -1,44 +1,44 @@
1
- import { FloatWindow, FloatWindowCloseProps, FloatWindowShowProps } from './float-window';
2
-
3
- export enum MessageBoxButtonProps {
4
- YesNo = 'yesno',
5
- OkCancel = 'okcancel',
6
- Ok = 'ok',
7
- }
8
- export type MessageBoxProps = FloatWindowShowProps & {
9
- buttonType: MessageBoxButtonProps;
10
- };
11
-
12
- export class MessageBox {
13
- static async show({
14
- title,
15
- children,
16
- contentMaxHeight,
17
- contentMinWidth,
18
- buttonType = MessageBoxButtonProps.OkCancel,
19
- noMoving = false,
20
- noModal = false,
21
- closeEvent,
22
- handleClicked,
23
- closeWhenClickOutside = false,
24
- }: MessageBoxProps): Promise<FloatWindowCloseProps> {
25
- const buttons =
26
- buttonType === MessageBoxButtonProps.OkCancel
27
- ? ['OK', 'Cancel']
28
- : buttonType === MessageBoxButtonProps.YesNo
29
- ? ['Yes', 'No']
30
- : ['OK'];
31
- return FloatWindow.show({
32
- title,
33
- children,
34
- contentMaxHeight,
35
- contentMinWidth,
36
- buttons,
37
- noMoving,
38
- noModal,
39
- closeEvent,
40
- handleClicked,
41
- closeWhenClickOutside,
42
- });
43
- }
44
- }
1
+ import { FloatWindow, FloatWindowCloseProps, FloatWindowShowProps } from './float-window';
2
+
3
+ export enum MessageBoxButtonProps {
4
+ YesNo = 'yesno',
5
+ OkCancel = 'okcancel',
6
+ Ok = 'ok',
7
+ }
8
+ export type MessageBoxProps = FloatWindowShowProps & {
9
+ buttonType: MessageBoxButtonProps;
10
+ };
11
+
12
+ export class MessageBox {
13
+ static async show({
14
+ title,
15
+ children,
16
+ contentMaxHeight,
17
+ contentMinWidth,
18
+ buttonType = MessageBoxButtonProps.OkCancel,
19
+ noMoving = false,
20
+ noModal = false,
21
+ closeEvent,
22
+ handleClicked,
23
+ closeWhenClickOutside = false,
24
+ }: MessageBoxProps): Promise<FloatWindowCloseProps> {
25
+ const buttons =
26
+ buttonType === MessageBoxButtonProps.OkCancel
27
+ ? ['OK', 'Cancel']
28
+ : buttonType === MessageBoxButtonProps.YesNo
29
+ ? ['Yes', 'No']
30
+ : ['OK'];
31
+ return FloatWindow.show({
32
+ title,
33
+ children,
34
+ contentMaxHeight,
35
+ contentMinWidth,
36
+ buttons,
37
+ noMoving,
38
+ noModal,
39
+ closeEvent,
40
+ handleClicked,
41
+ closeWhenClickOutside,
42
+ });
43
+ }
44
+ }
@@ -1,36 +1,36 @@
1
- // import { bindPageResetEvent } from '../core/page-reset-events';
2
- import { addMetaDataTags } from 'lupine.web';
3
- type NameMeta = { name: string; content: string };
4
- type PropertyMeta = { property: string; content: string };
5
- type HttpEquivMeta = { httpEquiv: string; content: string };
6
- type AllMeta = NameMeta | PropertyMeta | HttpEquivMeta;
7
-
8
- function isNameMeta(data: any): data is NameMeta {
9
- return !!(data.name && data.content);
10
- }
11
- function isPropertyMeta(data: any): data is PropertyMeta {
12
- return !!(data.property && data.content);
13
- }
14
- function isHttpEquivMeta(data: any): data is HttpEquivMeta {
15
- return !!(data.httpEquiv && data.content);
16
- }
17
-
18
- // should use description tag instead of meta tag ( <meta name="description" content="..."> )
19
- export const MetaData = (data: AllMeta) => {
20
- if (isNameMeta(data)) {
21
- addMetaDataTags(`name:${data.name}`, `<meta name="${data.name}" content="${data.content}">`);
22
- } else if (isPropertyMeta(data)) {
23
- addMetaDataTags(`property:${data.property}`, `<meta property="${data.property}" content="${data.content}">`);
24
- } else if (isHttpEquivMeta(data)) {
25
- addMetaDataTags(`http-equiv:${data.httpEquiv}`, `<meta http-equiv="${data.httpEquiv}" content="${data.content}">`);
26
- } else if ((data as any).key && (data as any).string) {
27
- addMetaDataTags(`${(data as any).key}`, `${(data as any).string}`);
28
- } else {
29
- console.warn('Unknown meta data:', data);
30
- }
31
- return <></>;
32
- };
33
-
34
- // bindPageResetEvent(() => {
35
- // _metaData = {};
36
- // });
1
+ // import { bindPageResetEvent } from '../core/page-reset-events';
2
+ import { addMetaDataTags } from 'lupine.web';
3
+ type NameMeta = { name: string; content: string };
4
+ type PropertyMeta = { property: string; content: string };
5
+ type HttpEquivMeta = { httpEquiv: string; content: string };
6
+ type AllMeta = NameMeta | PropertyMeta | HttpEquivMeta;
7
+
8
+ function isNameMeta(data: any): data is NameMeta {
9
+ return !!(data.name && data.content);
10
+ }
11
+ function isPropertyMeta(data: any): data is PropertyMeta {
12
+ return !!(data.property && data.content);
13
+ }
14
+ function isHttpEquivMeta(data: any): data is HttpEquivMeta {
15
+ return !!(data.httpEquiv && data.content);
16
+ }
17
+
18
+ // should use description tag instead of meta tag ( <meta name="description" content="..."> )
19
+ export const MetaData = (data: AllMeta) => {
20
+ if (isNameMeta(data)) {
21
+ addMetaDataTags(`name:${data.name}`, `<meta name="${data.name}" content="${data.content}">`);
22
+ } else if (isPropertyMeta(data)) {
23
+ addMetaDataTags(`property:${data.property}`, `<meta property="${data.property}" content="${data.content}">`);
24
+ } else if (isHttpEquivMeta(data)) {
25
+ addMetaDataTags(`http-equiv:${data.httpEquiv}`, `<meta http-equiv="${data.httpEquiv}" content="${data.content}">`);
26
+ } else if ((data as any).key && (data as any).string) {
27
+ addMetaDataTags(`${(data as any).key}`, `${(data as any).string}`);
28
+ } else {
29
+ console.warn('Unknown meta data:', data);
30
+ }
31
+ return <></>;
32
+ };
33
+
34
+ // bindPageResetEvent(() => {
35
+ // _metaData = {};
36
+ // });
@@ -1,12 +1,12 @@
1
- // import { bindPageResetEvent } from '../core/page-reset-events';
2
-
3
- import { addMetaDataTags } from "lupine.web";
4
-
5
- export const MetaDescription = ({ children }: { children: string }) => {
6
- addMetaDataTags('name:description', `<meta name="description" content="${children}">`);
7
- return <></>;
8
- };
9
-
10
- // bindPageResetEvent(() => {
11
- // _description.value = '';
12
- // });
1
+ // import { bindPageResetEvent } from '../core/page-reset-events';
2
+
3
+ import { addMetaDataTags } from 'lupine.web';
4
+
5
+ export const MetaDescription = ({ children }: { children: string }) => {
6
+ addMetaDataTags('name:description', `<meta name="description" content="${children}">`);
7
+ return <></>;
8
+ };
9
+
10
+ // bindPageResetEvent(() => {
11
+ // _description.value = '';
12
+ // });
@@ -1,6 +1,6 @@
1
- export interface IconMenuItemProps {
2
- icon: string;
3
- href: string;
4
- text: string;
5
- topout?: boolean; // Topout for mobile bottom icon menu
6
- }
1
+ export interface IconMenuItemProps {
2
+ icon: string;
3
+ href: string;
4
+ text: string;
5
+ topout?: boolean; // Topout for mobile bottom icon menu
6
+ }
@@ -1,9 +1,8 @@
1
- export * from './icon-menu-item-props';
2
- export * from './mobile-footer-menu';
3
- export * from './mobile-header-with-back';
4
- export * from './mobile-header-component';
5
- export * from './mobile-header-title-icon';
6
- export * from './mobile-side-menu';
7
- export * from './mobile-top-sys-icon';
8
- export * from './mobile-top-sys-menu';
9
-
1
+ export * from './icon-menu-item-props';
2
+ export * from './mobile-footer-menu';
3
+ export * from './mobile-header-with-back';
4
+ export * from './mobile-header-component';
5
+ export * from './mobile-header-title-icon';
6
+ export * from './mobile-side-menu';
7
+ export * from './mobile-top-sys-icon';
8
+ export * from './mobile-top-sys-menu';
@@ -1,95 +1,95 @@
1
- import { CssProps, MediaQueryRange } from 'lupine.components';
2
- import { IconMenuItemProps } from './icon-menu-item-props';
3
-
4
- export interface MobileFooterMenuProps {
5
- items: IconMenuItemProps[];
6
- color?: string;
7
- activeColor?: string;
8
- topoutColor?: string;
9
- topoutBackgroundColor?: string;
10
- }
11
- export const MobileFooterMenu = (props: MobileFooterMenuProps) => {
12
- const css: CssProps = {
13
- '.footer-menu': {
14
- display: 'none',
15
- // position: 'fixed',
16
- // left: 0,
17
- // right: 0,
18
- // bottom: 0,
19
- width: '100%',
20
- background: 'var(--sidebar-bg-color)',
21
- paddingBottom: 'env(safe-area-inset-bottom)',
22
- minHeight: '50px',
23
- justifyContent: 'space-around',
24
- alignItems: 'center',
25
- borderTop: 'var(--primary-border)',
26
- },
27
- '.footer-menu, .footer-menu a': {
28
- textDecoration: 'none',
29
- color: props.color || 'var(--primary-color)',
30
- },
31
- '.footer-menu .footer-menu-item': {
32
- padding: '4px 16px 4px 16px',
33
- fontSize: '11px',
34
- height: '55px', // 和主页保留的底部菜单高度一致
35
- width: '55px',
36
- display: 'flex',
37
- flexWrap: 'wrap',
38
- alignItems: 'center',
39
- },
40
- '.footer-menu .footer-menu-item i': {
41
- display: 'block',
42
- fontSize: '22px',
43
- marginBottom: '4px',
44
- },
45
- '.footer-menu .footer-menu-item.footer-menu-topout': {
46
- marginTop: '-43px',
47
- borderRadius: '50%',
48
- backgroundColor: props.topoutBackgroundColor || '#f33939',
49
- color: props.topoutColor || 'var(--primary-color)',
50
- },
51
- '.footer-menu .footer-menu-item-a': {
52
- zIndex: 'var(--layer-header-footer)',
53
- },
54
- '.footer-menu .footer-menu-item.active': {
55
- color: props.activeColor || 'var(--primary-accent-color)',
56
- },
57
- [MediaQueryRange.TabletBelow]: {
58
- '.footer-menu': {
59
- display: 'flex',
60
- },
61
- },
62
- };
63
- const onClick = (index: number, href: string) => {
64
- const items = document.querySelector('.footer-menu-item.active');
65
- items?.classList.remove('active');
66
- // find footer-menu-item by index
67
- const item = document.querySelector(`a:nth-child(${index + 1}) .footer-menu-item`);
68
- item?.classList.add('active');
69
- };
70
- let curretnUrl = typeof window !== 'undefined' ? window.location.pathname : '';
71
- return (
72
- <div css={css} class='footer-menu-box'>
73
- <div class='footer-menu'>
74
- {props.items.map((item, index) => (
75
- <a class='footer-menu-item-a' href={item.href} key={index}>
76
- <div
77
- class={`footer-menu-item ${item.topout ? 'footer-menu-topout' : ''} ${
78
- curretnUrl === item.href ? 'active' : ''
79
- }`}
80
- onClick={() => onClick(index, item.href)}
81
- >
82
- <i class={`ifc-icon ${item.icon}`}></i>
83
- {item.text}
84
- </div>
85
- </a>
86
- ))}
87
- {/* <div class='footer-menu-item'><a href='/'><i class="ifc-icon ma-home-outline"></i>主页</a></div>
88
- <div class='footer-menu-item'><a href='/user/tools'><i class="ifc-icon bo-multimedia-music-note"></i>工具</a></div>
89
- <div class='footer-menu-item footer-menu-topout'><a href='/user/customer'><i class="ifc-icon co-cil-chat-bubble"></i>客服</a></div>
90
- <div class='footer-menu-item'><a href='/user/member'><i class="ifc-icon ma-crown-outline"></i>会员</a></div>
91
- <div class='footer-menu-item'><a href='/user/mine'><i class="ifc-icon ma-account-cog-outline"></i>我的</a></div> */}
92
- </div>
93
- </div>
94
- );
95
- };
1
+ import { CssProps, MediaQueryRange } from 'lupine.components';
2
+ import { IconMenuItemProps } from './icon-menu-item-props';
3
+
4
+ export interface MobileFooterMenuProps {
5
+ items: IconMenuItemProps[];
6
+ color?: string;
7
+ activeColor?: string;
8
+ topoutColor?: string;
9
+ topoutBackgroundColor?: string;
10
+ }
11
+ export const MobileFooterMenu = (props: MobileFooterMenuProps) => {
12
+ const css: CssProps = {
13
+ '.footer-menu': {
14
+ display: 'none',
15
+ // position: 'fixed',
16
+ // left: 0,
17
+ // right: 0,
18
+ // bottom: 0,
19
+ width: '100%',
20
+ background: 'var(--sidebar-bg-color)',
21
+ paddingBottom: 'env(safe-area-inset-bottom)',
22
+ minHeight: '50px',
23
+ justifyContent: 'space-around',
24
+ alignItems: 'center',
25
+ borderTop: 'var(--primary-border)',
26
+ },
27
+ '.footer-menu, .footer-menu a': {
28
+ textDecoration: 'none',
29
+ color: props.color || 'var(--primary-color)',
30
+ },
31
+ '.footer-menu .footer-menu-item': {
32
+ padding: '4px 16px 4px 16px',
33
+ fontSize: '11px',
34
+ height: '55px', // 和主页保留的底部菜单高度一致
35
+ width: '55px',
36
+ display: 'flex',
37
+ flexWrap: 'wrap',
38
+ alignItems: 'center',
39
+ },
40
+ '.footer-menu .footer-menu-item i': {
41
+ display: 'block',
42
+ fontSize: '22px',
43
+ marginBottom: '4px',
44
+ },
45
+ '.footer-menu .footer-menu-item.footer-menu-topout': {
46
+ marginTop: '-43px',
47
+ borderRadius: '50%',
48
+ backgroundColor: props.topoutBackgroundColor || '#f33939',
49
+ color: props.topoutColor || 'var(--primary-color)',
50
+ },
51
+ '.footer-menu .footer-menu-item-a': {
52
+ zIndex: 'var(--layer-header-footer)',
53
+ },
54
+ '.footer-menu .footer-menu-item.active': {
55
+ color: props.activeColor || 'var(--primary-accent-color)',
56
+ },
57
+ [MediaQueryRange.TabletBelow]: {
58
+ '.footer-menu': {
59
+ display: 'flex',
60
+ },
61
+ },
62
+ };
63
+ const onClick = (index: number, href: string) => {
64
+ const items = document.querySelector('.footer-menu-item.active');
65
+ items?.classList.remove('active');
66
+ // find footer-menu-item by index
67
+ const item = document.querySelector(`a:nth-child(${index + 1}) .footer-menu-item`);
68
+ item?.classList.add('active');
69
+ };
70
+ let curretnUrl = typeof window !== 'undefined' ? window.location.pathname : '';
71
+ return (
72
+ <div css={css} class='footer-menu-box'>
73
+ <div class='footer-menu'>
74
+ {props.items.map((item, index) => (
75
+ <a class='footer-menu-item-a' href={item.href} key={index}>
76
+ <div
77
+ class={`footer-menu-item ${item.topout ? 'footer-menu-topout' : ''} ${
78
+ curretnUrl === item.href ? 'active' : ''
79
+ }`}
80
+ onClick={() => onClick(index, item.href)}
81
+ >
82
+ <i class={`ifc-icon ${item.icon}`}></i>
83
+ {item.text}
84
+ </div>
85
+ </a>
86
+ ))}
87
+ {/* <div class='footer-menu-item'><a href='/'><i class="ifc-icon ma-home-outline"></i>主页</a></div>
88
+ <div class='footer-menu-item'><a href='/user/tools'><i class="ifc-icon bo-multimedia-music-note"></i>工具</a></div>
89
+ <div class='footer-menu-item footer-menu-topout'><a href='/user/customer'><i class="ifc-icon co-cil-chat-bubble"></i>客服</a></div>
90
+ <div class='footer-menu-item'><a href='/user/member'><i class="ifc-icon ma-crown-outline"></i>会员</a></div>
91
+ <div class='footer-menu-item'><a href='/user/mine'><i class="ifc-icon ma-account-cog-outline"></i>我的</a></div> */}
92
+ </div>
93
+ </div>
94
+ );
95
+ };
@@ -1,101 +1,101 @@
1
- /*
2
- MobileHeaderComponent is the topest header for mobile, and Left, Center and Right part can be updated by other components
3
-
4
- If Left and Right are not set, then Center (100% width) can be used by temporiry headers like MobileHeaderTitleIcon,
5
- to set Left and Right icons inside Center part.
6
-
7
- For example, the header can be updated like this with different Left and Right icons:
8
- <MobileHeaderCenter>
9
- <MobileHeaderTitleIcon title='工具' left={<MobileHeaderEmptyIcon />} right={<MobileTopSysIcon />} />
10
- </MobileHeaderCenter>
11
- You can update Left, Right and Center separately, but it's convenient to use MobileHeaderCenter to set both Left and Right icons..
12
- */
13
- import { CssProps, HtmlVar, VNode } from 'lupine.components';
14
-
15
- export class MobileHeaderHelper {
16
- private static instance: MobileHeaderHelper;
17
-
18
- private leftContent = new HtmlVar('');
19
- private centerContent = new HtmlVar('');
20
- private rightContent = new HtmlVar('');
21
- private constructor() {}
22
-
23
- public static getInstance(): MobileHeaderHelper {
24
- if (!MobileHeaderHelper.instance) {
25
- MobileHeaderHelper.instance = new MobileHeaderHelper();
26
- }
27
- return MobileHeaderHelper.instance;
28
- }
29
-
30
- public setLeftContent(content: string | VNode<any>) {
31
- this.leftContent.value = content;
32
- }
33
- public getLeftContent() {
34
- return this.leftContent;
35
- }
36
- public setCenterContent(content: string | VNode<any>) {
37
- this.centerContent.value = content;
38
- }
39
- public getCenterContent() {
40
- return this.centerContent;
41
- }
42
- public setRightContent(content: string | VNode<any>) {
43
- this.rightContent.value = content;
44
- }
45
- public getRightContent() {
46
- return this.rightContent;
47
- }
48
-
49
- public hideHeader() {
50
- this.leftContent.value = '';
51
- this.centerContent.value = '';
52
- this.rightContent.value = '';
53
- }
54
- }
55
- export const mobileHeaderHelper = MobileHeaderHelper.getInstance();
56
-
57
- export const MobileHeaderLeft = (props: { children: VNode<any> }) => {
58
- mobileHeaderHelper.setLeftContent(props.children);
59
- return <></>;
60
- };
61
-
62
- export const MobileHeaderCenter = (props: { children: VNode<any> }) => {
63
- mobileHeaderHelper.setCenterContent(props.children);
64
- return <></>;
65
- };
66
-
67
- export const MobileHeaderRight = (props: { children: VNode<any> }) => {
68
- mobileHeaderHelper.setRightContent(props.children);
69
- return <></>;
70
- };
71
-
72
- export const MobileHeaderHide = () => {
73
- mobileHeaderHelper.hideHeader();
74
- return <></>;
75
- };
76
-
77
- // there should be only one MobileHeaderComponent on a page
78
- export const MobileHeaderComponent = (props: any) => {
79
- const css: CssProps = {
80
- display: 'flex',
81
- flexDirection: 'row',
82
- width: '100%',
83
- height: 'auto',
84
- // padding: '2px 0',
85
- // boxShadow: 'var(--mobile-header-shadow)', // 第二项 2px 的话,顶部有阴影(线)
86
- '& > *': {
87
- height: '100%',
88
- },
89
- '.mobile-header-center': {
90
- flex: 1,
91
- },
92
- };
93
-
94
- return (
95
- <div css={css} class='mobile-header-component'>
96
- <div class='mobile-header-left'>{mobileHeaderHelper.getLeftContent().node}</div>
97
- <div class='mobile-header-center'>{mobileHeaderHelper.getCenterContent().node}</div>
98
- <div class='mobile-header-right'>{mobileHeaderHelper.getRightContent().node}</div>
99
- </div>
100
- );
101
- };
1
+ /*
2
+ MobileHeaderComponent is the topest header for mobile, and Left, Center and Right part can be updated by other components
3
+
4
+ If Left and Right are not set, then Center (100% width) can be used by temporiry headers like MobileHeaderTitleIcon,
5
+ to set Left and Right icons inside Center part.
6
+
7
+ For example, the header can be updated like this with different Left and Right icons:
8
+ <MobileHeaderCenter>
9
+ <MobileHeaderTitleIcon title='工具' left={<MobileHeaderEmptyIcon />} right={<MobileTopSysIcon />} />
10
+ </MobileHeaderCenter>
11
+ You can update Left, Right and Center separately, but it's convenient to use MobileHeaderCenter to set both Left and Right icons..
12
+ */
13
+ import { CssProps, HtmlVar, VNode } from 'lupine.components';
14
+
15
+ export class MobileHeaderHelper {
16
+ private static instance: MobileHeaderHelper;
17
+
18
+ private leftContent = new HtmlVar('');
19
+ private centerContent = new HtmlVar('');
20
+ private rightContent = new HtmlVar('');
21
+ private constructor() {}
22
+
23
+ public static getInstance(): MobileHeaderHelper {
24
+ if (!MobileHeaderHelper.instance) {
25
+ MobileHeaderHelper.instance = new MobileHeaderHelper();
26
+ }
27
+ return MobileHeaderHelper.instance;
28
+ }
29
+
30
+ public setLeftContent(content: string | VNode<any>) {
31
+ this.leftContent.value = content;
32
+ }
33
+ public getLeftContent() {
34
+ return this.leftContent;
35
+ }
36
+ public setCenterContent(content: string | VNode<any>) {
37
+ this.centerContent.value = content;
38
+ }
39
+ public getCenterContent() {
40
+ return this.centerContent;
41
+ }
42
+ public setRightContent(content: string | VNode<any>) {
43
+ this.rightContent.value = content;
44
+ }
45
+ public getRightContent() {
46
+ return this.rightContent;
47
+ }
48
+
49
+ public hideHeader() {
50
+ this.leftContent.value = '';
51
+ this.centerContent.value = '';
52
+ this.rightContent.value = '';
53
+ }
54
+ }
55
+ export const mobileHeaderHelper = MobileHeaderHelper.getInstance();
56
+
57
+ export const MobileHeaderLeft = (props: { children: VNode<any> }) => {
58
+ mobileHeaderHelper.setLeftContent(props.children);
59
+ return <></>;
60
+ };
61
+
62
+ export const MobileHeaderCenter = (props: { children: VNode<any> }) => {
63
+ mobileHeaderHelper.setCenterContent(props.children);
64
+ return <></>;
65
+ };
66
+
67
+ export const MobileHeaderRight = (props: { children: VNode<any> }) => {
68
+ mobileHeaderHelper.setRightContent(props.children);
69
+ return <></>;
70
+ };
71
+
72
+ export const MobileHeaderHide = () => {
73
+ mobileHeaderHelper.hideHeader();
74
+ return <></>;
75
+ };
76
+
77
+ // there should be only one MobileHeaderComponent on a page
78
+ export const MobileHeaderComponent = (props: any) => {
79
+ const css: CssProps = {
80
+ display: 'flex',
81
+ flexDirection: 'row',
82
+ width: '100%',
83
+ height: 'auto',
84
+ // padding: '2px 0',
85
+ // boxShadow: 'var(--mobile-header-shadow)', // 第二项 2px 的话,顶部有阴影(线)
86
+ '& > *': {
87
+ height: '100%',
88
+ },
89
+ '.mobile-header-center': {
90
+ flex: 1,
91
+ },
92
+ };
93
+
94
+ return (
95
+ <div css={css} class='mobile-header-component'>
96
+ <div class='mobile-header-left'>{mobileHeaderHelper.getLeftContent().node}</div>
97
+ <div class='mobile-header-center'>{mobileHeaderHelper.getCenterContent().node}</div>
98
+ <div class='mobile-header-right'>{mobileHeaderHelper.getRightContent().node}</div>
99
+ </div>
100
+ );
101
+ };