@particle-network/ui-react 0.4.0-beta.2 → 0.4.0-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 (37) hide show
  1. package/dist/components/ProgressWrapper/index.d.ts +1 -1
  2. package/dist/components/ProgressWrapper/index.js +18 -3
  3. package/dist/components/UXAutocomplete/index.d.ts +5 -0
  4. package/dist/components/UXAutocomplete/index.js +72 -0
  5. package/dist/components/UXDrawer/index.d.ts +9 -0
  6. package/dist/components/UXDrawer/index.js +89 -0
  7. package/dist/components/UXDropdown/dropdown-item.js +1 -1
  8. package/dist/components/UXEmpty/index.js +3 -1
  9. package/dist/components/UXInput/index.d.ts +28 -28
  10. package/dist/components/UXInput/input.extend.d.ts +28 -28
  11. package/dist/components/UXModal/index.js +3 -1
  12. package/dist/components/UXSelect/index.js +2 -2
  13. package/dist/components/UXSwitch/index.d.ts +17 -17
  14. package/dist/components/UXSwitch/switch.extend.d.ts +17 -17
  15. package/dist/components/UXTable/index.d.ts +17 -17
  16. package/dist/components/UXTable/table.extend.d.ts +17 -17
  17. package/dist/components/UXTabs/tabs.classes.js +7 -7
  18. package/dist/components/UXThemeSwitch/index.d.ts +0 -1
  19. package/dist/components/UXThemeSwitch/index.js +0 -1
  20. package/dist/components/UXThemeSwitch/theme-item.d.ts +1 -1
  21. package/dist/components/UXThemeSwitch/theme-item.js +5 -4
  22. package/dist/components/UXThemeSwitch/theme-switch.js +72 -86
  23. package/dist/components/UXThemeSwitch/use-color-scheme.d.ts +1 -1
  24. package/dist/components/UXThemeSwitch/use-theme-color.d.ts +1 -19
  25. package/dist/components/UXThemeSwitch/use-theme-store.d.ts +1 -6
  26. package/dist/components/UXThemeSwitch/use-theme-store.js +2 -6
  27. package/dist/components/UXThemeSwitch/use-theme.d.ts +2 -4
  28. package/dist/components/UXThemeSwitch/use-theme.js +65 -50
  29. package/dist/components/UXToast/index.d.ts +7 -4
  30. package/dist/components/UXToast/index.js +21 -17
  31. package/dist/components/UXTooltip/tooltip.extend.d.ts +19 -19
  32. package/dist/components/index.d.ts +2 -0
  33. package/dist/components/index.js +2 -0
  34. package/package.json +4 -5
  35. package/tailwind-preset.js +192 -93
  36. package/dist/components/UXThemeSwitch/theme-data.d.ts +0 -29
  37. package/dist/components/UXThemeSwitch/theme-data.js +0 -304
@@ -40,7 +40,7 @@ declare const ExtendedTable: import("react").ForwardRefExoticComponent<Omit<{
40
40
  vocab?: string | undefined;
41
41
  autoCorrect?: string | undefined;
42
42
  autoSave?: string | undefined;
43
- color?: "default" | "secondary" | "primary" | "success" | "danger" | "warning" | undefined;
43
+ color?: "default" | "success" | "secondary" | "primary" | "danger" | "warning" | undefined;
44
44
  itemProp?: string | undefined;
45
45
  itemScope?: boolean | undefined;
46
46
  itemType?: string | undefined;
@@ -288,32 +288,32 @@ declare const ExtendedTable: import("react").ForwardRefExoticComponent<Omit<{
288
288
  layout?: "auto" | "fixed" | undefined;
289
289
  border?: number | undefined;
290
290
  key?: import("react").Key | null | undefined;
291
+ classNames?: import("@heroui/theme").SlotsToClasses<"table" | "base" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "wrapper" | "sortIcon" | "emptyWrapper" | "loadingWrapper"> | undefined;
291
292
  disableAnimation?: boolean | undefined;
292
- shadow?: "sm" | "md" | "lg" | "none" | undefined;
293
293
  summary?: string | undefined;
294
294
  as?: import("@heroui/system-rsc").As<any> | undefined;
295
- bgcolor?: string | undefined;
296
- cellPadding?: string | number | undefined;
297
- cellSpacing?: string | number | undefined;
298
- frame?: boolean | undefined;
299
- rules?: "none" | "all" | "rows" | "groups" | "columns" | undefined;
300
- classNames?: import("@heroui/theme").SlotsToClasses<"table" | "base" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "wrapper" | "sortIcon" | "emptyWrapper" | "loadingWrapper"> | undefined;
301
- topContent?: import("react").ReactNode;
302
- bottomContent?: import("react").ReactNode;
295
+ baseRef?: import("@heroui/react-utils").ReactRef<HTMLElement | null> | undefined;
296
+ disallowEmptySelection?: boolean | undefined;
297
+ onSelectionChange?: ((keys: import("@react-types/shared").Selection) => void) | undefined;
298
+ disabledKeys?: Iterable<import("@react-types/shared").Key> | undefined;
303
299
  scrollRef?: import("@react-types/shared").RefObject<HTMLElement | null> | undefined;
304
300
  isVirtualized?: boolean | undefined;
301
+ shadow?: "sm" | "md" | "lg" | "none" | undefined;
302
+ topContent?: import("react").ReactNode;
303
+ bottomContent?: import("react").ReactNode;
304
+ keyboardDelegate?: import("@react-types/shared").KeyboardDelegate | undefined;
305
+ selectionBehavior?: "replace" | "toggle" | undefined;
306
+ shouldSelectOnPressUp?: boolean | undefined;
305
307
  escapeKeyBehavior?: "none" | "clearSelection" | undefined;
306
- disabledKeys?: Iterable<import("@react-types/shared").Key> | undefined;
307
308
  selectionMode?: import("@react-types/shared").SelectionMode | undefined;
308
- disallowEmptySelection?: boolean | undefined;
309
309
  selectedKeys?: "all" | Iterable<import("@react-types/shared").Key> | undefined;
310
310
  defaultSelectedKeys?: "all" | Iterable<import("@react-types/shared").Key> | undefined;
311
- onSelectionChange?: ((keys: import("@react-types/shared").Selection) => void) | undefined;
312
- baseRef?: import("@heroui/react-utils").ReactRef<HTMLElement | null> | undefined;
311
+ bgcolor?: string | undefined;
312
+ cellPadding?: string | number | undefined;
313
+ cellSpacing?: string | number | undefined;
314
+ frame?: boolean | undefined;
315
+ rules?: "none" | "all" | "rows" | "groups" | "columns" | undefined;
313
316
  isCompact?: boolean | undefined;
314
- keyboardDelegate?: import("@react-types/shared").KeyboardDelegate | undefined;
315
- selectionBehavior?: "replace" | "toggle" | undefined;
316
- shouldSelectOnPressUp?: boolean | undefined;
317
317
  hideHeader?: boolean | undefined;
318
318
  isStriped?: boolean | undefined;
319
319
  isHeaderSticky?: boolean | undefined;
@@ -3,7 +3,7 @@ const tabsClasses = {
3
3
  variants: {
4
4
  variant: {
5
5
  solid: {
6
- tabList: 'gap-0 bg-background-400',
6
+ tabList: 'gap-0 bg-background-200',
7
7
  tab: 'py-0 !outline-none',
8
8
  cursor: 'shadow-none inset-0',
9
9
  tabContent: 'text-foreground-300 font-medium'
@@ -252,9 +252,9 @@ const tabsClasses = {
252
252
  color: 'default',
253
253
  class: {
254
254
  cursor: [
255
- 'bg-background-200'
255
+ '!bg-tertiary'
256
256
  ],
257
- tabContent: 'group-data-[selected=true]:text-default-foreground'
257
+ tabContent: 'group-data-[selected=true]:text-tertiary-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-foreground-100'
267
+ '!bg-tertiary'
268
268
  ],
269
- tabContent: 'group-data-[selected=true]:text-default-foreground'
269
+ tabContent: 'group-data-[selected=true]:text-tertiary-foreground'
270
270
  }
271
271
  },
272
272
  {
@@ -276,9 +276,9 @@ const tabsClasses = {
276
276
  color: 'default',
277
277
  class: {
278
278
  cursor: [
279
- 'bg-background-300'
279
+ '!bg-tertiary'
280
280
  ],
281
- tabContent: 'group-data-[selected=true]:text-default-foreground'
281
+ tabContent: 'group-data-[selected=true]:text-tertiary-foreground'
282
282
  }
283
283
  },
284
284
  {
@@ -1,4 +1,3 @@
1
- export * from './theme-data';
2
1
  export * from './theme-switch';
3
2
  export * from './use-color-scheme';
4
3
  export * from './use-theme';
@@ -1,4 +1,3 @@
1
- export * from "./theme-data.js";
2
1
  export * from "./theme-switch.js";
3
2
  export * from "./use-color-scheme.js";
4
3
  export * from "./use-theme.js";
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { ThemeItemType } from './theme-data';
2
+ import type { ThemeItemType } from '@particle-network/ui-shared';
3
3
  export interface ThemeItemProps extends ThemeItemType {
4
4
  isSelected: boolean;
5
5
  onClick: () => void;
@@ -8,15 +8,16 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
8
8
  const lang = useLang();
9
9
  return /*#__PURE__*/ jsxs(VStack, {
10
10
  center: true,
11
- className: cn('cursor-pointer hover:scale-105 transition-all duration-300', id),
11
+ gap: 2,
12
+ className: cn('cursor-pointer', id),
12
13
  onClick: onClick,
13
14
  children: [
14
15
  /*#__PURE__*/ jsx("div", {
15
- className: cn('rounded-small border-1.5', isSelected ? 'border-primary' : 'border-transparent'),
16
+ className: cn('rounded-medium border-2 hover:scale-105 transition-all duration-300', isSelected ? 'border-primary' : 'border-transparent'),
16
17
  children: /*#__PURE__*/ jsxs("svg", {
17
18
  xmlns: "http://www.w3.org/2000/svg",
18
- width: "180",
19
- height: "106.5",
19
+ width: "120",
20
+ height: "71",
20
21
  viewBox: "0 0 120 71",
21
22
  fill: "none",
22
23
  children: [
@@ -1,21 +1,21 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import "react";
3
- import { Drawer, DrawerBody, DrawerContent, DrawerFooter, DrawerHeader } from "@heroui/drawer";
4
3
  import { useDisclosure } from "@heroui/use-disclosure";
5
- import { ThemeSwitchIcon } from "@particle-network/icons/web";
4
+ import { ChartColorSwitchIcon } from "@particle-network/icons/web";
5
+ import { themeData } from "@particle-network/ui-shared";
6
6
  import { useI18n } from "../../hooks/index.js";
7
- import { Flex, HStack, VStack } from "../layout/index.js";
7
+ import { HStack, VStack } from "../layout/index.js";
8
8
  import { Text } from "../typography/Text.js";
9
9
  import { UXButton } from "../UXButton/index.js";
10
10
  import { UXDivider } from "../UXDivider/index.js";
11
+ import { UXDrawer } from "../UXDrawer/index.js";
11
12
  import { UXInput } from "../UXInput/index.js";
12
13
  import { UXSpinner } from "../UXSpinner/index.js";
13
- import { themeData } from "./theme-data.js";
14
14
  import { ThemeItem } from "./theme-item.js";
15
15
  import { useTheme } from "./use-theme.js";
16
16
  const UXThemeSwitchDrawer = ({ isOpen, onClose, onOpenChange, ...props })=>{
17
17
  const i18n = useI18n();
18
- const { selectedTheme, setSelectedTheme, savedTheme, setSavedTheme, selectedFontLink, setSelectedFontLink, savedFontLink, setSavedFontLink, fontName, fontLoadStatus, fontLoadError } = useTheme();
18
+ const { selectedTheme, setSelectedTheme, savedTheme, setSavedTheme, selectedFontLink, setSelectedFontLink, savedFontLink, setSavedFontLink, fontName, fontLoadStatus } = useTheme();
19
19
  const handleOpenChange = (_isOpen)=>{
20
20
  onOpenChange?.(_isOpen);
21
21
  if (!_isOpen) {
@@ -32,96 +32,82 @@ const UXThemeSwitchDrawer = ({ isOpen, onClose, onOpenChange, ...props })=>{
32
32
  setSelectedTheme(savedTheme);
33
33
  setSelectedFontLink(savedFontLink);
34
34
  };
35
- return /*#__PURE__*/ jsx(Drawer, {
35
+ return /*#__PURE__*/ jsxs(UXDrawer, {
36
36
  isOpen: isOpen,
37
37
  backdrop: "transparent",
38
- onOpenChange: handleOpenChange,
39
- ...props,
40
- children: /*#__PURE__*/ jsxs(DrawerContent, {
38
+ title: i18n.theme.title,
39
+ footer: /*#__PURE__*/ jsxs(HStack, {
40
+ fullWidth: true,
41
+ gap: "lg",
41
42
  children: [
42
- /*#__PURE__*/ jsx(DrawerHeader, {
43
- className: "flex flex-col gap-1",
44
- children: i18n.theme.title
43
+ /*#__PURE__*/ jsx(UXButton, {
44
+ fullWidth: true,
45
+ size: "lg",
46
+ onPress: handleReset,
47
+ children: i18n.theme.reset
45
48
  }),
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"
49
+ /*#__PURE__*/ jsx(UXButton, {
50
+ fullWidth: true,
51
+ isDisabled: 'error' === fontLoadStatus,
52
+ size: "lg",
53
+ color: "primary",
54
+ onPress: handleApplyTheme,
55
+ children: i18n.theme.apply
56
+ })
57
+ ]
58
+ }),
59
+ onOpenChange: handleOpenChange,
60
+ ...props,
61
+ children: [
62
+ /*#__PURE__*/ jsx("div", {
63
+ className: "grid grid-cols-3 gap-y-5",
64
+ children: themeData.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
65
+ isSelected: selectedTheme.id === theme.id,
66
+ onClick: ()=>setSelectedTheme(theme),
67
+ ...theme
68
+ }, theme.id))
69
+ }),
70
+ /*#__PURE__*/ jsx(UXDivider, {
71
+ className: "my-lg"
72
+ }),
73
+ /*#__PURE__*/ jsxs(VStack, {
74
+ gap: "md",
75
+ children: [
76
+ /*#__PURE__*/ jsx(Text, {
77
+ body1Bold: true,
78
+ children: i18n.theme.font.title
79
+ }),
80
+ /*#__PURE__*/ jsx(UXInput, {
81
+ isClearable: true,
82
+ startContent: 'loading' === fontLoadStatus && /*#__PURE__*/ jsx(UXSpinner, {
83
+ size: 18
60
84
  }),
61
- /*#__PURE__*/ jsxs(VStack, {
62
- gap: "md",
85
+ isInvalid: 'error' === fontLoadStatus,
86
+ className: "w-full",
87
+ placeholder: i18n.theme.font.placeholder,
88
+ value: selectedFontLink,
89
+ description: /*#__PURE__*/ jsxs(Fragment, {
63
90
  children: [
64
- /*#__PURE__*/ jsx(Text, {
65
- body1Bold: true,
66
- children: i18n.theme.font.title
91
+ 'success' === fontLoadStatus && /*#__PURE__*/ jsxs(Text, {
92
+ body3Bold: true,
93
+ color: "success",
94
+ children: [
95
+ i18n.theme.font.success,
96
+ fontName
97
+ ]
67
98
  }),
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
99
+ 'error' === fontLoadStatus && /*#__PURE__*/ jsx(Text, {
100
+ body3Bold: true,
101
+ color: "danger",
102
+ children: i18n.theme.font.error
95
103
  })
96
104
  ]
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
- ]
105
+ }),
106
+ onValueChange: setSelectedFontLink
121
107
  })
122
- })
123
- ]
124
- })
108
+ ]
109
+ })
110
+ ]
125
111
  });
126
112
  };
127
113
  const UXThemeSwitch = ({ children })=>{
@@ -132,7 +118,7 @@ const UXThemeSwitch = ({ children })=>{
132
118
  isIconOnly: true,
133
119
  variant: "light",
134
120
  onPress: onOpen,
135
- children: /*#__PURE__*/ jsx(ThemeSwitchIcon, {})
121
+ children: /*#__PURE__*/ jsx(ChartColorSwitchIcon, {})
136
122
  });
137
123
  };
138
124
  return /*#__PURE__*/ jsxs(Fragment, {
@@ -1,5 +1,5 @@
1
1
  export declare const useColorScheme: () => {
2
- colorScheme: import("./theme-data").ColorScheme;
2
+ colorScheme: import("@particle-network/ui-shared").ColorScheme;
3
3
  isDark: boolean;
4
4
  isLight: boolean;
5
5
  };
@@ -1,19 +1 @@
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
- };
1
+ export declare const useThemeColor: () => Record<import("@particle-network/ui-shared").UXColor, string>;
@@ -1,4 +1,4 @@
1
- import { type ThemeItemType } from './theme-data';
1
+ import { type ThemeItemType } from '@particle-network/ui-shared';
2
2
  export type FontLoadStatus = 'idle' | 'loading' | 'success' | 'error';
3
3
  interface State {
4
4
  /**
@@ -25,10 +25,6 @@ interface State {
25
25
  * 字体加载状态
26
26
  */
27
27
  fontLoadStatus: FontLoadStatus;
28
- /**
29
- * 字体加载错误信息
30
- */
31
- fontLoadError: string | null;
32
28
  }
33
29
  interface Actions {
34
30
  setSelectedTheme: (theme: ThemeItemType) => void;
@@ -36,7 +32,6 @@ interface Actions {
36
32
  setSelectedFontLink: (link: string) => void;
37
33
  setSavedFontLink: (link: string) => void;
38
34
  setFontLoadStatus: (status: FontLoadStatus) => void;
39
- setFontLoadError: (error: string | null) => void;
40
35
  setFontName: (name: string) => void;
41
36
  }
42
37
  type ThemeStore = State & Actions;
@@ -1,6 +1,6 @@
1
+ import { themeData } from "@particle-network/ui-shared";
1
2
  import { create } from "zustand";
2
3
  import { createJSONStorage, persist } from "zustand/middleware";
3
- import { themeData } from "./theme-data.js";
4
4
  const useThemeStore = create()(persist((set)=>({
5
5
  selectedTheme: themeData["0"],
6
6
  savedTheme: themeData["0"],
@@ -8,7 +8,6 @@ const useThemeStore = create()(persist((set)=>({
8
8
  savedFontLink: '',
9
9
  fontName: '',
10
10
  fontLoadStatus: 'idle',
11
- fontLoadError: null,
12
11
  setSelectedTheme: (theme)=>set({
13
12
  selectedTheme: theme
14
13
  }),
@@ -24,14 +23,11 @@ const useThemeStore = create()(persist((set)=>({
24
23
  setFontLoadStatus: (status)=>set({
25
24
  fontLoadStatus: status
26
25
  }),
27
- setFontLoadError: (error)=>set({
28
- fontLoadError: error
29
- }),
30
26
  setFontName: (name)=>set({
31
27
  fontName: name
32
28
  })
33
29
  }), {
34
- name: 'ux-theme',
30
+ name: 'ux-theme-1',
35
31
  storage: createJSONStorage(()=>'undefined' != typeof window ? window.localStorage : {}),
36
32
  partialize: (state)=>({
37
33
  selectedTheme: state.selectedTheme,
@@ -1,5 +1,4 @@
1
- import { type ThemeItemType } from './theme-data';
2
- import { type FontLoadStatus } from './use-theme-store';
1
+ import { type ThemeItemType } from '@particle-network/ui-shared';
3
2
  /**
4
3
  * UX 主题管理 Hook
5
4
  */
@@ -12,7 +11,6 @@ export declare const useTheme: () => {
12
11
  setSelectedFontLink: (link: string) => void;
13
12
  savedFontLink: string;
14
13
  setSavedFontLink: (link: string) => void;
15
- fontLoadStatus: FontLoadStatus;
16
- fontLoadError: string | null;
14
+ fontLoadStatus: import("./use-theme-store").FontLoadStatus;
17
15
  fontName: string;
18
16
  };
@@ -1,8 +1,19 @@
1
1
  import { useEffect } from "react";
2
+ import { themeKeys } from "@particle-network/ui-shared";
2
3
  import { useDebounceFn } from "ahooks";
3
- import { themeKeys } from "./theme-data.js";
4
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';
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
+ };
6
17
  const applyTheme = (theme)=>{
7
18
  if ('undefined' == typeof window) return;
8
19
  const root = document.documentElement;
@@ -11,6 +22,8 @@ const applyTheme = (theme)=>{
11
22
  themeKeys.forEach((key)=>{
12
23
  root.classList.remove(key);
13
24
  });
25
+ root.classList.remove('dark');
26
+ root.classList.remove('light');
14
27
  root.classList.add(theme.id);
15
28
  };
16
29
  const extractFontFamilyFromLink = (link)=>{
@@ -19,50 +32,21 @@ const extractFontFamilyFromLink = (link)=>{
19
32
  const url = new URL(link);
20
33
  const familyParam = url.searchParams.get('family');
21
34
  if (!familyParam) return null;
22
- const fontName = familyParam.split(':')[0].replace(/\+/g, ' ');
23
- return fontName;
35
+ const firstFamily = familyParam.split('&family=')[0].split(':')[0].replace(/\+/g, ' ');
36
+ return firstFamily;
24
37
  } catch {
25
38
  return null;
26
39
  }
27
40
  };
28
- const loadGoogleFont = (link, options)=>{
29
- const { setFontLoadStatus, setFontLoadError, setFontName } = options;
41
+ const applyFont = (fontName)=>{
30
42
  if ('undefined' == typeof window) return;
31
- const existingLink = document.getElementById('ux-google-font-link');
32
- if (existingLink) existingLink.remove();
33
- if (!link?.trim()) {
43
+ if (fontName) {
44
+ document.documentElement.style.setProperty('--ux-font-family', `"${fontName}", ${DEFAULT_FONT_FAMILY}`);
45
+ document.body.style.fontFamily = `"${fontName}", ${DEFAULT_FONT_FAMILY}`;
46
+ } else {
34
47
  document.documentElement.style.setProperty('--ux-font-family', DEFAULT_FONT_FAMILY);
35
48
  document.body.style.fontFamily = DEFAULT_FONT_FAMILY;
36
- setFontLoadStatus('idle');
37
- setFontLoadError(null);
38
- setFontName('');
39
- return;
40
49
  }
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
50
  };
67
51
  const useTheme = ()=>{
68
52
  const selectedTheme = useThemeStore((state)=>state.selectedTheme);
@@ -71,24 +55,55 @@ const useTheme = ()=>{
71
55
  const savedFontLink = useThemeStore((state)=>state.savedFontLink);
72
56
  const fontName = useThemeStore((state)=>state.fontName);
73
57
  const fontLoadStatus = useThemeStore((state)=>state.fontLoadStatus);
74
- const fontLoadError = useThemeStore((state)=>state.fontLoadError);
75
58
  const storeSetSelectedTheme = useThemeStore((state)=>state.setSelectedTheme);
76
59
  const storeSetSavedTheme = useThemeStore((state)=>state.setSavedTheme);
77
60
  const storeSetSelectedFontLink = useThemeStore((state)=>state.setSelectedFontLink);
78
61
  const storeSetSavedFontLink = useThemeStore((state)=>state.setSavedFontLink);
79
62
  const storeSetFontLoadStatus = useThemeStore((state)=>state.setFontLoadStatus);
80
- const storeSetFontLoadError = useThemeStore((state)=>state.setFontLoadError);
81
63
  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
64
+ const applyFontWithStatus = (customFontLink, themeFontName)=>{
65
+ if ('undefined' == typeof window) return;
66
+ const isCustomFont = !!customFontLink?.trim();
67
+ if (!isCustomFont) return void applyFont(themeFontName);
68
+ const existingLink = document.getElementById('ux-google-font-link');
69
+ if (existingLink) existingLink.remove();
70
+ storeSetFontLoadStatus('loading');
71
+ const linkElement = document.createElement('link');
72
+ linkElement.id = 'ux-google-font-link';
73
+ linkElement.rel = 'stylesheet';
74
+ linkElement.href = customFontLink;
75
+ linkElement.onload = ()=>{
76
+ storeSetFontLoadStatus('success');
77
+ const fontFamily = extractFontFamilyFromLink(customFontLink);
78
+ if (fontFamily) {
79
+ applyFont(fontFamily);
80
+ storeSetFontName(fontFamily);
81
+ }
82
+ };
83
+ linkElement.onerror = ()=>{
84
+ storeSetFontLoadStatus('error');
85
+ storeSetFontName('');
86
+ applyFont(themeFontName);
87
+ };
88
+ document.head.appendChild(linkElement);
89
+ };
90
+ const { run: debouncedApplyFont } = useDebounceFn((customFontLink, themeFontName)=>applyFontWithStatus(customFontLink, themeFontName), {
91
+ wait: 300
88
92
  });
93
+ useEffect(()=>{
94
+ preloadFonts();
95
+ }, []);
96
+ useEffect(()=>{
97
+ if (!selectedFontLink.trim()) {
98
+ storeSetFontLoadStatus('idle');
99
+ storeSetFontName('');
100
+ }
101
+ }, [
102
+ selectedFontLink
103
+ ]);
89
104
  useEffect(()=>{
90
105
  applyTheme(savedTheme);
91
- debouncedLoadGoogleFont(savedFontLink);
106
+ debouncedApplyFont(savedFontLink, savedTheme.fontName);
92
107
  }, [
93
108
  savedTheme,
94
109
  savedFontLink
@@ -96,6 +111,7 @@ const useTheme = ()=>{
96
111
  const setSelectedTheme = (theme)=>{
97
112
  storeSetSelectedTheme(theme);
98
113
  applyTheme(theme);
114
+ debouncedApplyFont(selectedFontLink, theme.fontName);
99
115
  };
100
116
  const setSavedTheme = (theme)=>{
101
117
  storeSetSavedTheme(theme);
@@ -103,11 +119,11 @@ const useTheme = ()=>{
103
119
  };
104
120
  const setSelectedFontLink = (link)=>{
105
121
  storeSetSelectedFontLink(link);
106
- debouncedLoadGoogleFont(link);
122
+ debouncedApplyFont(link, selectedTheme.fontName);
107
123
  };
108
124
  const setSavedFontLink = (link)=>{
109
125
  storeSetSavedFontLink(link);
110
- debouncedLoadGoogleFont(link);
126
+ debouncedApplyFont(link, savedTheme.fontName);
111
127
  };
112
128
  return {
113
129
  selectedTheme,
@@ -119,7 +135,6 @@ const useTheme = ()=>{
119
135
  savedFontLink,
120
136
  setSavedFontLink,
121
137
  fontLoadStatus,
122
- fontLoadError,
123
138
  fontName
124
139
  };
125
140
  };
@@ -1,13 +1,16 @@
1
+ import type { ReactNode } from 'react';
1
2
  import type { ToastProps } from '@heroui/toast';
2
- export type UXToastType = 'success' | 'error' | 'loading';
3
+ export { addToast, closeAll, closeToast, getToastQueue, isToastClosing } from '@heroui/toast';
4
+ export type UXToastType = 'success' | 'error' | 'loading' | 'info';
3
5
  export type UXToastProps = Partial<ToastProps> & {
4
6
  type: UXToastType;
5
7
  };
6
8
  export declare const UXToastProvider: () => import("react/jsx-runtime").JSX.Element;
7
9
  export declare const toast: {
8
- success: (message: string, props?: Partial<ToastProps>) => string | null;
9
- error: (message: string, props?: Partial<ToastProps>) => string | null;
10
- loading: (message: string, props?: Partial<ToastProps>) => string | null;
10
+ info: (message: ReactNode, props?: Partial<ToastProps>) => string | null;
11
+ success: (message: ReactNode, props?: Partial<ToastProps>) => string | null;
12
+ error: (message: ReactNode, props?: Partial<ToastProps>) => string | null;
13
+ loading: (message: ReactNode, props?: Partial<ToastProps>) => string | null;
11
14
  show: (props?: Partial<ToastProps> & {
12
15
  type: UXToastType;
13
16
  }) => string | null;