|
3 | 3 |
|
4 | 4 | import {
|
5 | 5 | Button,
|
| 6 | + Dialog, |
6 | 7 | Drawer,
|
7 | 8 | Form,
|
8 | 9 | Icon,
|
9 | 10 | MultiSelect,
|
10 | 11 | MultiSelectOption,
|
| 12 | + TextField, |
| 13 | + Toggle, |
11 | 14 | ToggleButton,
|
12 | 15 | ToggleGroup,
|
13 | 16 | ToggleOption,
|
| 17 | + type MenuOption, |
14 | 18 | } from 'svelte-ux';
|
15 | 19 | import Preview from '$lib/components/Preview.svelte';
|
16 | 20 |
|
17 |
| - const options = [ |
| 21 | + let options: MenuOption[] = [ |
18 | 22 | { label: 'One', value: 1 },
|
19 | 23 | { label: 'Two', value: 2 },
|
20 | 24 | { label: 'Three', value: 3 },
|
21 | 25 | { label: 'Four', value: 4 },
|
22 | 26 | ];
|
23 | 27 |
|
| 28 | + const newOption: () => MenuOption = () => { |
| 29 | + return { label: '', value: null }; |
| 30 | + }; |
| 31 | +
|
24 | 32 | const manyOptions = Array.from({ length: 100 }).map((_, i) => ({
|
25 | 33 | label: `${i + 1}`,
|
26 | 34 | value: i + 1,
|
|
168 | 176 | </div>
|
169 | 177 | </Preview>
|
170 | 178 |
|
171 |
| -<h2>actions slot</h2> |
172 |
| - |
173 |
| -<Preview> |
174 |
| - {value.length} selected |
175 |
| - <div class="flex flex-col max-h-[360px] overflow-auto"> |
176 |
| - <MultiSelect {options} {value} on:change={(e) => (value = e.detail.value)} search> |
177 |
| - <div slot="actions"> |
178 |
| - <Button color="primary" icon={mdiPlus}>Add item</Button> |
179 |
| - </div> |
180 |
| - </MultiSelect> |
181 |
| - </div> |
182 |
| -</Preview> |
183 |
| - |
184 |
| -<h2>actions slot with max warning</h2> |
185 |
| - |
186 |
| -<Preview> |
187 |
| - {value.length} selected |
188 |
| - <div class="flex flex-col max-h-[360px] overflow-auto"> |
189 |
| - <MultiSelect {options} {value} on:change={(e) => (value = e.detail.value)} search max={2}> |
190 |
| - <div slot="actions" let:selection class="flex items-center"> |
191 |
| - {#if selection.isMaxSelected()} |
192 |
| - <div class="text-sm text-danger">Maximum selection reached</div> |
193 |
| - {/if} |
194 |
| - </div> |
195 |
| - </MultiSelect> |
196 |
| - </div> |
197 |
| -</Preview> |
198 |
| - |
199 | 179 | <h2>beforeOptions slot</h2>
|
200 | 180 |
|
201 | 181 | <Preview>
|
|
254 | 234 | </div>
|
255 | 235 | </Preview>
|
256 | 236 |
|
| 237 | +<h2>actions slot</h2> |
| 238 | + |
| 239 | +<Preview> |
| 240 | + {value.length} selected |
| 241 | + <div class="flex flex-col max-h-[360px] overflow-auto"> |
| 242 | + <MultiSelect {options} {value} on:change={(e) => (value = e.detail.value)} search> |
| 243 | + <div slot="actions" class="p-2" on:click|stopPropagation role="none"> |
| 244 | + <Toggle let:on={open} let:toggle> |
| 245 | + <Button icon={mdiPlus} color="primary" on:click={toggle}>New item</Button> |
| 246 | + <Form |
| 247 | + initial={newOption()} |
| 248 | + on:change={(e) => { |
| 249 | + // Convert value to number if it's a valid number, otherwise keep as string |
| 250 | + const newOptionData = { ...e.detail }; |
| 251 | + if ( |
| 252 | + newOptionData.value !== null && |
| 253 | + newOptionData.value !== '' && |
| 254 | + !isNaN(Number(newOptionData.value)) |
| 255 | + ) { |
| 256 | + newOptionData.value = Number(newOptionData.value); |
| 257 | + } |
| 258 | + options = [newOptionData, ...options]; |
| 259 | + // Auto-select the newly created option |
| 260 | + value = [...(value || []), newOptionData.value]; |
| 261 | + }} |
| 262 | + let:draft |
| 263 | + let:current |
| 264 | + let:commit |
| 265 | + let:revert |
| 266 | + > |
| 267 | + <Dialog |
| 268 | + {open} |
| 269 | + on:close={() => { |
| 270 | + toggle(); |
| 271 | + }} |
| 272 | + > |
| 273 | + <div slot="title">Create new option</div> |
| 274 | + <div class="px-6 py-3 w-96 grid gap-2"> |
| 275 | + <TextField |
| 276 | + label="Label" |
| 277 | + value={current.label} |
| 278 | + on:change={(e) => { |
| 279 | + draft.label = e.detail.value; |
| 280 | + }} |
| 281 | + autofocus |
| 282 | + /> |
| 283 | + <TextField |
| 284 | + label="Value" |
| 285 | + value={draft.value} |
| 286 | + on:change={(e) => { |
| 287 | + draft.value = e.detail.value; |
| 288 | + }} |
| 289 | + /> |
| 290 | + </div> |
| 291 | + <div slot="actions"> |
| 292 | + <Button |
| 293 | + on:click={() => { |
| 294 | + commit(); |
| 295 | + toggle(); |
| 296 | + }} |
| 297 | + color="primary">Add option</Button |
| 298 | + > |
| 299 | + <Button |
| 300 | + on:click={() => { |
| 301 | + revert(); |
| 302 | + toggle(); |
| 303 | + }}>Cancel</Button |
| 304 | + > |
| 305 | + </div> |
| 306 | + </Dialog> |
| 307 | + </Form> |
| 308 | + </Toggle> |
| 309 | + </div> |
| 310 | + </MultiSelect> |
| 311 | + </div> |
| 312 | +</Preview> |
| 313 | + |
| 314 | +<h2>actions slot with max warning</h2> |
| 315 | + |
| 316 | +<Preview> |
| 317 | + {value.length} selected |
| 318 | + <div class="flex flex-col max-h-[360px] overflow-auto"> |
| 319 | + <MultiSelect {options} {value} on:change={(e) => (value = e.detail.value)} search max={2}> |
| 320 | + <div slot="actions" let:selection class="flex items-center"> |
| 321 | + {#if selection.isMaxSelected()} |
| 322 | + <div class="text-sm text-danger">Maximum selection reached</div> |
| 323 | + {/if} |
| 324 | + </div> |
| 325 | + </MultiSelect> |
| 326 | + </div> |
| 327 | +</Preview> |
| 328 | + |
257 | 329 | <h2>option slot with MultiSelectOption custom actions</h2>
|
258 | 330 |
|
259 | 331 | <Preview>
|
|
0 commit comments