myshell-react-lib 0.1.5 → 0.1.6

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 (145) hide show
  1. package/dist/index.cjs +50 -2
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +6 -1
  4. package/dist/index.js.map +1 -1
  5. package/package.json +1 -2
  6. package/src/common/assets/audio-playing.json +0 -3657
  7. package/src/common/constants/constants.ts +0 -24
  8. package/src/common/constants/types/common.ts +0 -10
  9. package/src/common/hooks/useAudioPlayer.tsx +0 -198
  10. package/src/common/hooks/useDevice.ts +0 -26
  11. package/src/common/hooks/useNativeBridge.ts +0 -42
  12. package/src/common/hooks/useNotification.tsx +0 -179
  13. package/src/common/hooks/useWindowWidth.ts +0 -19
  14. package/src/common/utils/common-helper.ts +0 -81
  15. package/src/components/ItemDemo.tsx +0 -15
  16. package/src/components/accordion.tsx +0 -126
  17. package/src/components/alert-dialog.tsx +0 -148
  18. package/src/components/alert.tsx +0 -65
  19. package/src/components/aspect-ratio.tsx +0 -7
  20. package/src/components/audio-player.tsx +0 -60
  21. package/src/components/audio-playing.tsx +0 -33
  22. package/src/components/avatar.tsx +0 -133
  23. package/src/components/badge.tsx +0 -67
  24. package/src/components/button/button.styles.ts +0 -258
  25. package/src/components/button/button.tsx +0 -215
  26. package/src/components/button/icon-button.styles.ts +0 -103
  27. package/src/components/button/icon-button.tsx +0 -100
  28. package/src/components/button/index.tsx +0 -3
  29. package/src/components/button/link-button.tsx +0 -184
  30. package/src/components/cascader.tsx +0 -175
  31. package/src/components/checkbox.tsx +0 -135
  32. package/src/components/command.tsx +0 -155
  33. package/src/components/context-menu.tsx +0 -198
  34. package/src/components/count-down.tsx +0 -83
  35. package/src/components/custom-notification.tsx +0 -95
  36. package/src/components/dialog.tsx +0 -158
  37. package/src/components/drawer.tsx +0 -116
  38. package/src/components/dropdown-menu.tsx +0 -196
  39. package/src/components/energy-progress.tsx +0 -55
  40. package/src/components/form.tsx +0 -201
  41. package/src/components/group.tsx +0 -9
  42. package/src/components/guide.tsx +0 -243
  43. package/src/components/icon.tsx +0 -96
  44. package/src/components/icons/index.tsx +0 -13
  45. package/src/components/icons/outline/ArrowLeftIcon.tsx +0 -28
  46. package/src/components/icons/outline/ArrowUpTrayIcon.tsx +0 -28
  47. package/src/components/icons/outline/CheckCircleIcon.tsx +0 -27
  48. package/src/components/icons/outline/ConfigIcon.tsx +0 -42
  49. package/src/components/icons/outline/DownIcon.tsx +0 -18
  50. package/src/components/icons/outline/FilterIcon.tsx +0 -20
  51. package/src/components/icons/outline/PencilSquareIcon.tsx +0 -28
  52. package/src/components/icons/outline/WindowIcon.tsx +0 -26
  53. package/src/components/icons/solid/CaretDownIcon.tsx +0 -22
  54. package/src/components/icons/solid/CodeIcon.tsx +0 -25
  55. package/src/components/icons/solid/DragIcon.tsx +0 -24
  56. package/src/components/icons/solid/PhoneIcon.tsx +0 -29
  57. package/src/components/icons/solid/RectangleGroupIcon.tsx +0 -26
  58. package/src/components/image.tsx +0 -152
  59. package/src/components/input.tsx +0 -118
  60. package/src/components/label.tsx +0 -26
  61. package/src/components/link.tsx +0 -123
  62. package/src/components/marquee/index.css +0 -15
  63. package/src/components/marquee/marquee.tsx +0 -220
  64. package/src/components/masonry.tsx +0 -138
  65. package/src/components/menubar.tsx +0 -234
  66. package/src/components/mobile/m-tooltip.tsx +0 -34
  67. package/src/components/modal.tsx +0 -561
  68. package/src/components/navigation-bar.tsx +0 -100
  69. package/src/components/number-input.tsx +0 -143
  70. package/src/components/page-content.tsx +0 -16
  71. package/src/components/popover.tsx +0 -191
  72. package/src/components/progress.tsx +0 -80
  73. package/src/components/radio-group.tsx +0 -44
  74. package/src/components/scroll-area.tsx +0 -49
  75. package/src/components/search-bar.tsx +0 -140
  76. package/src/components/secondary-navigation-bar.tsx +0 -328
  77. package/src/components/select.tsx +0 -273
  78. package/src/components/separator.tsx +0 -31
  79. package/src/components/sheet.tsx +0 -143
  80. package/src/components/skeleton.tsx +0 -20
  81. package/src/components/slider.tsx +0 -160
  82. package/src/components/spinner.tsx +0 -50
  83. package/src/components/swiper/index.module.scss +0 -88
  84. package/src/components/swiper/index.tsx +0 -319
  85. package/src/components/switch.tsx +0 -67
  86. package/src/components/tabs.tsx +0 -325
  87. package/src/components/textarea.tsx +0 -71
  88. package/src/components/toast/toast.tsx +0 -182
  89. package/src/components/toast/toaster.tsx +0 -160
  90. package/src/components/toast/use-toast.tsx +0 -248
  91. package/src/components/toggle-group.tsx +0 -64
  92. package/src/components/toggle.tsx +0 -46
  93. package/src/components/tooltip.tsx +0 -283
  94. package/src/components/typography.tsx +0 -437
  95. package/src/index.ts +0 -70
  96. package/src/lib/utils.ts +0 -62
  97. package/src/stories/Accordion.stories.tsx +0 -64
  98. package/src/stories/AccordionItem.stories.tsx +0 -48
  99. package/src/stories/Avatar.stories.ts +0 -58
  100. package/src/stories/Badge.stories.tsx +0 -40
  101. package/src/stories/BannerSwiper.stories.tsx +0 -102
  102. package/src/stories/Button.stories.tsx +0 -543
  103. package/src/stories/Checkbox.stories.tsx +0 -161
  104. package/src/stories/Configure.mdx +0 -341
  105. package/src/stories/CssProperties.mdx +0 -30
  106. package/src/stories/Description.stories.ts +0 -70
  107. package/src/stories/Display.stories.ts +0 -64
  108. package/src/stories/FeaturedSwiper.stories.tsx +0 -6978
  109. package/src/stories/GridSwiper.stories.tsx +0 -1407
  110. package/src/stories/Guide.stories.tsx +0 -247
  111. package/src/stories/Heading.stories.ts +0 -89
  112. package/src/stories/Icon.stories.ts +0 -77
  113. package/src/stories/IconButton.stories.tsx +0 -301
  114. package/src/stories/IconTextButton.stories.ts +0 -59
  115. package/src/stories/Image.stories.ts +0 -55
  116. package/src/stories/Input.stories.tsx +0 -203
  117. package/src/stories/Modal.stories.tsx +0 -144
  118. package/src/stories/NavigationBar.stories.tsx +0 -81
  119. package/src/stories/Notification.stories.tsx +0 -276
  120. package/src/stories/Popover.stories.tsx +0 -100
  121. package/src/stories/SearchBar.stories.ts +0 -43
  122. package/src/stories/SecondaryNavigationBar.stories.tsx +0 -199
  123. package/src/stories/Select.stories.tsx +0 -107
  124. package/src/stories/Separator.stories.tsx +0 -49
  125. package/src/stories/Spinner.stories.tsx +0 -48
  126. package/src/stories/SubHeading.stories.ts +0 -64
  127. package/src/stories/Swich.stories.tsx +0 -69
  128. package/src/stories/Tabs.stories.tsx +0 -90
  129. package/src/stories/Text.stories.ts +0 -78
  130. package/src/stories/Textarea.stories.tsx +0 -155
  131. package/src/stories/Toast.stories.tsx +0 -424
  132. package/src/stories/Tooltip.stories.tsx +0 -244
  133. package/src/stories/ViewAutoSwiper.stories.tsx +0 -1408
  134. package/src/styles/components-dark.scss +0 -212
  135. package/src/styles/components-light.scss +0 -210
  136. package/src/styles/design-dark.scss +0 -330
  137. package/src/styles/design-light.scss +0 -345
  138. package/src/styles/design2-dark.scss +0 -319
  139. package/src/styles/design2-light.scss +0 -364
  140. package/src/styles/font.css +0 -19
  141. package/src/styles/global.scss +0 -251
  142. package/src/styles/md-viewer.scss +0 -155
  143. package/src/styles/new-tokens.scss +0 -255
  144. package/src/styles/tokens.scss +0 -401
  145. package/src/types/scss.d.ts +0 -24
@@ -1,71 +0,0 @@
1
- import * as React from 'react';
2
-
3
- import { cn } from '@/lib/utils';
4
-
5
- import { Text } from './typography';
6
-
7
- export type TextareaProps =
8
- React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
9
- maxLengthClassName?: string;
10
- };
11
- const Textarea = React.forwardRef<
12
- HTMLTextAreaElement,
13
- TextareaProps & { error?: string }
14
- >(
15
- (
16
- { className, maxLength, value, error, maxLengthClassName, ...props },
17
- ref
18
- ) => {
19
- return (
20
- <div>
21
- <div className="relative">
22
- <textarea
23
- className={cn(
24
- 'w-full min-h-[123px] p-3 pb-10 rounded-lg border border-Colors-Border-Default bg-Colors-Background-Normal-Primary-Active ',
25
- 'text-sm text-Colors-Text-Default placeholder:text-Colors-Text-Subtlest ring-offset-cc-Focus-Rings-Brand-default',
26
- 'hover:border-hovered bg-cc-Input-bg-default hover:bg-cc-Input-bg-hover disabled:bg-cc-Input-bg-disabled aria-[invalid=true]:border-Colors-Border-Critical aria-[invalid=true]:hover:bg-Colors-Background-Critical-Subtle',
27
- 'aria-[invalid=true]:focus-visible:ring-error file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-Colors-Text-Subtler',
28
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cc-Focus-Rings-Brand-default focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-30',
29
- (maxLength && (value?.toString()?.length || 0) > maxLength) ||
30
- error
31
- ? 'border-Colors-Border-Critical hover:bg-Colors-Background-Critical-Subtle focus-visible:ring-error'
32
- : '',
33
- className
34
- )}
35
- ref={ref}
36
- maxLength={maxLength}
37
- value={value}
38
- {...props}
39
- />
40
- {maxLength ? (
41
- <div
42
- className={cn(
43
- 'absolute text-right bottom-5 right-4 border-Colors-Border-Default',
44
- maxLengthClassName
45
- )}
46
- >
47
- <Text size="sm" color="subtlest">{`${
48
- value?.toString()?.length || 0
49
- }/${maxLength}`}</Text>
50
- </div>
51
- ) : null}
52
- </div>
53
- {error && (
54
- <div className="w-full">
55
- <Text
56
- className="text-wrap"
57
- size="sm"
58
- weight="regular"
59
- color="critical"
60
- >
61
- {error}
62
- </Text>
63
- </div>
64
- )}
65
- </div>
66
- );
67
- }
68
- );
69
- Textarea.displayName = 'Textarea';
70
-
71
- export { Textarea };
@@ -1,182 +0,0 @@
1
- 'use client';
2
-
3
- import * as ToastPrimitives from '@radix-ui/react-toast';
4
- import { cva, type VariantProps } from 'class-variance-authority';
5
- import * as React from 'react';
6
- import { cn } from '@/lib/utils';
7
- import XMarkIcon from '@heroicons/react/24/outline/esm/XMarkIcon';
8
-
9
- const ToastProvider = ToastPrimitives.Provider;
10
-
11
- const viewportPositionVariants = cva(
12
- 'fixed z-[1000001] flex max-h-screen w-full p-0 gap-2',
13
- {
14
- variants: {
15
- position: {
16
- 'top-left': 'top-6 left-6 flex-col items-start',
17
- 'top-center': 'top-6 left-1/2 -translate-x-1/2 flex-col items-center',
18
- 'top-right': 'top-6 right-6 flex-col items-end',
19
- 'bottom-left': 'bottom-6 left-6 flex-col-reverse items-start',
20
- 'bottom-center':
21
- 'bottom-6 left-1/2 -translate-x-1/2 flex-col-reverse items-center',
22
- 'bottom-right': 'bottom-6 right-6 flex-col-reverse items-end',
23
- 'left-center': 'left-6 top-1/2 -translate-y-1/2 flex-row items-center',
24
- 'right-center':
25
- 'right-6 top-1/2 -translate-y-1/2 flex-row-reverse items-center',
26
- },
27
- },
28
- defaultVariants: {
29
- position: 'top-right',
30
- },
31
- }
32
- );
33
-
34
- interface ToastViewportProps
35
- extends React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport> {
36
- position?:
37
- | 'top-left'
38
- | 'top-center'
39
- | 'top-right'
40
- | 'bottom-left'
41
- | 'bottom-center'
42
- | 'bottom-right'
43
- | 'left-center'
44
- | 'right-center';
45
- }
46
-
47
- const ToastViewport = React.forwardRef<
48
- React.ElementRef<typeof ToastPrimitives.Viewport>,
49
- ToastViewportProps
50
- >(({ className, position, ...props }, ref) => (
51
- <ToastPrimitives.Viewport
52
- ref={ref}
53
- className={cn(viewportPositionVariants({ position }), className)}
54
- {...props}
55
- />
56
- ));
57
- ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
58
-
59
- const toastVariants = cva(
60
- 'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border border-Colors-Border-Opaque p-6 pr-8 shadow-modal-default transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 max-w-md',
61
- {
62
- variants: {
63
- variant: {
64
- info: 'bg-Colors-Background-Normal-Primary-Default p-4',
65
- warning: 'bg-Colors-Background-Normal-Primary-Default p-4',
66
- error: 'bg-Colors-Background-Normal-Primary-Default p-4',
67
- success: 'bg-Colors-Background-Normal-Primary-Default p-4',
68
- },
69
- position: {
70
- 'top-left':
71
- 'data-[state=open]:slide-in-from-left-full data-[state=closed]:slide-out-to-left-full',
72
- 'top-center':
73
- 'data-[state=open]:slide-in-from-top-full data-[state=closed]:slide-out-to-top-full',
74
- 'top-right':
75
- 'data-[state=open]:slide-in-from-right-full data-[state=closed]:slide-out-to-right-full',
76
- 'bottom-left':
77
- 'data-[state=open]:slide-in-from-left-full data-[state=closed]:slide-out-to-left-full',
78
- 'bottom-center':
79
- 'data-[state=open]:slide-in-from-bottom-full data-[state=closed]:slide-out-to-bottom-full',
80
- 'bottom-right':
81
- 'data-[state=open]:slide-in-from-right-full data-[state=closed]:slide-out-to-right-full',
82
- 'left-center':
83
- 'data-[state=open]:slide-in-from-left-full data-[state=closed]:slide-out-to-left-full',
84
- 'right-center':
85
- 'data-[state=open]:slide-in-from-right-full data-[state=closed]:slide-out-to-right-full',
86
- },
87
- },
88
- defaultVariants: {
89
- variant: 'info',
90
- position: 'top-right',
91
- },
92
- }
93
- );
94
-
95
- const Toast = React.forwardRef<
96
- React.ElementRef<typeof ToastPrimitives.Root>,
97
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
98
- VariantProps<typeof toastVariants>
99
- >(({ className, variant, position, ...props }, ref) => {
100
- return (
101
- <ToastPrimitives.Root
102
- ref={ref}
103
- className={cn(toastVariants({ variant, position }), className)}
104
- data-position={position}
105
- {...props}
106
- />
107
- );
108
- });
109
- Toast.displayName = ToastPrimitives.Root.displayName;
110
-
111
- const ToastAction = React.forwardRef<
112
- React.ElementRef<typeof ToastPrimitives.Action>,
113
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
114
- >(({ className, ...props }, ref) => (
115
- <ToastPrimitives.Action
116
- ref={ref}
117
- className={cn(
118
- 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-slate-200 bg-transparent px-3 text-sm font-medium ring-offset-white transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-slate-100/40 group-[.destructive]:hover:border-red-500/30 group-[.destructive]:hover:bg-red-500 group-[.destructive]:hover:text-slate-50 group-[.destructive]:focus:ring-red-500 dark:border-slate-800 dark:ring-offset-slate-950 dark:hover:bg-slate-800 dark:focus:ring-slate-300 dark:group-[.destructive]:border-slate-800/40 dark:group-[.destructive]:hover:border-red-900/30 dark:group-[.destructive]:hover:bg-red-900 dark:group-[.destructive]:hover:text-slate-50 dark:group-[.destructive]:focus:ring-red-900',
119
- className
120
- )}
121
- {...props}
122
- />
123
- ));
124
- ToastAction.displayName = ToastPrimitives.Action.displayName;
125
-
126
- const ToastClose = React.forwardRef<
127
- React.ElementRef<typeof ToastPrimitives.Close>,
128
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
129
- >(({ className, ...props }, ref) => (
130
- <ToastPrimitives.Close
131
- ref={ref}
132
- className={cn(
133
- 'absolute right-4 top-4 rounded-md p-1 text-slate-950/50 transition-opacity hover:text-slate-950 outline-none focus:outline-none focus:ring-2 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:text-slate-50/50 dark:hover:text-slate-50',
134
- className
135
- )}
136
- toast-close=""
137
- {...props}
138
- >
139
- <XMarkIcon className="h-5 w-5" />
140
- </ToastPrimitives.Close>
141
- ));
142
- ToastClose.displayName = ToastPrimitives.Close.displayName;
143
-
144
- const ToastTitle = React.forwardRef<
145
- React.ElementRef<typeof ToastPrimitives.Title>,
146
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
147
- >(({ className, ...props }, ref) => (
148
- <ToastPrimitives.Title
149
- ref={ref}
150
- className={cn('text-sm font-semibold', className)}
151
- {...props}
152
- />
153
- ));
154
- ToastTitle.displayName = ToastPrimitives.Title.displayName;
155
-
156
- const ToastDescription = React.forwardRef<
157
- React.ElementRef<typeof ToastPrimitives.Description>,
158
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
159
- >(({ className, ...props }, ref) => (
160
- <ToastPrimitives.Description
161
- ref={ref}
162
- className={cn('text-sm opacity-90', className)}
163
- {...props}
164
- />
165
- ));
166
- ToastDescription.displayName = ToastPrimitives.Description.displayName;
167
-
168
- type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
169
-
170
- type ToastActionElement = React.ReactElement<typeof ToastAction>;
171
-
172
- export {
173
- type ToastProps,
174
- type ToastActionElement,
175
- ToastProvider,
176
- ToastViewport,
177
- Toast,
178
- ToastTitle,
179
- ToastDescription,
180
- ToastClose,
181
- ToastAction,
182
- };
@@ -1,160 +0,0 @@
1
- 'use client';
2
-
3
- import CheckCircleIcon from '@heroicons/react/24/outline/esm/CheckCircleIcon';
4
- import ExclamationCircleIcon from '@heroicons/react/24/outline/esm/ExclamationCircleIcon';
5
- import InformationCircleIcon from '@heroicons/react/24/outline/esm/InformationCircleIcon';
6
- import XCircleIcon from '@heroicons/react/24/outline/esm/XCircleIcon';
7
-
8
- import {
9
- Toast,
10
- ToastClose,
11
- ToastDescription,
12
- ToastProvider,
13
- ToastTitle,
14
- ToastViewport,
15
- } from './toast';
16
- import { useToast } from './use-toast';
17
- import { cn } from '@/lib/utils';
18
- import React from 'react';
19
-
20
- type ToastVariant = 'info' | 'success' | 'warning' | 'error' | null | undefined;
21
-
22
- export interface ToasterProps {
23
- position?:
24
- | 'top-left'
25
- | 'top-center'
26
- | 'top-right'
27
- | 'bottom-left'
28
- | 'bottom-center'
29
- | 'bottom-right'
30
- | 'left-center'
31
- | 'right-center';
32
- }
33
-
34
- export function Toaster({ position = 'top-right' }: ToasterProps = {}) {
35
- const { toasts } = useToast();
36
-
37
- // 按位置分组
38
- const positionGroups = React.useMemo(() => {
39
- const groups: Record<string, typeof toasts> = {};
40
-
41
- const allPositions = [
42
- 'top-left',
43
- 'top-center',
44
- 'top-right',
45
- 'bottom-left',
46
- 'bottom-center',
47
- 'bottom-right',
48
- 'left-center',
49
- 'right-center',
50
- ];
51
-
52
- // 初始化所有位置组
53
- allPositions.forEach((pos) => {
54
- groups[pos] = [];
55
- });
56
-
57
- // 将每个Toast按其position分组,如果没有指定则使用默认位置
58
- toasts.forEach((toast) => {
59
- const toastPosition = toast.position || position;
60
- if (groups[toastPosition]) {
61
- groups[toastPosition].push(toast);
62
- } else {
63
- // 如果位置不在预定义列表中,则使用默认位置
64
- groups[position].push(toast);
65
- }
66
- });
67
-
68
- return groups;
69
- }, [toasts, position]);
70
-
71
- const renderToast = (toast: any) => {
72
- const {
73
- id,
74
- title,
75
- description,
76
- action,
77
- variant,
78
- position: toastPosition,
79
- } = toast;
80
-
81
- const renderIcon = (variant: ToastVariant) => {
82
- switch (variant) {
83
- case 'info':
84
- return (
85
- <InformationCircleIcon className="h-6 w-6 text-cc-Icon-Featured-icon-fg-Info" />
86
- );
87
- case 'success':
88
- return (
89
- <CheckCircleIcon className="h-6 w-6 text-cc-Icon-Featured-icon-fg-Success" />
90
- );
91
- case 'warning':
92
- return (
93
- <ExclamationCircleIcon className="h-6 w-6 text-cc-Icon-Featured-icon-fg-Warning" />
94
- );
95
- case 'error':
96
- return (
97
- <XCircleIcon className="h-6 w-6 text-cc-Icon-Featured-icon-fg-Error" />
98
- );
99
- }
100
- };
101
-
102
- const getBackgroundColor = (variant: ToastVariant) => {
103
- switch (variant) {
104
- case 'info':
105
- return 'bg-Colors-Background-Info-Default';
106
- case 'success':
107
- return 'bg-Colors-Background-Success-Default';
108
- case 'warning':
109
- return 'bg-Colors-Background-Warning-Default';
110
- case 'error':
111
- return 'bg-Colors-Background-Critical-Default';
112
- }
113
- };
114
-
115
- return (
116
- <Toast key={id} {...toast} position={toastPosition}>
117
- <div className="flex flex-col gap-3">
118
- <div className="flex items-start gap-3">
119
- <div
120
- className={cn(
121
- 'flex h-10 w-10 flex-shrink-0 flex-grow-0 items-center justify-center rounded-full',
122
- getBackgroundColor(variant)
123
- )}
124
- >
125
- {renderIcon(variant)}
126
- </div>
127
- <div className="grid gap-1">
128
- {title && (
129
- <ToastTitle className="text-base text-Colors-Text-Default">
130
- {title}
131
- </ToastTitle>
132
- )}
133
- {description && (
134
- <ToastDescription className="text-sm text-Colors-Text-Subtle">
135
- {description}
136
- </ToastDescription>
137
- )}
138
- {action}
139
- </div>
140
- </div>
141
- </div>
142
- <ToastClose />
143
- </Toast>
144
- );
145
- };
146
-
147
- return (
148
- <ToastProvider>
149
- {/* 为每个位置渲染一个ToastViewport */}
150
- {Object.entries(positionGroups).map(([pos, toastsForPosition]) => (
151
- <React.Fragment key={pos}>
152
- {toastsForPosition.map(renderToast)}
153
- {toastsForPosition.length > 0 && (
154
- <ToastViewport position={pos as any} />
155
- )}
156
- </React.Fragment>
157
- ))}
158
- </ToastProvider>
159
- );
160
- }
@@ -1,248 +0,0 @@
1
- 'use client';
2
-
3
- // Inspired by react-hot-toast library
4
- import * as React from 'react';
5
- import { ToastActionElement, ToastProps } from './toast';
6
- import { Text } from '../typography';
7
- import Link from '../link';
8
- const TOAST_LIMIT = 8;
9
- const TOAST_REMOVE_DELAY = 1000;
10
-
11
- type ToasterToast = ToastProps & {
12
- id: string;
13
- title?: React.ReactNode;
14
- description?: React.ReactNode;
15
- action?: ToastActionElement;
16
- };
17
-
18
- const actionTypes = {
19
- ADD_TOAST: 'ADD_TOAST',
20
- UPDATE_TOAST: 'UPDATE_TOAST',
21
- DISMISS_TOAST: 'DISMISS_TOAST',
22
- REMOVE_TOAST: 'REMOVE_TOAST',
23
- } as const;
24
-
25
- let count = 0;
26
-
27
- function genId() {
28
- count = (count + 1) % Number.MAX_SAFE_INTEGER;
29
-
30
- return count.toString();
31
- }
32
-
33
- type ActionType = typeof actionTypes;
34
-
35
- type Action =
36
- | {
37
- type: ActionType['ADD_TOAST'];
38
- toast: ToasterToast;
39
- }
40
- | {
41
- type: ActionType['UPDATE_TOAST'];
42
- toast: Partial<ToasterToast>;
43
- }
44
- | {
45
- type: ActionType['DISMISS_TOAST'];
46
- toastId?: ToasterToast['id'];
47
- }
48
- | {
49
- type: ActionType['REMOVE_TOAST'];
50
- toastId?: ToasterToast['id'];
51
- };
52
-
53
- interface State {
54
- toasts: ToasterToast[];
55
- }
56
-
57
- const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
58
-
59
- const addToRemoveQueue = (toastId: string) => {
60
- if (toastTimeouts.has(toastId)) {
61
- return;
62
- }
63
-
64
- const timeout = setTimeout(() => {
65
- toastTimeouts.delete(toastId);
66
- dispatch({
67
- type: 'REMOVE_TOAST',
68
- toastId,
69
- });
70
- }, TOAST_REMOVE_DELAY);
71
-
72
- toastTimeouts.set(toastId, timeout);
73
- };
74
-
75
- export const reducer = (state: State, action: Action): State => {
76
- switch (action.type) {
77
- case 'ADD_TOAST':
78
- return {
79
- ...state,
80
- toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
81
- };
82
-
83
- case 'UPDATE_TOAST':
84
- return {
85
- ...state,
86
- toasts: state.toasts.map((t) =>
87
- t.id === action.toast.id ? { ...t, ...action.toast } : t
88
- ),
89
- };
90
-
91
- case 'DISMISS_TOAST': {
92
- const { toastId } = action;
93
-
94
- // ! Side effects ! - This could be extracted into a dismissToast() action,
95
- // but I'll keep it here for simplicity
96
- if (toastId) {
97
- addToRemoveQueue(toastId);
98
- } else {
99
- state.toasts.forEach((toast) => {
100
- addToRemoveQueue(toast.id);
101
- });
102
- }
103
-
104
- return {
105
- ...state,
106
- toasts: state.toasts.map((t) =>
107
- t.id === toastId || toastId === undefined
108
- ? {
109
- ...t,
110
- open: false,
111
- }
112
- : t
113
- ),
114
- };
115
- }
116
- case 'REMOVE_TOAST':
117
- if (action.toastId === undefined) {
118
- return {
119
- ...state,
120
- toasts: [],
121
- };
122
- }
123
-
124
- return {
125
- ...state,
126
- toasts: state.toasts.filter((t) => t.id !== action.toastId),
127
- };
128
- }
129
- };
130
-
131
- const listeners: Array<(state: State) => void> = [];
132
-
133
- let memoryState: State = { toasts: [] };
134
-
135
- function dispatch(action: Action) {
136
- memoryState = reducer(memoryState, action);
137
- listeners.forEach((listener) => {
138
- listener(memoryState);
139
- });
140
- }
141
-
142
- type Toast = Omit<ToasterToast, 'id'> & {
143
- actions?: {
144
- dismissText?: string;
145
- view?: string;
146
- viewUrl?: string;
147
- };
148
- toastId?: string;
149
- position?:
150
- | 'top-left'
151
- | 'top-center'
152
- | 'top-right'
153
- | 'bottom-left'
154
- | 'bottom-center'
155
- | 'bottom-right'
156
- | 'left-center'
157
- | 'right-center';
158
- };
159
-
160
- function toast({ actions, toastId, position, ...props }: Toast) {
161
- const id = toastId || genId();
162
-
163
- const update = (props: ToasterToast) =>
164
- dispatch({
165
- type: 'UPDATE_TOAST',
166
- toast: { ...props, id },
167
- });
168
- const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id });
169
-
170
- dispatch({
171
- type: 'ADD_TOAST',
172
- toast: {
173
- ...props,
174
- position,
175
- ...(actions && {
176
- action: (
177
- <div className="flex justify-start items-center gap-2">
178
- {actions?.dismissText && (
179
- <Text
180
- size="sm"
181
- weight="medium"
182
- color="brand"
183
- className="cursor-pointer"
184
- onClick={() => {
185
- dismiss();
186
- }}
187
- >
188
- {actions?.dismissText}
189
- </Text>
190
- )}
191
- {actions?.view && actions.viewUrl && (
192
- <Link
193
- href={actions.viewUrl}
194
- target="_blank"
195
- rel="noreferrer noopener"
196
- >
197
- <div className="flex items-center gap-1.5">
198
- <Text
199
- size="sm"
200
- weight="medium"
201
- color="default"
202
- className="cursor-pointer"
203
- >
204
- {actions.view}
205
- </Text>
206
- </div>
207
- </Link>
208
- )}
209
- </div>
210
- ),
211
- }),
212
- id,
213
- open: true,
214
- onOpenChange: (open) => {
215
- if (!open) dismiss();
216
- },
217
- },
218
- });
219
-
220
- return {
221
- id,
222
- dismiss,
223
- update,
224
- };
225
- }
226
-
227
- function useToast() {
228
- const [state, setState] = React.useState<State>(memoryState);
229
-
230
- React.useEffect(() => {
231
- listeners.push(setState);
232
-
233
- return () => {
234
- const index = listeners.indexOf(setState);
235
- if (index > -1) {
236
- listeners.splice(index, 1);
237
- }
238
- };
239
- }, [state]);
240
-
241
- return {
242
- ...state,
243
- toast,
244
- dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }),
245
- };
246
- }
247
-
248
- export { toast, useToast };