fluentui-svelte 0.1.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 (283) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/dist/components/auto-suggest-box/auto-suggest-box.d.ts +2 -0
  4. package/dist/components/auto-suggest-box/auto-suggest-box.js +2 -0
  5. package/dist/components/auto-suggest-box/auto-suggest-box.svelte +457 -0
  6. package/dist/components/auto-suggest-box/auto-suggest-box.svelte.d.ts +4 -0
  7. package/dist/components/auto-suggest-box/docs/llms.md +73 -0
  8. package/dist/components/auto-suggest-box/option.svelte +82 -0
  9. package/dist/components/auto-suggest-box/option.svelte.d.ts +4 -0
  10. package/dist/components/auto-suggest-box/types.d.ts +140 -0
  11. package/dist/components/auto-suggest-box/types.js +1 -0
  12. package/dist/components/avatar/avatar.svelte +269 -0
  13. package/dist/components/avatar/avatar.svelte.d.ts +20 -0
  14. package/dist/components/avatar/docs/llms.md +92 -0
  15. package/dist/components/avatar/type.d.ts +63 -0
  16. package/dist/components/avatar/type.js +1 -0
  17. package/dist/components/badge/badge-icon.svelte +103 -0
  18. package/dist/components/badge/badge-icon.svelte.d.ts +25 -0
  19. package/dist/components/badge/badge.svelte +163 -0
  20. package/dist/components/badge/badge.svelte.d.ts +20 -0
  21. package/dist/components/badge/docs/llms.md +133 -0
  22. package/dist/components/badge/types.d.ts +70 -0
  23. package/dist/components/badge/types.js +1 -0
  24. package/dist/components/badge/utils.svelte.d.ts +16 -0
  25. package/dist/components/badge/utils.svelte.js +35 -0
  26. package/dist/components/button/button.svelte +203 -0
  27. package/dist/components/button/button.svelte.d.ts +38 -0
  28. package/dist/components/button/docs/llms.md +102 -0
  29. package/dist/components/button/split-button.svelte +66 -0
  30. package/dist/components/button/split-button.svelte.d.ts +4 -0
  31. package/dist/components/button/types.d.ts +84 -0
  32. package/dist/components/button/types.js +1 -0
  33. package/dist/components/calendar-date-picker/calendar-date-picker.svelte +119 -0
  34. package/dist/components/calendar-date-picker/calendar-date-picker.svelte.d.ts +4 -0
  35. package/dist/components/calendar-date-picker/docs/llms.md +33 -0
  36. package/dist/components/calendar-date-picker/types.d.ts +36 -0
  37. package/dist/components/calendar-date-picker/types.js +1 -0
  38. package/dist/components/calendar-view/calendar-view-controls.svelte +115 -0
  39. package/dist/components/calendar-view/calendar-view-controls.svelte.d.ts +3 -0
  40. package/dist/components/calendar-view/calendar-view-days.svelte +210 -0
  41. package/dist/components/calendar-view/calendar-view-days.svelte.d.ts +3 -0
  42. package/dist/components/calendar-view/calendar-view-grid.d.ts +38 -0
  43. package/dist/components/calendar-view/calendar-view-grid.js +140 -0
  44. package/dist/components/calendar-view/calendar-view-header.svelte +66 -0
  45. package/dist/components/calendar-view/calendar-view-header.svelte.d.ts +18 -0
  46. package/dist/components/calendar-view/calendar-view-item.svelte +181 -0
  47. package/dist/components/calendar-view/calendar-view-item.svelte.d.ts +4 -0
  48. package/dist/components/calendar-view/calendar-view-months.svelte +165 -0
  49. package/dist/components/calendar-view/calendar-view-months.svelte.d.ts +3 -0
  50. package/dist/components/calendar-view/calendar-view-years.svelte +161 -0
  51. package/dist/components/calendar-view/calendar-view-years.svelte.d.ts +3 -0
  52. package/dist/components/calendar-view/calendar-view.svelte +451 -0
  53. package/dist/components/calendar-view/calendar-view.svelte.d.ts +9 -0
  54. package/dist/components/calendar-view/calendar-view.svelte.js +196 -0
  55. package/dist/components/calendar-view/docs/llms.md +121 -0
  56. package/dist/components/calendar-view/index.d.ts +1 -0
  57. package/dist/components/calendar-view/index.js +1 -0
  58. package/dist/components/calendar-view/types.d.ts +174 -0
  59. package/dist/components/calendar-view/types.js +1 -0
  60. package/dist/components/checkbox/checkbox.svelte +171 -0
  61. package/dist/components/checkbox/checkbox.svelte.d.ts +40 -0
  62. package/dist/components/checkbox/docs/llms.md +78 -0
  63. package/dist/components/checkbox/types.d.ts +50 -0
  64. package/dist/components/checkbox/types.js +1 -0
  65. package/dist/components/date-picker/date-picker.svelte +381 -0
  66. package/dist/components/date-picker/date-picker.svelte.d.ts +4 -0
  67. package/dist/components/date-picker/docs/llms.md +52 -0
  68. package/dist/components/date-picker/index.d.ts +1 -0
  69. package/dist/components/date-picker/index.js +1 -0
  70. package/dist/components/date-picker/types.d.ts +74 -0
  71. package/dist/components/date-picker/types.js +1 -0
  72. package/dist/components/dialog/dialog-actions.svelte +37 -0
  73. package/dist/components/dialog/dialog-actions.svelte.d.ts +4 -0
  74. package/dist/components/dialog/dialog-content.svelte +17 -0
  75. package/dist/components/dialog/dialog-content.svelte.d.ts +4 -0
  76. package/dist/components/dialog/dialog-surface.svelte +95 -0
  77. package/dist/components/dialog/dialog-surface.svelte.d.ts +4 -0
  78. package/dist/components/dialog/dialog-title.svelte +33 -0
  79. package/dist/components/dialog/dialog-title.svelte.d.ts +25 -0
  80. package/dist/components/dialog/dialog-trigger.svelte +23 -0
  81. package/dist/components/dialog/dialog-trigger.svelte.d.ts +4 -0
  82. package/dist/components/dialog/dialog.svelte +64 -0
  83. package/dist/components/dialog/dialog.svelte.d.ts +7 -0
  84. package/dist/components/dialog/dialog.svelte.js +2 -0
  85. package/dist/components/dialog/docs/llms.md +131 -0
  86. package/dist/components/dialog/types.d.ts +92 -0
  87. package/dist/components/dialog/types.js +1 -0
  88. package/dist/components/divider/divider.svelte +120 -0
  89. package/dist/components/divider/divider.svelte.d.ts +39 -0
  90. package/dist/components/divider/docs/llms.md +83 -0
  91. package/dist/components/divider/types.d.ts +32 -0
  92. package/dist/components/divider/types.js +1 -0
  93. package/dist/components/dropdown/docs/llms.md +70 -0
  94. package/dist/components/dropdown/dropdown-context.d.ts +2 -0
  95. package/dist/components/dropdown/dropdown-context.js +2 -0
  96. package/dist/components/dropdown/dropdown-option.svelte +31 -0
  97. package/dist/components/dropdown/dropdown-option.svelte.d.ts +4 -0
  98. package/dist/components/dropdown/dropdown.svelte +309 -0
  99. package/dist/components/dropdown/dropdown.svelte.d.ts +4 -0
  100. package/dist/components/dropdown/types.d.ts +82 -0
  101. package/dist/components/dropdown/types.js +1 -0
  102. package/dist/components/dropdown-select/docs/llms.md +72 -0
  103. package/dist/components/dropdown-select/dropdown-select-option.svelte +87 -0
  104. package/dist/components/dropdown-select/dropdown-select-option.svelte.d.ts +4 -0
  105. package/dist/components/dropdown-select/dropdown-select.svelte +165 -0
  106. package/dist/components/dropdown-select/dropdown-select.svelte.d.ts +4 -0
  107. package/dist/components/dropdown-select/dropdown-select.svelte.js +48 -0
  108. package/dist/components/dropdown-select/index.d.ts +2 -0
  109. package/dist/components/dropdown-select/index.js +2 -0
  110. package/dist/components/dropdown-select/types.d.ts +46 -0
  111. package/dist/components/dropdown-select/types.js +1 -0
  112. package/dist/components/expander/docs/llms.md +88 -0
  113. package/dist/components/expander/expander.svelte +249 -0
  114. package/dist/components/expander/expander.svelte.d.ts +21 -0
  115. package/dist/components/expander/types.d.ts +47 -0
  116. package/dist/components/expander/types.js +1 -0
  117. package/dist/components/flyout/docs/llms.md +31 -0
  118. package/dist/components/flyout/flyout.svelte +148 -0
  119. package/dist/components/flyout/flyout.svelte.d.ts +19 -0
  120. package/dist/components/flyout/types.d.ts +36 -0
  121. package/dist/components/flyout/types.js +1 -0
  122. package/dist/components/hyperlink/docs/llms.md +33 -0
  123. package/dist/components/hyperlink/hyperlink.svelte +66 -0
  124. package/dist/components/hyperlink/hyperlink.svelte.d.ts +16 -0
  125. package/dist/components/hyperlink/types.d.ts +14 -0
  126. package/dist/components/hyperlink/types.js +1 -0
  127. package/dist/components/info-bar/docs/llms.md +81 -0
  128. package/dist/components/info-bar/info-bar.svelte +140 -0
  129. package/dist/components/info-bar/info-bar.svelte.d.ts +19 -0
  130. package/dist/components/info-bar/types.d.ts +27 -0
  131. package/dist/components/info-bar/types.js +1 -0
  132. package/dist/components/label/docs/llms.md +67 -0
  133. package/dist/components/label/label.svelte +95 -0
  134. package/dist/components/label/label.svelte.d.ts +4 -0
  135. package/dist/components/label/types.d.ts +32 -0
  136. package/dist/components/label/types.js +1 -0
  137. package/dist/components/list-view/docs/llms.md +110 -0
  138. package/dist/components/list-view/list-view-item.svelte +168 -0
  139. package/dist/components/list-view/list-view-item.svelte.d.ts +25 -0
  140. package/dist/components/list-view/list-view.svelte +137 -0
  141. package/dist/components/list-view/list-view.svelte.d.ts +25 -0
  142. package/dist/components/list-view/types.d.ts +95 -0
  143. package/dist/components/list-view/types.js +1 -0
  144. package/dist/components/list-view/utils.d.ts +6 -0
  145. package/dist/components/list-view/utils.js +12 -0
  146. package/dist/components/menu/context-menu-trigger.svelte +84 -0
  147. package/dist/components/menu/context-menu-trigger.svelte.d.ts +9 -0
  148. package/dist/components/menu/docs/llms.md +169 -0
  149. package/dist/components/menu/menu-divider.svelte +9 -0
  150. package/dist/components/menu/menu-divider.svelte.d.ts +26 -0
  151. package/dist/components/menu/menu-group.svelte +31 -0
  152. package/dist/components/menu/menu-group.svelte.d.ts +4 -0
  153. package/dist/components/menu/menu-item-checkbox.svelte +143 -0
  154. package/dist/components/menu/menu-item-checkbox.svelte.d.ts +15 -0
  155. package/dist/components/menu/menu-item-radio.svelte +147 -0
  156. package/dist/components/menu/menu-item-radio.svelte.d.ts +15 -0
  157. package/dist/components/menu/menu-item-switch.svelte +194 -0
  158. package/dist/components/menu/menu-item-switch.svelte.d.ts +15 -0
  159. package/dist/components/menu/menu-item.svelte +124 -0
  160. package/dist/components/menu/menu-item.svelte.d.ts +18 -0
  161. package/dist/components/menu/menu-list.svelte +38 -0
  162. package/dist/components/menu/menu-list.svelte.d.ts +5 -0
  163. package/dist/components/menu/menu-popover.svelte +125 -0
  164. package/dist/components/menu/menu-popover.svelte.d.ts +12 -0
  165. package/dist/components/menu/menu-trigger.svelte +121 -0
  166. package/dist/components/menu/menu-trigger.svelte.d.ts +4 -0
  167. package/dist/components/menu/menu.svelte +124 -0
  168. package/dist/components/menu/menu.svelte.d.ts +4 -0
  169. package/dist/components/menu/menu.svelte.js +77 -0
  170. package/dist/components/menu/types.d.ts +127 -0
  171. package/dist/components/menu/types.js +1 -0
  172. package/dist/components/number-box/docs/llms.md +37 -0
  173. package/dist/components/number-box/number-box.svelte +115 -0
  174. package/dist/components/number-box/number-box.svelte.d.ts +15 -0
  175. package/dist/components/number-box/types.d.ts +16 -0
  176. package/dist/components/number-box/types.js +1 -0
  177. package/dist/components/persona/docs/llms.md +107 -0
  178. package/dist/components/persona/persona.svelte +79 -0
  179. package/dist/components/persona/persona.svelte.d.ts +4 -0
  180. package/dist/components/persona/types.d.ts +42 -0
  181. package/dist/components/persona/types.js +1 -0
  182. package/dist/components/progress-bar/docs/llms.md +67 -0
  183. package/dist/components/progress-bar/progress-bar.svelte +167 -0
  184. package/dist/components/progress-bar/progress-bar.svelte.d.ts +15 -0
  185. package/dist/components/progress-bar/types.d.ts +39 -0
  186. package/dist/components/progress-bar/types.js +1 -0
  187. package/dist/components/progress-ring/docs/llms.md +76 -0
  188. package/dist/components/progress-ring/progress-ring.svelte +145 -0
  189. package/dist/components/progress-ring/progress-ring.svelte.d.ts +15 -0
  190. package/dist/components/progress-ring/types.d.ts +42 -0
  191. package/dist/components/progress-ring/types.js +1 -0
  192. package/dist/components/radio-button/docs/llms.md +64 -0
  193. package/dist/components/radio-button/radio-button.svelte +129 -0
  194. package/dist/components/radio-button/radio-button.svelte.d.ts +19 -0
  195. package/dist/components/radio-button/types.d.ts +24 -0
  196. package/dist/components/radio-button/types.js +1 -0
  197. package/dist/components/skeleton/docs/llms.md +67 -0
  198. package/dist/components/skeleton/skeleton.svelte +106 -0
  199. package/dist/components/skeleton/skeleton.svelte.d.ts +39 -0
  200. package/dist/components/skeleton/types.d.ts +24 -0
  201. package/dist/components/skeleton/types.js +1 -0
  202. package/dist/components/slider/docs/llms.md +75 -0
  203. package/dist/components/slider/slider.svelte +486 -0
  204. package/dist/components/slider/slider.svelte.d.ts +19 -0
  205. package/dist/components/slider/types.d.ts +102 -0
  206. package/dist/components/slider/types.js +1 -0
  207. package/dist/components/text-box/docs/llms.md +86 -0
  208. package/dist/components/text-box/text-box-button.svelte +65 -0
  209. package/dist/components/text-box/text-box-button.svelte.d.ts +9 -0
  210. package/dist/components/text-box/text-box.svelte +299 -0
  211. package/dist/components/text-box/text-box.svelte.d.ts +16 -0
  212. package/dist/components/text-box/types.d.ts +60 -0
  213. package/dist/components/text-box/types.js +1 -0
  214. package/dist/components/textarea/docs/llms.md +55 -0
  215. package/dist/components/textarea/textarea.svelte +151 -0
  216. package/dist/components/textarea/textarea.svelte.d.ts +17 -0
  217. package/dist/components/textarea/types.d.ts +33 -0
  218. package/dist/components/textarea/types.js +1 -0
  219. package/dist/components/time-picker/docs/llms.md +47 -0
  220. package/dist/components/time-picker/index.d.ts +1 -0
  221. package/dist/components/time-picker/index.js +1 -0
  222. package/dist/components/time-picker/time-picker.svelte +336 -0
  223. package/dist/components/time-picker/time-picker.svelte.d.ts +4 -0
  224. package/dist/components/time-picker/types.d.ts +54 -0
  225. package/dist/components/time-picker/types.js +1 -0
  226. package/dist/components/toggle-switch/docs/llms.md +39 -0
  227. package/dist/components/toggle-switch/toggle-switch.svelte +151 -0
  228. package/dist/components/toggle-switch/toggle-switch.svelte.d.ts +17 -0
  229. package/dist/components/toggle-switch/types.d.ts +20 -0
  230. package/dist/components/toggle-switch/types.js +1 -0
  231. package/dist/components/tooltip/docs/llms.md +74 -0
  232. package/dist/components/tooltip/tooltip.svelte +246 -0
  233. package/dist/components/tooltip/tooltip.svelte.d.ts +18 -0
  234. package/dist/components/tooltip/types.d.ts +67 -0
  235. package/dist/components/tooltip/types.js +1 -0
  236. package/dist/components/tree-view/docs/llms.md +117 -0
  237. package/dist/components/tree-view/tree-view-item-content.svelte +158 -0
  238. package/dist/components/tree-view/tree-view-item-content.svelte.d.ts +4 -0
  239. package/dist/components/tree-view/tree-view-item.svelte +197 -0
  240. package/dist/components/tree-view/tree-view-item.svelte.d.ts +4 -0
  241. package/dist/components/tree-view/tree-view.svelte +220 -0
  242. package/dist/components/tree-view/tree-view.svelte.d.ts +4 -0
  243. package/dist/components/tree-view/tree-view.svelte.js +111 -0
  244. package/dist/components/tree-view/types.d.ts +185 -0
  245. package/dist/components/tree-view/types.js +1 -0
  246. package/dist/css/class-darkmode.css +186 -0
  247. package/dist/css/media-darkmode.css +189 -0
  248. package/dist/css/reset.css +53 -0
  249. package/dist/css/theme.css +276 -0
  250. package/dist/css/typography.css +67 -0
  251. package/dist/css/utils.d.ts +1 -0
  252. package/dist/css/utils.js +153 -0
  253. package/dist/index.d.ts +63 -0
  254. package/dist/index.js +129 -0
  255. package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte +449 -0
  256. package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte.d.ts +22 -0
  257. package/dist/internal/components/render-soc/render-soc.svelte +29 -0
  258. package/dist/internal/components/render-soc/render-soc.svelte.d.ts +30 -0
  259. package/dist/internal/constants.d.ts +26 -0
  260. package/dist/internal/constants.js +4036 -0
  261. package/dist/internal/context.d.ts +14 -0
  262. package/dist/internal/context.js +13 -0
  263. package/dist/internal/dom-utils.svelte.d.ts +6 -0
  264. package/dist/internal/dom-utils.svelte.js +46 -0
  265. package/dist/internal/floating-ui/floating.svelte.d.ts +15 -0
  266. package/dist/internal/floating-ui/floating.svelte.js +26 -0
  267. package/dist/internal/floating-ui/utils.d.ts +3 -0
  268. package/dist/internal/floating-ui/utils.js +30 -0
  269. package/dist/internal/index.d.ts +9 -0
  270. package/dist/internal/index.js +9 -0
  271. package/dist/internal/polyfills/expander.svelte.d.ts +21 -0
  272. package/dist/internal/polyfills/expander.svelte.js +96 -0
  273. package/dist/internal/transitions.d.ts +32 -0
  274. package/dist/internal/transitions.js +37 -0
  275. package/dist/internal/utils.d.ts +22 -0
  276. package/dist/internal/utils.js +63 -0
  277. package/dist/providers/fluentui-svelte/fluentui-svelte.d.ts +19 -0
  278. package/dist/providers/fluentui-svelte/fluentui-svelte.js +11 -0
  279. package/dist/providers/fluentui-svelte/fluentui-svelte.svelte +68 -0
  280. package/dist/providers/fluentui-svelte/fluentui-svelte.svelte.d.ts +9 -0
  281. package/dist/types/index.d.ts +117 -0
  282. package/dist/types/index.js +1 -0
  283. package/package.json +142 -0
@@ -0,0 +1,117 @@
1
+ # Tree View
2
+
3
+ The Tree View displays hierarchical data in a nested list where each item can be expanded, checked or selected. Items are composed with the TreeViewItem and TreeViewItemContent components — the tree does not accept a data prop.
4
+
5
+ > **Early access:** The API, features, and behavior of the component are subject to significant changes. We strongly advise against using this component in production environments at this time.
6
+
7
+ ## Usage
8
+
9
+ ```svelte
10
+ <script>
11
+ import { TreeView, TreeViewItem, TreeViewItemContent } from 'fluentui-svelte';
12
+ </script>
13
+
14
+ <TreeView selectionMode="multiple">
15
+ <TreeViewItem id="fruits" type="branch">
16
+ <TreeViewItemContent>Fruits</TreeViewItemContent>
17
+ <TreeView>
18
+ <TreeViewItem id="apple">
19
+ <TreeViewItemContent>Apple</TreeViewItemContent>
20
+ </TreeViewItem>
21
+ <TreeViewItem id="banana" disabled>
22
+ <TreeViewItemContent>Banana</TreeViewItemContent>
23
+ </TreeViewItem>
24
+ </TreeView>
25
+ </TreeViewItem>
26
+ <TreeViewItem id="vegetables">
27
+ <TreeViewItemContent>Vegetables</TreeViewItemContent>
28
+ </TreeViewItem>
29
+ </TreeView>
30
+ ```
31
+
32
+ Nesting a TreeView inside a TreeViewItem of type='branch' creates a subtree. Use openItems / checkedItems on the root TreeView (bindable) to control open and checked state programmatically.
33
+
34
+ ## Examples
35
+
36
+ ### Checkable Items
37
+
38
+ Set `selectionMode="multiple"` to render checkboxes on selectable items.
39
+
40
+ ```svelte
41
+ <TreeView selectionMode="multiple">
42
+ <TreeViewItem id="fruits" type="branch">
43
+ <TreeViewItemContent>Fruits</TreeViewItemContent>
44
+ <TreeView>
45
+ <TreeViewItem id="apple">
46
+ <TreeViewItemContent>Apple</TreeViewItemContent>
47
+ </TreeViewItem>
48
+ </TreeView>
49
+ </TreeViewItem>
50
+ </TreeView>
51
+ ```
52
+
53
+ ### Controlling Open and Checked State
54
+
55
+ Use the bindable `openItems` and `checkedItems` props on the root `TreeView` to control state programmatically.
56
+
57
+ ```svelte
58
+ <script>
59
+ let openItems = $state(['fruits']);
60
+ let checkedItems = $state([]);
61
+ </script>
62
+
63
+ <TreeView bind:openItems bind:checkedItems selectionMode="multiple">
64
+ <TreeViewItem id="fruits" type="branch">
65
+ <TreeViewItemContent>Fruits</TreeViewItemContent>
66
+ <TreeView>
67
+ <TreeViewItem id="apple">
68
+ <TreeViewItemContent>Apple</TreeViewItemContent>
69
+ </TreeViewItem>
70
+ </TreeView>
71
+ </TreeViewItem>
72
+ </TreeView>
73
+ ```
74
+
75
+ ## Component Props (TreeView)
76
+
77
+ | Name | Type | Description |
78
+ | ----------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
79
+ | `ref` | `HTMLUListElement` | Bindable DOM reference of the root ul element. |
80
+ | `size` | `'small' \| 'medium' \| 'large'` | Visual size of the tree. Default is 'medium'. |
81
+ | `navigationMode` | `'tree' \| 'treegrid'` | Keyboard navigation mode. Default is 'tree'. |
82
+ | `selectionMode` | `'single' \| 'multiple'` | Selection mode for checkable items. Default is 'multiple'. |
83
+ | `openItems` | `string[] \| SvelteSet<string>` | Bindable list or set of open item ids. Uses SvelteSet when a virtualizer is provided. |
84
+ | `checkedItems` | `string[] \| SvelteSet<string>` | Bindable list or set of checked item ids. Uses SvelteSet when a virtualizer is provided. |
85
+ | `onOpenChange` | `(e: Event, openItems: string[]) => void` | Callback fired when an item is expanded or collapsed. |
86
+ | `onCheckedChange` | `(e: Event, checkedItems: string[]) => void` | Callback fired when an item is checked or unchecked. |
87
+ | `virtualizer` | `TreeViewVirtualizer` | Optional adapter for windowing or virtual list libraries. When provided, only the rendered slice is in the DOM. |
88
+ | `children` | `Snippet` | The TreeViewItem children of the tree. |
89
+
90
+ ## Component Props (TreeViewItem)
91
+
92
+ | Name | Type | Description |
93
+ | ----------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
94
+ | `id` | `string` | Unique identifier of the item. Required for open and checked state tracking. |
95
+ | `type` | `'item' \| 'branch'` | Whether the item is a leaf ('item') or a branch that can contain a nested TreeView. |
96
+ | `ref` | `HTMLLIElement` | Bindable DOM reference of the li element. |
97
+ | `value` | `string \| number` | Optional value associated with the item. |
98
+ | `text` | `string` | Optional accessible text label used by the tree. |
99
+ | `open` | `boolean` | Bindable open state for type='branch' items. |
100
+ | `checked` | `boolean` | Bindable checked state for selectable items. |
101
+ | `indeterminate` | `boolean` | Whether the item is in an indeterminate check state. |
102
+ | `disabled` | `boolean` | Disables the item. |
103
+ | `index` | `number` | Explicit index — used with a virtualizer to keep keyboard navigation in sync. |
104
+ | `onOpenChange` | `(e: Event, data: { id: string; open: boolean }) => void` | Callback fired when this item is expanded or collapsed. |
105
+ | `onCheckedChange` | `(e: Event, data: { id: string; checked: boolean }) => void` | Callback fired when this item is checked or unchecked. |
106
+
107
+ ## Component Props (TreeViewItemContent)
108
+
109
+ | Name | Type | Description |
110
+ | ------------ | ---------------------- | ----------------------------------------------------------- |
111
+ | `ref` | `HTMLDivElement` | Bindable DOM reference of the layout element. |
112
+ | `expandIcon` | `Snippet \| Component` | Custom icon rendered for the expand or collapse affordance. |
113
+ | `iconBefore` | `Snippet \| Component` | Icon rendered before the item text. |
114
+ | `iconAfter` | `Snippet \| Component` | Icon rendered after the item text. |
115
+ | `aside` | `Snippet \| Component` | Content rendered on the trailing side of the row. |
116
+ | `actions` | `Snippet \| Component` | Interactive actions rendered on hover or focus. |
117
+ | `children` | `Snippet` | The item label content. |
@@ -0,0 +1,158 @@
1
+ <script lang="ts">
2
+ import { Checkbox } from '../../index.js';
3
+ import { RenderSoC } from '../../internal/index.js';
4
+ import ChevronRightRegular from 'fluentui-icons-svelte/ChevronRightRegular.svelte';
5
+ import { getTreeViewContext, getTreeViewItemContext } from './tree-view.svelte.js';
6
+ import type { TreeViewItemLayoutProps } from './types.js';
7
+
8
+ let { actions, aside, expandIcon, iconBefore, iconAfter, ref, children, ...attributes }: TreeViewItemLayoutProps =
9
+ $props();
10
+
11
+ const TREE_VIEW_CONTEXT = getTreeViewContext();
12
+ const ITEM_CONTEXT = getTreeViewItemContext();
13
+
14
+ if (!TREE_VIEW_CONTEXT) throw new Error('TreeViewItemLayout must be used within a TreeView');
15
+ if (!ITEM_CONTEXT) throw new Error('TreeViewItemContent must be used within a TreeViewItem');
16
+
17
+ const { config, methods } = TREE_VIEW_CONTEXT;
18
+
19
+ const { size } = config;
20
+
21
+ const { handleCheck } = methods;
22
+ </script>
23
+
24
+ <!-- Presentational row. The interactive element is the parent treeitem (`<li>`); this
25
+ div is plain markup so it is not exposed as a separate control. -->
26
+ <div
27
+ class={['fs-tree-view-item-content', `size-${size}`, ITEM_CONTEXT.disabled && 'disabled']}
28
+ style="--depth: {ITEM_CONTEXT.depth}"
29
+ bind:this={ref}
30
+ {...attributes}
31
+ >
32
+ {#if expandIcon}
33
+ <span class="fs-tree-view-item-expand-icon">
34
+ <RenderSoC SoC={expandIcon} />
35
+ </span>
36
+ {/if}
37
+
38
+ {#if ITEM_CONTEXT.type === 'branch'}
39
+ <ChevronRightRegular width="1.2rem" class="branch-indicator" />
40
+ {/if}
41
+
42
+ <Checkbox
43
+ hidden
44
+ checked={ITEM_CONTEXT.checked}
45
+ indeterminate={ITEM_CONTEXT.indeterminate}
46
+ disabled={ITEM_CONTEXT.disabled}
47
+ wrapperAttributes={{
48
+ onclick: (e) => {
49
+ e.stopPropagation();
50
+ if (ITEM_CONTEXT.disabled) {
51
+ e.preventDefault();
52
+ return;
53
+ }
54
+ handleCheck(e, ITEM_CONTEXT.id, !ITEM_CONTEXT.checked);
55
+ }
56
+ }}
57
+ />
58
+
59
+ {#if iconBefore}
60
+ <span class="fs-tree-view-item-icon-before">
61
+ <RenderSoC SoC={iconBefore} />
62
+ </span>
63
+ {/if}
64
+
65
+ <span class="fs-tree-view-item-label" id="{ITEM_CONTEXT.id}-label">
66
+ {@render children?.()}
67
+ </span>
68
+
69
+ {#if iconAfter}
70
+ <span class="fs-tree-view-item-icon-after">
71
+ <RenderSoC SoC={iconAfter} />
72
+ </span>
73
+ {/if}
74
+
75
+ {#if aside}
76
+ <span class="fs-tree-view-item-aside">
77
+ <RenderSoC SoC={aside} />
78
+ </span>
79
+ {/if}
80
+
81
+ {#if actions}
82
+ <span class="fs-tree-view-item-actions">
83
+ <RenderSoC SoC={actions} />
84
+ </span>
85
+ {/if}
86
+ </div>
87
+
88
+ <style>
89
+ .fs-tree-view-item-content {
90
+ display: flex;
91
+ align-items: center;
92
+ gap: 0.75rem;
93
+ position: relative;
94
+ border-radius: var(--fs-control-border-radius);
95
+ font-size: var(--fs-body-font-size);
96
+ cursor: pointer;
97
+ outline: none;
98
+ background: none;
99
+ border: none;
100
+ width: 100%;
101
+ text-align: left;
102
+ user-select: none;
103
+ &.size-small {
104
+ font-size: var(--fs-body2-font-size);
105
+ padding: 0.125rem 0.5rem;
106
+ padding-left: calc(0.5rem + 1.5rem * var(--depth, 0));
107
+ }
108
+ &.size-medium {
109
+ font-size: var(--fs-body-font-size);
110
+ padding: 0.25rem 0.625rem;
111
+ padding-left: calc(0.625rem + 1.5rem * var(--depth, 0));
112
+ }
113
+ &.size-large {
114
+ font-size: var(--fs-subtitle2-font-size);
115
+ padding: 0.375rem 0.75rem;
116
+ padding-left: calc(0.75rem + 1.5rem * var(--depth, 0));
117
+ }
118
+
119
+ &::after {
120
+ content: '';
121
+ display: block;
122
+ width: 0.188rem;
123
+ height: 0;
124
+ background-color: var(--fs-accent-fill-default);
125
+ position: absolute;
126
+ left: 0;
127
+ top: 50%;
128
+ transform: translateY(-50%);
129
+ border-radius: 1rem;
130
+ transition: height 0.2s ease-in-out;
131
+ }
132
+
133
+ &:hover {
134
+ background-color: var(--fs-subtle-fill-secondary);
135
+ }
136
+
137
+ &.selected {
138
+ background-color: var(--fs-subtle-fill-secondary);
139
+
140
+ &::after {
141
+ height: 50%;
142
+ }
143
+ }
144
+
145
+ &.disabled {
146
+ opacity: 0.4;
147
+ cursor: not-allowed;
148
+ pointer-events: none;
149
+ }
150
+
151
+ :global(.tree-view-item-icon) {
152
+ width: 1.25rem;
153
+ height: 1.25rem;
154
+ flex-shrink: 0;
155
+ fill: currentColor;
156
+ }
157
+ }
158
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { TreeViewItemLayoutProps } from './types.ts';
2
+ declare const TreeViewItemContent: import("svelte").Component<TreeViewItemLayoutProps, {}, "">;
3
+ type TreeViewItemContent = ReturnType<typeof TreeViewItemContent>;
4
+ export default TreeViewItemContent;
@@ -0,0 +1,197 @@
1
+ <script lang="ts">
2
+ import { onMount, tick } from 'svelte';
3
+ import { PREFIX } from '../../internal/constants.js';
4
+ import {
5
+ getTreeViewDepth,
6
+ getTreeViewContext,
7
+ setTreeViewItemContext,
8
+ getTreeViewItemContext
9
+ } from './tree-view.svelte.js';
10
+ import type { TreeViewItemContext, TreeViewItemProps } from './types.js';
11
+
12
+ const COMPONENT_NAME = 'TreeViewItem';
13
+ const FALLBACK_ID = $props.id();
14
+ const ID = `${PREFIX}-${COMPONENT_NAME}-${FALLBACK_ID}`;
15
+
16
+ const context = getTreeViewContext();
17
+
18
+ const itemContext = getTreeViewItemContext();
19
+
20
+ if (!context) throw new Error('TreeViewItem must be used within a TreeView');
21
+
22
+ // Honor the `checked` and `open` props if provided, otherwise derive them from the parent tree's state.
23
+ const { checkedItems, openItems } = context.state;
24
+
25
+ let {
26
+ ref,
27
+ index,
28
+ id = ID,
29
+ disabled,
30
+ value = id,
31
+ indeterminate,
32
+ type = 'item',
33
+ open = (openItems instanceof Set ? openItems.has(id) : openItems.includes(id)) || undefined,
34
+ checked = (checkedItems instanceof Set ? checkedItems.has(id) : checkedItems.includes(id)) || undefined,
35
+ children,
36
+ ...attributes
37
+ }: TreeViewItemProps = $props();
38
+
39
+ const depth = getTreeViewDepth() ?? 0;
40
+
41
+ const { config, methods } = context;
42
+
43
+ const { size } = config;
44
+
45
+ const itemState: TreeViewItemContext = {
46
+ get disabled() {
47
+ return itemContext?.disabled ?? disabled;
48
+ },
49
+ get depth() {
50
+ return depth;
51
+ },
52
+ get value() {
53
+ return value;
54
+ },
55
+ get id() {
56
+ return id;
57
+ },
58
+ get type() {
59
+ return type;
60
+ },
61
+ get parentId() {
62
+ return itemContext?.id;
63
+ },
64
+ get open() {
65
+ return open;
66
+ },
67
+ set open(v) {
68
+ open = v;
69
+ },
70
+ get checked() {
71
+ return checked;
72
+ },
73
+ set checked(v) {
74
+ checked = v;
75
+ },
76
+ get indeterminate() {
77
+ return indeterminate;
78
+ },
79
+ set indeterminate(v) {
80
+ indeterminate = v;
81
+ }
82
+ };
83
+
84
+ setTreeViewItemContext(itemState);
85
+
86
+ // Virtualized tree: the windowing library mounts/unmounts (and may reuse) rows as it
87
+ // scrolls, so register via an effect that re-runs when the identity changes and cleans
88
+ // up the previous id.
89
+ if (config.virtualized && !itemContext) {
90
+ $effect(() => {
91
+ const _id: string = id;
92
+
93
+ methods.registerItem(itemState);
94
+ return () => methods.unregisterItem(_id);
95
+ });
96
+ } else {
97
+ // Static tree: register this node once so a branch's tri-state can be derived from its
98
+ // descendants.
99
+ onMount(() => {
100
+ methods.registerItem(itemState);
101
+ return () => methods.unregisterItem(id);
102
+ });
103
+ }
104
+
105
+ const isBranch = $derived(type === 'branch');
106
+ const isVirtualRoot = $derived(config.virtualized && !itemContext);
107
+
108
+ const handleClick = (e: MouseEvent) => {
109
+ if (itemState.disabled) return;
110
+ // Ignore clicks bubbling up from a descendant treeitem's own row.
111
+ if ((e.target as HTMLElement).closest('.fs-tree-view-item') !== e.currentTarget) return;
112
+ if (isBranch) {
113
+ if (open) methods.closeItem(e, id);
114
+ else methods.openItem(e, id);
115
+ } else {
116
+ methods.handleCheck(e, id, !checked);
117
+ }
118
+ };
119
+
120
+ const handleKeydown = async (e: KeyboardEvent) => {
121
+ if (e.target !== e.currentTarget || itemState.disabled) return;
122
+
123
+ switch (e.key) {
124
+ case 'Enter':
125
+ case ' ':
126
+ e.preventDefault();
127
+ methods.handleCheck(e, id, !checked);
128
+ break;
129
+ case 'ArrowRight':
130
+ if (isBranch && !open) {
131
+ methods.openItem(e, id);
132
+
133
+ // NOTE: This apparently works, maybe the problem is that TabSpot is losing the order of the items...
134
+ // TODO: investigate further.
135
+ if (config.virtualized) {
136
+ await tick();
137
+
138
+ const firstChildElement = ref?.querySelector(
139
+ `:scope .fs-tree-view-item:not([aria-disabled="true"])[aria-level="${depth + 2}"]`
140
+ ) as HTMLElement;
141
+
142
+ firstChildElement?.focus();
143
+ return;
144
+ }
145
+ }
146
+ break;
147
+ case 'ArrowLeft':
148
+ if (itemContext?.id) {
149
+ methods.closeItem(e, itemContext?.id);
150
+ }
151
+ break;
152
+ }
153
+ };
154
+ </script>
155
+
156
+ <li
157
+ {id}
158
+ class={['fs-tree-view-item', `fs-tree-item-size-${size}`, { open }]}
159
+ style="--depth: {depth}"
160
+ role="treeitem"
161
+ aria-expanded={type === 'branch' ? open : undefined}
162
+ aria-checked={indeterminate ? 'mixed' : checked}
163
+ aria-level={depth + 1}
164
+ aria-labelledby="{id}-label"
165
+ data-index={isVirtualRoot ? index : undefined}
166
+ data-value={value}
167
+ aria-disabled={itemState.disabled ? 'true' : undefined}
168
+ onclick={handleClick}
169
+ onkeydown={handleKeydown}
170
+ bind:this={ref}
171
+ {...attributes}
172
+ >
173
+ {@render children?.()}
174
+ </li>
175
+
176
+ <style>
177
+ .fs-tree-view-item {
178
+ list-style: none;
179
+ display: flex;
180
+ flex-direction: column;
181
+ /* The treeitem itself is the focus target; suppress its outline and show the
182
+ focus ring on its row instead. */
183
+ outline: none;
184
+ &:not(.open) :global(.fs-tree-view) {
185
+ height: 0;
186
+ overflow: hidden;
187
+ opacity: 0;
188
+ }
189
+ &:focus-visible > :global(.fs-tree-view-item-content) {
190
+ outline: 2px solid var(--fs-focus-stroke-outer);
191
+ outline-offset: 2px;
192
+ }
193
+ &.open :global(.branch-indicator) {
194
+ rotate: 90deg;
195
+ }
196
+ }
197
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { TreeViewItemProps } from './types.ts';
2
+ declare const TreeViewItem: import("svelte").Component<TreeViewItemProps, {}, "">;
3
+ type TreeViewItem = ReturnType<typeof TreeViewItem>;
4
+ export default TreeViewItem;
@@ -0,0 +1,220 @@
1
+ <script lang="ts">
2
+ import { onMount, tick } from 'svelte';
3
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
4
+ import { getTabspotAttributes, tabspotVirtual } from 'tabspot';
5
+ import {
6
+ getTreeViewContext,
7
+ getTreeViewDepth,
8
+ setTreeViewContext,
9
+ setTreeViewDepth,
10
+ getTreeViewItemContext,
11
+ traversalSync,
12
+ traversalSyncSingleSelection
13
+ } from './tree-view.svelte.js';
14
+ import type { TreeViewProps, TreeViewContext, TreeViewNode } from './types.js';
15
+
16
+ const CONTEXT = getTreeViewContext();
17
+ const TREE_NODES = new SvelteMap<string, TreeViewNode>();
18
+ const DEPTH = getTreeViewDepth() || 0;
19
+ const ITEM_CONTEXT = getTreeViewItemContext();
20
+ const IS_SUB_TREE = $derived(!!CONTEXT);
21
+
22
+ if (CONTEXT) setTreeViewDepth(DEPTH + 1);
23
+
24
+ let {
25
+ virtualizer,
26
+ navigationMode = CONTEXT?.config.navigationMode ?? 'tree',
27
+ checkedItems = $bindable(CONTEXT?.state.checkedItems ?? (virtualizer !== undefined ? new SvelteSet<string>() : [])),
28
+ openItems = $bindable(CONTEXT?.state.openItems ?? (virtualizer !== undefined ? new SvelteSet<string>() : [])),
29
+ ref = $bindable(),
30
+ onOpenChange,
31
+ onCheckedChange,
32
+ selectionMode = CONTEXT?.state.selectionMode ?? 'multiple',
33
+ size = 'medium',
34
+ children,
35
+ ...attributes
36
+ }: TreeViewProps = $props();
37
+
38
+ const config: TreeViewContext['config'] = $derived({
39
+ navigationMode: CONTEXT?.config.navigationMode || navigationMode,
40
+ size: CONTEXT?.config.size || size,
41
+ virtualized: CONTEXT?.config.virtualized ?? !!virtualizer,
42
+ virtualCount: CONTEXT?.config.virtualCount ?? virtualizer?.size
43
+ });
44
+
45
+ let forceVirtualRender = $state(false);
46
+
47
+ const _state: TreeViewContext['state'] = {
48
+ get openItems() {
49
+ return openItems;
50
+ },
51
+ get checkedItems() {
52
+ return checkedItems;
53
+ },
54
+ get selectionMode() {
55
+ return selectionMode;
56
+ },
57
+ get TREE_NODES() {
58
+ return CONTEXT?.state.TREE_NODES ?? TREE_NODES;
59
+ },
60
+ get forceVirtualRender() {
61
+ return CONTEXT?.state.forceVirtualRender ?? forceVirtualRender;
62
+ },
63
+ set forceVirtualRender(v) {
64
+ if (CONTEXT?.state.forceVirtualRender) {
65
+ CONTEXT.state.forceVirtualRender = v;
66
+ } else {
67
+ forceVirtualRender = v;
68
+ }
69
+ }
70
+ };
71
+
72
+ const events: TreeViewContext['events'] = $derived({
73
+ onCheckedChange: CONTEXT?.events.onCheckedChange ?? ((e, data) => onCheckedChange?.(e, data)),
74
+ onOpenChange: CONTEXT?.events.onOpenChange ?? ((e, data) => onOpenChange?.(e, data))
75
+ });
76
+
77
+ const methods: TreeViewContext['methods'] = {
78
+ handleCheck: async (e, id, checked) => {
79
+ if (virtualizer) {
80
+ _state.forceVirtualRender = true;
81
+ await tick();
82
+ }
83
+
84
+ if (_state.selectionMode === 'single') {
85
+ traversalSyncSingleSelection(id, _state.TREE_NODES, checkedItems);
86
+ return;
87
+ }
88
+
89
+ traversalSync(id, _state.TREE_NODES, checkedItems, checked);
90
+ },
91
+ openItem: (e, id) => {
92
+ if (openItems instanceof SvelteSet) {
93
+ openItems.add(id);
94
+ } else {
95
+ openItems = [...openItems, id];
96
+ }
97
+ const node = _state.TREE_NODES.get(id)!;
98
+
99
+ node.open = true;
100
+ },
101
+ closeItem: (e, id) => {
102
+ if (openItems instanceof SvelteSet) {
103
+ openItems.delete(id);
104
+ } else {
105
+ openItems = openItems.filter((itemId) => itemId !== id);
106
+ }
107
+ const node = _state.TREE_NODES.get(id)!;
108
+
109
+ node.open = false;
110
+
111
+ // If
112
+ if (virtualizer && _state.forceVirtualRender) {
113
+ _state.forceVirtualRender = false;
114
+ }
115
+ },
116
+ registerItem: (node) => {
117
+ _state.TREE_NODES.set(node.id, node);
118
+ },
119
+ unregisterItem: (id) => {
120
+ _state.TREE_NODES.delete(id);
121
+ }
122
+ };
123
+
124
+ const treeViewContext: TreeViewContext = {
125
+ get config() {
126
+ return config;
127
+ },
128
+ get state() {
129
+ return _state;
130
+ },
131
+ get events() {
132
+ return events;
133
+ },
134
+ get methods() {
135
+ return methods;
136
+ }
137
+ };
138
+
139
+ setTreeViewContext(treeViewContext);
140
+
141
+ const tabspotAttributes = $derived(
142
+ !IS_SUB_TREE
143
+ ? getTabspotAttributes({
144
+ root: {
145
+ manageSpecialKeys: true
146
+ },
147
+ mover: { axis: 'vertical', items: '.fs-tree-view-item', skip: '[aria-disabled="true"]' }
148
+ })
149
+ : getTabspotAttributes({
150
+ mover: { axis: 'vertical', items: '.fs-tree-view-item', skip: '[aria-disabled="true"]' },
151
+ grouper: { enterDirection: 'right', exitDirection: 'left' }
152
+ })
153
+ );
154
+
155
+ let typeBuffer = $state('');
156
+ let typeTimer: ReturnType<typeof setTimeout> | undefined = $state();
157
+
158
+ // APG type-ahead: typing printable characters moves focus to the next visible
159
+ // treeitem whose label starts with the typed string. Only the root tree listens;
160
+ // nav/activation keys are handled by tabspot and the treeitems themselves.
161
+ const handleTypeahead = (e: KeyboardEvent) => {
162
+ if (IS_SUB_TREE || !ref) return;
163
+ if (e.key.length !== 1 || e.key === ' ' || e.altKey || e.ctrlKey || e.metaKey) return;
164
+
165
+ typeBuffer += e.key.toLowerCase();
166
+ clearTimeout(typeTimer);
167
+ typeTimer = setTimeout(() => {
168
+ typeBuffer = '';
169
+ }, 500);
170
+
171
+ const items = Array.from(ref.querySelectorAll<HTMLElement>('.fs-tree-view-item')).filter((el) =>
172
+ el.checkVisibility ? el.checkVisibility() : el.offsetParent !== null
173
+ );
174
+ const start = items.indexOf(document.activeElement as HTMLElement);
175
+
176
+ for (let i = 1; i <= items.length; i++) {
177
+ const item = items[(start + i) % items.length];
178
+ const label = item.querySelector('.fs-tree-view-item-label')?.textContent?.trim().toLowerCase();
179
+ if (label?.startsWith(typeBuffer)) {
180
+ item.focus();
181
+ break;
182
+ }
183
+ }
184
+ };
185
+
186
+ // Add tabspot virtualizer for correct focus management
187
+ onMount(() => {
188
+ if (!IS_SUB_TREE || !ref || !virtualizer) return;
189
+ return tabspotVirtual(ref, {
190
+ scrollToIndex: (index) => virtualizer.scrollToIndex?.(index),
191
+ count: () => virtualizer.size
192
+ });
193
+ });
194
+ </script>
195
+
196
+ <!-- Render only when necessary (virtualizer perf) -->
197
+ {#if _state.forceVirtualRender || (config.virtualized && (!IS_SUB_TREE || ITEM_CONTEXT?.open)) || !config.virtualized}
198
+ <ul
199
+ class="fs-tree-view"
200
+ role={IS_SUB_TREE ? 'group' : 'tree'}
201
+ aria-multiselectable={selectionMode !== 'single'}
202
+ onkeydown={!IS_SUB_TREE ? handleTypeahead : undefined}
203
+ bind:this={ref}
204
+ {...tabspotAttributes}
205
+ {...attributes}
206
+ >
207
+ {@render children?.()}
208
+ </ul>
209
+ {/if}
210
+
211
+ <style>
212
+ .fs-tree-view {
213
+ display: flex;
214
+ flex-direction: column;
215
+ list-style: none;
216
+ padding: 0;
217
+ margin: 0;
218
+ gap: 0.125rem;
219
+ }
220
+ </style>