@particle-network/ui-react 0.5.1-beta.9 → 0.6.1-beta.0

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 (44) hide show
  1. package/dist/components/ProgressWrapper/index.js +1 -2
  2. package/dist/components/UXAutocomplete/index.js +1 -2
  3. package/dist/components/UXCheckbox/checkbox.extend.js +15 -12
  4. package/dist/components/UXColorPicker/color-picker.js +42 -30
  5. package/dist/components/UXColorPicker/types.d.ts +4 -0
  6. package/dist/components/UXHint/index.js +1 -1
  7. package/dist/components/UXModal/index.d.ts +1 -1
  8. package/dist/components/UXRangeInput/index.d.ts +42 -0
  9. package/dist/components/UXRangeInput/index.js +94 -0
  10. package/dist/components/UXThemeSwitch/custom-theme-config.d.ts +4 -1
  11. package/dist/components/UXThemeSwitch/custom-theme-config.js +4 -3
  12. package/dist/components/UXThemeSwitch/index.d.ts +2 -2
  13. package/dist/components/UXThemeSwitch/index.js +2 -2
  14. package/dist/components/UXThemeSwitch/theme-item.js +3 -4
  15. package/dist/components/UXThemeSwitch/theme-switch.d.ts +8 -1
  16. package/dist/components/UXThemeSwitch/theme-switch.js +11 -17
  17. package/dist/components/UXThemeSwitch/use-theme.d.ts +2 -1
  18. package/dist/components/UXThemeSwitch/use-theme.js +4 -9
  19. package/dist/components/UXThemeSwitch/utils.js +43 -6
  20. package/dist/components/UXToast/index.d.ts +1 -1
  21. package/dist/components/UXToast/index.js +22 -10
  22. package/dist/components/UXTooltip/index.js +4 -12
  23. package/dist/components/WrapText/index.d.ts +6 -0
  24. package/dist/components/WrapText/index.js +15 -0
  25. package/dist/components/index.d.ts +2 -0
  26. package/dist/components/index.js +2 -0
  27. package/dist/components/layout/Box/box-theme.d.ts +0 -12
  28. package/dist/components/layout/Box/box-theme.js +4 -8
  29. package/dist/components/layout/Box/box.js +10 -1
  30. package/dist/components/typography/Text.js +14 -4
  31. package/dist/components/typography/Text.type.d.ts +1 -0
  32. package/dist/hooks/useI18n.d.ts +8 -0
  33. package/dist/hooks/useI18n.js +8 -0
  34. package/dist/utils/cn.js +3 -11
  35. package/dist/utils/common.d.ts +4 -0
  36. package/dist/utils/common.js +13 -0
  37. package/package.json +3 -3
  38. package/tailwind-preset.js +6 -6
  39. package/dist/components/UXThemeSwitch/use-color-scheme.d.ts +0 -5
  40. package/dist/components/UXThemeSwitch/use-color-scheme.js +0 -14
  41. package/dist/components/UXThemeSwitch/use-theme-color.d.ts +0 -1
  42. package/dist/components/UXThemeSwitch/use-theme-color.js +0 -6
  43. package/dist/components/UXThemeSwitch/use-theme-store.d.ts +0 -46
  44. package/dist/components/UXThemeSwitch/use-theme-store.js +0 -36
@@ -1,11 +1,10 @@
1
1
  'use client';
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useMemo, useRef } from "react";
4
- import { radiusMap } from "@particle-network/ui-shared";
4
+ import { radiusMap, useThemeColor } from "@particle-network/ui-shared";
5
5
  import { useSize } from "ahooks";
6
6
  import { cn } from "../../utils/index.js";
7
7
  import { Center } from "../layout/index.js";
8
- import { useThemeColor } from "../UXThemeSwitch/use-theme-color.js";
9
8
  const ProgressWrapper = ({ className, value = 0, width, height, radius = 'sm', strokeWidth = 1, color = 'primary', children, svgClassName, ...restProps })=>{
10
9
  const uxColors = useThemeColor();
11
10
  const autoLayout = !width && !height;
@@ -3,10 +3,9 @@ import "react";
3
3
  import { Autocomplete, AutocompleteItem, AutocompleteSection } from "@heroui/autocomplete";
4
4
  import ChevronDownIcon from "@particle-network/icons/web/ChevronDownIcon";
5
5
  const UXAutocomplete = (props)=>{
6
- const { fullWidth = false, classNames = {}, radius = 'sm', labelPlacement = 'outside-top', ...restProps } = props;
6
+ const { classNames = {}, radius = 'sm', labelPlacement = 'outside-top', ...restProps } = props;
7
7
  const { base, popoverContent, selectorButton, endContentWrapper, clearButton, listboxWrapper } = classNames;
8
8
  return /*#__PURE__*/ jsx(Autocomplete, {
9
- fullWidth: fullWidth,
10
9
  classNames: {
11
10
  base: [
12
11
  'ux-base',
@@ -27,34 +27,37 @@ const ExtendedCheckbox = extendVariants(Checkbox, {
27
27
  },
28
28
  size: {
29
29
  sm: {
30
+ base: 'gap-1.5',
30
31
  wrapper: [
31
32
  'w-3.5 h-3.5 me-0',
32
33
  'rounded-[calc(theme(borderRadius.medium)*0.2)]',
33
34
  'before:rounded-[calc(theme(borderRadius.medium)*0.2)] before:border-secondary before:border-1',
34
35
  'after:rounded-[calc(theme(borderRadius.medium)*0.2)]'
35
36
  ],
36
- label: '!text-body3 font-medium',
37
- icon: 'h-2.5'
37
+ label: '!text-body2 font-medium',
38
+ icon: 'h-2'
38
39
  },
39
40
  md: {
41
+ base: 'gap-2',
40
42
  wrapper: [
41
43
  'w-4 h-4 me-0',
42
- 'rounded-[calc(theme(borderRadius.medium)*0.2)]',
43
- 'before:rounded-[calc(theme(borderRadius.medium)*0.2)] before:border-secondary before:border-1.5',
44
- 'after:rounded-[calc(theme(borderRadius.medium)*0.2)]'
44
+ 'rounded-[calc(theme(borderRadius.medium)*0.3)]',
45
+ 'before:rounded-[calc(theme(borderRadius.medium)*0.3)] before:border-secondary before:border-1.5',
46
+ 'after:rounded-[calc(theme(borderRadius.medium)*0.3)]'
45
47
  ],
46
48
  label: '!text-body2 font-medium',
47
- icon: 'h-3'
49
+ icon: 'h-2.5'
48
50
  },
49
51
  lg: {
52
+ base: 'gap-2',
50
53
  wrapper: [
51
54
  'w-[18px] h-[18px] me-0',
52
- 'rounded-[calc(theme(borderRadius.medium)*0.3)]',
53
- 'before:rounded-[calc(theme(borderRadius.medium)*0.3)] before:border-secondary before:border-1.5',
54
- 'after:rounded-[calc(theme(borderRadius.medium)*0.3)]'
55
+ 'rounded-[calc(theme(borderRadius.medium)*0.4)]',
56
+ 'before:rounded-[calc(theme(borderRadius.medium)*0.4)] before:border-secondary before:border-1.5',
57
+ 'after:rounded-[calc(theme(borderRadius.medium)*0.4)]'
55
58
  ],
56
59
  label: '!text-body1 font-medium',
57
- icon: 'h-3.5'
60
+ icon: 'h-3'
58
61
  }
59
62
  },
60
63
  radius: {
@@ -144,10 +147,10 @@ const ExtendedCheckbox = extendVariants(Checkbox, {
144
147
  },
145
148
  labelPlacement: {
146
149
  left: {
147
- base: 'flex-row-reverse gap-2'
150
+ base: 'flex-row-reverse'
148
151
  },
149
152
  right: {
150
- base: 'flex-row gap-2'
153
+ base: 'flex-row'
151
154
  }
152
155
  }
153
156
  },
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { ColorArea, ColorPicker, ColorSlider, ColorSwatch, ColorThumb, SliderTrack, parseColor } from "react-aria-components";
5
5
  import ColorPickerIcon from "@particle-network/icons/web/ColorPickerIcon";
@@ -12,11 +12,12 @@ import { useThemeColor } from "../UXThemeSwitch/index.js";
12
12
  import { ColorFields } from "./color-fields.js";
13
13
  import { ColorInput } from "./color-input.js";
14
14
  import { normalizeColor } from "./utils.js";
15
- const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', value, defaultValue, onChange, onChangeEnd, onValueChange, onValueChangeEnd, isChanged, onReset })=>{
16
- const { bg200: bg200 } = useThemeColor();
15
+ const UXColorPicker = ({ className, isDisabled, isIconOnly, placement = 'bottom-start', value, defaultValue, onChange, onChangeEnd, onValueChange, onValueChangeEnd, isChanged, onReset })=>{
16
+ const colors = useThemeColor();
17
17
  const isControlled = void 0 !== value;
18
18
  const [pickerKey, setPickerKey] = useState(0);
19
19
  const [isInputFocused, setIsInputFocused] = useState(false);
20
+ const [isInteracting, setIsInteracting] = useState(false);
20
21
  const getInitialColor = ()=>{
21
22
  if (isControlled && value) return normalizeColor(value);
22
23
  if (defaultValue) return normalizeColor(defaultValue);
@@ -31,12 +32,13 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
31
32
  return parseColor('#000000');
32
33
  });
33
34
  const currentColor = useMemo(()=>{
34
- if (isControlled && value) return normalizeColor(value);
35
+ if (isControlled && value && !isInteracting) return normalizeColor(value);
35
36
  return internalColor;
36
37
  }, [
37
38
  value,
38
39
  internalColor,
39
- isControlled
40
+ isControlled,
41
+ isInteracting
40
42
  ]);
41
43
  useEffect(()=>{
42
44
  const initialColor = getInitialColor();
@@ -62,7 +64,10 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
62
64
  ]);
63
65
  const handleChange = useCallback((color)=>{
64
66
  if (color) {
65
- setInternalColor(color);
67
+ if (isControlled) {
68
+ setInternalColor(color);
69
+ setIsInteracting(true);
70
+ } else setInternalColor(color);
66
71
  onChange?.(color);
67
72
  onValueChange?.(color.toString('hex'));
68
73
  }
@@ -86,6 +91,7 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
86
91
  ]);
87
92
  const handleChangeEnd = useCallback((color)=>{
88
93
  if (color) {
94
+ setIsInteracting(false);
89
95
  onChangeEnd?.(color);
90
96
  onValueChangeEnd?.(color.toString('hex'));
91
97
  }
@@ -123,12 +129,12 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
123
129
  handleChangeEnd
124
130
  ]);
125
131
  return /*#__PURE__*/ jsx(ColorPicker, {
126
- value: value,
132
+ value: currentColor,
127
133
  defaultValue: !isControlled && pickerKey > 0 ? internalColor : defaultValue,
128
134
  onChange: handleChange,
129
135
  children: /*#__PURE__*/ jsxs(HStack, {
130
136
  gap: 2,
131
- className: cn('rounded-small bg-background-200 px-md h-[30px] w-[8.5rem]', isDisabled && 'opacity-disabled', isInputFocused && 'ring-foreground ring-1', className),
137
+ className: cn(!isIconOnly && 'px-md rounded-small bg-background-200 h-[30px] w-[8.5rem]', isDisabled && 'opacity-disabled', isInputFocused && 'ring-foreground ring-1', className),
132
138
  children: [
133
139
  /*#__PURE__*/ jsxs(UXPopover, {
134
140
  placement: placement,
@@ -139,7 +145,7 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
139
145
  size: "auto",
140
146
  isDisabled: isDisabled,
141
147
  children: /*#__PURE__*/ jsx(ColorSwatch, {
142
- className: cn('h-4 w-4 rounded-[4px]', internalColor.toString('hex') === bg200 && 'border-foreground/10 border')
148
+ className: cn('h-4 w-4 rounded-[4px]', internalColor.toString('hex') === colors.bg200 && 'border-foreground/10 border')
143
149
  })
144
150
  })
145
151
  }),
@@ -153,6 +159,7 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
153
159
  xChannel: "saturation",
154
160
  yChannel: "brightness",
155
161
  className: "aspect-square w-full overflow-hidden rounded-lg",
162
+ onChange: handleChange,
156
163
  onChangeEnd: handleChangeEnd,
157
164
  children: /*#__PURE__*/ jsx(ColorThumb, {
158
165
  className: "h-4 w-4 rounded-full border-2 border-white shadow-[0_2px_4px_rgba(0,0,0,0.2)]"
@@ -179,6 +186,7 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
179
186
  className: "min-w-0 flex-1",
180
187
  colorSpace: "hsl",
181
188
  orientation: "horizontal",
189
+ onChange: handleChange,
182
190
  onChangeEnd: handleChangeEnd,
183
191
  children: /*#__PURE__*/ jsx(SliderTrack, {
184
192
  className: "h-3 rounded-full",
@@ -191,7 +199,7 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
191
199
  }),
192
200
  /*#__PURE__*/ jsx(ColorFields, {
193
201
  defaultValue: !isControlled && pickerKey > 0 ? internalColor : defaultValue,
194
- value: value,
202
+ value: currentColor,
195
203
  onChange: handleColorFieldsChange
196
204
  })
197
205
  ]
@@ -199,26 +207,30 @@ const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', valu
199
207
  })
200
208
  ]
201
209
  }),
202
- /*#__PURE__*/ jsx(ColorInput, {
203
- isDisabled: isDisabled,
204
- inputClassName: "focus:ring-0 px-0 text-left flex-1 relative bg-transparent",
205
- value: value,
206
- defaultValue: !isControlled && pickerKey > 0 ? internalColor : defaultValue,
207
- onChange: handleColorFieldsChange,
208
- onFocus: ()=>setIsInputFocused(true),
209
- onBlur: ()=>setIsInputFocused(false)
210
- }),
211
- hasChanged ? /*#__PURE__*/ jsx(UXButton, {
212
- isIconOnly: true,
213
- "aria-label": "Reset color",
214
- isDisabled: isDisabled,
215
- size: "sm",
216
- variant: "light",
217
- color: "secondary",
218
- onPress: handleReset,
219
- children: /*#__PURE__*/ jsx(RefreshCcwIcon, {})
220
- }) : /*#__PURE__*/ jsx("div", {
221
- className: "size-4 shrink-0"
210
+ !isIconOnly && /*#__PURE__*/ jsxs(Fragment, {
211
+ children: [
212
+ /*#__PURE__*/ jsx(ColorInput, {
213
+ isDisabled: isDisabled,
214
+ inputClassName: "focus:ring-0 px-0 text-left flex-1 relative bg-transparent",
215
+ value: currentColor,
216
+ defaultValue: !isControlled && pickerKey > 0 ? internalColor : defaultValue,
217
+ onChange: handleColorFieldsChange,
218
+ onFocus: ()=>setIsInputFocused(true),
219
+ onBlur: ()=>setIsInputFocused(false)
220
+ }),
221
+ hasChanged ? /*#__PURE__*/ jsx(UXButton, {
222
+ isIconOnly: true,
223
+ "aria-label": "Reset color",
224
+ isDisabled: isDisabled,
225
+ size: "sm",
226
+ variant: "light",
227
+ color: "secondary",
228
+ onPress: handleReset,
229
+ children: /*#__PURE__*/ jsx(RefreshCcwIcon, {})
230
+ }) : /*#__PURE__*/ jsx("div", {
231
+ className: "size-4 shrink-0"
232
+ })
233
+ ]
222
234
  })
223
235
  ]
224
236
  })
@@ -42,6 +42,10 @@ export interface UXColorPickerProps {
42
42
  * Popover 位置
43
43
  */
44
44
  placement?: UXPopoverProps['placement'];
45
+ /**
46
+ * 是否只显示图标
47
+ */
48
+ isIconOnly?: boolean;
45
49
  }
46
50
  export interface ColorFieldsProps extends Pick<UXColorPickerProps, 'value' | 'defaultValue'> {
47
51
  /**
@@ -6,7 +6,7 @@ import { cn } from "../../utils/index.js";
6
6
  const UXHint = (props)=>{
7
7
  const { content, children, buttonClassName, iconClassName, triggerType = 'hover', ...restProps } = props;
8
8
  const renderTriggerContent = ()=>/*#__PURE__*/ jsx(Center, {
9
- className: cn('size-4 cursor-pointer', buttonClassName),
9
+ className: cn('min-h-4 min-w-4 cursor-pointer', buttonClassName),
10
10
  children: /*#__PURE__*/ jsx(CircleQuestionIcon, {
11
11
  size: 14,
12
12
  className: iconClassName
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type ModalProps } from '@heroui/modal';
3
- export type UXModalProps = Omit<ModalProps, 'closeButton'> & {
3
+ export type UXModalProps = Omit<ModalProps, 'closeButton' | 'title'> & {
4
4
  title?: React.ReactNode;
5
5
  footer?: React.ReactNode;
6
6
  tip?: React.ReactNode;
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { type UXNumberInputProps } from '../UXNumberInput';
3
+ export interface UXRangeInputValue {
4
+ min?: number;
5
+ max?: number;
6
+ }
7
+ export type UXRangeInputProps = Omit<UXNumberInputProps, 'value' | 'defaultValue' | 'onValueChange' | 'minValue' | 'maxValue'> & {
8
+ asFragment?: boolean;
9
+ /**
10
+ * The current value of the range input (controlled)
11
+ */
12
+ value?: UXRangeInputValue;
13
+ /**
14
+ * The default value of the range input (uncontrolled)
15
+ */
16
+ defaultValue?: UXRangeInputValue;
17
+ /**
18
+ * The minimum value allowed for both inputs
19
+ */
20
+ minValue?: number;
21
+ /**
22
+ * The maximum value allowed for both inputs
23
+ */
24
+ maxValue?: number;
25
+ /**
26
+ * Props for the minimum input
27
+ */
28
+ minInputProps?: Partial<UXNumberInputProps>;
29
+ /**
30
+ * Props for the maximum input
31
+ */
32
+ maxInputProps?: Partial<UXNumberInputProps>;
33
+ /**
34
+ * Separator between the two inputs
35
+ */
36
+ separator?: React.ReactNode;
37
+ /**
38
+ * Callback fired when the value changes
39
+ */
40
+ onValueChange?: (value: UXRangeInputValue) => void;
41
+ };
42
+ export declare const UXRangeInput: React.FC<UXRangeInputProps>;
@@ -0,0 +1,94 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import react, { Fragment, useCallback, useMemo } from "react";
3
+ import { useI18n } from "../../hooks/index.js";
4
+ import { HStack } from "../layout/index.js";
5
+ import { UXNumberInput } from "../UXNumberInput/index.js";
6
+ const UXRangeInput = (props)=>{
7
+ const { asFragment, value, defaultValue, onValueChange, minValue, maxValue, minInputProps = {}, maxInputProps = {}, separator = '', className, ...restProps } = props;
8
+ const i18n = useI18n();
9
+ const [internalValue, setInternalValue] = react.useState(defaultValue || {
10
+ min: void 0,
11
+ max: void 0
12
+ });
13
+ const currentValue = void 0 !== value ? value : internalValue;
14
+ const handleMinChange = useCallback((newMin)=>{
15
+ const minValue = isNaN(newMin) ? 0 : newMin;
16
+ const newValue = {
17
+ min: minValue,
18
+ max: currentValue.max
19
+ };
20
+ if (void 0 !== currentValue.max && !isNaN(currentValue.max) && minValue > currentValue.max) newValue.max = minValue;
21
+ if (void 0 === value) setInternalValue(newValue);
22
+ onValueChange?.(newValue);
23
+ }, [
24
+ currentValue.max,
25
+ value,
26
+ onValueChange
27
+ ]);
28
+ const handleMaxChange = useCallback((newMax)=>{
29
+ const maxValue = isNaN(newMax) ? 0 : newMax;
30
+ const newValue = {
31
+ min: currentValue.min,
32
+ max: maxValue
33
+ };
34
+ if (void 0 !== currentValue.min && !isNaN(currentValue.min) && maxValue < currentValue.min) newValue.min = maxValue;
35
+ if (void 0 === value) setInternalValue(newValue);
36
+ onValueChange?.(newValue);
37
+ }, [
38
+ currentValue.min,
39
+ value,
40
+ onValueChange
41
+ ]);
42
+ const minInputMaxValue = useMemo(()=>{
43
+ if (void 0 !== currentValue.max && !isNaN(currentValue.max)) return currentValue.max;
44
+ return maxValue;
45
+ }, [
46
+ currentValue.max,
47
+ maxValue
48
+ ]);
49
+ const maxInputMinValue = useMemo(()=>{
50
+ if (void 0 !== currentValue.min && !isNaN(currentValue.min)) return currentValue.min;
51
+ return minValue;
52
+ }, [
53
+ currentValue.min,
54
+ minValue
55
+ ]);
56
+ const Wrapper = asFragment ? Fragment : HStack;
57
+ return /*#__PURE__*/ jsxs(Wrapper, {
58
+ gap: 2,
59
+ className: className,
60
+ children: [
61
+ /*#__PURE__*/ jsx(UXNumberInput, {
62
+ startContent: /*#__PURE__*/ jsx("span", {
63
+ className: "shrink-0",
64
+ "aria-hidden": "true",
65
+ children: i18n.rangeInput.min
66
+ }),
67
+ textAlign: "right",
68
+ ...restProps,
69
+ ...minInputProps,
70
+ value: currentValue.min,
71
+ minValue: minValue,
72
+ maxValue: minInputMaxValue,
73
+ onValueChange: handleMinChange
74
+ }),
75
+ separator,
76
+ /*#__PURE__*/ jsx(UXNumberInput, {
77
+ startContent: /*#__PURE__*/ jsx("span", {
78
+ className: "shrink-0",
79
+ "aria-hidden": "true",
80
+ children: i18n.rangeInput.max
81
+ }),
82
+ textAlign: "right",
83
+ ...restProps,
84
+ ...maxInputProps,
85
+ value: currentValue.max,
86
+ minValue: maxInputMinValue,
87
+ maxValue: maxValue,
88
+ onValueChange: handleMaxChange
89
+ })
90
+ ]
91
+ });
92
+ };
93
+ UXRangeInput.displayName = 'UX.RangeInput';
94
+ export { UXRangeInput };
@@ -1,2 +1,5 @@
1
1
  import React from 'react';
2
- export declare const CustomThemeConfig: React.FC;
2
+ export interface CustomThemeConfigProps {
3
+ colorChangeMode?: 'drag' | 'dragEnd';
4
+ }
5
+ export declare const CustomThemeConfig: React.FC<CustomThemeConfigProps>;
@@ -46,7 +46,7 @@ const COLOR_CATEGORIES = {
46
46
  'blue'
47
47
  ]
48
48
  };
49
- const CustomThemeConfig = ()=>{
49
+ const CustomThemeConfig = ({ colorChangeMode = 'dragEnd' })=>{
50
50
  const { lang } = useLang();
51
51
  const i18n = useI18n();
52
52
  const { theme, setTheme, setCustomTheme } = useTheme();
@@ -102,9 +102,10 @@ const CustomThemeConfig = ()=>{
102
102
  children: label
103
103
  }),
104
104
  /*#__PURE__*/ jsx(UXColorPicker, {
105
- value: value,
105
+ defaultValue: value,
106
106
  isChanged: isCustomized,
107
- onValueChange: (newValue)=>handleColorChange(color, newValue),
107
+ onValueChange: 'drag' === colorChangeMode ? (newValue)=>handleColorChange(color, newValue) : void 0,
108
+ onValueChangeEnd: 'dragEnd' === colorChangeMode ? (newValue)=>handleColorChange(color, newValue) : void 0,
108
109
  onReset: ()=>handleColorChange(color, baseTheme.colorVariables[color])
109
110
  })
110
111
  ]
@@ -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 };
@@ -162,8 +162,7 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
162
162
  'custom' === id ? /*#__PURE__*/ jsxs(Fragment, {
163
163
  children: [
164
164
  /*#__PURE__*/ jsx("g", {
165
- "clip-path": "url(#paint0_angular_48986_280686_clip_path)",
166
- "data-figma-skip-parse": "true",
165
+ clipPath: "url(#paint0_angular_48986_280686_clip_path)",
167
166
  children: /*#__PURE__*/ jsx("g", {
168
167
  transform: "matrix(0 0.011 -0.011 0 39 51)",
169
168
  children: /*#__PURE__*/ jsx("foreignObject", {
@@ -188,7 +187,7 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
188
187
  r: "10.7583",
189
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}',
190
189
  stroke: "#8B8EA1",
191
- "stroke-width": "0.483303"
190
+ strokeWidth: "0.483303"
192
191
  }),
193
192
  /*#__PURE__*/ jsx("defs", {
194
193
  children: /*#__PURE__*/ jsx("clipPath", {
@@ -197,7 +196,7 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
197
196
  cx: "39",
198
197
  cy: "51",
199
198
  r: "10.7583",
200
- "stroke-width": "0.483303"
199
+ strokeWidth: "0.483303"
201
200
  })
202
201
  })
203
202
  })
@@ -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,8 +1,8 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useMemo, useState } from "react";
2
+ import { useEffect, useMemo, useState } from "react";
3
3
  import { useDisclosure } from "@heroui/use-disclosure";
4
4
  import { ChartColorSwitchIcon, CopyIcon } from "@particle-network/icons/web";
5
- import { DEFAULT_THEME_ID, themeData } from "@particle-network/ui-shared";
5
+ import { themeData } from "@particle-network/ui-shared";
6
6
  import { useI18n } from "../../hooks/index.js";
7
7
  import { cn } from "../../utils/index.js";
8
8
  import { HStack, VStack } from "../layout/index.js";
@@ -32,27 +32,19 @@ const FONT_EXAMPLES = [
32
32
  url: 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap'
33
33
  }
34
34
  ];
35
- const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, onClose, onOpenChange })=>{
35
+ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, onClose, onOpenChange, colorChangeMode })=>{
36
36
  const i18n = useI18n();
37
- const { theme: selectedTheme, customTheme: savedCustomTheme, setTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
37
+ const { theme: selectedTheme, customTheme: savedCustomTheme, setTheme, initTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
38
38
  const [isFontExampleOpen, setIsFontExampleOpen] = useState(false);
39
+ useEffect(()=>{
40
+ initTheme();
41
+ }, []);
39
42
  const Component = 'modal' === as ? UXModal : UXDrawer;
40
43
  const themes = useMemo(()=>themeData.filter((theme)=>!omitThemes.includes(theme.id)), [
41
44
  omitThemes
42
45
  ]);
43
46
  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);
47
+ 'custom' === theme.id ? setTheme(savedCustomTheme) : setTheme(theme);
56
48
  };
57
49
  return /*#__PURE__*/ jsx(Component, {
58
50
  isOpen: isOpen,
@@ -83,7 +75,9 @@ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, o
83
75
  'custom' === selectedTheme.id && /*#__PURE__*/ jsxs(Fragment, {
84
76
  children: [
85
77
  /*#__PURE__*/ jsx(UXDivider, {}),
86
- /*#__PURE__*/ jsx(CustomThemeConfig, {})
78
+ /*#__PURE__*/ jsx(CustomThemeConfig, {
79
+ colorChangeMode: colorChangeMode
80
+ })
87
81
  ]
88
82
  }),
89
83
  /*#__PURE__*/ jsx(UXDivider, {}),
@@ -6,10 +6,11 @@ export declare const useTheme: () => {
6
6
  theme: ThemeItemType;
7
7
  customTheme: ThemeItemType;
8
8
  setTheme: (theme: ThemeItemType) => void;
9
+ initTheme: () => void;
9
10
  setCustomTheme: (customTheme: ThemeItemType) => void;
10
11
  fontUrl: string;
11
12
  setFontUrl: (link: string) => void;
12
13
  clearFontUrl: () => void;
13
- fontLoadStatus: import("./use-theme-store").FontLoadStatus;
14
+ fontLoadStatus: import("@particle-network/ui-shared").FontLoadStatus;
14
15
  fontName: string;
15
16
  };
@@ -1,6 +1,5 @@
1
- import { useEffect } from "react";
1
+ import { useThemeStore } from "@particle-network/ui-shared";
2
2
  import { useDebounceFn } from "ahooks";
3
- import { useThemeStore } from "./use-theme-store.js";
4
3
  import { applyFont, applyTheme, extractFontFamilyFromLink, preloadFonts } from "./utils.js";
5
4
  const useTheme = ()=>{
6
5
  const theme = useThemeStore((state)=>state.theme);
@@ -42,16 +41,11 @@ const useTheme = ()=>{
42
41
  const { run: debouncedApplyFont } = useDebounceFn((customFontLink, themeFontName)=>applyFontWithStatus(customFontLink, themeFontName), {
43
42
  wait: 300
44
43
  });
45
- useEffect(()=>{
44
+ const initTheme = ()=>{
46
45
  preloadFonts();
47
46
  applyTheme(theme);
48
47
  debouncedApplyFont(fontUrl, theme.fontName);
49
- }, []);
50
- useEffect(()=>{
51
- applyTheme(theme);
52
- }, [
53
- theme
54
- ]);
48
+ };
55
49
  const setTheme = (theme)=>{
56
50
  storeSetTheme(theme);
57
51
  applyTheme(theme);
@@ -71,6 +65,7 @@ const useTheme = ()=>{
71
65
  theme,
72
66
  customTheme,
73
67
  setTheme,
68
+ initTheme,
74
69
  setCustomTheme: storeSetCustomTheme,
75
70
  fontUrl,
76
71
  setFontUrl,