myshell-react-lib 0.1.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 (151) hide show
  1. package/README.md +268 -0
  2. package/dist/assets/audio-playing.json +3657 -0
  3. package/dist/index.cjs +9654 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1431 -0
  6. package/dist/index.d.ts +1431 -0
  7. package/dist/index.js +8788 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +140 -0
  10. package/src/common/assets/audio-playing.json +3657 -0
  11. package/src/common/constants/constants.ts +24 -0
  12. package/src/common/constants/types/common.ts +10 -0
  13. package/src/common/hooks/useAudioPlayer.tsx +198 -0
  14. package/src/common/hooks/useDevice.ts +26 -0
  15. package/src/common/hooks/useNativeBridge.ts +42 -0
  16. package/src/common/hooks/useNotification.tsx +179 -0
  17. package/src/common/hooks/useWindowWidth.ts +19 -0
  18. package/src/common/utils/common-helper.ts +81 -0
  19. package/src/components/ItemDemo.tsx +15 -0
  20. package/src/components/accordion.tsx +126 -0
  21. package/src/components/alert-dialog.tsx +148 -0
  22. package/src/components/alert.tsx +65 -0
  23. package/src/components/aspect-ratio.tsx +7 -0
  24. package/src/components/audio-player.tsx +58 -0
  25. package/src/components/avatar.tsx +133 -0
  26. package/src/components/badge.tsx +65 -0
  27. package/src/components/button/button.styles.ts +258 -0
  28. package/src/components/button/button.tsx +215 -0
  29. package/src/components/button/icon-button.styles.ts +101 -0
  30. package/src/components/button/icon-button.tsx +100 -0
  31. package/src/components/button/index.tsx +3 -0
  32. package/src/components/button/link-button.tsx +184 -0
  33. package/src/components/cascader.tsx +175 -0
  34. package/src/components/checkbox.tsx +135 -0
  35. package/src/components/command.tsx +155 -0
  36. package/src/components/context-menu.tsx +198 -0
  37. package/src/components/count-down.tsx +83 -0
  38. package/src/components/custom-notification.tsx +95 -0
  39. package/src/components/dialog.tsx +158 -0
  40. package/src/components/drawer.tsx +116 -0
  41. package/src/components/dropdown-menu.tsx +196 -0
  42. package/src/components/energy-progress.tsx +55 -0
  43. package/src/components/form.tsx +201 -0
  44. package/src/components/group.tsx +9 -0
  45. package/src/components/guide.tsx +243 -0
  46. package/src/components/icon.tsx +89 -0
  47. package/src/components/icons/outline/DownIcon.tsx +18 -0
  48. package/src/components/icons/outline/FilterIcon.tsx +21 -0
  49. package/src/components/icons/outline/arrow-left.tsx +16 -0
  50. package/src/components/icons/outline/arrow-up-tray.tsx +16 -0
  51. package/src/components/icons/outline/check-circle.tsx +17 -0
  52. package/src/components/icons/outline/config.tsx +42 -0
  53. package/src/components/icons/outline/pencil-square.tsx +16 -0
  54. package/src/components/icons/outline/trash.tsx +17 -0
  55. package/src/components/icons/outline/window.tsx +16 -0
  56. package/src/components/icons/outline/x-circle.tsx +17 -0
  57. package/src/components/icons/outline/x-mark.tsx +16 -0
  58. package/src/components/icons/solid/audio-playing.tsx +31 -0
  59. package/src/components/icons/solid/caret-down.tsx +14 -0
  60. package/src/components/icons/solid/code.tsx +18 -0
  61. package/src/components/icons/solid/drag.tsx +14 -0
  62. package/src/components/icons/solid/phone.tsx +23 -0
  63. package/src/components/icons/solid/rectangle-group.tsx +14 -0
  64. package/src/components/image.tsx +151 -0
  65. package/src/components/input.tsx +118 -0
  66. package/src/components/label.tsx +26 -0
  67. package/src/components/link.tsx +123 -0
  68. package/src/components/marquee/index.css +15 -0
  69. package/src/components/marquee/marquee.tsx +220 -0
  70. package/src/components/masonry.tsx +138 -0
  71. package/src/components/menubar.tsx +234 -0
  72. package/src/components/mobile/m-tooltip.tsx +34 -0
  73. package/src/components/modal.tsx +561 -0
  74. package/src/components/navigation-bar.tsx +100 -0
  75. package/src/components/number-input.tsx +143 -0
  76. package/src/components/page-content.tsx +16 -0
  77. package/src/components/popover.tsx +191 -0
  78. package/src/components/progress.tsx +80 -0
  79. package/src/components/radio-group.tsx +44 -0
  80. package/src/components/scroll-area.tsx +49 -0
  81. package/src/components/search-bar.tsx +140 -0
  82. package/src/components/secondary-navigation-bar.tsx +307 -0
  83. package/src/components/select.tsx +273 -0
  84. package/src/components/separator.tsx +31 -0
  85. package/src/components/sheet.tsx +143 -0
  86. package/src/components/skeleton.tsx +20 -0
  87. package/src/components/slider.tsx +160 -0
  88. package/src/components/spinner.tsx +48 -0
  89. package/src/components/swiper/index.module.scss +88 -0
  90. package/src/components/swiper/index.tsx +319 -0
  91. package/src/components/switch.tsx +67 -0
  92. package/src/components/tabs.tsx +325 -0
  93. package/src/components/textarea.tsx +71 -0
  94. package/src/components/toast/toast.tsx +182 -0
  95. package/src/components/toast/toaster.tsx +160 -0
  96. package/src/components/toast/use-toast.tsx +248 -0
  97. package/src/components/toggle-group.tsx +64 -0
  98. package/src/components/toggle.tsx +46 -0
  99. package/src/components/tooltip.tsx +283 -0
  100. package/src/components/typography.tsx +437 -0
  101. package/src/index.ts +66 -0
  102. package/src/lib/utils.ts +62 -0
  103. package/src/stories/Accordion.stories.tsx +64 -0
  104. package/src/stories/AccordionItem.stories.tsx +48 -0
  105. package/src/stories/Avatar.stories.ts +58 -0
  106. package/src/stories/Badge.stories.tsx +40 -0
  107. package/src/stories/BannerSwiper.stories.tsx +102 -0
  108. package/src/stories/Button.stories.tsx +543 -0
  109. package/src/stories/Checkbox.stories.tsx +161 -0
  110. package/src/stories/Configure.mdx +341 -0
  111. package/src/stories/CssProperties.mdx +30 -0
  112. package/src/stories/Description.stories.ts +70 -0
  113. package/src/stories/Display.stories.ts +64 -0
  114. package/src/stories/FeaturedSwiper.stories.tsx +6978 -0
  115. package/src/stories/GridSwiper.stories.tsx +1407 -0
  116. package/src/stories/Guide.stories.tsx +247 -0
  117. package/src/stories/Heading.stories.ts +89 -0
  118. package/src/stories/Icon.stories.ts +77 -0
  119. package/src/stories/IconButton.stories.tsx +301 -0
  120. package/src/stories/IconTextButton.stories.ts +59 -0
  121. package/src/stories/Image.stories.ts +55 -0
  122. package/src/stories/Input.stories.tsx +203 -0
  123. package/src/stories/Modal.stories.tsx +144 -0
  124. package/src/stories/NavigationBar.stories.tsx +81 -0
  125. package/src/stories/Notification.stories.tsx +276 -0
  126. package/src/stories/Popover.stories.tsx +100 -0
  127. package/src/stories/SearchBar.stories.ts +43 -0
  128. package/src/stories/SecondaryNavigationBar.stories.tsx +199 -0
  129. package/src/stories/Select.stories.tsx +107 -0
  130. package/src/stories/Separator.stories.tsx +49 -0
  131. package/src/stories/Spinner.stories.tsx +48 -0
  132. package/src/stories/SubHeading.stories.ts +64 -0
  133. package/src/stories/Swich.stories.tsx +69 -0
  134. package/src/stories/Tabs.stories.tsx +90 -0
  135. package/src/stories/Text.stories.ts +78 -0
  136. package/src/stories/Textarea.stories.tsx +155 -0
  137. package/src/stories/Toast.stories.tsx +424 -0
  138. package/src/stories/Tooltip.stories.tsx +244 -0
  139. package/src/stories/ViewAutoSwiper.stories.tsx +1408 -0
  140. package/src/styles/components-dark.scss +212 -0
  141. package/src/styles/components-light.scss +210 -0
  142. package/src/styles/design-dark.scss +330 -0
  143. package/src/styles/design-light.scss +345 -0
  144. package/src/styles/design2-dark.scss +319 -0
  145. package/src/styles/design2-light.scss +364 -0
  146. package/src/styles/font.css +19 -0
  147. package/src/styles/global.scss +251 -0
  148. package/src/styles/md-viewer.scss +155 -0
  149. package/src/styles/new-tokens.scss +255 -0
  150. package/src/styles/tokens.scss +401 -0
  151. package/src/types/scss.d.ts +24 -0
@@ -0,0 +1,301 @@
1
+ import ArrowsUpDownIcon from '@heroicons/react/24/outline/esm/ArrowsUpDownIcon';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+
4
+ import { IconButton } from '@/components/button';
5
+ import React from 'react';
6
+
7
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
8
+ const meta = {
9
+ title: 'Components/通用/IconButton-按钮',
10
+ component: IconButton,
11
+ parameters: {
12
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
13
+ layout: 'centered',
14
+ },
15
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
16
+ tags: ['autodocs'],
17
+
18
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
19
+ args: {
20
+ size: 'lg',
21
+ variant: 'primary',
22
+ disabled: false,
23
+ loading: false,
24
+ icon: ArrowsUpDownIcon,
25
+ hoverText: 'Content',
26
+ },
27
+ argTypes: {
28
+ // 定义size为select类型的控件
29
+ size: {
30
+ control: 'select',
31
+ options: ['sm', 'md', 'lg'],
32
+ },
33
+ variant: {
34
+ control: 'select',
35
+ options: ['primary', 'secondary', 'tertiary', 'plain', 'static', 'solid'],
36
+ },
37
+ color: {
38
+ control: 'select',
39
+ options: ['default', 'brand', 'error', 'gray'],
40
+ },
41
+ hoverText: {
42
+ control: 'text',
43
+ },
44
+ },
45
+ } satisfies Meta<typeof IconButton>;
46
+
47
+ export default meta;
48
+ // export const Default: StoryObj<typeof meta> = {
49
+ // // 这里不需要设置 args,因为它会继承 meta 中的 args
50
+ // };
51
+ type Story = StoryObj<typeof meta>;
52
+
53
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
54
+ export const IconButtonDemo: Story = {
55
+ args: {
56
+ ...meta.args, // 继承默认参数
57
+ },
58
+ render: (args) => {
59
+ return (
60
+ <div className="min-w-[60vw] w-full p-6 rounded-md flex flex-col justify-center items-center space-y-2">
61
+ <div className="w-full">示例:</div>
62
+ <div className="w-full flex flex-col justify-center items-center">
63
+ <div className="w-full flex justify-around mb-3">
64
+ <div className="font-bold w-10" />
65
+ <div className="flex justify-center">lg</div>
66
+ <div className="flex justify-center">md</div>
67
+ <div className="flex justify-center">sm</div>
68
+ </div>
69
+ <div className="w-full flex justify-around items-center mb-6">
70
+ <div className="font-semibold w-10">Primary (brand)</div>
71
+ <IconButton
72
+ icon={ArrowsUpDownIcon}
73
+ {...args}
74
+ variant="primary"
75
+ color="brand"
76
+ size="lg"
77
+ />
78
+ <IconButton
79
+ icon={ArrowsUpDownIcon}
80
+ {...args}
81
+ variant="primary"
82
+ color="brand"
83
+ size="md"
84
+ />
85
+ <IconButton
86
+ icon={ArrowsUpDownIcon}
87
+ {...args}
88
+ variant="primary"
89
+ color="brand"
90
+ size="sm"
91
+ />
92
+ </div>
93
+
94
+ <div className="w-full flex justify-around items-center mb-6">
95
+ <div className="font-semibold w-10">Secondary</div>
96
+ <IconButton
97
+ icon={ArrowsUpDownIcon}
98
+ {...args}
99
+ variant="secondary"
100
+ size="lg"
101
+ />
102
+ <IconButton
103
+ icon={ArrowsUpDownIcon}
104
+ {...args}
105
+ variant="secondary"
106
+ size="md"
107
+ />
108
+ <IconButton
109
+ icon={ArrowsUpDownIcon}
110
+ {...args}
111
+ variant="secondary"
112
+ size="sm"
113
+ />
114
+ </div>
115
+
116
+ <div className="w-full flex justify-around items-center mb-6">
117
+ <div className="font-semibold w-10">Tertiary</div>
118
+ <IconButton
119
+ icon={ArrowsUpDownIcon}
120
+ {...args}
121
+ variant="tertiary"
122
+ size="lg"
123
+ />
124
+ <IconButton
125
+ icon={ArrowsUpDownIcon}
126
+ {...args}
127
+ variant="tertiary"
128
+ size="md"
129
+ />
130
+ <IconButton
131
+ icon={ArrowsUpDownIcon}
132
+ {...args}
133
+ variant="tertiary"
134
+ size="sm"
135
+ />
136
+ </div>
137
+ <div className="w-full flex justify-around items-center mb-6">
138
+ <div className="font-semibold w-10">Plain</div>
139
+ <IconButton
140
+ icon={ArrowsUpDownIcon}
141
+ {...args}
142
+ variant="plain"
143
+ size="lg"
144
+ />
145
+ <IconButton
146
+ icon={ArrowsUpDownIcon}
147
+ {...args}
148
+ variant="plain"
149
+ size="md"
150
+ />
151
+ <IconButton
152
+ icon={ArrowsUpDownIcon}
153
+ {...args}
154
+ variant="plain"
155
+ size="sm"
156
+ />
157
+ </div>
158
+ <div className="w-full flex justify-around items-center mb-6">
159
+ <div className="font-semibold w-10">Plain (gray)</div>
160
+ <IconButton
161
+ icon={ArrowsUpDownIcon}
162
+ {...args}
163
+ variant="plain"
164
+ color="gray"
165
+ size="lg"
166
+ />
167
+ <IconButton
168
+ icon={ArrowsUpDownIcon}
169
+ {...args}
170
+ variant="plain"
171
+ color="gray"
172
+ size="md"
173
+ />
174
+ <IconButton
175
+ icon={ArrowsUpDownIcon}
176
+ {...args}
177
+ variant="plain"
178
+ color="gray"
179
+ size="sm"
180
+ />
181
+ </div>
182
+ <div className="w-full flex justify-around items-center mb-6">
183
+ <div className="font-semibold w-10">Primary (error)</div>
184
+ <IconButton
185
+ icon={ArrowsUpDownIcon}
186
+ {...args}
187
+ variant="primary"
188
+ color="error"
189
+ size="lg"
190
+ />
191
+ <IconButton
192
+ icon={ArrowsUpDownIcon}
193
+ {...args}
194
+ variant="primary"
195
+ color="error"
196
+ size="md"
197
+ />
198
+ <IconButton
199
+ icon={ArrowsUpDownIcon}
200
+ {...args}
201
+ variant="primary"
202
+ color="error"
203
+ size="sm"
204
+ />
205
+ </div>
206
+ <div className="w-full flex justify-around items-center mb-6">
207
+ <div className="font-semibold w-10">Secondary (error)</div>
208
+ <IconButton
209
+ icon={ArrowsUpDownIcon}
210
+ {...args}
211
+ variant="secondary"
212
+ color="error"
213
+ size="lg"
214
+ />
215
+ <IconButton
216
+ icon={ArrowsUpDownIcon}
217
+ {...args}
218
+ variant="secondary"
219
+ color="error"
220
+ size="md"
221
+ />
222
+ <IconButton
223
+ icon={ArrowsUpDownIcon}
224
+ {...args}
225
+ variant="secondary"
226
+ color="error"
227
+ size="sm"
228
+ />
229
+ </div>
230
+ <div className="w-full flex justify-around items-center mb-6">
231
+ <div className="font-semibold w-10">Plain (error)</div>
232
+ <IconButton
233
+ icon={ArrowsUpDownIcon}
234
+ {...args}
235
+ variant="plain"
236
+ color="error"
237
+ size="lg"
238
+ className=""
239
+ />
240
+ <IconButton
241
+ icon={ArrowsUpDownIcon}
242
+ {...args}
243
+ variant="plain"
244
+ color="error"
245
+ size="md"
246
+ />
247
+ <IconButton
248
+ icon={ArrowsUpDownIcon}
249
+ {...args}
250
+ variant="plain"
251
+ color="error"
252
+ size="sm"
253
+ />
254
+ </div>
255
+ <div className="w-full flex justify-around items-center mb-6">
256
+ <div className="font-semibold w-10">Static</div>
257
+ <IconButton
258
+ icon={ArrowsUpDownIcon}
259
+ {...args}
260
+ variant="static"
261
+ size="lg"
262
+ />
263
+ <IconButton
264
+ icon={ArrowsUpDownIcon}
265
+ {...args}
266
+ variant="static"
267
+ size="md"
268
+ />
269
+ <IconButton
270
+ icon={ArrowsUpDownIcon}
271
+ {...args}
272
+ variant="static"
273
+ size="sm"
274
+ />
275
+ </div>
276
+ <div className="w-full flex justify-around items-center mb-6">
277
+ <div className="font-semibold w-10">Solid</div>
278
+ <IconButton
279
+ icon={ArrowsUpDownIcon}
280
+ {...args}
281
+ variant="solid"
282
+ size="lg"
283
+ />
284
+ <IconButton
285
+ icon={ArrowsUpDownIcon}
286
+ {...args}
287
+ variant="solid"
288
+ size="md"
289
+ />
290
+ <IconButton
291
+ icon={ArrowsUpDownIcon}
292
+ {...args}
293
+ variant="solid"
294
+ size="sm"
295
+ />
296
+ </div>
297
+ </div>
298
+ </div>
299
+ );
300
+ },
301
+ };
@@ -0,0 +1,59 @@
1
+ import ArrowsUpDownIcon from '@heroicons/react/24/outline/esm/ArrowsUpDownIcon';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+
4
+ import { Button } from '@/components/button/button';
5
+
6
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
7
+ const meta = {
8
+ title: 'Components/通用/Button-按钮',
9
+ component: Button,
10
+ parameters: {
11
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
12
+ layout: 'centered',
13
+ },
14
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
15
+ tags: ['autodocs'],
16
+
17
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
18
+ args: {
19
+ size: 'lg',
20
+ color: 'default',
21
+ variant: 'primary',
22
+ disabled: false,
23
+ loading: false,
24
+ children: '按钮',
25
+ icon: ArrowsUpDownIcon,
26
+ },
27
+ argTypes: {
28
+ // 定义size为select类型的控件
29
+ size: {
30
+ control: 'select',
31
+ options: ['lg', 'sm', 'md'],
32
+ },
33
+ variant: {
34
+ control: 'select',
35
+ options: ['primary', 'outline', 'link'],
36
+ },
37
+ color: {
38
+ control: 'select',
39
+ options: ['default', 'brand', 'warning', 'error', 'gray'],
40
+ },
41
+ iconDirection: {
42
+ control: 'select',
43
+ options: ['left', 'right'],
44
+ },
45
+ },
46
+ } satisfies Meta<typeof Button>;
47
+
48
+ export default meta;
49
+ // export const Default: StoryObj<typeof meta> = {
50
+ // // 这里不需要设置 args,因为它会继承 meta 中的 args
51
+ // };
52
+ type Story = StoryObj<typeof meta>;
53
+
54
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
55
+ export const IconTextButton: Story = {
56
+ args: {
57
+ ...meta.args, // 继承默认参数
58
+ },
59
+ };
@@ -0,0 +1,55 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { Image, ImageProps } from '@/components/image';
4
+
5
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
6
+ const meta = {
7
+ title: 'Components/通用/Image-图片',
8
+ component: Image,
9
+ parameters: {
10
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
11
+ layout: 'centered',
12
+ },
13
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
14
+ tags: ['autodocs'],
15
+
16
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
17
+ args: {},
18
+ argTypes: {
19
+ rounded: {
20
+ control: 'select',
21
+ options: [
22
+ 'none',
23
+ 'sm',
24
+ 'default',
25
+ 'md',
26
+ 'lg',
27
+ 'xl',
28
+ '2xl',
29
+ '3xl',
30
+ 'full',
31
+ ],
32
+ },
33
+ object: {
34
+ control: 'select',
35
+ options: ['contain', 'cover', 'fill', 'none'],
36
+ },
37
+ },
38
+ } satisfies Meta<ImageProps>;
39
+
40
+ export default meta;
41
+ // export const Default: StoryObj<typeof meta> = {
42
+ // // 这里不需要设置 args,因为它会继承 meta 中的 args
43
+ // };
44
+ type Story = StoryObj<typeof meta>;
45
+
46
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
47
+ export const Demo: Story = {
48
+ args: {
49
+ width: '100%',
50
+ height: '100%',
51
+ src: 'https://www.myshellstatic.com/image/homepage/20240504/787721e9d8a04b029d279aa5310941e8.png',
52
+ fallback: '',
53
+ isBackgroud: false,
54
+ },
55
+ };
@@ -0,0 +1,203 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React, { useState } from 'react';
3
+
4
+ import { Input } from '../components/input';
5
+ import { Button } from '../components/button';
6
+
7
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
8
+ const meta = {
9
+ title: 'Components/表单/Input-输入框',
10
+ component: Input,
11
+ parameters: {
12
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
13
+ layout: 'centered',
14
+ },
15
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
16
+ tags: ['autodocs'],
17
+
18
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
19
+ args: {
20
+ placeholder: 'Search Myshell',
21
+ },
22
+ argTypes: {
23
+ // 定义size为select类型的控件
24
+ size: {
25
+ control: 'select',
26
+ options: ['lg', 'md', 'sm', 'xs'],
27
+ },
28
+ rounded: {
29
+ control: 'select',
30
+ options: [
31
+ 'none',
32
+ 'sm',
33
+ 'default',
34
+ 'md',
35
+ 'lg',
36
+ 'xl',
37
+ '2xl',
38
+ '3xl',
39
+ 'full',
40
+ ],
41
+ },
42
+ isFull: {
43
+ control: 'boolean',
44
+ defaultValue: true,
45
+ },
46
+ },
47
+ } satisfies Meta<typeof Input>;
48
+
49
+ export default meta;
50
+ // export const Default: StoryObj<typeof meta> = {
51
+ // // 这里不需要设置 args,因为它会继承 meta 中的 args
52
+ // };
53
+ type Story = StoryObj<typeof meta>;
54
+
55
+ const FormErrorDemo = () => {
56
+ const [formData, setFormData] = useState({
57
+ username: '',
58
+ email: '',
59
+ });
60
+
61
+ // 存储每个字段的错误信息
62
+ const [errors, setErrors] = useState({
63
+ username: '',
64
+ email: '',
65
+ });
66
+
67
+ // 触发验证的状态(仅在提交后激活)
68
+ const [isValidating, setIsValidating] = useState(false);
69
+
70
+ const handleChange = (e) => {
71
+ const { name, value } = e.target;
72
+ setFormData({
73
+ ...formData,
74
+ [name]: value,
75
+ });
76
+
77
+ // 如果已经在验证状态,即时验证
78
+ if (isValidating) {
79
+ validateField(name, value);
80
+ }
81
+ };
82
+
83
+ const validateField = (name, value) => {
84
+ let errorMessage = '';
85
+
86
+ switch (name) {
87
+ case 'username':
88
+ if (!value.trim()) {
89
+ errorMessage = '用户名不能为空';
90
+ } else if (value.length < 3) {
91
+ errorMessage = '用户名至少需要3个字符';
92
+ }
93
+ break;
94
+ case 'email':
95
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
96
+ if (!value.trim()) {
97
+ errorMessage = '邮箱不能为空';
98
+ } else if (!emailRegex.test(value)) {
99
+ errorMessage = '请输入有效的邮箱地址';
100
+ }
101
+ break;
102
+ default:
103
+ break;
104
+ }
105
+
106
+ setErrors((prev) => ({
107
+ ...prev,
108
+ [name]: errorMessage,
109
+ }));
110
+
111
+ return !errorMessage;
112
+ };
113
+
114
+ const validateForm = () => {
115
+ const usernameValid = validateField('username', formData.username);
116
+ const emailValid = validateField('email', formData.email);
117
+
118
+ return usernameValid && emailValid;
119
+ };
120
+
121
+ const handleSubmit = (e) => {
122
+ e.preventDefault();
123
+ setIsValidating(true);
124
+
125
+ if (validateForm()) {
126
+ // 表单验证通过,可以提交
127
+ console.log('表单提交成功:', formData);
128
+ // 这里可以添加提交逻辑
129
+ } else {
130
+ console.log('表单验证失败');
131
+ }
132
+ };
133
+
134
+ return (
135
+ <div className="space-y-4 w-full max-w-md">
136
+ <form onSubmit={handleSubmit}>
137
+ <div className="mb-4">
138
+ <Input
139
+ name="username"
140
+ placeholder="用户名"
141
+ value={formData.username}
142
+ onChange={handleChange}
143
+ aria-invalid={!!errors.username}
144
+ />
145
+ {errors.username && (
146
+ <p className="mt-1 text-sm text-Colors-Text-Critical-Default">
147
+ {errors.username}
148
+ </p>
149
+ )}
150
+ </div>
151
+
152
+ <div className="mb-4">
153
+ <Input
154
+ name="email"
155
+ type="email"
156
+ placeholder="邮箱"
157
+ value={formData.email}
158
+ onChange={handleChange}
159
+ aria-invalid={!!errors.email}
160
+ />
161
+ {errors.email && (
162
+ <p className="mt-1 text-sm text-Colors-Text-Critical-Default">
163
+ {errors.email}
164
+ </p>
165
+ )}
166
+ </div>
167
+
168
+ <div className="flex space-x-4">
169
+ <Button type="submit">提交表单</Button>
170
+ <Button
171
+ type="button"
172
+ variant="secondary"
173
+ onClick={() => {
174
+ setFormData({ username: '', email: '' });
175
+ setErrors({ username: '', email: '' });
176
+ setIsValidating(false);
177
+ }}
178
+ >
179
+ 重置
180
+ </Button>
181
+ <Button
182
+ type="button"
183
+ variant="secondary"
184
+ onClick={() => {
185
+ setFormData({
186
+ username: 'te', // 故意设置错误的值
187
+ email: 'invalid-email', // 故意设置错误的值
188
+ });
189
+ setIsValidating(true);
190
+ validateForm();
191
+ }}
192
+ >
193
+ 触发错误状态
194
+ </Button>
195
+ </div>
196
+ </form>
197
+ </div>
198
+ );
199
+ };
200
+
201
+ export const 表单验证: Story = {
202
+ render: () => <FormErrorDemo />,
203
+ };