@particle-network/ui-react 0.3.2 → 0.4.0-beta.1
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/dist/components/UXEmpty/index.js +1 -1
- package/dist/components/UXInput/index.d.ts +1 -1
- package/dist/components/UXInput/input.extend.d.ts +1 -1
- package/dist/components/UXThemeSwitch/index.d.ts +6 -0
- package/dist/components/UXThemeSwitch/index.js +6 -0
- package/dist/components/UXThemeSwitch/theme-data.d.ts +28 -0
- package/dist/components/UXThemeSwitch/theme-data.js +304 -0
- package/dist/components/UXThemeSwitch/theme-item.d.ts +7 -0
- package/dist/components/UXThemeSwitch/theme-item.js +145 -0
- package/dist/components/UXThemeSwitch/theme-switch.d.ts +8 -0
- package/dist/components/UXThemeSwitch/theme-switch.js +149 -0
- package/dist/components/UXThemeSwitch/use-color-scheme.d.ts +1 -0
- package/dist/components/UXThemeSwitch/use-color-scheme.js +6 -0
- package/dist/components/UXThemeSwitch/use-quote-color.d.ts +6 -0
- package/dist/components/UXThemeSwitch/use-quote-color.js +12 -0
- package/dist/components/UXThemeSwitch/use-theme-color.d.ts +19 -0
- package/dist/components/UXThemeSwitch/use-theme-color.js +6 -0
- package/dist/components/UXThemeSwitch/use-theme-store.d.ts +56 -0
- package/dist/components/UXThemeSwitch/use-theme-store.js +44 -0
- package/dist/components/UXThemeSwitch/use-theme.d.ts +18 -0
- package/dist/components/UXThemeSwitch/use-theme.js +126 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/hooks/useI18n.d.ts +12 -0
- package/dist/hooks/useI18n.js +24 -0
- package/dist/utils/input-classes.d.ts +0 -32
- package/dist/utils/input-classes.js +5 -23
- package/package.json +6 -5
- package/tailwind-preset.js +804 -44
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Drawer, DrawerBody, DrawerContent, DrawerFooter, DrawerHeader } from "@heroui/drawer";
|
|
4
|
+
import { useDisclosure } from "@heroui/use-disclosure";
|
|
5
|
+
import { ThemeSwitchIcon } from "@particle-network/icons/web";
|
|
6
|
+
import { useI18n } from "../../hooks/index.js";
|
|
7
|
+
import { Flex, HStack, VStack } from "../layout/index.js";
|
|
8
|
+
import { Text } from "../typography/Text.js";
|
|
9
|
+
import { UXButton } from "../UXButton/index.js";
|
|
10
|
+
import { UXDivider } from "../UXDivider/index.js";
|
|
11
|
+
import { UXInput } from "../UXInput/index.js";
|
|
12
|
+
import { UXSpinner } from "../UXSpinner/index.js";
|
|
13
|
+
import { themeData } from "./theme-data.js";
|
|
14
|
+
import { ThemeItem } from "./theme-item.js";
|
|
15
|
+
import { useTheme } from "./use-theme.js";
|
|
16
|
+
const UXThemeSwitchDrawer = ({ isOpen, onClose, onOpenChange, ...props })=>{
|
|
17
|
+
const i18n = useI18n();
|
|
18
|
+
const { selectedTheme, setSelectedTheme, savedTheme, setSavedTheme, selectedFontLink, setSelectedFontLink, savedFontLink, setSavedFontLink, fontName, fontLoadStatus, fontLoadError } = useTheme();
|
|
19
|
+
const handleOpenChange = (_isOpen)=>{
|
|
20
|
+
onOpenChange?.(_isOpen);
|
|
21
|
+
if (!_isOpen) {
|
|
22
|
+
setSelectedTheme(savedTheme);
|
|
23
|
+
setSelectedFontLink(savedFontLink);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const handleApplyTheme = ()=>{
|
|
27
|
+
setSavedTheme(selectedTheme);
|
|
28
|
+
setSavedFontLink(selectedFontLink);
|
|
29
|
+
onClose?.();
|
|
30
|
+
};
|
|
31
|
+
const handleReset = ()=>{
|
|
32
|
+
setSelectedTheme(savedTheme);
|
|
33
|
+
setSelectedFontLink(savedFontLink);
|
|
34
|
+
};
|
|
35
|
+
return /*#__PURE__*/ jsx(Drawer, {
|
|
36
|
+
isOpen: isOpen,
|
|
37
|
+
backdrop: "transparent",
|
|
38
|
+
onOpenChange: handleOpenChange,
|
|
39
|
+
...props,
|
|
40
|
+
children: /*#__PURE__*/ jsxs(DrawerContent, {
|
|
41
|
+
children: [
|
|
42
|
+
/*#__PURE__*/ jsx(DrawerHeader, {
|
|
43
|
+
className: "flex flex-col gap-1",
|
|
44
|
+
children: i18n.theme.title
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ jsxs(DrawerBody, {
|
|
47
|
+
children: [
|
|
48
|
+
/*#__PURE__*/ jsx(Flex, {
|
|
49
|
+
wrap: true,
|
|
50
|
+
justify: "between",
|
|
51
|
+
className: "gap-y-5",
|
|
52
|
+
children: themeData.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
|
|
53
|
+
isSelected: selectedTheme.id === theme.id,
|
|
54
|
+
onClick: ()=>setSelectedTheme(theme),
|
|
55
|
+
...theme
|
|
56
|
+
}, theme.id))
|
|
57
|
+
}),
|
|
58
|
+
/*#__PURE__*/ jsx(UXDivider, {
|
|
59
|
+
className: "my-lg"
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ jsxs(VStack, {
|
|
62
|
+
gap: "md",
|
|
63
|
+
children: [
|
|
64
|
+
/*#__PURE__*/ jsx(Text, {
|
|
65
|
+
body1Bold: true,
|
|
66
|
+
children: i18n.theme.font.title
|
|
67
|
+
}),
|
|
68
|
+
/*#__PURE__*/ jsx(UXInput, {
|
|
69
|
+
isClearable: true,
|
|
70
|
+
startContent: 'loading' === fontLoadStatus && /*#__PURE__*/ jsx(UXSpinner, {
|
|
71
|
+
size: 18
|
|
72
|
+
}),
|
|
73
|
+
isInvalid: 'error' === fontLoadStatus,
|
|
74
|
+
className: "w-full",
|
|
75
|
+
placeholder: i18n.theme.font.placeholder,
|
|
76
|
+
value: selectedFontLink,
|
|
77
|
+
description: /*#__PURE__*/ jsxs(Fragment, {
|
|
78
|
+
children: [
|
|
79
|
+
'success' === fontLoadStatus && /*#__PURE__*/ jsxs(Text, {
|
|
80
|
+
body3Bold: true,
|
|
81
|
+
color: "success",
|
|
82
|
+
children: [
|
|
83
|
+
i18n.theme.font.success,
|
|
84
|
+
fontName
|
|
85
|
+
]
|
|
86
|
+
}),
|
|
87
|
+
'error' === fontLoadStatus && fontLoadError && /*#__PURE__*/ jsx(Text, {
|
|
88
|
+
body3Bold: true,
|
|
89
|
+
color: "danger",
|
|
90
|
+
children: fontLoadError
|
|
91
|
+
})
|
|
92
|
+
]
|
|
93
|
+
}),
|
|
94
|
+
onValueChange: setSelectedFontLink
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
})
|
|
98
|
+
]
|
|
99
|
+
}),
|
|
100
|
+
/*#__PURE__*/ jsx(DrawerFooter, {
|
|
101
|
+
className: "mb-8",
|
|
102
|
+
children: /*#__PURE__*/ jsxs(HStack, {
|
|
103
|
+
fullWidth: true,
|
|
104
|
+
gap: "lg",
|
|
105
|
+
children: [
|
|
106
|
+
/*#__PURE__*/ jsx(UXButton, {
|
|
107
|
+
fullWidth: true,
|
|
108
|
+
size: "lg",
|
|
109
|
+
onPress: handleReset,
|
|
110
|
+
children: i18n.theme.reset
|
|
111
|
+
}),
|
|
112
|
+
/*#__PURE__*/ jsx(UXButton, {
|
|
113
|
+
fullWidth: true,
|
|
114
|
+
isDisabled: 'error' === fontLoadStatus,
|
|
115
|
+
size: "lg",
|
|
116
|
+
color: "primary",
|
|
117
|
+
onPress: handleApplyTheme,
|
|
118
|
+
children: i18n.theme.apply
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
]
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
const UXThemeSwitch = ({ children })=>{
|
|
128
|
+
const { isOpen, onOpen, onClose, onOpenChange } = useDisclosure();
|
|
129
|
+
const renderChildren = ()=>{
|
|
130
|
+
if (children) return children(onOpen);
|
|
131
|
+
return /*#__PURE__*/ jsx(UXButton, {
|
|
132
|
+
isIconOnly: true,
|
|
133
|
+
variant: "light",
|
|
134
|
+
onPress: onOpen,
|
|
135
|
+
children: /*#__PURE__*/ jsx(ThemeSwitchIcon, {})
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
139
|
+
children: [
|
|
140
|
+
renderChildren(),
|
|
141
|
+
/*#__PURE__*/ jsx(UXThemeSwitchDrawer, {
|
|
142
|
+
isOpen: isOpen,
|
|
143
|
+
onClose: onClose,
|
|
144
|
+
onOpenChange: onOpenChange
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
export { UXThemeSwitch, UXThemeSwitchDrawer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useColorScheme: () => "dark" | "light";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useThemeStore } from "./use-theme-store.js";
|
|
2
|
+
const useQuoteColor = ()=>{
|
|
3
|
+
const { selectedTheme } = useThemeStore();
|
|
4
|
+
const { bullish, bearish } = selectedTheme.colorVariables;
|
|
5
|
+
return {
|
|
6
|
+
bullish,
|
|
7
|
+
bearish,
|
|
8
|
+
upColor: bullish,
|
|
9
|
+
downColor: bearish
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export { useQuoteColor };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const useThemeColor: () => {
|
|
2
|
+
foreground: string;
|
|
3
|
+
secondary: string;
|
|
4
|
+
tertiary: string;
|
|
5
|
+
primary: string;
|
|
6
|
+
success: string;
|
|
7
|
+
danger: string;
|
|
8
|
+
alert: string;
|
|
9
|
+
warning: string;
|
|
10
|
+
gold: string;
|
|
11
|
+
background: string;
|
|
12
|
+
'background-200': string;
|
|
13
|
+
'background-300': string;
|
|
14
|
+
'background-400': string;
|
|
15
|
+
overlay: string;
|
|
16
|
+
divider: string;
|
|
17
|
+
bullish: string;
|
|
18
|
+
bearish: string;
|
|
19
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type ThemeItemType } from './theme-data';
|
|
2
|
+
export type FontLoadStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
3
|
+
interface State {
|
|
4
|
+
/**
|
|
5
|
+
* 临时选中的 theme(用于预览)
|
|
6
|
+
*/
|
|
7
|
+
selectedTheme: ThemeItemType;
|
|
8
|
+
/**
|
|
9
|
+
* 保存的主题
|
|
10
|
+
*/
|
|
11
|
+
savedTheme: ThemeItemType;
|
|
12
|
+
/**
|
|
13
|
+
* 临时输入的字体链接(用于预览)
|
|
14
|
+
*/
|
|
15
|
+
selectedFontLink: string;
|
|
16
|
+
/**
|
|
17
|
+
* 保存的字体链接
|
|
18
|
+
*/
|
|
19
|
+
savedFontLink: string;
|
|
20
|
+
/**
|
|
21
|
+
* 应用的字体名称
|
|
22
|
+
*/
|
|
23
|
+
fontName: string;
|
|
24
|
+
/**
|
|
25
|
+
* 字体加载状态
|
|
26
|
+
*/
|
|
27
|
+
fontLoadStatus: FontLoadStatus;
|
|
28
|
+
/**
|
|
29
|
+
* 字体加载错误信息
|
|
30
|
+
*/
|
|
31
|
+
fontLoadError: string | null;
|
|
32
|
+
}
|
|
33
|
+
interface Actions {
|
|
34
|
+
setSelectedTheme: (theme: ThemeItemType) => void;
|
|
35
|
+
setSavedTheme: (theme: ThemeItemType) => void;
|
|
36
|
+
setSelectedFontLink: (link: string) => void;
|
|
37
|
+
setSavedFontLink: (link: string) => void;
|
|
38
|
+
setFontLoadStatus: (status: FontLoadStatus) => void;
|
|
39
|
+
setFontLoadError: (error: string | null) => void;
|
|
40
|
+
setFontName: (name: string) => void;
|
|
41
|
+
}
|
|
42
|
+
type ThemeStore = State & Actions;
|
|
43
|
+
export declare const useThemeStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ThemeStore>, "setState" | "persist"> & {
|
|
44
|
+
setState(partial: ThemeStore | Partial<ThemeStore> | ((state: ThemeStore) => ThemeStore | Partial<ThemeStore>), replace?: false | undefined): unknown;
|
|
45
|
+
setState(state: ThemeStore | ((state: ThemeStore) => ThemeStore), replace: true): unknown;
|
|
46
|
+
persist: {
|
|
47
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ThemeStore, unknown, unknown>>) => void;
|
|
48
|
+
clearStorage: () => void;
|
|
49
|
+
rehydrate: () => Promise<void> | void;
|
|
50
|
+
hasHydrated: () => boolean;
|
|
51
|
+
onHydrate: (fn: (state: ThemeStore) => void) => () => void;
|
|
52
|
+
onFinishHydration: (fn: (state: ThemeStore) => void) => () => void;
|
|
53
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<ThemeStore, unknown, unknown>>;
|
|
54
|
+
};
|
|
55
|
+
}>;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
import { createJSONStorage, persist } from "zustand/middleware";
|
|
3
|
+
import { themeData } from "./theme-data.js";
|
|
4
|
+
const useThemeStore = create()(persist((set)=>({
|
|
5
|
+
selectedTheme: themeData["0"],
|
|
6
|
+
savedTheme: themeData["0"],
|
|
7
|
+
selectedFontLink: '',
|
|
8
|
+
savedFontLink: '',
|
|
9
|
+
fontName: '',
|
|
10
|
+
fontLoadStatus: 'idle',
|
|
11
|
+
fontLoadError: null,
|
|
12
|
+
setSelectedTheme: (theme)=>set({
|
|
13
|
+
selectedTheme: theme
|
|
14
|
+
}),
|
|
15
|
+
setSavedTheme: (theme)=>set({
|
|
16
|
+
savedTheme: theme
|
|
17
|
+
}),
|
|
18
|
+
setSelectedFontLink: (link)=>set({
|
|
19
|
+
selectedFontLink: link
|
|
20
|
+
}),
|
|
21
|
+
setSavedFontLink: (link)=>set({
|
|
22
|
+
savedFontLink: link
|
|
23
|
+
}),
|
|
24
|
+
setFontLoadStatus: (status)=>set({
|
|
25
|
+
fontLoadStatus: status
|
|
26
|
+
}),
|
|
27
|
+
setFontLoadError: (error)=>set({
|
|
28
|
+
fontLoadError: error
|
|
29
|
+
}),
|
|
30
|
+
setFontName: (name)=>set({
|
|
31
|
+
fontName: name
|
|
32
|
+
})
|
|
33
|
+
}), {
|
|
34
|
+
name: 'ux-theme',
|
|
35
|
+
storage: createJSONStorage(()=>'undefined' != typeof window ? window.localStorage : {}),
|
|
36
|
+
partialize: (state)=>({
|
|
37
|
+
selectedTheme: state.selectedTheme,
|
|
38
|
+
savedTheme: state.savedTheme,
|
|
39
|
+
fontName: state.fontName,
|
|
40
|
+
selectedFontLink: state.selectedFontLink,
|
|
41
|
+
savedFontLink: state.savedFontLink
|
|
42
|
+
})
|
|
43
|
+
}));
|
|
44
|
+
export { useThemeStore };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ThemeItemType } from './theme-data';
|
|
2
|
+
import { type FontLoadStatus } from './use-theme-store';
|
|
3
|
+
/**
|
|
4
|
+
* UX 主题管理 Hook
|
|
5
|
+
*/
|
|
6
|
+
export declare const useTheme: () => {
|
|
7
|
+
selectedTheme: ThemeItemType;
|
|
8
|
+
setSelectedTheme: (theme: ThemeItemType) => void;
|
|
9
|
+
savedTheme: ThemeItemType;
|
|
10
|
+
setSavedTheme: (theme: ThemeItemType) => void;
|
|
11
|
+
selectedFontLink: string;
|
|
12
|
+
setSelectedFontLink: (link: string) => void;
|
|
13
|
+
savedFontLink: string;
|
|
14
|
+
setSavedFontLink: (link: string) => void;
|
|
15
|
+
fontLoadStatus: FontLoadStatus;
|
|
16
|
+
fontLoadError: string | null;
|
|
17
|
+
fontName: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useDebounceFn } from "ahooks";
|
|
3
|
+
import { themeKeys } from "./theme-data.js";
|
|
4
|
+
import { useThemeStore } from "./use-theme-store.js";
|
|
5
|
+
const DEFAULT_FONT_FAMILY = 'ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji';
|
|
6
|
+
const applyTheme = (theme)=>{
|
|
7
|
+
if ('undefined' == typeof window) return;
|
|
8
|
+
const root = document.documentElement;
|
|
9
|
+
root.setAttribute('data-theme', theme.colorScheme);
|
|
10
|
+
root.setAttribute('data-prefers-color', theme.colorScheme);
|
|
11
|
+
themeKeys.forEach((key)=>{
|
|
12
|
+
root.classList.remove(key);
|
|
13
|
+
});
|
|
14
|
+
root.classList.add(theme.id);
|
|
15
|
+
};
|
|
16
|
+
const extractFontFamilyFromLink = (link)=>{
|
|
17
|
+
if (!link) return null;
|
|
18
|
+
try {
|
|
19
|
+
const url = new URL(link);
|
|
20
|
+
const familyParam = url.searchParams.get('family');
|
|
21
|
+
if (!familyParam) return null;
|
|
22
|
+
const fontName = familyParam.split(':')[0].replace(/\+/g, ' ');
|
|
23
|
+
return fontName;
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const loadGoogleFont = (link, options)=>{
|
|
29
|
+
const { setFontLoadStatus, setFontLoadError, setFontName } = options;
|
|
30
|
+
if ('undefined' == typeof window) return;
|
|
31
|
+
const existingLink = document.getElementById('ux-google-font-link');
|
|
32
|
+
if (existingLink) existingLink.remove();
|
|
33
|
+
if (!link?.trim()) {
|
|
34
|
+
document.documentElement.style.setProperty('--ux-font-family', DEFAULT_FONT_FAMILY);
|
|
35
|
+
document.body.style.fontFamily = DEFAULT_FONT_FAMILY;
|
|
36
|
+
setFontLoadStatus('idle');
|
|
37
|
+
setFontLoadError(null);
|
|
38
|
+
setFontName('');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setFontLoadStatus('loading');
|
|
42
|
+
setFontLoadError(null);
|
|
43
|
+
const linkElement = document.createElement('link');
|
|
44
|
+
linkElement.id = 'ux-google-font-link';
|
|
45
|
+
linkElement.rel = 'stylesheet';
|
|
46
|
+
linkElement.href = link;
|
|
47
|
+
linkElement.onload = ()=>{
|
|
48
|
+
setFontLoadStatus('success');
|
|
49
|
+
setFontLoadError(null);
|
|
50
|
+
const fontFamily = extractFontFamilyFromLink(link);
|
|
51
|
+
if (fontFamily) {
|
|
52
|
+
document.documentElement.style.setProperty('--ux-font-family', `"${fontFamily}", ${DEFAULT_FONT_FAMILY}`);
|
|
53
|
+
document.body.style.fontFamily = `"${fontFamily}", ${DEFAULT_FONT_FAMILY}`;
|
|
54
|
+
setFontName(fontFamily);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
linkElement.onerror = ()=>{
|
|
58
|
+
const errorMessage = '字体加载失败,请检查链接是否正确';
|
|
59
|
+
setFontLoadStatus('error');
|
|
60
|
+
setFontLoadError(errorMessage);
|
|
61
|
+
setFontName('');
|
|
62
|
+
document.documentElement.style.setProperty('--ux-font-family', DEFAULT_FONT_FAMILY);
|
|
63
|
+
document.body.style.fontFamily = DEFAULT_FONT_FAMILY;
|
|
64
|
+
};
|
|
65
|
+
document.head.appendChild(linkElement);
|
|
66
|
+
};
|
|
67
|
+
const useTheme = ()=>{
|
|
68
|
+
const selectedTheme = useThemeStore((state)=>state.selectedTheme);
|
|
69
|
+
const savedTheme = useThemeStore((state)=>state.savedTheme);
|
|
70
|
+
const selectedFontLink = useThemeStore((state)=>state.selectedFontLink);
|
|
71
|
+
const savedFontLink = useThemeStore((state)=>state.savedFontLink);
|
|
72
|
+
const fontName = useThemeStore((state)=>state.fontName);
|
|
73
|
+
const fontLoadStatus = useThemeStore((state)=>state.fontLoadStatus);
|
|
74
|
+
const fontLoadError = useThemeStore((state)=>state.fontLoadError);
|
|
75
|
+
const storeSetSelectedTheme = useThemeStore((state)=>state.setSelectedTheme);
|
|
76
|
+
const storeSetSavedTheme = useThemeStore((state)=>state.setSavedTheme);
|
|
77
|
+
const storeSetSelectedFontLink = useThemeStore((state)=>state.setSelectedFontLink);
|
|
78
|
+
const storeSetSavedFontLink = useThemeStore((state)=>state.setSavedFontLink);
|
|
79
|
+
const storeSetFontLoadStatus = useThemeStore((state)=>state.setFontLoadStatus);
|
|
80
|
+
const storeSetFontLoadError = useThemeStore((state)=>state.setFontLoadError);
|
|
81
|
+
const storeSetFontName = useThemeStore((state)=>state.setFontName);
|
|
82
|
+
const { run: debouncedLoadGoogleFont } = useDebounceFn((link)=>loadGoogleFont(link, {
|
|
83
|
+
setFontLoadStatus: storeSetFontLoadStatus,
|
|
84
|
+
setFontLoadError: storeSetFontLoadError,
|
|
85
|
+
setFontName: storeSetFontName
|
|
86
|
+
}), {
|
|
87
|
+
wait: 500
|
|
88
|
+
});
|
|
89
|
+
useEffect(()=>{
|
|
90
|
+
applyTheme(savedTheme);
|
|
91
|
+
debouncedLoadGoogleFont(savedFontLink);
|
|
92
|
+
}, [
|
|
93
|
+
savedTheme,
|
|
94
|
+
savedFontLink
|
|
95
|
+
]);
|
|
96
|
+
const setSelectedTheme = (theme)=>{
|
|
97
|
+
storeSetSelectedTheme(theme);
|
|
98
|
+
applyTheme(theme);
|
|
99
|
+
};
|
|
100
|
+
const setSavedTheme = (theme)=>{
|
|
101
|
+
storeSetSavedTheme(theme);
|
|
102
|
+
applyTheme(theme);
|
|
103
|
+
};
|
|
104
|
+
const setSelectedFontLink = (link)=>{
|
|
105
|
+
storeSetSelectedFontLink(link);
|
|
106
|
+
debouncedLoadGoogleFont(link);
|
|
107
|
+
};
|
|
108
|
+
const setSavedFontLink = (link)=>{
|
|
109
|
+
storeSetSavedFontLink(link);
|
|
110
|
+
debouncedLoadGoogleFont(link);
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
selectedTheme,
|
|
114
|
+
setSelectedTheme,
|
|
115
|
+
savedTheme,
|
|
116
|
+
setSavedTheme,
|
|
117
|
+
selectedFontLink,
|
|
118
|
+
setSelectedFontLink,
|
|
119
|
+
savedFontLink,
|
|
120
|
+
setSavedFontLink,
|
|
121
|
+
fontLoadStatus,
|
|
122
|
+
fontLoadError,
|
|
123
|
+
fontName
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
export { useTheme };
|
package/dist/components/index.js
CHANGED
|
@@ -24,5 +24,6 @@ export * from "./UXSwitch/index.js";
|
|
|
24
24
|
export * from "./UXTable/index.js";
|
|
25
25
|
export * from "./UXTabs/index.js";
|
|
26
26
|
export * from "./UXTextarea/index.js";
|
|
27
|
+
export * from "./UXThemeSwitch/index.js";
|
|
27
28
|
export * from "./UXToast/index.js";
|
|
28
29
|
export * from "./UXTooltip/index.js";
|
package/dist/hooks/useI18n.d.ts
CHANGED
|
@@ -8,4 +8,16 @@ export declare const useI18n: () => {
|
|
|
8
8
|
error: string;
|
|
9
9
|
address: string;
|
|
10
10
|
};
|
|
11
|
+
theme: {
|
|
12
|
+
title: string;
|
|
13
|
+
reset: string;
|
|
14
|
+
apply: string;
|
|
15
|
+
font: {
|
|
16
|
+
title: string;
|
|
17
|
+
placeholder: string;
|
|
18
|
+
loading: string;
|
|
19
|
+
success: string;
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
11
23
|
};
|
package/dist/hooks/useI18n.js
CHANGED
|
@@ -8,6 +8,18 @@ const en = {
|
|
|
8
8
|
success: 'Copied successfully!',
|
|
9
9
|
error: 'Copy failed: ',
|
|
10
10
|
address: 'Address copied: '
|
|
11
|
+
},
|
|
12
|
+
theme: {
|
|
13
|
+
title: 'Theme',
|
|
14
|
+
reset: 'Reset',
|
|
15
|
+
apply: 'Apply Theme',
|
|
16
|
+
font: {
|
|
17
|
+
title: 'Custom Font',
|
|
18
|
+
placeholder: 'Enter Google Fonts URL or custom font URL',
|
|
19
|
+
loading: 'Loading font...',
|
|
20
|
+
success: 'Font loaded: ',
|
|
21
|
+
error: 'Failed to load font'
|
|
22
|
+
}
|
|
11
23
|
}
|
|
12
24
|
};
|
|
13
25
|
const zh = {
|
|
@@ -19,6 +31,18 @@ const zh = {
|
|
|
19
31
|
success: '复制成功!',
|
|
20
32
|
error: '复制失败:',
|
|
21
33
|
address: '地址已复制:'
|
|
34
|
+
},
|
|
35
|
+
theme: {
|
|
36
|
+
title: '主题',
|
|
37
|
+
reset: '重置',
|
|
38
|
+
apply: '应用主题',
|
|
39
|
+
font: {
|
|
40
|
+
title: '自定义字体',
|
|
41
|
+
placeholder: '输入 Google Fonts 或自定义字体链接',
|
|
42
|
+
loading: '正在加载字体...',
|
|
43
|
+
success: '字体加载成功:',
|
|
44
|
+
error: '字体加载失败'
|
|
45
|
+
}
|
|
22
46
|
}
|
|
23
47
|
};
|
|
24
48
|
const useI18n = ()=>{
|
|
@@ -263,38 +263,6 @@ export declare const inputClasses: {
|
|
|
263
263
|
labelPlacement?: undefined;
|
|
264
264
|
radius?: undefined;
|
|
265
265
|
isMultiline?: undefined;
|
|
266
|
-
} | {
|
|
267
|
-
isInvalid: boolean;
|
|
268
|
-
variant: string;
|
|
269
|
-
class: {
|
|
270
|
-
inputWrapper: string[];
|
|
271
|
-
label?: undefined;
|
|
272
|
-
input?: undefined;
|
|
273
|
-
innerWrapper?: undefined;
|
|
274
|
-
stepperButton?: undefined;
|
|
275
|
-
};
|
|
276
|
-
size?: undefined;
|
|
277
|
-
color?: undefined;
|
|
278
|
-
labelPlacement?: undefined;
|
|
279
|
-
radius?: undefined;
|
|
280
|
-
disableAnimation?: undefined;
|
|
281
|
-
isMultiline?: undefined;
|
|
282
|
-
} | {
|
|
283
|
-
isInvalid: boolean;
|
|
284
|
-
variant: string;
|
|
285
|
-
class: {
|
|
286
|
-
inputWrapper: string;
|
|
287
|
-
label?: undefined;
|
|
288
|
-
input?: undefined;
|
|
289
|
-
innerWrapper?: undefined;
|
|
290
|
-
stepperButton?: undefined;
|
|
291
|
-
};
|
|
292
|
-
size?: undefined;
|
|
293
|
-
color?: undefined;
|
|
294
|
-
labelPlacement?: undefined;
|
|
295
|
-
radius?: undefined;
|
|
296
|
-
disableAnimation?: undefined;
|
|
297
|
-
isMultiline?: undefined;
|
|
298
266
|
} | {
|
|
299
267
|
labelPlacement: string;
|
|
300
268
|
size: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const inputClasses = {
|
|
2
2
|
defaultVariants: {
|
|
3
3
|
variant: 'flat',
|
|
4
|
-
color: '
|
|
4
|
+
color: 'default',
|
|
5
5
|
size: 'md',
|
|
6
6
|
fullWidth: true,
|
|
7
7
|
labelPlacement: 'outside',
|
|
@@ -75,19 +75,19 @@ const inputClasses = {
|
|
|
75
75
|
size: {
|
|
76
76
|
sm: {
|
|
77
77
|
label: 'text-tiny text-foreground-300',
|
|
78
|
-
inputWrapper: 'text-tiny h-6 min-h-6 px-2 rounded-small',
|
|
78
|
+
inputWrapper: 'text-tiny h-6 min-h-6 px-2.5 rounded-small',
|
|
79
79
|
input: 'text-tiny',
|
|
80
80
|
clearButton: 'text-medium'
|
|
81
81
|
},
|
|
82
82
|
md: {
|
|
83
83
|
label: 'text-tiny text-foreground-300',
|
|
84
|
-
inputWrapper: 'text-tiny h-[30px] min-h-[30px] rounded-small',
|
|
84
|
+
inputWrapper: 'text-tiny h-[30px] min-h-[30px] rounded-small px-2.5',
|
|
85
85
|
input: 'text-tiny',
|
|
86
86
|
clearButton: 'text-large'
|
|
87
87
|
},
|
|
88
88
|
lg: {
|
|
89
89
|
label: 'text-small text-foreground-300',
|
|
90
|
-
inputWrapper: 'text-small h-11 min-h-11 rounded-medium',
|
|
90
|
+
inputWrapper: 'text-small h-11 min-h-11 rounded-medium px-2.5',
|
|
91
91
|
input: 'text-small',
|
|
92
92
|
clearButton: 'text-large'
|
|
93
93
|
}
|
|
@@ -141,7 +141,7 @@ const inputClasses = {
|
|
|
141
141
|
},
|
|
142
142
|
isInvalid: {
|
|
143
143
|
true: {
|
|
144
|
-
inputWrapper: 'group-data-[focus=true]
|
|
144
|
+
inputWrapper: 'border border-danger caret-danger !bg-background group-data-[focus=true]:!bg-background group-data-[hover=true]:!bg-background',
|
|
145
145
|
label: 'text-danger',
|
|
146
146
|
input: 'placeholder:text-danger text-danger'
|
|
147
147
|
}
|
|
@@ -389,24 +389,6 @@ const inputClasses = {
|
|
|
389
389
|
inputWrapper: 'transition-colors motion-reduce:transition-none'
|
|
390
390
|
}
|
|
391
391
|
},
|
|
392
|
-
{
|
|
393
|
-
isInvalid: true,
|
|
394
|
-
variant: 'flat',
|
|
395
|
-
class: {
|
|
396
|
-
inputWrapper: [
|
|
397
|
-
'!bg-danger-50',
|
|
398
|
-
'data-[hover=true]:!bg-danger-100',
|
|
399
|
-
'group-data-[focus=true]:!bg-danger-50'
|
|
400
|
-
]
|
|
401
|
-
}
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
isInvalid: true,
|
|
405
|
-
variant: 'bordered',
|
|
406
|
-
class: {
|
|
407
|
-
inputWrapper: '!border-danger group-data-[focus=true]:!border-danger'
|
|
408
|
-
}
|
|
409
|
-
},
|
|
410
392
|
{
|
|
411
393
|
labelPlacement: 'inside',
|
|
412
394
|
size: 'sm',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@particle-network/ui-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"@types/react": "^19.1.10",
|
|
40
40
|
"react": "^19.1.0",
|
|
41
41
|
"typescript": "^5.8.3",
|
|
42
|
-
"@particle-network/
|
|
43
|
-
"@particle-network/
|
|
42
|
+
"@particle-network/eslint-config": "0.3.0",
|
|
43
|
+
"@particle-network/lintstaged-config": "0.1.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"react": ">=16.9.0",
|
|
@@ -49,8 +49,9 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"ahooks": "^3.9.4",
|
|
51
51
|
"copy-to-clipboard": "^3.3.3",
|
|
52
|
-
"
|
|
53
|
-
"@particle-network/icons": "0.
|
|
52
|
+
"zustand": "^5.0.8",
|
|
53
|
+
"@particle-network/icons": "0.4.0-beta.0",
|
|
54
|
+
"@particle-network/ui-shared": "0.3.0-beta.0"
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
57
|
"build": "rslib build",
|