@chenzy-design/svelte 0.1.0 → 0.2.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 (476) hide show
  1. package/dist/components.json +1 -1
  2. package/package.json +7 -8
  3. package/src/_floating/use-floating.ts +0 -208
  4. package/src/anchor/Anchor.a11y.test.ts +0 -49
  5. package/src/anchor/Anchor.kbd.test.ts +0 -70
  6. package/src/anchor/Anchor.svelte +0 -359
  7. package/src/anchor/AnchorKbdFixture.svelte +0 -24
  8. package/src/anchor/index.ts +0 -3
  9. package/src/anchor/meta.ts +0 -70
  10. package/src/anchor/types.ts +0 -8
  11. package/src/autocomplete/AutoComplete.a11y.test.ts +0 -49
  12. package/src/autocomplete/AutoComplete.kbd.test.ts +0 -69
  13. package/src/autocomplete/AutoComplete.svelte +0 -706
  14. package/src/autocomplete/AutoCompleteKbdFixture.svelte +0 -24
  15. package/src/autocomplete/index.ts +0 -2
  16. package/src/autocomplete/meta.ts +0 -41
  17. package/src/avatar/Avatar.a11y.test.ts +0 -37
  18. package/src/avatar/Avatar.svelte +0 -315
  19. package/src/avatar/AvatarGroup.svelte +0 -142
  20. package/src/avatar/context.ts +0 -21
  21. package/src/avatar/index.ts +0 -10
  22. package/src/avatar/meta.ts +0 -73
  23. package/src/back-top/BackTop.a11y.test.ts +0 -40
  24. package/src/back-top/BackTop.svelte +0 -314
  25. package/src/back-top/index.ts +0 -2
  26. package/src/back-top/meta.ts +0 -108
  27. package/src/badge/Badge.a11y.test.ts +0 -35
  28. package/src/badge/Badge.svelte +0 -328
  29. package/src/badge/BadgeA11yFixture.svelte +0 -18
  30. package/src/badge/index.ts +0 -2
  31. package/src/badge/meta.ts +0 -62
  32. package/src/banner/Banner.a11y.test.ts +0 -48
  33. package/src/banner/Banner.svelte +0 -368
  34. package/src/banner/index.ts +0 -3
  35. package/src/banner/meta.ts +0 -121
  36. package/src/breadcrumb/Breadcrumb.a11y.test.ts +0 -35
  37. package/src/breadcrumb/Breadcrumb.kbd.test.ts +0 -45
  38. package/src/breadcrumb/Breadcrumb.svelte +0 -414
  39. package/src/breadcrumb/BreadcrumbKbdFixture.svelte +0 -23
  40. package/src/breadcrumb/Item.svelte +0 -77
  41. package/src/breadcrumb/context.ts +0 -27
  42. package/src/breadcrumb/index.ts +0 -21
  43. package/src/breadcrumb/meta.ts +0 -128
  44. package/src/breadcrumb/types.ts +0 -4
  45. package/src/button/Button.a11y.test.ts +0 -54
  46. package/src/button/Button.svelte +0 -176
  47. package/src/button/index.ts +0 -2
  48. package/src/button/meta.ts +0 -28
  49. package/src/calendar/Calendar.a11y.test.ts +0 -51
  50. package/src/calendar/Calendar.kbd.test.ts +0 -59
  51. package/src/calendar/Calendar.svelte +0 -1344
  52. package/src/calendar/CalendarKbdFixture.svelte +0 -23
  53. package/src/calendar/index.ts +0 -3
  54. package/src/calendar/meta.ts +0 -117
  55. package/src/card/Card.a11y.test.ts +0 -38
  56. package/src/card/Card.svelte +0 -341
  57. package/src/card/CardMeta.svelte +0 -60
  58. package/src/card/index.ts +0 -8
  59. package/src/card/meta.ts +0 -83
  60. package/src/carousel/Carousel.a11y.test.ts +0 -53
  61. package/src/carousel/Carousel.kbd.test.ts +0 -67
  62. package/src/carousel/Carousel.svelte +0 -806
  63. package/src/carousel/CarouselA11yFixture.svelte +0 -25
  64. package/src/carousel/CarouselKbdFixture.svelte +0 -24
  65. package/src/carousel/index.ts +0 -2
  66. package/src/carousel/meta.ts +0 -74
  67. package/src/cascader/Cascader.a11y.test.ts +0 -59
  68. package/src/cascader/Cascader.kbd.test.ts +0 -56
  69. package/src/cascader/Cascader.svelte +0 -1570
  70. package/src/cascader/CascaderKbdFixture.svelte +0 -31
  71. package/src/cascader/index.ts +0 -3
  72. package/src/cascader/meta.ts +0 -57
  73. package/src/cascader/types.ts +0 -9
  74. package/src/checkbox/Checkbox.svelte +0 -281
  75. package/src/checkbox/CheckboxGroup.a11y.test.ts +0 -43
  76. package/src/checkbox/CheckboxGroup.kbd.test.ts +0 -40
  77. package/src/checkbox/CheckboxGroup.svelte +0 -122
  78. package/src/checkbox/CheckboxGroupKbdFixture.svelte +0 -20
  79. package/src/checkbox/context.ts +0 -31
  80. package/src/checkbox/index.ts +0 -4
  81. package/src/checkbox/meta.ts +0 -67
  82. package/src/collapse/Collapse.a11y.test.ts +0 -53
  83. package/src/collapse/Collapse.kbd.test.ts +0 -89
  84. package/src/collapse/Collapse.svelte +0 -406
  85. package/src/collapse/CollapseA11yFixture.svelte +0 -27
  86. package/src/collapse/CollapseKbdFixture.svelte +0 -25
  87. package/src/collapse/CollapsePanel.svelte +0 -102
  88. package/src/collapse/context.ts +0 -54
  89. package/src/collapse/index.ts +0 -17
  90. package/src/collapse/meta.ts +0 -79
  91. package/src/collapse/types.ts +0 -5
  92. package/src/color-picker/ColorPicker.a11y.test.ts +0 -60
  93. package/src/color-picker/ColorPicker.kbd.test.ts +0 -73
  94. package/src/color-picker/ColorPicker.svelte +0 -985
  95. package/src/color-picker/ColorPickerKbdFixture.svelte +0 -25
  96. package/src/color-picker/index.ts +0 -2
  97. package/src/color-picker/meta.ts +0 -47
  98. package/src/config-provider/ConfigProvider.svelte +0 -227
  99. package/src/config-provider/context.ts +0 -29
  100. package/src/config-provider/index.ts +0 -48
  101. package/src/config-provider/meta.ts +0 -128
  102. package/src/date-picker/DatePicker.a11y.test.ts +0 -45
  103. package/src/date-picker/DatePicker.kbd.test.ts +0 -71
  104. package/src/date-picker/DatePicker.svelte +0 -1798
  105. package/src/date-picker/DatePickerKbdFixture.svelte +0 -26
  106. package/src/date-picker/RangePicker.kbd.test.ts +0 -69
  107. package/src/date-picker/RangePicker.svelte +0 -775
  108. package/src/date-picker/RangePickerKbdFixture.svelte +0 -30
  109. package/src/date-picker/index.ts +0 -4
  110. package/src/date-picker/meta.ts +0 -67
  111. package/src/date-picker/range-meta.ts +0 -44
  112. package/src/descriptions/Descriptions.a11y.test.ts +0 -33
  113. package/src/descriptions/Descriptions.svelte +0 -287
  114. package/src/descriptions/DescriptionsItem.svelte +0 -43
  115. package/src/descriptions/context.ts +0 -21
  116. package/src/descriptions/index.ts +0 -16
  117. package/src/descriptions/meta.ts +0 -45
  118. package/src/descriptions/types.ts +0 -6
  119. package/src/divider/Divider.a11y.test.ts +0 -23
  120. package/src/divider/Divider.svelte +0 -154
  121. package/src/divider/index.ts +0 -2
  122. package/src/divider/meta.ts +0 -23
  123. package/src/drawer/Drawer.a11y.test.ts +0 -41
  124. package/src/drawer/Drawer.kbd.test.ts +0 -67
  125. package/src/drawer/Drawer.svelte +0 -554
  126. package/src/drawer/DrawerKbdFixture.svelte +0 -28
  127. package/src/drawer/index.ts +0 -2
  128. package/src/drawer/meta.ts +0 -127
  129. package/src/dropdown/Dropdown.a11y.test.ts +0 -46
  130. package/src/dropdown/Dropdown.kbd.test.ts +0 -56
  131. package/src/dropdown/Dropdown.svelte +0 -573
  132. package/src/dropdown/DropdownA11yFixture.svelte +0 -24
  133. package/src/dropdown/DropdownDivider.svelte +0 -17
  134. package/src/dropdown/DropdownItem.svelte +0 -127
  135. package/src/dropdown/DropdownItemNode.svelte +0 -355
  136. package/src/dropdown/DropdownKbdFixture.svelte +0 -26
  137. package/src/dropdown/DropdownMenu.svelte +0 -24
  138. package/src/dropdown/DropdownSubMenu.svelte +0 -212
  139. package/src/dropdown/DropdownTitle.svelte +0 -34
  140. package/src/dropdown/context.ts +0 -13
  141. package/src/dropdown/index.ts +0 -36
  142. package/src/dropdown/meta.ts +0 -97
  143. package/src/dropdown/types.test.ts +0 -50
  144. package/src/dropdown/types.ts +0 -67
  145. package/src/empty/Empty.a11y.test.ts +0 -24
  146. package/src/empty/Empty.svelte +0 -304
  147. package/src/empty/index.ts +0 -2
  148. package/src/empty/meta.ts +0 -41
  149. package/src/form/Field.svelte +0 -492
  150. package/src/form/FieldArray.svelte +0 -75
  151. package/src/form/Form.a11y.test.ts +0 -39
  152. package/src/form/Form.svelte +0 -243
  153. package/src/form/FormA11yFixture.svelte +0 -31
  154. package/src/form/FormCascader.svelte +0 -82
  155. package/src/form/FormCheckbox.svelte +0 -83
  156. package/src/form/FormDatePicker.svelte +0 -80
  157. package/src/form/FormErrorMessage.svelte +0 -44
  158. package/src/form/FormInput.svelte +0 -95
  159. package/src/form/FormLabel.svelte +0 -46
  160. package/src/form/FormRadio.svelte +0 -83
  161. package/src/form/FormRating.svelte +0 -85
  162. package/src/form/FormSection.svelte +0 -45
  163. package/src/form/FormSelect.svelte +0 -96
  164. package/src/form/FormSlider.svelte +0 -95
  165. package/src/form/FormSlot.svelte +0 -51
  166. package/src/form/FormSwitch.svelte +0 -82
  167. package/src/form/FormTagInput.svelte +0 -79
  168. package/src/form/FormTreeSelect.svelte +0 -85
  169. package/src/form/FormUpload.svelte +0 -92
  170. package/src/form/context.ts +0 -47
  171. package/src/form/index.ts +0 -22
  172. package/src/form/meta.ts +0 -85
  173. package/src/grid/Col.svelte +0 -142
  174. package/src/grid/Grid.a11y.test.ts +0 -14
  175. package/src/grid/GridA11yFixture.svelte +0 -12
  176. package/src/grid/Row.svelte +0 -116
  177. package/src/grid/index.ts +0 -3
  178. package/src/grid/meta.ts +0 -72
  179. package/src/grid/use-breakpoint.svelte.ts +0 -48
  180. package/src/highlight/Highlight.a11y.test.ts +0 -25
  181. package/src/highlight/Highlight.svelte +0 -99
  182. package/src/highlight/index.ts +0 -2
  183. package/src/highlight/meta.ts +0 -80
  184. package/src/icon/Icon.svelte +0 -156
  185. package/src/icon/index.ts +0 -2
  186. package/src/icon/meta.ts +0 -41
  187. package/src/image/Image.a11y.test.ts +0 -30
  188. package/src/image/Image.svelte +0 -387
  189. package/src/image/ImagePreview.kbd.test.ts +0 -52
  190. package/src/image/ImagePreview.svelte +0 -309
  191. package/src/image/ImagePreviewGroup.svelte +0 -93
  192. package/src/image/ImagePreviewKbdFixture.svelte +0 -32
  193. package/src/image/context.ts +0 -26
  194. package/src/image/index.ts +0 -15
  195. package/src/image/meta.ts +0 -131
  196. package/src/index.ts +0 -208
  197. package/src/input/Input.a11y.test.ts +0 -58
  198. package/src/input/Input.svelte +0 -505
  199. package/src/input/index.ts +0 -2
  200. package/src/input/meta.ts +0 -40
  201. package/src/input-number/InputNumber.a11y.test.ts +0 -43
  202. package/src/input-number/InputNumber.kbd.test.ts +0 -41
  203. package/src/input-number/InputNumber.svelte +0 -674
  204. package/src/input-number/InputNumberKbdFixture.svelte +0 -15
  205. package/src/input-number/index.ts +0 -2
  206. package/src/input-number/meta.ts +0 -65
  207. package/src/layout/Content.svelte +0 -37
  208. package/src/layout/Footer.svelte +0 -49
  209. package/src/layout/Header.svelte +0 -46
  210. package/src/layout/Layout.a11y.test.ts +0 -34
  211. package/src/layout/Layout.svelte +0 -60
  212. package/src/layout/LayoutA11yFixture.svelte +0 -21
  213. package/src/layout/Sider.svelte +0 -207
  214. package/src/layout/index.ts +0 -26
  215. package/src/layout/meta.ts +0 -116
  216. package/src/list/List.a11y.test.ts +0 -69
  217. package/src/list/List.bench.ts +0 -26
  218. package/src/list/List.kbd.test.ts +0 -71
  219. package/src/list/List.svelte +0 -920
  220. package/src/list/ListA11yFixture.svelte +0 -38
  221. package/src/list/ListBenchFixture.svelte +0 -22
  222. package/src/list/ListItem.svelte +0 -175
  223. package/src/list/ListKbdFixture.svelte +0 -31
  224. package/src/list/ListMeta.svelte +0 -73
  225. package/src/list/context.ts +0 -39
  226. package/src/list/index.ts +0 -21
  227. package/src/list/meta.ts +0 -99
  228. package/src/locale-provider/LocaleProvider.svelte +0 -110
  229. package/src/locale-provider/context.ts +0 -22
  230. package/src/locale-provider/index.ts +0 -21
  231. package/src/locale-provider/meta.ts +0 -93
  232. package/src/locale-provider/use-locale.ts +0 -25
  233. package/src/lottie-icon/LottieIcon.svelte +0 -330
  234. package/src/lottie-icon/index.ts +0 -9
  235. package/src/lottie-icon/meta.ts +0 -162
  236. package/src/menu/Menu.a11y.test.ts +0 -54
  237. package/src/menu/Menu.kbd.test.ts +0 -69
  238. package/src/menu/Menu.svelte +0 -762
  239. package/src/menu/MenuKbdFixture.svelte +0 -22
  240. package/src/menu/MenuPopupNode.svelte +0 -525
  241. package/src/menu/index.ts +0 -4
  242. package/src/menu/meta.ts +0 -137
  243. package/src/menu/types.ts +0 -120
  244. package/src/meta.test.ts +0 -173
  245. package/src/modal/ConfirmModal.svelte +0 -173
  246. package/src/modal/Modal.a11y.test.ts +0 -46
  247. package/src/modal/Modal.kbd.test.ts +0 -65
  248. package/src/modal/Modal.svelte +0 -511
  249. package/src/modal/ModalKbdFixture.svelte +0 -24
  250. package/src/modal/command.svelte.ts +0 -103
  251. package/src/modal/index.ts +0 -30
  252. package/src/modal/meta.ts +0 -165
  253. package/src/modal/z-stack.ts +0 -26
  254. package/src/notification/NotificationContainer.svelte +0 -192
  255. package/src/notification/NotificationItem.a11y.test.ts +0 -73
  256. package/src/notification/NotificationItem.svelte +0 -368
  257. package/src/notification/index.ts +0 -9
  258. package/src/notification/meta.ts +0 -120
  259. package/src/notification/store.ts +0 -191
  260. package/src/overflow-list/OverflowList.a11y.test.ts +0 -46
  261. package/src/overflow-list/OverflowList.kbd.test.ts +0 -34
  262. package/src/overflow-list/OverflowList.svelte +0 -539
  263. package/src/overflow-list/OverflowListA11yFixture.svelte +0 -22
  264. package/src/overflow-list/OverflowListKbdFixture.svelte +0 -21
  265. package/src/overflow-list/index.ts +0 -2
  266. package/src/overflow-list/meta.ts +0 -138
  267. package/src/pagination/Pagination.a11y.test.ts +0 -62
  268. package/src/pagination/Pagination.kbd.test.ts +0 -66
  269. package/src/pagination/Pagination.svelte +0 -428
  270. package/src/pagination/PaginationKbdFixture.svelte +0 -15
  271. package/src/pagination/index.ts +0 -2
  272. package/src/pagination/meta.ts +0 -73
  273. package/src/popconfirm/Popconfirm.a11y.test.ts +0 -46
  274. package/src/popconfirm/Popconfirm.kbd.test.ts +0 -42
  275. package/src/popconfirm/Popconfirm.svelte +0 -724
  276. package/src/popconfirm/PopconfirmA11yFixture.svelte +0 -34
  277. package/src/popconfirm/PopconfirmKbdFixture.svelte +0 -17
  278. package/src/popconfirm/index.ts +0 -2
  279. package/src/popconfirm/meta.ts +0 -200
  280. package/src/popover/Popover.a11y.test.ts +0 -58
  281. package/src/popover/Popover.kbd.test.ts +0 -42
  282. package/src/popover/Popover.svelte +0 -643
  283. package/src/popover/PopoverA11yFixture.svelte +0 -35
  284. package/src/popover/PopoverKbdFixture.svelte +0 -18
  285. package/src/popover/index.ts +0 -2
  286. package/src/popover/meta.ts +0 -103
  287. package/src/progress/Progress.a11y.test.ts +0 -37
  288. package/src/progress/Progress.svelte +0 -423
  289. package/src/progress/index.ts +0 -3
  290. package/src/progress/meta.ts +0 -132
  291. package/src/radio/Radio.svelte +0 -330
  292. package/src/radio/RadioGroup.a11y.test.ts +0 -43
  293. package/src/radio/RadioGroup.kbd.test.ts +0 -75
  294. package/src/radio/RadioGroup.svelte +0 -199
  295. package/src/radio/RadioGroupKbdFixture.svelte +0 -21
  296. package/src/radio/context.ts +0 -42
  297. package/src/radio/index.ts +0 -4
  298. package/src/radio/meta.ts +0 -68
  299. package/src/rating/Rating.a11y.test.ts +0 -41
  300. package/src/rating/Rating.kbd.test.ts +0 -48
  301. package/src/rating/Rating.svelte +0 -407
  302. package/src/rating/RatingKbdFixture.svelte +0 -15
  303. package/src/rating/index.ts +0 -2
  304. package/src/rating/meta.ts +0 -40
  305. package/src/resize-observer/ResizeObserver.svelte +0 -169
  306. package/src/resize-observer/action.ts +0 -80
  307. package/src/resize-observer/index.ts +0 -9
  308. package/src/resize-observer/meta.ts +0 -102
  309. package/src/scroll-list/ScrollColumn.svelte +0 -592
  310. package/src/scroll-list/ScrollList.svelte +0 -257
  311. package/src/scroll-list/index.ts +0 -4
  312. package/src/scroll-list/meta.ts +0 -93
  313. package/src/scroll-list/types.ts +0 -18
  314. package/src/select/Select.a11y.test.ts +0 -59
  315. package/src/select/Select.kbd.test.ts +0 -59
  316. package/src/select/Select.svelte +0 -1155
  317. package/src/select/SelectKbdFixture.svelte +0 -29
  318. package/src/select/index.ts +0 -3
  319. package/src/select/meta.ts +0 -78
  320. package/src/select/types.ts +0 -2
  321. package/src/side-sheet/SideSheet.a11y.test.ts +0 -53
  322. package/src/side-sheet/SideSheet.kbd.test.ts +0 -63
  323. package/src/side-sheet/SideSheet.svelte +0 -659
  324. package/src/side-sheet/SideSheetKbdFixture.svelte +0 -30
  325. package/src/side-sheet/index.ts +0 -2
  326. package/src/side-sheet/meta.ts +0 -116
  327. package/src/skeleton/Skeleton.a11y.test.ts +0 -35
  328. package/src/skeleton/Skeleton.svelte +0 -131
  329. package/src/skeleton/SkeletonAvatar.svelte +0 -82
  330. package/src/skeleton/SkeletonButton.svelte +0 -90
  331. package/src/skeleton/SkeletonImage.svelte +0 -100
  332. package/src/skeleton/SkeletonParagraph.svelte +0 -103
  333. package/src/skeleton/SkeletonTitle.svelte +0 -74
  334. package/src/skeleton/context.ts +0 -11
  335. package/src/skeleton/index.ts +0 -8
  336. package/src/skeleton/meta.ts +0 -65
  337. package/src/slider/Slider.a11y.test.ts +0 -44
  338. package/src/slider/Slider.kbd.test.ts +0 -74
  339. package/src/slider/Slider.svelte +0 -716
  340. package/src/slider/SliderKbdFixture.svelte +0 -21
  341. package/src/slider/index.ts +0 -2
  342. package/src/slider/meta.ts +0 -55
  343. package/src/space/Space.a11y.test.ts +0 -22
  344. package/src/space/Space.svelte +0 -109
  345. package/src/space/SpaceA11yFixture.svelte +0 -17
  346. package/src/space/index.ts +0 -2
  347. package/src/space/meta.ts +0 -27
  348. package/src/spin/Spin.a11y.test.ts +0 -29
  349. package/src/spin/Spin.svelte +0 -293
  350. package/src/spin/SpinA11yFixture.svelte +0 -18
  351. package/src/spin/index.ts +0 -2
  352. package/src/spin/meta.ts +0 -72
  353. package/src/steps/Steps.a11y.test.ts +0 -39
  354. package/src/steps/Steps.kbd.test.ts +0 -73
  355. package/src/steps/Steps.svelte +0 -392
  356. package/src/steps/StepsKbdFixture.svelte +0 -21
  357. package/src/steps/index.ts +0 -3
  358. package/src/steps/meta.ts +0 -59
  359. package/src/steps/types.ts +0 -8
  360. package/src/switch/Switch.a11y.test.ts +0 -46
  361. package/src/switch/Switch.kbd.test.ts +0 -40
  362. package/src/switch/Switch.svelte +0 -310
  363. package/src/switch/SwitchKbdFixture.svelte +0 -22
  364. package/src/switch/index.ts +0 -2
  365. package/src/switch/meta.ts +0 -44
  366. package/src/table/Table.a11y.test.ts +0 -70
  367. package/src/table/Table.bench.ts +0 -51
  368. package/src/table/Table.kbd.test.ts +0 -94
  369. package/src/table/Table.svelte +0 -2327
  370. package/src/table/TableKbdFixture.svelte +0 -35
  371. package/src/table/grid-nav.test.ts +0 -173
  372. package/src/table/grid-nav.ts +0 -146
  373. package/src/table/index.ts +0 -13
  374. package/src/table/meta.ts +0 -121
  375. package/src/table/types.ts +0 -133
  376. package/src/tabs/TabPane.svelte +0 -92
  377. package/src/tabs/Tabs.a11y.test.ts +0 -47
  378. package/src/tabs/Tabs.kbd.test.ts +0 -74
  379. package/src/tabs/Tabs.svelte +0 -1128
  380. package/src/tabs/TabsA11yFixture.svelte +0 -20
  381. package/src/tabs/TabsKbdFixture.svelte +0 -25
  382. package/src/tabs/context.ts +0 -43
  383. package/src/tabs/index.ts +0 -14
  384. package/src/tabs/meta.ts +0 -152
  385. package/src/tabs/types.ts +0 -6
  386. package/src/tag/Tag.a11y.test.ts +0 -33
  387. package/src/tag/Tag.svelte +0 -366
  388. package/src/tag/TagA11yFixture.svelte +0 -18
  389. package/src/tag/index.ts +0 -2
  390. package/src/tag/meta.ts +0 -92
  391. package/src/tag-input/TagInput.a11y.test.ts +0 -41
  392. package/src/tag-input/TagInput.svelte +0 -544
  393. package/src/tag-input/index.ts +0 -2
  394. package/src/tag-input/meta.ts +0 -43
  395. package/src/tag-input/reorder.test.ts +0 -59
  396. package/src/tag-input/reorder.ts +0 -41
  397. package/src/test-utils/LocaleHarness.svelte +0 -29
  398. package/src/test-utils/a11y.ts +0 -108
  399. package/src/test-utils/kbd.ts +0 -52
  400. package/src/textarea/TextArea.a11y.test.ts +0 -44
  401. package/src/textarea/TextArea.svelte +0 -420
  402. package/src/textarea/index.ts +0 -2
  403. package/src/textarea/meta.ts +0 -104
  404. package/src/time-picker/TimePicker.a11y.test.ts +0 -45
  405. package/src/time-picker/TimePicker.kbd.test.ts +0 -70
  406. package/src/time-picker/TimePicker.svelte +0 -1023
  407. package/src/time-picker/TimePickerKbdFixture.svelte +0 -23
  408. package/src/time-picker/index.ts +0 -2
  409. package/src/time-picker/meta.ts +0 -64
  410. package/src/timeline/Timeline.a11y.test.ts +0 -54
  411. package/src/timeline/Timeline.svelte +0 -599
  412. package/src/timeline/TimelineItem.svelte +0 -164
  413. package/src/timeline/context.ts +0 -28
  414. package/src/timeline/index.ts +0 -16
  415. package/src/timeline/meta.ts +0 -129
  416. package/src/timeline/types.ts +0 -9
  417. package/src/toast/Toast.a11y.test.ts +0 -67
  418. package/src/toast/ToastContainer.svelte +0 -184
  419. package/src/toast/ToastItem.svelte +0 -247
  420. package/src/toast/index.ts +0 -9
  421. package/src/toast/live-region.ts +0 -78
  422. package/src/toast/meta.ts +0 -95
  423. package/src/toast/store.ts +0 -187
  424. package/src/tooltip/Tooltip.a11y.test.ts +0 -41
  425. package/src/tooltip/Tooltip.kbd.test.ts +0 -37
  426. package/src/tooltip/Tooltip.svelte +0 -416
  427. package/src/tooltip/TooltipA11yFixture.svelte +0 -31
  428. package/src/tooltip/TooltipKbdFixture.svelte +0 -16
  429. package/src/tooltip/index.ts +0 -2
  430. package/src/tooltip/meta.ts +0 -59
  431. package/src/tooltip/placement.ts +0 -6
  432. package/src/transfer/Transfer.a11y.test.ts +0 -63
  433. package/src/transfer/Transfer.kbd.test.ts +0 -75
  434. package/src/transfer/Transfer.svelte +0 -1451
  435. package/src/transfer/TransferKbdFixture.svelte +0 -23
  436. package/src/transfer/group.test.ts +0 -55
  437. package/src/transfer/group.ts +0 -61
  438. package/src/transfer/index.ts +0 -3
  439. package/src/transfer/meta.ts +0 -55
  440. package/src/transfer/reorder.test.ts +0 -52
  441. package/src/transfer/reorder.ts +0 -42
  442. package/src/transfer/tree.test.ts +0 -44
  443. package/src/transfer/tree.ts +0 -52
  444. package/src/transfer/types.ts +0 -32
  445. package/src/tree/Tree.a11y.test.ts +0 -63
  446. package/src/tree/Tree.kbd.test.ts +0 -91
  447. package/src/tree/Tree.svelte +0 -1500
  448. package/src/tree/TreeKbdFixture.svelte +0 -30
  449. package/src/tree/index.ts +0 -3
  450. package/src/tree/meta.ts +0 -152
  451. package/src/tree-select/TreeSelect.a11y.test.ts +0 -52
  452. package/src/tree-select/TreeSelect.kbd.test.ts +0 -53
  453. package/src/tree-select/TreeSelect.svelte +0 -1611
  454. package/src/tree-select/TreeSelectKbdFixture.svelte +0 -20
  455. package/src/tree-select/index.ts +0 -3
  456. package/src/tree-select/meta.ts +0 -73
  457. package/src/tree-select/types.ts +0 -11
  458. package/src/tree-select/virtual.test.ts +0 -104
  459. package/src/typography/Link.svelte +0 -120
  460. package/src/typography/Paragraph.svelte +0 -92
  461. package/src/typography/Text.svelte +0 -93
  462. package/src/typography/Title.svelte +0 -91
  463. package/src/typography/Typography.a11y.test.ts +0 -34
  464. package/src/typography/TypographyA11yFixture.svelte +0 -27
  465. package/src/typography/TypographyBase.svelte +0 -807
  466. package/src/typography/index.ts +0 -16
  467. package/src/typography/meta.ts +0 -158
  468. package/src/upload/Upload.a11y.test.ts +0 -58
  469. package/src/upload/Upload.svelte +0 -1094
  470. package/src/upload/UploadA11yFixture.svelte +0 -23
  471. package/src/upload/index.ts +0 -3
  472. package/src/upload/meta.ts +0 -64
  473. package/src/upload/types.ts +0 -16
  474. package/src/virtual-list/VirtualList.svelte +0 -401
  475. package/src/virtual-list/index.ts +0 -2
  476. package/src/virtual-list/meta.ts +0 -106
@@ -1,1155 +0,0 @@
1
- <!--
2
- Select — see specs/components/input/Select.spec.md
3
- 单选 / 多选 / 本地过滤 / 键盘导航 / 浮层。Token-driven, a11y-correct.
4
- 下拉 portal 到 body + position:fixed(脱离 overflow:hidden 裁剪),matchWidth 跟随触发器宽度,flip 避让。
5
- maxTagCount:多选 tag 超出折叠为 +N。allowCreate:filter 无匹配时可创建新选项。
6
- 分组:options 含 { label, options:[] } 时按组渲染组标题;逻辑/键盘/filter 基于扁平序列。
7
- remote:提供 onSearch 时输入防抖回调(searchDebounce ms),由外部更新 options;loading 显示 spinner。
8
- 虚拟化:virtualized=true 时下拉只渲染视口内 option(复用 core fixedRange),spacer 撑总高、
9
- option 绝对定位按索引偏移;scrollTop 由命令式 scroll 回调 + rAF 节流写入本地 $state,可见区间
10
- 纯 $derived render 期只读(红线 #2/#3)。键盘移动 activeIndex 时命令式 scrollOffsetForIndex 滚到可见
11
- (未渲染的 active option 移动后会被滚进视口而渲染,a11y 取舍同 Tree 虚拟化)。
12
- 虚拟化仅作用于「非分组」扁平选项集(hasGroups 时回退全量渲染,忽略 virtualized)。
13
- dropdownMatchSelectWidth:浮层宽度是否跟随触发器(默认 true);false 时浮层自适应内容宽度。
14
- destroyOnClose:关闭时销毁浮层 DOM(默认 false,保持挂载)。
15
- getPopupContainer:浮层挂载目标容器(由 use:floating action 接管)。
16
- emptyContent/empty snippet:空态自定义内容。
17
- prefix/suffix/arrowIcon/clearIcon snippet:触发器前后缀与图标。
18
- dropdownHeader/dropdownFooter snippet:浮层顶/底固定区。
19
- option snippet:自定义单项渲染;label snippet:自定义选中值/Tag 渲染。
20
- onSelect/onDeselect/onClear/onCreate/onFocus/onBlur/onScrollToBottom/onExceed/onChangeWithObject。
21
- autoClearSearchValue:多选选中后自动清空搜索词(默认 true)。
22
- showRestTagsPopover:+N tag 悬停展示剩余 tags(利用 title 属性)。
23
- borderless:无边框模式;autoFocus:挂载自动聚焦;id:关联外部 label。
24
- optionLabelProp:用作回显的字段名(默认 'label',当前 OptionData 仅支持 label/value)。
25
- -->
26
- <script lang="ts">
27
- import type { Snippet } from 'svelte';
28
- import {
29
- useId,
30
- useDismiss,
31
- fixedRange,
32
- scrollOffsetForIndex,
33
- type Placement,
34
- } from '@chenzy-design/core';
35
- import { useLocale } from '../locale-provider/index.js';
36
- import { floating } from '../_floating/use-floating.js';
37
-
38
- type OptionValue = string | number;
39
- type OptionData = { label: string; value: OptionValue; disabled?: boolean; [key: string]: unknown };
40
- /** 选项分组:含 options 即为分组项 */
41
- type OptionGroup = { label: string; options: OptionData[] };
42
- type OptionOrGroup = OptionData | OptionGroup;
43
- type Size = 'small' | 'default' | 'large';
44
- type Status = 'default' | 'warning' | 'error';
45
-
46
- function isGroup(o: OptionOrGroup): o is OptionGroup {
47
- return Array.isArray((o as OptionGroup).options);
48
- }
49
-
50
- interface Props {
51
- value?: OptionValue | OptionValue[];
52
- defaultValue?: OptionValue | OptionValue[];
53
- /** 选项;可含分组项 { label, options: [] } */
54
- options?: OptionOrGroup[];
55
- multiple?: boolean;
56
- filter?: boolean;
57
- open?: boolean;
58
- defaultOpen?: boolean;
59
- size?: Size;
60
- status?: Status;
61
- /** 下拉浮层 placement(默认 bottomStart,自动避让仍生效) */
62
- placement?: Placement;
63
- placeholder?: string;
64
- /** combobox 触发器可访问名;缺省回退到 placeholder 或 locale 默认 */
65
- ariaLabel?: string;
66
- /** 关联外部 label 的 id(优先于 ariaLabel) */
67
- ariaLabelledby?: string;
68
- /** 绑定到触发器的 id 属性,用于关联外部 <label for="..."> */
69
- id?: string;
70
- disabled?: boolean;
71
- clearable?: boolean;
72
- /** 多选 tag 最大显示数,超出折叠为 +N(0=不折叠) */
73
- maxTagCount?: number;
74
- /** 多选单个 Tag 文本最大长度,超出截断为「前缀…」,完整文本经 title 查看(不截则不传) */
75
- maxTagTextLength?: number;
76
- /** filter 无匹配时允许创建新选项(值=输入文本) */
77
- allowCreate?: boolean;
78
- /** 远程搜索:输入防抖后回调(由外部更新 options,不再本地过滤) */
79
- onSearch?: (query: string) => void;
80
- /** 远程加载中(显示 spinner) */
81
- loading?: boolean;
82
- /** onSearch 防抖毫秒(默认 300) */
83
- searchDebounce?: number;
84
- /** 选项虚拟化:大数据下拉只渲染视口内 option(仅非分组生效,默认 false) */
85
- virtualized?: boolean;
86
- /** 虚拟化选项行高(px,默认 32);需与样式实际行高一致 */
87
- optionHeight?: number;
88
- /** 下拉最大高度(px,默认 256);虚拟化时同时作为视口高度 */
89
- maxHeight?: number;
90
- /** 浮层宽度是否跟随触发器(默认 true);false 时浮层自适应内容宽度 */
91
- dropdownMatchSelectWidth?: boolean;
92
- /** 关闭时销毁浮层 DOM(默认 false,复用节点避免重建开销) */
93
- destroyOnClose?: boolean;
94
- /** 浮层挂载目标容器(默认 body) */
95
- getPopupContainer?: () => HTMLElement;
96
- /** 无边框模式:移除触发器边框 */
97
- borderless?: boolean;
98
- /** 挂载后自动聚焦触发器 */
99
- autoFocus?: boolean;
100
- /** 多选选中后自动清空搜索词(默认 true) */
101
- autoClearSearchValue?: boolean;
102
- /** 超出 maxTagCount 时,将 +N 悬停展示剩余 tags(title tooltip) */
103
- showRestTagsPopover?: boolean;
104
- /** 透传给 +N 悬停 popover 的参数(预留,当前通过 title 实现) */
105
- restTagsPopoverProps?: Record<string, unknown>;
106
- /** 用作回显的字段名(默认 'label');当选项含自定义字段时取对应值作显示文本 */
107
- optionLabelProp?: string;
108
- onChange?: (v: OptionValue | OptionValue[]) => void;
109
- onOpenChange?: (open: boolean) => void;
110
- /** 选中某项时触发(多选:每次单个 toggle 选中时;单选:选中时) */
111
- onSelect?: (value: OptionValue, option: OptionData) => void;
112
- /** 多选取消某项时触发 */
113
- onDeselect?: (value: OptionValue, option: OptionData) => void;
114
- /** 点击清除按钮时触发 */
115
- onClear?: () => void;
116
- /** allowCreate 创建新项时触发 */
117
- onCreate?: (value: string) => void;
118
- /** 触发器获焦时触发 */
119
- onFocus?: () => void;
120
- /** 触发器失焦时触发 */
121
- onBlur?: () => void;
122
- /** 浮层列表滚动触底时触发 */
123
- onScrollToBottom?: () => void;
124
- /** 多选超出 maxTagCount 时触发(携带被隐藏的 option) */
125
- onExceed?: (option: OptionData) => void;
126
- /** 携带完整 option 对象的 change 回调(单选 OptionData;多选 OptionData[]) */
127
- onChangeWithObject?: (option: OptionData | OptionData[]) => void;
128
- /** 触发器左侧前缀 */
129
- prefix?: Snippet;
130
- /** 触发器右侧后缀(覆盖默认箭头区域) */
131
- suffix?: Snippet;
132
- /** 自定义清除按钮图标 */
133
- clearIcon?: Snippet;
134
- /** 自定义下拉箭头图标 */
135
- arrowIcon?: Snippet;
136
- /** 自定义空态内容(字符串或 Snippet 均可,为字符串时直接渲染文本) */
137
- emptyContent?: string | Snippet;
138
- /** 自定义空态 snippet(与 emptyContent 等价,优先级同) */
139
- empty?: Snippet;
140
- /** 浮层顶部固定区 */
141
- dropdownHeader?: Snippet;
142
- /** 浮层底部固定区 */
143
- dropdownFooter?: Snippet;
144
- /** 自定义单项渲染 */
145
- option?: Snippet<[{ option: OptionData; selected: boolean; active: boolean }]>;
146
- /** 自定义选中值/Tag 渲染 */
147
- label?: Snippet<[{ option: OptionData }]>;
148
- /** 自定义"创建xxx"项渲染 */
149
- renderCreateItem?: Snippet<[string]>;
150
- }
151
-
152
- let {
153
- value = $bindable(),
154
- defaultValue,
155
- options = [],
156
- multiple = false,
157
- filter = false,
158
- open = $bindable(),
159
- defaultOpen = false,
160
- size = 'default',
161
- status = 'default',
162
- placement = 'bottomStart',
163
- placeholder,
164
- ariaLabel,
165
- ariaLabelledby,
166
- id,
167
- disabled = false,
168
- clearable = false,
169
- maxTagCount = 0,
170
- maxTagTextLength,
171
- allowCreate = false,
172
- onSearch,
173
- loading = false,
174
- searchDebounce = 300,
175
- virtualized = false,
176
- optionHeight = 32,
177
- maxHeight = 256,
178
- dropdownMatchSelectWidth = true,
179
- destroyOnClose = false,
180
- getPopupContainer,
181
- borderless = false,
182
- autoFocus = false,
183
- autoClearSearchValue = true,
184
- showRestTagsPopover = false,
185
- restTagsPopoverProps,
186
- optionLabelProp = 'label',
187
- onChange,
188
- onOpenChange,
189
- onSelect,
190
- onDeselect,
191
- onClear,
192
- onCreate,
193
- onFocus,
194
- onBlur,
195
- onScrollToBottom,
196
- onExceed,
197
- onChangeWithObject,
198
- prefix,
199
- suffix,
200
- clearIcon,
201
- arrowIcon,
202
- emptyContent,
203
- empty,
204
- dropdownHeader,
205
- dropdownFooter,
206
- option: optionSnippet,
207
- label: labelSnippet,
208
- renderCreateItem,
209
- }: Props = $props();
210
-
211
- const loc = useLocale();
212
-
213
- const listId = useId('cd-select-list');
214
-
215
- // --- 受控值 (红线 #1): 不无条件回写 value,仅 onChange ---
216
- const isValueControlled = $derived(value !== undefined);
217
- let innerValue = $state<OptionValue | OptionValue[] | undefined>(getInitialValue());
218
- const currentValue = $derived(isValueControlled ? value : innerValue);
219
-
220
- function getInitialValue(): OptionValue | OptionValue[] | undefined {
221
- return defaultValue;
222
- }
223
-
224
- const selectedValues = $derived<OptionValue[]>(
225
- normalizeSelected(currentValue),
226
- );
227
-
228
- function normalizeSelected(v: OptionValue | OptionValue[] | undefined): OptionValue[] {
229
- if (v === undefined) return [];
230
- return Array.isArray(v) ? v : [v];
231
- }
232
-
233
- function setValue(next: OptionValue | OptionValue[]) {
234
- if (!isValueControlled) innerValue = next;
235
- onChange?.(next);
236
- }
237
-
238
- // --- 受控 open (红线 #1): 不无条件回写 open,仅 onOpenChange ---
239
- const isOpenControlled = $derived(open !== undefined);
240
- let innerOpen = $state(getInitialOpen());
241
- const isOpen = $derived(isOpenControlled ? !!open : innerOpen);
242
-
243
- function getInitialOpen(): boolean {
244
- return defaultOpen;
245
- }
246
-
247
- function setOpen(next: boolean) {
248
- if (next === isOpen) return;
249
- if (!isOpenControlled) innerOpen = next;
250
- onOpenChange?.(next);
251
- if (!next) {
252
- activeIndex = -1;
253
- query = '';
254
- }
255
- }
256
-
257
- // 挂载自动聚焦(autoFocus)。
258
- $effect(() => {
259
- if (!autoFocus || !rootEl) return;
260
- const trigger = rootEl.querySelector<HTMLElement>('[role="combobox"]');
261
- trigger?.focus();
262
- });
263
-
264
- // --- 本地过滤搜索 ---
265
- let query = $state('');
266
-
267
- // 是否含分组:决定渲染走分组结构还是扁平。
268
- const hasGroups = $derived(options.some(isGroup));
269
- // 扁平选项序列(拍平分组)——逻辑/键盘/filter/回显统一基于它。
270
- const flatBase = $derived<OptionData[]>(
271
- options.flatMap((o) => (isGroup(o) ? o.options : [o])),
272
- );
273
-
274
- // allowCreate:本地已创建选项,合并进选项集供回显与列表(不写回 options prop)。
275
- let createdOptions = $state<OptionData[]>([]);
276
- const mergedOptions = $derived<OptionData[]>(
277
- createdOptions.length === 0 ? flatBase : [...flatBase, ...createdOptions],
278
- );
279
-
280
- // remote 模式:外部已按 query 更新 options,本地不再过滤。
281
- const isRemote = $derived(onSearch !== undefined);
282
-
283
- const filteredOptions = $derived.by(() => {
284
- if (isRemote) return mergedOptions;
285
- if (!filter || query.trim() === '') return mergedOptions;
286
- const q = query.toLowerCase();
287
- return mergedOptions.filter((o) => o.label.toLowerCase().includes(q));
288
- });
289
-
290
- // 分组渲染视图:每组过滤后的选项 + 全局扁平索引(用于 activeIndex 匹配)。
291
- // 仅在 hasGroups 时使用;createdOptions 归入末尾「(新建)」无组段。
292
- const groupedView = $derived.by<{ label: string | null; items: { opt: OptionData; flatIndex: number }[] }[]>(() => {
293
- if (!hasGroups) return [];
294
- const out: { label: string | null; items: { opt: OptionData; flatIndex: number }[] }[] = [];
295
- const indexOf = (opt: OptionData) => filteredOptions.indexOf(opt);
296
- for (const o of options) {
297
- if (isGroup(o)) {
298
- const items = o.options
299
- .filter((opt) => filteredOptions.includes(opt))
300
- .map((opt) => ({ opt, flatIndex: indexOf(opt) }));
301
- if (items.length > 0) out.push({ label: o.label, items });
302
- } else if (filteredOptions.includes(o)) {
303
- out.push({ label: null, items: [{ opt: o, flatIndex: indexOf(o) }] });
304
- }
305
- }
306
- // 已创建选项(无组)
307
- const created = createdOptions
308
- .filter((opt) => filteredOptions.includes(opt))
309
- .map((opt) => ({ opt, flatIndex: indexOf(opt) }));
310
- if (created.length > 0) out.push({ label: null, items: created });
311
- return out;
312
- });
313
-
314
- // 当前输入是否可创建新选项:allowCreate + filter 有输入 + 无 label 完全匹配。
315
- const canCreate = $derived(
316
- allowCreate &&
317
- filter &&
318
- query.trim() !== '' &&
319
- !mergedOptions.some((o) => o.label.toLowerCase() === query.trim().toLowerCase()),
320
- );
321
-
322
- function createOption() {
323
- const label = query.trim();
324
- if (!label) return;
325
- const opt: OptionData = { label, value: label };
326
- createdOptions = [...createdOptions, opt];
327
- onCreate?.(label);
328
- selectOption(opt);
329
- query = '';
330
- }
331
-
332
- // --- roving 高亮 (红线 #2): activeIndex 为本地 $state,不依赖挂载 registry ---
333
- let activeIndex = $state(-1);
334
-
335
- const activeOptionId = $derived(
336
- activeIndex >= 0 && activeIndex < filteredOptions.length
337
- ? `${listId}-opt-${activeIndex}`
338
- : undefined,
339
- );
340
-
341
- // --- 选项虚拟化(仅非分组生效;分组时回退全量渲染)---
342
- // 视口=下拉容器自身滚动;scrollTop 由命令式 scroll 回调写入本地 $state,
343
- // 可见区间纯 $derived render 期只读不读 DOM(红线 #2/#3)。
344
- const VIRTUAL_OVERSCAN = 4;
345
- const isVirtual = $derived(virtualized && !hasGroups);
346
- const vOptionHeight = $derived(optionHeight > 0 ? optionHeight : 32);
347
- const vViewportH = $derived(maxHeight > 0 ? maxHeight : 256);
348
- // 仅由 scroll 回调写入的本地 scrollTop,render 期只读。
349
- let scrollTop = $state(0);
350
- // rAF 节流句柄(非响应式)。
351
- let rafId = 0;
352
-
353
- const vTotalHeight = $derived(filteredOptions.length * vOptionHeight);
354
- const vRange = $derived(
355
- isVirtual
356
- ? fixedRange(scrollTop, vViewportH, vOptionHeight, filteredOptions.length, VIRTUAL_OVERSCAN)
357
- : { startIndex: 0, endIndex: filteredOptions.length },
358
- );
359
- // 实际喂给 #each 的选项集合:虚拟化时只取视口内切片,否则全量。
360
- const vRenderOptions = $derived(
361
- isVirtual ? filteredOptions.slice(vRange.startIndex, vRange.endIndex) : filteredOptions,
362
- );
363
-
364
- const selectedOptions = $derived(
365
- mergedOptions.filter((o) => selectedValues.includes(o.value)),
366
- );
367
- // 截断纯函数:仅影响显示,超过 limit 取前 limit 字符 + 省略号(红线 #2)。
368
- function truncate(text: string, limit?: number): string {
369
- if (limit === undefined || limit < 0) return text;
370
- return text.length > limit ? `${text.slice(0, limit)}…` : text;
371
- }
372
-
373
- // maxTagCount 折叠:显示前 N 个 tag + 隐藏数。
374
- // maxTagTextLength 仅影响 tag 显示文本(截断派生),实际值/回显不变(红线 #1/#2)。
375
- const visibleTags = $derived(
376
- (maxTagCount > 0 ? selectedOptions.slice(0, maxTagCount) : selectedOptions).map(
377
- (opt) => {
378
- const raw = getOptionLabel(opt);
379
- const display = truncate(raw, maxTagTextLength);
380
- return { opt, display, truncated: display !== raw };
381
- },
382
- ),
383
- );
384
- const hiddenTagCount = $derived(
385
- maxTagCount > 0 ? Math.max(0, selectedOptions.length - maxTagCount) : 0,
386
- );
387
-
388
- // optionLabelProp:取选项对应字段作为显示文本(默认 'label')。
389
- function getOptionLabel(opt: OptionData): string {
390
- const val = opt[optionLabelProp];
391
- return typeof val === 'string' ? val : opt.label;
392
- }
393
-
394
- const singleLabel = $derived(
395
- !multiple && selectedOptions.length > 0 ? getOptionLabel(selectedOptions[0]!) : '',
396
- );
397
-
398
- const hasSelection = $derived(selectedValues.length > 0);
399
- const showClear = $derived(clearable && !disabled && hasSelection);
400
-
401
- function isSelected(v: OptionValue): boolean {
402
- return selectedValues.includes(v);
403
- }
404
-
405
- function selectOption(opt: OptionData) {
406
- if (opt.disabled || disabled) return;
407
- if (multiple) {
408
- const set = selectedValues.slice();
409
- const idx = set.indexOf(opt.value);
410
- const isAdd = idx === -1;
411
- if (isAdd) {
412
- set.push(opt.value);
413
- onSelect?.(opt.value, opt);
414
- // onExceed:新增后超出 maxTagCount 时,把被隐藏的 option 逐个通知
415
- if (onExceed && maxTagCount > 0 && set.length > maxTagCount) {
416
- // 新加入的 opt 将落入隐藏区(set 已包含 opt,取其后面被挤出的部分)
417
- const hiddenValues = set.slice(maxTagCount);
418
- for (const v of hiddenValues) {
419
- const hiddenOpt = mergedOptions.find((o) => o.value === v);
420
- if (hiddenOpt) onExceed(hiddenOpt);
421
- }
422
- }
423
- } else {
424
- set.splice(idx, 1);
425
- onDeselect?.(opt.value, opt);
426
- }
427
- setValue(set);
428
- // 多选携带完整对象回调:按新选中集合取 option
429
- const newSelected = mergedOptions.filter((o) => set.includes(o.value));
430
- onChangeWithObject?.(newSelected);
431
- // 多选选中后自动清空搜索词
432
- if (autoClearSearchValue && isAdd) query = '';
433
- // 多选不关闭
434
- } else {
435
- onSelect?.(opt.value, opt);
436
- setValue(opt.value);
437
- onChangeWithObject?.(opt);
438
- setOpen(false);
439
- }
440
- }
441
-
442
- function removeTag(v: OptionValue) {
443
- if (disabled) return;
444
- const set = selectedValues.filter((x) => x !== v);
445
- setValue(set);
446
- }
447
-
448
- function clearAll(e: MouseEvent) {
449
- e.stopPropagation();
450
- if (disabled) return;
451
- setValue(multiple ? [] : '');
452
- onClear?.();
453
- }
454
-
455
- function toggleOpen() {
456
- if (disabled) return;
457
- setOpen(!isOpen);
458
- }
459
-
460
- function moveActive(delta: number) {
461
- const len = filteredOptions.length;
462
- if (len === 0) return;
463
- let next = activeIndex;
464
- for (let i = 0; i < len; i += 1) {
465
- next = (next + delta + len) % len;
466
- if (!filteredOptions[next]?.disabled) {
467
- activeIndex = next;
468
- scrollIndexIntoView(next);
469
- return;
470
- }
471
- }
472
- }
473
-
474
- // Home/End:从列表首/末向内找首个可用(非禁用)选项作为活动项(spec §6 键盘)。
475
- function moveActiveEdge(edge: 'first' | 'last') {
476
- const len = filteredOptions.length;
477
- if (len === 0) return;
478
- const step = edge === 'first' ? 1 : -1;
479
- let i = edge === 'first' ? 0 : len - 1;
480
- while (i >= 0 && i < len) {
481
- if (!filteredOptions[i]?.disabled) {
482
- activeIndex = i;
483
- scrollIndexIntoView(i);
484
- return;
485
- }
486
- i += step;
487
- }
488
- }
489
-
490
- // 命令式滚到指定选项索引使其落入视口(虚拟化键盘导航时调用)。
491
- // 未渲染的 active option 经此滚入视口后才会渲染(a11y 取舍同 Tree 虚拟化)。
492
- function scrollIndexIntoView(index: number) {
493
- const el = dropdownEl;
494
- if (!el || !isVirtual || index < 0) return;
495
- const itemStart = index * vOptionHeight;
496
- const top = el.scrollTop;
497
- const bottom = top + el.clientHeight;
498
- // 已完整可见则不滚动,避免抖动。
499
- if (itemStart >= top && itemStart + vOptionHeight <= bottom) return;
500
- const align = itemStart < top ? 'start' : 'end';
501
- const target = scrollOffsetForIndex(
502
- itemStart,
503
- vOptionHeight,
504
- el.clientHeight,
505
- vTotalHeight,
506
- align,
507
- );
508
- el.scrollTop = target;
509
- scrollTop = target;
510
- }
511
-
512
- function onTriggerKeydown(e: KeyboardEvent) {
513
- if (disabled) return;
514
- switch (e.key) {
515
- case 'ArrowDown':
516
- e.preventDefault();
517
- if (!isOpen) setOpen(true);
518
- else moveActive(1);
519
- break;
520
- case 'ArrowUp':
521
- e.preventDefault();
522
- if (!isOpen) setOpen(true);
523
- else moveActive(-1);
524
- break;
525
- case 'Home':
526
- // 打开态下跳到列表首项;未打开则不拦截(让文本输入光标行为默认)。
527
- if (isOpen) {
528
- e.preventDefault();
529
- moveActiveEdge('first');
530
- }
531
- break;
532
- case 'End':
533
- if (isOpen) {
534
- e.preventDefault();
535
- moveActiveEdge('last');
536
- }
537
- break;
538
- case 'Enter':
539
- e.preventDefault();
540
- if (!isOpen) {
541
- setOpen(true);
542
- } else if (activeIndex >= 0) {
543
- const opt = filteredOptions[activeIndex];
544
- if (opt) selectOption(opt);
545
- } else if (canCreate) {
546
- createOption();
547
- }
548
- break;
549
- case ' ':
550
- // filter 输入时空格应输入到搜索框,不拦截
551
- if (!filter) {
552
- e.preventDefault();
553
- if (!isOpen) setOpen(true);
554
- }
555
- break;
556
- case 'Escape':
557
- if (isOpen) {
558
- e.preventDefault();
559
- setOpen(false);
560
- }
561
- break;
562
- default:
563
- break;
564
- }
565
- }
566
-
567
- // --- remote 搜索防抖(命令式定时器 + cleanup,红线 #3)---
568
- let searchTimer: ReturnType<typeof setTimeout> | undefined;
569
- function scheduleSearch(q: string) {
570
- if (searchTimer !== undefined) clearTimeout(searchTimer);
571
- searchTimer = setTimeout(() => {
572
- searchTimer = undefined;
573
- onSearch?.(q);
574
- }, Math.max(0, searchDebounce));
575
- }
576
- // 卸载兜底清理。
577
- $effect(() => () => {
578
- if (searchTimer !== undefined) clearTimeout(searchTimer);
579
- });
580
-
581
- function onSearchInput(e: Event & { currentTarget: HTMLInputElement }) {
582
- query = e.currentTarget.value;
583
- if (!isOpen) setOpen(true);
584
- activeIndex = -1;
585
- if (isRemote) scheduleSearch(query);
586
- }
587
-
588
- // --- DOM 引用:触发根 + portal 下拉(定位由 use:floating action 接管)---
589
- let rootEl = $state<HTMLDivElement | null>(null);
590
- let dropdownEl = $state<HTMLDivElement | null>(null);
591
-
592
- // --- 虚拟化滚动监听(命令式 + rAF 节流 + cleanup,红线 #3)---
593
- // 开启下拉后绑定到滚动容器;scrollTop 写本地 $state 驱动 vRange 派生。
594
- // 同时处理 onScrollToBottom(无论是否虚拟化)。
595
- $effect(() => {
596
- const el = dropdownEl;
597
- if (!el || !isOpen) return;
598
- if (isVirtual) {
599
- // 重新打开时复位滚动位置,避免沿用上次 scrollTop。
600
- scrollTop = el.scrollTop;
601
- }
602
- function onScroll() {
603
- if (isVirtual) {
604
- if (rafId) return;
605
- rafId = requestAnimationFrame(() => {
606
- rafId = 0;
607
- if (el) scrollTop = el.scrollTop;
608
- });
609
- }
610
- // 触底检测(1px 容差)
611
- if (onScrollToBottom && el) {
612
- const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
613
- if (atBottom) onScrollToBottom();
614
- }
615
- }
616
- el.addEventListener('scroll', onScroll, { passive: true });
617
- return () => {
618
- el.removeEventListener('scroll', onScroll);
619
- if (rafId) {
620
- cancelAnimationFrame(rafId);
621
- rafId = 0;
622
- }
623
- };
624
- });
625
-
626
- // --- useDismiss (红线 #3): dropdown portal 出 root 子树后列入 extraTargets ---
627
- $effect(() => {
628
- if (!isOpen || !rootEl) return;
629
- const cleanup = useDismiss(rootEl, {
630
- onDismiss: () => setOpen(false),
631
- escape: true,
632
- outsideClick: true,
633
- extraTargets: [dropdownEl],
634
- });
635
- return cleanup;
636
- });
637
-
638
- const cls = $derived(
639
- [
640
- 'cd-select',
641
- `cd-select--${size}`,
642
- `cd-select--${status}`,
643
- disabled && 'cd-select--disabled',
644
- isOpen && 'cd-select--open',
645
- multiple && 'cd-select--multiple',
646
- borderless && 'cd-select--borderless',
647
- ]
648
- .filter(Boolean)
649
- .join(' '),
650
- );
651
-
652
- // combobox 可访问名:ariaLabelledby > ariaLabel > placeholder > locale 默认
653
- const triggerAriaLabel = $derived(
654
- ariaLabelledby ? undefined : (ariaLabel || placeholder || loc().t('Select.ariaLabel')),
655
- );
656
- </script>
657
-
658
- <div class={cls} bind:this={rootEl}>
659
- <div
660
- class="cd-select__trigger"
661
- role="combobox"
662
- {id}
663
- aria-label={triggerAriaLabel}
664
- aria-labelledby={ariaLabelledby}
665
- aria-expanded={isOpen}
666
- aria-haspopup="listbox"
667
- aria-controls={listId}
668
- aria-activedescendant={activeOptionId}
669
- aria-disabled={disabled || undefined}
670
- aria-invalid={status === 'error' || undefined}
671
- tabindex={disabled ? -1 : 0}
672
- onclick={toggleOpen}
673
- onkeydown={onTriggerKeydown}
674
- onfocus={() => onFocus?.()}
675
- onblur={() => onBlur?.()}
676
- >
677
- {#if prefix}
678
- <span class="cd-select__prefix">{@render prefix()}</span>
679
- {/if}
680
-
681
- <div class="cd-select__content">
682
- {#if multiple && selectedOptions.length > 0}
683
- {#each visibleTags as tag (tag.opt.value)}
684
- <span class="cd-select__tag">
685
- {#if labelSnippet}
686
- {@render labelSnippet({ option: tag.opt })}
687
- {:else}
688
- <span
689
- class="cd-select__tag-label"
690
- title={tag.truncated ? getOptionLabel(tag.opt) : undefined}
691
- >{tag.display}</span>
692
- {/if}
693
- <button
694
- type="button"
695
- class="cd-select__tag-close"
696
- aria-label={loc().t('Select.removeItem', { label: getOptionLabel(tag.opt) })}
697
- onclick={(e) => {
698
- e.stopPropagation();
699
- removeTag(tag.opt.value);
700
- }}
701
- >
702
- <svg viewBox="0 0 16 16" width="10" height="10" aria-hidden="true" focusable="false">
703
- <path
704
- fill="currentColor"
705
- d="M9.1 8l3.2-3.2-1.1-1.1L8 6.9 4.8 3.7 3.7 4.8 6.9 8l-3.2 3.2 1.1 1.1L8 9.1l3.2 3.2 1.1-1.1L9.1 8Z"
706
- />
707
- </svg>
708
- </button>
709
- </span>
710
- {/each}
711
- {#if hiddenTagCount > 0}
712
- {@const hiddenOpts = selectedOptions.slice(maxTagCount)}
713
- <span
714
- class="cd-select__tag cd-select__tag--rest"
715
- title={showRestTagsPopover ? hiddenOpts.map((o) => getOptionLabel(o)).join(', ') : undefined}
716
- >+{hiddenTagCount}</span>
717
- {/if}
718
- {#if filter}
719
- <input
720
- class="cd-select__search"
721
- type="text"
722
- value={query}
723
- aria-label={loc().t('Select.searchPlaceholder')}
724
- oninput={onSearchInput}
725
- onkeydown={onTriggerKeydown}
726
- onclick={(e) => e.stopPropagation()}
727
- />
728
- {/if}
729
- {:else if filter}
730
- <input
731
- class="cd-select__search"
732
- type="text"
733
- value={query}
734
- placeholder={hasSelection ? singleLabel : (placeholder ?? loc().t('Select.placeholder'))}
735
- aria-label={loc().t('Select.searchPlaceholder')}
736
- oninput={onSearchInput}
737
- onkeydown={onTriggerKeydown}
738
- onclick={(e) => e.stopPropagation()}
739
- />
740
- {:else if hasSelection}
741
- {#if labelSnippet}
742
- {@render labelSnippet({ option: selectedOptions[0]! })}
743
- {:else}
744
- <span class="cd-select__value">{singleLabel}</span>
745
- {/if}
746
- {:else}
747
- <span class="cd-select__placeholder">{placeholder ?? loc().t('Select.placeholder')}</span>
748
- {/if}
749
- </div>
750
-
751
- {#if showClear}
752
- <button
753
- type="button"
754
- class="cd-select__clear"
755
- aria-label={loc().t('Select.clear')}
756
- onclick={clearAll}
757
- >
758
- {#if clearIcon}
759
- {@render clearIcon()}
760
- {:else}
761
- <svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" focusable="false">
762
- <path
763
- fill="currentColor"
764
- d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1Zm2.5 9.1-1.4 1.4L8 9.4 6.5 11l-1.4-1.4L6.6 8 5.1 6.5 6.5 5.1 8 6.6 9.5 5.1l1.4 1.4L9.4 8l1.1 1.1Z"
765
- />
766
- </svg>
767
- {/if}
768
- </button>
769
- {/if}
770
-
771
- {#if suffix}
772
- <span class="cd-select__suffix">{@render suffix()}</span>
773
- {:else}
774
- <span class="cd-select__arrow" aria-hidden="true">
775
- {#if arrowIcon}
776
- {@render arrowIcon()}
777
- {:else}
778
- <svg viewBox="0 0 16 16" width="12" height="12" focusable="false">
779
- <path fill="currentColor" d="M3.5 6 8 10.5 12.5 6l-1-1L8 8.5 4.5 5l-1 1Z" />
780
- </svg>
781
- {/if}
782
- </span>
783
- {/if}
784
- </div>
785
-
786
- {#if isOpen || !destroyOnClose}
787
- <div
788
- class="cd-select__dropdown"
789
- bind:this={dropdownEl}
790
- use:floating={{ trigger: rootEl, placement, autoAdjust: true, offset: 4, matchWidth: dropdownMatchSelectWidth }}
791
- role="listbox"
792
- id={listId}
793
- aria-multiselectable={multiple}
794
- aria-busy={loading || undefined}
795
- style={`max-block-size:${maxHeight}px`}
796
- hidden={!isOpen || undefined}
797
- >
798
- {#if dropdownHeader}
799
- <div class="cd-select__dropdown-header">{@render dropdownHeader()}</div>
800
- {/if}
801
- {#if loading}
802
- <div class="cd-select__loading">
803
- <span class="cd-select__spinner" aria-hidden="true"></span>
804
- <span>{loc().t('Select.loading')}</span>
805
- </div>
806
- {/if}
807
- {#if canCreate}
808
- <!-- svelte-ignore a11y_click_events_have_key_events -->
809
- <div
810
- class="cd-select__option cd-select__option--create"
811
- role="option"
812
- aria-selected={false}
813
- tabindex="-1"
814
- onclick={createOption}
815
- >
816
- {#if renderCreateItem}
817
- {@render renderCreateItem(query.trim())}
818
- {:else}
819
- <span class="cd-select__option-label">{loc().t('Select.create', { label: query.trim() })}</span>
820
- {/if}
821
- </div>
822
- {/if}
823
- {#if filteredOptions.length === 0 && !canCreate && !loading}
824
- <div class="cd-select__empty">
825
- {#if empty}
826
- {@render empty()}
827
- {:else if emptyContent !== undefined}
828
- {#if typeof emptyContent === 'string'}
829
- {emptyContent}
830
- {:else}
831
- {@render emptyContent()}
832
- {/if}
833
- {:else}
834
- {loc().t('Select.emptyText')}
835
- {/if}
836
- </div>
837
- {:else if hasGroups}
838
- {#each groupedView as group, gi (group.label ?? `g-${gi}`)}
839
- {#if group.label !== null}
840
- <div class="cd-select__group-label" role="presentation">{group.label}</div>
841
- {/if}
842
- {#each group.items as it (it.opt.value)}
843
- {@render optionRow(it.opt, it.flatIndex)}
844
- {/each}
845
- {/each}
846
- {:else if isVirtual}
847
- <!-- 虚拟化:spacer 撑总高,可见 option 绝对定位按全局索引偏移;只渲染视口切片 -->
848
- <div class="cd-select__spacer" style={`block-size:${vTotalHeight}px`}>
849
- {#each vRenderOptions as opt, i (opt.value)}
850
- {@render optionRow(
851
- opt,
852
- vRange.startIndex + i,
853
- `position:absolute; inset-inline:0; transform:translateY(${(vRange.startIndex + i) * vOptionHeight}px); block-size:${vOptionHeight}px`,
854
- )}
855
- {/each}
856
- </div>
857
- {:else}
858
- {#each filteredOptions as opt, i (opt.value)}
859
- {@render optionRow(opt, i)}
860
- {/each}
861
- {/if}
862
- {#if dropdownFooter}
863
- <div class="cd-select__dropdown-footer">{@render dropdownFooter()}</div>
864
- {/if}
865
- </div>
866
- {/if}
867
- </div>
868
-
869
- {#snippet optionRow(opt: OptionData, i: number, style?: string)}
870
- <!-- 选项通过 combobox 的 roving + aria-activedescendant 键盘操作,无需自身键事件 -->
871
- <!-- svelte-ignore a11y_click_events_have_key_events -->
872
- <div
873
- class="cd-select__option"
874
- class:cd-select__option--active={i === activeIndex}
875
- class:cd-select__option--selected={isSelected(opt.value)}
876
- id={`${listId}-opt-${i}`}
877
- role="option"
878
- aria-selected={isSelected(opt.value)}
879
- aria-disabled={opt.disabled || undefined}
880
- tabindex="-1"
881
- {style}
882
- onpointerenter={() => {
883
- if (!opt.disabled) activeIndex = i;
884
- }}
885
- onclick={() => selectOption(opt)}
886
- >
887
- {#if optionSnippet}
888
- {@render optionSnippet({ option: opt, selected: isSelected(opt.value), active: i === activeIndex })}
889
- {:else}
890
- {#if multiple}
891
- <span class="cd-select__check" aria-hidden="true">
892
- {#if isSelected(opt.value)}
893
- <svg viewBox="0 0 16 16" width="12" height="12" focusable="false">
894
- <path
895
- fill="currentColor"
896
- d="M6.2 11.2 2.9 7.9l1.1-1.1 2.2 2.2 5-5L12.3 5l-6.1 6.2Z"
897
- />
898
- </svg>
899
- {/if}
900
- </span>
901
- {/if}
902
- <span class="cd-select__option-label">{getOptionLabel(opt)}</span>
903
- {/if}
904
- </div>
905
- {/snippet}
906
-
907
- <style>
908
- .cd-select {
909
- position: relative;
910
- display: inline-flex;
911
- inline-size: 100%;
912
- font-size: var(--cd-select-font-size);
913
- }
914
- .cd-select__trigger {
915
- display: flex;
916
- align-items: center;
917
- gap: var(--cd-spacing-2);
918
- inline-size: 100%;
919
- min-block-size: var(--cd-select-height-default);
920
- padding-inline: var(--cd-select-padding-x);
921
- background: var(--cd-select-bg);
922
- border: 1px solid var(--cd-select-border);
923
- border-radius: var(--cd-select-radius);
924
- cursor: pointer;
925
- transition: border-color var(--cd-motion-duration-fast) var(--cd-motion-ease-standard);
926
- }
927
- .cd-select--small .cd-select__trigger {
928
- min-block-size: var(--cd-select-height-small);
929
- }
930
- .cd-select--large .cd-select__trigger {
931
- min-block-size: var(--cd-select-height-large);
932
- }
933
- .cd-select__trigger:focus-visible {
934
- outline: none;
935
- border-color: var(--cd-select-border-active);
936
- box-shadow: var(--cd-focus-ring);
937
- }
938
- .cd-select--open .cd-select__trigger {
939
- border-color: var(--cd-select-border-active);
940
- }
941
- .cd-select--error .cd-select__trigger {
942
- border-color: var(--cd-select-border-error);
943
- }
944
- .cd-select--disabled .cd-select__trigger {
945
- background: var(--cd-color-fill-0);
946
- color: var(--cd-color-text-3);
947
- cursor: not-allowed;
948
- }
949
- .cd-select__content {
950
- display: flex;
951
- flex: 1 1 auto;
952
- flex-wrap: wrap;
953
- align-items: center;
954
- gap: var(--cd-spacing-1);
955
- min-inline-size: 0;
956
- }
957
- .cd-select__placeholder {
958
- color: var(--cd-input-color-placeholder);
959
- }
960
- .cd-select__value {
961
- overflow: hidden;
962
- white-space: nowrap;
963
- text-overflow: ellipsis;
964
- }
965
- .cd-select__search {
966
- flex: 1 1 auto;
967
- min-inline-size: 2rem;
968
- margin: 0;
969
- padding: 0;
970
- border: none;
971
- background: transparent;
972
- color: inherit;
973
- font: inherit;
974
- outline: none;
975
- }
976
- .cd-select__search::placeholder {
977
- color: var(--cd-input-color-placeholder);
978
- }
979
- .cd-select__tag {
980
- display: inline-flex;
981
- align-items: center;
982
- gap: var(--cd-spacing-1);
983
- padding-inline: var(--cd-spacing-2);
984
- background: var(--cd-color-fill-1);
985
- border-radius: var(--cd-radius-1);
986
- font-size: var(--cd-font-size-1);
987
- }
988
- .cd-select__tag--rest {
989
- color: var(--cd-color-text-2);
990
- }
991
- .cd-select__option--create {
992
- color: var(--cd-color-primary);
993
- }
994
- .cd-select__tag-close {
995
- display: inline-flex;
996
- align-items: center;
997
- justify-content: center;
998
- padding: 0;
999
- border: none;
1000
- background: transparent;
1001
- color: var(--cd-color-text-2);
1002
- cursor: pointer;
1003
- }
1004
- .cd-select__tag-close:hover {
1005
- color: var(--cd-color-text-0);
1006
- }
1007
- .cd-select__clear,
1008
- .cd-select__arrow {
1009
- display: inline-flex;
1010
- align-items: center;
1011
- justify-content: center;
1012
- flex: 0 0 auto;
1013
- color: var(--cd-color-text-2);
1014
- }
1015
- .cd-select__clear {
1016
- padding: 0;
1017
- border: none;
1018
- background: transparent;
1019
- cursor: pointer;
1020
- }
1021
- .cd-select__clear:hover {
1022
- color: var(--cd-color-text-0);
1023
- }
1024
- .cd-select__arrow {
1025
- transition: transform var(--cd-motion-duration-fast) var(--cd-motion-ease-standard);
1026
- }
1027
- .cd-select--open .cd-select__arrow {
1028
- transform: rotate(180deg);
1029
- }
1030
- /* 下拉 portal 到 body,由 JS 写 position:fixed + transform + matchWidth */
1031
- .cd-select__dropdown {
1032
- z-index: var(--cd-select-dropdown-z);
1033
- max-block-size: 16rem;
1034
- overflow-y: auto;
1035
- padding-block: var(--cd-spacing-1);
1036
- background: var(--cd-select-dropdown-bg);
1037
- border-radius: var(--cd-select-dropdown-radius);
1038
- box-shadow: var(--cd-select-dropdown-shadow);
1039
- }
1040
- /* 虚拟化:spacer 撑出未渲染选项的总高,可见 option 绝对定位于其内 */
1041
- .cd-select__spacer {
1042
- position: relative;
1043
- inline-size: 100%;
1044
- }
1045
- /* 虚拟化行带固定 block-size + 内边距,需 border-box 保证行高与 optionHeight 一致 */
1046
- .cd-select__spacer .cd-select__option {
1047
- box-sizing: border-box;
1048
- overflow: hidden;
1049
- }
1050
- .cd-select__group-label {
1051
- padding: var(--cd-spacing-1) var(--cd-select-option-padding, var(--cd-spacing-2));
1052
- color: var(--cd-color-text-3);
1053
- font-size: var(--cd-font-size-1);
1054
- font-weight: var(--cd-font-weight-medium, 500);
1055
- user-select: none;
1056
- }
1057
- .cd-select__option {
1058
- display: flex;
1059
- align-items: center;
1060
- gap: var(--cd-spacing-2);
1061
- padding: var(--cd-select-option-padding);
1062
- cursor: pointer;
1063
- }
1064
- .cd-select__option--active {
1065
- background: var(--cd-select-option-bg-hover);
1066
- }
1067
- .cd-select__option--selected {
1068
- color: var(--cd-select-option-color-selected);
1069
- background: var(--cd-select-option-bg-active);
1070
- }
1071
- .cd-select__option[aria-disabled='true'] {
1072
- color: var(--cd-color-text-3);
1073
- cursor: not-allowed;
1074
- }
1075
- .cd-select__check {
1076
- display: inline-flex;
1077
- align-items: center;
1078
- justify-content: center;
1079
- inline-size: 1rem;
1080
- flex: 0 0 auto;
1081
- color: var(--cd-select-option-color-selected);
1082
- }
1083
- .cd-select__empty {
1084
- padding: var(--cd-select-option-padding);
1085
- color: var(--cd-color-text-3);
1086
- text-align: center;
1087
- }
1088
- .cd-select__loading {
1089
- display: flex;
1090
- align-items: center;
1091
- justify-content: center;
1092
- gap: var(--cd-spacing-2);
1093
- padding: var(--cd-select-option-padding);
1094
- color: var(--cd-color-text-3);
1095
- }
1096
- .cd-select__spinner {
1097
- inline-size: 1em;
1098
- block-size: 1em;
1099
- border: 2px solid var(--cd-color-border);
1100
- border-block-start-color: var(--cd-color-primary);
1101
- border-radius: var(--cd-radius-full);
1102
- animation: cd-select-spin 0.7s linear infinite;
1103
- }
1104
- @keyframes cd-select-spin {
1105
- to {
1106
- transform: rotate(360deg);
1107
- }
1108
- }
1109
- /* 无边框模式:移除触发器边框与背景 */
1110
- .cd-select--borderless .cd-select__trigger {
1111
- border-color: transparent;
1112
- background: transparent;
1113
- }
1114
- .cd-select--borderless .cd-select__trigger:focus-visible {
1115
- border-color: transparent;
1116
- box-shadow: var(--cd-focus-ring);
1117
- }
1118
- /* 前缀 / 后缀插槽 */
1119
- .cd-select__prefix,
1120
- .cd-select__suffix {
1121
- display: inline-flex;
1122
- align-items: center;
1123
- flex: 0 0 auto;
1124
- color: var(--cd-color-text-2);
1125
- }
1126
- .cd-select__prefix {
1127
- margin-inline-end: var(--cd-spacing-1);
1128
- }
1129
- .cd-select__suffix {
1130
- margin-inline-start: var(--cd-spacing-1);
1131
- }
1132
- /* 浮层顶/底固定区 */
1133
- .cd-select__dropdown-header,
1134
- .cd-select__dropdown-footer {
1135
- padding: var(--cd-spacing-1) var(--cd-select-option-padding, var(--cd-spacing-2));
1136
- border-block-color: var(--cd-color-border);
1137
- }
1138
- .cd-select__dropdown-header {
1139
- border-block-end-width: 1px;
1140
- border-block-end-style: solid;
1141
- }
1142
- .cd-select__dropdown-footer {
1143
- border-block-start-width: 1px;
1144
- border-block-start-style: solid;
1145
- }
1146
- @media (prefers-reduced-motion: reduce) {
1147
- .cd-select__spinner {
1148
- animation: none;
1149
- }
1150
- .cd-select__trigger,
1151
- .cd-select__arrow {
1152
- transition: none;
1153
- }
1154
- }
1155
- </style>