@svadmin/ui 0.73.0 → 0.74.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 (295) hide show
  1. package/README.md +53 -28
  2. package/dist/app.css +3733 -4119
  3. package/dist/app.theme.css +3733 -4119
  4. package/dist/component-registry.d.ts +14977 -0
  5. package/dist/component-registry.js +216 -0
  6. package/dist/components/AboutSettings.svelte +7 -1
  7. package/dist/components/AboutSettings.svelte.d.ts +4 -1
  8. package/dist/components/ActivityFeed.svelte +9 -3
  9. package/dist/components/ActivityFeed.svelte.d.ts +3 -0
  10. package/dist/components/AdminApp.svelte +19 -10
  11. package/dist/components/AdminApp.svelte.d.ts +6 -0
  12. package/dist/components/ApiSettings.svelte +41 -5
  13. package/dist/components/ApprovalCenter.svelte +283 -0
  14. package/dist/components/ApprovalCenter.svelte.d.ts +10 -0
  15. package/dist/components/AuditLogViewer.svelte +3 -1
  16. package/dist/components/AutoForm.svelte +33 -3
  17. package/dist/components/AutoForm.svelte.d.ts +1 -0
  18. package/dist/components/AutoTable.svelte +610 -47
  19. package/dist/components/AutoTable.svelte.d.ts +17 -1
  20. package/dist/components/BoundRecordDetailDrawer.svelte +9 -0
  21. package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +2 -0
  22. package/dist/components/Breadcrumbs.svelte +11 -1
  23. package/dist/components/CancelTaskButton.svelte +12 -42
  24. package/dist/components/ColorPicker.svelte +73 -0
  25. package/dist/components/ColorPicker.svelte.d.ts +15 -0
  26. package/dist/components/ComboboxField.svelte +114 -27
  27. package/dist/components/ComboboxField.svelte.d.ts +1 -0
  28. package/dist/components/DashboardView.svelte +99 -0
  29. package/dist/components/DashboardView.svelte.d.ts +14 -0
  30. package/dist/components/DatePicker.svelte +10 -0
  31. package/dist/components/DatePicker.svelte.d.ts +6 -0
  32. package/dist/components/DateRangeInput.svelte +85 -5
  33. package/dist/components/DateRangeInput.svelte.d.ts +10 -0
  34. package/dist/components/DateRangePicker.svelte +10 -0
  35. package/dist/components/DateRangePicker.svelte.d.ts +6 -0
  36. package/dist/components/DateTimeInput.svelte +74 -5
  37. package/dist/components/DateTimeInput.svelte.d.ts +8 -0
  38. package/dist/components/DateTimePicker.svelte +10 -0
  39. package/dist/components/DateTimePicker.svelte.d.ts +6 -0
  40. package/dist/components/DevTools.svelte +34 -26
  41. package/dist/components/DevframePanel.svelte +123 -0
  42. package/dist/components/DevframePanel.svelte.d.ts +3 -0
  43. package/dist/components/ErrorSummary.svelte +52 -0
  44. package/dist/components/ErrorSummary.svelte.d.ts +14 -0
  45. package/dist/components/FieldRenderer.svelte +82 -81
  46. package/dist/components/FileUpload.svelte +214 -52
  47. package/dist/components/FileUpload.svelte.d.ts +11 -0
  48. package/dist/components/FilterBuilder.svelte +88 -66
  49. package/dist/components/FilterCollectionInput.svelte +80 -0
  50. package/dist/components/FilterCollectionInput.svelte.d.ts +10 -0
  51. package/dist/components/GanttChart.svelte +66 -14
  52. package/dist/components/GanttChart.svelte.d.ts +6 -0
  53. package/dist/components/Header.svelte +18 -2
  54. package/dist/components/ImportWizard.svelte +339 -17
  55. package/dist/components/ImportWizard.svelte.d.ts +11 -0
  56. package/dist/components/JsonSchemaForm.svelte +120 -52
  57. package/dist/components/JsonSchemaForm.svelte.d.ts +7 -1
  58. package/dist/components/KanbanBoard.svelte +195 -40
  59. package/dist/components/KanbanBoard.svelte.d.ts +9 -2
  60. package/dist/components/Layout.svelte +4 -2
  61. package/dist/components/LazyAutoForm.svelte +28 -0
  62. package/dist/components/LazyAutoForm.svelte.d.ts +8 -0
  63. package/dist/components/LazyAutoTable.svelte +28 -0
  64. package/dist/components/LazyAutoTable.svelte.d.ts +8 -0
  65. package/dist/components/LazySettingsPage.svelte +28 -0
  66. package/dist/components/LazySettingsPage.svelte.d.ts +8 -0
  67. package/dist/components/LazyShowPage.svelte +28 -0
  68. package/dist/components/LazyShowPage.svelte.d.ts +8 -0
  69. package/dist/components/ListPage.svelte +5 -1
  70. package/dist/components/ListPage.svelte.d.ts +3 -0
  71. package/dist/components/LoginPage.svelte +1 -1
  72. package/dist/components/MultiTabKeepAlive.svelte +11 -6
  73. package/dist/components/NotificationsSettings.svelte +69 -2
  74. package/dist/components/NotificationsSettings.svelte.d.ts +25 -1
  75. package/dist/components/PermissionMatrix.svelte +20 -1
  76. package/dist/components/PivotExportButton.svelte +157 -0
  77. package/dist/components/PivotExportButton.svelte.d.ts +16 -0
  78. package/dist/components/PivotTable.svelte +229 -74
  79. package/dist/components/PivotTable.svelte.d.ts +19 -2
  80. package/dist/components/RadioGroup.svelte +121 -0
  81. package/dist/components/RadioGroup.svelte.d.ts +43 -0
  82. package/dist/components/RangeSlider.svelte +127 -0
  83. package/dist/components/RangeSlider.svelte.d.ts +22 -0
  84. package/dist/components/Rate.svelte +121 -0
  85. package/dist/components/Rate.svelte.d.ts +16 -0
  86. package/dist/components/RecordDetailDrawer.svelte +4 -2
  87. package/dist/components/RecordDetailDrawer.svelte.d.ts +2 -0
  88. package/dist/components/RelationPicker.svelte +341 -0
  89. package/dist/components/RelationPicker.svelte.d.ts +26 -0
  90. package/dist/components/ResourceOperationsPage.svelte +18 -18
  91. package/dist/components/ResourceOperationsPage.svelte.d.ts +2 -2
  92. package/dist/components/RetryTaskButton.svelte +12 -42
  93. package/dist/components/SecuritySettings.svelte +29 -5
  94. package/dist/components/SegmentedControl.svelte +145 -0
  95. package/dist/components/SegmentedControl.svelte.d.ts +38 -0
  96. package/dist/components/SettingsPage.svelte +3 -1
  97. package/dist/components/SettingsPage.svelte.d.ts +1 -0
  98. package/dist/components/ShowPage.svelte +18 -3
  99. package/dist/components/ShowPage.svelte.d.ts +3 -0
  100. package/dist/components/Sidebar.svelte +2 -2
  101. package/dist/components/Slider.svelte +100 -0
  102. package/dist/components/Slider.svelte.d.ts +19 -0
  103. package/dist/components/SpreadsheetView.svelte +1213 -95
  104. package/dist/components/SpreadsheetView.svelte.d.ts +19 -0
  105. package/dist/components/TagsInput.svelte +178 -0
  106. package/dist/components/TagsInput.svelte.d.ts +17 -0
  107. package/dist/components/TimePicker.svelte +10 -0
  108. package/dist/components/TimePicker.svelte.d.ts +6 -0
  109. package/dist/components/TreeSelect.svelte +267 -53
  110. package/dist/components/TreeSelect.svelte.d.ts +3 -0
  111. package/dist/components/TreeTable.svelte +484 -82
  112. package/dist/components/TreeTable.svelte.d.ts +24 -1
  113. package/dist/components/TwoFactorAuthPage.svelte +85 -48
  114. package/dist/components/TwoFactorAuthPage.svelte.d.ts +12 -1
  115. package/dist/components/VirtualTable.svelte +116 -20
  116. package/dist/components/VirtualTable.svelte.d.ts +5 -0
  117. package/dist/components/account/CompanyProfilePage.svelte +74 -38
  118. package/dist/components/account/GetStartedPage.svelte +2 -1
  119. package/dist/components/account/ImportMembersPage.svelte +22 -167
  120. package/dist/components/account/ImportMembersPage.svelte.d.ts +4 -1
  121. package/dist/components/account/MemberDirectory.svelte +156 -0
  122. package/dist/components/account/MemberDirectory.svelte.d.ts +19 -0
  123. package/dist/components/account/MembersStarterPage.svelte +9 -55
  124. package/dist/components/account/MembersStarterPage.svelte.d.ts +5 -1
  125. package/dist/components/account/SecurityLogPage.svelte +4 -1
  126. package/dist/components/account/SettingsPlainPage.svelte +7 -38
  127. package/dist/components/account/SettingsPlainPage.svelte.d.ts +4 -1
  128. package/dist/components/account/SettingsSidebarPage.svelte +7 -20
  129. package/dist/components/account/TeamMembersPage.svelte +4 -20
  130. package/dist/components/account/TeamMembersPage.svelte.d.ts +5 -1
  131. package/dist/components/account/UserProfilePage.svelte +3 -25
  132. package/dist/components/account/UserProfilePage.svelte.d.ts +17 -2
  133. package/dist/components/buttons/ExportButton.svelte +56 -12
  134. package/dist/components/buttons/ExportButton.svelte.d.ts +11 -0
  135. package/dist/components/content/ContentPageHeader.svelte +1 -1
  136. package/dist/components/content/ContentPageShell.svelte +1 -1
  137. package/dist/components/content/MetricBlock.svelte +1 -1
  138. package/dist/components/content/PageToolbar.svelte +1 -1
  139. package/dist/components/content/ReferenceNotice.svelte +5 -0
  140. package/dist/components/content/ReferenceNotice.svelte.d.ts +18 -0
  141. package/dist/components/content/SectionHeader.svelte +1 -1
  142. package/dist/components/content/SettingsFieldRow.svelte +1 -1
  143. package/dist/components/content/SettingsGroup.svelte +1 -1
  144. package/dist/components/content/StatusBadge.svelte +1 -1
  145. package/dist/components/content/WorkspaceLayout.svelte +1 -1
  146. package/dist/components/export-reference.d.ts +2 -0
  147. package/dist/components/export-reference.js +9 -0
  148. package/dist/components/fieldComponentMap.js +2 -5
  149. package/dist/components/fields/DateField.svelte +12 -13
  150. package/dist/components/fields/date-display.d.ts +6 -0
  151. package/dist/components/fields/date-display.js +24 -0
  152. package/dist/components/network/TeamCrewTablePage.svelte +6 -1
  153. package/dist/components/network/UserCardsNFTPage.svelte +2 -0
  154. package/dist/components/profile/PublicProfilePage.svelte +2 -0
  155. package/dist/components/saved-list-views.d.ts +74 -1
  156. package/dist/components/saved-list-views.js +191 -3
  157. package/dist/components/table-contract.d.ts +12 -1
  158. package/dist/components/task-action.svelte.d.ts +13 -0
  159. package/dist/components/task-action.svelte.js +73 -0
  160. package/dist/components/ui/DesignSystemShowcase.svelte +164 -0
  161. package/dist/components/ui/DesignSystemShowcase.svelte.d.ts +3 -0
  162. package/dist/components/ui/badge/badge-variants.d.ts +3 -2
  163. package/dist/components/ui/badge/badge-variants.js +2 -3
  164. package/dist/components/ui/badge/badge.svelte +3 -0
  165. package/dist/components/ui/badge/badge.svelte.d.ts +1 -0
  166. package/dist/components/ui/button/button-variants.d.ts +5 -4
  167. package/dist/components/ui/button/button-variants.js +7 -5
  168. package/dist/components/ui/checkbox/checkbox.svelte +5 -1
  169. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +5 -1
  170. package/dist/components/ui/input/input.svelte +7 -2
  171. package/dist/components/ui/input/input.svelte.d.ts +4 -1
  172. package/dist/components/ui/select/select.svelte +4 -1
  173. package/dist/components/ui/select/select.svelte.d.ts +2 -1
  174. package/dist/components/ui/textarea/textarea.svelte +2 -2
  175. package/dist/components.css +33 -2
  176. package/dist/date-input-policy.d.ts +4 -0
  177. package/dist/date-input-policy.js +35 -0
  178. package/dist/design-system-components.d.ts +100 -0
  179. package/dist/design-system-components.js +101 -0
  180. package/dist/design-system.js +1 -1
  181. package/dist/devtools-bridge.d.ts +80 -0
  182. package/dist/devtools-bridge.js +92 -0
  183. package/dist/index.d.ts +37 -2
  184. package/dist/index.js +23 -2
  185. package/dist/recipes.d.ts +960 -4
  186. package/dist/recipes.js +264 -4
  187. package/dist/tree-table-model.d.ts +24 -0
  188. package/dist/tree-table-model.js +111 -0
  189. package/package.json +22 -10
  190. package/dist/styled-system/css/conditions.js +0 -36
  191. package/dist/styled-system/css/css.d.ts +0 -22
  192. package/dist/styled-system/css/css.js +0 -45
  193. package/dist/styled-system/css/cva.d.ts +0 -6
  194. package/dist/styled-system/css/cva.js +0 -87
  195. package/dist/styled-system/css/cx.d.ts +0 -5
  196. package/dist/styled-system/css/cx.js +0 -15
  197. package/dist/styled-system/css/index.d.ts +0 -5
  198. package/dist/styled-system/css/index.js +0 -4
  199. package/dist/styled-system/css/sva.d.ts +0 -4
  200. package/dist/styled-system/css/sva.js +0 -46
  201. package/dist/styled-system/helpers.js +0 -316
  202. package/dist/styled-system/patterns/aspect-ratio.d.ts +0 -20
  203. package/dist/styled-system/patterns/aspect-ratio.js +0 -38
  204. package/dist/styled-system/patterns/bleed.d.ts +0 -21
  205. package/dist/styled-system/patterns/bleed.js +0 -24
  206. package/dist/styled-system/patterns/box.d.ts +0 -20
  207. package/dist/styled-system/patterns/box.js +0 -15
  208. package/dist/styled-system/patterns/center.d.ts +0 -20
  209. package/dist/styled-system/patterns/center.js +0 -21
  210. package/dist/styled-system/patterns/circle.d.ts +0 -20
  211. package/dist/styled-system/patterns/circle.js +0 -25
  212. package/dist/styled-system/patterns/container.d.ts +0 -20
  213. package/dist/styled-system/patterns/container.js +0 -21
  214. package/dist/styled-system/patterns/cq.d.ts +0 -21
  215. package/dist/styled-system/patterns/cq.js +0 -21
  216. package/dist/styled-system/patterns/divider.d.ts +0 -22
  217. package/dist/styled-system/patterns/divider.js +0 -25
  218. package/dist/styled-system/patterns/flex.d.ts +0 -26
  219. package/dist/styled-system/patterns/flex.js +0 -26
  220. package/dist/styled-system/patterns/float.d.ts +0 -23
  221. package/dist/styled-system/patterns/float.js +0 -52
  222. package/dist/styled-system/patterns/grid-item.d.ts +0 -25
  223. package/dist/styled-system/patterns/grid-item.js +0 -25
  224. package/dist/styled-system/patterns/grid.d.ts +0 -24
  225. package/dist/styled-system/patterns/grid.js +0 -27
  226. package/dist/styled-system/patterns/hstack.d.ts +0 -21
  227. package/dist/styled-system/patterns/hstack.js +0 -24
  228. package/dist/styled-system/patterns/index.d.ts +0 -21
  229. package/dist/styled-system/patterns/index.js +0 -20
  230. package/dist/styled-system/patterns/link-overlay.d.ts +0 -20
  231. package/dist/styled-system/patterns/link-overlay.js +0 -24
  232. package/dist/styled-system/patterns/spacer.d.ts +0 -20
  233. package/dist/styled-system/patterns/spacer.js +0 -25
  234. package/dist/styled-system/patterns/square.d.ts +0 -20
  235. package/dist/styled-system/patterns/square.js +0 -24
  236. package/dist/styled-system/patterns/stack.d.ts +0 -23
  237. package/dist/styled-system/patterns/stack.js +0 -24
  238. package/dist/styled-system/patterns/visually-hidden.d.ts +0 -20
  239. package/dist/styled-system/patterns/visually-hidden.js +0 -18
  240. package/dist/styled-system/patterns/vstack.d.ts +0 -21
  241. package/dist/styled-system/patterns/vstack.js +0 -24
  242. package/dist/styled-system/patterns/wrap.d.ts +0 -24
  243. package/dist/styled-system/patterns/wrap.js +0 -25
  244. package/dist/styled-system/recipes/content-header.d.ts +0 -31
  245. package/dist/styled-system/recipes/content-header.js +0 -65
  246. package/dist/styled-system/recipes/content-page.d.ts +0 -34
  247. package/dist/styled-system/recipes/content-page.js +0 -43
  248. package/dist/styled-system/recipes/create-recipe.js +0 -82
  249. package/dist/styled-system/recipes/index.d.ts +0 -17
  250. package/dist/styled-system/recipes/index.js +0 -16
  251. package/dist/styled-system/recipes/metric-block.d.ts +0 -34
  252. package/dist/styled-system/recipes/metric-block.js +0 -76
  253. package/dist/styled-system/recipes/product-list.d.ts +0 -31
  254. package/dist/styled-system/recipes/product-list.js +0 -73
  255. package/dist/styled-system/recipes/product-section.d.ts +0 -31
  256. package/dist/styled-system/recipes/product-section.js +0 -49
  257. package/dist/styled-system/recipes/product-settings-row.d.ts +0 -34
  258. package/dist/styled-system/recipes/product-settings-row.js +0 -58
  259. package/dist/styled-system/recipes/product-settings.d.ts +0 -31
  260. package/dist/styled-system/recipes/product-settings.js +0 -57
  261. package/dist/styled-system/recipes/product-status.d.ts +0 -34
  262. package/dist/styled-system/recipes/product-status.js +0 -45
  263. package/dist/styled-system/recipes/product-toolbar.d.ts +0 -31
  264. package/dist/styled-system/recipes/product-toolbar.js +0 -41
  265. package/dist/styled-system/recipes/product-workspace.d.ts +0 -34
  266. package/dist/styled-system/recipes/product-workspace.js +0 -58
  267. package/dist/styled-system/recipes/surface-metric.d.ts +0 -38
  268. package/dist/styled-system/recipes/surface-metric.js +0 -63
  269. package/dist/styled-system/recipes/surface-table.d.ts +0 -34
  270. package/dist/styled-system/recipes/surface-table.js +0 -62
  271. package/dist/styled-system/recipes/ui-badge.d.ts +0 -31
  272. package/dist/styled-system/recipes/ui-badge.js +0 -38
  273. package/dist/styled-system/recipes/ui-button.d.ts +0 -32
  274. package/dist/styled-system/recipes/ui-button.js +0 -43
  275. package/dist/styled-system/recipes/ui-input.d.ts +0 -31
  276. package/dist/styled-system/recipes/ui-input.js +0 -49
  277. package/dist/styled-system/recipes/ui-textarea.d.ts +0 -31
  278. package/dist/styled-system/recipes/ui-textarea.js +0 -24
  279. package/dist/styled-system/styles.css +0 -1257
  280. package/dist/styled-system/tokens/index.d.ts +0 -9
  281. package/dist/styled-system/tokens/index.js +0 -268
  282. package/dist/styled-system/tokens/tokens.d.ts +0 -36
  283. package/dist/styled-system/types/composition.d.ts +0 -227
  284. package/dist/styled-system/types/conditions.d.ts +0 -236
  285. package/dist/styled-system/types/csstype.d.ts +0 -22570
  286. package/dist/styled-system/types/index.d.ts +0 -6
  287. package/dist/styled-system/types/parts.d.ts +0 -8
  288. package/dist/styled-system/types/pattern.d.ts +0 -78
  289. package/dist/styled-system/types/prop-type.d.ts +0 -223
  290. package/dist/styled-system/types/recipe.d.ts +0 -181
  291. package/dist/styled-system/types/selectors.d.ts +0 -59
  292. package/dist/styled-system/types/static-css.d.ts +0 -56
  293. package/dist/styled-system/types/style-props.d.ts +0 -8088
  294. package/dist/styled-system/types/system-types.d.ts +0 -151
  295. package/dist/styles/recipes.css +0 -1262
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { definedOptions } from '@svadmin/core/options';
3
3
 
4
- import { SvelteSet } from 'svelte/reactivity';
5
- import { onDestroy } from 'svelte';
4
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
5
+ import { onDestroy, tick, untrack } from 'svelte';
6
6
  import { ChevronRight, ChevronDown, Check, X, Search, ChevronsUpDown, Loader2, Minus, RotateCw } from '@lucide/svelte';
7
7
  import { cn } from '../utils.js';
8
8
  import * as Popover from './ui/popover/index.js';
@@ -31,6 +31,9 @@
31
31
  disabled?: boolean;
32
32
  allowClear?: boolean;
33
33
  loadChildren?: (node: TreeSelectOption) => Promise<TreeSelectOption[]>;
34
+ virtualized?: boolean;
35
+ itemHeight?: number;
36
+ viewportHeight?: number;
34
37
  class?: string;
35
38
  onchange?: (value: string | number | (string | number)[] | undefined) => void;
36
39
  }
@@ -45,6 +48,9 @@
45
48
  disabled = false,
46
49
  allowClear = true,
47
50
  loadChildren,
51
+ virtualized = true,
52
+ itemHeight = 36,
53
+ viewportHeight = 280,
48
54
  class: className,
49
55
  onchange,
50
56
  }: Props = $props();
@@ -52,13 +58,29 @@
52
58
  let open = $state(false);
53
59
  let searchQuery = $state('');
54
60
  let loadingValues = new SvelteSet<string | number>();
55
- let loadErrors = new SvelteSet<string | number>();
56
- let expandedNodes = new SvelteSet<string | number>();
57
- let mounted = true;
58
- const loads = new Map<string | number, {
61
+ interface ChildLoad {
59
62
  node: TreeSelectOption;
60
63
  loader: NonNullable<Props['loadChildren']>;
61
- }>();
64
+ treeEpoch: number;
65
+ }
66
+ let loadErrors = new SvelteMap<string | number, ChildLoad>();
67
+ let expandedNodes = new SvelteSet<string | number>();
68
+ let mounted = true;
69
+ let treeRoot: HTMLElement | undefined = $state();
70
+ let treeScrollTop = $state(0);
71
+ let treeRevision = $state(0);
72
+ const loads = new Map<string | number, ChildLoad>();
73
+ let observedOptions = untrack(() => options);
74
+ let observedLoader = untrack(() => loadChildren);
75
+ interface SelectionAttempt {
76
+ key: string | number;
77
+ epoch: number;
78
+ loader: Props['loadChildren'];
79
+ value: Props['value'];
80
+ }
81
+ let selectionAttempt = $state.raw<SelectionAttempt>();
82
+ const selectionErrors = new SvelteSet<string | number>();
83
+ let treeEpoch = 0;
62
84
  onDestroy(() => { mounted = false; loads.clear(); });
63
85
 
64
86
  // Map to quickly look up option info by value
@@ -74,6 +96,20 @@
74
96
  return map;
75
97
  });
76
98
 
99
+ // 禁用状态沿完整数据树传播,搜索裁剪不能重新启用后代。
100
+ const disabledValues = $derived.by(() => {
101
+ const keys = new Set<string | number>();
102
+ function visit(nodes: TreeSelectOption[], inherited: boolean): void {
103
+ for (const node of nodes) {
104
+ const unavailable = inherited || node.disabled === true;
105
+ if (unavailable) keys.add(node.value);
106
+ if (node.children) visit(node.children, unavailable);
107
+ }
108
+ }
109
+ visit(options, false);
110
+ return keys;
111
+ });
112
+
77
113
  // Selected values array normalized
78
114
  const selectedValues = $derived.by< (string | number)[]>(() => {
79
115
  if (value === undefined || value === null || value === '') return [];
@@ -85,16 +121,32 @@
85
121
  });
86
122
 
87
123
  $effect.pre(() => {
88
- const nodes = optionMap;
124
+ // 外部替换根数组开启新数据版本;内部补充子节点保留当前版本。
125
+ if (options !== observedOptions) {
126
+ observedOptions = options;
127
+ treeEpoch += 1;
128
+ treeRevision += 1;
129
+ selectionAttempt = undefined;
130
+ selectionErrors.clear();
131
+ }
89
132
  const loader = loadChildren;
90
133
  const unavailable = disabled;
134
+ if (loader !== observedLoader || unavailable) {
135
+ observedLoader = loader;
136
+ selectionAttempt = undefined;
137
+ selectionErrors.clear();
138
+ }
139
+ if (!multiple || onlyLeafSelectable || selectionAttempt?.value !== value) selectionAttempt = undefined;
91
140
  for (const [key, request] of loads) {
92
- if (unavailable || nodes.get(key) !== request.node || loader !== request.loader) {
141
+ if (unavailable || request.treeEpoch !== treeEpoch || loader !== request.loader) {
93
142
  loads.delete(key);
94
143
  loadingValues.delete(key);
95
144
  loadErrors.delete(key);
96
145
  }
97
146
  }
147
+ for (const [key, request] of loadErrors) {
148
+ if (unavailable || request.treeEpoch !== treeEpoch || loader !== request.loader) loadErrors.delete(key);
149
+ }
98
150
  });
99
151
 
100
152
  function toggleExpand(nodeValue: string | number, event?: MouseEvent) {
@@ -116,7 +168,8 @@
116
168
  }
117
169
 
118
170
  function selectableLeaves(node: TreeSelectOption): TreeSelectOption[] {
119
- if (!hasChildren(node)) return node.disabled ? [] : [node];
171
+ if (node.disabled) return [];
172
+ if (!hasChildren(node)) return [node];
120
173
  if (!node.children) return [];
121
174
  return (node.children ?? []).flatMap(selectableLeaves);
122
175
  }
@@ -126,16 +179,24 @@
126
179
  }
127
180
 
128
181
  function isNodeSelected(node: TreeSelectOption): boolean {
182
+ node = optionMap.get(node.value) ?? node;
129
183
  if (!multiple || !hasChildren(node)) return isSelected(node.value);
130
184
  const leaves = selectableLeaves(node);
131
- return leaves.length > 0 && leaves.every((leaf) => isSelected(leaf.value));
185
+ return leaves.length > 0 && !hasUnloadedDescendants(node) && leaves.every((leaf) => isSelected(leaf.value));
186
+ }
187
+
188
+ function hasUnloadedDescendants(node: TreeSelectOption): boolean {
189
+ if (node.disabled || !hasChildren(node)) return false;
190
+ if (!node.children) return true;
191
+ return node.children.some(hasUnloadedDescendants);
132
192
  }
133
193
 
134
194
  function isPartiallySelected(node: TreeSelectOption): boolean {
195
+ node = optionMap.get(node.value) ?? node;
135
196
  if (!multiple || !hasChildren(node)) return false;
136
197
  const leaves = selectableLeaves(node);
137
198
  const count = leaves.filter((leaf) => isSelected(leaf.value)).length;
138
- return count > 0 && count < leaves.length;
199
+ return count > 0 && (count < leaves.length || hasUnloadedDescendants(node));
139
200
  }
140
201
 
141
202
  function updateOptionsChildren(nodes: TreeSelectOption[], target: string | number, children: TreeSelectOption[]): TreeSelectOption[] {
@@ -155,23 +216,25 @@
155
216
  }
156
217
 
157
218
  async function ensureChildren(node: TreeSelectOption): Promise<boolean> {
158
- if (!mounted || disabled || loadingValues.has(node.value)) return false;
219
+ if (!mounted || disabled || disabledValues.has(node.value) || loadingValues.has(node.value)) return false;
159
220
  if (!node.hasChildren || node.children) return true;
160
221
  const currentNode = optionMap.get(node.value);
161
222
  if (!loadChildren || !currentNode) return false;
162
- const request = { node: currentNode, loader: loadChildren };
223
+ const request = { node: currentNode, loader: loadChildren, treeEpoch };
163
224
  loads.set(node.value, request);
164
225
  const current = () => mounted && !disabled && loads.get(node.value) === request
165
- && optionMap.get(node.value) === request.node && loadChildren === request.loader;
226
+ && options === observedOptions && treeEpoch === request.treeEpoch
227
+ && optionMap.has(node.value) && !disabledValues.has(node.value) && loadChildren === request.loader;
166
228
  loadingValues.add(node.value);
167
229
  loadErrors.delete(node.value);
168
230
  try {
169
231
  const children = await request.loader(request.node);
170
232
  if (!current()) return false;
171
233
  options = updateOptionsChildren(options, node.value, children);
234
+ observedOptions = options;
172
235
  return true;
173
236
  } catch {
174
- if (current()) loadErrors.add(node.value);
237
+ if (current()) loadErrors.set(node.value, request);
175
238
  return false;
176
239
  } finally {
177
240
  if (mounted && loads.get(node.value) === request) {
@@ -190,11 +253,13 @@
190
253
 
191
254
  function retryChildren(node: TreeSelectOption, event: MouseEvent): void {
192
255
  event.stopPropagation();
193
- void toggleExpandAsync(node);
256
+ if (selectionErrors.has(node.value)) void handleSelect(node);
257
+ else void toggleExpandAsync(node);
194
258
  }
195
259
 
196
260
  function setMultipleSelection(node: TreeSelectOption): void {
197
261
  const leaves = selectableLeaves(node);
262
+ if (leaves.length === 0) return;
198
263
  const leafValues = new Set(leaves.map((leaf) => leaf.value));
199
264
  const shouldRemove = leaves.length > 0 && leaves.every((leaf) => isSelected(leaf.value));
200
265
  const next = shouldRemove
@@ -204,8 +269,54 @@
204
269
  onchange?.(next);
205
270
  }
206
271
 
272
+ function isCurrentSelection(attempt: SelectionAttempt): boolean {
273
+ return mounted && !disabled && multiple && !onlyLeafSelectable
274
+ && selectionAttempt === attempt && attempt.epoch === treeEpoch
275
+ && options === observedOptions && attempt.loader === loadChildren && attempt.value === value;
276
+ }
277
+
278
+ async function selectSubtree(node: TreeSelectOption): Promise<void> {
279
+ if (selectionAttempt?.key === node.value && isCurrentSelection(selectionAttempt)) return;
280
+ const attempt: SelectionAttempt = { key: node.value, epoch: treeEpoch, loader: loadChildren, value };
281
+ selectionAttempt = attempt;
282
+ selectionErrors.delete(node.value);
283
+ let visited = 0;
284
+ let requests = 0;
285
+ // 级联加载有界且只在全部成功后写入选择;搜索裁剪不改变选择范围。
286
+ async function loadSubtree(key: string | number, depth: number): Promise<boolean> {
287
+ if (!isCurrentSelection(attempt)) return false;
288
+ const currentNode = optionMap.get(key);
289
+ if (!currentNode || ++visited > 10000 || depth > 64) return false;
290
+ if (currentNode.disabled) return true;
291
+ if (currentNode.hasChildren && !currentNode.children) {
292
+ if (++requests > 100 || !await ensureChildren(currentNode)) return false;
293
+ }
294
+ if (!isCurrentSelection(attempt)) return false;
295
+ const loaded = optionMap.get(key);
296
+ if (!loaded) return false;
297
+ for (const child of loaded.children ?? []) {
298
+ if (!await loadSubtree(child.value, depth + 1)) return false;
299
+ }
300
+ return true;
301
+ }
302
+ try {
303
+ if (!await loadSubtree(node.value, 0)) {
304
+ if (isCurrentSelection(attempt)) selectionErrors.add(node.value);
305
+ return;
306
+ }
307
+ if (isCurrentSelection(attempt)) {
308
+ const loaded = optionMap.get(node.value);
309
+ if (loaded) setMultipleSelection(loaded);
310
+ }
311
+ } finally {
312
+ if (selectionAttempt === attempt) selectionAttempt = undefined;
313
+ }
314
+ }
315
+
207
316
  async function handleSelect(node: TreeSelectOption): Promise<void> {
208
- if (node.disabled) return;
317
+ node = optionMap.get(node.value) ?? node;
318
+ if (disabled || disabledValues.has(node.value)) return;
319
+ if (selectionAttempt?.key === node.value && isCurrentSelection(selectionAttempt)) return;
209
320
  const nodeHasChildren = hasChildren(node);
210
321
  if (onlyLeafSelectable && nodeHasChildren) {
211
322
  await toggleExpandAsync(node);
@@ -213,8 +324,16 @@
213
324
  }
214
325
 
215
326
  if (multiple) {
216
- if (nodeHasChildren) setMultipleSelection(node);
327
+ if (nodeHasChildren) {
328
+ if (hasUnloadedDescendants(node)) await selectSubtree(node);
329
+ else {
330
+ selectionAttempt = undefined;
331
+ selectionErrors.delete(node.value);
332
+ setMultipleSelection(node);
333
+ }
334
+ }
217
335
  else {
336
+ selectionAttempt = undefined;
218
337
  const next = isSelected(node.value)
219
338
  ? selectedValues.filter((selected) => selected !== node.value)
220
339
  : [...selectedValues, node.value];
@@ -238,19 +357,34 @@
238
357
  return undefined;
239
358
  }
240
359
 
241
- function focusTreeNode(valueToFocus: string | number): void {
242
- const element = document.querySelector<HTMLElement>(`[data-tree-value="${CSS.escape(String(valueToFocus))}"]`);
360
+ function treeKey(value: string | number): string {
361
+ return `${typeof value}:${String(value)}`;
362
+ }
363
+
364
+ async function focusTreeNode(valueToFocus: string | number): Promise<void> {
365
+ const index = flatVisibleNodes.findIndex(entry => entry.node.value === valueToFocus);
366
+ if (index < 0) return;
367
+ if (shouldVirtualize && treeRoot) {
368
+ const top = index * rowHeight;
369
+ if (top < treeScrollTop || top + rowHeight > treeScrollTop + windowHeight) {
370
+ treeScrollTop = Math.max(0, Math.min(top, totalHeight - windowHeight));
371
+ treeRoot.scrollTop = treeScrollTop;
372
+ await tick();
373
+ }
374
+ }
375
+ if (!mounted) return;
376
+ const element = treeRoot?.querySelector<HTMLElement>(`[data-tree-key="${CSS.escape(treeKey(valueToFocus))}"]`);
243
377
  element?.focus();
244
378
  }
245
379
 
246
380
  function focusSibling(nodeValue: string | number, offset: number): void {
247
- const nodes = Array.from(document.querySelectorAll<HTMLElement>('[data-tree-value]'));
248
- const index = nodes.findIndex((node) => node.dataset['treeValue'] === String(nodeValue));
249
- const target = nodes[index + offset];
250
- target?.focus();
381
+ const index = flatVisibleNodes.findIndex(entry => entry.node.value === nodeValue);
382
+ const target = flatVisibleNodes[index + offset];
383
+ if (target) void focusTreeNode(target.node.value);
251
384
  }
252
385
 
253
386
  function handleTreeKeydown(event: KeyboardEvent, node: TreeSelectOption, expanded: boolean): void {
387
+ if (event.target !== event.currentTarget) return;
254
388
  const nodeHasChildren = hasChildren(node);
255
389
  if (event.key === 'Enter' || event.key === ' ') {
256
390
  event.preventDefault();
@@ -263,34 +397,44 @@
263
397
  focusSibling(node.value, -1);
264
398
  } else if (event.key === 'Home') {
265
399
  event.preventDefault();
266
- document.querySelector<HTMLElement>('[data-tree-value]')?.focus();
400
+ const first = flatVisibleNodes[0];
401
+ if (first) void focusTreeNode(first.node.value);
267
402
  } else if (event.key === 'End') {
268
403
  event.preventDefault();
269
- const nodes = document.querySelectorAll<HTMLElement>('[data-tree-value]');
270
- nodes[nodes.length - 1]?.focus();
404
+ const last = flatVisibleNodes[flatVisibleNodes.length - 1];
405
+ if (last) void focusTreeNode(last.node.value);
271
406
  } else if (event.key === 'ArrowRight' && nodeHasChildren) {
272
407
  event.preventDefault();
273
408
  if (!expanded) void toggleExpandAsync(node);
274
- else focusTreeNode(node.children?.[0]?.value ?? node.value);
409
+ else {
410
+ const index = flatVisibleNodes.findIndex(entry => entry.node.value === node.value);
411
+ const current = flatVisibleNodes[index];
412
+ const next = flatVisibleNodes[index + 1];
413
+ if (current && next && next.level > current.level) void focusTreeNode(next.node.value);
414
+ }
275
415
  } else if (event.key === 'ArrowLeft') {
276
416
  event.preventDefault();
277
417
  if (nodeHasChildren && expanded) toggleExpand(node.value);
278
418
  else {
279
419
  const parent = findParent(options, node.value);
280
- if (parent) focusTreeNode(parent.value);
420
+ if (parent) void focusTreeNode(parent.value);
281
421
  }
282
422
  }
283
423
  }
284
424
 
285
- function clearAll(event?: MouseEvent) {
425
+ function clearAll(event?: MouseEvent | KeyboardEvent) {
286
426
  event?.stopPropagation();
427
+ if (disabled) return;
428
+ selectionAttempt = undefined;
287
429
  const next = multiple ? [] : undefined;
288
430
  value = next;
289
431
  onchange?.(next);
290
432
  }
291
433
 
292
- function removeSingle(val: string | number, event?: MouseEvent) {
434
+ function removeSingle(val: string | number, event?: MouseEvent | KeyboardEvent) {
293
435
  event?.stopPropagation();
436
+ if (disabled) return;
437
+ selectionAttempt = undefined;
294
438
  if (multiple) {
295
439
  const next = selectedValues.filter((v) => v !== val);
296
440
  value = next;
@@ -319,14 +463,54 @@
319
463
  }
320
464
 
321
465
  const visibleOptions = $derived(filterTree(options, searchQuery));
466
+
467
+ interface VisibleNode {
468
+ node: TreeSelectOption;
469
+ level: number;
470
+ position: number;
471
+ size: number;
472
+ }
473
+ const flatVisibleNodes = $derived.by(() => {
474
+ const result: VisibleNode[] = [];
475
+ function visit(nodes: TreeSelectOption[], level: number): void {
476
+ nodes.forEach((node, index) => {
477
+ result.push({ node, level, position: index + 1, size: nodes.length });
478
+ if (hasChildren(node) && isNodeExpanded(node) && node.children) visit(node.children, level + 1);
479
+ });
480
+ }
481
+ visit(visibleOptions, 0);
482
+ return result;
483
+ });
484
+ const rowHeight = $derived(Number.isSafeInteger(itemHeight) && itemHeight >= 32 && itemHeight <= 100 ? itemHeight : 36);
485
+ const windowHeight = $derived(Number.isSafeInteger(viewportHeight) && viewportHeight >= 120 && viewportHeight <= 800 ? viewportHeight : 280);
486
+ const shouldVirtualize = $derived(virtualized && flatVisibleNodes.length >= 200);
487
+ const totalHeight = $derived(flatVisibleNodes.length * rowHeight);
488
+ const clampedScrollTop = $derived(Math.max(0, Math.min(treeScrollTop, totalHeight - windowHeight)));
489
+ const virtualStart = $derived(Math.max(0, Math.floor(clampedScrollTop / rowHeight) - 5));
490
+ const virtualEnd = $derived(Math.min(flatVisibleNodes.length, Math.ceil((clampedScrollTop + windowHeight) / rowHeight) + 5));
491
+
492
+ $effect(() => {
493
+ // 搜索和外部数据替换从顶部开始;折叠或数据缩短只钳制窗口。
494
+ void searchQuery;
495
+ void treeRevision;
496
+ treeScrollTop = 0;
497
+ if (treeRoot) treeRoot.scrollTop = 0;
498
+ });
499
+ $effect(() => {
500
+ if (treeScrollTop !== clampedScrollTop) {
501
+ treeScrollTop = clampedScrollTop;
502
+ if (treeRoot) treeRoot.scrollTop = clampedScrollTop;
503
+ }
504
+ });
322
505
  </script>
323
506
 
324
- {#snippet treeNode(node: TreeSelectOption, level: number)}
325
- {@const nodeHasChildren = hasChildren(node)}
507
+ {#snippet treeNode(node: TreeSelectOption, level: number, position: number, size: number, recursive = true)}
508
+ {@const nodeHasChildren = hasChildren(optionMap.get(node.value) ?? node)}
326
509
  {@const expanded = isNodeExpanded(node)}
327
510
  {@const selected = isNodeSelected(node)}
328
511
  {@const partial = isPartiallySelected(node)}
329
- {@const selectable = !node.disabled && (!onlyLeafSelectable || !nodeHasChildren)}
512
+ {@const busy = selectionAttempt?.key === node.value || loadingValues.has(node.value)}
513
+ {@const unavailable = disabled || disabledValues.has(node.value)}
330
514
 
331
515
  <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed">
332
516
  <div
@@ -334,30 +518,34 @@
334
518
  tabindex="0"
335
519
  aria-selected={selected}
336
520
  aria-checked={multiple ? (partial ? 'mixed' : selected) : undefined}
521
+ aria-disabled={unavailable ? 'true' : undefined}
522
+ aria-busy={busy}
337
523
  aria-level={level + 1}
524
+ aria-posinset={position}
525
+ aria-setsize={size}
338
526
  aria-expanded={nodeHasChildren ? expanded : undefined}
339
527
  data-tree-value={String(node.value)}
528
+ data-tree-key={treeKey(node.value)}
340
529
  class={cn(
341
530
  'group svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-58284b4ea568 svadmin-u-421ac2be5045 svadmin-u-d5eab218aa34 svadmin-u-ec0091ee009b svadmin-u-359090c2d529 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-7f6912283f11',
342
531
  selected ? 'svadmin-u-375dc44df6e9 svadmin-u-20aaf08a7ed1 svadmin-u-2689f3958069' : 'svadmin-u-68646cdcc246 svadmin-u-d4108abe6359',
343
- node.disabled && 'svadmin-u-0b8c506a0596 svadmin-u-29b733e4c162 svadmin-u-a4326536b8f5'
532
+ unavailable && 'svadmin-u-0b8c506a0596 svadmin-u-29b733e4c162 svadmin-u-a4326536b8f5'
344
533
  )}
345
- style="padding-left: {level * 16 + 8}px;"
346
- onclick={() => {
347
- if (selectable) handleSelect(node);
348
- }}
534
+ style={`padding-left:${level * 16 + 8}px;${recursive ? '' : `height:${rowHeight}px;min-height:${rowHeight}px;box-sizing:border-box;overflow:hidden;`}`}
535
+ onclick={() => void handleSelect(node)}
349
536
  onkeydown={(e) => handleTreeKeydown(e, node, expanded)}
350
537
  >
351
538
  <div class="svadmin-u-60fbb7713999 svadmin-u-7e0b7cdf1a94 svadmin-u-3960ffc248d9 svadmin-u-58284b4ea568">
352
539
  {#if nodeHasChildren}
353
540
  <button
354
541
  type="button"
542
+ disabled={unavailable}
355
543
  aria-label={`${node.label}: ${i18n.t('tree.toggleChildren')}`}
356
- aria-busy={loadingValues.has(node.value)}
544
+ aria-busy={busy}
357
545
  class="svadmin-u-60fbb7713999 svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-012fbd121f37 svadmin-u-3960ffc248d9 svadmin-u-86843cf1e227 svadmin-u-07389a777c1f svadmin-u-bfa603190748 svadmin-u-8e551981c8d7"
358
546
  onclick={(e) => void toggleExpandAsync(node, e)}
359
547
  >
360
- {#if loadingValues.has(node.value)}
548
+ {#if busy}
361
549
  <Loader2 class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-afbdd13a380e" />
362
550
  {:else if expanded}
363
551
  <ChevronDown class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
@@ -372,9 +560,10 @@
372
560
  <span class="svadmin-u-f283ea9bea0e">{node.label}</span>
373
561
  </div>
374
562
 
375
- {#if loadErrors.has(node.value)}
376
- <span role="alert" class="svadmin-u-bfa603190748">{i18n.t('tree.loadFailed')}</span>
563
+ {#if loadErrors.has(node.value) || selectionErrors.has(node.value)}
564
+ <span role="alert" class="svadmin-u-bfa603190748">{i18n.t(selectionErrors.has(node.value) ? 'tree.selectionFailed' : 'tree.loadFailed')}</span>
377
565
  <button type="button" aria-label={`${node.label}: ${i18n.t('common.retry')}`}
566
+ disabled={unavailable}
378
567
  title={i18n.t('common.retry')} onclick={(e) => retryChildren(node, e)}>
379
568
  <RotateCw class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
380
569
  </button>
@@ -387,10 +576,10 @@
387
576
  {/if}
388
577
  </div>
389
578
 
390
- {#if nodeHasChildren && expanded && node.children}
579
+ {#if recursive && nodeHasChildren && expanded && node.children}
391
580
  <div role="group" class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed">
392
- {#each node.children as child (child.value)}
393
- {@render treeNode(child, level + 1)}
581
+ {#each node.children as child, index (treeKey(child.value))}
582
+ {@render treeNode(child, level + 1, index + 1, node.children.length)}
394
583
  {/each}
395
584
  </div>
396
585
  {/if}
@@ -424,10 +613,14 @@
424
613
  <span
425
614
  role="button"
426
615
  tabindex="0"
616
+ aria-label={i18n.t('tree.removeSelection', { label: opt?.label ?? String(val) })}
427
617
  class="svadmin-u-51e95020d6f2 svadmin-u-34516836730d"
428
618
  onclick={(e) => removeSingle(val, e)}
429
619
  onkeydown={(e) => {
430
- if (e.key === 'Enter') removeSingle(val, e as never);
620
+ if (e.key === 'Enter' || e.key === ' ') {
621
+ e.preventDefault();
622
+ removeSingle(val, e);
623
+ }
431
624
  }}
432
625
  >
433
626
  <X class="svadmin-u-6a60c09e6aaa svadmin-u-9cea05671a29" />
@@ -447,10 +640,14 @@
447
640
  <span
448
641
  role="button"
449
642
  tabindex="0"
643
+ aria-label={i18n.t('common.clearSelection')}
450
644
  class="svadmin-u-ea7b2e9e070e svadmin-u-34516836730d svadmin-u-de8350a3bbad"
451
645
  onclick={clearAll}
452
646
  onkeydown={(e) => {
453
- if (e.key === 'Enter') clearAll(e as never);
647
+ if (e.key === 'Enter' || e.key === ' ') {
648
+ e.preventDefault();
649
+ clearAll(e);
650
+ }
454
651
  }}
455
652
  >
456
653
  <X class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
@@ -475,14 +672,31 @@
475
672
  </div>
476
673
  {/if}
477
674
 
478
- <div role="tree" class="svadmin-u-67d7e383dca6 svadmin-u-92bf82f493b1 svadmin-u-e2eedc5718f0 svadmin-u-eda955402ba6">
479
- {#each visibleOptions as rootNode (rootNode.value)}
480
- {@render treeNode(rootNode, 0)}
675
+ <div
676
+ bind:this={treeRoot}
677
+ role="tree"
678
+ aria-multiselectable={multiple ? 'true' : undefined}
679
+ class="svadmin-u-67d7e383dca6 svadmin-u-92bf82f493b1 svadmin-u-e2eedc5718f0 svadmin-u-eda955402ba6"
680
+ style={shouldVirtualize ? `height:${windowHeight}px;max-height:${windowHeight}px;overflow-y:auto;padding:0;` : undefined}
681
+ onscroll={(event) => { treeScrollTop = event.currentTarget.scrollTop; }}
682
+ >
683
+ {#if shouldVirtualize}
684
+ <div style={`height:${totalHeight}px;position:relative;`}>
685
+ <div style={`position:absolute;top:${virtualStart * rowHeight}px;left:0;right:0;`}>
686
+ {#each flatVisibleNodes.slice(virtualStart, virtualEnd) as entry (treeKey(entry.node.value))}
687
+ {@render treeNode(entry.node, entry.level, entry.position, entry.size, false)}
688
+ {/each}
689
+ </div>
690
+ </div>
691
+ {:else if visibleOptions.length > 0}
692
+ {#each visibleOptions as rootNode, index (treeKey(rootNode.value))}
693
+ {@render treeNode(rootNode, 0, index + 1, visibleOptions.length)}
694
+ {/each}
481
695
  {:else}
482
696
  <div class="svadmin-u-940911bf310c svadmin-u-ca6bf63030aa svadmin-u-359090c2d529 svadmin-u-bfa603190748">
483
697
  {i18n.t('common.noData', undefined) ?? '无匹配选项'}
484
698
  </div>
485
- {/each}
699
+ {/if}
486
700
  </div>
487
701
  </Popover.Content>
488
702
  </Popover.Root>
@@ -16,6 +16,9 @@ interface Props {
16
16
  disabled?: boolean;
17
17
  allowClear?: boolean;
18
18
  loadChildren?: (node: TreeSelectOption) => Promise<TreeSelectOption[]>;
19
+ virtualized?: boolean;
20
+ itemHeight?: number;
21
+ viewportHeight?: number;
19
22
  class?: string;
20
23
  onchange?: (value: string | number | (string | number)[] | undefined) => void;
21
24
  }