@arcblock/ux 2.13.26 → 2.13.28
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/lib/Config/config-provider.d.ts +1 -0
- package/lib/RelativeTime/index.d.ts +3 -2
- package/lib/RelativeTime/index.js +178 -12
- package/lib/Tabs/index.js +2 -2
- package/lib/Theme/theme-provider.d.ts +5 -2
- package/lib/Theme/theme-provider.js +28 -9
- package/lib/Theme/theme.d.ts +6 -4
- package/lib/Theme/theme.js +15 -9
- package/lib/Util/index.d.ts +2 -1
- package/lib/Util/index.js +9 -3
- package/package.json +6 -6
- package/src/RelativeTime/index.tsx +160 -10
- package/src/Tabs/index.tsx +2 -2
- package/src/Theme/theme-provider.tsx +36 -10
- package/src/Theme/theme.ts +21 -15
- package/src/Util/index.ts +7 -3
@@ -12,6 +12,7 @@ export declare function ConfigProvider({ children, theme, injectFirst, darkSchem
|
|
12
12
|
export declare function useConfig(): {
|
13
13
|
mode: import("@mui/material").PaletteMode;
|
14
14
|
toggleMode: () => void;
|
15
|
+
changeMode: (mode: import("@mui/material").PaletteMode) => void;
|
15
16
|
prefer?: import("../Theme").Prefer;
|
16
17
|
locale: import("../type").Locale;
|
17
18
|
changeLocale: (locale: import("../type").Locale) => void;
|
@@ -6,9 +6,10 @@ export interface RelativeTimeProps {
|
|
6
6
|
withoutSuffix?: false | true;
|
7
7
|
from?: string | number;
|
8
8
|
to?: string | number;
|
9
|
-
type?: 'relative' | 'absolute';
|
9
|
+
type?: 'relative' | 'absolute' | 'utc' | 'all';
|
10
10
|
tz?: string;
|
11
11
|
relativeRange?: number;
|
12
12
|
enableTooltip?: boolean;
|
13
|
+
showUTCPrefix?: boolean;
|
13
14
|
}
|
14
|
-
export default function RelativeTime({ value, locale, withoutSuffix, from, to, type, tz, relativeRange, enableTooltip, ...rest }: RelativeTimeProps):
|
15
|
+
export default function RelativeTime({ value, locale, withoutSuffix, from, to, type, tz, relativeRange, enableTooltip, showUTCPrefix, ...rest }: RelativeTimeProps): import("react/jsx-runtime").JSX.Element;
|
@@ -1,8 +1,9 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import { Box, Tooltip } from '@mui/material';
|
3
|
+
import { useState } from 'react';
|
2
4
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
3
5
|
import dayjs from 'dayjs';
|
4
6
|
import 'dayjs/locale/zh-cn';
|
5
|
-
import { Tooltip } from '@mui/material';
|
6
7
|
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
7
8
|
import utc from 'dayjs/plugin/utc';
|
8
9
|
import timezone from 'dayjs/plugin/timezone';
|
@@ -33,7 +34,15 @@ dayjs.updateLocale('zh-cn', {
|
|
33
34
|
});
|
34
35
|
// FIXME: @@ 此处不能真正的将 relativeTime 设置为支持中文
|
35
36
|
setDateTool(dayjs);
|
36
|
-
|
37
|
+
const translations = {
|
38
|
+
en: {
|
39
|
+
utc: 'Your Timezone'
|
40
|
+
},
|
41
|
+
zh: {
|
42
|
+
utc: '你所在时区'
|
43
|
+
}
|
44
|
+
};
|
45
|
+
function useRelativeTime({
|
37
46
|
value,
|
38
47
|
locale = 'en',
|
39
48
|
withoutSuffix = false,
|
@@ -41,17 +50,31 @@ export default function RelativeTime({
|
|
41
50
|
to = '',
|
42
51
|
type = 'relative',
|
43
52
|
tz,
|
44
|
-
relativeRange
|
45
|
-
enableTooltip = true,
|
46
|
-
...rest
|
53
|
+
relativeRange
|
47
54
|
}) {
|
55
|
+
const date = new Date();
|
56
|
+
const timeZoneOffset = date.getTimezoneOffset();
|
57
|
+
const sign = timeZoneOffset > 0 ? '-' : '+';
|
58
|
+
const hoursOffset = Math.abs(timeZoneOffset) / 60;
|
59
|
+
const isLocalUtc = timeZoneOffset === 0;
|
60
|
+
const [isUtc, setIsUtc] = useState(isLocalUtc);
|
48
61
|
if (!value) {
|
49
|
-
return
|
62
|
+
return {
|
63
|
+
innerContent: '-',
|
64
|
+
popContent: '-',
|
65
|
+
isUtc,
|
66
|
+
setIsUtc,
|
67
|
+
sign,
|
68
|
+
hoursOffset
|
69
|
+
};
|
50
70
|
}
|
51
71
|
const localeOption = locale === 'zh' ? 'zh-cn' : 'en-us';
|
52
|
-
|
72
|
+
let datetime = dayjs(value).locale(localeOption);
|
73
|
+
if (type === 'utc') {
|
74
|
+
datetime = dayjs(value).utc().locale(localeOption);
|
75
|
+
}
|
53
76
|
if (tz) {
|
54
|
-
datetime.tz(tz);
|
77
|
+
datetime = datetime.tz(tz);
|
55
78
|
}
|
56
79
|
const absoluteString = formatToDatetime(value, {
|
57
80
|
locale: localeOption,
|
@@ -77,13 +100,156 @@ export default function RelativeTime({
|
|
77
100
|
innerContent = absoluteString;
|
78
101
|
popContent = relativeString;
|
79
102
|
}
|
103
|
+
if (type === 'utc') {
|
104
|
+
if (isUtc) {
|
105
|
+
innerContent = formatToDatetime(value, {
|
106
|
+
locale: localeOption,
|
107
|
+
tz,
|
108
|
+
isUtc: true
|
109
|
+
});
|
110
|
+
popContent = formatToDatetime(value, {
|
111
|
+
locale: localeOption,
|
112
|
+
tz,
|
113
|
+
isUtc: true
|
114
|
+
});
|
115
|
+
} else {
|
116
|
+
innerContent = absoluteString;
|
117
|
+
popContent = relativeString;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
return {
|
121
|
+
innerContent,
|
122
|
+
popContent,
|
123
|
+
isUtc,
|
124
|
+
setIsUtc,
|
125
|
+
sign,
|
126
|
+
hoursOffset,
|
127
|
+
relativeString,
|
128
|
+
absoluteString
|
129
|
+
};
|
130
|
+
}
|
131
|
+
function UTCChip({
|
132
|
+
locale,
|
133
|
+
isUtc,
|
134
|
+
sign,
|
135
|
+
hoursOffset,
|
136
|
+
setIsUtc,
|
137
|
+
showUTCPrefix = true
|
138
|
+
}) {
|
139
|
+
const prefix = showUTCPrefix ? `${translations[locale].utc}: ` : '';
|
140
|
+
return /*#__PURE__*/_jsx(Box, {
|
141
|
+
component: "span",
|
142
|
+
sx: {
|
143
|
+
color: 'inherit',
|
144
|
+
cursor: 'pointer',
|
145
|
+
border: '1px solid',
|
146
|
+
fontSize: '0.8rem',
|
147
|
+
borderColor: 'divider',
|
148
|
+
borderRadius: '20px',
|
149
|
+
padding: '4px 8px',
|
150
|
+
lineHeight: 1
|
151
|
+
},
|
152
|
+
onClick: () => setIsUtc(r => !r),
|
153
|
+
children: `${prefix}${isUtc ? 'UTC' : `UTC${sign}${hoursOffset}`}`
|
154
|
+
});
|
155
|
+
}
|
156
|
+
export default function RelativeTime({
|
157
|
+
value,
|
158
|
+
locale = 'en',
|
159
|
+
withoutSuffix = false,
|
160
|
+
from = '',
|
161
|
+
to = '',
|
162
|
+
type = 'relative',
|
163
|
+
tz,
|
164
|
+
relativeRange,
|
165
|
+
enableTooltip = true,
|
166
|
+
showUTCPrefix = true,
|
167
|
+
...rest
|
168
|
+
}) {
|
169
|
+
const {
|
170
|
+
innerContent,
|
171
|
+
popContent,
|
172
|
+
isUtc,
|
173
|
+
setIsUtc,
|
174
|
+
sign,
|
175
|
+
hoursOffset,
|
176
|
+
relativeString
|
177
|
+
} = useRelativeTime({
|
178
|
+
value,
|
179
|
+
locale,
|
180
|
+
withoutSuffix,
|
181
|
+
from,
|
182
|
+
to,
|
183
|
+
type: type === 'all' ? 'utc' : type,
|
184
|
+
tz,
|
185
|
+
relativeRange
|
186
|
+
});
|
187
|
+
if (type === 'all') {
|
188
|
+
return /*#__PURE__*/_jsx(Tooltip, {
|
189
|
+
title: undefined,
|
190
|
+
placement: "top-end",
|
191
|
+
enterTouchDelay: 0,
|
192
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
193
|
+
display: "flex",
|
194
|
+
alignItems: "center",
|
195
|
+
gap: 0.5,
|
196
|
+
width: "max-content",
|
197
|
+
...rest,
|
198
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
199
|
+
component: "span",
|
200
|
+
...rest,
|
201
|
+
sx: {},
|
202
|
+
children: innerContent
|
203
|
+
}), /*#__PURE__*/_jsx(Box, {
|
204
|
+
component: "span",
|
205
|
+
sx: {
|
206
|
+
color: 'inherit'
|
207
|
+
},
|
208
|
+
children: "\xB7"
|
209
|
+
}), /*#__PURE__*/_jsx(Box, {
|
210
|
+
component: "span",
|
211
|
+
sx: {
|
212
|
+
color: 'text.secondary'
|
213
|
+
},
|
214
|
+
children: relativeString
|
215
|
+
}), /*#__PURE__*/_jsx(Box, {
|
216
|
+
component: "span",
|
217
|
+
sx: {
|
218
|
+
color: 'inherit'
|
219
|
+
},
|
220
|
+
children: "\xB7"
|
221
|
+
}), /*#__PURE__*/_jsx(UTCChip, {
|
222
|
+
locale: locale,
|
223
|
+
isUtc: isUtc,
|
224
|
+
sign: sign,
|
225
|
+
hoursOffset: hoursOffset,
|
226
|
+
setIsUtc: setIsUtc,
|
227
|
+
showUTCPrefix: showUTCPrefix
|
228
|
+
})]
|
229
|
+
})
|
230
|
+
});
|
231
|
+
}
|
80
232
|
return /*#__PURE__*/_jsx(Tooltip, {
|
81
233
|
title: enableTooltip ? popContent : undefined,
|
82
234
|
placement: "top-end",
|
83
235
|
enterTouchDelay: 0,
|
84
|
-
children: /*#__PURE__*/
|
85
|
-
|
86
|
-
|
236
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
237
|
+
display: "flex",
|
238
|
+
alignItems: "center",
|
239
|
+
gap: 1,
|
240
|
+
width: "max-content",
|
241
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
242
|
+
component: "span",
|
243
|
+
...rest,
|
244
|
+
children: innerContent
|
245
|
+
}), type === 'utc' && /*#__PURE__*/_jsx(UTCChip, {
|
246
|
+
locale: locale,
|
247
|
+
isUtc: isUtc,
|
248
|
+
sign: sign,
|
249
|
+
hoursOffset: hoursOffset,
|
250
|
+
setIsUtc: setIsUtc,
|
251
|
+
showUTCPrefix: showUTCPrefix
|
252
|
+
})]
|
87
253
|
})
|
88
254
|
});
|
89
255
|
}
|
package/lib/Tabs/index.js
CHANGED
@@ -41,7 +41,7 @@ function CardTabs({
|
|
41
41
|
},
|
42
42
|
'.MuiTabs-flexContainer': {
|
43
43
|
borderRadius: '100vw',
|
44
|
-
backgroundColor: 'grey.
|
44
|
+
backgroundColor: 'grey.100',
|
45
45
|
padding: 0.5,
|
46
46
|
display: 'inline-flex',
|
47
47
|
columnGap: 0.25,
|
@@ -60,7 +60,7 @@ function CardTabs({
|
|
60
60
|
textTransform: 'capitalize',
|
61
61
|
transition: 'background-color 0.2s ease',
|
62
62
|
'&.Mui-selected, &:hover': {
|
63
|
-
backgroundColor: '
|
63
|
+
backgroundColor: 'action.selected',
|
64
64
|
borderColor: 'grey.100',
|
65
65
|
color: 'grey.A700'
|
66
66
|
}
|
@@ -1,15 +1,18 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
2
|
import { PaletteMode } from '@mui/material';
|
3
|
-
import { Theme } from '@mui/material/styles';
|
3
|
+
import { Theme, ThemeOptions } from '@mui/material/styles';
|
4
4
|
/** 颜色模式上下文类型 */
|
5
5
|
export interface ColorSchemeContextType {
|
6
6
|
mode: PaletteMode;
|
7
7
|
toggleMode: () => void;
|
8
|
+
changeMode: (mode: PaletteMode) => void;
|
8
9
|
prefer?: Prefer;
|
9
10
|
}
|
10
11
|
export declare const ColorSchemeContext: import("react").Context<ColorSchemeContextType>;
|
11
12
|
export declare function useColorScheme(): ColorSchemeContextType;
|
12
|
-
export type UxTheme =
|
13
|
+
export type UxTheme = ThemeOptions | ((parentTheme: Theme, context?: {
|
14
|
+
mode: PaletteMode;
|
15
|
+
}) => Theme);
|
13
16
|
export type Prefer = 'light' | 'dark' | 'system';
|
14
17
|
interface BaseThemeProviderProps {
|
15
18
|
children?: React.ReactNode;
|
@@ -7,7 +7,7 @@ import StyledEngineProvider from '@mui/material/StyledEngineProvider';
|
|
7
7
|
import CssBaseline from '@mui/material/CssBaseline';
|
8
8
|
import set from 'lodash/set';
|
9
9
|
import { BLOCKLET_THEME_PREFER_KEY } from '@blocklet/theme';
|
10
|
-
import { createTheme, getDefaultThemePrefer, isTheme,
|
10
|
+
import { createTheme, getDefaultThemePrefer, isTheme, isUxTheme, lazyCreateDefaultTheme } from './theme';
|
11
11
|
const defaultTheme = createTheme();
|
12
12
|
|
13
13
|
/** 颜色模式上下文类型 */
|
@@ -83,7 +83,7 @@ function DarkSchemeStyles({
|
|
83
83
|
}
|
84
84
|
return null;
|
85
85
|
}
|
86
|
-
/**
|
86
|
+
/** 快速配置 MUI 主题 */
|
87
87
|
function BaseThemeProvider({
|
88
88
|
children,
|
89
89
|
theme = defaultTheme,
|
@@ -110,7 +110,7 @@ function BaseThemeProvider({
|
|
110
110
|
})
|
111
111
|
);
|
112
112
|
}
|
113
|
-
/**
|
113
|
+
/** 配置带颜色模式切换功能的 MUI 主题 */
|
114
114
|
function ColorSchemeProvider({
|
115
115
|
children,
|
116
116
|
theme: themeInput,
|
@@ -119,14 +119,26 @@ function ColorSchemeProvider({
|
|
119
119
|
...rest
|
120
120
|
}) {
|
121
121
|
const [mode, setMode] = useState(() => resolveMode(prefer));
|
122
|
+
const parentTheme = useTheme();
|
122
123
|
const _themeInput = useMemo(() => {
|
123
124
|
let result = {};
|
124
|
-
const
|
125
|
+
const createBaseTheme = lazyCreateDefaultTheme(mode);
|
125
126
|
if (themeInput) {
|
126
127
|
if (typeof themeInput === 'function') {
|
127
|
-
|
128
|
-
|
129
|
-
|
128
|
+
const baseTheme = createBaseTheme();
|
129
|
+
if (isUxTheme(parentTheme)) {
|
130
|
+
result = {
|
131
|
+
...themeInput(parentTheme, {
|
132
|
+
mode
|
133
|
+
})
|
134
|
+
};
|
135
|
+
} else {
|
136
|
+
result = {
|
137
|
+
...themeInput(baseTheme, {
|
138
|
+
mode
|
139
|
+
})
|
140
|
+
};
|
141
|
+
}
|
130
142
|
} else {
|
131
143
|
result = {
|
132
144
|
...themeInput
|
@@ -136,7 +148,7 @@ function ColorSchemeProvider({
|
|
136
148
|
set(result, 'palette.mode', mode);
|
137
149
|
set(result, 'mode', mode);
|
138
150
|
return result;
|
139
|
-
}, [mode, themeInput]);
|
151
|
+
}, [mode, themeInput, parentTheme]);
|
140
152
|
const theme = useMemo(() => {
|
141
153
|
return createTheme({
|
142
154
|
..._themeInput,
|
@@ -150,11 +162,18 @@ function ColorSchemeProvider({
|
|
150
162
|
setMode(newMode);
|
151
163
|
localStorage.setItem(BLOCKLET_THEME_PREFER_KEY, newMode);
|
152
164
|
}, [mode, setMode]);
|
165
|
+
const changeMode = useCallback(newMode => {
|
166
|
+
if (mode !== newMode) {
|
167
|
+
setMode(newMode);
|
168
|
+
localStorage.setItem(BLOCKLET_THEME_PREFER_KEY, newMode);
|
169
|
+
}
|
170
|
+
}, [mode, setMode]);
|
153
171
|
const colorSchemeValue = useMemo(() => ({
|
154
172
|
mode,
|
155
173
|
toggleMode,
|
174
|
+
changeMode,
|
156
175
|
prefer
|
157
|
-
}), [mode, prefer, toggleMode]);
|
176
|
+
}), [mode, prefer, toggleMode, changeMode]);
|
158
177
|
useEffect(() => {
|
159
178
|
if (prefer) {
|
160
179
|
setMode(resolveMode(prefer));
|
package/lib/Theme/theme.d.ts
CHANGED
@@ -9,6 +9,8 @@ import '@fontsource/roboto/latin-ext-500.css';
|
|
9
9
|
import '@fontsource/roboto/latin-ext-700.css';
|
10
10
|
/** 是否是 MUI Theme 对象 */
|
11
11
|
export declare function isTheme(obj: any): obj is Theme;
|
12
|
+
/** 是否是 UX Theme 对象 */
|
13
|
+
export declare function isUxTheme(obj: any): obj is Theme;
|
12
14
|
export declare function collectFontFamilies(obj?: {
|
13
15
|
fontFamily?: string;
|
14
16
|
}, fontSet?: Set<string>): Set<string>;
|
@@ -19,10 +21,10 @@ export declare function getDefaultThemePrefer(meta?: {
|
|
19
21
|
};
|
20
22
|
}): PaletteMode;
|
21
23
|
export declare function createDefaultThemeOptions(mode?: PaletteMode): ThemeOptions;
|
22
|
-
export interface
|
24
|
+
export interface UxThemeOptions extends ThemeOptions {
|
23
25
|
disableBlockletTheme?: boolean;
|
24
26
|
}
|
25
|
-
export declare function
|
26
|
-
export declare const create: (...args: Array<
|
27
|
-
export declare const createTheme: (...args: Array<
|
27
|
+
export declare function lazyCreateDefaultTheme(mode: PaletteMode): () => Theme;
|
28
|
+
export declare const create: (...args: Array<UxThemeOptions | ((baseTheme: Theme) => UxThemeOptions)>) => Theme;
|
29
|
+
export declare const createTheme: (...args: Array<UxThemeOptions | ((baseTheme: Theme) => UxThemeOptions)>) => Theme;
|
28
30
|
export { deepmerge };
|
package/lib/Theme/theme.js
CHANGED
@@ -20,6 +20,11 @@ export function isTheme(obj) {
|
|
20
20
|
return obj && typeof obj === 'object' && obj.palette && typeof obj.palette.getContrastText === 'function';
|
21
21
|
}
|
22
22
|
|
23
|
+
/** 是否是 UX Theme 对象 */
|
24
|
+
export function isUxTheme(obj) {
|
25
|
+
return isTheme(obj) && obj.__isUxTheme__ === true;
|
26
|
+
}
|
27
|
+
|
23
28
|
// 收集字体配置
|
24
29
|
export function collectFontFamilies(obj, fontSet = new Set()) {
|
25
30
|
if (!obj || typeof obj !== 'object') return fontSet;
|
@@ -94,13 +99,13 @@ export function createDefaultThemeOptions(mode = 'light') {
|
|
94
99
|
}
|
95
100
|
return BLOCKLET_THEME_LIGHT;
|
96
101
|
}
|
97
|
-
|
98
|
-
|
99
|
-
let config = null;
|
102
|
+
export function lazyCreateDefaultTheme(mode) {
|
103
|
+
let theme = null;
|
100
104
|
return () => {
|
101
|
-
if (
|
102
|
-
|
103
|
-
|
105
|
+
if (theme) return theme;
|
106
|
+
const options = deepmerge(createDefaultThemeOptions(mode), window.blocklet?.theme?.[mode] ?? {});
|
107
|
+
theme = _createTheme(options);
|
108
|
+
return theme;
|
104
109
|
};
|
105
110
|
}
|
106
111
|
|
@@ -121,7 +126,7 @@ const normalizeUserThemeOptions = ({
|
|
121
126
|
};
|
122
127
|
return result;
|
123
128
|
};
|
124
|
-
const
|
129
|
+
const defaultUxThemeOptions = {
|
125
130
|
themeName: 'ArcBlock',
|
126
131
|
pageWidth: 'md',
|
127
132
|
disableBlockletTheme: false,
|
@@ -151,8 +156,8 @@ const defaultUserThemeOptions = {
|
|
151
156
|
// https://material-ui.com/customization/default-theme/
|
152
157
|
export const create = (...args) => {
|
153
158
|
const defaultPrefer = getDefaultThemePrefer();
|
154
|
-
const
|
155
|
-
const userThemeOptions = args.reduce((acc, curr) => deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(
|
159
|
+
const createBaseTheme = lazyCreateDefaultTheme(defaultPrefer);
|
160
|
+
const userThemeOptions = args.reduce((acc, curr) => deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(createBaseTheme()) : curr)), normalizeUserThemeOptions(defaultUxThemeOptions));
|
156
161
|
const prefer = userThemeOptions.mode || userThemeOptions.palette?.mode || defaultPrefer;
|
157
162
|
const blockletThemeOptions = window.blocklet?.theme?.[prefer] ?? {};
|
158
163
|
const defaultThemeOptions = createDefaultThemeOptions(prefer);
|
@@ -172,6 +177,7 @@ export const create = (...args) => {
|
|
172
177
|
|
173
178
|
// 创建主题
|
174
179
|
const theme = _createTheme(mergedThemeOptions);
|
180
|
+
theme.__isUxTheme__ = true;
|
175
181
|
|
176
182
|
// 异步加载字体
|
177
183
|
const fonts = collectFontFamilies(theme.typography);
|
package/lib/Util/index.d.ts
CHANGED
@@ -48,9 +48,10 @@ export declare function formatToDate(date: string | number | Date, { locale, tz
|
|
48
48
|
* Ensure that the setDateTool() function is called first to set the time tool library.
|
49
49
|
* @returns formatted date string
|
50
50
|
*/
|
51
|
-
export declare function formatToDatetime(date: string | number | Date, { locale, tz }?: {
|
51
|
+
export declare function formatToDatetime(date: string | number | Date, { locale, tz, isUtc }?: {
|
52
52
|
locale?: Locale;
|
53
53
|
tz?: string;
|
54
|
+
isUtc?: boolean;
|
54
55
|
}): any;
|
55
56
|
export declare function detectWalletExtension(): any;
|
56
57
|
export declare function openWebWallet({ webWalletUrl, action, locale, url, windowFeatures, appInfo, memberAppInfo, }: {
|
package/lib/Util/index.js
CHANGED
@@ -189,7 +189,8 @@ export function getDateTool() {
|
|
189
189
|
}
|
190
190
|
const createDateFormatter = format => (date, {
|
191
191
|
locale,
|
192
|
-
tz
|
192
|
+
tz,
|
193
|
+
isUtc
|
193
194
|
} = {}) => {
|
194
195
|
if (dateTool === null) {
|
195
196
|
throw new Error('call setDateTool to set the date tool library, such as: setDateTool(dayjs)');
|
@@ -201,6 +202,9 @@ const createDateFormatter = format => (date, {
|
|
201
202
|
if (tz) {
|
202
203
|
instance = instance.tz(tz);
|
203
204
|
}
|
205
|
+
if (isUtc) {
|
206
|
+
instance = instance.utc();
|
207
|
+
}
|
204
208
|
if (typeof locale !== 'undefined') {
|
205
209
|
instance = instance.locale(locale);
|
206
210
|
}
|
@@ -229,11 +233,13 @@ export function formatToDate(date, {
|
|
229
233
|
*/
|
230
234
|
export function formatToDatetime(date, {
|
231
235
|
locale = 'en',
|
232
|
-
tz
|
236
|
+
tz,
|
237
|
+
isUtc = false
|
233
238
|
} = {}) {
|
234
239
|
return createDateFormatter('lll')(date, {
|
235
240
|
locale,
|
236
|
-
tz
|
241
|
+
tz,
|
242
|
+
isUtc
|
237
243
|
});
|
238
244
|
}
|
239
245
|
export function detectWalletExtension() {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arcblock/ux",
|
3
|
-
"version": "2.13.
|
3
|
+
"version": "2.13.28",
|
4
4
|
"description": "Common used react components for arcblock products",
|
5
5
|
"keywords": [
|
6
6
|
"react",
|
@@ -71,14 +71,14 @@
|
|
71
71
|
"react": ">=18.2.0",
|
72
72
|
"react-router-dom": ">=6.22.3"
|
73
73
|
},
|
74
|
-
"gitHead": "
|
74
|
+
"gitHead": "345a8363b59137fc5691b68e6295b87c9efb028a",
|
75
75
|
"dependencies": {
|
76
76
|
"@arcblock/did-motif": "^1.1.13",
|
77
|
-
"@arcblock/icons": "^2.13.
|
78
|
-
"@arcblock/nft-display": "^2.13.
|
79
|
-
"@arcblock/react-hooks": "^2.13.
|
77
|
+
"@arcblock/icons": "^2.13.28",
|
78
|
+
"@arcblock/nft-display": "^2.13.28",
|
79
|
+
"@arcblock/react-hooks": "^2.13.28",
|
80
80
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
81
|
-
"@blocklet/theme": "^2.13.
|
81
|
+
"@blocklet/theme": "^2.13.28",
|
82
82
|
"@fontsource/roboto": "~5.1.1",
|
83
83
|
"@fontsource/ubuntu-mono": "^5.0.18",
|
84
84
|
"@iconify-icons/logos": "^1.2.36",
|
@@ -1,7 +1,8 @@
|
|
1
|
+
import { Box, Tooltip } from '@mui/material';
|
2
|
+
import { useState } from 'react';
|
1
3
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
2
4
|
import dayjs from 'dayjs';
|
3
5
|
import 'dayjs/locale/zh-cn';
|
4
|
-
import { Tooltip } from '@mui/material';
|
5
6
|
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
6
7
|
import utc from 'dayjs/plugin/utc';
|
7
8
|
import timezone from 'dayjs/plugin/timezone';
|
@@ -35,19 +36,29 @@ dayjs.updateLocale('zh-cn', {
|
|
35
36
|
// FIXME: @@ 此处不能真正的将 relativeTime 设置为支持中文
|
36
37
|
setDateTool(dayjs);
|
37
38
|
|
39
|
+
const translations: Record<Locale, { utc: string }> = {
|
40
|
+
en: {
|
41
|
+
utc: 'Your Timezone',
|
42
|
+
},
|
43
|
+
zh: {
|
44
|
+
utc: '你所在时区',
|
45
|
+
},
|
46
|
+
};
|
47
|
+
|
38
48
|
export interface RelativeTimeProps {
|
39
49
|
value: string | number;
|
40
50
|
locale?: Locale;
|
41
51
|
withoutSuffix?: false | true;
|
42
52
|
from?: string | number;
|
43
53
|
to?: string | number;
|
44
|
-
type?: 'relative' | 'absolute';
|
54
|
+
type?: 'relative' | 'absolute' | 'utc' | 'all';
|
45
55
|
tz?: string;
|
46
56
|
relativeRange?: number;
|
47
57
|
enableTooltip?: boolean;
|
58
|
+
showUTCPrefix?: boolean;
|
48
59
|
}
|
49
60
|
|
50
|
-
|
61
|
+
function useRelativeTime({
|
51
62
|
value,
|
52
63
|
locale = 'en',
|
53
64
|
withoutSuffix = false,
|
@@ -56,18 +67,36 @@ export default function RelativeTime({
|
|
56
67
|
type = 'relative',
|
57
68
|
tz,
|
58
69
|
relativeRange,
|
59
|
-
|
60
|
-
|
61
|
-
|
70
|
+
}: {
|
71
|
+
value: string | number;
|
72
|
+
locale?: Locale;
|
73
|
+
withoutSuffix?: boolean;
|
74
|
+
from?: string | number;
|
75
|
+
to?: string | number;
|
76
|
+
type?: 'relative' | 'absolute' | 'utc';
|
77
|
+
tz?: string;
|
78
|
+
relativeRange?: number;
|
79
|
+
}) {
|
80
|
+
const date = new Date();
|
81
|
+
const timeZoneOffset = date.getTimezoneOffset();
|
82
|
+
const sign = timeZoneOffset > 0 ? '-' : '+';
|
83
|
+
const hoursOffset = Math.abs(timeZoneOffset) / 60;
|
84
|
+
const isLocalUtc = timeZoneOffset === 0;
|
85
|
+
const [isUtc, setIsUtc] = useState(isLocalUtc);
|
86
|
+
|
62
87
|
if (!value) {
|
63
|
-
return '-';
|
88
|
+
return { innerContent: '-', popContent: '-', isUtc, setIsUtc, sign, hoursOffset };
|
64
89
|
}
|
65
90
|
|
66
91
|
const localeOption = locale === 'zh' ? 'zh-cn' : 'en-us';
|
67
|
-
|
92
|
+
let datetime = dayjs(value).locale(localeOption);
|
93
|
+
|
94
|
+
if (type === 'utc') {
|
95
|
+
datetime = dayjs(value).utc().locale(localeOption);
|
96
|
+
}
|
68
97
|
|
69
98
|
if (tz) {
|
70
|
-
datetime.tz(tz);
|
99
|
+
datetime = datetime.tz(tz);
|
71
100
|
}
|
72
101
|
|
73
102
|
const absoluteString = formatToDatetime(value, { locale: localeOption, tz });
|
@@ -97,9 +126,130 @@ export default function RelativeTime({
|
|
97
126
|
popContent = relativeString;
|
98
127
|
}
|
99
128
|
|
129
|
+
if (type === 'utc') {
|
130
|
+
if (isUtc) {
|
131
|
+
innerContent = formatToDatetime(value, { locale: localeOption, tz, isUtc: true });
|
132
|
+
popContent = formatToDatetime(value, { locale: localeOption, tz, isUtc: true });
|
133
|
+
} else {
|
134
|
+
innerContent = absoluteString;
|
135
|
+
popContent = relativeString;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
return { innerContent, popContent, isUtc, setIsUtc, sign, hoursOffset, relativeString, absoluteString };
|
140
|
+
}
|
141
|
+
|
142
|
+
function UTCChip({
|
143
|
+
locale,
|
144
|
+
isUtc,
|
145
|
+
sign,
|
146
|
+
hoursOffset,
|
147
|
+
setIsUtc,
|
148
|
+
showUTCPrefix = true,
|
149
|
+
}: {
|
150
|
+
locale: Locale;
|
151
|
+
isUtc?: boolean;
|
152
|
+
sign: string;
|
153
|
+
hoursOffset: number;
|
154
|
+
setIsUtc: (data: any) => void;
|
155
|
+
showUTCPrefix?: boolean;
|
156
|
+
}) {
|
157
|
+
const prefix = showUTCPrefix ? `${translations[locale].utc}: ` : '';
|
158
|
+
|
159
|
+
return (
|
160
|
+
<Box
|
161
|
+
component="span"
|
162
|
+
sx={{
|
163
|
+
color: 'inherit',
|
164
|
+
cursor: 'pointer',
|
165
|
+
border: '1px solid',
|
166
|
+
fontSize: '0.8rem',
|
167
|
+
borderColor: 'divider',
|
168
|
+
borderRadius: '20px',
|
169
|
+
padding: '4px 8px',
|
170
|
+
lineHeight: 1,
|
171
|
+
}}
|
172
|
+
onClick={() => setIsUtc((r: any) => !r)}>
|
173
|
+
{`${prefix}${isUtc ? 'UTC' : `UTC${sign}${hoursOffset}`}`}
|
174
|
+
</Box>
|
175
|
+
);
|
176
|
+
}
|
177
|
+
|
178
|
+
export default function RelativeTime({
|
179
|
+
value,
|
180
|
+
locale = 'en',
|
181
|
+
withoutSuffix = false,
|
182
|
+
from = '',
|
183
|
+
to = '',
|
184
|
+
type = 'relative',
|
185
|
+
tz,
|
186
|
+
relativeRange,
|
187
|
+
enableTooltip = true,
|
188
|
+
showUTCPrefix = true,
|
189
|
+
...rest
|
190
|
+
}: RelativeTimeProps) {
|
191
|
+
const { innerContent, popContent, isUtc, setIsUtc, sign, hoursOffset, relativeString } = useRelativeTime({
|
192
|
+
value,
|
193
|
+
locale,
|
194
|
+
withoutSuffix,
|
195
|
+
from,
|
196
|
+
to,
|
197
|
+
type: type === 'all' ? 'utc' : type,
|
198
|
+
tz,
|
199
|
+
relativeRange,
|
200
|
+
});
|
201
|
+
|
202
|
+
if (type === 'all') {
|
203
|
+
return (
|
204
|
+
<Tooltip title={undefined} placement="top-end" enterTouchDelay={0}>
|
205
|
+
<Box display="flex" alignItems="center" gap={0.5} width="max-content" {...rest}>
|
206
|
+
<Box component="span" {...rest} sx={{}}>
|
207
|
+
{innerContent}
|
208
|
+
</Box>
|
209
|
+
|
210
|
+
<Box component="span" sx={{ color: 'inherit' }}>
|
211
|
+
·
|
212
|
+
</Box>
|
213
|
+
|
214
|
+
<Box component="span" sx={{ color: 'text.secondary' }}>
|
215
|
+
{relativeString}
|
216
|
+
</Box>
|
217
|
+
|
218
|
+
<Box component="span" sx={{ color: 'inherit' }}>
|
219
|
+
·
|
220
|
+
</Box>
|
221
|
+
|
222
|
+
<UTCChip
|
223
|
+
locale={locale}
|
224
|
+
isUtc={isUtc}
|
225
|
+
sign={sign}
|
226
|
+
hoursOffset={hoursOffset}
|
227
|
+
setIsUtc={setIsUtc}
|
228
|
+
showUTCPrefix={showUTCPrefix}
|
229
|
+
/>
|
230
|
+
</Box>
|
231
|
+
</Tooltip>
|
232
|
+
);
|
233
|
+
}
|
234
|
+
|
100
235
|
return (
|
101
236
|
<Tooltip title={enableTooltip ? popContent : undefined} placement="top-end" enterTouchDelay={0}>
|
102
|
-
<
|
237
|
+
<Box display="flex" alignItems="center" gap={1} width="max-content">
|
238
|
+
<Box component="span" {...rest}>
|
239
|
+
{innerContent}
|
240
|
+
</Box>
|
241
|
+
|
242
|
+
{type === 'utc' && (
|
243
|
+
<UTCChip
|
244
|
+
locale={locale}
|
245
|
+
isUtc={isUtc}
|
246
|
+
sign={sign}
|
247
|
+
hoursOffset={hoursOffset}
|
248
|
+
setIsUtc={setIsUtc}
|
249
|
+
showUTCPrefix={showUTCPrefix}
|
250
|
+
/>
|
251
|
+
)}
|
252
|
+
</Box>
|
103
253
|
</Tooltip>
|
104
254
|
);
|
105
255
|
}
|
package/src/Tabs/index.tsx
CHANGED
@@ -46,7 +46,7 @@ function CardTabs({ tabs, current, onChange, ...rest }: CardTabsProps) {
|
|
46
46
|
},
|
47
47
|
'.MuiTabs-flexContainer': {
|
48
48
|
borderRadius: '100vw',
|
49
|
-
backgroundColor: 'grey.
|
49
|
+
backgroundColor: 'grey.100',
|
50
50
|
padding: 0.5,
|
51
51
|
display: 'inline-flex',
|
52
52
|
columnGap: 0.25,
|
@@ -65,7 +65,7 @@ function CardTabs({ tabs, current, onChange, ...rest }: CardTabsProps) {
|
|
65
65
|
textTransform: 'capitalize',
|
66
66
|
transition: 'background-color 0.2s ease',
|
67
67
|
'&.Mui-selected, &:hover': {
|
68
|
-
backgroundColor: '
|
68
|
+
backgroundColor: 'action.selected',
|
69
69
|
borderColor: 'grey.100',
|
70
70
|
color: 'grey.A700',
|
71
71
|
},
|
@@ -1,13 +1,20 @@
|
|
1
1
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import { GlobalStyles, PaletteMode } from '@mui/material';
|
4
|
-
import { ThemeProvider as MuiThemeProvider, Theme, useTheme } from '@mui/material/styles';
|
4
|
+
import { ThemeProvider as MuiThemeProvider, Theme, ThemeOptions, useTheme } from '@mui/material/styles';
|
5
5
|
import StyledEngineProvider from '@mui/material/StyledEngineProvider';
|
6
6
|
import CssBaseline from '@mui/material/CssBaseline';
|
7
7
|
import set from 'lodash/set';
|
8
8
|
import { BLOCKLET_THEME_PREFER_KEY } from '@blocklet/theme';
|
9
9
|
|
10
|
-
import {
|
10
|
+
import {
|
11
|
+
createTheme,
|
12
|
+
getDefaultThemePrefer,
|
13
|
+
isTheme,
|
14
|
+
isUxTheme,
|
15
|
+
lazyCreateDefaultTheme,
|
16
|
+
type UxThemeOptions,
|
17
|
+
} from './theme';
|
11
18
|
|
12
19
|
const defaultTheme = createTheme();
|
13
20
|
|
@@ -15,6 +22,7 @@ const defaultTheme = createTheme();
|
|
15
22
|
export interface ColorSchemeContextType {
|
16
23
|
mode: PaletteMode;
|
17
24
|
toggleMode: () => void;
|
25
|
+
changeMode: (mode: PaletteMode) => void;
|
18
26
|
prefer?: Prefer;
|
19
27
|
}
|
20
28
|
|
@@ -102,7 +110,7 @@ function DarkSchemeStyles({ className }: { className?: string }) {
|
|
102
110
|
return null;
|
103
111
|
}
|
104
112
|
|
105
|
-
export type UxTheme =
|
113
|
+
export type UxTheme = ThemeOptions | ((parentTheme: Theme, context?: { mode: PaletteMode }) => Theme);
|
106
114
|
export type Prefer = 'light' | 'dark' | 'system';
|
107
115
|
|
108
116
|
interface BaseThemeProviderProps {
|
@@ -113,7 +121,7 @@ interface BaseThemeProviderProps {
|
|
113
121
|
darkSchemeClass?: string;
|
114
122
|
}
|
115
123
|
|
116
|
-
/**
|
124
|
+
/** 快速配置 MUI 主题 */
|
117
125
|
function BaseThemeProvider({
|
118
126
|
children,
|
119
127
|
theme = defaultTheme,
|
@@ -144,7 +152,7 @@ interface ColorSchemeProviderProps extends BaseThemeProviderProps {
|
|
144
152
|
disableBlockletTheme?: boolean;
|
145
153
|
}
|
146
154
|
|
147
|
-
/**
|
155
|
+
/** 配置带颜色模式切换功能的 MUI 主题 */
|
148
156
|
function ColorSchemeProvider({
|
149
157
|
children,
|
150
158
|
theme: themeInput,
|
@@ -153,14 +161,21 @@ function ColorSchemeProvider({
|
|
153
161
|
...rest
|
154
162
|
}: ThemeProviderProps) {
|
155
163
|
const [mode, setMode] = useState<PaletteMode>(() => resolveMode(prefer));
|
164
|
+
const parentTheme = useTheme();
|
156
165
|
|
157
166
|
const _themeInput = useMemo(() => {
|
158
|
-
let result:
|
159
|
-
const
|
167
|
+
let result: UxThemeOptions = {};
|
168
|
+
const createBaseTheme = lazyCreateDefaultTheme(mode);
|
160
169
|
|
161
170
|
if (themeInput) {
|
162
171
|
if (typeof themeInput === 'function') {
|
163
|
-
|
172
|
+
const baseTheme = createBaseTheme();
|
173
|
+
|
174
|
+
if (isUxTheme(parentTheme)) {
|
175
|
+
result = { ...themeInput(parentTheme, { mode }) };
|
176
|
+
} else {
|
177
|
+
result = { ...themeInput(baseTheme, { mode }) };
|
178
|
+
}
|
164
179
|
} else {
|
165
180
|
result = { ...themeInput };
|
166
181
|
}
|
@@ -170,7 +185,7 @@ function ColorSchemeProvider({
|
|
170
185
|
set(result, 'mode', mode);
|
171
186
|
|
172
187
|
return result;
|
173
|
-
}, [mode, themeInput]);
|
188
|
+
}, [mode, themeInput, parentTheme]);
|
174
189
|
|
175
190
|
const theme = useMemo(() => {
|
176
191
|
return createTheme({ ..._themeInput, disableBlockletTheme });
|
@@ -183,13 +198,24 @@ function ColorSchemeProvider({
|
|
183
198
|
localStorage.setItem(BLOCKLET_THEME_PREFER_KEY, newMode);
|
184
199
|
}, [mode, setMode]);
|
185
200
|
|
201
|
+
const changeMode = useCallback(
|
202
|
+
(newMode: PaletteMode) => {
|
203
|
+
if (mode !== newMode) {
|
204
|
+
setMode(newMode);
|
205
|
+
localStorage.setItem(BLOCKLET_THEME_PREFER_KEY, newMode);
|
206
|
+
}
|
207
|
+
},
|
208
|
+
[mode, setMode]
|
209
|
+
);
|
210
|
+
|
186
211
|
const colorSchemeValue = useMemo(
|
187
212
|
() => ({
|
188
213
|
mode,
|
189
214
|
toggleMode,
|
215
|
+
changeMode,
|
190
216
|
prefer,
|
191
217
|
}),
|
192
|
-
[mode, prefer, toggleMode]
|
218
|
+
[mode, prefer, toggleMode, changeMode]
|
193
219
|
);
|
194
220
|
|
195
221
|
useEffect(() => {
|
package/src/Theme/theme.ts
CHANGED
@@ -20,6 +20,11 @@ export function isTheme(obj: any): obj is Theme {
|
|
20
20
|
return obj && typeof obj === 'object' && obj.palette && typeof obj.palette.getContrastText === 'function';
|
21
21
|
}
|
22
22
|
|
23
|
+
/** 是否是 UX Theme 对象 */
|
24
|
+
export function isUxTheme(obj: any): obj is Theme {
|
25
|
+
return isTheme(obj) && obj.__isUxTheme__ === true;
|
26
|
+
}
|
27
|
+
|
23
28
|
// 收集字体配置
|
24
29
|
export function collectFontFamilies(obj?: { fontFamily?: string }, fontSet: Set<string> = new Set()): Set<string> {
|
25
30
|
if (!obj || typeof obj !== 'object') return fontSet;
|
@@ -107,26 +112,26 @@ export function createDefaultThemeOptions(mode: PaletteMode = 'light') {
|
|
107
112
|
return BLOCKLET_THEME_LIGHT;
|
108
113
|
}
|
109
114
|
|
110
|
-
export interface
|
115
|
+
export interface UxThemeOptions extends ThemeOptions {
|
111
116
|
disableBlockletTheme?: boolean;
|
112
117
|
}
|
113
118
|
|
114
|
-
|
115
|
-
|
116
|
-
let config: Partial<Theme> | null = null;
|
119
|
+
export function lazyCreateDefaultTheme(mode: PaletteMode) {
|
120
|
+
let theme: Theme | null = null;
|
117
121
|
|
118
122
|
return () => {
|
119
|
-
if (
|
123
|
+
if (theme) return theme;
|
120
124
|
|
121
|
-
|
125
|
+
const options = deepmerge(createDefaultThemeOptions(mode), window.blocklet?.theme?.[mode] ?? {});
|
122
126
|
|
123
|
-
|
127
|
+
theme = _createTheme(options);
|
128
|
+
return theme;
|
124
129
|
};
|
125
130
|
}
|
126
131
|
|
127
132
|
// 主要处理 overrides
|
128
|
-
const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }:
|
129
|
-
const result:
|
133
|
+
const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }: UxThemeOptions) => {
|
134
|
+
const result: UxThemeOptions = {
|
130
135
|
palette,
|
131
136
|
components: {
|
132
137
|
...overrides,
|
@@ -138,7 +143,7 @@ const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }:
|
|
138
143
|
return result;
|
139
144
|
};
|
140
145
|
|
141
|
-
const
|
146
|
+
const defaultUxThemeOptions: UxThemeOptions = {
|
142
147
|
themeName: 'ArcBlock',
|
143
148
|
pageWidth: 'md',
|
144
149
|
disableBlockletTheme: false,
|
@@ -166,13 +171,13 @@ const defaultUserThemeOptions: UserThemeOptions = {
|
|
166
171
|
};
|
167
172
|
|
168
173
|
// https://material-ui.com/customization/default-theme/
|
169
|
-
export const create = (...args: Array<
|
174
|
+
export const create = (...args: Array<UxThemeOptions | ((baseTheme: Theme) => UxThemeOptions)>) => {
|
170
175
|
const defaultPrefer = getDefaultThemePrefer();
|
171
|
-
const
|
172
|
-
const userThemeOptions = args.reduce<
|
176
|
+
const createBaseTheme = lazyCreateDefaultTheme(defaultPrefer);
|
177
|
+
const userThemeOptions = args.reduce<UxThemeOptions>(
|
173
178
|
(acc, curr) =>
|
174
|
-
deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(
|
175
|
-
normalizeUserThemeOptions(
|
179
|
+
deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(createBaseTheme()) : curr)),
|
180
|
+
normalizeUserThemeOptions(defaultUxThemeOptions)
|
176
181
|
);
|
177
182
|
const prefer = userThemeOptions.mode || userThemeOptions.palette?.mode || defaultPrefer;
|
178
183
|
const blockletThemeOptions = window.blocklet?.theme?.[prefer] ?? {};
|
@@ -195,6 +200,7 @@ export const create = (...args: Array<UserThemeOptions | ((config: Partial<Theme
|
|
195
200
|
|
196
201
|
// 创建主题
|
197
202
|
const theme = _createTheme(mergedThemeOptions);
|
203
|
+
theme.__isUxTheme__ = true;
|
198
204
|
|
199
205
|
// 异步加载字体
|
200
206
|
const fonts = collectFontFamilies(theme.typography);
|
package/src/Util/index.ts
CHANGED
@@ -246,7 +246,7 @@ export function getDateTool() {
|
|
246
246
|
|
247
247
|
const createDateFormatter =
|
248
248
|
(format: string) =>
|
249
|
-
(date: string | number | Date, { locale, tz }: { locale?: Locale; tz?: string } = {}) => {
|
249
|
+
(date: string | number | Date, { locale, tz, isUtc }: { locale?: Locale; tz?: string; isUtc?: boolean } = {}) => {
|
250
250
|
if (dateTool === null) {
|
251
251
|
throw new Error('call setDateTool to set the date tool library, such as: setDateTool(dayjs)');
|
252
252
|
}
|
@@ -261,6 +261,10 @@ const createDateFormatter =
|
|
261
261
|
instance = instance.tz(tz);
|
262
262
|
}
|
263
263
|
|
264
|
+
if (isUtc) {
|
265
|
+
instance = instance.utc();
|
266
|
+
}
|
267
|
+
|
264
268
|
if (typeof locale !== 'undefined') {
|
265
269
|
instance = instance.locale(locale);
|
266
270
|
}
|
@@ -287,9 +291,9 @@ export function formatToDate(
|
|
287
291
|
*/
|
288
292
|
export function formatToDatetime(
|
289
293
|
date: string | number | Date,
|
290
|
-
{ locale = 'en', tz }: { locale?: Locale; tz?: string } = {}
|
294
|
+
{ locale = 'en', tz, isUtc = false }: { locale?: Locale; tz?: string; isUtc?: boolean } = {}
|
291
295
|
) {
|
292
|
-
return createDateFormatter('lll')(date, { locale, tz });
|
296
|
+
return createDateFormatter('lll')(date, { locale, tz, isUtc });
|
293
297
|
}
|
294
298
|
|
295
299
|
export function detectWalletExtension() {
|