lupine.web 1.0.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/LICENSE +21 -0
- package/README.md +3 -0
- package/jsx-runtime/index.js +14 -0
- package/jsx-runtime/package.json +16 -0
- package/jsx-runtime/src/index.d.ts +2 -0
- package/package.json +51 -0
- package/src/assets/themes/base-themes.ts +16 -0
- package/src/assets/themes/dark-themes.ts +85 -0
- package/src/assets/themes/index.ts +4 -0
- package/src/assets/themes/light-themes.ts +92 -0
- package/src/assets/themes/shared-themes.ts +50 -0
- package/src/components/button-push-animation.tsx +138 -0
- package/src/components/button.tsx +55 -0
- package/src/components/drag-refresh.tsx +110 -0
- package/src/components/editable-label.tsx +83 -0
- package/src/components/float-window.tsx +226 -0
- package/src/components/grid.tsx +18 -0
- package/src/components/html-var.tsx +41 -0
- package/src/components/index.ts +36 -0
- package/src/components/input-with-title.tsx +24 -0
- package/src/components/link-item.tsx +13 -0
- package/src/components/link-list.tsx +62 -0
- package/src/components/menu-bar.tsx +220 -0
- package/src/components/menu-item-props.tsx +10 -0
- package/src/components/menu-sidebar.tsx +289 -0
- package/src/components/message-box.tsx +44 -0
- package/src/components/meta-data.tsx +54 -0
- package/src/components/meta-description.tsx +19 -0
- package/src/components/meta-title.tsx +19 -0
- package/src/components/modal.tsx +29 -0
- package/src/components/notice-message.tsx +119 -0
- package/src/components/paging-link.tsx +100 -0
- package/src/components/panel.tsx +24 -0
- package/src/components/popup-menu.tsx +218 -0
- package/src/components/progress.tsx +91 -0
- package/src/components/redirect.tsx +19 -0
- package/src/components/resizable-splitter.tsx +129 -0
- package/src/components/select-with-title.tsx +37 -0
- package/src/components/spinner.tsx +100 -0
- package/src/components/svg.tsx +24 -0
- package/src/components/tabs.tsx +252 -0
- package/src/components/text-glow.tsx +36 -0
- package/src/components/text-wave.tsx +54 -0
- package/src/components/theme-selector.tsx +35 -0
- package/src/components/toggle-base.tsx +260 -0
- package/src/components/toggle-switch.tsx +156 -0
- package/src/core/bind-attributes.ts +58 -0
- package/src/core/bind-lang.ts +51 -0
- package/src/core/bind-links.ts +16 -0
- package/src/core/bind-ref.ts +33 -0
- package/src/core/bind-styles.ts +180 -0
- package/src/core/bind-theme.ts +51 -0
- package/src/core/camel-to-hyphens.ts +3 -0
- package/src/core/core.ts +179 -0
- package/src/core/index.ts +15 -0
- package/src/core/mount-components.ts +259 -0
- package/src/core/page-loaded-events.ts +16 -0
- package/src/core/page-router.ts +170 -0
- package/src/core/replace-innerhtml.ts +10 -0
- package/src/core/server-cookie.ts +22 -0
- package/src/core/web-version.ts +12 -0
- package/src/global.d.ts +66 -0
- package/src/index.ts +15 -0
- package/src/jsx.ts +1041 -0
- package/src/lib/date-utils.ts +317 -0
- package/src/lib/debug-watch.ts +31 -0
- package/src/lib/deep-merge.ts +37 -0
- package/src/lib/document-ready.ts +36 -0
- package/src/lib/dom/calculate-text-width.ts +13 -0
- package/src/lib/dom/cookie.ts +41 -0
- package/src/lib/dom/download-stream.ts +17 -0
- package/src/lib/dom/download.ts +12 -0
- package/src/lib/dom/index.ts +71 -0
- package/src/lib/dynamical-load.ts +138 -0
- package/src/lib/format-bytes.ts +11 -0
- package/src/lib/index.ts +17 -0
- package/src/lib/lite-dom.ts +227 -0
- package/src/lib/logger.ts +55 -0
- package/src/lib/message-hub.ts +105 -0
- package/src/lib/observable.ts +188 -0
- package/src/lib/promise-timeout.ts +1 -0
- package/src/lib/simple-storage.ts +40 -0
- package/src/lib/stop-propagation.ts +7 -0
- package/src/lib/unique-id.ts +39 -0
- package/src/lib/upload-file.ts +68 -0
- package/src/lib/web-env.ts +98 -0
- package/src/models/index.ts +2 -0
- package/src/models/simple-storage-props.ts +9 -0
- package/src/models/to-client-delivery-props.ts +8 -0
- package/src/types/css-styles.ts +814 -0
- package/src/types/css-types.ts +17 -0
- package/src/types/index.ts +6 -0
- package/src/types/media-query.ts +93 -0
- package/tsconfig.json +113 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { bindGlobalStyles } from '../core';
|
|
2
|
+
import { CssProps } from '../jsx';
|
|
3
|
+
/**
|
|
4
|
+
How to use:
|
|
5
|
+
Notification.sendMessage(message);
|
|
6
|
+
*/
|
|
7
|
+
export enum NotificationColor {
|
|
8
|
+
Success = 'var(--success-bg-color)',
|
|
9
|
+
Info = 'var(--info-bg-color)',
|
|
10
|
+
Warning = 'var(--warning-bg-color)',
|
|
11
|
+
Error = 'var(--error-bg-color)',
|
|
12
|
+
}
|
|
13
|
+
export const notificationColorFromValue = (value: string) => {
|
|
14
|
+
switch (value) {
|
|
15
|
+
case 'Success':
|
|
16
|
+
return NotificationColor.Success;
|
|
17
|
+
case 'Info':
|
|
18
|
+
return NotificationColor.Info;
|
|
19
|
+
case 'Warning':
|
|
20
|
+
return NotificationColor.Warning;
|
|
21
|
+
case 'Error':
|
|
22
|
+
return NotificationColor.Error;
|
|
23
|
+
}
|
|
24
|
+
return NotificationColor.Info;
|
|
25
|
+
};
|
|
26
|
+
export class NotificationMessage {
|
|
27
|
+
// public static readonly Color = NotificationColor;
|
|
28
|
+
|
|
29
|
+
private static initialized = false;
|
|
30
|
+
private static container: HTMLElement;
|
|
31
|
+
|
|
32
|
+
static init() {
|
|
33
|
+
/* styles for resizable splitter */
|
|
34
|
+
const css: CssProps = {
|
|
35
|
+
position: 'fixed',
|
|
36
|
+
top: 0,
|
|
37
|
+
right: 0,
|
|
38
|
+
height: 'auto',
|
|
39
|
+
overflowY: 'auto',
|
|
40
|
+
maxHeight: '100%',
|
|
41
|
+
width: '100%',
|
|
42
|
+
maxWidth: '400px',
|
|
43
|
+
// cursor: 'pointer',
|
|
44
|
+
// backgroundColor: '#fefefe',
|
|
45
|
+
padding: '0 10px',
|
|
46
|
+
zIndex: 'var(--layer-notice)',
|
|
47
|
+
// borderRadius: '6px',
|
|
48
|
+
// boxShadow: '0px 0px 2px #000',
|
|
49
|
+
'>div': {
|
|
50
|
+
color: 'var(--notice-color-with-bg)',
|
|
51
|
+
padding: '10px 8px',
|
|
52
|
+
margin: '16px 0',
|
|
53
|
+
borderRadius: '6px',
|
|
54
|
+
boxShadow: 'var(--cover-box-shadow)', //'3px 3px 8px #767676',
|
|
55
|
+
transition: 'all 0.5s',
|
|
56
|
+
transform: 'scale(0.1)',
|
|
57
|
+
opacity: 0,
|
|
58
|
+
},
|
|
59
|
+
'.close-btn': {
|
|
60
|
+
position: 'absolute',
|
|
61
|
+
top: '-2px',
|
|
62
|
+
right: '3px',
|
|
63
|
+
color: 'var(--notice-color-with-bg)',
|
|
64
|
+
fontWeight: 'bold',
|
|
65
|
+
fontSize: '22px',
|
|
66
|
+
lineHeight: '20px',
|
|
67
|
+
cursor: 'pointer',
|
|
68
|
+
transition: '0.3s',
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
'.close-btn:hover': {
|
|
72
|
+
color: 'black',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
bindGlobalStyles('lj_notification', '.lj_notification', css);
|
|
76
|
+
|
|
77
|
+
let container = document.querySelector('.lj_notification');
|
|
78
|
+
if (!container) {
|
|
79
|
+
container = document.createElement('div');
|
|
80
|
+
container.className = 'lj_notification';
|
|
81
|
+
document.body.appendChild(container);
|
|
82
|
+
this.container = container as HTMLElement;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static sendMessage(message: string, backgroundColor = NotificationColor.Info, permanent = false, showTime = 3000) {
|
|
87
|
+
if (!this.initialized) {
|
|
88
|
+
this.initialized = true;
|
|
89
|
+
this.init();
|
|
90
|
+
}
|
|
91
|
+
this.container.scrollTop = 0;
|
|
92
|
+
const div = document.createElement('div');
|
|
93
|
+
div.innerHTML = message;
|
|
94
|
+
div.style.backgroundColor = backgroundColor;
|
|
95
|
+
this.container.insertBefore(div, this.container.firstChild);
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
div.style.opacity = '1';
|
|
98
|
+
div.style.transform = 'scale(1)';
|
|
99
|
+
}, 0);
|
|
100
|
+
|
|
101
|
+
if (permanent) {
|
|
102
|
+
const closeBtn = document.createElement('span');
|
|
103
|
+
closeBtn.innerHTML = '×';
|
|
104
|
+
closeBtn.className = 'close-btn';
|
|
105
|
+
div.appendChild(closeBtn);
|
|
106
|
+
closeBtn.onclick = () => {
|
|
107
|
+
this.container.removeChild(div);
|
|
108
|
+
};
|
|
109
|
+
} else {
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
div.style.opacity = '0';
|
|
112
|
+
div.style.transform = 'scale(0.1)';
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
this.container.removeChild(div);
|
|
115
|
+
}, 1000);
|
|
116
|
+
}, showTime);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { CssProps } from '../jsx';
|
|
2
|
+
import { bindGlobalStyles, getRenderPageProps } from '../core';
|
|
3
|
+
|
|
4
|
+
let _DEFAULT_PAGE_LIMIT = 7;
|
|
5
|
+
export const getDefaultPageLimit = () => {
|
|
6
|
+
return _DEFAULT_PAGE_LIMIT;
|
|
7
|
+
};
|
|
8
|
+
export const setDefaultPageLimit = (limit: number) => {
|
|
9
|
+
_DEFAULT_PAGE_LIMIT = limit;
|
|
10
|
+
};
|
|
11
|
+
export type PagingLinkProps = {
|
|
12
|
+
itemsCount: number;
|
|
13
|
+
pageLimit?: number;
|
|
14
|
+
pageIndex?: number;
|
|
15
|
+
baseLink: string;
|
|
16
|
+
onClick?: (index: number) => void; // if onClick is set then use it instead of href
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const PagingLink = (props: PagingLinkProps) => {
|
|
20
|
+
const css: CssProps = {
|
|
21
|
+
textAlign: 'right',
|
|
22
|
+
paddingRight: '16px',
|
|
23
|
+
'.paging-link-index': {
|
|
24
|
+
padding: '0px 4px',
|
|
25
|
+
},
|
|
26
|
+
a: {
|
|
27
|
+
textDecoration: 'none',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
bindGlobalStyles('paging-link-box', '.paging-link-box', css);
|
|
32
|
+
const html = [];
|
|
33
|
+
let pageIndex = props.pageIndex ?? (Number.parseInt(getRenderPageProps().query['pg_i'] || '') || 0);
|
|
34
|
+
const pageLimit = props.pageLimit || _DEFAULT_PAGE_LIMIT;
|
|
35
|
+
if (props.itemsCount > 0 && pageLimit > 0) {
|
|
36
|
+
let maxPages = Math.floor(props.itemsCount / pageLimit);
|
|
37
|
+
if (props.itemsCount % pageLimit !== 0) {
|
|
38
|
+
maxPages++;
|
|
39
|
+
}
|
|
40
|
+
if (pageIndex > maxPages) {
|
|
41
|
+
pageIndex = maxPages - 1;
|
|
42
|
+
}
|
|
43
|
+
if (pageIndex > 0) {
|
|
44
|
+
html.push(
|
|
45
|
+
<span class='paging-link-go'>
|
|
46
|
+
<a
|
|
47
|
+
href={props.onClick ? 'javascript:void(0)' : props.baseLink + '?pg_i=' + (pageIndex - 1)}
|
|
48
|
+
onClick={() => props.onClick && props.onClick(pageIndex - 1)}
|
|
49
|
+
>
|
|
50
|
+
<
|
|
51
|
+
</a>
|
|
52
|
+
</span>
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
html.push(<span class='paging-link-go disabled'><</span>);
|
|
56
|
+
}
|
|
57
|
+
for (let i = 0; i < maxPages; i++) {
|
|
58
|
+
if (i < 2 || i >= maxPages - 2 || (i > pageIndex - 3 && i < pageIndex + 3)) {
|
|
59
|
+
if (i == pageIndex) {
|
|
60
|
+
html.push(
|
|
61
|
+
<span class='paging-link-index current'>
|
|
62
|
+
<b>{'' + (i + 1)}</b>
|
|
63
|
+
</span>
|
|
64
|
+
);
|
|
65
|
+
} else {
|
|
66
|
+
html.push(
|
|
67
|
+
<span class='paging-link-index'>
|
|
68
|
+
<a
|
|
69
|
+
href={props.onClick ? 'javascript:void(0)' : props.baseLink + '?pg_i=' + i}
|
|
70
|
+
onClick={() => props.onClick && props.onClick(i)}
|
|
71
|
+
>
|
|
72
|
+
{'' + (i + 1)}
|
|
73
|
+
</a>
|
|
74
|
+
</span>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
if (i == pageIndex - 4 || i == pageIndex + 4) {
|
|
79
|
+
html.push(<span class='paging-link-skip'>...</span>);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (pageIndex < maxPages - 1) {
|
|
84
|
+
html.push(
|
|
85
|
+
<span class='paging-link-go'>
|
|
86
|
+
<a
|
|
87
|
+
href={props.onClick ? 'javascript:void(0)' : props.baseLink + '?pg_i=' + (pageIndex + 1)}
|
|
88
|
+
onClick={() => props.onClick && props.onClick(pageIndex + 1)}
|
|
89
|
+
>
|
|
90
|
+
>
|
|
91
|
+
</a>
|
|
92
|
+
</span>
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
html.push(<span class='paging-link-go disabled'>></span>);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return html.length > 0 ? <div class='paging-link-box'>{html}</div> : <></>;
|
|
100
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CssProps, JSXInternal } from '../jsx';
|
|
2
|
+
import { ContentPosition, Position } from '../types';
|
|
3
|
+
|
|
4
|
+
export type PanelProps = {
|
|
5
|
+
children: any;
|
|
6
|
+
className?: string;
|
|
7
|
+
contentPosition?: ContentPosition;
|
|
8
|
+
css?: CssProps;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const Panel = ({ children, className, css }: PanelProps) => {
|
|
12
|
+
const newCss: CssProps = {
|
|
13
|
+
display: 'flex',
|
|
14
|
+
flexDirection: 'column',
|
|
15
|
+
// justifyContent: ContentPosition.center,
|
|
16
|
+
...css,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div css={newCss} class={['panel-box', className].join(' ')}>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { RefProps, stopPropagation } from 'lupine.js';
|
|
2
|
+
|
|
3
|
+
export type PopupMenuOpenMenuProps = { handle?: Function };
|
|
4
|
+
|
|
5
|
+
export type PopupMenuProps = {
|
|
6
|
+
list: string[];
|
|
7
|
+
defaultValue: string;
|
|
8
|
+
tips?: string;
|
|
9
|
+
minWidth?: string;
|
|
10
|
+
maxWidth?: string;
|
|
11
|
+
maxHeight?: string;
|
|
12
|
+
handleSelected?: Function;
|
|
13
|
+
handleOpened?: Function;
|
|
14
|
+
handleClosed?: Function;
|
|
15
|
+
noUpdateValue?: boolean;
|
|
16
|
+
refOpenMenu?: PopupMenuOpenMenuProps;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type PopupMenuWithButtonProps = { label: string } & PopupMenuProps;
|
|
20
|
+
|
|
21
|
+
export const PopupMenuWithButton = (props: PopupMenuWithButtonProps) => {
|
|
22
|
+
const handle: PopupMenuOpenMenuProps = {};
|
|
23
|
+
return (
|
|
24
|
+
<button
|
|
25
|
+
class='button-base'
|
|
26
|
+
onClick={() => {
|
|
27
|
+
handle.handle && handle.handle();
|
|
28
|
+
}}
|
|
29
|
+
css={{ '>div': { float: 'right', textAlign: 'left' } }}
|
|
30
|
+
>
|
|
31
|
+
{props.label}:{' '}
|
|
32
|
+
<PopupMenu
|
|
33
|
+
list={props.list}
|
|
34
|
+
defaultValue={props.defaultValue}
|
|
35
|
+
tips={props.tips}
|
|
36
|
+
minWidth={props.minWidth}
|
|
37
|
+
maxWidth={props.maxWidth}
|
|
38
|
+
maxHeight={props.maxHeight}
|
|
39
|
+
handleSelected={props.handleSelected}
|
|
40
|
+
handleOpened={props.handleOpened}
|
|
41
|
+
handleClosed={props.handleClosed}
|
|
42
|
+
noUpdateValue={props.noUpdateValue}
|
|
43
|
+
refOpenMenu={handle}
|
|
44
|
+
></PopupMenu>
|
|
45
|
+
</button>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type PopupMenuWithLabelProps = { label: string } & PopupMenuProps;
|
|
50
|
+
|
|
51
|
+
export const PopupMenuWithLabel = (props: PopupMenuWithLabelProps) => {
|
|
52
|
+
const handle: PopupMenuOpenMenuProps = {};
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
onClick={() => {
|
|
56
|
+
handle.handle && handle.handle();
|
|
57
|
+
}}
|
|
58
|
+
css={{ cursor: 'pointer', '>div': { float: 'right', textAlign: 'left' } }}
|
|
59
|
+
>
|
|
60
|
+
{props.label}:{' '}
|
|
61
|
+
<PopupMenu
|
|
62
|
+
list={props.list}
|
|
63
|
+
defaultValue={props.defaultValue}
|
|
64
|
+
tips={props.tips}
|
|
65
|
+
minWidth={props.minWidth}
|
|
66
|
+
maxWidth={props.maxWidth}
|
|
67
|
+
maxHeight={props.maxHeight}
|
|
68
|
+
handleSelected={props.handleSelected}
|
|
69
|
+
handleOpened={props.handleOpened}
|
|
70
|
+
handleClosed={props.handleClosed}
|
|
71
|
+
noUpdateValue={props.noUpdateValue}
|
|
72
|
+
refOpenMenu={handle}
|
|
73
|
+
></PopupMenu>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const PopupMenu = ({
|
|
79
|
+
list,
|
|
80
|
+
defaultValue,
|
|
81
|
+
tips = '',
|
|
82
|
+
minWidth,
|
|
83
|
+
maxWidth,
|
|
84
|
+
maxHeight,
|
|
85
|
+
handleSelected,
|
|
86
|
+
handleOpened,
|
|
87
|
+
handleClosed,
|
|
88
|
+
noUpdateValue,
|
|
89
|
+
refOpenMenu,
|
|
90
|
+
}: PopupMenuProps) => {
|
|
91
|
+
const css: any = {
|
|
92
|
+
'.popup-menu-item': {
|
|
93
|
+
padding: '0 0 1px 0',
|
|
94
|
+
display: 'inline-block',
|
|
95
|
+
position: 'relative',
|
|
96
|
+
'.popup-menu-text': {
|
|
97
|
+
display: 'inline-block',
|
|
98
|
+
cursor: 'pointer',
|
|
99
|
+
whiteSpace: 'nowrap',
|
|
100
|
+
marginRight: '15px',
|
|
101
|
+
},
|
|
102
|
+
// cover-box-shadow
|
|
103
|
+
'.popup-menu-text::after': {
|
|
104
|
+
content: '""',
|
|
105
|
+
position: 'absolute',
|
|
106
|
+
top: '50%',
|
|
107
|
+
transform: 'translateY(-50%)',
|
|
108
|
+
marginLeft: '3px',
|
|
109
|
+
width: 0,
|
|
110
|
+
height: 0,
|
|
111
|
+
borderLeft: '5px solid transparent',
|
|
112
|
+
borderRight: '5px solid transparent',
|
|
113
|
+
borderTop: '5px solid var(--primary-color)',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
'.popup-menu-item:hover': {
|
|
117
|
+
padding: '1px 0 0 0',
|
|
118
|
+
},
|
|
119
|
+
'.popup-menu-bottom': {
|
|
120
|
+
position: 'relative',
|
|
121
|
+
height: '1px',
|
|
122
|
+
'.popup-menu-list': {
|
|
123
|
+
display: 'none',
|
|
124
|
+
position: 'absolute',
|
|
125
|
+
fontSize: 'var(--menu-font-size)',
|
|
126
|
+
top: 0,
|
|
127
|
+
left: '2px',
|
|
128
|
+
color: 'var(--activatable-color-normal)',
|
|
129
|
+
backgroundColor: 'var(--activatable-bg-color-normal)',
|
|
130
|
+
zIndex: 'var(--layer-menu)',
|
|
131
|
+
borderRadius: '4px',
|
|
132
|
+
border: '1px solid #ddd',
|
|
133
|
+
padding: '5px 0px',
|
|
134
|
+
overflow: 'auto',
|
|
135
|
+
'line-height': '1.2em',
|
|
136
|
+
'min-width': minWidth || 'auto',
|
|
137
|
+
'max-width': maxWidth || '200px',
|
|
138
|
+
'max-height': maxHeight || '300px',
|
|
139
|
+
'box-shadow': 'var(--cover-box-shadow)', //'#0000004c 0px 19px 38px, #00000038 0px 15px 12px',
|
|
140
|
+
'.menu-focus': {
|
|
141
|
+
position: 'absolute',
|
|
142
|
+
height: '0px',
|
|
143
|
+
},
|
|
144
|
+
'.item': {
|
|
145
|
+
padding: '2px 12px',
|
|
146
|
+
},
|
|
147
|
+
'.item:hover': {
|
|
148
|
+
padding: '2px 11px 2px 13px',
|
|
149
|
+
color: 'var(--activatable-color-hover)',
|
|
150
|
+
backgroundColor: 'var(--activatable-bg-color-hover)',
|
|
151
|
+
cursor: 'pointer',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
let ref: RefProps = { id: '' };
|
|
158
|
+
let isShowing = false;
|
|
159
|
+
const handleClick = (event: any) => {
|
|
160
|
+
stopPropagation(event);
|
|
161
|
+
|
|
162
|
+
handleOpened && handleOpened();
|
|
163
|
+
// console.log('=======22', event);
|
|
164
|
+
isShowing = !isShowing;
|
|
165
|
+
ref.$('.popup-menu-list').style.display = isShowing ? 'inline-block' : 'none';
|
|
166
|
+
ref.$('.popup-menu-list .menu-focus').focus();
|
|
167
|
+
};
|
|
168
|
+
if (refOpenMenu) {
|
|
169
|
+
refOpenMenu.handle = handleClick;
|
|
170
|
+
}
|
|
171
|
+
const itemClick = (event: any) => {
|
|
172
|
+
stopPropagation(event);
|
|
173
|
+
|
|
174
|
+
// console.log('=======', event);
|
|
175
|
+
isShowing = false;
|
|
176
|
+
ref.$('.popup-menu-list').style.display = 'none';
|
|
177
|
+
if (event.target) {
|
|
178
|
+
if (noUpdateValue !== true) {
|
|
179
|
+
ref.$('.popup-menu-item .popup-menu-text').innerText = event.target.innerText;
|
|
180
|
+
}
|
|
181
|
+
if (handleSelected) {
|
|
182
|
+
handleSelected(event.target.innerText);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
handleClosed && handleClosed();
|
|
186
|
+
};
|
|
187
|
+
const onBlur = (event: any) => {
|
|
188
|
+
setTimeout(() => {
|
|
189
|
+
ref.$('.popup-menu-list').style.display = 'none';
|
|
190
|
+
isShowing && handleClosed && handleClosed();
|
|
191
|
+
isShowing = false;
|
|
192
|
+
}, 300);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div ref={ref} css={css} onClick={handleClick} title={tips}>
|
|
197
|
+
<div class='popup-menu-item'>
|
|
198
|
+
<span class='popup-menu-text'>{defaultValue || ' '}</span>
|
|
199
|
+
</div>
|
|
200
|
+
<div class='popup-menu-bottom'>
|
|
201
|
+
<div class='popup-menu-list'>
|
|
202
|
+
<div>
|
|
203
|
+
{list.map((item) => {
|
|
204
|
+
return item === '' ? (
|
|
205
|
+
<hr />
|
|
206
|
+
) : (
|
|
207
|
+
<div class='item' onClick={itemClick}>
|
|
208
|
+
{item}
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
})}
|
|
212
|
+
</div>
|
|
213
|
+
<div class='menu-focus' onBlur={onBlur} tabIndex={0}></div>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
218
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { RefProps } from '../jsx';
|
|
2
|
+
import { HtmlVar } from './html-var';
|
|
3
|
+
|
|
4
|
+
export type ProgressHookProps = {
|
|
5
|
+
onProgress?: (percentage: number, chunkNumber: number, totalChunks: number) => void;
|
|
6
|
+
onShow?: (show: boolean, title?: string) => void;
|
|
7
|
+
};
|
|
8
|
+
export type ProgressProps = {
|
|
9
|
+
hook: ProgressHookProps;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const Progress = (props: ProgressProps) => {
|
|
13
|
+
const css: any = {
|
|
14
|
+
position: 'fixed',
|
|
15
|
+
display: 'flex',
|
|
16
|
+
bottom: '0',
|
|
17
|
+
left: '0',
|
|
18
|
+
width: '100%',
|
|
19
|
+
zIndex: 'var(--layer-modal-over)',
|
|
20
|
+
flexDirection: 'column',
|
|
21
|
+
backgroundColor: '#e6e6e6de',
|
|
22
|
+
padding: '16px',
|
|
23
|
+
'.progress-box': {
|
|
24
|
+
display: 'flex',
|
|
25
|
+
flexDirection: 'column',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
justifyContent: 'center',
|
|
28
|
+
width: '100%',
|
|
29
|
+
height: 'auto',
|
|
30
|
+
margin: 'auto',
|
|
31
|
+
},
|
|
32
|
+
'.progress-bar': {
|
|
33
|
+
display: 'flex',
|
|
34
|
+
width: '100%',
|
|
35
|
+
height: '60px',
|
|
36
|
+
borderRadius: '4px',
|
|
37
|
+
overflow: 'hidden',
|
|
38
|
+
},
|
|
39
|
+
'.progress-bar1': {
|
|
40
|
+
height: '100%',
|
|
41
|
+
width: '0%',
|
|
42
|
+
backgroundColor: '#49e57e',
|
|
43
|
+
},
|
|
44
|
+
'.progress-bar2': {
|
|
45
|
+
height: '100%',
|
|
46
|
+
width: '100%',
|
|
47
|
+
backgroundColor: '#2bb8cd',
|
|
48
|
+
},
|
|
49
|
+
'.progress-tips': {
|
|
50
|
+
marginTop: '10px',
|
|
51
|
+
fontSize: '30px',
|
|
52
|
+
color: '#49e57e',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
props.hook.onProgress = (percentage: number, chunkNumber: number, totalChunks: number) => {
|
|
57
|
+
// console.log(`Upload progress: ${percentage}% (chunk ${chunkNumber} of ${totalChunks})`);
|
|
58
|
+
percentage = Math.round(percentage * 100);
|
|
59
|
+
const bar1 = document.querySelector('.progress-bar1') as HTMLElement;
|
|
60
|
+
const bar2 = document.querySelector('.progress-bar2') as HTMLElement;
|
|
61
|
+
bar1.style.width = `${percentage}%`;
|
|
62
|
+
bar2.style.width = `${1 - percentage}%`;
|
|
63
|
+
dom.value = `${percentage}%`;
|
|
64
|
+
};
|
|
65
|
+
props.hook.onShow = (show: boolean, title?: string) => {
|
|
66
|
+
if (title) {
|
|
67
|
+
domTitle.value = title;
|
|
68
|
+
}
|
|
69
|
+
if (show) {
|
|
70
|
+
ref.current?.classList.remove('d-none');
|
|
71
|
+
} else {
|
|
72
|
+
ref.current?.classList.add('d-none');
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const ref: RefProps = {};
|
|
77
|
+
const domTitle = HtmlVar('Progress');
|
|
78
|
+
const dom = HtmlVar('0 %');
|
|
79
|
+
return (
|
|
80
|
+
<div ref={ref} css={css} class='progress-top d-none'>
|
|
81
|
+
<div class='progress-box'>
|
|
82
|
+
<div class='progress-title mb-m align-left w-100p'>{domTitle.node}</div>
|
|
83
|
+
<div class='progress-bar'>
|
|
84
|
+
<div class='progress-bar1'></div>
|
|
85
|
+
<div class='progress-bar2'></div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class='progress-tips'>{dom.node}</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RefProps } from '../jsx';
|
|
2
|
+
|
|
3
|
+
export type RedirectProps = {
|
|
4
|
+
title?: string;
|
|
5
|
+
url: string;
|
|
6
|
+
delaySeconds?: number;
|
|
7
|
+
};
|
|
8
|
+
export const Redirect = ({ title = 'redirect...', url, delaySeconds = 0 }: RedirectProps) => {
|
|
9
|
+
// if SSR is disabled, then MetaData will not be working
|
|
10
|
+
// MetaData({ httpEquiv: 'refresh', content: delaySeconds + ';URL=' + url });
|
|
11
|
+
const ref: RefProps = {
|
|
12
|
+
onLoad: async (el: Element) => {
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
window.location.href = url;
|
|
15
|
+
}, delaySeconds * 1000);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
return <div ref={ref}>{title}</div>;
|
|
19
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { bindGlobalStyles } from '../core';
|
|
2
|
+
import { CssProps } from '../jsx';
|
|
3
|
+
import { stopPropagation } from '../lib';
|
|
4
|
+
/**
|
|
5
|
+
How to use:
|
|
6
|
+
// getSplitter's first parameter is the container's selector where the Splitter will be in.
|
|
7
|
+
// the second parameter is whether it's Vertical
|
|
8
|
+
// then the third parameter is it's RightOrTop or not
|
|
9
|
+
const locationLeft = false;
|
|
10
|
+
const splitter = ResizableSplitter.getSplitter('.body .side', true, locationLeft);
|
|
11
|
+
const container = (
|
|
12
|
+
<div class='body'>
|
|
13
|
+
<div class='side'>
|
|
14
|
+
{splitter}
|
|
15
|
+
{designPanel}
|
|
16
|
+
</div>
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
*/
|
|
20
|
+
export class ResizableSplitter {
|
|
21
|
+
static hostNode: HTMLElement;
|
|
22
|
+
static isVertical = true;
|
|
23
|
+
static isRightOrTop = true;
|
|
24
|
+
|
|
25
|
+
private static initialized = false;
|
|
26
|
+
private static startXorY = 0;
|
|
27
|
+
private static startWidthOrHeight = 0;
|
|
28
|
+
private static pressed = false;
|
|
29
|
+
|
|
30
|
+
static init() {
|
|
31
|
+
/* styles for resizable splitter */
|
|
32
|
+
const css: CssProps = {
|
|
33
|
+
'.resizable-splitter-v-left, .resizable-splitter-v-right': {
|
|
34
|
+
position: 'absolute',
|
|
35
|
+
top: 0,
|
|
36
|
+
bottom: 0,
|
|
37
|
+
left: 0,
|
|
38
|
+
width: '2px',
|
|
39
|
+
cursor: 'col-resize',
|
|
40
|
+
},
|
|
41
|
+
'.resizable-splitter-v-right': {
|
|
42
|
+
left: 'unset',
|
|
43
|
+
right: 0,
|
|
44
|
+
},
|
|
45
|
+
'.resizable-splitter-v-left:hover, .resizable-splitter-v-right:hover': {
|
|
46
|
+
width: '4px',
|
|
47
|
+
backgroundColor: '#ccc',
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
'.resizable-splitter-h-top, .resizable-splitter-h-bottom': {
|
|
51
|
+
position: 'absolute',
|
|
52
|
+
top: 0,
|
|
53
|
+
left: 0,
|
|
54
|
+
right: 0,
|
|
55
|
+
height: '2px',
|
|
56
|
+
cursor: 'row-resize',
|
|
57
|
+
},
|
|
58
|
+
'.resizable-splitter-h-bottom': {
|
|
59
|
+
top: 'unset',
|
|
60
|
+
bottom: 0,
|
|
61
|
+
},
|
|
62
|
+
'.resizable-splitter-h-top:hover, .resizable-splitter-h-bottom:hover': {
|
|
63
|
+
height: '4px',
|
|
64
|
+
backgroundColor: '#ccc',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
bindGlobalStyles('resizable-splitter', 'html', css);
|
|
68
|
+
|
|
69
|
+
window.addEventListener('mousemove', ResizableSplitter.onMousemove.bind(ResizableSplitter), false);
|
|
70
|
+
document.documentElement.addEventListener('mouseup', ResizableSplitter.onMouseup.bind(ResizableSplitter), false);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static getSplitterClassName(isVertical: boolean, isRightOrTop: boolean): string {
|
|
74
|
+
const className =
|
|
75
|
+
'resizable-splitter-' +
|
|
76
|
+
(isVertical ? (isRightOrTop ? 'v-right' : 'v-left') : isRightOrTop ? 'h-top' : 'h-bottom');
|
|
77
|
+
return className;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static onMousedown(event: any) {
|
|
81
|
+
if (event.buttons !== 1 || event.button !== 0) return;
|
|
82
|
+
this.pressed = true;
|
|
83
|
+
this.startXorY = this.isVertical ? event.clientX : event.clientY;
|
|
84
|
+
const startPosition = document.defaultView!.getComputedStyle(this.hostNode)[this.isVertical ? 'width' : 'height'];
|
|
85
|
+
this.startWidthOrHeight = parseInt(startPosition, 10);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static onMousemove(event: any) {
|
|
89
|
+
if (!this.pressed || event.buttons !== 1 || event.button !== 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// prevent text/element selection when drag
|
|
94
|
+
stopPropagation(event);
|
|
95
|
+
if (this.isVertical) {
|
|
96
|
+
const movedXorY = this.startWidthOrHeight + (event.clientX - this.startXorY) * (this.isRightOrTop ? 1 : -1);
|
|
97
|
+
this.hostNode.style.width = movedXorY + 'px';
|
|
98
|
+
} else {
|
|
99
|
+
const movedXorY = this.startWidthOrHeight + (event.clientY - this.startXorY) * (this.isRightOrTop ? -1 : 1);
|
|
100
|
+
this.hostNode.style.height = movedXorY + 'px';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static onMouseup() {
|
|
105
|
+
if (this.pressed) this.pressed = false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static getSplitter(selector: string, isVertical: boolean, isRightOrTop: boolean) {
|
|
109
|
+
const className = this.getSplitterClassName(isVertical, isRightOrTop);
|
|
110
|
+
|
|
111
|
+
const onMousedown = (event: any) => {
|
|
112
|
+
if (!this.initialized) {
|
|
113
|
+
this.initialized = true;
|
|
114
|
+
this.init();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
ResizableSplitter.hostNode = document.querySelector(selector)!;
|
|
118
|
+
if (!ResizableSplitter.hostNode) {
|
|
119
|
+
console.error(`Can't find element: ${selector}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
ResizableSplitter.isVertical = isVertical;
|
|
123
|
+
ResizableSplitter.isRightOrTop = isRightOrTop;
|
|
124
|
+
ResizableSplitter.onMousedown.bind(ResizableSplitter)(event);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return <div onMouseDown={onMousedown} class={className}></div>;
|
|
128
|
+
}
|
|
129
|
+
}
|