@particle-network/ui-react 0.5.1-beta.2 → 0.5.1-beta.21

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 (90) hide show
  1. package/dist/components/ProgressWrapper/index.d.ts +2 -2
  2. package/dist/components/ProgressWrapper/index.js +2 -3
  3. package/dist/components/UXAutocomplete/index.js +1 -2
  4. package/dist/components/UXButton/button-theme.js +2 -2
  5. package/dist/components/UXButton/button.js +1 -1
  6. package/dist/components/UXCheckbox/checkbox.extend.js +16 -13
  7. package/dist/components/UXChip/chip.extend.d.ts +2 -1
  8. package/dist/components/UXChip/index.d.ts +1 -1
  9. package/dist/components/UXColorPicker/color-input.js +1 -1
  10. package/dist/components/UXColorPicker/color-picker.js +51 -33
  11. package/dist/components/UXColorPicker/types.d.ts +15 -0
  12. package/dist/components/UXCopy/index.js +1 -1
  13. package/dist/components/UXEmpty/index.js +1 -1
  14. package/dist/components/UXHint/index.js +1 -1
  15. package/dist/components/UXInput/index.d.ts +6 -6
  16. package/dist/components/UXInput/input.extend.d.ts +6 -6
  17. package/dist/components/UXModal/index.d.ts +1 -1
  18. package/dist/components/UXRadio/radio.extend.js +3 -3
  19. package/dist/components/UXSlider/use-slider.js +1 -1
  20. package/dist/components/UXSpinner/spinner.d.ts +1 -5
  21. package/dist/components/UXSpinner/spinner.js +3 -4
  22. package/dist/components/UXSwitch/index.d.ts +2 -2
  23. package/dist/components/UXSwitch/switch.extend.d.ts +2 -2
  24. package/dist/components/UXSwitch/switch.extend.js +6 -6
  25. package/dist/components/UXTabs/tabs.classes.js +4 -4
  26. package/dist/components/UXThemeSwitch/constants.d.ts +9 -0
  27. package/dist/components/UXThemeSwitch/constants.js +3 -0
  28. package/dist/components/UXThemeSwitch/custom-theme-config.d.ts +5 -0
  29. package/dist/components/UXThemeSwitch/custom-theme-config.js +172 -0
  30. package/dist/components/UXThemeSwitch/index.d.ts +2 -2
  31. package/dist/components/UXThemeSwitch/index.js +2 -2
  32. package/dist/components/UXThemeSwitch/theme-item.js +93 -15
  33. package/dist/components/UXThemeSwitch/theme-switch.d.ts +8 -1
  34. package/dist/components/UXThemeSwitch/theme-switch.js +20 -5
  35. package/dist/components/UXThemeSwitch/use-theme.d.ts +4 -1
  36. package/dist/components/UXThemeSwitch/use-theme.js +9 -57
  37. package/dist/components/UXThemeSwitch/utils.d.ts +28 -0
  38. package/dist/components/UXThemeSwitch/utils.js +260 -0
  39. package/dist/components/UXToast/index.d.ts +1 -1
  40. package/dist/components/UXToast/index.js +23 -11
  41. package/dist/components/UXTooltip/index.js +4 -12
  42. package/dist/components/WrapText/index.d.ts +6 -0
  43. package/dist/components/WrapText/index.js +15 -0
  44. package/dist/components/index.d.ts +1 -0
  45. package/dist/components/index.js +1 -0
  46. package/dist/components/layout/Box/box-theme.d.ts +2213 -0
  47. package/dist/components/layout/Box/box-theme.js +344 -0
  48. package/dist/components/layout/Box/box.d.ts +14 -0
  49. package/dist/components/layout/Box/box.js +99 -0
  50. package/dist/components/layout/Circle.js +2 -3
  51. package/dist/components/layout/Flex.d.ts +3 -27
  52. package/dist/components/layout/Flex.js +6 -19
  53. package/dist/components/layout/HStack.d.ts +1 -1
  54. package/dist/components/layout/Square.js +3 -3
  55. package/dist/components/layout/VStack.d.ts +1 -1
  56. package/dist/components/layout/VStack.js +2 -2
  57. package/dist/components/layout/index.d.ts +1 -0
  58. package/dist/components/layout/index.js +1 -0
  59. package/dist/components/typography/Text.js +35 -10
  60. package/dist/components/typography/Text.type.d.ts +4 -26
  61. package/dist/components/typography/Text.type.js +0 -47
  62. package/dist/components/typography/text-theme.d.ts +178 -0
  63. package/dist/components/typography/text-theme.js +79 -0
  64. package/dist/heroui/constants.d.ts +18 -0
  65. package/dist/heroui/constants.js +98 -0
  66. package/dist/heroui/types.d.ts +91 -0
  67. package/dist/heroui/types.js +0 -0
  68. package/dist/heroui/utils/colors.d.ts +34 -0
  69. package/dist/heroui/utils/colors.js +121 -0
  70. package/dist/heroui/utils/object.d.ts +1 -0
  71. package/dist/heroui/utils/object.js +17 -0
  72. package/dist/hooks/useI18n.d.ts +133 -25
  73. package/dist/hooks/useI18n.js +84 -2
  74. package/dist/hooks/useLang.d.ts +5 -1
  75. package/dist/hooks/useLang.js +13 -1
  76. package/dist/utils/cn.d.ts +2 -0
  77. package/dist/utils/cn.js +250 -0
  78. package/dist/utils/common.d.ts +1 -0
  79. package/dist/utils/common.js +4 -0
  80. package/dist/utils/index.d.ts +2 -0
  81. package/dist/utils/index.js +3 -1
  82. package/dist/utils/input-classes.js +2 -2
  83. package/package.json +7 -5
  84. package/tailwind-preset.js +84 -160
  85. package/dist/components/UXThemeSwitch/use-color-scheme.d.ts +0 -5
  86. package/dist/components/UXThemeSwitch/use-color-scheme.js +0 -11
  87. package/dist/components/UXThemeSwitch/use-theme-color.d.ts +0 -22
  88. package/dist/components/UXThemeSwitch/use-theme-color.js +0 -10
  89. package/dist/components/UXThemeSwitch/use-theme-store.d.ts +0 -41
  90. package/dist/components/UXThemeSwitch/use-theme-store.js +0 -31
@@ -48,9 +48,9 @@ const ExtendedSwitch = extendVariants(Switch, {
48
48
  },
49
49
  size: {
50
50
  sm: {
51
- wrapper: 'w-5 h-3 px-0.5',
51
+ wrapper: 'w-5 h-3 px-0.5 bg-cursor',
52
52
  thumb: [
53
- 'w-2 h-2 text-tiny',
53
+ 'w-2 h-2 text-tiny shadow-none',
54
54
  'group-data-[selected=true]:ms-2'
55
55
  ],
56
56
  endContent: 'text-tiny',
@@ -58,9 +58,9 @@ const ExtendedSwitch = extendVariants(Switch, {
58
58
  label: 'text-body3 font-medium ms-sm'
59
59
  },
60
60
  md: {
61
- wrapper: 'w-6 h-3.5 px-[3px]',
61
+ wrapper: 'w-6 h-3.5 px-[3px] bg-cursor',
62
62
  thumb: [
63
- 'w-2.5 h-2.5 text-small',
63
+ 'w-2.5 h-2.5 text-small shadow-none',
64
64
  'group-data-[selected=true]:ms-2'
65
65
  ],
66
66
  endContent: 'text-small',
@@ -68,9 +68,9 @@ const ExtendedSwitch = extendVariants(Switch, {
68
68
  label: 'text-body3 font-medium ms-sm'
69
69
  },
70
70
  lg: {
71
- wrapper: 'w-[34px] h-5 px-[3px]',
71
+ wrapper: 'w-[34px] h-5 px-[3px] bg-cursor',
72
72
  thumb: [
73
- 'w-3.5 h-3.5 text-medium',
73
+ 'w-3.5 h-3.5 text-medium shadow-none',
74
74
  'group-data-[selected=true]:ms-3.5'
75
75
  ],
76
76
  endContent: 'text-medium',
@@ -252,9 +252,9 @@ const tabsClasses = {
252
252
  color: 'default',
253
253
  class: {
254
254
  cursor: [
255
- 'bg-tertiary dark:bg-tertiary'
255
+ 'bg-cursor dark:bg-cursor'
256
256
  ],
257
- tabContent: 'group-data-[selected=true]:text-tertiary-foreground'
257
+ tabContent: 'group-data-[selected=true]:text-cursor-foreground'
258
258
  }
259
259
  },
260
260
  {
@@ -264,9 +264,9 @@ const tabsClasses = {
264
264
  color: 'default',
265
265
  class: {
266
266
  cursor: [
267
- 'bg-tertiary'
267
+ 'bg-cursor'
268
268
  ],
269
- tabContent: 'group-data-[selected=true]:text-tertiary-foreground'
269
+ tabContent: 'group-data-[selected=true]:text-cursor-foreground'
270
270
  }
271
271
  },
272
272
  {
@@ -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,5 @@
1
+ import React from 'react';
2
+ export interface CustomThemeConfigProps {
3
+ colorChangeMode?: 'drag' | 'dragEnd';
4
+ }
5
+ export declare const CustomThemeConfig: React.FC<CustomThemeConfigProps>;
@@ -0,0 +1,172 @@
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
+ 'bgDefault',
21
+ 'bg400',
22
+ 'bg300',
23
+ 'bg200',
24
+ 'cursor',
25
+ 'overlay',
26
+ 'divider'
27
+ ],
28
+ text: [
29
+ 'foreground',
30
+ 'secondary',
31
+ 'tertiary'
32
+ ],
33
+ candle: [
34
+ 'candleUp',
35
+ 'candleBorderUp',
36
+ 'candleWickUp',
37
+ 'candleDown',
38
+ 'candleBorderDown',
39
+ 'candleWickDown'
40
+ ],
41
+ signal: [
42
+ 'success',
43
+ 'danger',
44
+ 'warning',
45
+ 'alert',
46
+ 'blue'
47
+ ]
48
+ };
49
+ const CustomThemeConfig = ({ colorChangeMode = 'dragEnd' })=>{
50
+ const { lang } = useLang();
51
+ const i18n = useI18n();
52
+ const { theme, setTheme, setCustomTheme } = useTheme();
53
+ const baseThemes = useMemo(()=>themeData.filter((t)=>'custom' !== t.id), []);
54
+ const baseThemeId = theme.baseThemeId || DEFAULT_THEME_ID;
55
+ const baseTheme = useMemo(()=>themeData.find((t)=>t.id === baseThemeId) || themeData.find((t)=>t.id === DEFAULT_THEME_ID), [
56
+ baseThemeId
57
+ ]);
58
+ const handleBaseThemeChange = (themeId)=>{
59
+ const selectedBaseTheme = themeData.find((t)=>t.id === themeId);
60
+ if (selectedBaseTheme) {
61
+ const updatedTheme = {
62
+ ...theme,
63
+ baseThemeId: themeId,
64
+ colorScheme: selectedBaseTheme.colorScheme,
65
+ colorVariables: selectedBaseTheme.colorVariables
66
+ };
67
+ setTheme(updatedTheme);
68
+ setCustomTheme(updatedTheme);
69
+ }
70
+ };
71
+ const handleColorChange = (color, value)=>{
72
+ const updatedTheme = produce(theme, (draft)=>{
73
+ draft.colorVariables[color] = value;
74
+ });
75
+ setTheme(updatedTheme);
76
+ setCustomTheme(updatedTheme);
77
+ };
78
+ const handleSwapUpDown = ()=>{
79
+ const updatedTheme = produce(theme, (draft)=>{
80
+ const { bullish, bearish, candleUp, candleDown, candleWickUp, candleWickDown, candleBorderUp, candleBorderDown } = draft.colorVariables;
81
+ draft.colorVariables.bullish = bearish;
82
+ draft.colorVariables.bearish = bullish;
83
+ draft.colorVariables.candleUp = candleDown;
84
+ draft.colorVariables.candleDown = candleUp;
85
+ draft.colorVariables.candleWickUp = candleWickDown;
86
+ draft.colorVariables.candleWickDown = candleWickUp;
87
+ draft.colorVariables.candleBorderUp = candleBorderDown;
88
+ draft.colorVariables.candleBorderDown = candleBorderUp;
89
+ });
90
+ setTheme(updatedTheme);
91
+ setCustomTheme(updatedTheme);
92
+ };
93
+ const getColorValue = (color)=>theme.colorVariables[color] || baseTheme.colorVariables[color] || '#000000';
94
+ const renderColorItem = (color, label)=>{
95
+ const value = getColorValue(color);
96
+ const isCustomized = void 0 !== theme.colorVariables[color] && theme.colorVariables[color] !== baseTheme.colorVariables[color];
97
+ return /*#__PURE__*/ jsxs(HStack, {
98
+ justify: "between",
99
+ children: [
100
+ /*#__PURE__*/ jsx(Text, {
101
+ color: "secondary",
102
+ children: label
103
+ }),
104
+ /*#__PURE__*/ jsx(UXColorPicker, {
105
+ defaultValue: value,
106
+ isChanged: isCustomized,
107
+ onValueChange: 'drag' === colorChangeMode ? (newValue)=>handleColorChange(color, newValue) : void 0,
108
+ onValueChangeEnd: 'dragEnd' === colorChangeMode ? (newValue)=>handleColorChange(color, newValue) : void 0,
109
+ onReset: ()=>handleColorChange(color, baseTheme.colorVariables[color])
110
+ })
111
+ ]
112
+ }, color);
113
+ };
114
+ return /*#__PURE__*/ jsxs(VStack, {
115
+ gap: "lg",
116
+ children: [
117
+ /*#__PURE__*/ jsxs(HStack, {
118
+ justify: "between",
119
+ children: [
120
+ /*#__PURE__*/ jsx(Text, {
121
+ body1Bold: true,
122
+ children: i18n.theme.custom.title
123
+ }),
124
+ /*#__PURE__*/ jsx(UXButton, {
125
+ variant: "text",
126
+ color: "primary",
127
+ onPress: handleSwapUpDown,
128
+ children: i18n.theme.custom.swapUpDown
129
+ })
130
+ ]
131
+ }),
132
+ /*#__PURE__*/ jsxs(HStack, {
133
+ justify: "between",
134
+ children: [
135
+ /*#__PURE__*/ jsx(Text, {
136
+ color: "secondary",
137
+ children: i18n.theme.custom.preset
138
+ }),
139
+ /*#__PURE__*/ jsx(UXSelect, {
140
+ className: "min-w-48",
141
+ selectedKeys: [
142
+ baseThemeId
143
+ ],
144
+ onSelectionChange: (keys)=>{
145
+ const selectedKey = Array.from(keys)[0];
146
+ if (selectedKey) handleBaseThemeChange(selectedKey);
147
+ },
148
+ children: baseThemes.map((t)=>/*#__PURE__*/ jsx(UXSelectItem, {
149
+ children: 'zh' === lang ? t.zhName : t.enName
150
+ }, t.id))
151
+ })
152
+ ]
153
+ }),
154
+ /*#__PURE__*/ jsx(UXTabs, {
155
+ fullWidth: true,
156
+ variant: "switch",
157
+ children: Object.entries(COLOR_CATEGORIES).map(([category, colors])=>/*#__PURE__*/ jsx(UXTab, {
158
+ title: i18n.theme.custom.categories[category],
159
+ children: /*#__PURE__*/ jsx(VStack, {
160
+ gap: "md",
161
+ className: "pt-md",
162
+ children: colors.map((color)=>{
163
+ const label = i18n.colors[color] || color;
164
+ return renderColorItem(color, label);
165
+ })
166
+ })
167
+ }, category))
168
+ })
169
+ ]
170
+ });
171
+ };
172
+ export { CustomThemeConfig };
@@ -1,4 +1,4 @@
1
+ import { useColorScheme, useThemeColor, useThemeStore } from '@particle-network/ui-shared';
1
2
  export * from './theme-switch';
2
- export * from './use-color-scheme';
3
3
  export * from './use-theme';
4
- export * from './use-theme-color';
4
+ export { useColorScheme, useThemeColor, useThemeStore };
@@ -1,4 +1,4 @@
1
+ import { useColorScheme, useThemeColor, useThemeStore } from "@particle-network/ui-shared";
1
2
  export * from "./theme-switch.js";
2
- export * from "./use-color-scheme.js";
3
3
  export * from "./use-theme.js";
4
- export * from "./use-theme-color.js";
4
+ export { useColorScheme, useThemeColor, useThemeStore };
@@ -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
- import { cn } from "@heroui/theme";
4
3
  import { useLang } from "../../hooks/index.js";
4
+ import { cn } from "../../utils/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.bgDefault : 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.bgDefault : 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,54 @@ 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
+ clipPath: "url(#paint0_angular_48986_280686_clip_path)",
166
+ children: /*#__PURE__*/ jsx("g", {
167
+ transform: "matrix(0 0.011 -0.011 0 39 51)",
168
+ children: /*#__PURE__*/ jsx("foreignObject", {
169
+ x: "-1043.94",
170
+ y: "-1043.94",
171
+ width: "2087.87",
172
+ height: "2087.87",
173
+ children: /*#__PURE__*/ jsx("div", {
174
+ style: {
175
+ 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)',
176
+ height: '100%',
177
+ width: '100%',
178
+ opacity: 1
179
+ }
180
+ })
181
+ })
182
+ })
183
+ }),
184
+ /*#__PURE__*/ jsx("circle", {
185
+ cx: "39",
186
+ cy: "51",
187
+ r: "10.7583",
188
+ "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}',
189
+ stroke: "#8B8EA1",
190
+ strokeWidth: "0.483303"
191
+ }),
192
+ /*#__PURE__*/ jsx("defs", {
193
+ children: /*#__PURE__*/ jsx("clipPath", {
194
+ id: "paint0_angular_48986_280686_clip_path",
195
+ children: /*#__PURE__*/ jsx("circle", {
196
+ cx: "39",
197
+ cy: "51",
198
+ r: "10.7583",
199
+ strokeWidth: "0.483303"
200
+ })
201
+ })
202
+ })
203
+ ]
204
+ }) : /*#__PURE__*/ jsx("rect", {
127
205
  x: "27",
128
206
  y: "39",
129
207
  width: "22.5688",
@@ -4,9 +4,16 @@ import { type UXModalProps } from '../UXModal';
4
4
  export interface UXThemeSwitchModalProps extends Pick<UXModalProps, 'isOpen' | 'onClose' | 'onOpenChange' | 'backdrop'> {
5
5
  as?: 'modal' | 'drawer';
6
6
  omitThemes?: ThemeId[];
7
+ /**
8
+ * 颜色改变模式
9
+ * - drag: 拖动时改变颜色
10
+ * - dragEnd: 拖动停止时改变颜色
11
+ * @default dragEnd
12
+ */
13
+ colorChangeMode?: 'drag' | 'dragEnd';
7
14
  }
8
15
  export declare const UXThemeSwitchModal: React.FC<UXThemeSwitchModalProps>;
9
- export interface UXThemeSwitchProps extends Pick<UXThemeSwitchModalProps, 'as' | 'omitThemes' | 'backdrop'> {
16
+ export interface UXThemeSwitchProps extends Pick<UXThemeSwitchModalProps, 'as' | 'omitThemes' | 'backdrop' | 'colorChangeMode'> {
10
17
  children?: (onOpen: () => void) => React.ReactNode;
11
18
  }
12
19
  export declare const UXThemeSwitch: React.FC<UXThemeSwitchProps>;
@@ -1,10 +1,10 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useMemo, useState } from "react";
3
- import { cn } from "@heroui/theme";
2
+ import { useEffect, useMemo, useState } from "react";
4
3
  import { useDisclosure } from "@heroui/use-disclosure";
5
4
  import { ChartColorSwitchIcon, CopyIcon } from "@particle-network/icons/web";
6
5
  import { themeData } from "@particle-network/ui-shared";
7
6
  import { useI18n } from "../../hooks/index.js";
7
+ import { cn } from "../../utils/index.js";
8
8
  import { HStack, VStack } from "../layout/index.js";
9
9
  import { Text } from "../typography/Text.js";
10
10
  import { UXButton } from "../UXButton/index.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 = [
@@ -31,14 +32,20 @@ const FONT_EXAMPLES = [
31
32
  url: 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap'
32
33
  }
33
34
  ];
34
- const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, onClose, onOpenChange })=>{
35
+ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, onClose, onOpenChange, colorChangeMode })=>{
35
36
  const i18n = useI18n();
36
- const { theme: selectedTheme, setTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
37
+ const { theme: selectedTheme, customTheme: savedCustomTheme, setTheme, initTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
37
38
  const [isFontExampleOpen, setIsFontExampleOpen] = useState(false);
39
+ useEffect(()=>{
40
+ initTheme();
41
+ }, []);
38
42
  const Component = 'modal' === as ? UXModal : UXDrawer;
39
43
  const themes = useMemo(()=>themeData.filter((theme)=>!omitThemes.includes(theme.id)), [
40
44
  omitThemes
41
45
  ]);
46
+ const handleThemeSelect = (theme)=>{
47
+ 'custom' === theme.id ? setTheme(savedCustomTheme) : setTheme(theme);
48
+ };
42
49
  return /*#__PURE__*/ jsx(Component, {
43
50
  isOpen: isOpen,
44
51
  classNames: {
@@ -61,10 +68,18 @@ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, o
61
68
  className: "grid grid-cols-3 gap-y-5 pt-1",
62
69
  children: themes.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
63
70
  isSelected: selectedTheme.id === theme.id,
64
- onClick: ()=>setTheme(theme),
71
+ onClick: ()=>handleThemeSelect(theme),
65
72
  ...theme
66
73
  }, theme.id))
67
74
  }),
75
+ 'custom' === selectedTheme.id && /*#__PURE__*/ jsxs(Fragment, {
76
+ children: [
77
+ /*#__PURE__*/ jsx(UXDivider, {}),
78
+ /*#__PURE__*/ jsx(CustomThemeConfig, {
79
+ colorChangeMode: colorChangeMode
80
+ })
81
+ ]
82
+ }),
68
83
  /*#__PURE__*/ jsx(UXDivider, {}),
69
84
  /*#__PURE__*/ jsxs(VStack, {
70
85
  gap: "md",
@@ -4,10 +4,13 @@ import { type ThemeItemType } from '@particle-network/ui-shared';
4
4
  */
5
5
  export declare const useTheme: () => {
6
6
  theme: ThemeItemType;
7
+ customTheme: ThemeItemType;
7
8
  setTheme: (theme: ThemeItemType) => void;
9
+ initTheme: () => void;
10
+ setCustomTheme: (customTheme: ThemeItemType) => void;
8
11
  fontUrl: string;
9
12
  setFontUrl: (link: string) => void;
10
13
  clearFontUrl: () => void;
11
- fontLoadStatus: import("./use-theme-store").FontLoadStatus;
14
+ fontLoadStatus: import("@particle-network/ui-shared").FontLoadStatus;
12
15
  fontName: string;
13
16
  };
@@ -1,65 +1,14 @@
1
- import { useEffect } from "react";
2
- import { themeKeys } from "@particle-network/ui-shared";
1
+ import { useThemeStore } from "@particle-network/ui-shared";
3
2
  import { useDebounceFn } from "ahooks";
4
- import { useThemeStore } from "./use-theme-store.js";
5
- const DEFAULT_FONT_FAMILY = 'Inter,system-ui,sans-serif,"Microsoft YaHei"';
6
- 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';
7
- const preloadFonts = ()=>{
8
- if ('undefined' == typeof window) return;
9
- const existingLink = document.getElementById('ux-preload-fonts-link');
10
- if (existingLink) return;
11
- const linkElement = document.createElement('link');
12
- linkElement.id = 'ux-preload-fonts-link';
13
- linkElement.rel = 'stylesheet';
14
- linkElement.href = PRELOAD_FONTS_URL;
15
- document.head.appendChild(linkElement);
16
- };
17
- const applyTheme = (theme)=>{
18
- if ('undefined' == typeof window) return;
19
- const root = document.documentElement;
20
- const isClassListCorrect = root.classList.contains(theme.id);
21
- const isDataThemeCorrect = root.getAttribute('data-theme') === theme.colorScheme;
22
- const isDataPrefersColorCorrect = root.getAttribute('data-prefers-color') === theme.colorScheme;
23
- if (isClassListCorrect && isDataThemeCorrect && isDataPrefersColorCorrect) return;
24
- if (!isDataThemeCorrect) root.setAttribute('data-theme', theme.colorScheme);
25
- if (!isDataPrefersColorCorrect) root.setAttribute('data-prefers-color', theme.colorScheme);
26
- root.classList.remove('dark');
27
- root.classList.remove('light');
28
- if (!isClassListCorrect) {
29
- themeKeys.forEach((key)=>{
30
- root.classList.remove(key);
31
- });
32
- root.classList.add(theme.id);
33
- }
34
- };
35
- const extractFontFamilyFromLink = (link)=>{
36
- if (!link) return null;
37
- try {
38
- const url = new URL(link);
39
- const familyParam = url.searchParams.get('family');
40
- if (!familyParam) return null;
41
- const firstFamily = familyParam.split('&family=')[0].split(':')[0].replace(/\+/g, ' ');
42
- return firstFamily;
43
- } catch {
44
- return null;
45
- }
46
- };
47
- const applyFont = (fontName)=>{
48
- if ('undefined' == typeof window) return;
49
- if (fontName) {
50
- document.documentElement.style.setProperty('--ux-font-family', `"${fontName}", ${DEFAULT_FONT_FAMILY}`);
51
- document.body.style.fontFamily = `"${fontName}", ${DEFAULT_FONT_FAMILY}`;
52
- } else {
53
- document.documentElement.style.setProperty('--ux-font-family', DEFAULT_FONT_FAMILY);
54
- document.body.style.fontFamily = DEFAULT_FONT_FAMILY;
55
- }
56
- };
3
+ import { applyFont, applyTheme, extractFontFamilyFromLink, preloadFonts } from "./utils.js";
57
4
  const useTheme = ()=>{
58
5
  const theme = useThemeStore((state)=>state.theme);
6
+ const customTheme = useThemeStore((state)=>state.customTheme);
59
7
  const fontUrl = useThemeStore((state)=>state.fontUrl);
60
8
  const fontName = useThemeStore((state)=>state.fontName);
61
9
  const fontLoadStatus = useThemeStore((state)=>state.fontLoadStatus);
62
10
  const storeSetTheme = useThemeStore((state)=>state.setTheme);
11
+ const storeSetCustomTheme = useThemeStore((state)=>state.setCustomTheme);
63
12
  const storeSetFontUrl = useThemeStore((state)=>state.setFontUrl);
64
13
  const storeSetFontLoadStatus = useThemeStore((state)=>state.setFontLoadStatus);
65
14
  const storeSetFontName = useThemeStore((state)=>state.setFontName);
@@ -92,11 +41,11 @@ const useTheme = ()=>{
92
41
  const { run: debouncedApplyFont } = useDebounceFn((customFontLink, themeFontName)=>applyFontWithStatus(customFontLink, themeFontName), {
93
42
  wait: 300
94
43
  });
95
- useEffect(()=>{
44
+ const initTheme = ()=>{
96
45
  preloadFonts();
97
46
  applyTheme(theme);
98
47
  debouncedApplyFont(fontUrl, theme.fontName);
99
- }, []);
48
+ };
100
49
  const setTheme = (theme)=>{
101
50
  storeSetTheme(theme);
102
51
  applyTheme(theme);
@@ -114,7 +63,10 @@ const useTheme = ()=>{
114
63
  };
115
64
  return {
116
65
  theme,
66
+ customTheme,
117
67
  setTheme,
68
+ initTheme,
69
+ setCustomTheme: storeSetCustomTheme,
118
70
  fontUrl,
119
71
  setFontUrl,
120
72
  clearFontUrl,