Skip to content

Commit 33fa1ab

Browse files
viva-jinyisnomiao
authored andcommitted
[feat] Enhance MultiSelect component and Storybook stories (#5154)
1 parent 345a1d4 commit 33fa1ab

File tree

11 files changed

+432
-184
lines changed

11 files changed

+432
-184
lines changed

.storybook/preview-head.html

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@
44
transition: background-color 0.3s ease, color 0.3s ease;
55
}
66

7-
/* Light theme default */
8-
body {
9-
background-color: #ffffff;
10-
color: #1a1a1a;
7+
/* Light theme default - with explicit color to override media queries */
8+
body:not(.dark-theme) {
9+
background-color: #fff !important;
10+
color: #000 !important;
11+
}
12+
13+
/* Override browser dark mode preference for light theme */
14+
@media (prefers-color-scheme: dark) {
15+
body:not(.dark-theme) {
16+
color: #000 !important;
17+
--fg-color: #000 !important;
18+
--bg-color: #fff !important;
19+
}
1120
}
1221

1322
/* Dark theme styles */
1423
body.dark-theme,
1524
.dark-theme body {
16-
background-color: #0a0a0a;
17-
color: #e5e5e5;
25+
background-color: #202020;
26+
color: #fff;
1827
}
1928

2029
/* Ensure Storybook canvas follows theme */
@@ -24,11 +33,33 @@
2433

2534
.dark-theme .sb-show-main,
2635
.dark-theme .docs-story {
27-
background-color: #0a0a0a !important;
36+
background-color: #202020 !important;
37+
}
38+
39+
/* CSS Variables for theme consistency */
40+
body:not(.dark-theme) {
41+
--fg-color: #000;
42+
--bg-color: #fff;
43+
--content-bg: #e0e0e0;
44+
--content-fg: #000;
45+
--content-hover-bg: #adadad;
46+
--content-hover-fg: #000;
47+
}
48+
49+
body.dark-theme {
50+
--fg-color: #fff;
51+
--bg-color: #202020;
52+
--content-bg: #4e4e4e;
53+
--content-fg: #fff;
54+
--content-hover-bg: #222;
55+
--content-hover-fg: #fff;
2856
}
2957

30-
/* Fix for Storybook controls panel in dark mode */
31-
.dark-theme .docblock-argstable-body {
32-
color: #e5e5e5;
58+
/* Override Storybook's problematic & selector styles */
59+
/* Reset only the specific properties that Storybook injects */
60+
#storybook-root li+li,
61+
#storybook-docs li+li {
62+
margin: inherit;
63+
padding: inherit;
3364
}
3465
</style>

src/components/button/MoreButton.stories.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ export const Basic: Story = {
2424
<MoreButton>
2525
<template #default="{ close }">
2626
<IconTextButton
27-
type="secondary"
27+
type="transparent"
2828
label="Settings"
2929
@click="() => { close() }"
3030
>
3131
<template #icon>
32-
<Download />
32+
<Download :size="16" />
3333
</template>
3434
</IconTextButton>
3535
3636
<IconTextButton
37-
type="primary"
37+
type="transparent"
3838
label="Profile"
3939
@click="() => { close() }"
4040
>
4141
<template #icon>
42-
<ScrollText />
42+
<ScrollText :size="16" />
4343
</template>
4444
</IconTextButton>
4545
</template>

src/components/input/MultiSelect.stories.ts

Lines changed: 139 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
import type { Meta, StoryObj } from '@storybook/vue3-vite'
2+
import type { MultiSelectProps } from 'primevue/multiselect'
23
import { ref } from 'vue'
34

45
import MultiSelect from './MultiSelect.vue'
56

6-
const meta: Meta<typeof MultiSelect> = {
7+
// Combine our component props with PrimeVue MultiSelect props
8+
// Since we use v-bind="$attrs", all PrimeVue props are available
9+
interface ExtendedProps extends Partial<MultiSelectProps> {
10+
// Our custom props
11+
label?: string
12+
showSearchBox?: boolean
13+
showSelectedCount?: boolean
14+
showClearButton?: boolean
15+
searchPlaceholder?: string
16+
// Override modelValue type to match our Option type
17+
modelValue?: Array<{ name: string; value: string }>
18+
}
19+
20+
const meta: Meta<ExtendedProps> = {
721
title: 'Components/Input/MultiSelect',
822
component: MultiSelect,
923
tags: ['autodocs'],
@@ -13,7 +27,35 @@ const meta: Meta<typeof MultiSelect> = {
1327
},
1428
options: {
1529
control: 'object'
30+
},
31+
showSearchBox: {
32+
control: 'boolean',
33+
description: 'Toggle searchBar visibility'
34+
},
35+
showSelectedCount: {
36+
control: 'boolean',
37+
description: 'Toggle selected count visibility'
38+
},
39+
showClearButton: {
40+
control: 'boolean',
41+
description: 'Toggle clear button visibility'
42+
},
43+
searchPlaceholder: {
44+
control: 'text'
1645
}
46+
},
47+
args: {
48+
label: 'Select',
49+
options: [
50+
{ name: 'Vue', value: 'vue' },
51+
{ name: 'React', value: 'react' },
52+
{ name: 'Angular', value: 'angular' },
53+
{ name: 'Svelte', value: 'svelte' }
54+
],
55+
showSearchBox: false,
56+
showSelectedCount: false,
57+
showClearButton: false,
58+
searchPlaceholder: 'Search...'
1759
}
1860
}
1961

@@ -25,7 +67,7 @@ export const Default: Story = {
2567
components: { MultiSelect },
2668
setup() {
2769
const selected = ref([])
28-
const options = [
70+
const options = args.options || [
2971
{ name: 'Vue', value: 'vue' },
3072
{ name: 'React', value: 'react' },
3173
{ name: 'Angular', value: 'angular' },
@@ -38,8 +80,11 @@ export const Default: Story = {
3880
<MultiSelect
3981
v-model="selected"
4082
:options="options"
41-
label="Select Frameworks"
42-
v-bind="args"
83+
:label="args.label"
84+
:showSearchBox="args.showSearchBox"
85+
:showSelectedCount="args.showSelectedCount"
86+
:showClearButton="args.showClearButton"
87+
:searchPlaceholder="args.searchPlaceholder"
4388
/>
4489
<div class="mt-4 p-3 bg-gray-50 dark-theme:bg-zinc-800 rounded">
4590
<p class="text-sm">Selected: {{ selected.length > 0 ? selected.map(s => s.name).join(', ') : 'None' }}</p>
@@ -50,36 +95,54 @@ export const Default: Story = {
5095
}
5196

5297
export const WithPreselectedValues: Story = {
53-
render: () => ({
98+
render: (args) => ({
5499
components: { MultiSelect },
55100
setup() {
56-
const options = [
101+
const options = args.options || [
57102
{ name: 'JavaScript', value: 'js' },
58103
{ name: 'TypeScript', value: 'ts' },
59104
{ name: 'Python', value: 'python' },
60105
{ name: 'Go', value: 'go' },
61106
{ name: 'Rust', value: 'rust' }
62107
]
63108
const selected = ref([options[0], options[1]])
64-
return { selected, options }
109+
return { selected, options, args }
65110
},
66111
template: `
67112
<div>
68113
<MultiSelect
69114
v-model="selected"
70115
:options="options"
71-
label="Select Languages"
116+
:label="args.label"
117+
:showSearchBox="args.showSearchBox"
118+
:showSelectedCount="args.showSelectedCount"
119+
:showClearButton="args.showClearButton"
120+
:searchPlaceholder="args.searchPlaceholder"
72121
/>
73122
<div class="mt-4 p-3 bg-gray-50 dark-theme:bg-zinc-800 rounded">
74123
<p class="text-sm">Selected: {{ selected.map(s => s.name).join(', ') }}</p>
75124
</div>
76125
</div>
77126
`
78-
})
127+
}),
128+
args: {
129+
label: 'Select Languages',
130+
options: [
131+
{ name: 'JavaScript', value: 'js' },
132+
{ name: 'TypeScript', value: 'ts' },
133+
{ name: 'Python', value: 'python' },
134+
{ name: 'Go', value: 'go' },
135+
{ name: 'Rust', value: 'rust' }
136+
],
137+
showSearchBox: false,
138+
showSelectedCount: false,
139+
showClearButton: false,
140+
searchPlaceholder: 'Search...'
141+
}
79142
}
80143

81144
export const MultipleSelectors: Story = {
82-
render: () => ({
145+
render: (args) => ({
83146
components: { MultiSelect },
84147
setup() {
85148
const frameworkOptions = ref([
@@ -114,7 +177,8 @@ export const MultipleSelectors: Story = {
114177
tagOptions,
115178
selectedFrameworks,
116179
selectedProjects,
117-
selectedTags
180+
selectedTags,
181+
args
118182
}
119183
},
120184
template: `
@@ -124,28 +188,89 @@ export const MultipleSelectors: Story = {
124188
v-model="selectedFrameworks"
125189
:options="frameworkOptions"
126190
label="Select Frameworks"
191+
:showSearchBox="args.showSearchBox"
192+
:showSelectedCount="args.showSelectedCount"
193+
:showClearButton="args.showClearButton"
194+
:searchPlaceholder="args.searchPlaceholder"
127195
/>
128196
<MultiSelect
129197
v-model="selectedProjects"
130198
:options="projectOptions"
131199
label="Select Projects"
200+
:showSearchBox="args.showSearchBox"
201+
:showSelectedCount="args.showSelectedCount"
202+
:showClearButton="args.showClearButton"
203+
:searchPlaceholder="args.searchPlaceholder"
132204
/>
133205
<MultiSelect
134206
v-model="selectedTags"
135207
:options="tagOptions"
136208
label="Select Tags"
209+
:showSearchBox="args.showSearchBox"
210+
:showSelectedCount="args.showSelectedCount"
211+
:showClearButton="args.showClearButton"
212+
:searchPlaceholder="args.searchPlaceholder"
137213
/>
138214
</div>
139215
140216
<div class="p-4 bg-gray-50 dark-theme:bg-zinc-800 rounded">
141-
<h4 class="font-medium mb-2">Current Selection:</h4>
142-
<div class="space-y-1 text-sm">
217+
<h4 class="font-medium mt-0">Current Selection:</h4>
218+
<div class="flex flex-col text-sm">
143219
<p>Frameworks: {{ selectedFrameworks.length > 0 ? selectedFrameworks.map(s => s.name).join(', ') : 'None' }}</p>
144220
<p>Projects: {{ selectedProjects.length > 0 ? selectedProjects.map(s => s.name).join(', ') : 'None' }}</p>
145221
<p>Tags: {{ selectedTags.length > 0 ? selectedTags.map(s => s.name).join(', ') : 'None' }}</p>
146222
</div>
147223
</div>
148224
</div>
149225
`
150-
})
226+
}),
227+
args: {
228+
showSearchBox: false,
229+
showSelectedCount: false,
230+
showClearButton: false,
231+
searchPlaceholder: 'Search...'
232+
}
233+
}
234+
235+
export const WithSearchBox: Story = {
236+
...Default,
237+
args: {
238+
...Default.args,
239+
showSearchBox: true
240+
}
241+
}
242+
243+
export const WithSelectedCount: Story = {
244+
...Default,
245+
args: {
246+
...Default.args,
247+
showSelectedCount: true
248+
}
249+
}
250+
251+
export const WithClearButton: Story = {
252+
...Default,
253+
args: {
254+
...Default.args,
255+
showClearButton: true
256+
}
257+
}
258+
259+
export const AllHeaderFeatures: Story = {
260+
...Default,
261+
args: {
262+
...Default.args,
263+
showSearchBox: true,
264+
showSelectedCount: true,
265+
showClearButton: true
266+
}
267+
}
268+
269+
export const CustomSearchPlaceholder: Story = {
270+
...Default,
271+
args: {
272+
...Default.args,
273+
showSearchBox: true,
274+
searchPlaceholder: 'Filter packages...'
275+
}
151276
}

0 commit comments

Comments
 (0)