lupine.components 1.1.42 → 1.1.43
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 +1 -1
- package/src/component-pool/charts/chart-utils.ts +3 -2
- package/src/component-pool/youtube-player/youtube-player.tsx +2 -2
- package/src/components/action-sheet-demo.tsx +12 -0
- package/src/components/action-sheet-theme.tsx +150 -0
- package/src/components/index.ts +1 -0
- package/src/components/menu-sidebar.tsx +22 -12
- package/src/components/message-box.tsx +18 -0
- package/src/components/popup-menu.tsx +4 -4
package/package.json
CHANGED
|
@@ -20,8 +20,9 @@ declare global {
|
|
|
20
20
|
export const chartCommonCss: CssProps = {
|
|
21
21
|
position: 'relative',
|
|
22
22
|
width: '100%',
|
|
23
|
-
height: '
|
|
24
|
-
minHeight: '
|
|
23
|
+
height: 'auto',
|
|
24
|
+
minHeight: '0', // Default min height
|
|
25
|
+
maxHeight: '100%',
|
|
25
26
|
display: 'flex',
|
|
26
27
|
flexDirection: 'column',
|
|
27
28
|
|
|
@@ -94,7 +94,7 @@ export const YouTubePlayer = (props: YouTubePlayerProps) => {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
return (
|
|
97
|
-
<div class={className} css={{ position: 'relative', width, height, ...style }}>
|
|
97
|
+
<div class={className} css={{ position: 'relative', width, height, display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden', ...style }}>
|
|
98
98
|
{src ? (
|
|
99
99
|
<iframe
|
|
100
100
|
width='100%'
|
|
@@ -104,7 +104,7 @@ export const YouTubePlayer = (props: YouTubePlayerProps) => {
|
|
|
104
104
|
frameBorder='0'
|
|
105
105
|
allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
|
|
106
106
|
allowFullScreen={allowFullScreen}
|
|
107
|
-
style={{ border: 'none', display: 'block' }}
|
|
107
|
+
style={{ border: 'none', display: 'block', aspectRatio: '16 / 9', height: 'auto', maxHeight: '100%' }}
|
|
108
108
|
></iframe>
|
|
109
109
|
) : (
|
|
110
110
|
<div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: '#f0f0f0', color: '#999', border: '1px solid #ddd' }}>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { ActionSheetTimePicker } from './action-sheet-time';
|
|
11
11
|
import { ActionSheetDatePicker } from './action-sheet-date';
|
|
12
12
|
import { ActionSheetColorPicker } from './action-sheet-color';
|
|
13
|
+
import { ActionSheetThemePicker } from './action-sheet-theme';
|
|
13
14
|
import { Button, ButtonSize } from './button';
|
|
14
15
|
|
|
15
16
|
export const actionSheetDemo: DemoStory<any> = {
|
|
@@ -180,6 +181,17 @@ export const actionSheetDemo: DemoStory<any> = {
|
|
|
180
181
|
if (result) console.log('Color selected:', result);
|
|
181
182
|
}}
|
|
182
183
|
/>
|
|
184
|
+
<Button
|
|
185
|
+
text='Show Theme Picker'
|
|
186
|
+
size={ButtonSize.Medium}
|
|
187
|
+
onClick={async () => {
|
|
188
|
+
const result = await ActionSheetThemePicker({
|
|
189
|
+
title: 'Pick a theme variable',
|
|
190
|
+
value: 'var(--primary-color)',
|
|
191
|
+
});
|
|
192
|
+
if (result) console.log('Theme variable selected:', result);
|
|
193
|
+
}}
|
|
194
|
+
/>
|
|
183
195
|
</div>
|
|
184
196
|
);
|
|
185
197
|
},
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { CssProps, getCurrentTheme } from 'lupine.web';
|
|
2
|
+
import { ActionSheet, ActionSheetCloseProps, ActionSheetCloseReasonProps } from './action-sheet';
|
|
3
|
+
|
|
4
|
+
export type ActionSheetThemePickerProps = {
|
|
5
|
+
value?: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
cancelButtonText?: string;
|
|
8
|
+
zIndex?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const getThemeVarNameFromValue = (value: string) => {
|
|
12
|
+
const match = String(value || '').match(/var\((--[^),\s]+)/);
|
|
13
|
+
return match ? match[1] : '';
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getThemeValue = (themes: any, themeName: string, key: string) => {
|
|
17
|
+
const themeValue = themes?.[themeName]?.[key];
|
|
18
|
+
if (themeValue !== undefined) return String(themeValue);
|
|
19
|
+
|
|
20
|
+
const fallbackThemeName = Object.keys(themes || {})[0];
|
|
21
|
+
const fallbackValue = themes?.[fallbackThemeName]?.[key];
|
|
22
|
+
return fallbackValue !== undefined ? String(fallbackValue) : '';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getThemeItems = () => {
|
|
26
|
+
const { themeName, themes } = getCurrentTheme();
|
|
27
|
+
const keys = new Set<string>();
|
|
28
|
+
|
|
29
|
+
Object.values(themes || {}).forEach((theme: any) => {
|
|
30
|
+
Object.keys(theme || {}).forEach((key) => {
|
|
31
|
+
if (key.startsWith('--')) keys.add(key);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return Array.from(keys)
|
|
36
|
+
.sort()
|
|
37
|
+
.map((key) => ({
|
|
38
|
+
key,
|
|
39
|
+
value: getThemeValue(themes, themeName, key),
|
|
40
|
+
}));
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const ActionSheetThemePicker = async ({
|
|
44
|
+
value = '',
|
|
45
|
+
title = 'Select Theme Variable',
|
|
46
|
+
cancelButtonText = 'Cancel',
|
|
47
|
+
zIndex,
|
|
48
|
+
}: ActionSheetThemePickerProps): Promise<string | undefined> => {
|
|
49
|
+
return new Promise(async (resolve) => {
|
|
50
|
+
let handleClose: ActionSheetCloseProps;
|
|
51
|
+
const selectedKey = getThemeVarNameFromValue(value);
|
|
52
|
+
const items = getThemeItems();
|
|
53
|
+
|
|
54
|
+
const closeEvent = (reason?: ActionSheetCloseReasonProps) => {
|
|
55
|
+
if (reason !== 'confirm') resolve(undefined);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const css: CssProps = {
|
|
59
|
+
borderTop: '1px solid var(--primary-border-color)',
|
|
60
|
+
overflow: 'hidden',
|
|
61
|
+
'.theme-list': {
|
|
62
|
+
maxHeight: '60vh',
|
|
63
|
+
overflowY: 'auto',
|
|
64
|
+
padding: '8px 0',
|
|
65
|
+
},
|
|
66
|
+
'.theme-empty': {
|
|
67
|
+
padding: '24px 16px',
|
|
68
|
+
textAlign: 'center',
|
|
69
|
+
color: 'var(--secondary-color, #888)',
|
|
70
|
+
fontSize: '13px',
|
|
71
|
+
},
|
|
72
|
+
'.theme-item': {
|
|
73
|
+
display: 'grid',
|
|
74
|
+
gridTemplateColumns: '28px minmax(0, 1fr) auto',
|
|
75
|
+
alignItems: 'center',
|
|
76
|
+
gap: '10px',
|
|
77
|
+
padding: '9px 14px',
|
|
78
|
+
cursor: 'pointer',
|
|
79
|
+
borderBottom: '1px solid var(--primary-border-color)',
|
|
80
|
+
color: 'var(--primary-color)',
|
|
81
|
+
'&:hover': {
|
|
82
|
+
backgroundColor: 'var(--activatable-bg-color-hover, rgba(0,0,0,0.06))',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
'.theme-item-selected': {
|
|
86
|
+
backgroundColor: 'var(--activatable-bg-color-selected, rgba(24,144,255,0.12))',
|
|
87
|
+
},
|
|
88
|
+
'.theme-swatch': {
|
|
89
|
+
width: '22px',
|
|
90
|
+
height: '22px',
|
|
91
|
+
borderRadius: '50%',
|
|
92
|
+
border: '1px solid var(--primary-border-color)',
|
|
93
|
+
boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.08)',
|
|
94
|
+
},
|
|
95
|
+
'.theme-key': {
|
|
96
|
+
minWidth: 0,
|
|
97
|
+
overflow: 'hidden',
|
|
98
|
+
textOverflow: 'ellipsis',
|
|
99
|
+
whiteSpace: 'nowrap',
|
|
100
|
+
fontFamily: 'monospace',
|
|
101
|
+
fontSize: '13px',
|
|
102
|
+
},
|
|
103
|
+
'.theme-value': {
|
|
104
|
+
maxWidth: '160px',
|
|
105
|
+
overflow: 'hidden',
|
|
106
|
+
textOverflow: 'ellipsis',
|
|
107
|
+
whiteSpace: 'nowrap',
|
|
108
|
+
color: 'var(--secondary-color, #888)',
|
|
109
|
+
fontFamily: 'monospace',
|
|
110
|
+
fontSize: '12px',
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const pickerBody = (
|
|
115
|
+
<div css={css}>
|
|
116
|
+
<div class='theme-list'>
|
|
117
|
+
{items.length === 0 && <div class='theme-empty'>No theme variables found.</div>}
|
|
118
|
+
{items.map((item) => {
|
|
119
|
+
const result = `var(${item.key})`;
|
|
120
|
+
return (
|
|
121
|
+
<div
|
|
122
|
+
class={`theme-item ${item.key === selectedKey ? 'theme-item-selected' : ''}`}
|
|
123
|
+
title={`${item.key}: ${item.value}`}
|
|
124
|
+
onClick={() => {
|
|
125
|
+
resolve(result);
|
|
126
|
+
handleClose('confirm');
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<div class='theme-swatch' style={{ background: result }} />
|
|
130
|
+
<div class='theme-key'>{item.key}</div>
|
|
131
|
+
<div class='theme-value'>{item.value}</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
})}
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
handleClose = await ActionSheet.show({
|
|
140
|
+
title,
|
|
141
|
+
children: pickerBody,
|
|
142
|
+
contentMaxHeight: '70vh',
|
|
143
|
+
closeEvent,
|
|
144
|
+
closeWhenClickOutside: true,
|
|
145
|
+
zIndex,
|
|
146
|
+
cancelButtonText,
|
|
147
|
+
buttonsPosition: 'header',
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -100,7 +100,7 @@ export const MenuSidebar = ({
|
|
|
100
100
|
'.menu-sidebar-sub-box.open > .menu-sidebar-item::after': {
|
|
101
101
|
transform: 'rotate(0deg)',
|
|
102
102
|
},
|
|
103
|
-
'&.mobile .menu-sidebar-sub-box > .menu-sidebar-item::after': {
|
|
103
|
+
'&.mobile .menu-sidebar-sub-box.open > .menu-sidebar-item::after': {
|
|
104
104
|
transform: 'rotate(0deg)',
|
|
105
105
|
},
|
|
106
106
|
// '.menu-sidebar-sub-box .menu-sidebar-sub > .menu-sidebar-item': {
|
|
@@ -170,15 +170,17 @@ export const MenuSidebar = ({
|
|
|
170
170
|
display: 'block',
|
|
171
171
|
},
|
|
172
172
|
'&.mobile.open': {
|
|
173
|
-
position: '
|
|
173
|
+
position: 'fixed',
|
|
174
|
+
inset: 0,
|
|
174
175
|
width: '100%',
|
|
175
176
|
height: '100%',
|
|
177
|
+
minHeight: '100dvh',
|
|
176
178
|
top: 0,
|
|
177
179
|
left: 0,
|
|
178
180
|
display: 'flex',
|
|
179
181
|
flexDirection: 'column',
|
|
180
182
|
backgroundColor: '#ccccccc2',
|
|
181
|
-
zIndex: 'var(--layer-
|
|
183
|
+
zIndex: 'var(--layer-menu-sub)',
|
|
182
184
|
},
|
|
183
185
|
'.menu-sidebar-top': {
|
|
184
186
|
display: 'none',
|
|
@@ -195,7 +197,7 @@ export const MenuSidebar = ({
|
|
|
195
197
|
marginLeft: 'unset',
|
|
196
198
|
justifyContent: 'start',
|
|
197
199
|
},
|
|
198
|
-
'.menu-sidebar-top.open .menu-sidebar-sub-box > .menu-sidebar-sub': {
|
|
200
|
+
'.menu-sidebar-top.open .menu-sidebar-sub-box.open > .menu-sidebar-sub': {
|
|
199
201
|
display: 'flex',
|
|
200
202
|
position: 'unset',
|
|
201
203
|
'.menu-sidebar-item': {
|
|
@@ -230,7 +232,7 @@ export const MenuSidebar = ({
|
|
|
230
232
|
}
|
|
231
233
|
let ref: RefProps = {};
|
|
232
234
|
return item.items ? (
|
|
233
|
-
<div ref={ref} class={`menu-sidebar-sub-box ${defaultOpenAll ? 'open' : ''}`} onClick={() => onItemToggleClick(ref)}>
|
|
235
|
+
<div ref={ref} class={`menu-sidebar-sub-box ${defaultOpenAll ? 'open' : ''}`} onClick={(event) => onItemToggleClick(event, ref)}>
|
|
234
236
|
<div class='menu-sidebar-item'>{item.text}</div>
|
|
235
237
|
{renderItems(item.items, 'menu-sidebar-sub')}
|
|
236
238
|
</div>
|
|
@@ -241,8 +243,10 @@ export const MenuSidebar = ({
|
|
|
241
243
|
alt={item.alt || item.text}
|
|
242
244
|
onClick={(event) => {
|
|
243
245
|
stopPropagation(event);
|
|
244
|
-
// hide menu
|
|
245
|
-
|
|
246
|
+
// hide menu only when the mobile overlay is open
|
|
247
|
+
if (ref.current?.classList.contains('open')) {
|
|
248
|
+
onToggleClick(event);
|
|
249
|
+
}
|
|
246
250
|
item.js && item.js();
|
|
247
251
|
}}
|
|
248
252
|
>
|
|
@@ -280,17 +284,23 @@ export const MenuSidebar = ({
|
|
|
280
284
|
const topMenu = ref.$('.menu-sidebar-top');
|
|
281
285
|
topMenu.classList.toggle('open');
|
|
282
286
|
const isOpen = ref.current.classList.toggle('open');
|
|
283
|
-
|
|
287
|
+
|
|
284
288
|
if (isOpen) {
|
|
289
|
+
if (ref.current.classList.contains('mobile')) {
|
|
290
|
+
ref.current.querySelectorAll('.menu-sidebar-sub-box').forEach((item: Element) => {
|
|
291
|
+
item.classList.add('open');
|
|
292
|
+
});
|
|
293
|
+
}
|
|
285
294
|
ref.current.setAttribute('data-back-action', backActionHelper.genBackActionId());
|
|
286
295
|
} else {
|
|
287
296
|
ref.current.removeAttribute('data-back-action');
|
|
288
297
|
}
|
|
289
298
|
};
|
|
290
|
-
const onItemToggleClick = (ref: RefProps) => {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
299
|
+
const onItemToggleClick = (event: Event, ref: RefProps) => {
|
|
300
|
+
stopPropagation(event);
|
|
301
|
+
if (event.target != ref.current && (event.target as any).parentNode != ref.current) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
294
304
|
ref.current.classList.toggle('open');
|
|
295
305
|
};
|
|
296
306
|
|
|
@@ -10,6 +10,24 @@ export type MessageBoxProps = FloatWindowShowProps & {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export class MessageBox {
|
|
13
|
+
static async showPromise(props: MessageBoxProps): Promise<number> {
|
|
14
|
+
return new Promise(async (resolve) => {
|
|
15
|
+
const handleClicked = (index: number, close: FloatWindowCloseProps) => {
|
|
16
|
+
resolve(index);
|
|
17
|
+
close();
|
|
18
|
+
};
|
|
19
|
+
const closeEvent = () => {
|
|
20
|
+
resolve(-1);
|
|
21
|
+
props.closeEvent?.();
|
|
22
|
+
};
|
|
23
|
+
await MessageBox.show({
|
|
24
|
+
...props,
|
|
25
|
+
handleClicked,
|
|
26
|
+
closeEvent,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
static async show({
|
|
14
32
|
title,
|
|
15
33
|
children,
|
|
@@ -502,9 +502,9 @@ export const PopupMenuWithButton = (props: PopupMenuWithButtonProps) => {
|
|
|
502
502
|
onClick={() => {
|
|
503
503
|
hook.openMenu && hook.openMenu();
|
|
504
504
|
}}
|
|
505
|
-
css={{
|
|
505
|
+
css={{ display: 'flex', flexDirection: 'row' }}
|
|
506
506
|
>
|
|
507
|
-
{props.label
|
|
507
|
+
{props.label ? <div style={{ marginRight: '5px' }}>{`${props.label}:`}</div> : ''}
|
|
508
508
|
<PopupMenu
|
|
509
509
|
list={props.list}
|
|
510
510
|
defaultValue={props.defaultValue}
|
|
@@ -535,9 +535,9 @@ export const PopupMenuWithLabel = (props: PopupMenuWithLabelProps) => {
|
|
|
535
535
|
onClick={() => {
|
|
536
536
|
hook.openMenu && hook.openMenu();
|
|
537
537
|
}}
|
|
538
|
-
css={{
|
|
538
|
+
css={{ display: 'flex', flexDirection: 'row', cursor: 'pointer' }}
|
|
539
539
|
>
|
|
540
|
-
{props.label
|
|
540
|
+
{props.label ? <div style={{ marginRight: '5px' }}>{`${props.label}:`}</div> : ''}
|
|
541
541
|
<PopupMenu
|
|
542
542
|
list={props.list}
|
|
543
543
|
defaultValue={props.defaultValue}
|