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
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Rating
|
|
2
|
+
|
|
3
|
+
A rating lets users give a value to an item by selecting one of a row of stars. It supports half-filled stars, four sizes and a custom number of items.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```svelte
|
|
8
|
+
<script>
|
|
9
|
+
import { Rating } from 'fluentui-svelte';
|
|
10
|
+
|
|
11
|
+
let value = $state(3);
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Rating bind:value />
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Component API
|
|
18
|
+
|
|
19
|
+
A rating lets users give a value to an item, using a row of symbols such as stars. It supports half-filled items and four sizes.
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
### Bind the value
|
|
24
|
+
|
|
25
|
+
Use `bind:value` to read the rating the user picks.
|
|
26
|
+
|
|
27
|
+
```svelte
|
|
28
|
+
<script>
|
|
29
|
+
let value = $state(3);
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<Rating bind:value />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Half stars
|
|
36
|
+
|
|
37
|
+
Set `step={0.5}` to let users pick half-filled stars.
|
|
38
|
+
|
|
39
|
+
```svelte
|
|
40
|
+
<Rating value={2.5} step={0.5} />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Quarter stars
|
|
44
|
+
|
|
45
|
+
Until the user rates, a fractional `value` is drawn in quarters, which is handy to show an average. Once the user picks a star, the rating snaps to the `step`.
|
|
46
|
+
|
|
47
|
+
```svelte
|
|
48
|
+
<Rating value={3.75} />
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Size
|
|
52
|
+
|
|
53
|
+
Use `size` to choose between `small`, `medium`, `large` and `extra-large`.
|
|
54
|
+
|
|
55
|
+
```svelte
|
|
56
|
+
<Rating value={3} size="small" />
|
|
57
|
+
<Rating value={3} size="medium" />
|
|
58
|
+
<Rating value={3} size="large" />
|
|
59
|
+
<Rating value={3} size="extra-large" />
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Shape
|
|
63
|
+
|
|
64
|
+
Use `iconFilled` and `iconOutline` to replace the stars with any other icon component. Both fall back to the star when omitted, and partially filled items are clipped, so custom shapes also work with `step={0.5}`.
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<script>
|
|
68
|
+
import { HeartFilled, HeartRegular } from 'fluentui-icons-svelte';
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<Rating value={3} iconFilled={HeartFilled} iconOutline={HeartRegular} />
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Max
|
|
75
|
+
|
|
76
|
+
Use `max` to change the number of stars.
|
|
77
|
+
|
|
78
|
+
```svelte
|
|
79
|
+
<Rating value={4} max={10} />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Item label
|
|
83
|
+
|
|
84
|
+
Use `itemLabel` to customize the accessible label of each radio input.
|
|
85
|
+
|
|
86
|
+
```svelte
|
|
87
|
+
<Rating value={3} itemLabel={(rating) => `${rating} out of 5 stars`} />
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The root is the control element. HTML attributes, class and ref apply to that element. There is no separate wrapper API.
|
|
91
|
+
|
|
92
|
+
## Component Props
|
|
93
|
+
|
|
94
|
+
<!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
|
|
95
|
+
<!-- props:RatingProps -->
|
|
96
|
+
|
|
97
|
+
| Name | Type | Default | Description |
|
|
98
|
+
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
99
|
+
| `value` _bindable_ | `number` | `0` | The current rating. Fractions are drawn in quarters until the user rates. |
|
|
100
|
+
| `max` | `number` | `5` | The number of items displayed. Must be a whole number greater than 1. |
|
|
101
|
+
| `step` | `1` | `0.5` | `1` | The precision of the rating. `0.5` allows half-filled items. |
|
|
102
|
+
| `size` | `'small'` | `'medium'` | `'large'` | `'extra-large'` | `'extra-large'` | The size of the rating items. |
|
|
103
|
+
| `iconFilled` | `Component` | | The icon of a filled item. Falls back to a filled star. Partially filled items are clipped, so it also works with half steps. |
|
|
104
|
+
| `iconOutline` | `Component` | | The icon of an empty item. Falls back to an outlined star. |
|
|
105
|
+
| `itemLabel` | `(rating: number) => string` | `` (rating) => `${rating}` `` | Generates the accessible label of the radio input for a rating value. |
|
|
106
|
+
| `onChange` | `(value: number) => void` | | Called when the user changes the rating. |
|
|
107
|
+
| `wrapperRef` _bindable_ | `HTMLDivElement` | `null` | | The DOM reference of the radiogroup element. |
|
|
108
|
+
| `wrapperAttributes` | `HTMLAttributes` | | The attributes to spread on the radiogroup element. This is where its `aria-label`, `aria-labelledby`, `aria-invalid`, `id` and `class` go. |
|
|
109
|
+
| `HTMLInputAttributes` without `type`, `value`, `checked`, `max`, `step`, `size`, `style`, `aria-label`, `aria-invalid`, `children` | | | |
|
|
110
|
+
|
|
111
|
+
<!-- /props:RatingProps -->
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { claimLabel } from '../label/label-context.js';
|
|
3
|
+
import { invokeHandlers } from '../../internal/index.js';
|
|
4
|
+
import { PREFIX } from '../../internal/constants.js';
|
|
5
|
+
import StarFilled from 'fluentui-icons-svelte/StarFilled.svelte';
|
|
6
|
+
import StarHalfRegular from 'fluentui-icons-svelte/StarHalfRegular.svelte';
|
|
7
|
+
import StarOneQuarterRegular from 'fluentui-icons-svelte/StarOneQuarterRegular.svelte';
|
|
8
|
+
import StarRegular from 'fluentui-icons-svelte/StarRegular.svelte';
|
|
9
|
+
import StarThreeQuarterRegular from 'fluentui-icons-svelte/StarThreeQuarterRegular.svelte';
|
|
10
|
+
import type { RatingProps } from './types.js';
|
|
11
|
+
|
|
12
|
+
const FALLBACK_ID = $props.id();
|
|
13
|
+
const COMPONENT_NAME = 'rating';
|
|
14
|
+
const ID = `${PREFIX}${COMPONENT_NAME}-${FALLBACK_ID}`;
|
|
15
|
+
const VALUE_ID = `${ID}-value`;
|
|
16
|
+
|
|
17
|
+
const labelContext = claimLabel(() => undefined);
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
value = $bindable(0),
|
|
21
|
+
max = 5,
|
|
22
|
+
step = 1,
|
|
23
|
+
size = 'extra-large',
|
|
24
|
+
iconFilled,
|
|
25
|
+
iconOutline,
|
|
26
|
+
id = ID,
|
|
27
|
+
class: classes,
|
|
28
|
+
name = id,
|
|
29
|
+
itemLabel = (rating) => `${rating}`,
|
|
30
|
+
onChange,
|
|
31
|
+
wrapperRef = $bindable(null),
|
|
32
|
+
wrapperAttributes,
|
|
33
|
+
onclick,
|
|
34
|
+
onpointerenter,
|
|
35
|
+
...attributes
|
|
36
|
+
}: RatingProps = $props();
|
|
37
|
+
|
|
38
|
+
/** Until the user rates, the value is only displayed, so it is drawn with the precision of a quarter. */
|
|
39
|
+
let rated = $state(false);
|
|
40
|
+
let hovered = $state<number>();
|
|
41
|
+
|
|
42
|
+
const _max = $derived.by(() => {
|
|
43
|
+
if (!Number.isInteger(max) || max <= 1) throw new Error('Max must be a whole number greater than 1');
|
|
44
|
+
return max;
|
|
45
|
+
});
|
|
46
|
+
const items = $derived(Array.from({ length: _max }, (_, index) => index + 1));
|
|
47
|
+
const shown = $derived(hovered ?? value);
|
|
48
|
+
const checkedValue = $derived(value === 0 ? 0 : Math.min(_max, Math.max(step, Math.round(value / step) * step)));
|
|
49
|
+
|
|
50
|
+
const custom = $derived(!!(iconFilled || iconOutline));
|
|
51
|
+
|
|
52
|
+
/** How much of the item is filled, snapped to the precision it is shown with. */
|
|
53
|
+
function fillFor(item: number) {
|
|
54
|
+
const fill = Math.min(Math.max(shown - (item - 1), 0), 1);
|
|
55
|
+
const precision = hovered !== undefined || rated ? step / 2 : 0.25;
|
|
56
|
+
return Math.round(fill / precision) * precision;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function iconFor(snapped: number) {
|
|
60
|
+
if (snapped >= 1) return StarFilled;
|
|
61
|
+
if (snapped >= 0.75) return StarThreeQuarterRegular;
|
|
62
|
+
if (snapped >= 0.5) return StarHalfRegular;
|
|
63
|
+
if (snapped >= 0.25) return StarOneQuarterRegular;
|
|
64
|
+
return StarRegular;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function select(next: number) {
|
|
68
|
+
rated = true;
|
|
69
|
+
value = next;
|
|
70
|
+
onChange?.(next);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The value of the checked radio. Clicks select, the arrow keys included; a form reset unchecks every radio, which the binding reports as `null`. */
|
|
74
|
+
let checked = $derived<number | null>(checkedValue);
|
|
75
|
+
|
|
76
|
+
$effect(() => {
|
|
77
|
+
if (checked !== null) return;
|
|
78
|
+
rated = false;
|
|
79
|
+
value = 0;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
function hover(event: PointerEvent & { currentTarget: HTMLInputElement }, item: number) {
|
|
83
|
+
invokeHandlers(event, [], [() => (hovered = item), onpointerenter]);
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<!--
|
|
88
|
+
@component
|
|
89
|
+
A rating lets users give a value to an item, using a row of symbols such as stars. It supports half-filled items and four sizes.
|
|
90
|
+
|
|
91
|
+
- Usage:
|
|
92
|
+
```tsx
|
|
93
|
+
<script>
|
|
94
|
+
import { Rating } from 'fluentui-svelte';
|
|
95
|
+
|
|
96
|
+
let value = $state(3);
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<Rating bind:value />
|
|
100
|
+
<Rating bind:value step={0.5} size="medium" />
|
|
101
|
+
```
|
|
102
|
+
-->
|
|
103
|
+
<div
|
|
104
|
+
{...wrapperAttributes}
|
|
105
|
+
class={['fs-rating', `size-${size}`, wrapperAttributes?.class]}
|
|
106
|
+
bind:this={wrapperRef}
|
|
107
|
+
role="radiogroup"
|
|
108
|
+
onpointerleave={(e) => invokeHandlers(e, [], [() => (hovered = undefined), wrapperAttributes?.onpointerleave])}
|
|
109
|
+
aria-labelledby={wrapperAttributes?.['aria-labelledby'] ?? labelContext?.labelId}
|
|
110
|
+
aria-label={wrapperAttributes?.['aria-label'] ??
|
|
111
|
+
(wrapperAttributes?.['aria-labelledby'] || labelContext ? undefined : 'Rating')}
|
|
112
|
+
aria-describedby={[wrapperAttributes?.['aria-describedby'], VALUE_ID].filter(Boolean).join(' ')}
|
|
113
|
+
>
|
|
114
|
+
<span id={VALUE_ID} hidden>Current rating: {value} out of {_max}.</span>
|
|
115
|
+
{#each items as item (item)}
|
|
116
|
+
{@const fill = fillFor(item)}
|
|
117
|
+
<span class="rating-item">
|
|
118
|
+
{#if custom}
|
|
119
|
+
{@const Outline = iconOutline ?? StarRegular}
|
|
120
|
+
{@const Filled = iconFilled ?? StarFilled}
|
|
121
|
+
<span class={['rating-icon custom', { selected: fill > 0 }]} style="--rating-fill: {fill * 100}%">
|
|
122
|
+
<Outline aria-hidden="true" />
|
|
123
|
+
<span class="filled"><Filled aria-hidden="true" /></span>
|
|
124
|
+
</span>
|
|
125
|
+
{:else}
|
|
126
|
+
{@const Icon = iconFor(fill)}
|
|
127
|
+
<span class={['rating-icon', { selected: fill > 0 }]}><Icon aria-hidden="true" /></span>
|
|
128
|
+
{/if}
|
|
129
|
+
{#if step === 0.5}
|
|
130
|
+
<input
|
|
131
|
+
{...attributes}
|
|
132
|
+
{id}
|
|
133
|
+
{name}
|
|
134
|
+
class={['half-value', classes]}
|
|
135
|
+
type="radio"
|
|
136
|
+
value={item - 0.5}
|
|
137
|
+
aria-label={itemLabel(item - 0.5)}
|
|
138
|
+
bind:group={checked}
|
|
139
|
+
onclick={(e) => invokeHandlers(e, [], [() => value !== item - 0.5 && select(item - 0.5), onclick])}
|
|
140
|
+
onpointerenter={(e) => hover(e, item - 0.5)}
|
|
141
|
+
/>
|
|
142
|
+
{/if}
|
|
143
|
+
<input
|
|
144
|
+
{...attributes}
|
|
145
|
+
{name}
|
|
146
|
+
{id}
|
|
147
|
+
class={['full-value', classes]}
|
|
148
|
+
type="radio"
|
|
149
|
+
value={item}
|
|
150
|
+
aria-label={itemLabel(item)}
|
|
151
|
+
bind:group={checked}
|
|
152
|
+
onclick={(e) => invokeHandlers(e, [], [() => value !== item && select(item), onclick])}
|
|
153
|
+
onpointerenter={(e) => hover(e, item)}
|
|
154
|
+
/>
|
|
155
|
+
</span>
|
|
156
|
+
{/each}
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<style>
|
|
160
|
+
.fs-rating {
|
|
161
|
+
--rating-size: 24px;
|
|
162
|
+
display: inline-flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
color: var(--fs-accent-fill-default);
|
|
165
|
+
|
|
166
|
+
&.size-small {
|
|
167
|
+
--rating-size: 12px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&.size-medium {
|
|
171
|
+
--rating-size: 16px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
&.size-large {
|
|
175
|
+
--rating-size: 20px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
&:is([aria-invalid='true'], :has(input:user-invalid)) .rating-icon {
|
|
179
|
+
color: var(--fs-system-critical);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&:has(input:disabled) .rating-icon {
|
|
183
|
+
color: var(--fs-text-disabled);
|
|
184
|
+
& .filled {
|
|
185
|
+
color: inherit;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.rating-item {
|
|
191
|
+
display: inline-flex;
|
|
192
|
+
position: relative;
|
|
193
|
+
border-radius: var(--fs-control-border-radius);
|
|
194
|
+
padding: 2px;
|
|
195
|
+
|
|
196
|
+
&:has(input:focus-visible) {
|
|
197
|
+
box-shadow: var(--fs-focus-stroke-outer);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
& input {
|
|
201
|
+
appearance: none;
|
|
202
|
+
position: absolute;
|
|
203
|
+
inset-block: 0;
|
|
204
|
+
inset-inline-start: 0;
|
|
205
|
+
margin: 0;
|
|
206
|
+
outline: none;
|
|
207
|
+
cursor: pointer;
|
|
208
|
+
inline-size: 100%;
|
|
209
|
+
block-size: 100%;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
& .half-value {
|
|
213
|
+
z-index: 1;
|
|
214
|
+
inline-size: 50%;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.rating-icon {
|
|
219
|
+
display: inline-flex;
|
|
220
|
+
color: var(--fs-text-secondary);
|
|
221
|
+
|
|
222
|
+
&.selected {
|
|
223
|
+
color: var(--fs-accent-fill-default);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
& :global(svg) {
|
|
227
|
+
inline-size: var(--rating-size);
|
|
228
|
+
block-size: var(--rating-size);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&.custom {
|
|
232
|
+
position: relative;
|
|
233
|
+
|
|
234
|
+
& .filled {
|
|
235
|
+
display: inline-flex;
|
|
236
|
+
position: absolute;
|
|
237
|
+
inset: 0;
|
|
238
|
+
color: var(--fs-accent-fill-default);
|
|
239
|
+
clip-path: inset(0 calc(100% - var(--rating-fill)) 0 0);
|
|
240
|
+
|
|
241
|
+
&:dir(rtl) {
|
|
242
|
+
clip-path: inset(0 0 0 calc(100% - var(--rating-fill)));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RatingProps } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* A rating lets users give a value to an item, using a row of symbols such as stars. It supports half-filled items and four sizes.
|
|
4
|
+
*
|
|
5
|
+
* - Usage:
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <script>
|
|
8
|
+
* import { Rating } from 'fluentui-svelte';
|
|
9
|
+
*
|
|
10
|
+
* let value = $state(3);
|
|
11
|
+
* </script>
|
|
12
|
+
*
|
|
13
|
+
* <Rating bind:value />
|
|
14
|
+
* <Rating bind:value step={0.5} size="medium" />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
declare const Rating: import("svelte").Component<RatingProps, {}, "value" | "wrapperRef">;
|
|
18
|
+
type Rating = ReturnType<typeof Rating>;
|
|
19
|
+
export default Rating;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Component } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes, HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
/** @propsmith RatingProps */
|
|
4
|
+
export type RatingProps = {
|
|
5
|
+
/** The current rating. Fractions are drawn in quarters until the user rates.
|
|
6
|
+
* @default 0
|
|
7
|
+
* @bindable
|
|
8
|
+
*/
|
|
9
|
+
value?: number;
|
|
10
|
+
/** The number of items displayed. Must be a whole number greater than 1.
|
|
11
|
+
* @default 5
|
|
12
|
+
*/
|
|
13
|
+
max?: number;
|
|
14
|
+
/** The precision of the rating. `0.5` allows half-filled items.
|
|
15
|
+
* @default 1
|
|
16
|
+
*/
|
|
17
|
+
step?: 1 | 0.5;
|
|
18
|
+
/** The size of the rating items.
|
|
19
|
+
* @default 'extra-large'
|
|
20
|
+
*/
|
|
21
|
+
size?: 'small' | 'medium' | 'large' | 'extra-large';
|
|
22
|
+
/** The icon of a filled item. Falls back to a filled star. Partially filled items are clipped, so it also works with half steps.
|
|
23
|
+
* @type Component
|
|
24
|
+
*/
|
|
25
|
+
iconFilled?: Component;
|
|
26
|
+
/** The icon of an empty item. Falls back to an outlined star.
|
|
27
|
+
* @type Component
|
|
28
|
+
*/
|
|
29
|
+
iconOutline?: Component;
|
|
30
|
+
/** Generates the accessible label of the radio input for a rating value.
|
|
31
|
+
* @default (rating) => `${rating}`
|
|
32
|
+
*/
|
|
33
|
+
itemLabel?: (rating: number) => string;
|
|
34
|
+
/** Called when the user changes the rating. */
|
|
35
|
+
onChange?: (value: number) => void;
|
|
36
|
+
/** The DOM reference of the radiogroup element.
|
|
37
|
+
* @bindable
|
|
38
|
+
*/
|
|
39
|
+
wrapperRef?: HTMLDivElement | null;
|
|
40
|
+
/** The attributes to spread on the radiogroup element. This is where its `aria-label`, `aria-labelledby`, `aria-invalid`, `id` and `class` go.
|
|
41
|
+
* @type HTMLAttributes
|
|
42
|
+
*/
|
|
43
|
+
wrapperAttributes?: HTMLAttributes<HTMLDivElement>;
|
|
44
|
+
} & Omit<HTMLInputAttributes, 'type' | 'value' | 'checked' | 'max' | 'step' | 'size' | 'style' | 'aria-label' | 'aria-invalid' | 'children'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# SideNav
|
|
2
|
+
|
|
3
|
+
App navigation built on ListView. SideNavItem renders an anchor by default. Use `as="button"` for actions, or `as="li"` / `as="div"` for content with multiple controls. The navigation owns no router: set href and active from your app's current route.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```svelte
|
|
8
|
+
<script>
|
|
9
|
+
import { AppWindow, AppSurface, SideNav, SideNavItem } from 'fluentui-svelte';
|
|
10
|
+
import { HomeRegular, FolderRegular, SettingsRegular } from 'fluentui-icons-svelte';
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<AppWindow width={480} height={240}>
|
|
14
|
+
<SideNav header="Workspace">
|
|
15
|
+
<SideNavItem href="#home" label="Home" icon={HomeRegular} active />
|
|
16
|
+
<SideNavItem href="#documents" label="Documents" icon={FolderRegular} />
|
|
17
|
+
<SideNavItem href="#settings" label="Settings" icon={SettingsRegular} />
|
|
18
|
+
</SideNav>
|
|
19
|
+
<AppSurface style="padding: 1rem">Page content</AppSurface>
|
|
20
|
+
</AppWindow>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
SideNav also works on its own, in any container with a height. Use `bind:collapsed` to control it, `SideNavBranch` to nest items and the `footer` snippet to pin items to the bottom.
|
|
24
|
+
|
|
25
|
+
## Modes and accessibility
|
|
26
|
+
|
|
27
|
+
Docked navigation occupies layout space and collapses to an icon rail. Labels remain available to assistive technology. Items without icons show their initial in the rail. Opening a branch from the rail expands the navigation first.
|
|
28
|
+
|
|
29
|
+
With `floating`, SideNav overlays AppWindow's body below its optional TitleBar. Closed floating navigation shows only the hamburger; opening it does not move page content. It is non-modal and does not trap focus. Escape, an outside pointer press, moving focus outside, and activating a SideNavItem close it. Set `closeOnSelect={false}` to keep it open after activation. A standalone floating SideNav needs a positioned parent.
|
|
30
|
+
|
|
31
|
+
Inside an AppWindow whose TitleBar has a global navigation button (`TitleBarLeftControls globalNav`), that button expands and collapses the SideNav, follows its state in `aria-expanded`, and SideNav hides its own hamburger. Set `showToggle` to `true` to keep both, or to `false` to hide the hamburger and control it yourself (`getAppWindowContext().state.sideNav.setCollapsed`). While a floating navigation is open, the global button is not an outside press.
|
|
32
|
+
|
|
33
|
+
The Button toggle exposes aria-expanded and aria-controls. SideNav is a named navigation landmark with native lists and links. The underlying ListView supplies arrow navigation, disabled-item handling and selection. Avoid menu/listbox roles for ordinary route navigation. There is no back button.
|
|
34
|
+
|
|
35
|
+
## Custom content and footer
|
|
36
|
+
|
|
37
|
+
Only two regions accept text, snippets or components: `topContent`, between the hamburger section and the list, and `footerContent`, after the list and before the pinned navigation footer. Strings render as text and are hidden in the compact rail. Snippets receive `{ collapsed, floating }`; components receive these as props, so they can render compact controls or hide their content. Use a snippet to supply other required component props.
|
|
38
|
+
|
|
39
|
+
The header is plain text. SideNavItem uses its label or ordinary ListViewItem children markup. The `footer` snippet contains navigation entries and remains pinned while the main list scrolls. Compose real Menu, TextBox, Avatar and Button components in the two custom regions.
|
|
40
|
+
|
|
41
|
+
## ListView customization
|
|
42
|
+
|
|
43
|
+
`listViewProps` customizes every list of the navigation: the main one, the footer and the ones inside a SideNavBranch. Defaults are role="list", selectionMode="none" and navigationMode="items". Keep native list semantics when using branches. Selection can be enabled and bound through `selectedItems`, shared across all of them. Set each item's value when using selection.
|
|
44
|
+
|
|
45
|
+
## Component Props (SideNav)
|
|
46
|
+
|
|
47
|
+
<!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
|
|
48
|
+
<!-- props:SideNavProps -->
|
|
49
|
+
|
|
50
|
+
| Name | Type | Default | Description |
|
|
51
|
+
| ------------------------------------------------ | -------------------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| `ref` _bindable_ | `HTMLElement` | `null` | | The DOM reference of the navigation landmark. |
|
|
53
|
+
| `label` | `string` | `'Main navigation'` | The accessible name of the navigation landmark. |
|
|
54
|
+
| `collapsed` _bindable_ | `boolean` | `false` | Shows an icon rail when docked, or only the toggle when floating. |
|
|
55
|
+
| `position` | `'left'` | `'right'` | `'left'` | The side of the window the navigation is on. It mirrors in right-to-left layouts, and AppSurface rounds the corners that face it. |
|
|
56
|
+
| `showToggle` | `boolean` | `Automatic` | Whether the navigation shows its own hamburger toggle. By default it hides it when the title bar of its window has a global navigation button, which then controls the navigation. Set it to true to keep both, or to false to control the navigation yourself. |
|
|
57
|
+
| `floating` | `boolean` | `false` | Overlays the content of a positioned parent instead of taking layout space. The overlay is non-modal. |
|
|
58
|
+
| `width` | `number` | `string` | `200` | The expanded width. Numbers are pixels converted to rem; strings are CSS lengths. |
|
|
59
|
+
| `expandLabel` | `string` | `'Expand navigation'` | The accessible label of the toggle while collapsed. |
|
|
60
|
+
| `collapseLabel` | `string` | `'Collapse navigation'` | The accessible label of the toggle while expanded. |
|
|
61
|
+
| `closeOnSelect` | `boolean` | `true` | Closes a floating panel after activating a SideNavItem. |
|
|
62
|
+
| `onCollapsedChange` | `(event: Event, collapsed: boolean) => void` | | Called when the user expands or collapses the navigation. |
|
|
63
|
+
| `selectedItems` _bindable_ | `string[]` | | The selection shared by every list in the navigation. Selection is off by default. |
|
|
64
|
+
| `listViewProps` | `SideNavListViewProps` | | Overrides the defaults of every list in the navigation, the main one, the footer and the ones inside a SideNavBranch: native list semantics, no selection and one tab stop per item. |
|
|
65
|
+
| `header` | `string` | | The text heading beside the hamburger button. Hidden in the compact rail. |
|
|
66
|
+
| `topContent` | `string` | `Snippet` | `Component` | | Custom content between the hamburger section and the list. Text, snippets and components are supported. Renderers receive collapsed and floating; strings are hidden in the compact rail. |
|
|
67
|
+
| `footerContent` | `string` | `Snippet` | `Component` | | Custom content after the scrolling list and before the pinned footer. Text, snippets and components are supported. Renderers receive collapsed and floating; strings are hidden in the compact rail. |
|
|
68
|
+
| `footer` | `Snippet` | | Footer list items pinned to the bottom, outside the main list's scroll area. |
|
|
69
|
+
| `children` | `Snippet` | | Main navigation items. Use SideNavItem and SideNavBranch. |
|
|
70
|
+
| `HTMLAttributes<HTMLElement>` without `children` | | | |
|
|
71
|
+
|
|
72
|
+
<!-- /props:SideNavProps -->
|
|
73
|
+
|
|
74
|
+
## Component Props (SideNavItem)
|
|
75
|
+
|
|
76
|
+
<!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
|
|
77
|
+
<!-- props:SideNavItemProps -->
|
|
78
|
+
|
|
79
|
+
| Name | Type | Default | Description |
|
|
80
|
+
| ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `as` | `'li'` | `'a'` | `'button'` | `'div'` | `'a'` | The HTML tag. Links are the default; use button for actions and li or div for custom controls. |
|
|
82
|
+
| `ref` _bindable_ | `HTMLLIElement` | `HTMLAnchorElement` | `HTMLButtonElement` | `HTMLDivElement` | | The DOM reference of the item. |
|
|
83
|
+
| `label` | `string` | | The accessible label, also used as visible content when children are absent. |
|
|
84
|
+
| `icon` | `Snippet` | `Component` | | The decorative icon shown in both expanded and collapsed modes. |
|
|
85
|
+
| `children` | `Snippet` | | Optional item markup, following ListViewItem. The label is rendered when children are absent. |
|
|
86
|
+
| `shape`, `value`, `active`, `role`, `disabled`, `checkmark`, `onAction`, `onfocus` from `ListViewItemProps` | | | |
|
|
87
|
+
| HTML Attributes | | | |
|
|
88
|
+
|
|
89
|
+
<!-- /props:SideNavItemProps -->
|
|
90
|
+
|
|
91
|
+
## Component Props (SideNavBranch)
|
|
92
|
+
|
|
93
|
+
<!-- DO NOT EDIT THIS SECTION (propsmith generated) -->
|
|
94
|
+
<!-- props:SideNavBranchProps -->
|
|
95
|
+
|
|
96
|
+
| Name | Type | Default | Description |
|
|
97
|
+
| ---------------------------------------------------------------------------------------------------- | --------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
98
|
+
| `label` | `string` | | The accessible label of the disclosure button. In the compact rail, its initial stands in when there is no icon. |
|
|
99
|
+
| `icon` | `Snippet` | `Component` | | The decorative icon before the label. |
|
|
100
|
+
| `expanded` _bindable_ | `boolean` | `false` | Whether the nested items are visible. Branches only expand or collapse and are never selectable. The compact rail reports a branch as collapsed, and opens the navigation when one is pressed. |
|
|
101
|
+
| `onExpandedChange` | `(e: Event, expanded: boolean) => void` | | Called when a user expands or collapses the branch. |
|
|
102
|
+
| `disabled` | `boolean` | `false` | Disables the disclosure button. |
|
|
103
|
+
| `ref` _bindable_ | `HTMLButtonElement` | | The DOM reference of the native disclosure button. Additional HTML attributes, including class and id, also target this button. |
|
|
104
|
+
| `wrapperRef` _bindable_ | `HTMLLIElement` | `HTMLDivElement` | | The DOM reference of the wrapper element, the list item that holds the button and the nested list. |
|
|
105
|
+
| `wrapperAttributes` | `HTMLAttributes` | | The attributes to spread on the wrapper element. |
|
|
106
|
+
| `shape` | `ListViewItemBranchProps['shape']` | | The disclosure button shape. Inherited from the list by default. |
|
|
107
|
+
| `children` | `Snippet` | | The nested SideNavItem and SideNavBranch content. |
|
|
108
|
+
| `HTMLButtonAttributes` without `children`, `role`, `type`, `value`, `aria-expanded`, `aria-controls` | | | |
|
|
109
|
+
|
|
110
|
+
<!-- /props:SideNavBranchProps -->
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ListViewItemBranch from '../list-view/list-view-item-branch.svelte';
|
|
3
|
+
import SideNavList from './side-nav-list.svelte';
|
|
4
|
+
import { getSideNavContext } from './side-nav.js';
|
|
5
|
+
import type { SideNavBranchProps } from './types.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
ref = $bindable(null),
|
|
9
|
+
wrapperRef = $bindable(null),
|
|
10
|
+
expanded = $bindable(false),
|
|
11
|
+
label,
|
|
12
|
+
wrapperAttributes,
|
|
13
|
+
icon,
|
|
14
|
+
onclick,
|
|
15
|
+
children,
|
|
16
|
+
...attributes
|
|
17
|
+
}: SideNavBranchProps = $props();
|
|
18
|
+
|
|
19
|
+
const context = getSideNavContext();
|
|
20
|
+
// The rail hides the branch, so the branch reports collapsed there without losing its own state.
|
|
21
|
+
const visiblyExpanded = () => expanded && !context?.state.compact;
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
{#snippet initial()}<span>{label.slice(0, 1)}</span>{/snippet}
|
|
25
|
+
|
|
26
|
+
<ListViewItemBranch
|
|
27
|
+
{...attributes}
|
|
28
|
+
{label}
|
|
29
|
+
wrapperAttributes={{ class: `fs-side-nav-branch ${wrapperAttributes?.class ?? ''}`, ...wrapperAttributes }}
|
|
30
|
+
icon={icon ?? (context?.state.compact ? initial : undefined)}
|
|
31
|
+
bind:ref
|
|
32
|
+
bind:wrapperRef
|
|
33
|
+
bind:expanded={visiblyExpanded, (value) => (expanded = value)}
|
|
34
|
+
onclick={(event) => {
|
|
35
|
+
onclick?.(event);
|
|
36
|
+
// A branch cannot open inside the rail, so the rail opens first.
|
|
37
|
+
if (!event.defaultPrevented) context?.methods.setCollapsed(event, false);
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<SideNavList>
|
|
41
|
+
{@render children?.()}
|
|
42
|
+
</SideNavList>
|
|
43
|
+
</ListViewItemBranch>
|