@indielayer/ui 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/docs/App.vue +19 -4
  2. package/docs/assets/css/tailwind.css +7 -1
  3. package/docs/components/Cookies.vue +3 -1
  4. package/docs/components/common/CodePreview.vue +1 -1
  5. package/docs/components/common/DocsCopyPage.vue +200 -0
  6. package/docs/components/common/DocumentPage.vue +76 -23
  7. package/docs/components/toolbar/ToolbarColorToggle.vue +29 -18
  8. package/docs/components/toolbar/ToolbarSearch.vue +4 -4
  9. package/docs/composables/useDocMeta.ts +63 -4
  10. package/docs/icons.ts +3 -0
  11. package/docs/main.ts +25 -26
  12. package/docs/pages/component/accordion/index.vue +2 -2
  13. package/docs/pages/component/alert/index.vue +2 -2
  14. package/docs/pages/component/avatar/index.vue +4 -4
  15. package/docs/pages/component/badge/index.vue +2 -2
  16. package/docs/pages/component/breadcrumbs/index.vue +2 -2
  17. package/docs/pages/component/button/button-group.vue +3 -3
  18. package/docs/pages/component/button/index.vue +14 -7
  19. package/docs/pages/component/button/tooltip.vue +10 -0
  20. package/docs/pages/component/card/index.vue +2 -2
  21. package/docs/pages/component/carousel/index.vue +2 -2
  22. package/docs/pages/component/checkbox/index.vue +5 -5
  23. package/docs/pages/component/container/index.vue +2 -2
  24. package/docs/pages/component/datepicker/index.vue +2 -2
  25. package/docs/pages/component/divider/index.vue +4 -4
  26. package/docs/pages/component/drawer/index.vue +2 -2
  27. package/docs/pages/component/empty/index.vue +3 -3
  28. package/docs/pages/component/form/index.vue +2 -2
  29. package/docs/pages/component/formGroup/index.vue +2 -2
  30. package/docs/pages/component/infiniteLoader/index.vue +3 -3
  31. package/docs/pages/component/input/index.vue +5 -5
  32. package/docs/pages/component/inputGroup/index.vue +3 -3
  33. package/docs/pages/component/inputGroup/validation.vue +6 -1
  34. package/docs/pages/component/link/index.vue +2 -2
  35. package/docs/pages/component/loader/index.vue +2 -2
  36. package/docs/pages/component/menu/index.vue +2 -2
  37. package/docs/pages/component/modal/index.vue +3 -3
  38. package/docs/pages/component/notifications/index.vue +2 -2
  39. package/docs/pages/component/pagination/index.vue +2 -2
  40. package/docs/pages/component/popover/index.vue +2 -2
  41. package/docs/pages/component/popover/usage.vue +14 -0
  42. package/docs/pages/component/progress/index.vue +3 -3
  43. package/docs/pages/component/qrCode/index.vue +2 -2
  44. package/docs/pages/component/radio/index.vue +3 -3
  45. package/docs/pages/component/scroll/index.vue +3 -3
  46. package/docs/pages/component/select/index.vue +5 -5
  47. package/docs/pages/component/skeleton/index.vue +2 -2
  48. package/docs/pages/component/slider/index.vue +2 -2
  49. package/docs/pages/component/spacer/index.vue +2 -2
  50. package/docs/pages/component/spinner/index.vue +3 -3
  51. package/docs/pages/component/table/index.vue +4 -4
  52. package/docs/pages/component/tabs/index.vue +2 -2
  53. package/docs/pages/component/tabs/usage.vue +26 -0
  54. package/docs/pages/component/tag/index.vue +2 -2
  55. package/docs/pages/component/textarea/index.vue +4 -4
  56. package/docs/pages/component/toggle/index.vue +4 -4
  57. package/docs/pages/component/upload/index.vue +2 -2
  58. package/docs/pages/component/upload/usage.vue +1 -0
  59. package/docs/pages/component/virtualGrid/index.vue +2 -2
  60. package/docs/pages/component/virtualList/index.vue +3 -3
  61. package/docs/pages/icons.vue +2 -2
  62. package/docs/router/index.ts +39 -44
  63. package/docs/search/components.json +1 -1
  64. package/docs/search/index.json +1 -1
  65. package/lib/common/buttonGroupRadius.d.ts +3 -0
  66. package/lib/common/buttonGroupRadius.js +6 -0
  67. package/lib/common/props.d.ts +1 -1
  68. package/lib/common/props.js +10 -9
  69. package/lib/components/accordion/Accordion.vue.d.ts +42 -9
  70. package/lib/components/accordion/Accordion.vue_vue_type_script_setup_true_lang.js +18 -6
  71. package/lib/components/accordion/AccordionItem.vue.d.ts +33 -6
  72. package/lib/components/accordion/AccordionItem.vue_vue_type_script_setup_true_lang.js +31 -6
  73. package/lib/components/alert/Alert.vue.d.ts +27 -6
  74. package/lib/components/alert/Alert.vue_vue_type_script_setup_true_lang.js +20 -6
  75. package/lib/components/avatar/Avatar.vue.d.ts +45 -9
  76. package/lib/components/avatar/Avatar.vue_vue_type_script_setup_true_lang.js +17 -6
  77. package/lib/components/badge/Badge.vue.d.ts +54 -9
  78. package/lib/components/badge/Badge.vue_vue_type_script_setup_true_lang.js +26 -9
  79. package/lib/components/breadcrumbs/Breadcrumbs.vue.d.ts +30 -6
  80. package/lib/components/breadcrumbs/Breadcrumbs.vue_vue_type_script_setup_true_lang.js +13 -5
  81. package/lib/components/button/Button.js +2 -2
  82. package/lib/components/button/Button.vue.d.ts +138 -28
  83. package/lib/components/button/Button.vue_vue_type_script_setup_true_lang.js +192 -70
  84. package/lib/components/button/ButtonGroup.js +4 -5
  85. package/lib/components/button/ButtonGroup.vue.d.ts +54 -10
  86. package/lib/components/button/ButtonGroup.vue_vue_type_script_setup_true_lang.js +30 -19
  87. package/lib/components/button/theme/Button.base.theme.js +6 -5
  88. package/lib/components/button/theme/Button.carbon.theme.js +6 -5
  89. package/lib/components/card/Card.vue.d.ts +3 -0
  90. package/lib/components/card/Card.vue_vue_type_script_setup_true_lang.js +4 -2
  91. package/lib/components/carousel/Carousel.vue.d.ts +21 -3
  92. package/lib/components/carousel/Carousel.vue_vue_type_script_setup_true_lang.js +23 -5
  93. package/lib/components/carousel/CarouselSlide.js +2 -2
  94. package/lib/components/carousel/CarouselSlide.vue.d.ts +3 -0
  95. package/lib/components/carousel/CarouselSlide.vue_vue_type_script_setup_true_lang.js +3 -1
  96. package/lib/components/carousel/{CarouselSlide.vue_vue_type_style_index_0_scoped_e90d2127_lang.module.js → CarouselSlide.vue_vue_type_style_index_0_scoped_4f559831_lang.module.js} +1 -1
  97. package/lib/components/checkbox/Checkbox.vue.d.ts +198 -45
  98. package/lib/components/checkbox/Checkbox.vue_vue_type_script_setup_true_lang.js +20 -3
  99. package/lib/components/container/Container.vue.d.ts +6 -0
  100. package/lib/components/container/Container.vue_vue_type_script_setup_true_lang.js +5 -2
  101. package/lib/components/datepicker/Datepicker.vue.d.ts +462 -36
  102. package/lib/components/datepicker/Datepicker.vue_vue_type_script_setup_true_lang.js +294 -153
  103. package/lib/components/divider/Divider.vue.d.ts +12 -3
  104. package/lib/components/divider/Divider.vue_vue_type_script_setup_true_lang.js +6 -2
  105. package/lib/components/drawer/Drawer.vue.d.ts +39 -6
  106. package/lib/components/drawer/Drawer.vue_vue_type_script_setup_true_lang.js +30 -7
  107. package/lib/components/empty/Empty.vue.d.ts +30 -6
  108. package/lib/components/empty/Empty.vue_vue_type_script_setup_true_lang.js +17 -4
  109. package/lib/components/form/Form.vue.d.ts +48 -9
  110. package/lib/components/form/Form.vue_vue_type_script_setup_true_lang.js +34 -7
  111. package/lib/components/formGroup/FormGroup.vue.d.ts +171 -39
  112. package/lib/components/formGroup/FormGroup.vue_vue_type_script_setup_true_lang.js +15 -9
  113. package/lib/components/icon/Icon.vue.d.ts +9 -0
  114. package/lib/components/icon/Icon.vue_vue_type_script_setup_true_lang.js +6 -3
  115. package/lib/components/image/Image.vue.d.ts +12 -3
  116. package/lib/components/image/Image.vue_vue_type_script_setup_true_lang.js +5 -1
  117. package/lib/components/index.js +18 -18
  118. package/lib/components/input/Input.vue.d.ts +291 -66
  119. package/lib/components/input/Input.vue_vue_type_script_setup_true_lang.js +53 -15
  120. package/lib/components/inputFooter/InputFooter.vue.d.ts +48 -12
  121. package/lib/components/inputFooter/InputFooter.vue_vue_type_script_setup_true_lang.js +18 -5
  122. package/lib/components/inputGroup/InputGroup.vue.d.ts +171 -39
  123. package/lib/components/inputGroup/InputGroup.vue_vue_type_script_setup_true_lang.js +6 -1
  124. package/lib/components/label/Label.vue.d.ts +78 -18
  125. package/lib/components/label/Label.vue_vue_type_script_setup_true_lang.js +28 -8
  126. package/lib/components/link/Link.js +2 -2
  127. package/lib/components/link/Link.vue.d.ts +18 -3
  128. package/lib/components/link/Link.vue_vue_type_script_setup_true_lang.js +10 -5
  129. package/lib/components/loader/Loader.vue.d.ts +30 -6
  130. package/lib/components/loader/Loader.vue_vue_type_script_setup_true_lang.js +11 -3
  131. package/lib/components/menu/Menu.vue.d.ts +51 -9
  132. package/lib/components/menu/Menu.vue_vue_type_script_setup_true_lang.js +24 -8
  133. package/lib/components/menu/MenuItem.js +2 -2
  134. package/lib/components/menu/MenuItem.vue.d.ts +198 -45
  135. package/lib/components/menu/MenuItem.vue_vue_type_script_setup_true_lang.js +84 -23
  136. package/lib/components/menu/{MenuItem.vue_vue_type_style_index_0_scoped_2a6b7341_lang.module.js → MenuItem.vue_vue_type_style_index_0_scoped_5aebaff3_lang.module.js} +1 -1
  137. package/lib/components/modal/Modal.vue.d.ts +177 -39
  138. package/lib/components/modal/Modal.vue_vue_type_script_setup_true_lang.js +104 -23
  139. package/lib/components/notifications/Notifications.vue.d.ts +24 -0
  140. package/lib/components/notifications/Notifications.vue_vue_type_script_setup_true_lang.js +39 -12
  141. package/lib/components/pagination/Pagination.vue.d.ts +12 -0
  142. package/lib/components/pagination/Pagination.vue_vue_type_script_setup_true_lang.js +8 -4
  143. package/lib/components/pagination/PaginationItem.vue.d.ts +18 -3
  144. package/lib/components/pagination/PaginationItem.vue_vue_type_script_setup_true_lang.js +8 -3
  145. package/lib/components/popover/Popover.vue.d.ts +204 -45
  146. package/lib/components/popover/Popover.vue_vue_type_script_setup_true_lang.js +157 -66
  147. package/lib/components/popover/PopoverContainer.vue.d.ts +3 -0
  148. package/lib/components/popover/PopoverContainer.vue_vue_type_script_setup_true_lang.js +3 -1
  149. package/lib/components/popover/PopoverContentBoundary.js +5 -0
  150. package/lib/components/popover/PopoverContentBoundary.vue.d.ts +9 -0
  151. package/lib/components/popover/PopoverContentBoundary.vue_vue_type_script_setup_true_lang.js +18 -0
  152. package/lib/components/popover/theme/PopoverContainer.base.theme.js +1 -1
  153. package/lib/components/progress/Progress.vue.d.ts +9 -0
  154. package/lib/components/progress/Progress.vue_vue_type_script_setup_true_lang.js +7 -4
  155. package/lib/components/qrCode/QrCode.vue.d.ts +24 -3
  156. package/lib/components/qrCode/QrCode.vue_vue_type_script_setup_true_lang.js +13 -5
  157. package/lib/components/radio/Radio.vue.d.ts +186 -42
  158. package/lib/components/radio/Radio.vue_vue_type_script_setup_true_lang.js +10 -2
  159. package/lib/components/radioButton/RadioButton.vue.d.ts +186 -42
  160. package/lib/components/radioButton/RadioButton.vue_vue_type_script_setup_true_lang.js +9 -1
  161. package/lib/components/scroll/Scroll.vue.d.ts +3 -0
  162. package/lib/components/scroll/Scroll.vue_vue_type_script_setup_true_lang.js +9 -4
  163. package/lib/components/select/Select.vue.d.ts +633 -144
  164. package/lib/components/select/Select.vue_vue_type_script_setup_true_lang.js +224 -189
  165. package/lib/components/skeleton/Skeleton.vue.d.ts +6 -0
  166. package/lib/components/skeleton/Skeleton.vue_vue_type_script_setup_true_lang.js +5 -2
  167. package/lib/components/slider/Slider.js +1 -1
  168. package/lib/components/slider/Slider.vue.d.ts +180 -39
  169. package/lib/components/slider/Slider.vue_vue_type_script_setup_true_lang.js +14 -3
  170. package/lib/components/spinner/Spinner.vue.d.ts +6 -0
  171. package/lib/components/spinner/Spinner.vue_vue_type_script_setup_true_lang.js +3 -1
  172. package/lib/components/stepper/Stepper.vue.d.ts +120 -24
  173. package/lib/components/stepper/Stepper.vue_vue_type_script_setup_true_lang.js +63 -15
  174. package/lib/components/tab/Tab.vue.d.ts +112 -31
  175. package/lib/components/tab/Tab.vue_vue_type_script_setup_true_lang.js +166 -95
  176. package/lib/components/tab/TabGroup.vue.d.ts +47 -12
  177. package/lib/components/tab/TabGroup.vue_vue_type_script_setup_true_lang.js +93 -49
  178. package/lib/components/tab/theme/Tab.base.theme.js +6 -6
  179. package/lib/components/tab/theme/Tab.carbon.theme.js +6 -6
  180. package/lib/components/tab/theme/TabGroup.base.theme.js +7 -7
  181. package/lib/components/tab/theme/TabGroup.carbon.theme.js +3 -3
  182. package/lib/components/table/Table.vue.d.ts +45 -9
  183. package/lib/components/table/Table.vue_vue_type_script_setup_true_lang.js +82 -27
  184. package/lib/components/table/TableCell.vue.d.ts +54 -12
  185. package/lib/components/table/TableCell.vue_vue_type_script_setup_true_lang.js +23 -8
  186. package/lib/components/table/TableHead.vue_vue_type_script_setup_true_lang.js +2 -1
  187. package/lib/components/table/TableHeader.vue.d.ts +18 -3
  188. package/lib/components/table/TableHeader.vue_vue_type_script_setup_true_lang.js +10 -4
  189. package/lib/components/table/TableRow.vue.d.ts +15 -3
  190. package/lib/components/table/TableRow.vue_vue_type_script_setup_true_lang.js +10 -5
  191. package/lib/components/tag/Tag.vue.d.ts +33 -6
  192. package/lib/components/tag/Tag.vue_vue_type_script_setup_true_lang.js +21 -7
  193. package/lib/components/textarea/Textarea.vue.d.ts +237 -54
  194. package/lib/components/textarea/Textarea.vue_vue_type_script_setup_true_lang.js +38 -13
  195. package/lib/components/themeProvider/ThemeProvider.vue.d.ts +10 -4
  196. package/lib/components/themeProvider/ThemeProvider.vue_vue_type_script_setup_true_lang.js +6 -1
  197. package/lib/components/toggle/Toggle.vue.d.ts +174 -39
  198. package/lib/components/toggle/Toggle.vue_vue_type_script_setup_true_lang.js +5 -1
  199. package/lib/components/tooltip/ToggleTip.vue.d.ts +24 -6
  200. package/lib/components/tooltip/ToggleTip.vue_vue_type_script_setup_true_lang.js +9 -2
  201. package/lib/components/tooltip/Tooltip.vue.d.ts +30 -6
  202. package/lib/components/tooltip/Tooltip.vue_vue_type_script_setup_true_lang.js +16 -4
  203. package/lib/components/upload/Upload.vue.d.ts +249 -57
  204. package/lib/components/upload/Upload.vue_vue_type_script_setup_true_lang.js +156 -125
  205. package/lib/components/upload/fileAccept.d.ts +6 -0
  206. package/lib/components/upload/fileAccept.js +17 -0
  207. package/lib/composables/useColors.d.ts +1 -0
  208. package/lib/composables/useColors.js +2 -1
  209. package/lib/composables/useCommon.d.ts +1 -0
  210. package/lib/composables/useCommon.js +2 -1
  211. package/lib/composables/useFocusTrap.js +1 -1
  212. package/lib/composables/useInputtable.d.ts +45 -10
  213. package/lib/composables/useInputtable.js +56 -14
  214. package/lib/composables/useInteractive.d.ts +13 -3
  215. package/lib/composables/useInteractive.js +14 -4
  216. package/lib/index.js +12 -12
  217. package/lib/index.umd.js +9 -10
  218. package/lib/themes/base/styles.d.ts +1 -1
  219. package/lib/themes/base/styles.js +1 -1
  220. package/lib/themes/carbon/styles.d.ts +1 -1
  221. package/lib/themes/carbon/styles.js +1 -1
  222. package/lib/version.d.ts +1 -1
  223. package/lib/version.js +1 -1
  224. package/lib/virtual/components/infiniteLoader/InfiniteLoader.vue.d.ts +27 -16
  225. package/lib/virtual/components/infiniteLoader/InfiniteLoader.vue_vue_type_script_setup_true_lang.js +25 -5
  226. package/lib/virtual/components/virtualGrid/VirtualGrid.vue.d.ts +108 -86
  227. package/lib/virtual/components/virtualGrid/VirtualGrid.vue_vue_type_script_setup_true_lang.js +91 -21
  228. package/lib/virtual/components/virtualList/VirtualList.vue.d.ts +62 -48
  229. package/lib/virtual/components/virtualList/VirtualList.vue_vue_type_script_setup_true_lang.js +64 -13
  230. package/lib/virtual/components/virtualList/useDynamicRowHeight.js +4 -3
  231. package/package.json +5 -3
  232. package/src/common/buttonGroupRadius.ts +16 -0
  233. package/src/common/props.ts +10 -9
  234. package/src/components/accordion/Accordion.vue +20 -4
  235. package/src/components/accordion/AccordionItem.vue +28 -3
  236. package/src/components/alert/Alert.vue +22 -6
  237. package/src/components/avatar/Avatar.vue +20 -5
  238. package/src/components/badge/Badge.vue +24 -5
  239. package/src/components/breadcrumbs/Breadcrumbs.vue +15 -5
  240. package/src/components/button/Button.vue +140 -5
  241. package/src/components/button/ButtonGroup.vue +41 -25
  242. package/src/components/button/__tests__/ Button.spec.ts +41 -0
  243. package/src/components/button/__tests__/ ButtonGroup.spec.ts +32 -0
  244. package/src/components/button/theme/Button.base.theme.ts +4 -1
  245. package/src/components/button/theme/Button.carbon.theme.ts +5 -4
  246. package/src/components/card/Card.vue +10 -2
  247. package/src/components/carousel/Carousel.vue +22 -2
  248. package/src/components/carousel/CarouselSlide.vue +6 -0
  249. package/src/components/checkbox/Checkbox.vue +22 -3
  250. package/src/components/container/Container.vue +10 -1
  251. package/src/components/datepicker/Datepicker.vue +466 -101
  252. package/src/components/datepicker/__tests__/Datepicker.spec.ts +31 -0
  253. package/src/components/divider/Divider.vue +9 -3
  254. package/src/components/drawer/Drawer.vue +27 -2
  255. package/src/components/empty/Empty.vue +18 -3
  256. package/src/components/form/Form.vue +32 -3
  257. package/src/components/formGroup/FormGroup.vue +12 -0
  258. package/src/components/icon/Icon.vue +4 -1
  259. package/src/components/image/Image.vue +8 -2
  260. package/src/components/input/Input.vue +54 -12
  261. package/src/components/inputFooter/InputFooter.vue +21 -6
  262. package/src/components/inputGroup/InputGroup.vue +12 -1
  263. package/src/components/label/Label.vue +31 -7
  264. package/src/components/link/Link.vue +16 -5
  265. package/src/components/loader/Loader.vue +10 -2
  266. package/src/components/menu/Menu.vue +23 -5
  267. package/src/components/menu/MenuItem.vue +78 -17
  268. package/src/components/modal/Modal.vue +90 -15
  269. package/src/components/notifications/Notifications.vue +23 -0
  270. package/src/components/notifications/__tests__/Notifications.spec.ts +44 -4
  271. package/src/components/pagination/Pagination.vue +9 -1
  272. package/src/components/pagination/PaginationItem.vue +11 -2
  273. package/src/components/popover/Popover.vue +113 -18
  274. package/src/components/popover/PopoverContainer.vue +9 -1
  275. package/src/components/popover/PopoverContentBoundary.vue +32 -0
  276. package/src/components/popover/__tests__/Popover.spec.ts +51 -0
  277. package/src/components/popover/theme/PopoverContainer.base.theme.ts +1 -1
  278. package/src/components/progress/Progress.vue +8 -3
  279. package/src/components/qrCode/QrCode.vue +9 -1
  280. package/src/components/radio/Radio.vue +16 -2
  281. package/src/components/radioButton/RadioButton.vue +15 -1
  282. package/src/components/scroll/Scroll.vue +15 -4
  283. package/src/components/select/Select.vue +53 -16
  284. package/src/components/skeleton/Skeleton.vue +3 -0
  285. package/src/components/slider/Slider.vue +15 -0
  286. package/src/components/spinner/Spinner.vue +2 -0
  287. package/src/components/stepper/Stepper.vue +57 -9
  288. package/src/components/tab/Tab.vue +153 -63
  289. package/src/components/tab/TabGroup.vue +110 -26
  290. package/src/components/tab/__tests__/Tab.spec.ts +53 -0
  291. package/src/components/tab/__tests__/TabGroup.spec.ts +113 -0
  292. package/src/components/tab/theme/Tab.base.theme.ts +24 -2
  293. package/src/components/tab/theme/Tab.carbon.theme.ts +30 -7
  294. package/src/components/tab/theme/TabGroup.base.theme.ts +12 -9
  295. package/src/components/tab/theme/TabGroup.carbon.theme.ts +6 -2
  296. package/src/components/table/Table.vue +76 -19
  297. package/src/components/table/TableCell.vue +25 -6
  298. package/src/components/table/TableHead.vue +9 -2
  299. package/src/components/table/TableHeader.vue +16 -3
  300. package/src/components/table/TableRow.vue +17 -5
  301. package/src/components/tag/Tag.vue +22 -6
  302. package/src/components/textarea/Textarea.vue +40 -11
  303. package/src/components/themeProvider/ThemeProvider.vue +22 -7
  304. package/src/components/toggle/Toggle.vue +9 -1
  305. package/src/components/tooltip/ToggleTip.vue +12 -3
  306. package/src/components/tooltip/Tooltip.vue +19 -3
  307. package/src/components/upload/Upload.vue +46 -16
  308. package/src/components/upload/__tests__/fileAccept.spec.ts +39 -0
  309. package/src/components/upload/fileAccept.ts +29 -0
  310. package/src/composables/useColors.ts +1 -0
  311. package/src/composables/useCommon.ts +1 -0
  312. package/src/composables/useFocusTrap.ts +3 -1
  313. package/src/composables/useInputtable.ts +66 -10
  314. package/src/composables/useInteractive.ts +13 -3
  315. package/src/themes/base/styles.ts +2 -3
  316. package/src/themes/carbon/styles.ts +2 -3
  317. package/src/version.ts +1 -1
  318. package/src/virtual/components/infiniteLoader/InfiniteLoader.vue +33 -1
  319. package/src/virtual/components/virtualGrid/VirtualGrid.vue +104 -10
  320. package/src/virtual/components/virtualList/VirtualList.vue +73 -8
  321. package/src/virtual/components/virtualList/useDynamicRowHeight.ts +9 -2
  322. package/volar.d.ts +3 -0
  323. package/docs/layouts/simple.vue +0 -5
  324. package/lib/components/button/ButtonGroup.vue_vue_type_style_index_0_lang.module.js +0 -7
  325. /package/lib/components/button/{Button.vue_vue_type_style_index_0_scoped_4402fde2_lang.module.js → Button.vue_vue_type_style_index_0_scoped_486cb9c0_lang.module.js} +0 -0
  326. /package/lib/components/link/{Link.vue_vue_type_style_index_0_scoped_8e0e4d08_lang.module.js → Link.vue_vue_type_style_index_0_scoped_3ee61e03_lang.module.js} +0 -0
@@ -3,19 +3,50 @@ import { optionalBooleanProp } from '../../common/props'
3
3
 
4
4
  const tabProps = {
5
5
  ...useCommon.props(),
6
+ size: {
7
+ type: String as PropType<Size>,
8
+ validator: (value: string) => useCommon.validators().size.includes(value),
9
+ description: 'Tab size. Falls back to the parent tab group size when omitted.',
10
+ },
6
11
  value: {
7
12
  type: [String, Number],
13
+ description: 'Value used to select this tab in the group.',
8
14
  },
9
15
  tag: {
10
16
  type: String,
11
17
  default: 'button',
18
+ description: 'Root element tag when not using `to`.',
19
+ },
20
+ to: {
21
+ type: [String, Object],
22
+ description: 'Vue Router location; renders as a link when set.',
23
+ },
24
+ label: {
25
+ type: String,
26
+ description: 'Visible label. Defaults to `value` when omitted.',
27
+ },
28
+ icon: {
29
+ type: String,
30
+ description: 'Icon name shown before the label.',
12
31
  },
13
- to: [String, Object],
14
- label: String,
15
- icon: String,
16
- disabled: Boolean,
17
- exact: Boolean,
18
- removable: optionalBooleanProp(),
32
+ tooltip: {
33
+ type: String,
34
+ description: 'Tooltip text. Prefer the tooltip slot for custom content.',
35
+ },
36
+ tooltipPosition: {
37
+ type: String as PropType<TooltipPosition>,
38
+ default: 'top',
39
+ description: 'Tooltip placement relative to the tab.',
40
+ },
41
+ disabled: {
42
+ type: Boolean,
43
+ description: 'Prevents selecting this tab.',
44
+ },
45
+ exact: {
46
+ type: Boolean,
47
+ description: 'Requires exact route match when using `to`.',
48
+ },
49
+ removable: optionalBooleanProp('Shows a remove control that emits `remove`.'),
19
50
  }
20
51
 
21
52
  export type TabProps = ExtractPublicPropTypes<typeof tabProps>
@@ -23,6 +54,7 @@ export type TabProps = ExtractPublicPropTypes<typeof tabProps>
23
54
  type InternalClasses = 'wrapper' | 'content' | 'label' | 'icon' | 'tabpanel'
24
55
  type InternalExtraData = {
25
56
  selected: boolean;
57
+ showLabel: boolean;
26
58
  } & Pick<TabGroupInjection, 'state'>['state']
27
59
  export interface TabTheme extends ThemeComponent<TabProps, InternalClasses, InternalExtraData> {}
28
60
 
@@ -31,11 +63,21 @@ export default {
31
63
  validators: {
32
64
  ...useCommon.validators(),
33
65
  },
66
+ docs: {
67
+ slots: {
68
+ default: 'Tab panel content shown when this tab is selected.',
69
+ tab: 'Custom tab trigger content. Slot props: label, value, size, icon.',
70
+ tooltip: 'Custom tooltip content; overrides the `tooltip` prop.',
71
+ },
72
+ emits: {
73
+ remove: 'Emitted when the remove control is clicked.',
74
+ },
75
+ },
34
76
  }
35
77
  </script>
36
78
 
37
79
  <script setup lang="ts">
38
- import { inject, reactive, computed, ref, onMounted, type ExtractPublicPropTypes } from 'vue'
80
+ import { inject, reactive, computed, ref, onMounted, onBeforeUnmount, type ExtractPublicPropTypes, type PropType } from 'vue'
39
81
  import { useMutationObserver } from '@vueuse/core'
40
82
  import { injectTabGroupKey } from '../../composables/keys'
41
83
  import { useCommon, type Size } from '../../composables/useCommon'
@@ -44,22 +86,40 @@ import { useResolvedComponentProps } from '../../composables/resolveComponentDef
44
86
 
45
87
  import XIcon from '../icon/Icon.vue'
46
88
  import XLink from '../link/Link.vue'
89
+ import XTooltip from '../tooltip/Tooltip.vue'
47
90
 
48
91
  import { closeIcon } from '../../common/icons'
49
92
 
93
+ import type { TooltipPosition } from '../tooltip/Tooltip.vue'
50
94
  import type { TabGroupInjection, TabGroupVariant } from './TabGroup.vue'
51
95
 
52
96
  const props = defineProps(tabProps)
53
97
  const resolvedProps = useResolvedComponentProps('Tab', props)
54
98
 
55
99
  const computedValue = computed(() => (elRef.value as typeof XLink)?.$el?.href || props.value)
100
+ const showLabel = computed(() => {
101
+ if (props.icon && (props.label === undefined || props.label === '')) return false
102
+
103
+ return true
104
+ })
56
105
  const computedLabel = computed(() => props.label || props.value)
106
+ const ariaLabel = computed(() => {
107
+ if (showLabel.value) return undefined
108
+
109
+ if (props.tooltip) return props.tooltip
110
+ if (props.label) return props.label
111
+ if (computedValue.value !== undefined && computedValue.value !== null) return String(computedValue.value)
112
+
113
+ return undefined
114
+ })
57
115
  const teleportTo = ref<HTMLElement | null>(null)
58
116
  const elRef = ref<HTMLElement | typeof XLink | null>(null)
59
117
 
60
118
  const tabs = inject(injectTabGroupKey, {
61
119
  tabsContentRef: ref(null),
62
120
  activateTab: () => {},
121
+ registerTab: () => {},
122
+ unregisterTab: () => {},
63
123
  state: reactive({
64
124
  active: undefined,
65
125
  variant: 'line' as TabGroupVariant,
@@ -72,11 +132,13 @@ const tabs = inject(injectTabGroupKey, {
72
132
  })
73
133
 
74
134
  const computedExact = computed(() => tabs.state.exact || props.exact)
75
- const computedSize = computed(() => props.size || tabs.state.size)
135
+ const computedSize = computed(() => props.size ?? tabs.state.size ?? 'md')
76
136
 
77
137
  onMounted(() => {
78
138
  teleportTo.value = tabs.tabsContentRef.value
79
139
 
140
+ if (typeof computedValue.value !== 'undefined') tabs.registerTab(computedValue.value)
141
+
80
142
  if (props.to && elRef.value) {
81
143
  check()
82
144
  useMutationObserver((elRef.value as typeof XLink).$el, check, {
@@ -86,6 +148,10 @@ onMounted(() => {
86
148
  }
87
149
  })
88
150
 
151
+ onBeforeUnmount(() => {
152
+ if (typeof computedValue.value !== 'undefined') tabs.unregisterTab(computedValue.value)
153
+ })
154
+
89
155
  function check() {
90
156
  if (elRef.value && (elRef.value as typeof XLink).$el && (props.to)) {
91
157
  const active = (elRef.value as typeof XLink).$el.classList.contains(computedExact.value ? 'router-link-exact-active' : 'router-link-active')
@@ -111,74 +177,98 @@ function onClickTab(e: MouseEvent) {
111
177
 
112
178
  defineEmits(['remove'])
113
179
 
114
- const { styles, classes, className } = useTheme('Tab', {}, ref({
180
+ const isBlockLike = computed(() => tabs.state.variant === 'block' || tabs.state.variant === 'compact')
181
+
182
+ const themeProps = computed(() => ({
115
183
  ...props,
116
184
  size: computedSize.value,
117
185
  exact: computedExact.value,
118
- }), {
186
+ }))
187
+
188
+ const { styles, classes, className } = useTheme('Tab', {}, themeProps, {
119
189
  ...tabs.state,
120
190
  selected,
191
+ showLabel,
121
192
  })
122
193
  </script>
123
194
 
124
195
  <template>
125
- <component
126
- :is="to ? XLink : tag"
127
- ref="elRef"
128
- :type="tag === 'button' ? 'button' : undefined"
196
+ <x-tooltip
197
+ :position="tooltipPosition"
129
198
  :data-value="computedValue"
130
- :to="to"
131
- :color="selected ? color : undefined"
132
- :style="[
133
- styles,
134
- to && selected && tabs.state.variant === 'block'
135
- ? '--x-link-text: var(--x-tab-group-text); --x-link-text-hover: var(--x-tab-group-text);'
136
- : ''
137
- ]"
138
199
  :class="[
139
- className,
140
- classes.wrapper,
141
200
  'shrink-0',
142
- {
143
- 'flex-1': tabs.state.grow,
144
- 'text-[color:var(--x-tab-group-text)] dark:text-[color:var(--x-tab-group-dark-text)]': selected,
145
- 'cursor-pointer': !disabled,
146
- 'cursor-not-allowed': disabled,
147
- 'cursor-not-allowed text-secondary-500': disabled && !selected,
148
- },
201
+ { 'flex-1': tabs.state.grow },
149
202
  ]"
150
- :aria-disabled="disabled ? 'true' : undefined"
151
- :aria-selected="selected ? 'true' : 'false'"
152
- @click="onClickTab"
153
203
  >
154
- <slot
155
- name="tab"
156
- :label="label"
157
- :value="value"
158
- :size="computedSize"
159
- :icon="icon"
204
+ <template v-if="$slots.tooltip || tooltip" #tooltip>
205
+ <slot name="tooltip">
206
+ {{ tooltip }}
207
+ </slot>
208
+ </template>
209
+ <component
210
+ :is="to ? XLink : tag"
211
+ ref="elRef"
212
+ :type="tag === 'button' ? 'button' : undefined"
213
+ :to="to"
214
+ :color="selected ? color : undefined"
215
+ :style="[
216
+ styles,
217
+ to && selected && isBlockLike
218
+ ? '--x-link-text: var(--x-tab-group-text); --x-link-text-hover: var(--x-tab-group-text);'
219
+ : ''
220
+ ]"
221
+ :class="[
222
+ className,
223
+ classes.wrapper,
224
+ 'flex items-center justify-center',
225
+ {
226
+ 'w-full': tabs.state.grow,
227
+ 'text-[color:var(--x-tab-group-text)] dark:text-[color:var(--x-tab-group-dark-text)]': selected,
228
+ 'cursor-pointer': !disabled,
229
+ 'cursor-not-allowed': disabled,
230
+ 'cursor-not-allowed text-secondary-500': disabled && !selected,
231
+ },
232
+ ]"
233
+ :aria-label="ariaLabel"
234
+ :aria-disabled="disabled ? 'true' : undefined"
235
+ :aria-selected="selected ? 'true' : 'false'"
236
+ @click="onClickTab"
160
237
  >
161
- <div :class="classes.content">
162
- <x-icon
163
- v-if="icon"
164
- :icon="icon"
165
- :size="computedSize"
166
- :class="classes.icon"
167
- />
168
- <div :class="classes.label">{{ computedLabel }}</div>
169
- <x-icon
170
- v-if="resolvedProps.removable"
171
- size="sm"
172
- :icon="closeIcon"
173
- class="ml-2 cursor-pointer hover:text-secondary-700 dark:hover:text-secondary-500 transition-colors duration-150"
174
- @click="(e: Event) => $emit('remove', e)"
175
- />
176
- </div>
177
- </slot>
178
- <teleport v-if="selected && teleportTo" :to="teleportTo">
179
- <div v-if="$slots.default" role="tabpanel" :class="classes.tabpanel">
180
- <slot></slot>
181
- </div>
182
- </teleport>
183
- </component>
238
+ <slot
239
+ name="tab"
240
+ :label="label"
241
+ :value="value"
242
+ :size="computedSize"
243
+ :icon="icon"
244
+ >
245
+ <div :class="classes.content">
246
+ <x-icon
247
+ v-if="icon"
248
+ :icon="icon"
249
+ :size="computedSize"
250
+ :class="classes.icon"
251
+ />
252
+ <div
253
+ v-if="showLabel"
254
+ :class="classes.label"
255
+ >
256
+ {{ computedLabel }}
257
+ </div>
258
+ <x-icon
259
+ v-if="resolvedProps.removable"
260
+ size="sm"
261
+ :icon="closeIcon"
262
+ class="ml-2 cursor-pointer hover:text-secondary-700 dark:hover:text-secondary-500 transition-colors duration-150"
263
+ @click="(e: Event) => $emit('remove', e)"
264
+ />
265
+ </div>
266
+ </slot>
267
+ <teleport v-if="selected && teleportTo" :to="teleportTo">
268
+ <div v-if="$slots.default" role="tabpanel" :class="classes.tabpanel">
269
+ <slot></slot>
270
+ </div>
271
+ </teleport>
272
+ </component>
273
+ </x-tooltip>
184
274
  </template>
@@ -3,33 +3,44 @@ import { optionalBooleanProp } from '../../common/props'
3
3
 
4
4
  const validators = {
5
5
  ...useCommon.validators(),
6
- variant: ['line', 'block'] as const,
6
+ variant: ['line', 'block', 'compact'] as const,
7
7
  align: ['left', 'center', 'right'] as const,
8
8
  }
9
9
  const tabGroupProps = {
10
10
  ...useCommon.props(),
11
11
  ...useColors.props('primary'),
12
- modelValue: [String, Number],
12
+ modelValue: {
13
+ type: [String, Number],
14
+ description: 'Active tab value (v-model).',
15
+ },
13
16
  variant: {
14
- type: String as PropType<'line' | 'block'>,
17
+ type: String as PropType<'line' | 'block' | 'compact'>,
15
18
  default: 'line',
19
+ description: 'Visual style of the tab list (line, block, or compact).',
16
20
  },
17
21
  align: {
18
22
  type: String as PropType<'left' | 'center' | 'right'>,
19
23
  default: 'left',
24
+ description: 'Horizontal alignment of tabs in the list.',
25
+ },
26
+ ghost: optionalBooleanProp('Subtle styling with less background emphasis.'),
27
+ grow: optionalBooleanProp('Stretches tabs to fill the list width.'),
28
+ exact: {
29
+ type: Boolean,
30
+ description: 'Default exact route matching for linked tabs.',
20
31
  },
21
- ghost: optionalBooleanProp(),
22
- grow: optionalBooleanProp(),
23
- exact: Boolean,
24
32
  fullWidth: {
25
33
  type: Boolean,
26
34
  default: true,
35
+ description: 'Stretches the tab list to the container width.',
27
36
  },
28
37
  }
29
38
 
30
39
  export type TabGroupInjection = {
31
40
  tabsContentRef: Ref<HTMLElement | null>;
32
- activateTab: (tab: string | number) => void;
41
+ activateTab: (tab: string | number | null) => void;
42
+ registerTab: (tab: string | number) => void;
43
+ unregisterTab: (tab: string | number) => void;
33
44
  state: {
34
45
  active: string | number | undefined;
35
46
  variant: TabGroupVariant;
@@ -50,6 +61,14 @@ export interface TabGroupTheme extends ThemeComponent<TabGroupProps, InternalCla
50
61
  export default {
51
62
  name: 'XTabGroup',
52
63
  validators,
64
+ docs: {
65
+ slots: {
66
+ default: 'Tab triggers (typically x-tab children).',
67
+ },
68
+ emits: {
69
+ 'update:modelValue': 'Emitted when the active tab changes (v-model).',
70
+ },
71
+ },
53
72
  }
54
73
  </script>
55
74
 
@@ -91,38 +110,100 @@ const state = reactive({
91
110
  color: computed(() => props.color),
92
111
  })
93
112
 
113
+ const showTracker = ref(true)
114
+ const registeredTabs: (string | number)[] = []
115
+
94
116
  function activateTab(tab: string | number | null) {
95
117
  active.value = tab
96
118
  emit('update:modelValue', tab)
97
119
  }
98
120
 
121
+ function registerTab(tab: string | number) {
122
+ if (!registeredTabs.includes(tab)) registeredTabs.push(tab)
123
+ }
124
+
125
+ function unregisterTab(tab: string | number) {
126
+ const index = registeredTabs.indexOf(tab)
127
+
128
+ if (index === -1) return
129
+
130
+ registeredTabs.splice(index, 1)
131
+
132
+ if (active.value !== tab) return
133
+
134
+ const fallback = registeredTabs[Math.min(index, registeredTabs.length - 1)]
135
+
136
+ if (typeof fallback !== 'undefined') {
137
+ activateTab(fallback)
138
+ } else {
139
+ activateTab(null)
140
+ showTracker.value = false
141
+ }
142
+ }
143
+
99
144
  provide(injectTabGroupKey, {
100
145
  tabsContentRef,
101
146
  activateTab,
147
+ registerTab,
148
+ unregisterTab,
102
149
  state,
103
150
  })
104
151
 
105
152
  const updateTracker = useThrottleFn(async (value: string | number | undefined) => {
106
- if (typeof value === 'undefined') return
153
+ if (typeof value === 'undefined' || value === null) {
154
+ showTracker.value = false
155
+
156
+ return
157
+ }
107
158
 
108
159
  await nextTick()
109
160
 
110
161
  const tabEl = tabsRef.value?.querySelector(`[data-value="${value}"]`) as HTMLElement
111
162
 
112
- if (!tabEl || !trackerRef.value) return
163
+ if (!tabEl || !trackerRef.value) {
164
+ showTracker.value = false
113
165
 
166
+ return
167
+ }
168
+
169
+ showTracker.value = true
114
170
  trackerRef.value.style.left = `${tabEl.offsetLeft}px`
115
171
  trackerRef.value.style.width = `${tabEl.offsetWidth}px`
116
172
 
117
- if (!tabsRef.value || !scrollRef.value) return
173
+ if (!tabsRef.value || !scrollRef.value?.scrollEl) return
118
174
 
119
- // scrollIntoView only updates one at a time
120
- const center = tabEl.offsetLeft - (tabsRef.value.getBoundingClientRect().width - tabEl.getBoundingClientRect().width) / 2
175
+ const scrollEl = scrollRef.value.scrollEl
176
+ // Measure overflow from the in-flow tabs list only (tracker is absolute and clipped).
177
+ const maxScroll = Math.max(0, tabsRef.value.scrollWidth - scrollEl.clientWidth)
178
+ const viewLeft = scrollEl.scrollLeft
179
+ const viewRight = viewLeft + scrollEl.clientWidth
180
+ const tabLeft = tabEl.offsetLeft
181
+ const tabRight = tabLeft + tabEl.offsetWidth
182
+ const tabFullyVisible = tabLeft >= viewLeft && tabRight <= viewRight
121
183
 
122
- if (scrollRef.value.scrollEl) scrollRef.value.scrollEl.scrollTo({ left: center, behavior: 'smooth' })
123
- }, 100, true)
184
+ if (maxScroll <= 0) {
185
+ if (scrollEl.scrollLeft !== 0) scrollEl.scrollTo({ left: 0 })
186
+ scrollEl.dispatchEvent(new CustomEvent('scroll'))
124
187
 
125
- const showTracker = ref(true)
188
+ return
189
+ }
190
+
191
+ if (tabFullyVisible) {
192
+ scrollEl.dispatchEvent(new CustomEvent('scroll'))
193
+
194
+ return
195
+ }
196
+
197
+ let nextLeft = viewLeft
198
+
199
+ if (tabLeft < viewLeft) nextLeft = tabLeft
200
+ else if (tabRight > viewRight) nextLeft = tabRight - scrollEl.clientWidth
201
+
202
+ nextLeft = Math.max(0, Math.min(nextLeft, maxScroll))
203
+
204
+ if (nextLeft !== viewLeft) scrollEl.scrollTo({ left: nextLeft, behavior: 'smooth' })
205
+ else scrollEl.dispatchEvent(new CustomEvent('scroll'))
206
+ }, 100, true)
126
207
 
127
208
  function check() {
128
209
  if (!tabsRef.value?.querySelector('.router-link-active')) {
@@ -170,18 +251,21 @@ const { styles, classes, className } = useTheme('TabGroup', {}, props)
170
251
  mousewheel
171
252
  :class="classes.scroller"
172
253
  >
173
- <div
174
- ref="tabsRef"
175
- class="relative"
176
- :class="classes.list"
177
- >
178
- <slot></slot>
254
+ <div class="relative overflow-x-clip">
255
+ <div
256
+ ref="tabsRef"
257
+ class="relative"
258
+ :class="classes.list"
259
+ >
260
+ <slot></slot>
261
+ </div>
262
+ <div
263
+ v-show="showTracker"
264
+ ref="trackerRef"
265
+ class="pointer-events-none"
266
+ :class="classes.tracker"
267
+ ></div>
179
268
  </div>
180
- <div
181
- v-show="showTracker"
182
- ref="trackerRef"
183
- :class="classes.tracker"
184
- ></div>
185
269
  </x-scroll>
186
270
  </div>
187
271
  <div ref="tabsContentRef"></div>
@@ -8,4 +8,57 @@ describe('Tab', () => {
8
8
 
9
9
  expect(wrapper.vm).toBeTruthy()
10
10
  })
11
+
12
+ it('falls back label to value when icon is absent', () => {
13
+ const wrapper = mount(Tab, {
14
+ props: { value: 'grid' },
15
+ })
16
+
17
+ expect(wrapper.text()).toContain('grid')
18
+ })
19
+
20
+ it('omits label when icon is set without label', () => {
21
+ const wrapper = mount(Tab, {
22
+ props: { value: 'grid', icon: 'grid' },
23
+ global: {
24
+ stubs: { XIcon: true },
25
+ },
26
+ })
27
+
28
+ expect(wrapper.text()).not.toContain('grid')
29
+ })
30
+
31
+ it('renders label when icon and label are both set', () => {
32
+ const wrapper = mount(Tab, {
33
+ props: { value: 'grid', icon: 'grid', label: 'Grid' },
34
+ global: {
35
+ stubs: { XIcon: true },
36
+ },
37
+ })
38
+
39
+ expect(wrapper.text()).toContain('Grid')
40
+ })
41
+
42
+ it('passes tooltip to the tooltip wrapper', () => {
43
+ const wrapper = mount(Tab, {
44
+ props: { value: 'grid', icon: 'grid', tooltip: 'Grid view' },
45
+ global: {
46
+ stubs: {
47
+ XIcon: true,
48
+ XTooltip: {
49
+ props: ['position'],
50
+ template: `
51
+ <div class="tooltip-stub">
52
+ <slot />
53
+ <div class="tooltip-content"><slot name="tooltip" /></div>
54
+ </div>
55
+ `,
56
+ },
57
+ },
58
+ },
59
+ })
60
+
61
+ expect(wrapper.find('.tooltip-content').text()).toBe('Grid view')
62
+ expect(wrapper.find('[aria-label="Grid view"]').exists()).toBe(true)
63
+ })
11
64
  })
@@ -1,6 +1,8 @@
1
1
  import { describe, it, expect } from 'vitest'
2
+ import { defineComponent, h, nextTick } from 'vue'
2
3
  import { mount } from '@vue/test-utils'
3
4
  import TabGroup from '../TabGroup.vue'
5
+ import Tab from '../Tab.vue'
4
6
 
5
7
  describe('TabGroup', () => {
6
8
  it('renders without errors', () => {
@@ -8,4 +10,115 @@ describe('TabGroup', () => {
8
10
 
9
11
  expect(wrapper.vm).toBeTruthy()
10
12
  })
13
+
14
+ it('supports compact variant with text labels', async () => {
15
+ const wrapper = mount(TabGroup, {
16
+ props: {
17
+ variant: 'compact',
18
+ modelValue: 'unique',
19
+ },
20
+ slots: {
21
+ default: () => [
22
+ h(Tab, { value: 'unique', label: 'Unique' }),
23
+ h(Tab, { value: 'total', label: 'Total' }),
24
+ ],
25
+ },
26
+ global: {
27
+ stubs: {
28
+ XScroll: {
29
+ template: '<div><slot /></div>',
30
+ },
31
+ },
32
+ },
33
+ })
34
+
35
+ await nextTick()
36
+
37
+ expect(wrapper.text()).toContain('Unique')
38
+ expect(wrapper.text()).toContain('Total')
39
+ expect(wrapper.find('[data-value="unique"] [aria-selected="true"]').exists()).toBe(true)
40
+ })
41
+
42
+ it('hides label for icon-only compact tabs', async () => {
43
+ const Host = defineComponent({
44
+ components: { TabGroup, Tab },
45
+ data: () => ({ view: 'grid' }),
46
+ template: `
47
+ <TabGroup v-model="view" variant="compact">
48
+ <Tab value="grid" icon="grid" tooltip="Grid view" />
49
+ <Tab value="list" icon="list" tooltip="List view" />
50
+ </TabGroup>
51
+ `,
52
+ })
53
+
54
+ const wrapper = mount(Host, {
55
+ global: {
56
+ stubs: {
57
+ XScroll: {
58
+ template: '<div><slot /></div>',
59
+ },
60
+ XIcon: true,
61
+ },
62
+ },
63
+ })
64
+
65
+ await nextTick()
66
+
67
+ expect(wrapper.find('[data-value="grid"] [aria-label="Grid view"]').exists()).toBe(true)
68
+ expect(wrapper.find('[data-value="list"] [aria-label="List view"]').exists()).toBe(true)
69
+ expect(wrapper.text()).not.toContain('grid')
70
+ expect(wrapper.text()).not.toContain('list')
71
+ })
72
+
73
+ it('passes size down to Tab icons', async () => {
74
+ const wrapper = mount(TabGroup, {
75
+ props: {
76
+ modelValue: 'a',
77
+ size: 'lg',
78
+ },
79
+ slots: {
80
+ default: () => h(Tab, { value: 'a', label: 'Tab A', icon: 'smile' }),
81
+ },
82
+ global: {
83
+ stubs: {
84
+ XScroll: { template: '<div><slot /></div>' },
85
+ XTooltip: { template: '<div><slot /></div>' },
86
+ XIcon: {
87
+ props: ['icon', 'size'],
88
+ template: '<i class="icon-stub" :data-size="size" />',
89
+ },
90
+ },
91
+ },
92
+ })
93
+
94
+ await nextTick()
95
+
96
+ expect(wrapper.find('.icon-stub').attributes('data-size')).toBe('lg')
97
+ })
98
+
99
+ it('lets Tab size override TabGroup size', async () => {
100
+ const wrapper = mount(TabGroup, {
101
+ props: {
102
+ modelValue: 'a',
103
+ size: 'lg',
104
+ },
105
+ slots: {
106
+ default: () => h(Tab, { value: 'a', label: 'Tab A', icon: 'smile', size: 'sm' }),
107
+ },
108
+ global: {
109
+ stubs: {
110
+ XScroll: { template: '<div><slot /></div>' },
111
+ XTooltip: { template: '<div><slot /></div>' },
112
+ XIcon: {
113
+ props: ['icon', 'size'],
114
+ template: '<i class="icon-stub" :data-size="size" />',
115
+ },
116
+ },
117
+ },
118
+ })
119
+
120
+ await nextTick()
121
+
122
+ expect(wrapper.find('.icon-stub').attributes('data-size')).toBe('sm')
123
+ })
11
124
  })