lupine.components 1.0.4 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lupine.components",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "license": "MIT",
5
5
  "author": "uuware.com",
6
6
  "homepage": "https://uuware.com/",
@@ -33,8 +33,5 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "lupine.web": "^1.0.0"
36
- },
37
- "devDependencies": {
38
- "@types/node": "^22.10.5"
39
36
  }
40
37
  }
@@ -0,0 +1,191 @@
1
+ import { CssProps, RefProps, VNode, mountComponents } from 'lupine.web';
2
+
3
+ export type ActionSheetCloseProps = () => void;
4
+
5
+ export type ActionSheetShowProps = {
6
+ title: string;
7
+ children: VNode<any>;
8
+ contentMaxHeight?: string;
9
+ closeEvent?: () => void;
10
+ closeWhenClickOutside?: boolean; // default true
11
+ cancelButtonText?: string; // no showing if not set
12
+ zIndex?: string;
13
+ };
14
+
15
+ // because it's over a mask, so it can use primary colors
16
+ export class ActionSheet {
17
+ static hostNode: HTMLElement;
18
+
19
+ static async show({
20
+ title,
21
+ children,
22
+ contentMaxHeight,
23
+ closeEvent,
24
+ closeWhenClickOutside = true,
25
+ cancelButtonText = 'Cancel',
26
+ zIndex,
27
+ }: ActionSheetShowProps): Promise<ActionSheetCloseProps> {
28
+ const onCancel = () => {
29
+ handleClose();
30
+ };
31
+ const onClickContainer = (event: any) => {
32
+ if (closeWhenClickOutside !== false && event.target.className === 'act-sheet-box') {
33
+ handleClose();
34
+ }
35
+ };
36
+ const handleClose = () => {
37
+ closeEvent?.();
38
+ ref.current.classList.remove('animation-open');
39
+ setTimeout(() => {
40
+ base.remove();
41
+ }, 300);
42
+ };
43
+
44
+ const base = document.createElement('div');
45
+ const ref: RefProps = {
46
+ onLoad: async () => {
47
+ setTimeout(() => {
48
+ ref.current.classList.add('animation-open');
49
+ }, 1);
50
+ },
51
+ };
52
+ const cssContainer: CssProps = {
53
+ position: 'fixed',
54
+ top: 0,
55
+ left: 0,
56
+ width: '100%',
57
+ height: '100%',
58
+ backgroundColor: 'var(--cover-mask-bg-color)',
59
+ '.act-sheet-body': {
60
+ display: 'flex',
61
+ flexDirection: 'column',
62
+ textAlign: 'center',
63
+ position: 'fixed',
64
+ bottom: '0px',
65
+ left: '0px',
66
+ width: '100%',
67
+ maxHeight: contentMaxHeight ? contentMaxHeight : '',
68
+ color: 'var(--primary-color)',
69
+ padding: '8px',
70
+ transition: 'all 0.3s',
71
+ transform: 'translateY(100%)',
72
+ '&.animation-open': {
73
+ transform: 'translateY(0)',
74
+ },
75
+ '.act-sheet-title': {
76
+ padding: '20px 15px 10px 15px',
77
+ opacity: 0.5,
78
+ },
79
+ '.act-sheet-content': {
80
+ display: 'flex',
81
+ flexDirection: 'column',
82
+ flex: 1,
83
+ overflowY: 'auto',
84
+ borderRadius: '8px',
85
+ backgroundColor: 'var(--cover-bg-color)', //'#fefefe',
86
+ width: '100%',
87
+ maxWidth: '450px',
88
+ margin: '0 auto',
89
+ },
90
+ '.act-sheet-bottom-item, .act-sheet-item': {
91
+ backgroundColor: 'var(--cover-bg-color)', //'#fefefe',
92
+ padding: '20px 0',
93
+ cursor: 'pointer',
94
+ transition: 'all 0.3s ease',
95
+ width: '100%',
96
+ maxWidth: '450px',
97
+ borderTop: '1px solid var(--primary-border-color)',
98
+ },
99
+ '.act-sheet-bottom-item': {
100
+ borderRadius: '8px',
101
+ margin: '0 auto',
102
+ marginTop: '4px',
103
+ },
104
+ '.act-sheet-bottom-item:hover, .act-sheet-item:hover': {
105
+ fontWeight: 'bold',
106
+ },
107
+ },
108
+ };
109
+ const component = (
110
+ <div css={cssContainer} class='act-sheet-box' onClick={onClickContainer}>
111
+ <div ref={ref} class='act-sheet-body'>
112
+ <div class='act-sheet-content'>
113
+ <div class='act-sheet-title'>{title}</div>
114
+ {children}
115
+ </div>
116
+ {cancelButtonText && (
117
+ <div class='act-sheet-bottom-item' onClick={onCancel}>
118
+ {cancelButtonText}
119
+ </div>
120
+ )}
121
+ </div>
122
+ </div>
123
+ );
124
+ base.style.position = 'fixed';
125
+ base.style.zIndex = zIndex || 'var(--layer-actionsheet-window)';
126
+ document.body.appendChild(base);
127
+ await mountComponents(base, component);
128
+ return handleClose;
129
+ }
130
+ }
131
+
132
+ export const ActionSheetSelectOptionsProps = {
133
+ YesNo: ['Yes', 'No'],
134
+ OkCancel: ['OK'],
135
+ };
136
+ export type ActionSheetSelectProps = Omit<ActionSheetShowProps, 'children'> & {
137
+ options: string[];
138
+ handleClicked: (index: number, close: ActionSheetCloseProps) => void;
139
+ };
140
+
141
+ export class ActionSheetSelect {
142
+ static async show({
143
+ title,
144
+ contentMaxHeight,
145
+ options = ActionSheetSelectOptionsProps.OkCancel,
146
+ closeEvent,
147
+ handleClicked,
148
+ closeWhenClickOutside = true,
149
+ cancelButtonText = 'Cancel',
150
+ }: ActionSheetSelectProps): Promise<ActionSheetCloseProps> {
151
+ const handleClose = await ActionSheet.show({
152
+ title,
153
+ children: (
154
+ <div>
155
+ {options.map((option, index) => (
156
+ <div class='act-sheet-item' key={index} onClick={() => handleClicked(index, handleClose)}>
157
+ {option}
158
+ </div>
159
+ ))}
160
+ </div>
161
+ ),
162
+ contentMaxHeight,
163
+ cancelButtonText,
164
+ closeEvent,
165
+ closeWhenClickOutside,
166
+ });
167
+ return handleClose;
168
+ }
169
+ }
170
+
171
+ export type ActionSheetMessageProps = Omit<ActionSheetShowProps, 'children' | 'handleClicked' | 'closeEvent'> & {
172
+ message: string;
173
+ };
174
+ export class ActionSheetMessage {
175
+ static async show({
176
+ title,
177
+ message,
178
+ contentMaxHeight,
179
+ closeWhenClickOutside = true,
180
+ cancelButtonText = '',
181
+ }: ActionSheetMessageProps): Promise<ActionSheetCloseProps> {
182
+ const handleClose = await ActionSheet.show({
183
+ title,
184
+ children: <div css={{ padding: '0 8px 16px 8px' }}>{message}</div>,
185
+ contentMaxHeight,
186
+ cancelButtonText,
187
+ closeWhenClickOutside,
188
+ });
189
+ return handleClose;
190
+ }
191
+ }
@@ -1,4 +1,4 @@
1
- import { CssProps, RefProps } from '../jsx';
1
+ import { CssProps, RefProps } from 'lupine.web';
2
2
  import { Spinner02, SpinnerSize } from './spinner';
3
3
 
4
4
  export type DragRefreshCloseProps = () => void;
@@ -1,4 +1,4 @@
1
- import { CssProps, RefProps } from '../jsx';
1
+ import { CssProps, RefProps } from 'lupine.web';
2
2
 
3
3
  export type EditableLabelHookProps = {
4
4
  updateValue?: (value: string) => void;
@@ -80,7 +80,10 @@ export class FloatWindow {
80
80
 
81
81
  const ref: RefProps = {
82
82
  onLoad: async () => {
83
- ref.current.classList.add('transition', 'animation');
83
+ ref.current.classList.add('transition');
84
+ setTimeout(() => {
85
+ ref.current.classList.add('animation');
86
+ }, 1);
84
87
  setTimeout(() => {
85
88
  // don't need transition for moving
86
89
  ref.current.classList.remove('transition');
@@ -1,6 +1,7 @@
1
1
  import { RefProps, VNode, mountComponents } from 'lupine.web';
2
2
 
3
- export const HtmlVar = (initial?: string | VNode<any>) => {
3
+ export type HtmlVarResult = { value: string | VNode<any>; ref: RefProps; node: VNode<any> };
4
+ export const HtmlVar = (initial?: string | VNode<any>): HtmlVarResult => {
4
5
  let _value: string | VNode<any> = initial || '';
5
6
  let _dirty = false;
6
7
  const waitUpdate = async (value: string | VNode<any>) => {
@@ -11,10 +12,12 @@ export const HtmlVar = (initial?: string | VNode<any>) => {
11
12
  ref.current.innerHTML = value;
12
13
  }
13
14
  _dirty = false;
14
- }
15
- const ref: RefProps = { onLoad: async (el: Element) => {
16
- _dirty && waitUpdate(_value);
17
- } };
15
+ };
16
+ const ref: RefProps = {
17
+ onLoad: async (el: Element) => {
18
+ _dirty && waitUpdate(_value);
19
+ },
20
+ };
18
21
  const FragmentRef = (props: any) => {
19
22
  return <>{props.children}</>;
20
23
  };
@@ -1,4 +1,5 @@
1
1
 
2
+ export * from './action-sheet';
2
3
  export * from './button-push-animation';
3
4
  export * from './button';
4
5
  export * from './drag-refresh';
@@ -1,4 +1,4 @@
1
- import { CssProps } from '../jsx';
1
+ import { CssProps } from 'lupine.web';
2
2
 
3
3
  export type PanelProps = {
4
4
  children: any;
@@ -1,4 +1,4 @@
1
- import { RefProps } from '../jsx';
1
+ import { RefProps } from 'lupine.web';
2
2
  import { HtmlVar } from './html-var';
3
3
 
4
4
  export type ProgressHookProps = {
@@ -1,4 +1,4 @@
1
- import { RefProps } from '../jsx';
1
+ import { RefProps } from 'lupine.web';
2
2
 
3
3
  export type RedirectProps = {
4
4
  title?: string;
@@ -1,4 +1,4 @@
1
- import { CssProps } from '../jsx';
1
+ import { CssProps } from 'lupine.web';
2
2
 
3
3
  export type SelectOptionProps = {
4
4
  option: string;
@@ -1,4 +1,4 @@
1
- import { CssProps } from '../jsx';
1
+ import { CssProps } from 'lupine.web';
2
2
 
3
3
  export type TextGlowProps = {
4
4
  text: string;
@@ -1,4 +1,4 @@
1
- import { CssProps } from "../jsx";
1
+ import { CssProps } from "lupine.web";
2
2
 
3
3
  export type TextLoadingProps = {
4
4
  text: string;
@@ -0,0 +1,118 @@
1
+ /*
2
+ const moveFn = createDragUtil();
3
+ moveFn.setOnMoveCallback((clientX: number, clientY: number, movedX: number, movedY: number) => {
4
+ const dragDom = moveFn.getDraggingDom();
5
+ if (dragDom?.classList.contains('xxx')) {
6
+ updateRangeMMove(clientX, true, dragDom, _saved.stopDoms);
7
+ } else if (dragDom?.classList.contains('yyy')) {
8
+ updatePicMMove(clientX);
9
+ }
10
+ });
11
+ <div
12
+ onMouseMove={moveFn.onMouseMove}
13
+ onMouseUp={moveFn.onMouseUp}
14
+ onTouchMove={moveFn.onTouchMove}
15
+ onTouchEnd={moveFn.onTouchEnd}
16
+ >
17
+ <div onMouseDown={moveFn.onMouseDown} onTouchStart={moveFn.onTouchStart}></div>
18
+ </div>
19
+
20
+ // when zooming an image, the way to scale slowly
21
+ const slowDelta = 1 + (scale - 1) * 0.2;
22
+ tempScale = lastScale * slowDelta;
23
+ */
24
+ export const createDragUtil = () => {
25
+ let isDragging = false;
26
+ let initialX = 0;
27
+ let initialY = 0;
28
+ let draggingDom: HTMLDivElement | null = null;
29
+ let onMoveCallback: (clientX: number, clientY: number, movedX: number, movedY: number) => void = () => {};
30
+ let onScaleCallback: (scale: number) => void = () => {};
31
+
32
+ let isZooming = false;
33
+ let initialDistance = 0;
34
+
35
+ const getDistance = (t1: Touch, t2: Touch) => {
36
+ const dx = t2.clientX - t1.clientX;
37
+ const dy = t2.clientY - t1.clientY;
38
+ return Math.sqrt(dx * dx + dy * dy);
39
+ };
40
+ return {
41
+ setOnMoveCallback: (callback: (clientX: number, clientY: number, movedX: number, movedY: number) => void) => {
42
+ onMoveCallback = callback;
43
+ },
44
+ setOnScaleCallback: (callback: (scale: number) => void) => {
45
+ onScaleCallback = callback;
46
+ },
47
+ getDistance,
48
+ getDraggingDom: () => draggingDom,
49
+ onMouseDown: (event: MouseEvent) => {
50
+ event.preventDefault();
51
+ if (event.buttons !== 1) {
52
+ isDragging = false;
53
+ draggingDom = null;
54
+ return;
55
+ }
56
+ isDragging = true;
57
+ draggingDom = event.currentTarget as HTMLDivElement;
58
+ initialX = event.clientX;
59
+ initialY = event.clientY;
60
+ },
61
+ onMouseMove: (event: MouseEvent) => {
62
+ if (event.buttons === 0 || !draggingDom) {
63
+ isDragging = false;
64
+ draggingDom = null;
65
+ return;
66
+ }
67
+ onMoveCallback(event.clientX, event.clientY, event.clientX - initialX, event.clientY - initialY);
68
+ },
69
+ onMouseUp: () => {
70
+ isDragging = false;
71
+ isZooming = false;
72
+ draggingDom = null;
73
+ },
74
+
75
+ onTouchStart: (event: TouchEvent) => {
76
+ if (event.touches.length === 1) {
77
+ isDragging = true;
78
+ draggingDom = event.currentTarget as HTMLDivElement;
79
+ initialX = event.touches[0].clientX;
80
+ initialY = event.touches[0].clientY;
81
+ } else if (event.touches.length === 2) {
82
+ initialDistance = getDistance(event.touches[0], event.touches[1]);
83
+ isZooming = true;
84
+ } else {
85
+ isDragging = false;
86
+ draggingDom = null;
87
+ }
88
+ },
89
+ onTouchMove: (event: TouchEvent) => {
90
+ if (isZooming) {
91
+ if (event.touches.length === 2) {
92
+ event.preventDefault(); // 防止页面滚动
93
+ const newDistance = getDistance(event.touches[0], event.touches[1]);
94
+ const delta = newDistance / initialDistance;
95
+ // const newScale = Math.min(Math.max(1, scale * delta), 4); // 限制缩放范围
96
+ onScaleCallback(delta);
97
+ return;
98
+ }
99
+ }
100
+ if (!isDragging || event.touches.length === 0 || !draggingDom) {
101
+ isDragging = false;
102
+ draggingDom = null;
103
+ return;
104
+ }
105
+ onMoveCallback(
106
+ event.touches[0].clientX,
107
+ event.touches[0].clientY,
108
+ event.touches[0].clientX - initialX,
109
+ event.touches[0].clientY - initialY
110
+ );
111
+ },
112
+ onTouchEnd: () => {
113
+ isDragging = false;
114
+ isZooming = false;
115
+ draggingDom = null;
116
+ },
117
+ };
118
+ };
package/src/lib/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from './dom';
2
2
  export * from './date-utils';
3
3
  export * from './deep-merge';
4
4
  export * from './document-ready';
5
+ export * from './drag-util';
5
6
  export * from './dynamical-load';
6
7
  export * from './format-bytes';
7
8
  export * from './lite-dom';
@@ -39,21 +39,22 @@ export const uploadFileChunk = async (
39
39
  };
40
40
 
41
41
  export const uploadFile = async (
42
- file: File,
42
+ file: File | string,
43
43
  uploadUrl: string,
44
44
  progressFn?: (percentage: number, chunkNumber: number, totalChunks: number) => void,
45
45
  chunkSize = _saveChunkSize.size
46
46
  ) => {
47
47
  // const uploadedSize = await checkUploadedFileSize(uploadUrl);
48
48
  let key = '';
49
- if (file.size <= chunkSize) {
49
+ const len = file instanceof File ? file.size : file.length;
50
+ if (len <= chunkSize) {
50
51
  return await uploadFileChunk(file, 0, 1, uploadUrl, key);
51
52
  }
52
53
 
53
- const totalChunks = Math.ceil(file.size / chunkSize);
54
+ const totalChunks = Math.ceil(len / chunkSize);
54
55
  for (let i = 0; i < totalChunks; i++) {
55
56
  const start = i * chunkSize;
56
- const end = Math.min((i + 1) * chunkSize, file.size);
57
+ const end = Math.min((i + 1) * chunkSize, len);
57
58
  const chunk = file.slice(start, end);
58
59
  const uploaded = await uploadFileChunk(chunk, i, totalChunks, uploadUrl, key);
59
60
  if (!uploaded || uploaded.chunkNumber === i.toString() || !uploaded.key) {
@@ -9,18 +9,20 @@ export const darkThemes: ThemeProps = {
9
9
  '--scrollbar-thumb-bg': '#373636',
10
10
  '--scrollbar-active-thumb-bg': '#5b5b5b',
11
11
 
12
- '--primary-color': '#aeaeae',
12
+ '--primary-color': '#e5e5e5',
13
13
  '--primary-color-disabled': '#7d7d7d',
14
14
  '--primary-bg-color': '#000000',
15
15
  '--primary-border-color': '#aeaeae',
16
16
  '--primary-border': '1px solid var(--primary-border-color)',
17
- // '--secondary-color': '#b3b3b3',
18
- // '--secondary-bg-color': '#151515',
19
- // '--secondary-border': '1px solid #303030',
20
17
  '--primary-opacity': '0.5', // used for dark theme
21
18
  '--primary-disabled-opacity': '0.7', // used for dark theme
22
19
  '--primary-accent-color': '#1a588a', // used for radio and checkbox's background color
23
20
 
21
+ '--secondary-color': '#747474',
22
+ '--secondary-bg-color': '#1c1c1c',
23
+ '--secondary-border-color': '#494949',
24
+ '--secondary-border': '1px solid var(--secondary-border-color)',
25
+
24
26
  // including menus, tabs
25
27
  '--activatable-color-normal': 'var(--primary-color)',
26
28
  '--activatable-bg-color-normal': 'var(--primary-bg-color)',
@@ -15,13 +15,15 @@ export const lightThemes: ThemeProps = {
15
15
  '--primary-bg-color': '#ffffff',
16
16
  '--primary-border-color': '#858585',
17
17
  '--primary-border': '1px solid var(--primary-border-color)',
18
- // '--secondary-color': '#505050',
19
- // '--secondary-bg-color': '#ffffff',
20
- // '--secondary-border': '1px solid #858585',
21
18
  '--primary-opacity': 'unset', // used for dark theme
22
19
  '--primary-disabled-opacity': '0.5', // used for dark theme
23
20
  '--primary-accent-color': '#0a74c9', // used for radio and checkbox's background color
24
21
 
22
+ '--secondary-color': '#818181',
23
+ '--secondary-bg-color': '#eeeeee',
24
+ '--secondary-border-color': '#a0a0a0',
25
+ '--secondary-border': '1px solid var(--secondary-border-color)',
26
+
25
27
  // including menus, tabs, sidebars
26
28
  '--activatable-color-normal': 'var(--primary-color)',
27
29
  '--activatable-bg-color-normal': 'var(--primary-bg-color)',
@@ -11,6 +11,7 @@ export const sharedThemes: ThemeProps = {
11
11
  '--layer-modal': '600',
12
12
  '--layer-modal-over': '610',
13
13
  '--layer-float-window': '700',
14
+ '--layer-actionsheet-window': '710',
14
15
  '--layer-menu': '800', // popup menu
15
16
  '--layer-menu-sub': '810',
16
17
  '--layer-notice': '900', // notice, loading, toast