@arcblock/ux 2.12.54 → 2.12.56
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.js +15 -5
- package/lib/Datatable/CustomToolbar.js +4 -3
- package/lib/Datatable/DatatableContext.js +3 -0
- package/lib/Datatable/index.d.ts +1 -0
- package/lib/Datatable/index.js +6 -0
- package/lib/Theme/theme.d.ts +7 -11
- package/lib/Theme/theme.js +60 -13
- package/package.json +9 -7
- package/src/Config/config-provider.tsx +17 -5
- package/src/Datatable/CustomToolbar.jsx +5 -4
- package/src/Datatable/DatatableContext.jsx +3 -0
- package/src/Datatable/index.jsx +6 -1
- package/src/Theme/theme.ts +69 -30
@@ -1,5 +1,5 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import { createContext, useContext, useMemo, useState, useCallback } from 'react';
|
2
|
+
import { createContext, useContext, useMemo, useState, useCallback, useEffect } from 'react';
|
3
3
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
4
4
|
import set from 'lodash/set';
|
5
5
|
import { LocaleProvider, useLocaleContext } from '../Locale/context';
|
@@ -28,11 +28,14 @@ export function ConfigProvider({
|
|
28
28
|
}) {
|
29
29
|
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
30
30
|
const [mode, setMode] = useState(() => {
|
31
|
-
|
32
|
-
|
33
|
-
return preferMode;
|
31
|
+
if (prefer) {
|
32
|
+
return prefer;
|
34
33
|
}
|
35
|
-
|
34
|
+
const localPrefer = localStorage.getItem(preferThemeModeKey);
|
35
|
+
if (localPrefer && (localPrefer === 'light' || localPrefer === 'dark')) {
|
36
|
+
return localPrefer;
|
37
|
+
}
|
38
|
+
return prefersDarkMode ? 'dark' : 'light';
|
36
39
|
});
|
37
40
|
const _themeOptions = useMemo(() => {
|
38
41
|
let result = {};
|
@@ -64,6 +67,13 @@ export function ConfigProvider({
|
|
64
67
|
themeOptions: _themeOptions,
|
65
68
|
toggleMode
|
66
69
|
}), [mode, _themeOptions, toggleMode]);
|
70
|
+
|
71
|
+
// change prefer manually
|
72
|
+
useEffect(() => {
|
73
|
+
if (prefer) {
|
74
|
+
setMode(prefer);
|
75
|
+
}
|
76
|
+
}, [prefer, setMode]);
|
67
77
|
return /*#__PURE__*/_jsx(ConfigContext.Provider, {
|
68
78
|
value: config,
|
69
79
|
children: /*#__PURE__*/_jsx(LocaleProvider, {
|
@@ -32,6 +32,7 @@ export default function CustomToolbar(props) {
|
|
32
32
|
const toolbarId = useRef(Math.random().toString(32).slice(2));
|
33
33
|
const [searchOpened, setSearchOpened] = useState(false);
|
34
34
|
const {
|
35
|
+
customPreButtons,
|
35
36
|
customButtons,
|
36
37
|
loading,
|
37
38
|
disabled
|
@@ -129,12 +130,12 @@ export default function CustomToolbar(props) {
|
|
129
130
|
}
|
130
131
|
});
|
131
132
|
}
|
132
|
-
const showMore = [!hidePrint, ...defaultButtons, ...customButtons].filter(e => !!e).length > 1 && isMobile;
|
133
|
+
const showMore = [...customPreButtons, !hidePrint, ...defaultButtons, ...customButtons].filter(e => !!e).length > 1 && isMobile;
|
133
134
|
const allPops = [];
|
134
135
|
|
135
136
|
// Large screens show the toolbar buttons directly, small screens show the drop-down menu style buttons
|
136
137
|
// The right-hand button of the form toolbar in desktop mode
|
137
|
-
const toolbarButtons = [...defaultButtons, ...customButtons].map((e, index) => {
|
138
|
+
const toolbarButtons = [...customPreButtons, ...defaultButtons, ...customButtons].map((e, index) => {
|
138
139
|
if (/*#__PURE__*/isValidElement(e)) {
|
139
140
|
return e;
|
140
141
|
}
|
@@ -189,7 +190,7 @@ export default function CustomToolbar(props) {
|
|
189
190
|
});
|
190
191
|
|
191
192
|
// The toolbar menu in the mobile to replace toolbarButtons
|
192
|
-
const menuItems = [...defaultButtons, ...customButtons].map((e, index) => {
|
193
|
+
const menuItems = [...customPreButtons, ...defaultButtons, ...customButtons].map((e, index) => {
|
193
194
|
const popId = getPopId(index);
|
194
195
|
let content;
|
195
196
|
if (/*#__PURE__*/isValidElement(e)) {
|
@@ -10,12 +10,15 @@ function DatatableProvider({
|
|
10
10
|
children
|
11
11
|
}) {
|
12
12
|
const [customButtons, setCustomButtons] = useState([]);
|
13
|
+
const [customPreButtons, setCustomPreButtons] = useState([]);
|
13
14
|
const [loading, setLoading] = useState(false);
|
14
15
|
const [disabled, setDisabled] = useState(false);
|
15
16
|
const [filterLabel, setFilterLabel] = useState('Filter');
|
16
17
|
const value = {
|
17
18
|
customButtons,
|
18
19
|
setCustomButtons,
|
20
|
+
customPreButtons,
|
21
|
+
setCustomPreButtons,
|
19
22
|
filterLabel,
|
20
23
|
setFilterLabel,
|
21
24
|
loading,
|
package/lib/Datatable/index.d.ts
CHANGED
@@ -29,6 +29,7 @@ export type DataTableProps = {
|
|
29
29
|
} & import("mui-datatables").MUIDataTableOptions;
|
30
30
|
style?: import("react").CSSProperties;
|
31
31
|
customButtons?: Array<DataTableCustomButton>;
|
32
|
+
customPreButtons?: Array<DataTableCustomButton>;
|
32
33
|
onChange?: (state: DataTableState, action: string) => void | Promise<void>;
|
33
34
|
loading?: false | true;
|
34
35
|
disabled?: false | true;
|
package/lib/Datatable/index.js
CHANGED
@@ -48,6 +48,7 @@ import { styled } from '../Theme';
|
|
48
48
|
* options?: { searchDebounceTime?: number } & import('mui-datatables').MUIDataTableOptions,
|
49
49
|
* style?: import('react').CSSProperties,
|
50
50
|
* customButtons?: Array<DataTableCustomButton>,
|
51
|
+
* customPreButtons?: Array<DataTableCustomButton>,
|
51
52
|
* onChange?: (state: DataTableState, action: string) => void | Promise<void>,
|
52
53
|
* loading?: false | true,
|
53
54
|
* disabled?: false | true,
|
@@ -166,6 +167,7 @@ function ReDataTable({
|
|
166
167
|
options,
|
167
168
|
// The options object is usually a property supported by mui-datatable
|
168
169
|
style,
|
170
|
+
customPreButtons,
|
169
171
|
customButtons,
|
170
172
|
onChange,
|
171
173
|
loading,
|
@@ -181,6 +183,7 @@ function ReDataTable({
|
|
181
183
|
}) {
|
182
184
|
const oldState = useRef(null);
|
183
185
|
const {
|
186
|
+
setCustomPreButtons,
|
184
187
|
setCustomButtons,
|
185
188
|
setFilterLabel,
|
186
189
|
setLoading,
|
@@ -271,6 +274,7 @@ function ReDataTable({
|
|
271
274
|
return e;
|
272
275
|
});
|
273
276
|
useEffect(() => setCustomButtons(customButtons || []), [customButtons]);
|
277
|
+
useEffect(() => setCustomPreButtons(customPreButtons || []), [customPreButtons]);
|
274
278
|
useEffect(() => setLoading(loading), [loading]);
|
275
279
|
useEffect(() => setDisabled(disabled), [disabled]);
|
276
280
|
let emptyEl;
|
@@ -435,6 +439,7 @@ ReDataTable.propTypes = {
|
|
435
439
|
locale: PropTypes.string,
|
436
440
|
loading: PropTypes.bool,
|
437
441
|
disabled: PropTypes.bool,
|
442
|
+
customPreButtons: PropTypes.array,
|
438
443
|
customButtons: PropTypes.array,
|
439
444
|
onChange: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
|
440
445
|
stripped: PropTypes.bool,
|
@@ -451,6 +456,7 @@ ReDataTable.defaultProps = {
|
|
451
456
|
locale: 'en',
|
452
457
|
loading: false,
|
453
458
|
disabled: false,
|
459
|
+
customPreButtons: [],
|
454
460
|
customButtons: [],
|
455
461
|
onChange: '',
|
456
462
|
stripped: false,
|
package/lib/Theme/theme.d.ts
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
import { Components, type ThemeOptions } from '@mui/material/styles';
|
2
2
|
import type { Typography } from '@mui/material/styles/createTypography';
|
3
|
-
import '@fontsource/
|
4
|
-
import '@fontsource/
|
5
|
-
import '@fontsource/
|
6
|
-
import '@fontsource/inter/latin-700.css';
|
7
|
-
import '@fontsource/inter/latin-ext-300.css';
|
8
|
-
import '@fontsource/inter/latin-ext-400.css';
|
9
|
-
import '@fontsource/inter/latin-ext-500.css';
|
10
|
-
import '@fontsource/inter/latin-ext-700.css';
|
3
|
+
import '@fontsource/roboto/400';
|
4
|
+
import '@fontsource/roboto/500';
|
5
|
+
import '@fontsource/roboto/700';
|
11
6
|
import { ThemeMode } from '../type';
|
12
7
|
declare module '@mui/material/styles' {
|
13
8
|
interface Theme {
|
@@ -39,11 +34,12 @@ declare module '@mui/material/styles/createTypography' {
|
|
39
34
|
interface TypographyOptions {
|
40
35
|
useNextVariants?: boolean;
|
41
36
|
color?: Record<string, string>;
|
42
|
-
button?: {
|
43
|
-
fontWeight?: number;
|
44
|
-
};
|
45
37
|
}
|
46
38
|
}
|
39
|
+
export declare function collectFontFamilies(obj?: {
|
40
|
+
fontFamily?: string;
|
41
|
+
}, fontSet?: Set<string>): Set<string>;
|
42
|
+
export declare function loadFonts(fonts: string[]): Promise<boolean>;
|
47
43
|
export declare function createDefaultThemeOptions(mode?: ThemeMode): ThemeOptions;
|
48
44
|
export declare const create: ({ mode, pageWidth, overrides, palette, components, ...rest }?: ThemeOptions) => import("@mui/material/styles").Theme;
|
49
45
|
export declare const createTheme: ({ mode, pageWidth, overrides, palette, components, ...rest }?: ThemeOptions) => import("@mui/material/styles").Theme;
|
package/lib/Theme/theme.js
CHANGED
@@ -2,15 +2,14 @@
|
|
2
2
|
// https://app.zeplin.io/styleguide/5d1436f1e97c2156f49c0725/colors
|
3
3
|
import { createTheme as _createTheme, responsiveFontSizes } from '@mui/material/styles';
|
4
4
|
import { deepmerge } from '@mui/utils';
|
5
|
-
|
6
|
-
|
7
|
-
import
|
8
|
-
import '@fontsource/
|
9
|
-
import
|
10
|
-
import '@fontsource/
|
11
|
-
import
|
12
|
-
import '@fontsource/
|
13
|
-
import '@fontsource/inter/latin-ext-700.css';
|
5
|
+
import webfontloader from 'webfontloader';
|
6
|
+
// 为了避免加载全量的字体导致打包后体积太大,目前只选择了 MUI 默认的 Roboto 字体
|
7
|
+
// eslint-disable-next-line import/no-unresolved
|
8
|
+
import '@fontsource/roboto/400';
|
9
|
+
// eslint-disable-next-line import/no-unresolved
|
10
|
+
import '@fontsource/roboto/500';
|
11
|
+
// eslint-disable-next-line import/no-unresolved
|
12
|
+
import '@fontsource/roboto/700';
|
14
13
|
import colors from '../Colors';
|
15
14
|
import { cleanedObj } from '../Util';
|
16
15
|
|
@@ -18,12 +17,56 @@ import { cleanedObj } from '../Util';
|
|
18
17
|
|
19
18
|
// 扩展 TypographyOptions
|
20
19
|
|
21
|
-
|
20
|
+
// 默认深色主题
|
21
|
+
const defaultDarkTheme = _createTheme({
|
22
22
|
palette: {
|
23
23
|
mode: 'dark'
|
24
24
|
}
|
25
25
|
});
|
26
|
-
|
26
|
+
|
27
|
+
// 收集字体配置
|
28
|
+
export function collectFontFamilies(obj, fontSet = new Set()) {
|
29
|
+
if (!obj || typeof obj !== 'object') return fontSet;
|
30
|
+
if (typeof obj.fontFamily === 'string') {
|
31
|
+
obj.fontFamily.replace(/"/g, '').split(',').map(font => font.trim()).filter(Boolean).forEach(font => fontSet.add(font));
|
32
|
+
}
|
33
|
+
Object.values(obj).forEach(value => {
|
34
|
+
if (typeof value === 'object') {
|
35
|
+
collectFontFamilies(value, fontSet);
|
36
|
+
}
|
37
|
+
});
|
38
|
+
return fontSet;
|
39
|
+
}
|
40
|
+
|
41
|
+
// 动态加载字体
|
42
|
+
const prevFonts = new Set(['Roboto', 'inherit']);
|
43
|
+
export function loadFonts(fonts) {
|
44
|
+
// 过滤出未加载的字体
|
45
|
+
const unloadedFonts = fonts.filter(font => !prevFonts.has(font));
|
46
|
+
|
47
|
+
// 如果所有字体都已加载,直接返回
|
48
|
+
if (unloadedFonts.length === 0) {
|
49
|
+
return Promise.resolve(true);
|
50
|
+
}
|
51
|
+
|
52
|
+
// record
|
53
|
+
unloadedFonts.forEach(font => prevFonts.add(font));
|
54
|
+
return new Promise(resolve => {
|
55
|
+
webfontloader.load({
|
56
|
+
google: {
|
57
|
+
families: unloadedFonts
|
58
|
+
},
|
59
|
+
active: () => resolve(true),
|
60
|
+
inactive: () => resolve(true),
|
61
|
+
fontinactive: (familyName, fvd) => {
|
62
|
+
prevFonts.delete(familyName);
|
63
|
+
console.warn(`font ${familyName} ${fvd} download failed`);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
});
|
67
|
+
}
|
68
|
+
|
69
|
+
// 创建默认主题配置
|
27
70
|
export function createDefaultThemeOptions(mode = 'light') {
|
28
71
|
const result = {
|
29
72
|
palette: {
|
@@ -44,7 +87,6 @@ export function createDefaultThemeOptions(mode = 'light') {
|
|
44
87
|
main: mode === 'light' ? '#222222' : colors.common.white,
|
45
88
|
gray: mode === 'light' ? colors.grey[500] : colors.grey[300]
|
46
89
|
},
|
47
|
-
fontFamily: DEFAULT_FONT_FAMILY,
|
48
90
|
// button 默认使用粗体
|
49
91
|
button: {
|
50
92
|
fontWeight: 700
|
@@ -95,10 +137,11 @@ export function createDefaultThemeOptions(mode = 'light') {
|
|
95
137
|
}
|
96
138
|
}
|
97
139
|
};
|
140
|
+
|
98
141
|
// 深色主题
|
99
142
|
if (mode === 'dark') {
|
100
143
|
result.palette = {
|
101
|
-
...
|
144
|
+
...defaultDarkTheme.palette,
|
102
145
|
background: {
|
103
146
|
paper: colors.grey[900],
|
104
147
|
default: colors.grey[900]
|
@@ -163,6 +206,10 @@ export const create = ({
|
|
163
206
|
const mergedThemeOptions = deepmerge(deepmerge(defaultThemeOptions, cleanedObj(blockletThemeOptions)), cleanedObj(userThemeOptions));
|
164
207
|
const theme = _createTheme(mergedThemeOptions);
|
165
208
|
|
209
|
+
// 异步加载字体
|
210
|
+
const fonts = collectFontFamilies(theme.typography);
|
211
|
+
loadFonts(Array.from(fonts));
|
212
|
+
|
166
213
|
/**
|
167
214
|
* 响应式字体,配置后,theme.typography 会变为下面的结构
|
168
215
|
* {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arcblock/ux",
|
3
|
-
"version": "2.12.
|
3
|
+
"version": "2.12.56",
|
4
4
|
"description": "Common used react components for arcblock products",
|
5
5
|
"keywords": [
|
6
6
|
"react",
|
@@ -47,6 +47,7 @@
|
|
47
47
|
"@types/pako": "^2.0.3",
|
48
48
|
"@types/react": "^18.3.4",
|
49
49
|
"@types/react-helmet": "^6.1.11",
|
50
|
+
"@types/webfontloader": "^1.6.38",
|
50
51
|
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
51
52
|
"@typescript-eslint/parser": "^8.7.0",
|
52
53
|
"babel-jest": "29",
|
@@ -69,14 +70,14 @@
|
|
69
70
|
"react": ">=18.2.0",
|
70
71
|
"react-router-dom": ">=6.22.3"
|
71
72
|
},
|
72
|
-
"gitHead": "
|
73
|
+
"gitHead": "dad60e296d45cc578ede5c25e2c051da0d5e3c5a",
|
73
74
|
"dependencies": {
|
74
75
|
"@arcblock/did-motif": "^1.1.13",
|
75
|
-
"@arcblock/icons": "^2.12.
|
76
|
-
"@arcblock/nft-display": "^2.12.
|
77
|
-
"@arcblock/react-hooks": "^2.12.
|
76
|
+
"@arcblock/icons": "^2.12.56",
|
77
|
+
"@arcblock/nft-display": "^2.12.56",
|
78
|
+
"@arcblock/react-hooks": "^2.12.56",
|
78
79
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
79
|
-
"@fontsource/
|
80
|
+
"@fontsource/roboto": "^5.2.5",
|
80
81
|
"@fontsource/ubuntu-mono": "^5.0.18",
|
81
82
|
"@iconify-icons/logos": "^1.2.36",
|
82
83
|
"@iconify-icons/material-symbols": "^1.2.58",
|
@@ -123,6 +124,7 @@
|
|
123
124
|
"topojson-client": "^3.1.0",
|
124
125
|
"type-fest": "^4.28.0",
|
125
126
|
"validator": "^13.9.0",
|
126
|
-
"versor": "^0.0.4"
|
127
|
+
"versor": "^0.0.4",
|
128
|
+
"webfontloader": "^1.6.28"
|
127
129
|
}
|
128
130
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { createContext, useContext, ReactNode, useMemo, useState, useCallback } from 'react';
|
1
|
+
import { createContext, useContext, ReactNode, useMemo, useState, useCallback, useEffect } from 'react';
|
2
2
|
import type { ThemeOptions } from '@mui/material/styles';
|
3
3
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
4
4
|
import set from 'lodash/set';
|
@@ -49,11 +49,16 @@ export function ConfigProvider({
|
|
49
49
|
}: ConfigProviderProps) {
|
50
50
|
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
51
51
|
const [mode, setMode] = useState<ThemeMode>(() => {
|
52
|
-
|
53
|
-
|
54
|
-
return preferMode;
|
52
|
+
if (prefer) {
|
53
|
+
return prefer;
|
55
54
|
}
|
56
|
-
|
55
|
+
|
56
|
+
const localPrefer = localStorage.getItem(preferThemeModeKey) as ThemeMode;
|
57
|
+
if (localPrefer && (localPrefer === 'light' || localPrefer === 'dark')) {
|
58
|
+
return localPrefer;
|
59
|
+
}
|
60
|
+
|
61
|
+
return prefersDarkMode ? 'dark' : 'light';
|
57
62
|
});
|
58
63
|
|
59
64
|
const _themeOptions = useMemo(() => {
|
@@ -92,6 +97,13 @@ export function ConfigProvider({
|
|
92
97
|
[mode, _themeOptions, toggleMode]
|
93
98
|
);
|
94
99
|
|
100
|
+
// change prefer manually
|
101
|
+
useEffect(() => {
|
102
|
+
if (prefer) {
|
103
|
+
setMode(prefer);
|
104
|
+
}
|
105
|
+
}, [prefer, setMode]);
|
106
|
+
|
95
107
|
return (
|
96
108
|
<ConfigContext.Provider value={config}>
|
97
109
|
<LocaleProvider
|
@@ -32,7 +32,7 @@ export default function CustomToolbar(props) {
|
|
32
32
|
const isMobile = useMobile();
|
33
33
|
const toolbarId = useRef(Math.random().toString(32).slice(2));
|
34
34
|
const [searchOpened, setSearchOpened] = useState(false);
|
35
|
-
const { customButtons, loading, disabled } = useDatatableContext();
|
35
|
+
const { customPreButtons, customButtons, loading, disabled } = useDatatableContext();
|
36
36
|
|
37
37
|
const {
|
38
38
|
data,
|
@@ -136,13 +136,14 @@ export default function CustomToolbar(props) {
|
|
136
136
|
});
|
137
137
|
}
|
138
138
|
|
139
|
-
const showMore =
|
139
|
+
const showMore =
|
140
|
+
[...customPreButtons, !hidePrint, ...defaultButtons, ...customButtons].filter((e) => !!e).length > 1 && isMobile;
|
140
141
|
|
141
142
|
const allPops = [];
|
142
143
|
|
143
144
|
// Large screens show the toolbar buttons directly, small screens show the drop-down menu style buttons
|
144
145
|
// The right-hand button of the form toolbar in desktop mode
|
145
|
-
const toolbarButtons = [...defaultButtons, ...customButtons].map((e, index) => {
|
146
|
+
const toolbarButtons = [...customPreButtons, ...defaultButtons, ...customButtons].map((e, index) => {
|
146
147
|
if (isValidElement(e)) {
|
147
148
|
return e;
|
148
149
|
}
|
@@ -198,7 +199,7 @@ export default function CustomToolbar(props) {
|
|
198
199
|
});
|
199
200
|
|
200
201
|
// The toolbar menu in the mobile to replace toolbarButtons
|
201
|
-
const menuItems = [...defaultButtons, ...customButtons].map((e, index) => {
|
202
|
+
const menuItems = [...customPreButtons, ...defaultButtons, ...customButtons].map((e, index) => {
|
202
203
|
const popId = getPopId(index);
|
203
204
|
|
204
205
|
let content;
|
@@ -7,6 +7,7 @@ const { Provider } = DatatableContext;
|
|
7
7
|
// eslint-disable-next-line react/prop-types
|
8
8
|
function DatatableProvider({ children }) {
|
9
9
|
const [customButtons, setCustomButtons] = useState([]);
|
10
|
+
const [customPreButtons, setCustomPreButtons] = useState([]);
|
10
11
|
const [loading, setLoading] = useState(false);
|
11
12
|
const [disabled, setDisabled] = useState(false);
|
12
13
|
const [filterLabel, setFilterLabel] = useState('Filter');
|
@@ -14,6 +15,8 @@ function DatatableProvider({ children }) {
|
|
14
15
|
const value = {
|
15
16
|
customButtons,
|
16
17
|
setCustomButtons,
|
18
|
+
customPreButtons,
|
19
|
+
setCustomPreButtons,
|
17
20
|
filterLabel,
|
18
21
|
setFilterLabel,
|
19
22
|
loading,
|
package/src/Datatable/index.jsx
CHANGED
@@ -47,6 +47,7 @@ import { styled } from '../Theme';
|
|
47
47
|
* options?: { searchDebounceTime?: number } & import('mui-datatables').MUIDataTableOptions,
|
48
48
|
* style?: import('react').CSSProperties,
|
49
49
|
* customButtons?: Array<DataTableCustomButton>,
|
50
|
+
* customPreButtons?: Array<DataTableCustomButton>,
|
50
51
|
* onChange?: (state: DataTableState, action: string) => void | Promise<void>,
|
51
52
|
* loading?: false | true,
|
52
53
|
* disabled?: false | true,
|
@@ -166,6 +167,7 @@ function ReDataTable({
|
|
166
167
|
locale,
|
167
168
|
options, // The options object is usually a property supported by mui-datatable
|
168
169
|
style,
|
170
|
+
customPreButtons,
|
169
171
|
customButtons,
|
170
172
|
onChange,
|
171
173
|
loading,
|
@@ -180,7 +182,7 @@ function ReDataTable({
|
|
180
182
|
...rest
|
181
183
|
}) {
|
182
184
|
const oldState = useRef(null);
|
183
|
-
const { setCustomButtons, setFilterLabel, setLoading, setDisabled } = useDatatableContext();
|
185
|
+
const { setCustomPreButtons, setCustomButtons, setFilterLabel, setLoading, setDisabled } = useDatatableContext();
|
184
186
|
|
185
187
|
const disabledCellStyle = {
|
186
188
|
cursor: 'not-allowed',
|
@@ -276,6 +278,7 @@ function ReDataTable({
|
|
276
278
|
});
|
277
279
|
|
278
280
|
useEffect(() => setCustomButtons(customButtons || []), [customButtons]);
|
281
|
+
useEffect(() => setCustomPreButtons(customPreButtons || []), [customPreButtons]);
|
279
282
|
useEffect(() => setLoading(loading), [loading]);
|
280
283
|
useEffect(() => setDisabled(disabled), [disabled]);
|
281
284
|
|
@@ -420,6 +423,7 @@ ReDataTable.propTypes = {
|
|
420
423
|
locale: PropTypes.string,
|
421
424
|
loading: PropTypes.bool,
|
422
425
|
disabled: PropTypes.bool,
|
426
|
+
customPreButtons: PropTypes.array,
|
423
427
|
customButtons: PropTypes.array,
|
424
428
|
onChange: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
|
425
429
|
stripped: PropTypes.bool,
|
@@ -437,6 +441,7 @@ ReDataTable.defaultProps = {
|
|
437
441
|
locale: 'en',
|
438
442
|
loading: false,
|
439
443
|
disabled: false,
|
444
|
+
customPreButtons: [],
|
440
445
|
customButtons: [],
|
441
446
|
onChange: '',
|
442
447
|
stripped: false,
|
package/src/Theme/theme.ts
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
import { createTheme as _createTheme, Components, responsiveFontSizes, type ThemeOptions } from '@mui/material/styles';
|
4
4
|
import { deepmerge } from '@mui/utils';
|
5
5
|
import type { Typography } from '@mui/material/styles/createTypography';
|
6
|
-
|
7
|
-
|
8
|
-
import
|
9
|
-
import '@fontsource/
|
10
|
-
import
|
11
|
-
import '@fontsource/
|
12
|
-
import
|
13
|
-
import '@fontsource/
|
14
|
-
|
6
|
+
import webfontloader from 'webfontloader';
|
7
|
+
// 为了避免加载全量的字体导致打包后体积太大,目前只选择了 MUI 默认的 Roboto 字体
|
8
|
+
// eslint-disable-next-line import/no-unresolved
|
9
|
+
import '@fontsource/roboto/400';
|
10
|
+
// eslint-disable-next-line import/no-unresolved
|
11
|
+
import '@fontsource/roboto/500';
|
12
|
+
// eslint-disable-next-line import/no-unresolved
|
13
|
+
import '@fontsource/roboto/700';
|
14
|
+
|
15
15
|
import colors from '../Colors';
|
16
16
|
import { ThemeMode } from '../type';
|
17
17
|
import { cleanedObj } from '../Util';
|
@@ -48,29 +48,64 @@ declare module '@mui/material/styles/createTypography' {
|
|
48
48
|
interface TypographyOptions {
|
49
49
|
useNextVariants?: boolean;
|
50
50
|
color?: Record<string, string>;
|
51
|
-
button?: {
|
52
|
-
fontWeight?: number;
|
53
|
-
};
|
54
51
|
}
|
55
52
|
}
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
'
|
63
|
-
|
64
|
-
'
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
54
|
+
// 默认深色主题
|
55
|
+
const defaultDarkTheme = _createTheme({ palette: { mode: 'dark' } });
|
56
|
+
|
57
|
+
// 收集字体配置
|
58
|
+
export function collectFontFamilies(obj?: { fontFamily?: string }, fontSet: Set<string> = new Set()): Set<string> {
|
59
|
+
if (!obj || typeof obj !== 'object') return fontSet;
|
60
|
+
|
61
|
+
if (typeof obj.fontFamily === 'string') {
|
62
|
+
obj.fontFamily
|
63
|
+
.replace(/"/g, '')
|
64
|
+
.split(',')
|
65
|
+
.map((font: string) => font.trim())
|
66
|
+
.filter(Boolean)
|
67
|
+
.forEach((font: string) => fontSet.add(font));
|
68
|
+
}
|
69
|
+
|
70
|
+
Object.values(obj).forEach((value) => {
|
71
|
+
if (typeof value === 'object') {
|
72
|
+
collectFontFamilies(value, fontSet);
|
73
|
+
}
|
74
|
+
});
|
75
|
+
|
76
|
+
return fontSet;
|
77
|
+
}
|
78
|
+
|
79
|
+
// 动态加载字体
|
80
|
+
const prevFonts = new Set<string>(['Roboto', 'inherit']);
|
81
|
+
export function loadFonts(fonts: string[]) {
|
82
|
+
// 过滤出未加载的字体
|
83
|
+
const unloadedFonts = fonts.filter((font) => !prevFonts.has(font));
|
73
84
|
|
85
|
+
// 如果所有字体都已加载,直接返回
|
86
|
+
if (unloadedFonts.length === 0) {
|
87
|
+
return Promise.resolve(true);
|
88
|
+
}
|
89
|
+
|
90
|
+
// record
|
91
|
+
unloadedFonts.forEach((font) => prevFonts.add(font));
|
92
|
+
|
93
|
+
return new Promise<boolean>((resolve) => {
|
94
|
+
webfontloader.load({
|
95
|
+
google: {
|
96
|
+
families: unloadedFonts,
|
97
|
+
},
|
98
|
+
active: () => resolve(true),
|
99
|
+
inactive: () => resolve(true),
|
100
|
+
fontinactive: (familyName, fvd) => {
|
101
|
+
prevFonts.delete(familyName);
|
102
|
+
console.warn(`font ${familyName} ${fvd} download failed`);
|
103
|
+
},
|
104
|
+
});
|
105
|
+
});
|
106
|
+
}
|
107
|
+
|
108
|
+
// 创建默认主题配置
|
74
109
|
export function createDefaultThemeOptions(mode: ThemeMode = 'light'): ThemeOptions {
|
75
110
|
const result: ThemeOptions = {
|
76
111
|
palette: {
|
@@ -91,7 +126,6 @@ export function createDefaultThemeOptions(mode: ThemeMode = 'light'): ThemeOptio
|
|
91
126
|
main: mode === 'light' ? '#222222' : colors.common.white,
|
92
127
|
gray: mode === 'light' ? colors.grey[500] : colors.grey[300],
|
93
128
|
},
|
94
|
-
fontFamily: DEFAULT_FONT_FAMILY,
|
95
129
|
// button 默认使用粗体
|
96
130
|
button: {
|
97
131
|
fontWeight: 700,
|
@@ -142,10 +176,11 @@ export function createDefaultThemeOptions(mode: ThemeMode = 'light'): ThemeOptio
|
|
142
176
|
},
|
143
177
|
},
|
144
178
|
};
|
179
|
+
|
145
180
|
// 深色主题
|
146
181
|
if (mode === 'dark') {
|
147
182
|
result.palette = {
|
148
|
-
...
|
183
|
+
...defaultDarkTheme.palette,
|
149
184
|
background: {
|
150
185
|
paper: colors.grey[900],
|
151
186
|
default: colors.grey[900],
|
@@ -215,6 +250,10 @@ export const create = ({
|
|
215
250
|
|
216
251
|
const theme = _createTheme(mergedThemeOptions);
|
217
252
|
|
253
|
+
// 异步加载字体
|
254
|
+
const fonts = collectFontFamilies(theme.typography);
|
255
|
+
loadFonts(Array.from(fonts));
|
256
|
+
|
218
257
|
/**
|
219
258
|
* 响应式字体,配置后,theme.typography 会变为下面的结构
|
220
259
|
* {
|