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.
- package/README.md +1 -1
- package/dist/components/auto-suggest-box/docs/llms.md +76 -15
- package/dist/components/card/card-header.svelte +2 -2
- 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 +32 -3
- 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/docs/llms.md +2 -2
- package/dist/components/dialog/types.d.ts +6 -2
- package/dist/components/dialog/utils.d.ts +2 -0
- package/dist/components/dialog/utils.js +1 -0
- package/dist/components/dropdown/dropdown.svelte +1 -0
- package/dist/components/list-view/docs/llms.md +79 -27
- package/dist/components/list-view/list-view-item.svelte +14 -11
- package/dist/components/list-view/list-view.svelte +3 -2
- package/dist/components/list-view/types.d.ts +5 -1
- package/dist/components/menu/docs/llms.md +16 -0
- package/dist/components/menu/menu-popover.svelte +7 -12
- package/dist/components/menu/menu-popover.svelte.d.ts +2 -10
- package/dist/components/menu/types.d.ts +21 -0
- package/dist/components/rating/docs/llms.md +110 -0
- package/dist/components/rating/rating.svelte +210 -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/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 +458 -0
- package/dist/components/tag/tag.svelte.d.ts +19 -0
- package/dist/components/tag/types.d.ts +135 -0
- package/dist/components/tag/types.js +1 -0
- package/dist/components/tag-picker/docs/llms.md +292 -0
- package/dist/components/tag-picker/option-group.svelte +38 -0
- package/dist/components/tag-picker/option-group.svelte.d.ts +4 -0
- package/dist/components/tag-picker/option.svelte +71 -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 +644 -0
- package/dist/components/tag-picker/tag-picker.svelte.d.ts +21 -0
- package/dist/components/tag-picker/types.d.ts +122 -0
- package/dist/components/tag-picker/types.js +1 -0
- package/dist/components/tree-view/docs/llms.md +166 -1
- package/dist/components/tree-view/tree-view-item-content.svelte +41 -8
- package/dist/components/tree-view/tree-view-item.svelte +10 -1
- package/dist/components/tree-view/tree-view.svelte +17 -2
- package/dist/components/tree-view/tree-view.svelte.js +4 -2
- package/dist/components/tree-view/types.d.ts +4 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/internal/constants.d.ts +0 -4
- package/dist/internal/constants.js +0 -4002
- package/package.json +3 -2
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes, HTMLInputAttributes, SVGAttributes } from 'svelte/elements';
|
|
3
|
+
import type { FSContext } from '../../internal/index.js';
|
|
4
|
+
import type { ListViewItemProps } from '../list-view/types.ts';
|
|
5
|
+
import type { TagGroupProps } from '../tag/types.ts';
|
|
6
|
+
export type TagPickerSizes = 'medium' | 'large' | 'extra-large';
|
|
7
|
+
/** @propsmith TagPickerProps */
|
|
8
|
+
export type TagPickerProps = {
|
|
9
|
+
/** The DOM reference of the wrapper element.
|
|
10
|
+
* @bindable
|
|
11
|
+
*/
|
|
12
|
+
ref?: HTMLDivElement;
|
|
13
|
+
/** The DOM reference of the input element.
|
|
14
|
+
* @bindable
|
|
15
|
+
*/
|
|
16
|
+
inputRef?: HTMLInputElement;
|
|
17
|
+
/** The values of the chosen options, shown as tags in the control. A value no option has is shown as it is.
|
|
18
|
+
* @default []
|
|
19
|
+
* @bindable
|
|
20
|
+
*/
|
|
21
|
+
selectedOptions?: string[];
|
|
22
|
+
/** The text typed in the input. It filters the options, and is cleared when one is chosen.
|
|
23
|
+
* @default ''
|
|
24
|
+
* @bindable
|
|
25
|
+
*/
|
|
26
|
+
value?: string;
|
|
27
|
+
/** Controls the open state of the option list.
|
|
28
|
+
* @default false
|
|
29
|
+
* @bindable
|
|
30
|
+
*/
|
|
31
|
+
open?: boolean;
|
|
32
|
+
/** Limits the picker to one tag: choosing an option replaces the current one and closes the list. */
|
|
33
|
+
single?: boolean;
|
|
34
|
+
/** Disables the user interaction: the input, the tags and the list. */
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
/** The size of the control. It also picks the size of the tags.
|
|
37
|
+
* @default 'medium'
|
|
38
|
+
*/
|
|
39
|
+
size?: TagPickerSizes;
|
|
40
|
+
/** The placeholder text of the input. */
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
/** The message shown in place of the list when there is no option left to choose.
|
|
43
|
+
* @default 'No options available'
|
|
44
|
+
*/
|
|
45
|
+
notFoundText?: string;
|
|
46
|
+
/** The dropdown arrow. Pass `null` to remove it.
|
|
47
|
+
* @default ChevronDownRegular
|
|
48
|
+
* @type Snippet | Component | null
|
|
49
|
+
*/
|
|
50
|
+
expandIcon?: Snippet<[SVGAttributes<SVGElement>]> | Component<SVGAttributes<SVGElement>> | null;
|
|
51
|
+
/** A button-like element rendered at the end of the control, before the dropdown arrow. */
|
|
52
|
+
secondaryAction?: Snippet;
|
|
53
|
+
/** Renders the tag of a chosen option, to give it media or custom text. Falls back to a plain tag.
|
|
54
|
+
* Render a `Tag` with the given `value`, and `role="listitem"`.
|
|
55
|
+
* @type Snippet<[{ value: string; text: string }]>
|
|
56
|
+
*/
|
|
57
|
+
tag?: Snippet<[{
|
|
58
|
+
value: string;
|
|
59
|
+
text: string;
|
|
60
|
+
}]>;
|
|
61
|
+
/** The props to spread on the group holding the tags. This is where its `aria-label` goes.
|
|
62
|
+
* @type TagGroupProps
|
|
63
|
+
*/
|
|
64
|
+
tagGroupProps?: Omit<TagGroupProps, 'children' | 'size' | 'appearance' | 'disabled' | 'dismissible' | 'selectedValues' | 'onTagSelect' | 'onDismiss'>;
|
|
65
|
+
/** The props to spread on the input. This is where its accessible name (`aria-label`) and
|
|
66
|
+
* `readonly` (to turn the input into a plain trigger) go.
|
|
67
|
+
* @type HTMLInputAttributes
|
|
68
|
+
*/
|
|
69
|
+
inputProps?: Omit<HTMLInputAttributes, 'value' | 'type' | 'role' | 'disabled' | 'oninput' | 'onkeydown'>;
|
|
70
|
+
/** Called when an option is chosen, or a tag is removed. */
|
|
71
|
+
onSelectionChange?: (e: Event, selectedOptions: string[]) => void;
|
|
72
|
+
/** Called when Enter is pressed with text in the input and no option under the cursor. This is
|
|
73
|
+
* where a free-form tag is added.
|
|
74
|
+
*/
|
|
75
|
+
querySubmitted?: (e: KeyboardEvent, query: string) => void;
|
|
76
|
+
/** The options. Leave it out to get a picker without a list. */
|
|
77
|
+
children?: Snippet;
|
|
78
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, 'children'>;
|
|
79
|
+
export type OptionType = {
|
|
80
|
+
id: string;
|
|
81
|
+
value: string;
|
|
82
|
+
disabled?: boolean;
|
|
83
|
+
};
|
|
84
|
+
export type TagPickerContext = FSContext<null, {
|
|
85
|
+
readonly query: string;
|
|
86
|
+
readonly selectedOptions: string[];
|
|
87
|
+
readonly open: boolean;
|
|
88
|
+
}, null, {
|
|
89
|
+
/** Remembers what the tag of `value` says. Every option calls it, on screen or not. */
|
|
90
|
+
setLabel: (value: string, text: string) => void;
|
|
91
|
+
setOption: (option: OptionType) => void;
|
|
92
|
+
deleteOption: (id: string) => void;
|
|
93
|
+
chooseOption: (e: Event, id: string) => void;
|
|
94
|
+
}>;
|
|
95
|
+
/** @propsmith TagPickerOptionProps */
|
|
96
|
+
export type TagPickerOptionProps = {
|
|
97
|
+
/** The value added to `selectedOptions` when the option is chosen. */
|
|
98
|
+
value: string;
|
|
99
|
+
/** The text the option is filtered by, and the text of its tag. Falls back to `value`. */
|
|
100
|
+
text?: string;
|
|
101
|
+
/** The id of the option element, referenced by the input through `aria-activedescendant`.
|
|
102
|
+
* Falls back to a generated id.
|
|
103
|
+
*/
|
|
104
|
+
id?: string;
|
|
105
|
+
/** The DOM reference of the option element.
|
|
106
|
+
* @bindable
|
|
107
|
+
*/
|
|
108
|
+
ref?: HTMLLIElement;
|
|
109
|
+
/** Takes the option out of reach: it is shown, but the cursor steps over it. */
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
} & Omit<ListViewItemProps<'li'>, 'as' | 'value' | 'onAction' | 'checkmark'>;
|
|
112
|
+
/** @propsmith TagPickerOptionGroupProps */
|
|
113
|
+
export type TagPickerOptionGroupProps = {
|
|
114
|
+
/** The label of the group. */
|
|
115
|
+
label: string;
|
|
116
|
+
/** The DOM reference of the group element.
|
|
117
|
+
* @bindable
|
|
118
|
+
*/
|
|
119
|
+
ref?: HTMLUListElement;
|
|
120
|
+
/** The options of the group. */
|
|
121
|
+
children?: Snippet;
|
|
122
|
+
} & Omit<HTMLAttributes<HTMLUListElement>, 'children'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -35,7 +35,7 @@ Nesting a TreeView inside a TreeViewItem of type='branch' creates a subtree. Use
|
|
|
35
35
|
|
|
36
36
|
### Checkable Items
|
|
37
37
|
|
|
38
|
-
Set `selectionMode
|
|
38
|
+
Set `selectionMode` to `"multiple" | "single"` to render checkboxes on selectable items.
|
|
39
39
|
|
|
40
40
|
```svelte
|
|
41
41
|
<TreeView selectionMode="multiple">
|
|
@@ -50,6 +50,132 @@ Set `selectionMode="multiple"` to render checkboxes on selectable items.
|
|
|
50
50
|
</TreeView>
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
### Single selection
|
|
54
|
+
|
|
55
|
+
Set `selectionMode` to `single` so checking an item unchecks the previous one, and branches no longer cascade to their children.
|
|
56
|
+
|
|
57
|
+
```svelte
|
|
58
|
+
<script>
|
|
59
|
+
let checked = $state([]);
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<TreeView selectionMode="single" bind:checkedItems={checked}>
|
|
63
|
+
<TreeViewItem id="fruits" type="branch" open>
|
|
64
|
+
<TreeViewItemContent>Fruits</TreeViewItemContent>
|
|
65
|
+
<TreeView>
|
|
66
|
+
<TreeViewItem id="apple">
|
|
67
|
+
<TreeViewItemContent>Apple</TreeViewItemContent>
|
|
68
|
+
</TreeViewItem>
|
|
69
|
+
<TreeViewItem id="banana">
|
|
70
|
+
<TreeViewItemContent>Banana</TreeViewItemContent>
|
|
71
|
+
</TreeViewItem>
|
|
72
|
+
</TreeView>
|
|
73
|
+
</TreeViewItem>
|
|
74
|
+
<TreeViewItem id="vegetables">
|
|
75
|
+
<TreeViewItemContent>Vegetables</TreeViewItemContent>
|
|
76
|
+
</TreeViewItem>
|
|
77
|
+
</TreeView>
|
|
78
|
+
|
|
79
|
+
<p>Checked: {checked.join(', ')}</p>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Icons
|
|
83
|
+
|
|
84
|
+
Use `iconBefore` and `iconAfter` to render icons around the label. Every item reserves the space of the expand chevron, so checkboxes and icons stay aligned between branches and leaves.
|
|
85
|
+
|
|
86
|
+
```svelte
|
|
87
|
+
<script>
|
|
88
|
+
import { TreeView, TreeViewItem, TreeViewItemContent } from 'fluentui-svelte';
|
|
89
|
+
import FolderRegular from 'fluentui-icons-svelte/FolderRegular.svelte';
|
|
90
|
+
import DocumentRegular from 'fluentui-icons-svelte/DocumentRegular.svelte';
|
|
91
|
+
import ImageRegular from 'fluentui-icons-svelte/ImageRegular.svelte';
|
|
92
|
+
import StarRegular from 'fluentui-icons-svelte/StarRegular.svelte';
|
|
93
|
+
import LockClosedRegular from 'fluentui-icons-svelte/LockClosedRegular.svelte';
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
{#snippet folder()}<FolderRegular width="1.25rem" />{/snippet}
|
|
97
|
+
{#snippet document()}<DocumentRegular width="1.25rem" />{/snippet}
|
|
98
|
+
{#snippet image()}<ImageRegular width="1.25rem" />{/snippet}
|
|
99
|
+
{#snippet star()}<StarRegular width="1rem" />{/snippet}
|
|
100
|
+
{#snippet lock()}<LockClosedRegular width="1rem" />{/snippet}
|
|
101
|
+
|
|
102
|
+
<TreeView selectionMode="multiple">
|
|
103
|
+
<TreeViewItem id="documents" type="branch" open>
|
|
104
|
+
<TreeViewItemContent iconBefore={folder}>Documents</TreeViewItemContent>
|
|
105
|
+
<TreeView>
|
|
106
|
+
<TreeViewItem id="report">
|
|
107
|
+
<TreeViewItemContent iconBefore={document} iconAfter={star}>Report</TreeViewItemContent>
|
|
108
|
+
</TreeViewItem>
|
|
109
|
+
<TreeViewItem id="photo">
|
|
110
|
+
<TreeViewItemContent iconBefore={image}>Photo</TreeViewItemContent>
|
|
111
|
+
</TreeViewItem>
|
|
112
|
+
</TreeView>
|
|
113
|
+
</TreeViewItem>
|
|
114
|
+
<TreeViewItem id="notes">
|
|
115
|
+
<TreeViewItemContent iconBefore={document} iconAfter={lock}>Notes</TreeViewItemContent>
|
|
116
|
+
</TreeViewItem>
|
|
117
|
+
</TreeView>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Aside and actions
|
|
121
|
+
|
|
122
|
+
`aside` is pinned to the end of the row. `actions` comes after it and is revealed when the row is hovered or focused.
|
|
123
|
+
|
|
124
|
+
```svelte
|
|
125
|
+
<script>
|
|
126
|
+
import { TreeView, TreeViewItem, TreeViewItemContent, Button } from 'fluentui-svelte';
|
|
127
|
+
import DocumentRegular from 'fluentui-icons-svelte/DocumentRegular.svelte';
|
|
128
|
+
import MoreHorizontalRegular from 'fluentui-icons-svelte/MoreHorizontalRegular.svelte';
|
|
129
|
+
</script>
|
|
130
|
+
|
|
131
|
+
{#snippet document()}<DocumentRegular width="1.25rem" />{/snippet}
|
|
132
|
+
{#snippet fileSize()}<span>2 KB</span>{/snippet}
|
|
133
|
+
{#snippet more()}
|
|
134
|
+
<Button appearance="subtle" onclick={(e) => e.stopPropagation()} aria-label="More actions"
|
|
135
|
+
><MoreHorizontalRegular width="1rem" /></Button
|
|
136
|
+
>
|
|
137
|
+
{/snippet}
|
|
138
|
+
|
|
139
|
+
<TreeView>
|
|
140
|
+
<TreeViewItem id="report">
|
|
141
|
+
<TreeViewItemContent iconBefore={document} aside={fileSize} actions={more}>Report</TreeViewItemContent>
|
|
142
|
+
</TreeViewItem>
|
|
143
|
+
<TreeViewItem id="annual-summary">
|
|
144
|
+
<TreeViewItemContent iconBefore={document} aside={fileSize} actions={more}>Annual summary</TreeViewItemContent>
|
|
145
|
+
</TreeViewItem>
|
|
146
|
+
</TreeView>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Sizes
|
|
150
|
+
|
|
151
|
+
Set `size` to `small`, `medium` or `large` on the root `TreeView`.
|
|
152
|
+
|
|
153
|
+
```svelte
|
|
154
|
+
<TreeView size="small">...</TreeView>
|
|
155
|
+
<TreeView size="medium">...</TreeView>
|
|
156
|
+
<TreeView size="large">...</TreeView>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Disabled items
|
|
160
|
+
|
|
161
|
+
A disabled item can't be opened or checked, and it is skipped when its parent checks its children, which leaves the parent in its mixed state.
|
|
162
|
+
|
|
163
|
+
```svelte
|
|
164
|
+
<TreeView selectionMode="multiple">
|
|
165
|
+
<TreeViewItem id="fruits" type="branch" open>
|
|
166
|
+
<TreeViewItemContent>Fruits</TreeViewItemContent>
|
|
167
|
+
<TreeView>
|
|
168
|
+
<TreeViewItem id="apple">
|
|
169
|
+
<TreeViewItemContent>Apple</TreeViewItemContent>
|
|
170
|
+
</TreeViewItem>
|
|
171
|
+
<TreeViewItem id="banana" disabled>
|
|
172
|
+
<TreeViewItemContent>Banana</TreeViewItemContent>
|
|
173
|
+
</TreeViewItem>
|
|
174
|
+
</TreeView>
|
|
175
|
+
</TreeViewItem>
|
|
176
|
+
</TreeView>
|
|
177
|
+
```
|
|
178
|
+
|
|
53
179
|
### Controlling Open and Checked State
|
|
54
180
|
|
|
55
181
|
Use the bindable `openItems` and `checkedItems` props on the root `TreeView` to control state programmatically.
|
|
@@ -70,6 +196,45 @@ Use the bindable `openItems` and `checkedItems` props on the root `TreeView` to
|
|
|
70
196
|
</TreeView>
|
|
71
197
|
</TreeViewItem>
|
|
72
198
|
</TreeView>
|
|
199
|
+
|
|
200
|
+
<p>Open: {openItems.join(', ')}</p>
|
|
201
|
+
<p>Checked: {checkedItems.join(', ')}</p>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Events
|
|
205
|
+
|
|
206
|
+
`onCheckedChange` and `onOpenChange` on the TreeView receive the resulting ids. The same props on a TreeViewItem receive the item and its new state, including the children a branch cascades to.
|
|
207
|
+
|
|
208
|
+
```svelte
|
|
209
|
+
<script>
|
|
210
|
+
let treeEvent = $state('');
|
|
211
|
+
let itemEvent = $state('');
|
|
212
|
+
</script>
|
|
213
|
+
|
|
214
|
+
<TreeView
|
|
215
|
+
selectionMode="multiple"
|
|
216
|
+
onCheckedChange={(e, checkedItems) => (treeEvent = 'Checked: ' + checkedItems.join(', '))}
|
|
217
|
+
onOpenChange={(e, openItems) => (treeEvent = 'Open: ' + openItems.join(', '))}
|
|
218
|
+
>
|
|
219
|
+
<TreeViewItem
|
|
220
|
+
id="fruits"
|
|
221
|
+
type="branch"
|
|
222
|
+
onOpenChange={(e, { id, open }) => (itemEvent = id + (open ? ' opened' : ' closed'))}
|
|
223
|
+
>
|
|
224
|
+
<TreeViewItemContent>Fruits</TreeViewItemContent>
|
|
225
|
+
<TreeView>
|
|
226
|
+
<TreeViewItem
|
|
227
|
+
id="apple"
|
|
228
|
+
onCheckedChange={(e, { id, checked }) => (itemEvent = id + (checked ? ' checked' : ' unchecked'))}
|
|
229
|
+
>
|
|
230
|
+
<TreeViewItemContent>Apple</TreeViewItemContent>
|
|
231
|
+
</TreeViewItem>
|
|
232
|
+
</TreeView>
|
|
233
|
+
</TreeViewItem>
|
|
234
|
+
</TreeView>
|
|
235
|
+
|
|
236
|
+
<p>Tree: {treeEvent}</p>
|
|
237
|
+
<p>Item: {itemEvent}</p>
|
|
73
238
|
```
|
|
74
239
|
|
|
75
240
|
## Component Props (TreeView)
|
|
@@ -47,10 +47,8 @@
|
|
|
47
47
|
wrapperAttributes={{
|
|
48
48
|
onclick: (e) => {
|
|
49
49
|
e.stopPropagation();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
if (ITEM_CONTEXT.disabled) return;
|
|
54
52
|
handleCheck(e, ITEM_CONTEXT.id, !ITEM_CONTEXT.checked);
|
|
55
53
|
}
|
|
56
54
|
}}
|
|
@@ -87,9 +85,12 @@
|
|
|
87
85
|
|
|
88
86
|
<style>
|
|
89
87
|
.fs-tree-view-item-content {
|
|
88
|
+
--chevron-width: 1.2rem;
|
|
89
|
+
--gap: 0.75rem;
|
|
90
|
+
box-sizing: border-box;
|
|
90
91
|
display: flex;
|
|
91
92
|
align-items: center;
|
|
92
|
-
gap:
|
|
93
|
+
gap: var(--gap);
|
|
93
94
|
position: relative;
|
|
94
95
|
border-radius: var(--fs-control-border-radius);
|
|
95
96
|
font-size: var(--fs-body-font-size);
|
|
@@ -100,20 +101,26 @@
|
|
|
100
101
|
width: 100%;
|
|
101
102
|
text-align: left;
|
|
102
103
|
user-select: none;
|
|
104
|
+
&:not(:has(:global(.branch-indicator))) {
|
|
105
|
+
--leaf-offset: calc(var(--chevron-width) + var(--gap) + 0rem);
|
|
106
|
+
}
|
|
103
107
|
&.size-small {
|
|
104
108
|
font-size: var(--fs-body2-font-size);
|
|
105
109
|
padding: 0.125rem 0.5rem;
|
|
106
|
-
padding-left: calc(0.5rem +
|
|
110
|
+
padding-left: calc(0.5rem + 2rem * var(--depth, 0) + var(--leaf-offset, 0rem));
|
|
111
|
+
min-height: 1.75rem;
|
|
107
112
|
}
|
|
108
113
|
&.size-medium {
|
|
109
114
|
font-size: var(--fs-body-font-size);
|
|
110
115
|
padding: 0.25rem 0.625rem;
|
|
111
|
-
padding-left: calc(0.625rem +
|
|
116
|
+
padding-left: calc(0.625rem + 2rem * var(--depth, 0) + var(--leaf-offset, 0rem));
|
|
117
|
+
min-height: 2rem;
|
|
112
118
|
}
|
|
113
119
|
&.size-large {
|
|
114
120
|
font-size: var(--fs-subtitle2-font-size);
|
|
115
121
|
padding: 0.375rem 0.75rem;
|
|
116
|
-
padding-left: calc(0.75rem +
|
|
122
|
+
padding-left: calc(0.75rem + 2rem * var(--depth, 0) + var(--leaf-offset, 0rem));
|
|
123
|
+
min-height: 2.25rem;
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
&::after {
|
|
@@ -155,4 +162,30 @@
|
|
|
155
162
|
fill: currentColor;
|
|
156
163
|
}
|
|
157
164
|
}
|
|
165
|
+
.fs-tree-view-item-icon-before,
|
|
166
|
+
.fs-tree-view-item-icon-after,
|
|
167
|
+
.fs-tree-view-item-aside,
|
|
168
|
+
.fs-tree-view-item-actions {
|
|
169
|
+
display: inline-flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
flex-shrink: 0;
|
|
172
|
+
}
|
|
173
|
+
.fs-tree-view-item-aside,
|
|
174
|
+
.fs-tree-view-item-actions {
|
|
175
|
+
margin-left: auto;
|
|
176
|
+
}
|
|
177
|
+
.fs-tree-view-item-aside + .fs-tree-view-item-actions {
|
|
178
|
+
margin-left: 0;
|
|
179
|
+
}
|
|
180
|
+
.fs-tree-view-item-actions {
|
|
181
|
+
opacity: 0;
|
|
182
|
+
@media (hover: none) {
|
|
183
|
+
opacity: 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
.fs-tree-view-item-content:hover .fs-tree-view-item-actions,
|
|
187
|
+
.fs-tree-view-item-content:focus-within .fs-tree-view-item-actions,
|
|
188
|
+
:global(.fs-tree-view-item:focus-visible) > .fs-tree-view-item-content .fs-tree-view-item-actions {
|
|
189
|
+
opacity: 1;
|
|
190
|
+
}
|
|
158
191
|
</style>
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
type = 'item',
|
|
33
33
|
open = (openItems instanceof Set ? openItems.has(id) : openItems.includes(id)) || undefined,
|
|
34
34
|
checked = (checkedItems instanceof Set ? checkedItems.has(id) : checkedItems.includes(id)) || undefined,
|
|
35
|
+
onCheckedChange,
|
|
36
|
+
onOpenChange,
|
|
35
37
|
children,
|
|
36
38
|
...attributes
|
|
37
39
|
}: TreeViewItemProps = $props();
|
|
@@ -61,6 +63,12 @@
|
|
|
61
63
|
get parentId() {
|
|
62
64
|
return itemContext?.id;
|
|
63
65
|
},
|
|
66
|
+
get onCheckedChange() {
|
|
67
|
+
return onCheckedChange;
|
|
68
|
+
},
|
|
69
|
+
get onOpenChange() {
|
|
70
|
+
return onOpenChange;
|
|
71
|
+
},
|
|
64
72
|
get open() {
|
|
65
73
|
return open;
|
|
66
74
|
},
|
|
@@ -190,7 +198,8 @@
|
|
|
190
198
|
outline: 2px solid var(--fs-focus-stroke-outer);
|
|
191
199
|
outline-offset: 2px;
|
|
192
200
|
}
|
|
193
|
-
|
|
201
|
+
/* Only the chevron of this item's own row, not the ones of the branches nested inside it. */
|
|
202
|
+
&.open > :global(.fs-tree-view-item-content .branch-indicator) {
|
|
194
203
|
rotate: 90deg;
|
|
195
204
|
}
|
|
196
205
|
}
|
|
@@ -89,12 +89,21 @@
|
|
|
89
89
|
await tick();
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
const wasChecked = new Map(state.TREE_NODES.entries().map(([nodeId, node]) => [nodeId, !!node.checked]));
|
|
93
|
+
|
|
92
94
|
if (selectionMode === 'single') {
|
|
93
95
|
traversalSyncSingleSelection(id, state.TREE_NODES, checkedItems);
|
|
94
|
-
|
|
96
|
+
} else {
|
|
97
|
+
traversalSync(id, state.TREE_NODES, checkedItems, checked);
|
|
95
98
|
}
|
|
96
99
|
|
|
97
|
-
|
|
100
|
+
// Every item the click reached reports its own change, the tree reports the resulting set.
|
|
101
|
+
for (const node of state.TREE_NODES.values()) {
|
|
102
|
+
if (!!node.checked !== wasChecked.get(node.id)) {
|
|
103
|
+
node.onCheckedChange?.(e as Event, { id: node.id, checked: !!node.checked });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
treeViewContext.events.onCheckedChange(e as Event, Array.from(checkedItems));
|
|
98
107
|
},
|
|
99
108
|
openItem: (e, id) => {
|
|
100
109
|
if (openItems instanceof SvelteSet) {
|
|
@@ -105,6 +114,9 @@
|
|
|
105
114
|
const node = treeViewContext.state.TREE_NODES.get(id)!;
|
|
106
115
|
|
|
107
116
|
node.open = true;
|
|
117
|
+
|
|
118
|
+
node.onOpenChange?.(e as Event, { id, open: true });
|
|
119
|
+
treeViewContext.events.onOpenChange(e as Event, Array.from(openItems));
|
|
108
120
|
},
|
|
109
121
|
closeItem: (e, id) => {
|
|
110
122
|
const { state } = treeViewContext;
|
|
@@ -122,6 +134,9 @@
|
|
|
122
134
|
if (virtualizer && state.forceVirtualRender) {
|
|
123
135
|
state.forceVirtualRender = false;
|
|
124
136
|
}
|
|
137
|
+
|
|
138
|
+
node.onOpenChange?.(e as Event, { id, open: false });
|
|
139
|
+
treeViewContext.events.onOpenChange(e as Event, Array.from(openItems));
|
|
125
140
|
},
|
|
126
141
|
registerItem: (node) => {
|
|
127
142
|
treeViewContext.state.TREE_NODES.set(node.id, node);
|
|
@@ -102,10 +102,12 @@ export function traversalSyncSingleSelection(itemId, state, iterable) {
|
|
|
102
102
|
node.indeterminate = false;
|
|
103
103
|
if (iterable instanceof Set) {
|
|
104
104
|
iterable.clear();
|
|
105
|
-
|
|
105
|
+
if (node.checked)
|
|
106
|
+
iterable.add(node.id);
|
|
106
107
|
}
|
|
107
108
|
else if (Array.isArray(iterable)) {
|
|
108
109
|
iterable.length = 0;
|
|
109
|
-
|
|
110
|
+
if (node.checked)
|
|
111
|
+
iterable.push(node.id);
|
|
110
112
|
}
|
|
111
113
|
}
|
|
@@ -14,6 +14,8 @@ export type TreeViewNode = {
|
|
|
14
14
|
checked?: boolean;
|
|
15
15
|
indeterminate?: boolean;
|
|
16
16
|
open?: boolean;
|
|
17
|
+
onCheckedChange?: TreeViewItemProps['onCheckedChange'];
|
|
18
|
+
onOpenChange?: TreeViewItemProps['onOpenChange'];
|
|
17
19
|
};
|
|
18
20
|
export type TreeViewEvent<T extends Record<string, unknown> | Iterable<unknown>> = (e: Event, data: T) => void;
|
|
19
21
|
/**
|
|
@@ -179,6 +181,8 @@ export type TreeViewItemContext = {
|
|
|
179
181
|
readonly id: string;
|
|
180
182
|
readonly type: TreeViewItemType;
|
|
181
183
|
readonly parentId?: string;
|
|
184
|
+
readonly onCheckedChange?: TreeViewItemProps['onCheckedChange'];
|
|
185
|
+
readonly onOpenChange?: TreeViewItemProps['onOpenChange'];
|
|
182
186
|
open?: boolean;
|
|
183
187
|
checked?: boolean;
|
|
184
188
|
indeterminate?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -57,6 +57,8 @@ export { default as Persona } from './components/persona/persona.svelte';
|
|
|
57
57
|
export { default as ProgressBar } from './components/progress-bar/progress-bar.svelte';
|
|
58
58
|
export { default as ProgressRing } from './components/progress-ring/progress-ring.svelte';
|
|
59
59
|
export { default as RadioButton } from './components/radio-button/radio-button.svelte';
|
|
60
|
+
export { default as Rating } from './components/rating/rating.svelte';
|
|
61
|
+
export type { RatingProps } from './components/rating/types.js';
|
|
60
62
|
export { default as Skeleton } from './components/skeleton/skeleton.svelte';
|
|
61
63
|
export { default as Slider } from './components/slider/slider.svelte';
|
|
62
64
|
export { default as Table } from './components/table/table.svelte';
|
|
@@ -70,6 +72,11 @@ export { default as TableCellLayout } from './components/table/table-cell-layout
|
|
|
70
72
|
export { default as TableCellActions } from './components/table/table-cell-actions.svelte';
|
|
71
73
|
export { default as TabView } from './components/tab-view/tab-view.svelte';
|
|
72
74
|
export { default as TabViewTab } from './components/tab-view/tab-view-tab.svelte';
|
|
75
|
+
export { default as Tag } from './components/tag/tag.svelte';
|
|
76
|
+
export { default as TagGroup } from './components/tag/tag-group.svelte';
|
|
77
|
+
export { default as TagPicker } from './components/tag-picker/tag-picker.svelte';
|
|
78
|
+
export { default as TagPickerOption } from './components/tag-picker/option.svelte';
|
|
79
|
+
export { default as TagPickerOptionGroup } from './components/tag-picker/option-group.svelte';
|
|
73
80
|
export { default as TextArea } from './components/textarea/textarea.svelte';
|
|
74
81
|
export { default as TextBox } from './components/text-box/text-box.svelte';
|
|
75
82
|
export { default as TextBoxButton } from './components/text-box/text-box-button.svelte';
|
package/dist/index.js
CHANGED
|
@@ -109,6 +109,9 @@ export { default as ProgressRing } from './components/progress-ring/progress-rin
|
|
|
109
109
|
// Start RadioButton Component
|
|
110
110
|
export { default as RadioButton } from './components/radio-button/radio-button.svelte';
|
|
111
111
|
// End RadioButton Component
|
|
112
|
+
// Start Rating Component
|
|
113
|
+
export { default as Rating } from './components/rating/rating.svelte';
|
|
114
|
+
// End Rating Component
|
|
112
115
|
// Start Skeleton Component
|
|
113
116
|
export { default as Skeleton } from './components/skeleton/skeleton.svelte';
|
|
114
117
|
// End Skeleton Component
|
|
@@ -130,6 +133,15 @@ export { default as TableCellActions } from './components/table/table-cell-actio
|
|
|
130
133
|
export { default as TabView } from './components/tab-view/tab-view.svelte';
|
|
131
134
|
export { default as TabViewTab } from './components/tab-view/tab-view-tab.svelte';
|
|
132
135
|
// End TabView Component
|
|
136
|
+
// Start Tag Component
|
|
137
|
+
export { default as Tag } from './components/tag/tag.svelte';
|
|
138
|
+
export { default as TagGroup } from './components/tag/tag-group.svelte';
|
|
139
|
+
// End Tag Component
|
|
140
|
+
// Start TagPicker Component
|
|
141
|
+
export { default as TagPicker } from './components/tag-picker/tag-picker.svelte';
|
|
142
|
+
export { default as TagPickerOption } from './components/tag-picker/option.svelte';
|
|
143
|
+
export { default as TagPickerOptionGroup } from './components/tag-picker/option-group.svelte';
|
|
144
|
+
// End TagPicker Component
|
|
133
145
|
// Start TextArea Component
|
|
134
146
|
export { default as TextArea } from './components/textarea/textarea.svelte';
|
|
135
147
|
// End TextArea Component
|