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,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="multiple"` to render checkboxes on selectable items.
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
- if (ITEM_CONTEXT.disabled) {
51
- e.preventDefault();
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: 0.75rem;
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 + 1.5rem * var(--depth, 0));
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 + 1.5rem * var(--depth, 0));
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 + 1.5rem * var(--depth, 0));
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
- &.open :global(.branch-indicator) {
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
- return;
96
+ } else {
97
+ traversalSync(id, state.TREE_NODES, checkedItems, checked);
95
98
  }
96
99
 
97
- traversalSync(id, state.TREE_NODES, checkedItems, checked);
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
- iterable.add(node.id);
105
+ if (node.checked)
106
+ iterable.add(node.id);
106
107
  }
107
108
  else if (Array.isArray(iterable)) {
108
109
  iterable.length = 0;
109
- iterable.push(node.id);
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
@@ -20,7 +20,3 @@ export declare const DIRECTION: {
20
20
  export declare const PREFIX = "fs";
21
21
  export declare const DEFAULT_OFFSET = 8;
22
22
  export declare const VIRTUAL_ELEMENT: VirtualElement;
23
- export declare const fake: {
24
- id: string;
25
- name: string;
26
- }[];