fluentui-svelte 0.4.0 → 0.6.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 (59) hide show
  1. package/README.md +1 -1
  2. package/dist/components/auto-suggest-box/docs/llms.md +76 -15
  3. package/dist/components/card/card-header.svelte +2 -2
  4. package/dist/components/dialog/dialog-actions.svelte +17 -2
  5. package/dist/components/dialog/dialog-content.svelte +2 -2
  6. package/dist/components/dialog/dialog-content.svelte.d.ts +1 -1
  7. package/dist/components/dialog/dialog-surface.svelte +32 -3
  8. package/dist/components/dialog/dialog-title.svelte +23 -6
  9. package/dist/components/dialog/dialog-trigger.svelte +8 -2
  10. package/dist/components/dialog/dialog-trigger.svelte.d.ts +1 -1
  11. package/dist/components/dialog/docs/llms.md +2 -2
  12. package/dist/components/dialog/types.d.ts +6 -2
  13. package/dist/components/dialog/utils.d.ts +2 -0
  14. package/dist/components/dialog/utils.js +1 -0
  15. package/dist/components/dropdown/dropdown.svelte +1 -0
  16. package/dist/components/list-view/docs/llms.md +79 -27
  17. package/dist/components/list-view/list-view-item.svelte +14 -11
  18. package/dist/components/list-view/list-view.svelte +3 -2
  19. package/dist/components/list-view/types.d.ts +5 -1
  20. package/dist/components/menu/docs/llms.md +16 -0
  21. package/dist/components/menu/menu-popover.svelte +7 -12
  22. package/dist/components/menu/menu-popover.svelte.d.ts +2 -10
  23. package/dist/components/menu/types.d.ts +21 -0
  24. package/dist/components/rating/docs/llms.md +110 -0
  25. package/dist/components/rating/rating.svelte +210 -0
  26. package/dist/components/rating/rating.svelte.d.ts +19 -0
  27. package/dist/components/rating/types.d.ts +44 -0
  28. package/dist/components/rating/types.js +1 -0
  29. package/dist/components/tag/docs/llms.md +383 -0
  30. package/dist/components/tag/tag-group.d.ts +2 -0
  31. package/dist/components/tag/tag-group.js +2 -0
  32. package/dist/components/tag/tag-group.svelte +117 -0
  33. package/dist/components/tag/tag-group.svelte.d.ts +20 -0
  34. package/dist/components/tag/tag.svelte +458 -0
  35. package/dist/components/tag/tag.svelte.d.ts +19 -0
  36. package/dist/components/tag/types.d.ts +135 -0
  37. package/dist/components/tag/types.js +1 -0
  38. package/dist/components/tag-picker/docs/llms.md +292 -0
  39. package/dist/components/tag-picker/option-group.svelte +38 -0
  40. package/dist/components/tag-picker/option-group.svelte.d.ts +4 -0
  41. package/dist/components/tag-picker/option.svelte +71 -0
  42. package/dist/components/tag-picker/option.svelte.d.ts +4 -0
  43. package/dist/components/tag-picker/tag-picker.d.ts +2 -0
  44. package/dist/components/tag-picker/tag-picker.js +2 -0
  45. package/dist/components/tag-picker/tag-picker.svelte +644 -0
  46. package/dist/components/tag-picker/tag-picker.svelte.d.ts +21 -0
  47. package/dist/components/tag-picker/types.d.ts +122 -0
  48. package/dist/components/tag-picker/types.js +1 -0
  49. package/dist/components/tree-view/docs/llms.md +166 -1
  50. package/dist/components/tree-view/tree-view-item-content.svelte +41 -8
  51. package/dist/components/tree-view/tree-view-item.svelte +10 -1
  52. package/dist/components/tree-view/tree-view.svelte +17 -2
  53. package/dist/components/tree-view/tree-view.svelte.js +4 -2
  54. package/dist/components/tree-view/types.d.ts +4 -0
  55. package/dist/index.d.ts +7 -0
  56. package/dist/index.js +12 -0
  57. package/dist/internal/constants.d.ts +0 -4
  58. package/dist/internal/constants.js +0 -4002
  59. package/package.json +3 -2
@@ -0,0 +1,292 @@
1
+ # TagPicker
2
+
3
+ A TagPicker combines a text field and a dropdown, giving people a way to choose several options from a list or to enter their own choice. Every choice becomes a dismissible `Tag` shown in the control. It is made of `TagPicker`, `TagPickerOption` and `TagPickerOptionGroup`.
4
+
5
+ ## Usage
6
+
7
+ ```svelte
8
+ <script>
9
+ import { TagPicker, TagPickerOption } from 'fluentui-svelte';
10
+
11
+ const options = ['John Doe', 'Jane Doe', 'Max Mustermann'];
12
+
13
+ let selectedOptions = $state([]);
14
+ </script>
15
+
16
+ <TagPicker
17
+ bind:selectedOptions
18
+ inputProps={{ 'aria-label': 'Select Employees' }}
19
+ tagGroupProps={{ 'aria-label': 'Selected Employees' }}
20
+ >
21
+ {#each options as option (option)}
22
+ <TagPickerOption value={option}>{option}</TagPickerOption>
23
+ {/each}
24
+ </TagPicker>
25
+ ```
26
+
27
+ ## TagPicker API
28
+
29
+ - `selectedOptions` holds the values of the chosen options. It is bindable, and every value shows as a tag.
30
+ - Selecting an option adds a tag and clears the text. The option is not offered again until its tag is removed.
31
+ - The options are filtered by what is typed in the input: a case-insensitive substring of the `text` of the option (its `value` when there is no `text`). The first match is highlighted.
32
+ - A multiple picker keeps the list open after each choice. With `single` a new choice replaces the tag and closes the list.
33
+ - Give the input an accessible name with `inputProps={{ 'aria-label': '...' }}`, and the group of tags one with `tagGroupProps`.
34
+ - Pressing Backspace in an empty input removes the last tag. Tell your users about it.
35
+ - A tag shows the `text` of its option, and keeps it once the option leaves the screen. This holds for a tag preselected through `selectedOptions` too, as long as the options are children of the TagPicker. A value that no option has is shown as it is, and so is every value during server-side rendering. To control what a tag says, render the tags yourself with the `tag` snippet.
36
+ - Do not use an interactive `Tag` inside a TagPicker.
37
+ - Keys: ArrowDown and ArrowUp open the list and move through the options, Enter chooses the option under the cursor, Escape and Tab close the list, Home and End move the caret of the input.
38
+
39
+ ## Examples
40
+
41
+ ### Default
42
+
43
+ The `tag` snippet renders the tag of a chosen option, here with an `Avatar` as its media. Render a `Tag` with the given `value` and `role="listitem"`.
44
+
45
+ ```svelte
46
+ <script>
47
+ let selectedOptions = $state([]);
48
+ </script>
49
+
50
+ {#snippet tag({ value, text })}
51
+ {#snippet media()}
52
+ <Avatar aria-hidden="true" name={text} size={16} color="colorful" />
53
+ {/snippet}
54
+ <Tag role="listitem" {value} {media} title={text}>{text}</Tag>
55
+ {/snippet}
56
+
57
+ <TagPicker
58
+ bind:selectedOptions
59
+ {tag}
60
+ inputProps={{ 'aria-label': 'Select Employees' }}
61
+ tagGroupProps={{ 'aria-label': 'Selected Employees' }}
62
+ >
63
+ {#each options as option (option)}
64
+ <TagPickerOption value={option}>
65
+ <Avatar aria-hidden="true" shape="square" name={option} size={20} color="colorful" />
66
+ {option}
67
+ </TagPickerOption>
68
+ {/each}
69
+ </TagPicker>
70
+ ```
71
+
72
+ ### Button
73
+
74
+ Make the input read only with `inputProps={{ readonly: true }}` to use the TagPicker as a button that opens the list.
75
+
76
+ ```svelte
77
+ <TagPicker
78
+ bind:selectedOptions
79
+ placeholder="Select employees"
80
+ inputProps={{ 'aria-label': 'Select Employees', readonly: true }}
81
+ >
82
+ {#each options as option (option)}
83
+ <TagPickerOption value={option}>{option}</TagPickerOption>
84
+ {/each}
85
+ </TagPicker>
86
+ ```
87
+
88
+ ### Disabled
89
+
90
+ A disabled TagPicker cannot be opened, typed in or changed, and its tags cannot be dismissed.
91
+
92
+ ```svelte
93
+ <TagPicker disabled selectedOptions={[options[0]]} inputProps={{ 'aria-label': 'Select Employees' }}>
94
+ {#each options as option (option)}
95
+ <TagPickerOption value={option}>{option}</TagPickerOption>
96
+ {/each}
97
+ </TagPicker>
98
+ ```
99
+
100
+ ### Expand icon
101
+
102
+ Replace the dropdown arrow with `expandIcon`, a component or a snippet, or remove it by passing `null`.
103
+
104
+ ```svelte
105
+ <script>
106
+ import { ArrowDownFilled } from 'fluentui-icons-svelte';
107
+ </script>
108
+
109
+ <!-- A custom icon -->
110
+ <TagPicker bind:selectedOptions expandIcon={ArrowDownFilled} inputProps={{ 'aria-label': 'Select Employees' }}>
111
+ ...
112
+ </TagPicker>
113
+
114
+ <!-- No icon -->
115
+ <TagPicker bind:selectedOptions expandIcon={null} inputProps={{ 'aria-label': 'Select Employees' }}>...</TagPicker>
116
+ ```
117
+
118
+ ### Filtering
119
+
120
+ The options are filtered as the user types, and the first match is highlighted so that Enter chooses it. `notFoundText` is shown when no option is left.
121
+
122
+ ```svelte
123
+ <TagPicker
124
+ bind:selectedOptions
125
+ notFoundText="We couldn't find any matches"
126
+ inputProps={{ 'aria-label': 'Select Employees' }}
127
+ >
128
+ {#each options as option (option)}
129
+ <TagPickerOption value={option}>{option}</TagPickerOption>
130
+ {/each}
131
+ </TagPicker>
132
+ ```
133
+
134
+ ### Grouped
135
+
136
+ Group options with `TagPickerOptionGroup`. A group with no option left on screen hides itself.
137
+
138
+ ```svelte
139
+ <TagPicker bind:selectedOptions inputProps={{ 'aria-label': 'Select Employees' }}>
140
+ <TagPickerOptionGroup label="Managers">
141
+ {#each managers as option (option)}
142
+ <TagPickerOption value={option}>{option}</TagPickerOption>
143
+ {/each}
144
+ </TagPickerOptionGroup>
145
+ <TagPickerOptionGroup label="Developers">
146
+ {#each devs as option (option)}
147
+ <TagPickerOption value={option}>{option}</TagPickerOption>
148
+ {/each}
149
+ </TagPickerOptionGroup>
150
+ </TagPicker>
151
+ ```
152
+
153
+ ### No popover
154
+
155
+ Leave out the options to get a TagPicker without a list, to let users enter their own tags. Bind `value` and add the tag in `querySubmitted`, called when Enter is pressed with text in the input.
156
+
157
+ ```svelte
158
+ <script>
159
+ let selectedOptions = $state([]);
160
+ let value = $state('');
161
+ </script>
162
+
163
+ <TagPicker
164
+ bind:selectedOptions
165
+ bind:value
166
+ placeholder="Type and press Enter"
167
+ inputProps={{ 'aria-label': 'Add Employees' }}
168
+ querySubmitted={(e, query) => {
169
+ if (!selectedOptions.includes(query)) selectedOptions = [...selectedOptions, query];
170
+ value = '';
171
+ }}
172
+ />
173
+ ```
174
+
175
+ ### Secondary action
176
+
177
+ Add a button next to the dropdown arrow with the `secondaryAction` snippet.
178
+
179
+ ```svelte
180
+ {#snippet allClear()}
181
+ <Button appearance="subtle" onclick={() => (selectedOptions = [])}>All Clear</Button>
182
+ {/snippet}
183
+
184
+ <TagPicker bind:selectedOptions secondaryAction={allClear} inputProps={{ 'aria-label': 'Select Employees' }}>
185
+ {#each options as option (option)}
186
+ <TagPickerOption value={option}>{option}</TagPickerOption>
187
+ {/each}
188
+ </TagPicker>
189
+ ```
190
+
191
+ ### Single select
192
+
193
+ With `single` a new choice replaces the current tag and closes the list.
194
+
195
+ ```svelte
196
+ <TagPicker single bind:selectedOptions inputProps={{ 'aria-label': 'Select Employee' }}>
197
+ {#each options as option (option)}
198
+ <TagPickerOption value={option}>{option}</TagPickerOption>
199
+ {/each}
200
+ </TagPicker>
201
+ ```
202
+
203
+ ### Size
204
+
205
+ A TagPicker is `medium` by default, or `large` or `extra-large`. The size of the control also picks the size of its tags.
206
+
207
+ ```svelte
208
+ {#each ['medium', 'large', 'extra-large'] as size}
209
+ <TagPicker {size} selectedOptions={[options[0]]} inputProps={{ 'aria-label': size }}>
210
+ {#each options as option (option)}
211
+ <TagPickerOption value={option}>{option}</TagPickerOption>
212
+ {/each}
213
+ </TagPicker>
214
+ {/each}
215
+ ```
216
+
217
+ ### Truncated text
218
+
219
+ A tag that is wider than the control, or than its own `max-width`, shortens its text with an ellipsis. Give the tag a `title` so the full text stays reachable, and truncate the text of the options yourself.
220
+
221
+ ```svelte
222
+ {#snippet tag({ value, text })}
223
+ <Tag role="listitem" {value} title={text} style="max-width: 100px;">{text}</Tag>
224
+ {/snippet}
225
+
226
+ <TagPicker bind:selectedOptions {tag} inputProps={{ 'aria-label': 'Select Employees' }}>
227
+ {#each [...longOptions, ...options] as option (option)}
228
+ <TagPickerOption value={option}>
229
+ <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">{option}</span>
230
+ </TagPickerOption>
231
+ {/each}
232
+ </TagPicker>
233
+ ```
234
+
235
+ ## Component Props (TagPicker)
236
+
237
+ <!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
238
+ <!-- props:TagPickerProps -->
239
+
240
+ | Name | Type | Default | Description |
241
+ | --------------------------------------------------- | -------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
242
+ | `ref` _bindable_ | `HTMLDivElement` | | The DOM reference of the wrapper element. |
243
+ | `inputRef` _bindable_ | `HTMLInputElement` | | The DOM reference of the input element. |
244
+ | `selectedOptions` _bindable_ | `string[]` | `[]` | The values of the chosen options, shown as tags in the control. A value no option has is shown as it is. |
245
+ | `value` _bindable_ | `string` | `''` | The text typed in the input. It filters the options, and is cleared when one is chosen. |
246
+ | `open` _bindable_ | `boolean` | `false` | Controls the open state of the option list. |
247
+ | `single` | `boolean` | | Limits the picker to one tag: choosing an option replaces the current one and closes the list. |
248
+ | `disabled` | `boolean` | | Disables the user interaction: the input, the tags and the list. |
249
+ | `size` | `'medium'` &#124; `'large'` &#124; `'extra-large'` | `'medium'` | The size of the control. It also picks the size of the tags. |
250
+ | `placeholder` | `string` | | The placeholder text of the input. |
251
+ | `notFoundText` | `string` | `'No options available'` | The message shown in place of the list when there is no option left to choose. |
252
+ | `expandIcon` | `Snippet` &#124; `Component` &#124; `null` | `ChevronDownRegular` | The dropdown arrow. Pass `null` to remove it. |
253
+ | `secondaryAction` | `Snippet` | | A button-like element rendered at the end of the control, before the dropdown arrow. |
254
+ | `tag` | `Snippet<[{ value: string; text: string }]>` | | Renders the tag of a chosen option, to give it media or custom text. Falls back to a plain tag. Render a `Tag` with the given `value`, and `role="listitem"`. |
255
+ | `tagGroupProps` | `TagGroupProps` | | The props to spread on the group holding the tags. This is where its `aria-label` goes. |
256
+ | `inputProps` | `HTMLInputAttributes` | | The props to spread on the input. This is where its accessible name (`aria-label`) and `readonly` (to turn the input into a plain trigger) go. |
257
+ | `onSelectionChange` | `(e: Event, selectedOptions: string[]) => void` | | Called when an option is chosen, or a tag is removed. |
258
+ | `querySubmitted` | `(e: KeyboardEvent, query: string) => void` | | Called when Enter is pressed with text in the input and no option under the cursor. This is where a free-form tag is added. |
259
+ | `children` | `Snippet` | | The options. Leave it out to get a picker without a list. |
260
+ | `HTMLAttributes<HTMLDivElement>` without `children` | | | |
261
+
262
+ <!-- /props:TagPickerProps -->
263
+
264
+ ## Component Props (TagPickerOption)
265
+
266
+ <!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
267
+ <!-- props:TagPickerOptionProps -->
268
+
269
+ | Name | Type | Default | Description |
270
+ | ------------------------------------------------------------------------ | --------------- | ------- | -------------------------------------------------------------------------------------------------------------------- |
271
+ | `value` | `string` | | The value added to `selectedOptions` when the option is chosen. |
272
+ | `text` | `string` | | The text the option is filtered by, and the text of its tag. Falls back to `value`. |
273
+ | `id` | `string` | | The id of the option element, referenced by the input through `aria-activedescendant`. Falls back to a generated id. |
274
+ | `ref` _bindable_ | `HTMLLIElement` | | The DOM reference of the option element. |
275
+ | `disabled` | `boolean` | | Takes the option out of reach: it is shown, but the cursor steps over it. |
276
+ | `ListViewItemProps<'li'>` without `as`, `value`, `onAction`, `checkmark` | | | |
277
+
278
+ <!-- /props:TagPickerOptionProps -->
279
+
280
+ ## Component Props (TagPickerOptionGroup)
281
+
282
+ <!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
283
+ <!-- props:TagPickerOptionGroupProps -->
284
+
285
+ | Name | Type | Default | Description |
286
+ | ----------------------------------------------------- | ------------------ | ------- | --------------------------------------- |
287
+ | `label` | `string` | | The label of the group. |
288
+ | `ref` _bindable_ | `HTMLUListElement` | | The DOM reference of the group element. |
289
+ | `children` | `Snippet` | | The options of the group. |
290
+ | `HTMLAttributes<HTMLUListElement>` without `children` | | | |
291
+
292
+ <!-- /props:TagPickerOptionGroupProps -->
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import { PREFIX } from '../../internal/constants.js';
3
+ import type { TagPickerOptionGroupProps } from './types.js';
4
+
5
+ const FALLBACK_ID = $props.id();
6
+ const LABEL_ID = `${PREFIX}-tagpicker-group-${FALLBACK_ID}-label`;
7
+
8
+ let { label, ref = $bindable(), class: classes, children, ...attributes }: TagPickerOptionGroupProps = $props();
9
+ </script>
10
+
11
+ <li class="fs-tagpicker-group" role="presentation">
12
+ <span class="fs-tagpicker-group-label" id={LABEL_ID}>{label}</span>
13
+ <ul bind:this={ref} class={classes} role="group" aria-labelledby={LABEL_ID} {...attributes}>
14
+ {@render children?.()}
15
+ </ul>
16
+ </li>
17
+
18
+ <style>
19
+ .fs-tagpicker-group {
20
+ list-style: none;
21
+ /* A group left without an option on screen hides itself. */
22
+ &:not(:has(:global(.fs-tagpicker-option))) {
23
+ display: none;
24
+ }
25
+ }
26
+ .fs-tagpicker-group-label {
27
+ display: block;
28
+ padding: 0.375rem 0.713rem;
29
+ font-size: var(--fs-caption-font-size);
30
+ font-weight: 600;
31
+ color: var(--fs-text-secondary);
32
+ }
33
+ ul {
34
+ list-style: none;
35
+ margin: 0;
36
+ padding: 0;
37
+ }
38
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { TagPickerOptionGroupProps } from './types.ts';
2
+ declare const OptionGroup: import("svelte").Component<TagPickerOptionGroupProps, {}, "ref">;
3
+ type OptionGroup = ReturnType<typeof OptionGroup>;
4
+ export default OptionGroup;
@@ -0,0 +1,71 @@
1
+ <script lang="ts">
2
+ import { PREFIX } from '../../internal/constants.js';
3
+ import ListViewItem from '../list-view/list-view-item.svelte';
4
+ import { getTagPickerContext } from './tag-picker.js';
5
+ import type { TagPickerOptionProps } from './types.js';
6
+
7
+ const FALLBACK_ID = $props.id();
8
+ const ID = `${PREFIX}-${FALLBACK_ID}`;
9
+
10
+ let {
11
+ disabled,
12
+ ref = $bindable(),
13
+ id = ID,
14
+ value,
15
+ text,
16
+ class: classes,
17
+ onclick,
18
+ children,
19
+ ...attributes
20
+ }: TagPickerOptionProps = $props();
21
+
22
+ const context = getTagPickerContext();
23
+
24
+ if (!context) throw new Error('TagPickerOption must be used within a TagPicker');
25
+
26
+ const { state: _state, methods } = context;
27
+ const label = $derived(text ?? value);
28
+
29
+ // A chosen option is not offered again, and a typed query leaves only the options that contain it.
30
+ const isVisible = $derived(
31
+ !_state.selectedOptions.includes(value) && label.toLowerCase().includes(_state.query.toLowerCase())
32
+ );
33
+
34
+ function handleClick(e: Parameters<NonNullable<typeof onclick>>[0]) {
35
+ onclick?.(e);
36
+
37
+ if (!disabled) methods.chooseOption(e, id);
38
+ }
39
+
40
+ // The tag of the option keeps its text even when the option itself is not on screen.
41
+ $effect(() => methods.setLabel(value, label));
42
+
43
+ // An option counts only while it is on screen: that is what makes the empty list detectable
44
+ // and keeps keyboard navigation off options nobody can see.
45
+ $effect(() => {
46
+ if (!isVisible || !_state.open) return;
47
+
48
+ // Capture current values to avoid them being stale in the callback
49
+ const _id = id;
50
+
51
+ methods.setOption({ id, value, disabled });
52
+
53
+ return () => methods.deleteOption(_id);
54
+ });
55
+ </script>
56
+
57
+ {#if isVisible}
58
+ <ListViewItem
59
+ {id}
60
+ role="option"
61
+ {value}
62
+ tabindex={-1}
63
+ class={['fs-tagpicker-option', classes]}
64
+ bind:ref
65
+ {disabled}
66
+ {...attributes}
67
+ onclick={handleClick}
68
+ >
69
+ {@render children?.()}
70
+ </ListViewItem>
71
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { TagPickerOptionProps } from './types.ts';
2
+ declare const Option: import("svelte").Component<TagPickerOptionProps, {}, "ref">;
3
+ type Option = ReturnType<typeof Option>;
4
+ export default Option;
@@ -0,0 +1,2 @@
1
+ import type { TagPickerContext } from './types.ts';
2
+ export declare const getTagPickerContext: () => TagPickerContext | null, setTagPickerContext: (context: TagPickerContext) => void;
@@ -0,0 +1,2 @@
1
+ import { createFSContext } from '../../internal/index.js';
2
+ export const [getTagPickerContext, setTagPickerContext] = createFSContext();