@particle-network/ui-react 0.5.1-beta.3 → 0.5.1-beta.5

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.
Files changed (35) hide show
  1. package/dist/components/ProgressWrapper/index.d.ts +2 -2
  2. package/dist/components/UXChip/chip.extend.d.ts +2 -1
  3. package/dist/components/UXChip/index.d.ts +1 -1
  4. package/dist/components/UXColorPicker/color-picker.js +13 -7
  5. package/dist/components/UXColorPicker/types.d.ts +11 -0
  6. package/dist/components/UXThemeSwitch/constants.d.ts +9 -0
  7. package/dist/components/UXThemeSwitch/constants.js +3 -0
  8. package/dist/components/UXThemeSwitch/custom-theme-config.d.ts +2 -0
  9. package/dist/components/UXThemeSwitch/custom-theme-config.js +169 -0
  10. package/dist/components/UXThemeSwitch/theme-item.js +93 -14
  11. package/dist/components/UXThemeSwitch/theme-switch.js +24 -3
  12. package/dist/components/UXThemeSwitch/use-theme-color.d.ts +1 -22
  13. package/dist/components/UXThemeSwitch/use-theme-color.js +1 -9
  14. package/dist/components/UXThemeSwitch/use-theme-store.d.ts +5 -0
  15. package/dist/components/UXThemeSwitch/use-theme-store.js +9 -4
  16. package/dist/components/UXThemeSwitch/use-theme.d.ts +2 -0
  17. package/dist/components/UXThemeSwitch/use-theme.js +10 -53
  18. package/dist/components/UXThemeSwitch/utils.d.ts +28 -0
  19. package/dist/components/UXThemeSwitch/utils.js +202 -0
  20. package/dist/components/typography/Text.type.d.ts +2 -2
  21. package/dist/components/typography/Text.type.js +0 -1
  22. package/dist/heroui/constants.d.ts +18 -0
  23. package/dist/heroui/constants.js +98 -0
  24. package/dist/heroui/types.d.ts +91 -0
  25. package/dist/heroui/types.js +0 -0
  26. package/dist/heroui/utils/colors.d.ts +34 -0
  27. package/dist/heroui/utils/colors.js +121 -0
  28. package/dist/heroui/utils/object.d.ts +1 -0
  29. package/dist/heroui/utils/object.js +17 -0
  30. package/dist/hooks/useI18n.d.ts +129 -25
  31. package/dist/hooks/useI18n.js +80 -2
  32. package/dist/hooks/useLang.d.ts +5 -1
  33. package/dist/hooks/useLang.js +13 -1
  34. package/package.json +5 -3
  35. package/tailwind-preset.js +22 -148
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { type UXForegroundColor, type UXRadius } from '@particle-network/ui-shared';
2
+ import { type HexColor, type UXForegroundColor, type UXRadius } from '@particle-network/ui-shared';
3
3
  export interface ProgressWrapperProps extends React.HTMLAttributes<HTMLDivElement> {
4
4
  /**
5
5
  * 进度 (%)
@@ -24,7 +24,7 @@ export interface ProgressWrapperProps extends React.HTMLAttributes<HTMLDivElemen
24
24
  /**
25
25
  * 进度条颜色
26
26
  */
27
- color?: UXForegroundColor | 'transparent' | `#${string}`;
27
+ color?: Exclude<UXForegroundColor, 'default' | 'white'> | 'transparent' | HexColor;
28
28
  /**
29
29
  * 进度条 SVG 样式
30
30
  */
@@ -1,7 +1,8 @@
1
1
  import type React from 'react';
2
2
  import { type ChipProps } from '@heroui/chip';
3
+ import type { HexColor } from '@particle-network/ui-shared';
3
4
  type ExtendedChipProps = Omit<ChipProps, 'color'> & {
4
- color?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'alert' | 'danger' | 'bullish' | 'bearish' | `#${string}`;
5
+ color?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'alert' | 'danger' | 'bullish' | 'bearish' | HexColor;
5
6
  };
6
7
  declare const ExtendedChip: React.ForwardRefExoticComponent<ExtendedChipProps>;
7
8
  export default ExtendedChip;
@@ -2,5 +2,5 @@ import React from 'react';
2
2
  import ExtendedChip from './chip.extend';
3
3
  export type UXChipProps = React.ComponentPropsWithRef<typeof ExtendedChip>;
4
4
  export declare const UXChip: import("@heroui/system-rsc").InternalForwardRefRenderFunction<"div", Omit<import("@heroui/chip").ChipProps, "color"> & {
5
- color?: "default" | "primary" | "secondary" | "success" | "warning" | "alert" | "danger" | "bullish" | "bearish" | `#${string}`;
5
+ color?: "default" | "primary" | "secondary" | "success" | "warning" | "alert" | "danger" | "bullish" | "bearish" | import("@particle-network/ui-shared").HexColor;
6
6
  }, never>;
@@ -8,10 +8,12 @@ import RefreshCcwIcon from "@particle-network/icons/web/RefreshCcwIcon";
8
8
  import { HStack } from "../layout/index.js";
9
9
  import { UXButton } from "../UXButton/index.js";
10
10
  import { UXPopover, UXPopoverContent, UXPopoverTrigger } from "../UXPopover/index.js";
11
+ import { useThemeColor } from "../UXThemeSwitch/index.js";
11
12
  import { ColorFields } from "./color-fields.js";
12
13
  import { ColorInput } from "./color-input.js";
13
14
  import { normalizeColor } from "./utils.js";
14
- const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd, onValueChange, onValueChangeEnd, isDisabled, placement = 'bottom-start' })=>{
15
+ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', value, defaultValue, onChange, onChangeEnd, onValueChange, onValueChangeEnd, isChanged, onReset })=>{
16
+ const { 'bg-200': bg200 } = useThemeColor();
15
17
  const isControlled = void 0 !== value;
16
18
  const [pickerKey, setPickerKey] = useState(0);
17
19
  const [isInputFocused, setIsInputFocused] = useState(false);
@@ -92,13 +94,16 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
92
94
  onValueChangeEnd
93
95
  ]);
94
96
  const hasChanged = useMemo(()=>{
97
+ if (void 0 !== isChanged) return isChanged;
95
98
  const initialHex = initialColorRef.current.toString('hex');
96
99
  const currentHex = currentColor.toString('hex');
97
100
  return initialHex !== currentHex;
98
101
  }, [
99
- currentColor
102
+ currentColor,
103
+ isChanged
100
104
  ]);
101
105
  const handleReset = ()=>{
106
+ if (onReset) return void onReset();
102
107
  const resetColor = initialColorRef.current;
103
108
  if (!isControlled) {
104
109
  setInternalColor(resetColor);
@@ -130,10 +135,11 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
130
135
  children: [
131
136
  /*#__PURE__*/ jsx(UXPopoverTrigger, {
132
137
  children: /*#__PURE__*/ jsx(UXButton, {
138
+ radius: "none",
133
139
  size: "auto",
134
140
  isDisabled: isDisabled,
135
141
  children: /*#__PURE__*/ jsx(ColorSwatch, {
136
- className: "h-4 w-4 rounded-sm border-none"
142
+ className: cn('h-4 w-4 rounded-[4px]', internalColor.toString('hex') === bg200 && 'border-foreground/10 border')
137
143
  })
138
144
  })
139
145
  }),
@@ -149,7 +155,7 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
149
155
  className: "aspect-square w-full overflow-hidden rounded-lg",
150
156
  onChangeEnd: handleChangeEnd,
151
157
  children: /*#__PURE__*/ jsx(ColorThumb, {
152
- className: "border-1 h-2 w-2 rounded-full border-white shadow-[0_0_0_0.5px_black,inset_0_0_0_0.5px_black]"
158
+ className: "h-4 w-4 rounded-full border-2 border-white shadow-[0_2px_4px_rgba(0,0,0,0.2)]"
153
159
  })
154
160
  }),
155
161
  /*#__PURE__*/ jsxs(HStack, {
@@ -177,7 +183,7 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
177
183
  children: /*#__PURE__*/ jsx(SliderTrack, {
178
184
  className: "h-3 rounded-full",
179
185
  children: /*#__PURE__*/ jsx(ColorThumb, {
180
- className: "top-[50%] z-10 h-4 w-4 rounded-full border-2 border-white"
186
+ className: "top-[50%] z-10 h-4 w-4 rounded-full border-2 border-white shadow-[0_2px_4px_rgba(0,0,0,0.2)]"
181
187
  })
182
188
  })
183
189
  })
@@ -195,10 +201,10 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
195
201
  }),
196
202
  /*#__PURE__*/ jsx(ColorInput, {
197
203
  isDisabled: isDisabled,
198
- inputClassName: "focus:ring-0 px-0 text-left flex-1",
204
+ inputClassName: "focus:ring-0 px-0 text-left flex-1 relative bg-transparent",
199
205
  value: value,
200
206
  defaultValue: !isControlled && pickerKey > 0 ? internalColor : defaultValue,
201
- onChange: (color)=>handleChange(color),
207
+ onChange: handleColorFieldsChange,
202
208
  onFocus: ()=>setIsInputFocused(true),
203
209
  onBlur: ()=>setIsInputFocused(false)
204
210
  }),
@@ -26,10 +26,21 @@ export interface UXColorPickerProps {
26
26
  * HEX 格式颜色变化结束回调(释放时调用)
27
27
  */
28
28
  onValueChangeEnd?: (color: string) => void;
29
+ /**
30
+ * 是否已改变(展示 reset 按钮)
31
+ */
32
+ isChanged?: boolean;
33
+ /**
34
+ * 重置回调
35
+ */
36
+ onReset?: () => void;
29
37
  /**
30
38
  * 是否禁用
31
39
  */
32
40
  isDisabled?: boolean;
41
+ /**
42
+ * Popover 位置
43
+ */
33
44
  placement?: UXPopoverProps['placement'];
34
45
  }
35
46
  export interface ColorFieldsProps extends Pick<UXColorPickerProps, 'value' | 'defaultValue'> {
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 默认字体
3
+ */
4
+ export declare const DEFAULT_FONT_FAMILY = "Inter,system-ui,sans-serif,\"Microsoft YaHei\"";
5
+ /**
6
+ * 预加载所有主题字体的 Google Fonts CSS
7
+ * 包含所有可能用到的字体,一次性加载,避免切换主题时重复加载
8
+ */
9
+ export declare const PRELOAD_FONTS_URL = "https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&display=swap";
@@ -0,0 +1,3 @@
1
+ const DEFAULT_FONT_FAMILY = 'Inter,system-ui,sans-serif,"Microsoft YaHei"';
2
+ const PRELOAD_FONTS_URL = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&display=swap';
3
+ export { DEFAULT_FONT_FAMILY, PRELOAD_FONTS_URL };
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const CustomThemeConfig: React.FC;
@@ -0,0 +1,169 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { DEFAULT_THEME_ID, themeData } from "@particle-network/ui-shared";
4
+ import { produce } from "immer";
5
+ import { useI18n, useLang } from "../../hooks/index.js";
6
+ import { HStack, VStack } from "../layout/index.js";
7
+ import { Text } from "../typography/Text.js";
8
+ import { UXButton } from "../UXButton/index.js";
9
+ import { UXColorPicker } from "../UXColorPicker/index.js";
10
+ import { UXSelect, UXSelectItem } from "../UXSelect/index.js";
11
+ import { UXTab, UXTabs } from "../UXTabs/index.js";
12
+ import { useTheme } from "./use-theme.js";
13
+ const COLOR_CATEGORIES = {
14
+ basic: [
15
+ 'primary',
16
+ 'bullish',
17
+ 'bearish'
18
+ ],
19
+ background: [
20
+ 'bg-default',
21
+ 'bg-400',
22
+ 'bg-300',
23
+ 'bg-200',
24
+ 'overlay',
25
+ 'divider'
26
+ ],
27
+ text: [
28
+ 'foreground',
29
+ 'secondary',
30
+ 'tertiary'
31
+ ],
32
+ candle: [
33
+ 'candleUp',
34
+ 'candleBorderUp',
35
+ 'candleWickUp',
36
+ 'candleDown',
37
+ 'candleBorderDown',
38
+ 'candleWickDown'
39
+ ],
40
+ signal: [
41
+ 'success',
42
+ 'danger',
43
+ 'warning',
44
+ 'alert'
45
+ ]
46
+ };
47
+ const CustomThemeConfig = ()=>{
48
+ const { lang } = useLang();
49
+ const i18n = useI18n();
50
+ const { theme, setTheme, setCustomTheme } = useTheme();
51
+ const baseThemes = useMemo(()=>themeData.filter((t)=>'custom' !== t.id), []);
52
+ const baseThemeId = theme.baseThemeId || DEFAULT_THEME_ID;
53
+ const baseTheme = useMemo(()=>themeData.find((t)=>t.id === baseThemeId) || themeData.find((t)=>t.id === DEFAULT_THEME_ID), [
54
+ baseThemeId
55
+ ]);
56
+ const handleBaseThemeChange = (themeId)=>{
57
+ const selectedBaseTheme = themeData.find((t)=>t.id === themeId);
58
+ if (selectedBaseTheme) {
59
+ const updatedTheme = {
60
+ ...theme,
61
+ baseThemeId: themeId,
62
+ colorScheme: selectedBaseTheme.colorScheme,
63
+ colorVariables: selectedBaseTheme.colorVariables
64
+ };
65
+ setTheme(updatedTheme);
66
+ setCustomTheme(updatedTheme);
67
+ }
68
+ };
69
+ const handleColorChange = (color, value)=>{
70
+ const updatedTheme = produce(theme, (draft)=>{
71
+ draft.colorVariables[color] = value;
72
+ });
73
+ setTheme(updatedTheme);
74
+ setCustomTheme(updatedTheme);
75
+ };
76
+ const handleSwapUpDown = ()=>{
77
+ const updatedTheme = produce(theme, (draft)=>{
78
+ const { bullish, bearish, candleUp, candleDown, candleWickUp, candleWickDown, candleBorderUp, candleBorderDown } = draft.colorVariables;
79
+ draft.colorVariables.bullish = bearish;
80
+ draft.colorVariables.bearish = bullish;
81
+ draft.colorVariables.candleUp = candleDown;
82
+ draft.colorVariables.candleDown = candleUp;
83
+ draft.colorVariables.candleWickUp = candleWickDown;
84
+ draft.colorVariables.candleWickDown = candleWickUp;
85
+ draft.colorVariables.candleBorderUp = candleBorderDown;
86
+ draft.colorVariables.candleBorderDown = candleBorderUp;
87
+ });
88
+ setTheme(updatedTheme);
89
+ setCustomTheme(updatedTheme);
90
+ };
91
+ const getColorValue = (color)=>theme.colorVariables[color] || baseTheme.colorVariables[color] || '#000000';
92
+ const renderColorItem = (color, label)=>{
93
+ const value = getColorValue(color);
94
+ const isCustomized = void 0 !== theme.colorVariables[color] && theme.colorVariables[color] !== baseTheme.colorVariables[color];
95
+ return /*#__PURE__*/ jsxs(HStack, {
96
+ justify: "between",
97
+ children: [
98
+ /*#__PURE__*/ jsx(Text, {
99
+ color: "secondary",
100
+ children: label
101
+ }),
102
+ /*#__PURE__*/ jsx(UXColorPicker, {
103
+ value: value,
104
+ isChanged: isCustomized,
105
+ onValueChange: (newValue)=>handleColorChange(color, newValue),
106
+ onReset: ()=>handleColorChange(color, baseTheme.colorVariables[color])
107
+ })
108
+ ]
109
+ }, color);
110
+ };
111
+ return /*#__PURE__*/ jsxs(VStack, {
112
+ gap: "lg",
113
+ children: [
114
+ /*#__PURE__*/ jsxs(HStack, {
115
+ justify: "between",
116
+ children: [
117
+ /*#__PURE__*/ jsx(Text, {
118
+ body1Bold: true,
119
+ children: i18n.theme.custom.title
120
+ }),
121
+ /*#__PURE__*/ jsx(UXButton, {
122
+ variant: "text",
123
+ color: "primary",
124
+ onPress: handleSwapUpDown,
125
+ children: i18n.theme.custom.swapUpDown
126
+ })
127
+ ]
128
+ }),
129
+ /*#__PURE__*/ jsxs(HStack, {
130
+ justify: "between",
131
+ children: [
132
+ /*#__PURE__*/ jsx(Text, {
133
+ color: "secondary",
134
+ children: i18n.theme.custom.preset
135
+ }),
136
+ /*#__PURE__*/ jsx(UXSelect, {
137
+ className: "min-w-48",
138
+ selectedKeys: [
139
+ baseThemeId
140
+ ],
141
+ onSelectionChange: (keys)=>{
142
+ const selectedKey = Array.from(keys)[0];
143
+ if (selectedKey) handleBaseThemeChange(selectedKey);
144
+ },
145
+ children: baseThemes.map((t)=>/*#__PURE__*/ jsx(UXSelectItem, {
146
+ children: 'zh' === lang ? t.zhName : t.enName
147
+ }, t.id))
148
+ })
149
+ ]
150
+ }),
151
+ /*#__PURE__*/ jsx(UXTabs, {
152
+ fullWidth: true,
153
+ variant: "switch",
154
+ children: Object.entries(COLOR_CATEGORIES).map(([category, colors])=>/*#__PURE__*/ jsx(UXTab, {
155
+ title: i18n.theme.custom.categories[category],
156
+ children: /*#__PURE__*/ jsx(VStack, {
157
+ gap: "md",
158
+ className: "pt-md",
159
+ children: colors.map((color)=>{
160
+ const label = i18n.colors[color] || color;
161
+ return renderColorItem(color, label);
162
+ })
163
+ })
164
+ }, category))
165
+ })
166
+ ]
167
+ });
168
+ };
169
+ export { CustomThemeConfig };
@@ -1,11 +1,14 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import "react";
3
3
  import { cn } from "@heroui/theme";
4
4
  import { useLang } from "../../hooks/index.js";
5
5
  import { VStack } from "../layout/index.js";
6
6
  import { Text } from "../typography/Text.js";
7
+ import { useTheme } from "./use-theme.js";
7
8
  const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
8
- const lang = useLang();
9
+ const { lang } = useLang();
10
+ const { customTheme } = useTheme();
11
+ const customColors = customTheme.colorVariables;
9
12
  return /*#__PURE__*/ jsxs(VStack, {
10
13
  gap: 2,
11
14
  items: "center",
@@ -13,7 +16,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
13
16
  onClick: onClick,
14
17
  children: [
15
18
  /*#__PURE__*/ jsx("div", {
16
- className: cn('rounded-medium border-2 transition-all duration-300 hover:scale-105', 'h-[59px] w-[100px] md:h-[71px] md:w-[120px]', isSelected ? 'border-primary' : 'border-transparent'),
19
+ className: cn('rounded-medium border-2 border-transparent transition-all duration-300 hover:scale-105', 'h-[59px] w-[100px] md:h-[71px] md:w-[120px]', isSelected && 'border-primary'),
20
+ style: {
21
+ borderColor: isSelected && 'custom' === id ? customColors.primary : void 0
22
+ },
17
23
  children: /*#__PURE__*/ jsxs("svg", {
18
24
  xmlns: "http://www.w3.org/2000/svg",
19
25
  viewBox: "0 0 120 71",
@@ -27,7 +33,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
27
33
  height: "67",
28
34
  rx: "5",
29
35
  fill: "currentColor",
30
- className: "text-primary"
36
+ className: "text-primary",
37
+ style: {
38
+ color: 'custom' === id ? customColors.primary : void 0
39
+ }
31
40
  }),
32
41
  /*#__PURE__*/ jsx("mask", {
33
42
  id: "mask0_40928_218196",
@@ -46,7 +55,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
46
55
  height: "67",
47
56
  rx: "5",
48
57
  fill: "currentColor",
49
- className: "text-background"
58
+ className: "text-background",
59
+ style: {
60
+ color: 'custom' === id ? customColors['bg-default'] : void 0
61
+ }
50
62
  })
51
63
  }),
52
64
  /*#__PURE__*/ jsx("g", {
@@ -58,7 +70,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
58
70
  height: "67",
59
71
  rx: "6",
60
72
  fill: "currentColor",
61
- className: "text-background"
73
+ className: "text-background",
74
+ style: {
75
+ color: 'custom' === id ? customColors['bg-default'] : void 0
76
+ }
62
77
  })
63
78
  }),
64
79
  /*#__PURE__*/ jsx("rect", {
@@ -67,7 +82,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
67
82
  width: "100",
68
83
  height: "1",
69
84
  fill: "currentColor",
70
- className: "text-divider"
85
+ className: "text-divider",
86
+ style: {
87
+ color: 'custom' === id ? customColors.divider : void 0
88
+ }
71
89
  }),
72
90
  /*#__PURE__*/ jsx("rect", {
73
91
  x: "54.082",
@@ -76,7 +94,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
76
94
  height: "6.01835",
77
95
  rx: "3.00917",
78
96
  fill: "currentColor",
79
- className: "text-foreground"
97
+ className: "text-foreground",
98
+ style: {
99
+ color: 'custom' === id ? customColors.foreground : void 0
100
+ }
80
101
  }),
81
102
  /*#__PURE__*/ jsx("rect", {
82
103
  x: "54.082",
@@ -85,7 +106,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
85
106
  height: "6.01835",
86
107
  rx: "3.00917",
87
108
  fill: "currentColor",
88
- className: "text-bullish"
109
+ className: "text-bullish",
110
+ style: {
111
+ color: 'custom' === id ? customColors.bullish : void 0
112
+ }
89
113
  }),
90
114
  /*#__PURE__*/ jsx("rect", {
91
115
  x: "75.8994",
@@ -94,7 +118,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
94
118
  height: "6.01835",
95
119
  rx: "3.00917",
96
120
  fill: "currentColor",
97
- className: "text-bearish"
121
+ className: "text-bearish",
122
+ style: {
123
+ color: 'custom' === id ? customColors.bearish : void 0
124
+ }
98
125
  }),
99
126
  /*#__PURE__*/ jsx("rect", {
100
127
  x: "86.4316",
@@ -103,7 +130,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
103
130
  height: "6.01835",
104
131
  rx: "3.00917",
105
132
  fill: "currentColor",
106
- className: "text-secondary"
133
+ className: "text-secondary",
134
+ style: {
135
+ color: 'custom' === id ? customColors.secondary : void 0
136
+ }
107
137
  }),
108
138
  /*#__PURE__*/ jsx("rect", {
109
139
  x: "94.707",
@@ -112,7 +142,10 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
112
142
  height: "6.01835",
113
143
  rx: "3.00917",
114
144
  fill: "currentColor",
115
- className: "text-secondary"
145
+ className: "text-secondary",
146
+ style: {
147
+ color: 'custom' === id ? customColors.secondary : void 0
148
+ }
116
149
  }),
117
150
  /*#__PURE__*/ jsx("rect", {
118
151
  x: "102.981",
@@ -121,9 +154,55 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
121
154
  height: "6.01835",
122
155
  rx: "3.00917",
123
156
  fill: "currentColor",
124
- className: "text-secondary"
157
+ className: "text-secondary",
158
+ style: {
159
+ color: 'custom' === id ? customColors.secondary : void 0
160
+ }
125
161
  }),
126
- /*#__PURE__*/ jsx("rect", {
162
+ 'custom' === id ? /*#__PURE__*/ jsxs(Fragment, {
163
+ children: [
164
+ /*#__PURE__*/ jsx("g", {
165
+ "clip-path": "url(#paint0_angular_48986_280686_clip_path)",
166
+ "data-figma-skip-parse": "true",
167
+ children: /*#__PURE__*/ jsx("g", {
168
+ transform: "matrix(0 0.011 -0.011 0 39 51)",
169
+ children: /*#__PURE__*/ jsx("foreignObject", {
170
+ x: "-1043.94",
171
+ y: "-1043.94",
172
+ width: "2087.87",
173
+ height: "2087.87",
174
+ children: /*#__PURE__*/ jsx("div", {
175
+ style: {
176
+ background: 'conic-gradient(from 90deg,rgba(255, 0, 0, 1) 0deg,rgba(255, 133, 0, 1) 54deg,rgba(190, 255, 0, 1) 117deg,rgba(7, 225, 255, 1) 199.8deg,rgba(35, 0, 255, 1) 282.6deg,rgba(173, 0, 255, 1) 360deg)',
177
+ height: '100%',
178
+ width: '100%',
179
+ opacity: 1
180
+ }
181
+ })
182
+ })
183
+ })
184
+ }),
185
+ /*#__PURE__*/ jsx("circle", {
186
+ cx: "39",
187
+ cy: "51",
188
+ r: "10.7583",
189
+ "data-figma-gradient-fill": '{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":1.0,"g":0.0,"b":0.0,"a":1.0},"position":0.0},{"color":{"r":1.0,"g":0.52295231819152832,"b":0.0,"a":1.0},"position":0.15000000596046448},{"color":{"r":0.74555355310440063,"g":1.0,"b":0.0,"a":1.0},"position":0.32499998807907104},{"color":{"r":0.029410807415843010,"g":0.88352936506271362,"b":1.0,"a":1.0},"position":0.55500000715255737},{"color":{"r":0.14000000059604645,"g":0.0,"b":1.0,"a":1.0},"position":0.78500002622604370},{"color":{"r":0.67999994754791260,"g":0.0,"b":1.0,"a":1.0},"position":1.0}],"stopsVar":[{"color":{"r":1.0,"g":0.0,"b":0.0,"a":1.0},"position":0.0},{"color":{"r":1.0,"g":0.52295231819152832,"b":0.0,"a":1.0},"position":0.15000000596046448},{"color":{"r":0.74555355310440063,"g":1.0,"b":0.0,"a":1.0},"position":0.32499998807907104},{"color":{"r":0.029410807415843010,"g":0.88352936506271362,"b":1.0,"a":1.0},"position":0.55500000715255737},{"color":{"r":0.14000000059604645,"g":0.0,"b":1.0,"a":1.0},"position":0.78500002622604370},{"color":{"r":0.67999994754791260,"g":0.0,"b":1.0,"a":1.0},"position":1.0}],"transform":{"m00":1.3471115643134642e-15,"m01":-22.0,"m02":50.0,"m10":22.0,"m11":1.3471115643134642e-15,"m12":40.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}',
190
+ stroke: "#8B8EA1",
191
+ "stroke-width": "0.483303"
192
+ }),
193
+ /*#__PURE__*/ jsx("defs", {
194
+ children: /*#__PURE__*/ jsx("clipPath", {
195
+ id: "paint0_angular_48986_280686_clip_path",
196
+ children: /*#__PURE__*/ jsx("circle", {
197
+ cx: "39",
198
+ cy: "51",
199
+ r: "10.7583",
200
+ "stroke-width": "0.483303"
201
+ })
202
+ })
203
+ })
204
+ ]
205
+ }) : /*#__PURE__*/ jsx("rect", {
127
206
  x: "27",
128
207
  y: "39",
129
208
  width: "22.5688",
@@ -3,7 +3,7 @@ import { useMemo, useState } from "react";
3
3
  import { cn } from "@heroui/theme";
4
4
  import { useDisclosure } from "@heroui/use-disclosure";
5
5
  import { ChartColorSwitchIcon, CopyIcon } from "@particle-network/icons/web";
6
- import { themeData } from "@particle-network/ui-shared";
6
+ import { DEFAULT_THEME_ID, themeData } from "@particle-network/ui-shared";
7
7
  import { useI18n } from "../../hooks/index.js";
8
8
  import { HStack, VStack } from "../layout/index.js";
9
9
  import { Text } from "../typography/Text.js";
@@ -15,6 +15,7 @@ import { UXInput } from "../UXInput/index.js";
15
15
  import { UXModal } from "../UXModal/index.js";
16
16
  import { UXSpinner } from "../UXSpinner/index.js";
17
17
  import { UXTooltip } from "../UXTooltip/index.js";
18
+ import { CustomThemeConfig } from "./custom-theme-config.js";
18
19
  import { ThemeItem } from "./theme-item.js";
19
20
  import { useTheme } from "./use-theme.js";
20
21
  const FONT_EXAMPLES = [
@@ -33,12 +34,26 @@ const FONT_EXAMPLES = [
33
34
  ];
34
35
  const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, onClose, onOpenChange })=>{
35
36
  const i18n = useI18n();
36
- const { theme: selectedTheme, setTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
37
+ const { theme: selectedTheme, customTheme: savedCustomTheme, setTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
37
38
  const [isFontExampleOpen, setIsFontExampleOpen] = useState(false);
38
39
  const Component = 'modal' === as ? UXModal : UXDrawer;
39
40
  const themes = useMemo(()=>themeData.filter((theme)=>!omitThemes.includes(theme.id)), [
40
41
  omitThemes
41
42
  ]);
43
+ const handleThemeSelect = (theme)=>{
44
+ if ('custom' === theme.id) if (savedCustomTheme) setTheme(savedCustomTheme);
45
+ else {
46
+ const baseTheme = themeData.find((t)=>t.id === DEFAULT_THEME_ID) || themeData["0"];
47
+ const customTheme = {
48
+ ...theme,
49
+ baseThemeId: DEFAULT_THEME_ID,
50
+ colorScheme: baseTheme.colorScheme,
51
+ colorVariables: baseTheme.colorVariables
52
+ };
53
+ setTheme(customTheme);
54
+ }
55
+ else setTheme(theme);
56
+ };
42
57
  return /*#__PURE__*/ jsx(Component, {
43
58
  isOpen: isOpen,
44
59
  classNames: {
@@ -61,10 +76,16 @@ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, o
61
76
  className: "grid grid-cols-3 gap-y-5 pt-1",
62
77
  children: themes.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
63
78
  isSelected: selectedTheme.id === theme.id,
64
- onClick: ()=>setTheme(theme),
79
+ onClick: ()=>handleThemeSelect(theme),
65
80
  ...theme
66
81
  }, theme.id))
67
82
  }),
83
+ 'custom' === selectedTheme.id && /*#__PURE__*/ jsxs(Fragment, {
84
+ children: [
85
+ /*#__PURE__*/ jsx(UXDivider, {}),
86
+ /*#__PURE__*/ jsx(CustomThemeConfig, {})
87
+ ]
88
+ }),
68
89
  /*#__PURE__*/ jsx(UXDivider, {}),
69
90
  /*#__PURE__*/ jsxs(VStack, {
70
91
  gap: "md",
@@ -1,22 +1 @@
1
- export declare const useThemeColor: () => {
2
- transparent: string;
3
- white: string;
4
- default: string;
5
- alert: string;
6
- success: string;
7
- foreground: string;
8
- secondary: string;
9
- tertiary: string;
10
- primary: string;
11
- danger: string;
12
- warning: string;
13
- gold: string;
14
- bullish: string;
15
- bearish: string;
16
- "bg-default": string;
17
- "bg-300": string;
18
- "bg-200": string;
19
- "bg-400": string;
20
- divider: string;
21
- overlay: string;
22
- };
1
+ export declare const useThemeColor: () => Record<import("@particle-network/ui-shared").ThemeColorVariable, string>;
@@ -1,14 +1,6 @@
1
- import { useMemo } from "react";
2
1
  import { useThemeStore } from "./use-theme-store.js";
3
2
  const useThemeColor = ()=>{
4
3
  const { colorVariables } = useThemeStore((state)=>state.theme);
5
- const themeColor = useMemo(()=>({
6
- ...colorVariables,
7
- transparent: 'transparent',
8
- white: '#FFFFFF'
9
- }), [
10
- colorVariables
11
- ]);
12
- return themeColor;
4
+ return colorVariables;
13
5
  };
14
6
  export { useThemeColor };
@@ -5,6 +5,10 @@ interface State {
5
5
  * 保存的主题
6
6
  */
7
7
  theme: ThemeItemType;
8
+ /**
9
+ * 保存的自定义主题配置(当切换到其他主题时保存,切回 custom 时恢复)
10
+ */
11
+ customTheme: ThemeItemType;
8
12
  /**
9
13
  * 保存的字体链接
10
14
  */
@@ -20,6 +24,7 @@ interface State {
20
24
  }
21
25
  interface Actions {
22
26
  setTheme: (theme: ThemeItemType) => void;
27
+ setCustomTheme: (customTheme: ThemeItemType) => void;
23
28
  setFontUrl: (fontUrl: string) => void;
24
29
  setFontLoadStatus: (status: FontLoadStatus) => void;
25
30
  setFontName: (name: string) => void;