fluentui-svelte 0.5.0 → 0.7.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.
- package/dist/components/app-surface/app-surface.svelte +96 -0
- package/dist/components/app-surface/app-surface.svelte.d.ts +22 -0
- package/dist/components/app-surface/docs/llms.md +73 -0
- package/dist/components/app-surface/types.d.ts +19 -0
- package/dist/components/app-surface/types.js +1 -0
- package/dist/components/app-window/app-window.d.ts +3 -0
- package/dist/components/app-window/app-window.js +3 -0
- package/dist/components/app-window/app-window.svelte +193 -0
- package/dist/components/app-window/app-window.svelte.d.ts +25 -0
- package/dist/components/app-window/docs/llms.md +119 -0
- package/dist/components/app-window/types.d.ts +66 -0
- package/dist/components/app-window/types.js +1 -0
- package/dist/components/auto-suggest-box/auto-suggest-box.svelte +47 -31
- package/dist/components/auto-suggest-box/auto-suggest-box.svelte.d.ts +2 -2
- package/dist/components/auto-suggest-box/docs/llms.md +34 -33
- package/dist/components/auto-suggest-box/option.svelte +6 -4
- package/dist/components/auto-suggest-box/types.d.ts +13 -16
- package/dist/components/avatar/avatar.svelte +4 -3
- package/dist/components/avatar/docs/llms.md +1 -1
- package/dist/components/avatar/type.d.ts +1 -1
- package/dist/components/badge/badge-icon.svelte +2 -2
- package/dist/components/badge/badge.svelte +2 -2
- package/dist/components/badge/docs/llms.md +2 -2
- package/dist/components/badge/types.d.ts +2 -2
- package/dist/components/breadcrumb/breadcrumb-button.svelte +2 -2
- package/dist/components/breadcrumb/breadcrumb-divider.svelte +2 -2
- package/dist/components/breadcrumb/breadcrumb-item.svelte +2 -2
- package/dist/components/breadcrumb/breadcrumb.svelte +10 -5
- package/dist/components/breadcrumb/docs/llms.md +11 -11
- package/dist/components/breadcrumb/types.d.ts +7 -7
- package/dist/components/button/button.svelte +2 -2
- package/dist/components/button/docs/llms.md +17 -17
- package/dist/components/button/split-button.svelte +7 -7
- package/dist/components/button/types.d.ts +5 -5
- package/dist/components/calendar-date-picker/calendar-date-picker.svelte +98 -10
- package/dist/components/calendar-date-picker/calendar-date-picker.svelte.d.ts +1 -1
- package/dist/components/calendar-date-picker/docs/llms.md +19 -14
- package/dist/components/calendar-date-picker/types.d.ts +22 -8
- package/dist/components/calendar-view/calendar-view-days.svelte +3 -2
- package/dist/components/calendar-view/calendar-view-grid.js +8 -3
- package/dist/components/calendar-view/calendar-view-item.svelte +10 -4
- package/dist/components/calendar-view/calendar-view-months.svelte +3 -2
- package/dist/components/calendar-view/calendar-view-years.svelte +3 -2
- package/dist/components/calendar-view/calendar-view.svelte +11 -4
- package/dist/components/calendar-view/calendar-view.svelte.js +5 -0
- package/dist/components/calendar-view/docs/llms.md +20 -19
- package/dist/components/calendar-view/types.d.ts +6 -1
- package/dist/components/card/card-footer.svelte +2 -2
- package/dist/components/card/card-header.svelte +5 -4
- package/dist/components/card/card-preview.svelte +13 -2
- package/dist/components/card/card.svelte +5 -5
- package/dist/components/card/docs/llms.md +22 -21
- package/dist/components/card/types.d.ts +8 -4
- package/dist/components/checkbox/checkbox.svelte +47 -26
- package/dist/components/checkbox/checkbox.svelte.d.ts +3 -24
- package/dist/components/checkbox/docs/llms.md +24 -23
- package/dist/components/checkbox/types.d.ts +10 -23
- package/dist/components/date-picker/date-picker.svelte +98 -27
- package/dist/components/date-picker/date-picker.svelte.d.ts +1 -1
- package/dist/components/date-picker/docs/llms.md +23 -20
- package/dist/components/date-picker/types.d.ts +24 -15
- package/dist/components/dialog/dialog-actions.svelte +17 -2
- package/dist/components/dialog/dialog-content.svelte +2 -2
- package/dist/components/dialog/dialog-content.svelte.d.ts +1 -1
- package/dist/components/dialog/dialog-surface.svelte +130 -8
- package/dist/components/dialog/dialog-title.svelte +23 -6
- package/dist/components/dialog/dialog-trigger.svelte +8 -2
- package/dist/components/dialog/dialog-trigger.svelte.d.ts +1 -1
- package/dist/components/dialog/dialog.svelte +22 -11
- package/dist/components/dialog/docs/llms.md +56 -19
- package/dist/components/dialog/types.d.ts +31 -9
- package/dist/components/dialog/utils.d.ts +2 -0
- package/dist/components/dialog/utils.js +1 -0
- package/dist/components/divider/divider.svelte +6 -4
- package/dist/components/divider/types.d.ts +1 -1
- package/dist/components/dropdown/docs/llms.md +30 -28
- package/dist/components/dropdown/dropdown-option.svelte +17 -5
- package/dist/components/dropdown/dropdown.svelte +182 -84
- package/dist/components/dropdown/dropdown.svelte.d.ts +1 -1
- package/dist/components/dropdown/types.d.ts +26 -20
- package/dist/components/dropdown-select/docs/llms.md +24 -22
- package/dist/components/dropdown-select/dropdown-select-option.svelte +2 -2
- package/dist/components/dropdown-select/dropdown-select.svelte +42 -7
- package/dist/components/dropdown-select/types.d.ts +4 -4
- package/dist/components/expander/docs/llms.md +3 -3
- package/dist/components/expander/expander.svelte +13 -8
- package/dist/components/expander/types.d.ts +5 -5
- package/dist/components/flyout/docs/llms.md +1 -1
- package/dist/components/flyout/flyout.svelte +17 -6
- package/dist/components/flyout/types.d.ts +1 -1
- package/dist/components/hyperlink/docs/llms.md +6 -6
- package/dist/components/hyperlink/hyperlink.svelte +13 -4
- package/dist/components/hyperlink/types.d.ts +1 -1
- package/dist/components/info-bar/docs/llms.md +11 -10
- package/dist/components/info-bar/info-bar.svelte +3 -2
- package/dist/components/info-bar/types.d.ts +4 -0
- package/dist/components/label/docs/llms.md +75 -22
- package/dist/components/label/label-context.d.ts +14 -0
- package/dist/components/label/label-context.js +10 -0
- package/dist/components/label/label.svelte +153 -30
- package/dist/components/label/label.svelte.d.ts +1 -1
- package/dist/components/label/types.d.ts +48 -4
- package/dist/components/list-view/docs/llms.md +103 -33
- package/dist/components/list-view/list-view-item-branch.svelte +257 -0
- package/dist/components/list-view/list-view-item-branch.svelte.d.ts +4 -0
- package/dist/components/list-view/list-view-item.svelte +164 -46
- package/dist/components/list-view/list-view-item.svelte.d.ts +5 -5
- package/dist/components/list-view/list-view.svelte +73 -25
- package/dist/components/list-view/types.d.ts +71 -8
- package/dist/components/list-view/utils.d.ts +10 -0
- package/dist/components/list-view/utils.js +17 -1
- package/dist/components/menu/docs/llms.md +98 -15
- package/dist/components/menu/menu-command-bar-item.svelte +61 -0
- package/dist/components/menu/menu-command-bar-item.svelte.d.ts +14 -0
- package/dist/components/menu/menu-command-bar.svelte +218 -0
- package/dist/components/menu/menu-command-bar.svelte.d.ts +21 -0
- package/dist/components/menu/menu-group.svelte +6 -3
- package/dist/components/menu/menu-item-checkbox.svelte +5 -4
- package/dist/components/menu/menu-item-radio.svelte +5 -4
- package/dist/components/menu/menu-item-switch.svelte +5 -4
- package/dist/components/menu/menu-item.svelte +5 -5
- package/dist/components/menu/menu-item.svelte.d.ts +2 -3
- package/dist/components/menu/menu-list.svelte +10 -1
- package/dist/components/menu/menu-popover.svelte +9 -5
- package/dist/components/menu/menu-trigger.svelte +2 -1
- package/dist/components/menu/menu.svelte.js +1 -0
- package/dist/components/menu/types.d.ts +62 -7
- package/dist/components/number-box/docs/llms.md +6 -4
- package/dist/components/number-box/number-box.svelte +35 -29
- package/dist/components/number-box/number-box.svelte.d.ts +1 -1
- package/dist/components/number-box/types.d.ts +1 -1
- package/dist/components/persona/docs/llms.md +29 -25
- package/dist/components/persona/persona.svelte +8 -6
- package/dist/components/persona/types.d.ts +4 -3
- package/dist/components/progress-bar/docs/llms.md +13 -13
- package/dist/components/progress-bar/progress-bar.svelte +6 -6
- package/dist/components/progress-bar/types.d.ts +4 -4
- package/dist/components/progress-ring/docs/llms.md +14 -14
- package/dist/components/progress-ring/progress-ring.svelte +5 -5
- package/dist/components/progress-ring/types.d.ts +3 -3
- package/dist/components/radio-button/docs/llms.md +11 -8
- package/dist/components/radio-button/radio-button.svelte +38 -12
- package/dist/components/radio-button/radio-button.svelte.d.ts +1 -1
- package/dist/components/radio-button/types.d.ts +11 -8
- package/dist/components/rating/docs/llms.md +111 -0
- package/dist/components/rating/rating.svelte +247 -0
- package/dist/components/rating/rating.svelte.d.ts +19 -0
- package/dist/components/rating/types.d.ts +44 -0
- package/dist/components/rating/types.js +1 -0
- package/dist/components/side-nav/docs/llms.md +110 -0
- package/dist/components/side-nav/side-nav-branch.svelte +43 -0
- package/dist/components/side-nav/side-nav-branch.svelte.d.ts +4 -0
- package/dist/components/side-nav/side-nav-item.svelte +75 -0
- package/dist/components/side-nav/side-nav-item.svelte.d.ts +25 -0
- package/dist/components/side-nav/side-nav-list.svelte +32 -0
- package/dist/components/side-nav/side-nav-list.svelte.d.ts +7 -0
- package/dist/components/side-nav/side-nav.d.ts +2 -0
- package/dist/components/side-nav/side-nav.js +2 -0
- package/dist/components/side-nav/side-nav.svelte +355 -0
- package/dist/components/side-nav/side-nav.svelte.d.ts +24 -0
- package/dist/components/side-nav/types.d.ts +149 -0
- package/dist/components/side-nav/types.js +1 -0
- package/dist/components/skeleton/docs/llms.md +1 -1
- package/dist/components/skeleton/skeleton.svelte +2 -2
- package/dist/components/skeleton/types.d.ts +1 -1
- package/dist/components/slider/docs/llms.md +31 -28
- package/dist/components/slider/slider.svelte +126 -61
- package/dist/components/slider/slider.svelte.d.ts +1 -3
- package/dist/components/slider/types.d.ts +21 -14
- package/dist/components/tab-view/docs/llms.md +7 -7
- package/dist/components/tab-view/tab-view-tab.svelte +16 -14
- package/dist/components/tab-view/tab-view.svelte +16 -9
- package/dist/components/tab-view/types.d.ts +6 -6
- package/dist/components/table/docs/llms.md +38 -33
- package/dist/components/table/table-body.svelte +2 -2
- package/dist/components/table/table-cell-actions.svelte +8 -2
- package/dist/components/table/table-cell-layout.svelte +2 -2
- package/dist/components/table/table-cell.svelte +2 -2
- package/dist/components/table/table-header-cell.svelte +2 -2
- package/dist/components/table/table-header.svelte +2 -2
- package/dist/components/table/table-row.svelte +2 -2
- package/dist/components/table/table-selection-cell.svelte +6 -6
- package/dist/components/table/table.svelte +2 -2
- package/dist/components/table/types.d.ts +11 -11
- package/dist/components/tag/docs/llms.md +383 -0
- package/dist/components/tag/tag-group.d.ts +2 -0
- package/dist/components/tag/tag-group.js +2 -0
- package/dist/components/tag/tag-group.svelte +117 -0
- package/dist/components/tag/tag-group.svelte.d.ts +20 -0
- package/dist/components/tag/tag.svelte +459 -0
- package/dist/components/tag/tag.svelte.d.ts +19 -0
- package/dist/components/tag/types.d.ts +137 -0
- package/dist/components/tag/types.js +1 -0
- package/dist/components/tag-picker/docs/llms.md +298 -0
- package/dist/components/tag-picker/option-group.svelte +51 -0
- package/dist/components/tag-picker/option-group.svelte.d.ts +4 -0
- package/dist/components/tag-picker/option.svelte +82 -0
- package/dist/components/tag-picker/option.svelte.d.ts +4 -0
- package/dist/components/tag-picker/tag-picker.d.ts +2 -0
- package/dist/components/tag-picker/tag-picker.js +2 -0
- package/dist/components/tag-picker/tag-picker.svelte +716 -0
- package/dist/components/tag-picker/tag-picker.svelte.d.ts +21 -0
- package/dist/components/tag-picker/types.d.ts +142 -0
- package/dist/components/tag-picker/types.js +1 -0
- package/dist/components/text-box/docs/llms.md +31 -4
- package/dist/components/text-box/text-box-button.svelte +3 -3
- package/dist/components/text-box/text-box-button.svelte.d.ts +1 -1
- package/dist/components/text-box/text-box.svelte +41 -14
- package/dist/components/text-box/types.d.ts +5 -5
- package/dist/components/textarea/docs/llms.md +4 -3
- package/dist/components/textarea/textarea.svelte +14 -6
- package/dist/components/textarea/types.d.ts +2 -4
- package/dist/components/time-picker/docs/llms.md +18 -15
- package/dist/components/time-picker/time-picker.svelte +133 -33
- package/dist/components/time-picker/time-picker.svelte.d.ts +1 -1
- package/dist/components/time-picker/types.d.ts +23 -13
- package/dist/components/title-bar/docs/llms.md +382 -0
- package/dist/components/title-bar/title-bar-left-controls.svelte +215 -0
- package/dist/components/title-bar/title-bar-left-controls.svelte.d.ts +22 -0
- package/dist/components/title-bar/title-bar-right-controls.svelte +190 -0
- package/dist/components/title-bar/title-bar-right-controls.svelte.d.ts +27 -0
- package/dist/components/title-bar/title-bar.d.ts +3 -0
- package/dist/components/title-bar/title-bar.js +4 -0
- package/dist/components/title-bar/title-bar.svelte +224 -0
- package/dist/components/title-bar/title-bar.svelte.d.ts +26 -0
- package/dist/components/title-bar/types.d.ts +165 -0
- package/dist/components/title-bar/types.js +1 -0
- package/dist/components/toggle-switch/docs/llms.md +11 -9
- package/dist/components/toggle-switch/toggle-switch.svelte +23 -14
- package/dist/components/toggle-switch/toggle-switch.svelte.d.ts +1 -1
- package/dist/components/toggle-switch/types.d.ts +12 -10
- package/dist/components/tooltip/docs/llms.md +1 -1
- package/dist/components/tooltip/tooltip.svelte +5 -4
- package/dist/components/tooltip/types.d.ts +1 -1
- package/dist/components/top-nav/docs/llms.md +1 -1
- package/dist/components/top-nav/top-nav-item.svelte +2 -2
- package/dist/components/top-nav/top-nav.svelte +2 -2
- package/dist/components/top-nav/types.d.ts +2 -2
- package/dist/components/tree-view/docs/llms.md +11 -11
- package/dist/components/tree-view/tree-view-item-content.svelte +3 -3
- package/dist/components/tree-view/tree-view-item.svelte +13 -5
- package/dist/components/tree-view/tree-view.svelte +20 -5
- package/dist/components/tree-view/tree-view.svelte.d.ts +1 -1
- package/dist/components/tree-view/tree-view.svelte.js +31 -3
- package/dist/components/tree-view/types.d.ts +7 -3
- package/dist/index.d.ts +25 -0
- package/dist/index.js +32 -0
- package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte +26 -5
- package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte.d.ts +2 -0
- package/dist/internal/constants.d.ts +0 -4
- package/dist/internal/constants.js +0 -4002
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.js +1 -0
- package/dist/internal/native-field.svelte.d.ts +44 -0
- package/dist/internal/native-field.svelte.js +85 -0
- package/dist/internal/utils.d.ts +16 -2
- package/dist/internal/utils.js +25 -3
- package/dist/types/index.d.ts +3 -3
- package/package.json +51 -37
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { claimLabel } from '../label/label-context.js';
|
|
3
|
+
import { dispatchFieldEvents, invokeHandlers, NativeField } from '../../internal/index.js';
|
|
2
4
|
import { onClickOutside } from 'runed';
|
|
3
5
|
import ChevronDownFilled from 'fluentui-icons-svelte/ChevronDownFilled.svelte';
|
|
4
6
|
import { Flyout, ListView, ListViewItem } from '../../index.js';
|
|
5
|
-
import type { DropdownContext, DropdownProps } from './types.js';
|
|
7
|
+
import type { DropdownContext, DropdownOptionLabel, DropdownProps } from './types.js';
|
|
6
8
|
import { tick } from 'svelte';
|
|
7
|
-
import {
|
|
8
|
-
import { setTabspotAttributes, unsetTabspotSection } from 'tabspot';
|
|
9
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
10
|
+
import { clearTabspotActive, setTabspotActive, setTabspotAttributes, unsetTabspotSection } from 'tabspot';
|
|
9
11
|
import { PREFIX } from '../../internal/constants.js';
|
|
10
12
|
import { getGlobalFSContext } from '../../providers/fluentui-svelte/fluentui-svelte.js';
|
|
11
13
|
import { setDropdownContext } from './dropdown-context.js';
|
|
@@ -13,26 +15,39 @@
|
|
|
13
15
|
const FALLBACK_ID = $props.id();
|
|
14
16
|
const ID = `${PREFIX}-dropdown-${FALLBACK_ID}`;
|
|
15
17
|
|
|
18
|
+
const labelContext = claimLabel(() => id);
|
|
19
|
+
|
|
16
20
|
let {
|
|
17
|
-
id = ID,
|
|
18
|
-
name
|
|
21
|
+
id = labelContext?.fieldId ?? ID,
|
|
22
|
+
name,
|
|
19
23
|
placeholder = 'Select an option',
|
|
20
24
|
multiple,
|
|
21
25
|
value = $bindable(multiple ? [] : ''),
|
|
22
26
|
disabled,
|
|
23
27
|
flyoutMaxHeight,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
wrapperRef = $bindable(null),
|
|
29
|
+
wrapperAttributes,
|
|
30
|
+
ref = $bindable(null),
|
|
31
|
+
buttonRef = $bindable(null),
|
|
32
|
+
buttonAttributes,
|
|
33
|
+
flyoutRef = $bindable(null),
|
|
29
34
|
flyoutProps,
|
|
30
|
-
listboxRef = $bindable(),
|
|
35
|
+
listboxRef = $bindable(null),
|
|
31
36
|
listboxProps,
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
onfocus,
|
|
38
|
+
onblur,
|
|
39
|
+
children,
|
|
40
|
+
...attributes
|
|
34
41
|
}: DropdownProps = $props();
|
|
35
42
|
|
|
43
|
+
const BUTTON_ID = $derived(buttonAttributes?.id ?? `${id}-button`);
|
|
44
|
+
|
|
45
|
+
const native = new NativeField(
|
|
46
|
+
() => ref,
|
|
47
|
+
() => buttonRef,
|
|
48
|
+
labelContext
|
|
49
|
+
);
|
|
50
|
+
|
|
36
51
|
let open = $state(false);
|
|
37
52
|
|
|
38
53
|
let roundClass = $state('bottom');
|
|
@@ -41,16 +56,19 @@
|
|
|
41
56
|
|
|
42
57
|
const OPEN_KEYS = ['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Enter', ' '];
|
|
43
58
|
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
const optionLabels = new
|
|
59
|
+
// The list stays in the page while closed, so every option is here from the start, and is read live.
|
|
60
|
+
const options = new SvelteSet<DropdownOptionLabel>();
|
|
61
|
+
const optionLabels = $derived(new Map([...options].map((option) => [option.value, option.text])));
|
|
47
62
|
|
|
48
63
|
const context: DropdownContext = $state({
|
|
49
64
|
config: null,
|
|
50
65
|
state: null,
|
|
51
66
|
events: null,
|
|
52
67
|
methods: {
|
|
53
|
-
registerOption: (
|
|
68
|
+
registerOption: (option) => {
|
|
69
|
+
options.add(option);
|
|
70
|
+
return () => options.delete(option);
|
|
71
|
+
}
|
|
54
72
|
}
|
|
55
73
|
});
|
|
56
74
|
|
|
@@ -65,8 +83,11 @@
|
|
|
65
83
|
);
|
|
66
84
|
|
|
67
85
|
onClickOutside(
|
|
68
|
-
() =>
|
|
69
|
-
() =>
|
|
86
|
+
() => wrapperRef,
|
|
87
|
+
(event) => {
|
|
88
|
+
if (event.target instanceof Element && event.target.closest('label')?.control === ref) return;
|
|
89
|
+
closeDropdown();
|
|
90
|
+
}
|
|
70
91
|
);
|
|
71
92
|
|
|
72
93
|
function handlePlacementChange(newPlacement: string) {
|
|
@@ -77,7 +98,12 @@
|
|
|
77
98
|
if (disabled || open) return;
|
|
78
99
|
open = true;
|
|
79
100
|
await tick();
|
|
80
|
-
globalFSContext?.state?.tabspotInstance?.rebuild(
|
|
101
|
+
globalFSContext?.state?.tabspotInstance?.rebuild(wrapperRef ?? undefined);
|
|
102
|
+
// The cursor starts on the selection, or on the first option, so it is announced on open.
|
|
103
|
+
const start =
|
|
104
|
+
listboxRef?.querySelector<HTMLElement>('.fs-list-view-item[aria-selected="true"]:not([aria-disabled="true"])') ??
|
|
105
|
+
listboxRef?.querySelector<HTMLElement>('.fs-list-view-item:not([aria-disabled="true"])');
|
|
106
|
+
if (start) setTabspotActive(start, { nearest: true });
|
|
81
107
|
}
|
|
82
108
|
|
|
83
109
|
function closeDropdown() {
|
|
@@ -91,6 +117,13 @@
|
|
|
91
117
|
|
|
92
118
|
const { key } = e;
|
|
93
119
|
|
|
120
|
+
if (open && (key === 'Enter' || key === ' ')) {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
// Focus stays on the button, so the option under the cursor never sees the key: click it here.
|
|
123
|
+
listboxRef?.querySelector<HTMLElement>('[data-active="true"]')?.click();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
94
127
|
if (OPEN_KEYS.includes(key)) {
|
|
95
128
|
e.preventDefault();
|
|
96
129
|
await openDropdown();
|
|
@@ -103,18 +136,32 @@
|
|
|
103
136
|
}
|
|
104
137
|
}
|
|
105
138
|
|
|
106
|
-
async function handleClick(
|
|
139
|
+
async function handleClick() {
|
|
107
140
|
if (open) closeDropdown();
|
|
108
141
|
else await openDropdown();
|
|
109
|
-
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** A label activates the native select it belongs to, which hands the activation to the button. */
|
|
145
|
+
async function openFromField() {
|
|
146
|
+
buttonRef?.focus();
|
|
147
|
+
await openDropdown();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function select(items: string[] | undefined) {
|
|
151
|
+
const next = multiple ? (items ?? []) : (items?.[0] ?? '');
|
|
152
|
+
if (!multiple && next === value) return;
|
|
153
|
+
value = next;
|
|
154
|
+
dispatchFieldEvents(ref);
|
|
110
155
|
}
|
|
111
156
|
|
|
112
157
|
// Force rebuild of tabspot handling tree
|
|
113
158
|
$effect(() => {
|
|
114
|
-
if (!
|
|
159
|
+
if (!wrapperRef) return;
|
|
115
160
|
|
|
116
161
|
if (!open) {
|
|
117
|
-
|
|
162
|
+
// The list stays in the page once closed: nothing in it reads as chosen.
|
|
163
|
+
clearTabspotActive(wrapperRef);
|
|
164
|
+
unsetTabspotSection(wrapperRef, 'root');
|
|
118
165
|
return;
|
|
119
166
|
}
|
|
120
167
|
|
|
@@ -127,7 +174,7 @@
|
|
|
127
174
|
axis: 'vertical',
|
|
128
175
|
items: '.fs-list-view-item',
|
|
129
176
|
activation: {
|
|
130
|
-
controller: `#${
|
|
177
|
+
controller: `#${CSS.escape(BUTTON_ID)}`,
|
|
131
178
|
mode: 'activedescendant',
|
|
132
179
|
mark: {
|
|
133
180
|
attribute: 'data-active'
|
|
@@ -135,83 +182,119 @@
|
|
|
135
182
|
}
|
|
136
183
|
}
|
|
137
184
|
},
|
|
138
|
-
element:
|
|
185
|
+
element: wrapperRef,
|
|
139
186
|
merge: true
|
|
140
187
|
});
|
|
141
188
|
});
|
|
142
189
|
</script>
|
|
143
190
|
|
|
144
|
-
<div
|
|
191
|
+
<div
|
|
192
|
+
{...wrapperAttributes}
|
|
193
|
+
class={['fs-dropdown', `square-${roundClass}`, { open, disabled }, wrapperAttributes?.class]}
|
|
194
|
+
bind:this={wrapperRef}
|
|
195
|
+
>
|
|
196
|
+
<!-- Hidden while closed, not gone: each option reports its text as it is created, and comes before
|
|
197
|
+
the button, so the button shows it before the list ever opens, on the server too. -->
|
|
198
|
+
<Flyout
|
|
199
|
+
{...flyoutProps}
|
|
200
|
+
hidden={!open}
|
|
201
|
+
style="{flyoutProps?.style ?? ''}; {flyoutMaxHeight ? `max-height: ${flyoutMaxHeight};` : ''}"
|
|
202
|
+
offset={0}
|
|
203
|
+
bind:ref={flyoutRef}
|
|
204
|
+
floating
|
|
205
|
+
roundCorners="bottom"
|
|
206
|
+
reference={wrapperRef ?? undefined}
|
|
207
|
+
id={`${id}-flyout`}
|
|
208
|
+
onPlacementChange={(place) => {
|
|
209
|
+
handlePlacementChange(place);
|
|
210
|
+
flyoutProps?.onPlacementChange?.(place);
|
|
211
|
+
}}
|
|
212
|
+
placementConfig={{ allowedPlacements: ['bottom', 'top'] }}
|
|
213
|
+
class="fs-dropdown-flyout {roundClass === 'top' ? 'top-shadow' : ''} {flyoutProps?.class}"
|
|
214
|
+
>
|
|
215
|
+
<ListView
|
|
216
|
+
{...listboxProps}
|
|
217
|
+
bind:ref={listboxRef}
|
|
218
|
+
bind:selectedItems={() => selectedValues, select}
|
|
219
|
+
selectionMode={multiple ? 'multiselect' : 'single'}
|
|
220
|
+
toggleOnClick={multiple}
|
|
221
|
+
onSelectionChange={(event, selected) => {
|
|
222
|
+
if (!multiple) closeDropdown();
|
|
223
|
+
listboxProps?.onSelectionChange?.(event, selected);
|
|
224
|
+
}}
|
|
225
|
+
navigationMode="items"
|
|
226
|
+
id={`${id}-listbox`}
|
|
227
|
+
role="listbox"
|
|
228
|
+
disableTabspot
|
|
229
|
+
>
|
|
230
|
+
{#if !children}
|
|
231
|
+
<ListViewItem disabled>No options available</ListViewItem>
|
|
232
|
+
{:else}
|
|
233
|
+
{@render children?.()}
|
|
234
|
+
{/if}
|
|
235
|
+
</ListView>
|
|
236
|
+
</Flyout>
|
|
145
237
|
<ChevronDownFilled class="indicator" />
|
|
146
238
|
<button
|
|
239
|
+
{...buttonAttributes}
|
|
240
|
+
{...native.aria(attributes, buttonAttributes)}
|
|
147
241
|
bind:this={buttonRef}
|
|
148
242
|
type="button"
|
|
149
243
|
role="combobox"
|
|
150
|
-
onclick={handleClick}
|
|
151
|
-
onkeydown={handleKeyDown}
|
|
152
|
-
|
|
244
|
+
onclick={(e) => invokeHandlers(e, [disabled], [handleClick, buttonAttributes?.onclick])}
|
|
245
|
+
onkeydown={(e) => invokeHandlers(e, [disabled], [handleKeyDown, buttonAttributes?.onkeydown])}
|
|
246
|
+
onfocus={(e) => invokeHandlers(e, [], [onfocus, buttonAttributes?.onfocus])}
|
|
247
|
+
onblur={(e) => invokeHandlers(e, [], [onblur, buttonAttributes?.onblur])}
|
|
248
|
+
aria-controls={open ? `${id}-listbox` : undefined}
|
|
153
249
|
aria-expanded={open}
|
|
154
|
-
id={
|
|
250
|
+
id={BUTTON_ID}
|
|
155
251
|
aria-haspopup="listbox"
|
|
156
252
|
{disabled}
|
|
157
|
-
class={['fs-dropdown-button', hasValue && 'has-value']}
|
|
158
|
-
{...buttonProps}
|
|
253
|
+
class={['fs-dropdown-button', hasValue && 'has-value', buttonAttributes?.class]}
|
|
159
254
|
>
|
|
160
255
|
{displayLabel}
|
|
161
256
|
</button>
|
|
162
257
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
258
|
+
<!-- The field of the form: submitted, validated and reset like any select input,
|
|
259
|
+
behind the button and out of the tab order, since the button is what people use. See `NativeField`. -->
|
|
260
|
+
<!-- Svelte needs a static `multiple` to bind a select, hence the two branches. This is the native form -->
|
|
261
|
+
{#if multiple}
|
|
262
|
+
<select
|
|
263
|
+
{...attributes}
|
|
264
|
+
class="native-field"
|
|
265
|
+
aria-hidden={native.reported ? undefined : 'true'}
|
|
266
|
+
multiple
|
|
267
|
+
tabindex={-1}
|
|
268
|
+
{id}
|
|
269
|
+
{name}
|
|
270
|
+
{disabled}
|
|
271
|
+
bind:value
|
|
272
|
+
bind:this={ref}
|
|
273
|
+
onclick={openFromField}
|
|
178
274
|
>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
navigationMode="items"
|
|
203
|
-
id={`${id}-listbox`}
|
|
204
|
-
role="listbox"
|
|
205
|
-
disableTabspot
|
|
206
|
-
{...listboxProps}
|
|
207
|
-
>
|
|
208
|
-
{#if !children}
|
|
209
|
-
<ListViewItem disabled>No options available</ListViewItem>
|
|
210
|
-
{:else}
|
|
211
|
-
{@render children?.()}
|
|
212
|
-
{/if}
|
|
213
|
-
</ListView>
|
|
214
|
-
</Flyout>
|
|
275
|
+
{#each selectedValues as option (option)}
|
|
276
|
+
<option value={option}>{optionLabels.get(option) ?? option}</option>
|
|
277
|
+
{/each}
|
|
278
|
+
</select>
|
|
279
|
+
{:else}
|
|
280
|
+
<select
|
|
281
|
+
{...attributes}
|
|
282
|
+
class="native-field"
|
|
283
|
+
aria-hidden={native.reported ? undefined : 'true'}
|
|
284
|
+
tabindex={-1}
|
|
285
|
+
{id}
|
|
286
|
+
{name}
|
|
287
|
+
{disabled}
|
|
288
|
+
bind:value
|
|
289
|
+
bind:this={ref}
|
|
290
|
+
onclick={openFromField}
|
|
291
|
+
>
|
|
292
|
+
<!-- The placeholder makes an empty value missing for `required`, and is what a reset returns to. -->
|
|
293
|
+
<option value="" hidden></option>
|
|
294
|
+
{#if hasValue}
|
|
295
|
+
<option {value}>{displayLabel}</option>
|
|
296
|
+
{/if}
|
|
297
|
+
</select>
|
|
215
298
|
{/if}
|
|
216
299
|
</div>
|
|
217
300
|
|
|
@@ -300,6 +383,21 @@
|
|
|
300
383
|
left: -0.063rem;
|
|
301
384
|
background-color: var(--fs-accent-fill-default);
|
|
302
385
|
}
|
|
386
|
+
&:has(> .native-field:is(:user-invalid, [aria-invalid='true'])):after {
|
|
387
|
+
width: calc(100% + 0.125rem);
|
|
388
|
+
left: -0.063rem;
|
|
389
|
+
background-color: var(--fs-system-critical);
|
|
390
|
+
}
|
|
391
|
+
& .native-field {
|
|
392
|
+
position: absolute;
|
|
393
|
+
inset: 0;
|
|
394
|
+
inline-size: 100%;
|
|
395
|
+
block-size: 100%;
|
|
396
|
+
margin: 0;
|
|
397
|
+
box-sizing: border-box;
|
|
398
|
+
opacity: 0;
|
|
399
|
+
pointer-events: none;
|
|
400
|
+
}
|
|
303
401
|
& :global(> .indicator) {
|
|
304
402
|
width: 1rem;
|
|
305
403
|
position: absolute;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { DropdownProps } from './types.ts';
|
|
2
|
-
declare const Dropdown: import("svelte").Component<DropdownProps, {}, "ref" | "value" | "flyoutRef" | "buttonRef" | "listboxRef">;
|
|
2
|
+
declare const Dropdown: import("svelte").Component<DropdownProps, {}, "ref" | "value" | "wrapperRef" | "flyoutRef" | "buttonRef" | "listboxRef">;
|
|
3
3
|
type Dropdown = ReturnType<typeof Dropdown>;
|
|
4
4
|
export default Dropdown;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes, HTMLButtonAttributes, HTMLSelectAttributes } from 'svelte/elements';
|
|
2
3
|
import type { ListViewProps, ListViewItemProps } from '../list-view/types.ts';
|
|
3
4
|
import type { FlyoutProps } from '../flyout/types.ts';
|
|
4
|
-
import type { FSContext } from '../../internal/index.js';
|
|
5
|
+
import type { FSContext, NativeFieldAttributes } from '../../internal/index.js';
|
|
5
6
|
/** The value shape of a dropdown that allows more than one selection. */
|
|
6
7
|
export type DropdownMultipleValue = {
|
|
7
8
|
multiple: true;
|
|
@@ -28,34 +29,32 @@ export type DropdownProps = {
|
|
|
28
29
|
placeholder?: string;
|
|
29
30
|
/** Disables the user interaction. */
|
|
30
31
|
disabled?: boolean;
|
|
31
|
-
/** The name submitted
|
|
32
|
-
* @default id
|
|
33
|
-
*/
|
|
32
|
+
/** The name the value is submitted under. Without one, the form leaves the value out, as with any field. */
|
|
34
33
|
name?: string | null;
|
|
35
|
-
/** The DOM reference of the
|
|
34
|
+
/** The DOM reference of the wrapper element.
|
|
36
35
|
* @bindable
|
|
37
36
|
*/
|
|
38
|
-
|
|
39
|
-
/** Called when the dropdown is clicked. */
|
|
40
|
-
onclick?: (e: MouseEvent) => void;
|
|
37
|
+
wrapperRef?: HTMLDivElement | null;
|
|
41
38
|
/** The attributes to spread on the wrapper element.
|
|
42
39
|
* @type HTMLAttributes
|
|
43
40
|
*/
|
|
44
|
-
|
|
41
|
+
wrapperAttributes?: HTMLAttributes<HTMLDivElement>;
|
|
42
|
+
/** The DOM reference of the native select that holds the value. The other attributes of the dropdown are applied to it.
|
|
43
|
+
* @bindable
|
|
44
|
+
*/
|
|
45
|
+
ref?: HTMLSelectElement | null;
|
|
45
46
|
/** The DOM reference of the button that opens the dropdown.
|
|
46
47
|
* @bindable
|
|
47
48
|
*/
|
|
48
|
-
buttonRef?: HTMLButtonElement;
|
|
49
|
+
buttonRef?: HTMLButtonElement | null;
|
|
49
50
|
/** The attributes to spread on the button that opens the dropdown.
|
|
50
51
|
* @type HTMLButtonAttributes
|
|
51
52
|
*/
|
|
52
|
-
|
|
53
|
-
/** The DOM reference of the hidden input holding the value. */
|
|
54
|
-
inputRef?: HTMLInputElement;
|
|
53
|
+
buttonAttributes?: Omit<HTMLButtonAttributes, 'type' | 'role' | 'value'>;
|
|
55
54
|
/** The DOM reference of the flyout element.
|
|
56
55
|
* @bindable
|
|
57
56
|
*/
|
|
58
|
-
flyoutRef?: HTMLDivElement;
|
|
57
|
+
flyoutRef?: HTMLDivElement | null;
|
|
59
58
|
/** The props to spread on the flyout.
|
|
60
59
|
* @type FlyoutProps
|
|
61
60
|
*/
|
|
@@ -65,18 +64,25 @@ export type DropdownProps = {
|
|
|
65
64
|
/** The DOM reference of the listbox element.
|
|
66
65
|
* @bindable
|
|
67
66
|
*/
|
|
68
|
-
listboxRef?: HTMLUListElement;
|
|
67
|
+
listboxRef?: HTMLUListElement | null;
|
|
69
68
|
/** The props to spread on the listbox rendered inside the flyout.
|
|
70
69
|
* @type ListViewProps
|
|
71
70
|
*/
|
|
72
71
|
listboxProps?: Omit<ListViewProps<'ul'>, 'ref' | 'children' | 'selectedItems' | 'selectionMode'>;
|
|
73
|
-
|
|
72
|
+
/** The `DropdownOption` elements of the list. */
|
|
73
|
+
children?: Snippet;
|
|
74
|
+
} & (DropdownMultipleValue | DropdownSingleValue) & NativeFieldAttributes<HTMLSelectAttributes>;
|
|
74
75
|
/** @propsmith DropdownOptionProps */
|
|
75
76
|
export type DropdownOptionProps = {
|
|
76
|
-
/** The text shown by the dropdown once the option is selected. Falls back to the rendered children. */
|
|
77
|
+
/** The text shown by the dropdown once the option is selected. Falls back to the rendered children, which the server cannot read: pass it when rendering on the server. */
|
|
77
78
|
text?: string;
|
|
78
79
|
} & ListViewItemProps<'li'>;
|
|
80
|
+
/** What an option tells the trigger, read live. */
|
|
81
|
+
export type DropdownOptionLabel = {
|
|
82
|
+
readonly value?: string;
|
|
83
|
+
readonly text?: string;
|
|
84
|
+
};
|
|
79
85
|
export type DropdownContext = FSContext<null, null, null, {
|
|
80
|
-
/** Options report their display text so the trigger can show a label instead of the raw value. */
|
|
81
|
-
registerOption: (
|
|
86
|
+
/** Options report their display text so the trigger can show a label instead of the raw value. Returns the call that withdraws the option. */
|
|
87
|
+
registerOption: (option: DropdownOptionLabel) => () => void;
|
|
82
88
|
}>;
|
|
@@ -11,7 +11,7 @@ The Dropdown Select is a dropdown built on the native `<select>` element. It let
|
|
|
11
11
|
import { DropdownSelect, DropdownSelectOption } from 'fluentui-svelte';
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
|
-
<DropdownSelect>
|
|
14
|
+
<DropdownSelect aria-label="Choose an option">
|
|
15
15
|
<DropdownSelectOption value="A">Option A</DropdownSelectOption>
|
|
16
16
|
<DropdownSelectOption value="B">Option B</DropdownSelectOption>
|
|
17
17
|
<DropdownSelectOption value="C">Option C</DropdownSelectOption>
|
|
@@ -25,13 +25,13 @@ The Dropdown Select is a dropdown built on the native `<select>` element. It let
|
|
|
25
25
|
Options can render rich content such as a `Persona`. Provide a `text` prop for the plain-text selection label.
|
|
26
26
|
|
|
27
27
|
```svelte
|
|
28
|
-
<DropdownSelect>
|
|
28
|
+
<DropdownSelect aria-label="Choose an option">
|
|
29
29
|
<DropdownSelectOption value="John Doe" text="John Doe">
|
|
30
30
|
<Persona
|
|
31
31
|
name="John Doe"
|
|
32
32
|
primaryText="Software Engineer"
|
|
33
33
|
presence={{ status: 'available' }}
|
|
34
|
-
|
|
34
|
+
avatarProps={{ color: 'colorful', idForColor: '' }}
|
|
35
35
|
/>
|
|
36
36
|
</DropdownSelectOption>
|
|
37
37
|
<DropdownSelectOption value="B">Option B</DropdownSelectOption>
|
|
@@ -44,28 +44,30 @@ Options can render rich content such as a `Persona`. Provide a `text` prop for t
|
|
|
44
44
|
Set the `multiple` prop to allow selecting more than one option.
|
|
45
45
|
|
|
46
46
|
```svelte
|
|
47
|
-
<DropdownSelect multiple>
|
|
47
|
+
<DropdownSelect multiple aria-label="Choose options">
|
|
48
48
|
<DropdownSelectOption value="A">Option A</DropdownSelectOption>
|
|
49
49
|
<DropdownSelectOption value="B">Option B</DropdownSelectOption>
|
|
50
50
|
<DropdownSelectOption value="C">Option C</DropdownSelectOption>
|
|
51
51
|
</DropdownSelect>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
HTML attributes, including class, id and ARIA attributes, apply to the control element. Bind ref to access that control. Use wrapperAttributes and wrapperRef for the outer container.
|
|
55
|
+
|
|
54
56
|
## Component Props
|
|
55
57
|
|
|
56
58
|
<!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
|
|
57
59
|
<!-- props:DropdownSelectProps -->
|
|
58
60
|
|
|
59
|
-
| Name | Type
|
|
60
|
-
| ----------------------------- |
|
|
61
|
-
| `value` _bindable_ | `string` | `string[]`
|
|
62
|
-
| `multiple` | `boolean`
|
|
63
|
-
| `placeholder` | `string`
|
|
64
|
-
| `hidePlaceholder` | `boolean`
|
|
65
|
-
| `ref` _bindable_ | `HTMLSelectElement`
|
|
66
|
-
| `wrapperRef` _bindable_ | `HTMLDivElement`
|
|
67
|
-
| `
|
|
68
|
-
| Element Attributes (`select`) |
|
|
61
|
+
| Name | Type | Default | Description |
|
|
62
|
+
| ----------------------------- | --------------------------------- | -------------------------- | ---------------------------------------------------------------------- |
|
|
63
|
+
| `value` _bindable_ | `string` | `string[]` | `multiple ? [] : ''` | The selected value. An array of values when `multiple` is set. |
|
|
64
|
+
| `multiple` | `boolean` | | Allows more than one option to be selected at a time. |
|
|
65
|
+
| `placeholder` | `string` | `'Native Select Dropdown'` | The text shown while no option is selected. |
|
|
66
|
+
| `hidePlaceholder` | `boolean` | | Keeps the placeholder out of the option list once a value is selected. |
|
|
67
|
+
| `ref` _bindable_ | `HTMLSelectElement` | `null` | | The DOM reference of the select element. |
|
|
68
|
+
| `wrapperRef` _bindable_ | `HTMLDivElement` | `null` | | The DOM reference of the wrapper element. |
|
|
69
|
+
| `wrapperAttributes` | `HTMLAttributes` | | The attributes to spread on the wrapper element. |
|
|
70
|
+
| Element Attributes (`select`) | | | |
|
|
69
71
|
|
|
70
72
|
<!-- /props:DropdownSelectProps -->
|
|
71
73
|
|
|
@@ -74,13 +76,13 @@ Set the `multiple` prop to allow selecting more than one option.
|
|
|
74
76
|
<!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
|
|
75
77
|
<!-- props:DropdownSelectOptionProps -->
|
|
76
78
|
|
|
77
|
-
| Name | Type
|
|
78
|
-
| ----------------------------- |
|
|
79
|
-
| `value` | `string`
|
|
80
|
-
| `text` | `string`
|
|
81
|
-
| `disabled` | `boolean`
|
|
82
|
-
| `ref` _bindable_ | `HTMLElement` | | The DOM reference of the option element. |
|
|
83
|
-
| `children` | `Snippet`
|
|
84
|
-
| Element Attributes (`option`) |
|
|
79
|
+
| Name | Type | Default | Description |
|
|
80
|
+
| ----------------------------- | --------------------------- | ------- | ------------------------------------------------------------- |
|
|
81
|
+
| `value` | `string` | | The value reported to the select when the option is picked. |
|
|
82
|
+
| `text` | `string` | | The label of the option. Falls back to the rendered children. |
|
|
83
|
+
| `disabled` | `boolean` | | Disables the user interaction. |
|
|
84
|
+
| `ref` _bindable_ | `HTMLElement` | `null` | | The DOM reference of the option element. |
|
|
85
|
+
| `children` | `Snippet` | | The content of the option, used when no `text` is given. |
|
|
86
|
+
| Element Attributes (`option`) | | | |
|
|
85
87
|
|
|
86
88
|
<!-- /props:DropdownSelectOptionProps -->
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
value,
|
|
7
7
|
text,
|
|
8
8
|
disabled,
|
|
9
|
-
ref = $bindable(),
|
|
9
|
+
ref = $bindable(null),
|
|
10
10
|
class: classes,
|
|
11
11
|
children,
|
|
12
12
|
...attributes
|
|
13
13
|
}: DropdownSelectOptionProps = $props();
|
|
14
14
|
</script>
|
|
15
15
|
|
|
16
|
-
<option class="fs-dropdown-select-option {classes}" {value} {disabled} bind:this={ref}
|
|
16
|
+
<option {...attributes} class="fs-dropdown-select-option {classes}" {value} {disabled} bind:this={ref}>
|
|
17
17
|
<span class="option-content">
|
|
18
18
|
<CheckmarkFilled class="checkmark" width="16" height="16" />
|
|
19
19
|
{#if text}
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { claimLabel } from '../label/label-context.js';
|
|
3
|
+
import { flushSync } from 'svelte';
|
|
2
4
|
import ChevronDownFilled from 'fluentui-icons-svelte/ChevronDownFilled.svelte';
|
|
3
5
|
import { selectDirection } from './dropdown-select.svelte.js';
|
|
4
6
|
import type { DropdownSelectProps } from './types.js';
|
|
5
7
|
|
|
8
|
+
const labelContext = claimLabel(() => id);
|
|
9
|
+
|
|
6
10
|
let {
|
|
7
11
|
hidePlaceholder,
|
|
8
12
|
placeholder = 'Native Select Dropdown',
|
|
9
|
-
ref = $bindable(),
|
|
13
|
+
ref = $bindable(null),
|
|
10
14
|
children,
|
|
11
|
-
wrapperRef = $bindable(),
|
|
12
|
-
|
|
15
|
+
wrapperRef = $bindable(null),
|
|
16
|
+
wrapperAttributes,
|
|
13
17
|
multiple,
|
|
18
|
+
class: classes,
|
|
14
19
|
value = $bindable(multiple ? [] : ''),
|
|
20
|
+
id = labelContext?.fieldId,
|
|
21
|
+
name = id,
|
|
15
22
|
...attributes
|
|
16
23
|
}: DropdownSelectProps = $props();
|
|
17
24
|
</script>
|
|
18
25
|
|
|
19
|
-
<div class=
|
|
26
|
+
<div {...wrapperAttributes} class={['fs-dropdown', wrapperAttributes?.class]} bind:this={wrapperRef}>
|
|
20
27
|
{#if !multiple}
|
|
21
28
|
<ChevronDownFilled class="indicator" />
|
|
22
29
|
{/if}
|
|
@@ -25,17 +32,40 @@
|
|
|
25
32
|
We need to use a if block with the same structure
|
|
26
33
|
-->
|
|
27
34
|
{#if multiple}
|
|
28
|
-
<select
|
|
35
|
+
<select
|
|
36
|
+
{...attributes}
|
|
37
|
+
{id}
|
|
38
|
+
{name}
|
|
39
|
+
class={['fs-dropdown-select', classes]}
|
|
40
|
+
{@attach selectDirection()}
|
|
41
|
+
multiple
|
|
42
|
+
bind:value
|
|
43
|
+
bind:this={ref}
|
|
44
|
+
>
|
|
29
45
|
<button>
|
|
30
46
|
<selectedcontent></selectedcontent>
|
|
31
47
|
</button>
|
|
32
48
|
{#if !hidePlaceholder}
|
|
33
|
-
<option class="fs-dropdown-placeholder" disabled selected hidden value="">{placeholder}</option
|
|
49
|
+
<option class="fs-dropdown-placeholder" disabled selected={!value?.length} hidden value="">{placeholder}</option
|
|
50
|
+
>
|
|
34
51
|
{/if}
|
|
35
52
|
{@render children?.()}
|
|
36
53
|
</select>
|
|
37
54
|
{:else}
|
|
38
|
-
<select
|
|
55
|
+
<select
|
|
56
|
+
{...attributes}
|
|
57
|
+
{id}
|
|
58
|
+
{name}
|
|
59
|
+
class={['fs-dropdown-select', classes]}
|
|
60
|
+
{@attach selectDirection()}
|
|
61
|
+
bind:value
|
|
62
|
+
bind:this={ref}
|
|
63
|
+
oninputcapture={(event) => {
|
|
64
|
+
// selectedcontent mutates before change; sync the binding before its observer restores the old value.
|
|
65
|
+
flushSync(() => (value = event.currentTarget.value));
|
|
66
|
+
attributes.oninputcapture?.(event);
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
39
69
|
<button>
|
|
40
70
|
<selectedcontent></selectedcontent>
|
|
41
71
|
</button>
|
|
@@ -94,6 +124,11 @@
|
|
|
94
124
|
left: 0;
|
|
95
125
|
background-color: var(--fs-accent-fill-default);
|
|
96
126
|
}
|
|
127
|
+
&:has(select:is(:user-invalid, [aria-invalid='true'])):after {
|
|
128
|
+
width: calc(100%);
|
|
129
|
+
left: 0;
|
|
130
|
+
background-color: var(--fs-system-critical);
|
|
131
|
+
}
|
|
97
132
|
& .fs-dropdown-select {
|
|
98
133
|
border-radius: 0;
|
|
99
134
|
background: unset;
|