@sakoa/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/README.md +171 -0
  2. package/dist/App.d.ts +2 -0
  3. package/dist/cli/index.js +9243 -0
  4. package/dist/components/DemoSection.d.ts +30 -0
  5. package/dist/components/SApiKeyboard.d.ts +22 -0
  6. package/dist/components/SApiSection.d.ts +21 -0
  7. package/dist/components/SApiTable.d.ts +46 -0
  8. package/dist/components/STableOfContents.d.ts +2 -0
  9. package/dist/components/ui/SAlert.d.ts +76 -0
  10. package/dist/components/ui/SBadge.d.ts +56 -0
  11. package/dist/components/ui/SButton.d.ts +67 -0
  12. package/dist/components/ui/SCheckbox.d.ts +64 -0
  13. package/dist/components/ui/SChip.d.ts +43 -0
  14. package/dist/components/ui/SDatePicker.d.ts +77 -0
  15. package/dist/components/ui/SGlassButton.d.ts +70 -0
  16. package/dist/components/ui/SIcon.d.ts +29 -0
  17. package/dist/components/ui/SInput.d.ts +129 -0
  18. package/dist/components/ui/SKbd.d.ts +24 -0
  19. package/dist/components/ui/SKbdShortcut.d.ts +14 -0
  20. package/dist/components/ui/SSelect.d.ts +148 -0
  21. package/dist/components/ui/SSkeleton.d.ts +37 -0
  22. package/dist/components/ui/SSwitch.d.ts +61 -0
  23. package/dist/components/ui/STooltip.d.ts +82 -0
  24. package/dist/components/ui/accordion/SAccordionContent.d.ts +23 -0
  25. package/dist/components/ui/accordion/SAccordionItem.d.ts +70 -0
  26. package/dist/components/ui/accordion/SAccordionTrigger.d.ts +37 -0
  27. package/dist/components/ui/accordion/index.d.ts +4 -0
  28. package/dist/components/ui/avatar/SAvatar.d.ts +36 -0
  29. package/dist/components/ui/avatar/SAvatarFallback.d.ts +26 -0
  30. package/dist/components/ui/avatar/SAvatarGroup.d.ts +30 -0
  31. package/dist/components/ui/avatar/SAvatarImage.d.ts +23 -0
  32. package/dist/components/ui/avatar/index.d.ts +4 -0
  33. package/dist/components/ui/breadcrumb/SBreadcrumb.d.ts +22 -0
  34. package/dist/components/ui/breadcrumb/SBreadcrumbEllipsis.d.ts +17 -0
  35. package/dist/components/ui/breadcrumb/SBreadcrumbItem.d.ts +17 -0
  36. package/dist/components/ui/breadcrumb/SBreadcrumbLink.d.ts +26 -0
  37. package/dist/components/ui/breadcrumb/SBreadcrumbList.d.ts +17 -0
  38. package/dist/components/ui/breadcrumb/SBreadcrumbPage.d.ts +17 -0
  39. package/dist/components/ui/breadcrumb/SBreadcrumbSeparator.d.ts +17 -0
  40. package/dist/components/ui/breadcrumb/index.d.ts +7 -0
  41. package/dist/components/ui/card/SCard.d.ts +103 -0
  42. package/dist/components/ui/card/SCardActions.d.ts +44 -0
  43. package/dist/components/ui/card/SCardContent.d.ts +35 -0
  44. package/dist/components/ui/card/SCardFooter.d.ts +38 -0
  45. package/dist/components/ui/card/SCardHeader.d.ts +53 -0
  46. package/dist/components/ui/card/SCardMedia.d.ts +83 -0
  47. package/dist/components/ui/card/SGlassCard.d.ts +103 -0
  48. package/dist/components/ui/card/SMorphingCardContent.d.ts +18 -0
  49. package/dist/components/ui/card/index.d.ts +24 -0
  50. package/dist/components/ui/carousel/SCarousel.d.ts +166 -0
  51. package/dist/components/ui/carousel/index.d.ts +2 -0
  52. package/dist/components/ui/color-picker/SColorPickerAlphaSlider.d.ts +4 -0
  53. package/dist/components/ui/color-picker/SColorPickerCopy.d.ts +19 -0
  54. package/dist/components/ui/color-picker/SColorPickerEyeDropper.d.ts +17 -0
  55. package/dist/components/ui/color-picker/SColorPickerHueSlider.d.ts +4 -0
  56. package/dist/components/ui/color-picker/SColorPickerInputs.d.ts +2 -0
  57. package/dist/components/ui/color-picker/SColorPickerPresets.d.ts +9 -0
  58. package/dist/components/ui/color-picker/SColorPickerPreview.d.ts +2 -0
  59. package/dist/components/ui/color-picker/SColorPickerRecent.d.ts +7 -0
  60. package/dist/components/ui/color-picker/SColorPickerSpectrum.d.ts +4 -0
  61. package/dist/components/ui/color-picker/index.d.ts +11 -0
  62. package/dist/components/ui/drawer/index.d.ts +11 -0
  63. package/dist/components/ui/dropdown/SDropdownDivider.d.ts +8 -0
  64. package/dist/components/ui/dropdown/SDropdownGroup.d.ts +25 -0
  65. package/dist/components/ui/dropdown/SDropdownItem.d.ts +56 -0
  66. package/dist/components/ui/dropdown/index.d.ts +4 -0
  67. package/dist/components/ui/form/SForm.d.ts +38 -0
  68. package/dist/components/ui/form/SFormField.d.ts +31 -0
  69. package/dist/components/ui/form/index.d.ts +5 -0
  70. package/dist/components/ui/modal/index.d.ts +19 -0
  71. package/dist/components/ui/option/SOption.d.ts +32 -0
  72. package/dist/components/ui/option/SOptionGroup.d.ts +28 -0
  73. package/dist/components/ui/option/index.d.ts +2 -0
  74. package/dist/components/ui/otp/SOTP.d.ts +122 -0
  75. package/dist/components/ui/otp/SOTPGroup.d.ts +23 -0
  76. package/dist/components/ui/otp/SOTPSeparator.d.ts +17 -0
  77. package/dist/components/ui/otp/SOTPSlot.d.ts +49 -0
  78. package/dist/components/ui/otp/index.d.ts +7 -0
  79. package/dist/components/ui/otp/types.d.ts +26 -0
  80. package/dist/components/ui/otp/useOTPContext.d.ts +42 -0
  81. package/dist/components/ui/pagination/SPagination.d.ts +151 -0
  82. package/dist/components/ui/pagination/index.d.ts +2 -0
  83. package/dist/components/ui/progress/SProgress.d.ts +62 -0
  84. package/dist/components/ui/progress/SProgressRange.d.ts +91 -0
  85. package/dist/components/ui/progress/index.d.ts +4 -0
  86. package/dist/components/ui/radio/SRadio.d.ts +58 -0
  87. package/dist/components/ui/radio/SRadioGroup.d.ts +52 -0
  88. package/dist/components/ui/radio/index.d.ts +2 -0
  89. package/dist/components/ui/stepper/SStepper.d.ts +83 -0
  90. package/dist/components/ui/stepper/SStepperContent.d.ts +24 -0
  91. package/dist/components/ui/stepper/SStepperDescription.d.ts +20 -0
  92. package/dist/components/ui/stepper/SStepperIndicator.d.ts +37 -0
  93. package/dist/components/ui/stepper/SStepperItem.d.ts +37 -0
  94. package/dist/components/ui/stepper/SStepperSeparator.d.ts +5 -0
  95. package/dist/components/ui/stepper/SStepperTitle.d.ts +20 -0
  96. package/dist/components/ui/stepper/SStepperTrigger.d.ts +22 -0
  97. package/dist/components/ui/stepper/index.d.ts +11 -0
  98. package/dist/components/ui/table/STableBody.d.ts +27 -0
  99. package/dist/components/ui/table/STableCell.d.ts +55 -0
  100. package/dist/components/ui/table/STableColumn.d.ts +87 -0
  101. package/dist/components/ui/table/STableEmpty.d.ts +54 -0
  102. package/dist/components/ui/table/STableHeader.d.ts +25 -0
  103. package/dist/components/ui/table/STableRow.d.ts +38 -0
  104. package/dist/components/ui/table/STableSkeleton.d.ts +29 -0
  105. package/dist/components/ui/table/index.d.ts +98 -0
  106. package/dist/components/ui/table/useDataTable.d.ts +80 -0
  107. package/dist/components/ui/tabs/STabPane.d.ts +31 -0
  108. package/dist/components/ui/tabs/STabsContent.d.ts +21 -0
  109. package/dist/components/ui/tabs/STabsIndicator.d.ts +9 -0
  110. package/dist/components/ui/tabs/STabsTrigger.d.ts +28 -0
  111. package/dist/components/ui/tabs/index.d.ts +6 -0
  112. package/dist/components/ui/toast/SToast.d.ts +49 -0
  113. package/dist/components/ui/toast/SToastContainer.d.ts +21 -0
  114. package/dist/components/ui/toast/index.d.ts +2 -0
  115. package/dist/composables/useAsync.d.ts +134 -0
  116. package/dist/composables/useClickOutside.d.ts +69 -0
  117. package/dist/composables/useClipboard.d.ts +46 -0
  118. package/dist/composables/useDebounce.d.ts +150 -0
  119. package/dist/composables/useDialog.d.ts +118 -0
  120. package/dist/composables/useForm.d.ts +204 -0
  121. package/dist/composables/useHotkey.d.ts +128 -0
  122. package/dist/composables/useIntersectionObserver.d.ts +156 -0
  123. package/dist/composables/useLocalStorage.d.ts +120 -0
  124. package/dist/composables/useMediaQuery.d.ts +115 -0
  125. package/dist/composables/useTheme.d.ts +8 -0
  126. package/dist/composables/useToast.d.ts +1619 -0
  127. package/dist/index.d.ts +71 -0
  128. package/dist/layouts/UILayout.d.ts +2 -0
  129. package/dist/lib/utils.d.ts +2 -0
  130. package/dist/main.d.ts +0 -0
  131. package/dist/router.d.ts +2 -0
  132. package/dist/saka-ui.css +1 -0
  133. package/dist/saka-ui.js +18513 -0
  134. package/dist/saka-ui.umd.cjs +38 -0
  135. package/dist/views/docs/CustomizationView.d.ts +2 -0
  136. package/dist/views/docs/FormValidationView.d.ts +2 -0
  137. package/dist/views/docs/StylingGuideView.d.ts +2 -0
  138. package/dist/views/docs/UseAsyncView.d.ts +2 -0
  139. package/dist/views/docs/UseClickOutsideView.d.ts +124 -0
  140. package/dist/views/docs/UseClipboardView.d.ts +4 -0
  141. package/dist/views/docs/UseDebounceView.d.ts +2 -0
  142. package/dist/views/docs/UseHotkeyView.d.ts +205 -0
  143. package/dist/views/docs/UseIntersectionObserverView.d.ts +5 -0
  144. package/dist/views/docs/UseLocalStorageView.d.ts +2 -0
  145. package/dist/views/docs/UseMediaQueryView.d.ts +2 -0
  146. package/dist/views/docs/UseThemeView.d.ts +2 -0
  147. package/dist/views/examples/AuthFormView.d.ts +2 -0
  148. package/dist/views/examples/CreditCardFormView.d.ts +6 -0
  149. package/dist/views/examples/FormFieldExampleView.d.ts +2 -0
  150. package/dist/views/examples/ProjectFormView.d.ts +2 -0
  151. package/dist/views/ui/AccordionView.d.ts +2 -0
  152. package/dist/views/ui/AlertView.d.ts +2 -0
  153. package/dist/views/ui/AvatarView.d.ts +2 -0
  154. package/dist/views/ui/BadgeView.d.ts +2 -0
  155. package/dist/views/ui/BreadcrumbView.d.ts +2 -0
  156. package/dist/views/ui/ButtonView.d.ts +2 -0
  157. package/dist/views/ui/CardView.d.ts +2 -0
  158. package/dist/views/ui/CarouselView.d.ts +274 -0
  159. package/dist/views/ui/CheckboxView.d.ts +2 -0
  160. package/dist/views/ui/ChipView.d.ts +2 -0
  161. package/dist/views/ui/ColorPickerView.d.ts +2 -0
  162. package/dist/views/ui/DatePickerView.d.ts +2 -0
  163. package/dist/views/ui/DialogView.d.ts +2 -0
  164. package/dist/views/ui/DrawerView.d.ts +2 -0
  165. package/dist/views/ui/DropdownView.d.ts +2 -0
  166. package/dist/views/ui/GlassButtonView.d.ts +2 -0
  167. package/dist/views/ui/GlassCardView.d.ts +2 -0
  168. package/dist/views/ui/HomeView.d.ts +2 -0
  169. package/dist/views/ui/IconsView.d.ts +2 -0
  170. package/dist/views/ui/InputView.d.ts +2 -0
  171. package/dist/views/ui/KbdView.d.ts +2 -0
  172. package/dist/views/ui/ModalView.d.ts +2 -0
  173. package/dist/views/ui/MorphingCardView.d.ts +2 -0
  174. package/dist/views/ui/MorphingModalView.d.ts +2 -0
  175. package/dist/views/ui/OTPView.d.ts +206 -0
  176. package/dist/views/ui/PaginationView.d.ts +2 -0
  177. package/dist/views/ui/ProgressView.d.ts +2 -0
  178. package/dist/views/ui/RadioView.d.ts +2 -0
  179. package/dist/views/ui/SelectView.d.ts +2 -0
  180. package/dist/views/ui/SkeletonView.d.ts +2 -0
  181. package/dist/views/ui/StepperView.d.ts +2 -0
  182. package/dist/views/ui/SwitchView.d.ts +2 -0
  183. package/dist/views/ui/TableView.d.ts +2 -0
  184. package/dist/views/ui/TabsView.d.ts +2 -0
  185. package/dist/views/ui/ToastView.d.ts +2 -0
  186. package/dist/views/ui/TooltipView.d.ts +2 -0
  187. package/dist/vite.svg +1 -0
  188. package/package.json +64 -0
  189. package/registry/components/accordion.json +19 -0
  190. package/registry/components/alert.json +17 -0
  191. package/registry/components/avatar.json +18 -0
  192. package/registry/components/badge.json +14 -0
  193. package/registry/components/breadcrumb.json +24 -0
  194. package/registry/components/button.json +17 -0
  195. package/registry/components/card.json +23 -0
  196. package/registry/components/carousel.json +19 -0
  197. package/registry/components/checkbox.json +17 -0
  198. package/registry/components/chip.json +17 -0
  199. package/registry/components/color-picker.json +24 -0
  200. package/registry/components/date-picker.json +17 -0
  201. package/registry/components/drawer.json +26 -0
  202. package/registry/components/dropdown.json +21 -0
  203. package/registry/components/form.json +16 -0
  204. package/registry/components/glass-button.json +17 -0
  205. package/registry/components/icon.json +17 -0
  206. package/registry/components/input.json +17 -0
  207. package/registry/components/kbd.json +16 -0
  208. package/registry/components/modal.json +32 -0
  209. package/registry/components/option.json +16 -0
  210. package/registry/components/otp.json +23 -0
  211. package/registry/components/pagination.json +18 -0
  212. package/registry/components/progress.json +16 -0
  213. package/registry/components/radio.json +19 -0
  214. package/registry/components/select.json +17 -0
  215. package/registry/components/skeleton.json +14 -0
  216. package/registry/components/switch.json +17 -0
  217. package/registry/components/table.json +26 -0
  218. package/registry/components/tabs.json +19 -0
  219. package/registry/components/toast.json +19 -0
  220. package/registry/components/tooltip.json +14 -0
  221. package/registry/index.json +4 -0
  222. package/registry/source/components/ui/SAlert.vue +388 -0
  223. package/registry/source/components/ui/SBadge.vue +243 -0
  224. package/registry/source/components/ui/SButton.vue +387 -0
  225. package/registry/source/components/ui/SCheckbox.vue +310 -0
  226. package/registry/source/components/ui/SChip.vue +130 -0
  227. package/registry/source/components/ui/SDatePicker.vue +1290 -0
  228. package/registry/source/components/ui/SGlassButton.vue +547 -0
  229. package/registry/source/components/ui/SIcon.vue +78 -0
  230. package/registry/source/components/ui/SInput.vue +1054 -0
  231. package/registry/source/components/ui/SKbd.vue +96 -0
  232. package/registry/source/components/ui/SKbdShortcut.vue +36 -0
  233. package/registry/source/components/ui/SSelect.vue +1290 -0
  234. package/registry/source/components/ui/SSkeleton.vue +185 -0
  235. package/registry/source/components/ui/SSwitch.vue +275 -0
  236. package/registry/source/components/ui/STooltip.vue +491 -0
  237. package/registry/source/components/ui/accordion/SAccordion.vue +248 -0
  238. package/registry/source/components/ui/accordion/SAccordionItem.vue +353 -0
  239. package/registry/source/components/ui/accordion/index.ts +5 -0
  240. package/registry/source/components/ui/avatar/SAvatar.vue +169 -0
  241. package/registry/source/components/ui/avatar/SAvatarFallback.vue +66 -0
  242. package/registry/source/components/ui/avatar/SAvatarGroup.vue +69 -0
  243. package/registry/source/components/ui/avatar/SAvatarImage.vue +92 -0
  244. package/registry/source/components/ui/avatar/index.ts +5 -0
  245. package/registry/source/components/ui/breadcrumb/SBreadcrumb.vue +23 -0
  246. package/registry/source/components/ui/breadcrumb/SBreadcrumbEllipsis.vue +17 -0
  247. package/registry/source/components/ui/breadcrumb/SBreadcrumbItem.vue +14 -0
  248. package/registry/source/components/ui/breadcrumb/SBreadcrumbLink.vue +46 -0
  249. package/registry/source/components/ui/breadcrumb/SBreadcrumbList.vue +17 -0
  250. package/registry/source/components/ui/breadcrumb/SBreadcrumbPage.vue +15 -0
  251. package/registry/source/components/ui/breadcrumb/SBreadcrumbSeparator.vue +18 -0
  252. package/registry/source/components/ui/breadcrumb/index.ts +7 -0
  253. package/registry/source/components/ui/card/SCard.vue +517 -0
  254. package/registry/source/components/ui/card/SCardActions.vue +129 -0
  255. package/registry/source/components/ui/card/SCardContent.vue +117 -0
  256. package/registry/source/components/ui/card/SCardFooter.vue +103 -0
  257. package/registry/source/components/ui/card/SCardHeader.vue +163 -0
  258. package/registry/source/components/ui/card/SCardMedia.vue +312 -0
  259. package/registry/source/components/ui/card/index.ts +34 -0
  260. package/registry/source/components/ui/carousel/SCarousel.vue +1069 -0
  261. package/registry/source/components/ui/carousel/SCarouselSlide.vue +107 -0
  262. package/registry/source/components/ui/carousel/index.ts +3 -0
  263. package/registry/source/components/ui/color-picker/SColorPicker.vue +772 -0
  264. package/registry/source/components/ui/color-picker/SColorPickerAlphaSlider.vue +158 -0
  265. package/registry/source/components/ui/color-picker/SColorPickerCopy.vue +76 -0
  266. package/registry/source/components/ui/color-picker/SColorPickerEyeDropper.vue +68 -0
  267. package/registry/source/components/ui/color-picker/SColorPickerHueSlider.vue +138 -0
  268. package/registry/source/components/ui/color-picker/SColorPickerInputs.vue +227 -0
  269. package/registry/source/components/ui/color-picker/SColorPickerPresets.vue +87 -0
  270. package/registry/source/components/ui/color-picker/SColorPickerPreview.vue +46 -0
  271. package/registry/source/components/ui/color-picker/SColorPickerRecent.vue +74 -0
  272. package/registry/source/components/ui/color-picker/SColorPickerSpectrum.vue +149 -0
  273. package/registry/source/components/ui/color-picker/index.ts +11 -0
  274. package/registry/source/components/ui/drawer/SDrawer.vue +797 -0
  275. package/registry/source/components/ui/drawer/SDrawerClose.vue +64 -0
  276. package/registry/source/components/ui/drawer/SDrawerContent.vue +81 -0
  277. package/registry/source/components/ui/drawer/SDrawerDescription.vue +40 -0
  278. package/registry/source/components/ui/drawer/SDrawerFooter.vue +97 -0
  279. package/registry/source/components/ui/drawer/SDrawerHandle.vue +79 -0
  280. package/registry/source/components/ui/drawer/SDrawerHeader.vue +117 -0
  281. package/registry/source/components/ui/drawer/SDrawerTitle.vue +40 -0
  282. package/registry/source/components/ui/drawer/SDrawerTrigger.vue +51 -0
  283. package/registry/source/components/ui/drawer/index.ts +20 -0
  284. package/registry/source/components/ui/dropdown/SDropdown.vue +843 -0
  285. package/registry/source/components/ui/dropdown/SDropdownDivider.vue +23 -0
  286. package/registry/source/components/ui/dropdown/SDropdownGroup.vue +53 -0
  287. package/registry/source/components/ui/dropdown/SDropdownItem.vue +179 -0
  288. package/registry/source/components/ui/dropdown/index.ts +5 -0
  289. package/registry/source/components/ui/form/SForm.vue +84 -0
  290. package/registry/source/components/ui/form/SFormField.vue +78 -0
  291. package/registry/source/components/ui/form/index.ts +8 -0
  292. package/registry/source/components/ui/modal/SModal.vue +648 -0
  293. package/registry/source/components/ui/modal/SModalClose.vue +49 -0
  294. package/registry/source/components/ui/modal/SModalContent.vue +74 -0
  295. package/registry/source/components/ui/modal/SModalDescription.vue +39 -0
  296. package/registry/source/components/ui/modal/SModalFooter.vue +84 -0
  297. package/registry/source/components/ui/modal/SModalHeader.vue +107 -0
  298. package/registry/source/components/ui/modal/SModalTitle.vue +39 -0
  299. package/registry/source/components/ui/modal/SModalTrigger.vue +61 -0
  300. package/registry/source/components/ui/modal/SMorphingModal.vue +429 -0
  301. package/registry/source/components/ui/modal/SMorphingModalClose.vue +42 -0
  302. package/registry/source/components/ui/modal/SMorphingModalDescription.vue +49 -0
  303. package/registry/source/components/ui/modal/SMorphingModalImage.vue +44 -0
  304. package/registry/source/components/ui/modal/SMorphingModalSubtitle.vue +29 -0
  305. package/registry/source/components/ui/modal/SMorphingModalTitle.vue +34 -0
  306. package/registry/source/components/ui/modal/SMorphingModalTrigger.vue +95 -0
  307. package/registry/source/components/ui/modal/index.ts +32 -0
  308. package/registry/source/components/ui/option/SOption.vue +180 -0
  309. package/registry/source/components/ui/option/SOptionGroup.vue +77 -0
  310. package/registry/source/components/ui/option/index.ts +3 -0
  311. package/registry/source/components/ui/otp/SOTP.vue +843 -0
  312. package/registry/source/components/ui/otp/SOTPGroup.vue +29 -0
  313. package/registry/source/components/ui/otp/SOTPSeparator.vue +15 -0
  314. package/registry/source/components/ui/otp/SOTPSlot.vue +462 -0
  315. package/registry/source/components/ui/otp/index.ts +7 -0
  316. package/registry/source/components/ui/otp/types.ts +27 -0
  317. package/registry/source/components/ui/otp/useOTPContext.ts +62 -0
  318. package/registry/source/components/ui/pagination/SPagination.vue +923 -0
  319. package/registry/source/components/ui/pagination/index.ts +8 -0
  320. package/registry/source/components/ui/progress/SProgress.vue +635 -0
  321. package/registry/source/components/ui/progress/SProgressRange.vue +715 -0
  322. package/registry/source/components/ui/progress/index.ts +4 -0
  323. package/registry/source/components/ui/radio/SRadio.vue +407 -0
  324. package/registry/source/components/ui/radio/SRadioGroup.vue +200 -0
  325. package/registry/source/components/ui/radio/index.ts +3 -0
  326. package/registry/source/components/ui/table/SDataTable.vue +828 -0
  327. package/registry/source/components/ui/table/STableBody.vue +70 -0
  328. package/registry/source/components/ui/table/STableCell.vue +147 -0
  329. package/registry/source/components/ui/table/STableColumn.vue +120 -0
  330. package/registry/source/components/ui/table/STableEmpty.vue +159 -0
  331. package/registry/source/components/ui/table/STableHeader.vue +132 -0
  332. package/registry/source/components/ui/table/STableRow.vue +106 -0
  333. package/registry/source/components/ui/table/STableSkeleton.vue +208 -0
  334. package/registry/source/components/ui/table/index.ts +126 -0
  335. package/registry/source/components/ui/table/useDataTable.ts +519 -0
  336. package/registry/source/components/ui/tabs/STabPane.vue +130 -0
  337. package/registry/source/components/ui/tabs/STabs.vue +467 -0
  338. package/registry/source/components/ui/tabs/index.ts +7 -0
  339. package/registry/source/components/ui/toast/SToast.vue +261 -0
  340. package/registry/source/components/ui/toast/SToastContainer.vue +209 -0
  341. package/registry/source/components/ui/toast/index.ts +2 -0
  342. package/registry/source/composables/useForm.ts +960 -0
  343. package/registry/source/composables/useTheme.ts +86 -0
  344. package/registry/source/composables/useToast.ts +440 -0
  345. package/registry/source/lib/utils.ts +6 -0
@@ -0,0 +1,1069 @@
1
+ <script setup lang="ts">
2
+ import { provide, ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
3
+ import { cn } from '../../../lib/utils'
4
+ import { SCarouselContextKey, type SCarouselContext } from './SCarouselSlide.vue'
5
+
6
+ defineOptions({ inheritAttrs: false })
7
+
8
+ export type CarouselEffect =
9
+ | 'slide' | 'fade' | 'cube' | 'flip' | 'coverflow' | 'cards'
10
+ | 'zoom' | 'creative' | 'parallax' | 'stack' | 'swirl' | 'kenburns'
11
+ export type CarouselDirection = 'horizontal' | 'vertical'
12
+ export type DotsPosition = 'bottom' | 'top' | 'left' | 'right'
13
+ export type DotsStyle = 'dots' | 'bars' | 'numbers' | 'fraction'
14
+ export type ArrowStyle = 'default' | 'minimal' | 'rounded' | 'square'
15
+ export type ArrowPlacement =
16
+ | 'sides' // Classic left/right or top/bottom on sides (default)
17
+ | 'bottom-right' // Both arrows grouped in bottom-right corner
18
+ | 'bottom-left' // Both arrows grouped in bottom-left corner
19
+ | 'top-right' // Both arrows grouped in top-right corner
20
+ | 'top-left' // Both arrows grouped in top-left corner
21
+ | 'bottom-center' // Both arrows grouped at bottom center
22
+ | 'top-center' // Both arrows grouped at top center
23
+
24
+ export interface Props {
25
+ modelValue?: number
26
+ effect?: CarouselEffect
27
+ direction?: CarouselDirection
28
+ loop?: boolean
29
+ rewind?: boolean
30
+ autoplay?: boolean
31
+ autoplayDelay?: number
32
+ pauseOnHover?: boolean
33
+ pauseOnInteraction?: boolean
34
+ speed?: number
35
+ easing?: 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' | 'spring' | 'bounce'
36
+ showArrows?: boolean
37
+ showDots?: boolean
38
+ showProgress?: boolean
39
+ showThumbnails?: boolean
40
+ showCounter?: boolean
41
+ arrowsInside?: boolean
42
+ arrowStyle?: ArrowStyle
43
+ arrowPlacement?: ArrowPlacement
44
+ dotsPosition?: DotsPosition
45
+ dotsStyle?: DotsStyle
46
+ gap?: number
47
+ slidesPerView?: number
48
+ slidesPerGroup?: number
49
+ centeredSlides?: boolean
50
+ height?: string
51
+ aspectRatio?: string
52
+ borderRadius?: string
53
+ arrowSize?: 'small' | 'medium' | 'large'
54
+ mousewheel?: boolean
55
+ grabCursor?: boolean
56
+ watchSlidesProgress?: boolean
57
+ virtualSlides?: boolean
58
+ freeMode?: boolean
59
+ freeModeSticky?: boolean
60
+ resistance?: boolean
61
+ resistanceRatio?: number
62
+ touchSensitivity?: number
63
+ preventClicks?: boolean
64
+ slideVisibleClass?: string
65
+ slideActiveClass?: string
66
+ containerClass?: string
67
+ a11y?: boolean
68
+ ariaLabel?: string
69
+ }
70
+
71
+ const props = withDefaults(defineProps<Props>(), {
72
+ modelValue: 0,
73
+ effect: 'slide',
74
+ direction: 'horizontal',
75
+ loop: false,
76
+ rewind: false,
77
+ autoplay: false,
78
+ autoplayDelay: 3000,
79
+ pauseOnHover: true,
80
+ pauseOnInteraction: true,
81
+ speed: 500,
82
+ easing: 'ease-out',
83
+ showArrows: true,
84
+ showDots: true,
85
+ showProgress: false,
86
+ showThumbnails: false,
87
+ showCounter: false,
88
+ arrowsInside: true,
89
+ arrowStyle: 'default',
90
+ arrowPlacement: 'sides',
91
+ dotsPosition: 'bottom',
92
+ dotsStyle: 'dots',
93
+ gap: 0,
94
+ slidesPerView: 1,
95
+ slidesPerGroup: 1,
96
+ centeredSlides: false,
97
+ height: '400px',
98
+ aspectRatio: '',
99
+ borderRadius: '16px',
100
+ arrowSize: 'medium',
101
+ mousewheel: false,
102
+ grabCursor: true,
103
+ watchSlidesProgress: false,
104
+ virtualSlides: false,
105
+ freeMode: false,
106
+ freeModeSticky: false,
107
+ resistance: true,
108
+ resistanceRatio: 0.85,
109
+ touchSensitivity: 1,
110
+ preventClicks: true,
111
+ slideVisibleClass: '',
112
+ slideActiveClass: '',
113
+ containerClass: '',
114
+ a11y: true,
115
+ ariaLabel: 'Image carousel'
116
+ })
117
+
118
+ const emit = defineEmits<{
119
+ 'update:modelValue': [index: number]
120
+ 'change': [index: number]
121
+ 'slideStart': [index: number]
122
+ 'slideEnd': [index: number]
123
+ 'autoplayStart': []
124
+ 'autoplayStop': []
125
+ 'autoplayPause': []
126
+ 'autoplayResume': []
127
+ 'reachStart': []
128
+ 'reachEnd': []
129
+ 'touchStart': [event: TouchEvent | MouseEvent]
130
+ 'touchMove': [event: TouchEvent | MouseEvent]
131
+ 'touchEnd': []
132
+ 'click': [index: number]
133
+ 'doubleClick': [index: number]
134
+ }>()
135
+
136
+ // Refs
137
+ const containerRef = ref<HTMLElement | null>(null)
138
+ const activeIndex = ref(props.modelValue)
139
+ const slideElements = ref<Map<number, HTMLElement>>(new Map())
140
+ const slideProgress = ref<Map<number, number>>(new Map())
141
+ const isTransitioning = ref(false)
142
+ const isHovering = ref(false)
143
+ const isPaused = ref(false)
144
+ const autoplayTimer = ref<number | null>(null)
145
+ const progressPercent = ref(0)
146
+ const progressTimer = ref<number | null>(null)
147
+ const velocity = ref(0)
148
+ const lastMoveTime = ref(0)
149
+
150
+ // Touch/drag handling
151
+ const isDragging = ref(false)
152
+ const dragStart = ref({ x: 0, y: 0 })
153
+ const dragOffset = ref(0)
154
+ const dragThreshold = 50
155
+
156
+ // Computed
157
+ const totalSlides = computed(() => slideElements.value.size)
158
+ const canGoPrev = computed(() => {
159
+ if (props.loop) return true
160
+ if (props.rewind && activeIndex.value === 0) return true
161
+ return activeIndex.value > 0
162
+ })
163
+ const canGoNext = computed(() => {
164
+ if (props.loop) return true
165
+ if (props.rewind && activeIndex.value >= totalSlides.value - props.slidesPerView) return true
166
+ return activeIndex.value < totalSlides.value - props.slidesPerView
167
+ })
168
+
169
+ const easingFunction = computed(() => {
170
+ const easings: Record<string, string> = {
171
+ 'ease': 'cubic-bezier(0.25, 0.1, 0.25, 1)',
172
+ 'ease-in': 'cubic-bezier(0.42, 0, 1, 1)',
173
+ 'ease-out': 'cubic-bezier(0, 0, 0.58, 1)',
174
+ 'ease-in-out': 'cubic-bezier(0.42, 0, 0.58, 1)',
175
+ 'linear': 'linear',
176
+ 'spring': 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
177
+ 'bounce': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
178
+ }
179
+ return easings[props.easing]
180
+ })
181
+
182
+ const arrowSizeClasses = computed(() => {
183
+ const sizes = {
184
+ small: 'w-8 h-8 text-lg',
185
+ medium: 'w-10 h-10 text-xl',
186
+ large: 'w-12 h-12 text-2xl'
187
+ }
188
+ return sizes[props.arrowSize]
189
+ })
190
+
191
+ const arrowStyleClasses = computed(() => {
192
+ const styles: Record<string, string> = {
193
+ 'default': 'rounded-full',
194
+ 'minimal': 'bg-transparent! shadow-none! hover:bg-background/50!',
195
+ 'rounded': 'rounded-2xl',
196
+ 'square': 'rounded-lg'
197
+ }
198
+ return styles[props.arrowStyle]
199
+ })
200
+
201
+ // Effect-specific styles
202
+ const trackStyle = computed(() => {
203
+ const baseStyle: Record<string, string> = {
204
+ '--carousel-speed': `${props.speed}ms`,
205
+ '--carousel-gap': `${props.gap}px`,
206
+ '--carousel-easing': easingFunction.value
207
+ }
208
+
209
+ if (props.effect === 'slide' || props.effect === 'parallax') {
210
+ const offset = props.direction === 'horizontal'
211
+ ? `translateX(calc(-${activeIndex.value * 100}% - ${activeIndex.value * props.gap}px + ${isDragging.value ? dragOffset.value : 0}px))`
212
+ : `translateY(calc(-${activeIndex.value * 100}% - ${activeIndex.value * props.gap}px + ${isDragging.value ? dragOffset.value : 0}px))`
213
+ baseStyle.transform = offset
214
+ }
215
+
216
+ return baseStyle
217
+ })
218
+
219
+ const containerStyle = computed(() => {
220
+ const style: Record<string, string> = {
221
+ borderRadius: props.borderRadius
222
+ }
223
+
224
+ if (props.aspectRatio) {
225
+ style.aspectRatio = props.aspectRatio
226
+ } else {
227
+ style.height = props.height
228
+ }
229
+
230
+ return style
231
+ })
232
+
233
+ // Methods
234
+ const registerSlide = (el: HTMLElement | null, index: number) => {
235
+ if (el) {
236
+ slideElements.value.set(index, el)
237
+ }
238
+ }
239
+
240
+ const unregisterSlide = (index: number) => {
241
+ slideElements.value.delete(index)
242
+ slideProgress.value.delete(index)
243
+ }
244
+
245
+ const updateSlideProgress = () => {
246
+ if (!props.watchSlidesProgress) return
247
+
248
+ slideElements.value.forEach((el, index) => {
249
+ const progress = Math.abs(index - activeIndex.value)
250
+ slideProgress.value.set(index, progress)
251
+ })
252
+ }
253
+
254
+ const goTo = (index: number, skipTransition = false) => {
255
+ if (isTransitioning.value && !skipTransition) return
256
+
257
+ let targetIndex = index
258
+
259
+ if (props.loop) {
260
+ if (index < 0) targetIndex = totalSlides.value - 1
261
+ else if (index >= totalSlides.value) targetIndex = 0
262
+ } else if (props.rewind) {
263
+ if (index < 0) targetIndex = totalSlides.value - 1
264
+ else if (index >= totalSlides.value) targetIndex = 0
265
+ } else {
266
+ targetIndex = Math.max(0, Math.min(index, totalSlides.value - props.slidesPerView))
267
+ }
268
+
269
+ if (targetIndex === activeIndex.value && !skipTransition) return
270
+
271
+ // Check for edge events
272
+ if (targetIndex === 0) emit('reachStart')
273
+ if (targetIndex === totalSlides.value - 1) emit('reachEnd')
274
+
275
+ isTransitioning.value = true
276
+ emit('slideStart', targetIndex)
277
+
278
+ activeIndex.value = targetIndex
279
+ emit('update:modelValue', targetIndex)
280
+ emit('change', targetIndex)
281
+
282
+ updateSlideProgress()
283
+
284
+ setTimeout(() => {
285
+ isTransitioning.value = false
286
+ emit('slideEnd', targetIndex)
287
+ }, props.speed)
288
+ }
289
+
290
+ const next = () => goTo(activeIndex.value + props.slidesPerGroup)
291
+ const prev = () => goTo(activeIndex.value - props.slidesPerGroup)
292
+
293
+ // Autoplay
294
+ const startAutoplay = () => {
295
+ if (!props.autoplay || autoplayTimer.value || isPaused.value) return
296
+
297
+ emit('autoplayStart')
298
+ progressPercent.value = 0
299
+
300
+ // Progress animation
301
+ if (props.showProgress) {
302
+ const startTime = Date.now()
303
+ const animate = () => {
304
+ const elapsed = Date.now() - startTime
305
+ progressPercent.value = Math.min((elapsed / props.autoplayDelay) * 100, 100)
306
+ if (progressPercent.value < 100) {
307
+ progressTimer.value = requestAnimationFrame(animate)
308
+ }
309
+ }
310
+ progressTimer.value = requestAnimationFrame(animate)
311
+ }
312
+
313
+ autoplayTimer.value = window.setTimeout(() => {
314
+ next()
315
+ autoplayTimer.value = null
316
+ progressPercent.value = 0
317
+ startAutoplay()
318
+ }, props.autoplayDelay)
319
+ }
320
+
321
+ const stopAutoplay = () => {
322
+ if (autoplayTimer.value) {
323
+ clearTimeout(autoplayTimer.value)
324
+ autoplayTimer.value = null
325
+ }
326
+ if (progressTimer.value) {
327
+ cancelAnimationFrame(progressTimer.value)
328
+ progressTimer.value = null
329
+ }
330
+ progressPercent.value = 0
331
+ emit('autoplayStop')
332
+ }
333
+
334
+ const pauseAutoplay = () => {
335
+ isPaused.value = true
336
+ stopAutoplay()
337
+ emit('autoplayPause')
338
+ }
339
+
340
+ const resumeAutoplay = () => {
341
+ isPaused.value = false
342
+ startAutoplay()
343
+ emit('autoplayResume')
344
+ }
345
+
346
+ const start = () => startAutoplay()
347
+ const stop = () => stopAutoplay()
348
+ const pause = () => pauseAutoplay()
349
+ const resume = () => resumeAutoplay()
350
+
351
+ // Mouse/Touch handlers
352
+ const handleMouseEnter = () => {
353
+ isHovering.value = true
354
+ if (props.pauseOnHover && props.autoplay) {
355
+ stopAutoplay()
356
+ }
357
+ }
358
+
359
+ const handleMouseLeave = () => {
360
+ isHovering.value = false
361
+ if (props.pauseOnHover && props.autoplay && !isPaused.value) {
362
+ startAutoplay()
363
+ }
364
+ }
365
+
366
+ const handleDragStart = (e: MouseEvent | TouchEvent) => {
367
+ if (isTransitioning.value) return
368
+
369
+ emit('touchStart', e)
370
+ isDragging.value = true
371
+ const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX
372
+ const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY
373
+ dragStart.value = { x: clientX, y: clientY }
374
+ dragOffset.value = 0
375
+ lastMoveTime.value = Date.now()
376
+ velocity.value = 0
377
+
378
+ if (props.pauseOnInteraction && props.autoplay) stopAutoplay()
379
+ }
380
+
381
+ const handleDragMove = (e: MouseEvent | TouchEvent) => {
382
+ if (!isDragging.value) return
383
+
384
+ emit('touchMove', e)
385
+ const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX
386
+ const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY
387
+
388
+ const newOffset = props.direction === 'horizontal'
389
+ ? (clientX - dragStart.value.x) * props.touchSensitivity
390
+ : (clientY - dragStart.value.y) * props.touchSensitivity
391
+
392
+ // Calculate velocity for momentum
393
+ const now = Date.now()
394
+ const dt = now - lastMoveTime.value
395
+ if (dt > 0) {
396
+ velocity.value = (newOffset - dragOffset.value) / dt
397
+ }
398
+ lastMoveTime.value = now
399
+
400
+ // Apply resistance at edges
401
+ if (props.resistance && !props.loop) {
402
+ const isAtStart = activeIndex.value === 0 && newOffset > 0
403
+ const isAtEnd = activeIndex.value >= totalSlides.value - 1 && newOffset < 0
404
+ if (isAtStart || isAtEnd) {
405
+ dragOffset.value = newOffset * props.resistanceRatio
406
+ return
407
+ }
408
+ }
409
+
410
+ dragOffset.value = newOffset
411
+ }
412
+
413
+ const handleDragEnd = () => {
414
+ if (!isDragging.value) return
415
+
416
+ emit('touchEnd')
417
+ isDragging.value = false
418
+
419
+ // Use velocity for momentum-based navigation in free mode
420
+ const threshold = props.freeMode ? dragThreshold / 2 : dragThreshold
421
+ const velocityThreshold = 0.3
422
+
423
+ const shouldNavigate = Math.abs(dragOffset.value) > threshold ||
424
+ (props.freeMode && Math.abs(velocity.value) > velocityThreshold)
425
+
426
+ if (shouldNavigate) {
427
+ if (dragOffset.value > 0 || (props.freeMode && velocity.value > velocityThreshold)) {
428
+ prev()
429
+ } else {
430
+ next()
431
+ }
432
+ }
433
+
434
+ dragOffset.value = 0
435
+ velocity.value = 0
436
+
437
+ if (props.autoplay && !isHovering.value && !isPaused.value) {
438
+ startAutoplay()
439
+ }
440
+ }
441
+
442
+ // Mousewheel navigation
443
+ const handleWheel = (e: WheelEvent) => {
444
+ if (!props.mousewheel) return
445
+
446
+ e.preventDefault()
447
+
448
+ if (isTransitioning.value) return
449
+
450
+ const delta = props.direction === 'horizontal' ? e.deltaX || e.deltaY : e.deltaY
451
+
452
+ if (delta > 0) {
453
+ next()
454
+ } else if (delta < 0) {
455
+ prev()
456
+ }
457
+ }
458
+
459
+ // Keyboard navigation
460
+ const handleKeydown = (e: KeyboardEvent) => {
461
+ if (props.direction === 'horizontal') {
462
+ if (e.key === 'ArrowLeft') { e.preventDefault(); prev() }
463
+ if (e.key === 'ArrowRight') { e.preventDefault(); next() }
464
+ } else {
465
+ if (e.key === 'ArrowUp') { e.preventDefault(); prev() }
466
+ if (e.key === 'ArrowDown') { e.preventDefault(); next() }
467
+ }
468
+ if (e.key === 'Home') { e.preventDefault(); goTo(0) }
469
+ if (e.key === 'End') { e.preventDefault(); goTo(totalSlides.value - 1) }
470
+ }
471
+
472
+ // Click handling
473
+ let clickTimeout: number | null = null
474
+ const handleSlideClick = (index: number) => {
475
+ if (clickTimeout) {
476
+ clearTimeout(clickTimeout)
477
+ clickTimeout = null
478
+ emit('doubleClick', index)
479
+ } else {
480
+ clickTimeout = window.setTimeout(() => {
481
+ emit('click', index)
482
+ clickTimeout = null
483
+ }, 250)
484
+ }
485
+ }
486
+
487
+ // Watch for external modelValue changes
488
+ watch(() => props.modelValue, (newVal) => {
489
+ if (newVal !== activeIndex.value) {
490
+ goTo(newVal)
491
+ }
492
+ })
493
+
494
+ // Lifecycle
495
+ onMounted(() => {
496
+ if (containerRef.value) {
497
+ containerRef.value.addEventListener('keydown', handleKeydown)
498
+ if (props.mousewheel) {
499
+ containerRef.value.addEventListener('wheel', handleWheel, { passive: false })
500
+ }
501
+ }
502
+
503
+ nextTick(() => {
504
+ if (props.autoplay) {
505
+ startAutoplay()
506
+ }
507
+ updateSlideProgress()
508
+ })
509
+ })
510
+
511
+ onUnmounted(() => {
512
+ stopAutoplay()
513
+ if (containerRef.value) {
514
+ containerRef.value.removeEventListener('keydown', handleKeydown)
515
+ containerRef.value.removeEventListener('wheel', handleWheel)
516
+ }
517
+ })
518
+
519
+ // Provide context to slides
520
+ provide<SCarouselContext>(SCarouselContextKey, {
521
+ registerSlide,
522
+ unregisterSlide,
523
+ activeIndex,
524
+ effect: props.effect,
525
+ direction: props.direction,
526
+ slidesPerView: props.slidesPerView
527
+ })
528
+
529
+ // Expose methods
530
+ defineExpose({
531
+ next,
532
+ prev,
533
+ goTo,
534
+ start,
535
+ stop,
536
+ pause,
537
+ resume,
538
+ activeIndex,
539
+ totalSlides,
540
+ isTransitioning,
541
+ slideProgress
542
+ })
543
+ </script>
544
+
545
+ <template>
546
+ <div
547
+ ref="containerRef"
548
+ v-bind="$attrs"
549
+ :class="cn('s-carousel relative overflow-hidden bg-muted select-none', [
550
+ `s-carousel--${effect}`,
551
+ `s-carousel--${direction}`,
552
+ { 's-carousel--dragging': isDragging },
553
+ { 'cursor-grab': grabCursor && !isDragging },
554
+ { 'cursor-grabbing': grabCursor && isDragging },
555
+ containerClass
556
+ ], $attrs.class ?? '')"
557
+ :style="containerStyle"
558
+ tabindex="0"
559
+ :role="a11y ? 'region' : undefined"
560
+ :aria-roledescription="a11y ? 'carousel' : undefined"
561
+ :aria-label="a11y ? ariaLabel : undefined"
562
+ @mouseenter="handleMouseEnter"
563
+ @mouseleave="handleMouseLeave"
564
+ @mousedown="handleDragStart"
565
+ @mousemove="handleDragMove"
566
+ @mouseup="handleDragEnd"
567
+ @mouseleave.capture="handleDragEnd"
568
+ @touchstart.passive="handleDragStart"
569
+ @touchmove.passive="handleDragMove"
570
+ @touchend="handleDragEnd"
571
+ >
572
+ <!-- Track / Slides Container -->
573
+ <div
574
+ class="s-carousel__track h-full"
575
+ :class="{
576
+ 'flex': ['slide', 'parallax'].includes(effect),
577
+ 'flex-row': ['slide', 'parallax'].includes(effect) && direction === 'horizontal',
578
+ 'flex-col': ['slide', 'parallax'].includes(effect) && direction === 'vertical',
579
+ 'relative': !['slide', 'parallax'].includes(effect),
580
+ }"
581
+ :style="trackStyle"
582
+ >
583
+ <slot />
584
+ </div>
585
+
586
+ <!-- Progress Bar -->
587
+ <div
588
+ v-if="showProgress && autoplay"
589
+ class="s-carousel__progress absolute bottom-0 left-0 right-0 h-1 bg-black/20 z-30"
590
+ >
591
+ <div
592
+ class="h-full bg-primary transition-none"
593
+ :style="{ width: `${progressPercent}%` }"
594
+ />
595
+ </div>
596
+
597
+ <!-- Slide Counter -->
598
+ <div
599
+ v-if="showCounter"
600
+ class="s-carousel__counter absolute top-4 right-4 z-20 px-3 py-1.5 rounded-full bg-black/50 backdrop-blur-sm text-white text-sm font-medium"
601
+ >
602
+ {{ activeIndex + 1 }} / {{ totalSlides }}
603
+ </div>
604
+
605
+ <!-- Navigation Arrows -->
606
+ <template v-if="showArrows">
607
+ <!-- Grouped Arrow Placements (corner/center positions) -->
608
+ <div
609
+ v-if="arrowPlacement !== 'sides'"
610
+ class="s-carousel__arrows absolute z-20 flex gap-2"
611
+ :class="{
612
+ 'bottom-4 right-4': arrowPlacement === 'bottom-right',
613
+ 'bottom-4 left-4': arrowPlacement === 'bottom-left',
614
+ 'top-4 right-4': arrowPlacement === 'top-right',
615
+ 'top-4 left-4': arrowPlacement === 'top-left',
616
+ 'bottom-4 left-1/2 -translate-x-1/2': arrowPlacement === 'bottom-center',
617
+ 'top-4 left-1/2 -translate-x-1/2': arrowPlacement === 'top-center',
618
+ }"
619
+ >
620
+ <button
621
+ class="s-carousel__arrow s-carousel__arrow--prev flex items-center justify-center bg-background/90 backdrop-blur-sm text-foreground shadow-lg transition-all duration-300 hover:scale-110 hover:bg-background disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:scale-100"
622
+ :class="[arrowSizeClasses, arrowStyleClasses]"
623
+ :disabled="!canGoPrev"
624
+ @click.stop="prev"
625
+ :aria-label="a11y ? 'Previous slide' : undefined"
626
+ >
627
+ <span class="mdi mdi-chevron-left" />
628
+ </button>
629
+
630
+ <button
631
+ class="s-carousel__arrow s-carousel__arrow--next flex items-center justify-center bg-background/90 backdrop-blur-sm text-foreground shadow-lg transition-all duration-300 hover:scale-110 hover:bg-background disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:scale-100"
632
+ :class="[arrowSizeClasses, arrowStyleClasses]"
633
+ :disabled="!canGoNext"
634
+ @click.stop="next"
635
+ :aria-label="a11y ? 'Next slide' : undefined"
636
+ >
637
+ <span class="mdi mdi-chevron-right" />
638
+ </button>
639
+ </div>
640
+
641
+ <!-- Side Arrow Placement (classic left/right or top/bottom) -->
642
+ <template v-else>
643
+ <button
644
+ class="s-carousel__arrow s-carousel__arrow--prev absolute z-20 flex items-center justify-center bg-background/90 backdrop-blur-sm text-foreground shadow-lg transition-all duration-300 hover:scale-110 hover:bg-background disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:scale-100"
645
+ :class="[
646
+ arrowSizeClasses,
647
+ arrowStyleClasses,
648
+ direction === 'horizontal'
649
+ ? (arrowsInside ? 'left-4 top-1/2 -translate-y-1/2' : '-left-14 top-1/2 -translate-y-1/2')
650
+ : (arrowsInside ? 'top-4 left-1/2 -translate-x-1/2' : 'top-4 left-1/2 -translate-x-1/2')
651
+ ]"
652
+ :disabled="!canGoPrev"
653
+ @click.stop="prev"
654
+ :aria-label="a11y ? 'Previous slide' : undefined"
655
+ >
656
+ <span
657
+ class="mdi"
658
+ :class="direction === 'horizontal' ? 'mdi-chevron-left' : 'mdi-chevron-up'"
659
+ />
660
+ </button>
661
+
662
+ <button
663
+ class="s-carousel__arrow s-carousel__arrow--next absolute z-20 flex items-center justify-center bg-background/90 backdrop-blur-sm text-foreground shadow-lg transition-all duration-300 hover:scale-110 hover:bg-background disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:scale-100"
664
+ :class="[
665
+ arrowSizeClasses,
666
+ arrowStyleClasses,
667
+ direction === 'horizontal'
668
+ ? (arrowsInside ? 'right-4 top-1/2 -translate-y-1/2' : '-right-14 top-1/2 -translate-y-1/2')
669
+ : (arrowsInside ? 'bottom-4 left-1/2 -translate-x-1/2' : 'bottom-4 left-1/2 -translate-x-1/2')
670
+ ]"
671
+ :disabled="!canGoNext"
672
+ @click.stop="next"
673
+ :aria-label="a11y ? 'Next slide' : undefined"
674
+ >
675
+ <span
676
+ class="mdi"
677
+ :class="direction === 'horizontal' ? 'mdi-chevron-right' : 'mdi-chevron-down'"
678
+ />
679
+ </button>
680
+ </template>
681
+ </template>
682
+
683
+ <!-- Pagination -->
684
+ <div
685
+ v-if="showDots && totalSlides > 1"
686
+ class="s-carousel__dots absolute z-20 flex gap-2"
687
+ :class="{
688
+ 'bottom-4 left-1/2 -translate-x-1/2 flex-row': dotsPosition === 'bottom',
689
+ 'top-4 left-1/2 -translate-x-1/2 flex-row': dotsPosition === 'top',
690
+ 'left-4 top-1/2 -translate-y-1/2 flex-col': dotsPosition === 'left',
691
+ 'right-4 top-1/2 -translate-y-1/2 flex-col': dotsPosition === 'right',
692
+ }"
693
+ role="tablist"
694
+ >
695
+ <!-- Dots Style -->
696
+ <template v-if="dotsStyle === 'dots'">
697
+ <button
698
+ v-for="i in totalSlides"
699
+ :key="i - 1"
700
+ class="s-carousel__dot w-2.5 h-2.5 rounded-full transition-all duration-300"
701
+ :class="activeIndex === i - 1
702
+ ? 'bg-primary scale-125'
703
+ : 'bg-muted-foreground/50 hover:bg-muted-foreground'"
704
+ role="tab"
705
+ :aria-selected="activeIndex === i - 1"
706
+ :aria-label="a11y ? `Go to slide ${i}` : undefined"
707
+ @click.stop="goTo(i - 1)"
708
+ />
709
+ </template>
710
+
711
+ <!-- Bars Style -->
712
+ <template v-else-if="dotsStyle === 'bars'">
713
+ <button
714
+ v-for="i in totalSlides"
715
+ :key="i - 1"
716
+ class="s-carousel__bar h-1 rounded-full transition-all duration-300"
717
+ :class="activeIndex === i - 1
718
+ ? 'bg-primary w-8'
719
+ : 'bg-muted-foreground/50 hover:bg-muted-foreground w-4'"
720
+ role="tab"
721
+ :aria-selected="activeIndex === i - 1"
722
+ @click.stop="goTo(i - 1)"
723
+ />
724
+ </template>
725
+
726
+ <!-- Numbers Style -->
727
+ <template v-else-if="dotsStyle === 'numbers'">
728
+ <button
729
+ v-for="i in totalSlides"
730
+ :key="i - 1"
731
+ class="s-carousel__num w-7 h-7 rounded-full text-xs font-medium flex items-center justify-center transition-all duration-300"
732
+ :class="activeIndex === i - 1
733
+ ? 'bg-primary text-primary-foreground scale-110'
734
+ : 'bg-accent/80 text-muted-foreground hover:bg-background'"
735
+ role="tab"
736
+ :aria-selected="activeIndex === i - 1"
737
+ @click.stop="goTo(i - 1)"
738
+ >
739
+ {{ i }}
740
+ </button>
741
+ </template>
742
+
743
+ <!-- Fraction Style -->
744
+ <template v-else-if="dotsStyle === 'fraction'">
745
+ <div class="px-3 py-1.5 rounded-full bg-black/50 backdrop-blur-sm text-white text-sm font-medium">
746
+ <span class="font-bold">{{ activeIndex + 1 }}</span>
747
+ <span class="mx-1 opacity-60">/</span>
748
+ <span class="opacity-80">{{ totalSlides }}</span>
749
+ </div>
750
+ </template>
751
+ </div>
752
+
753
+ <!-- Thumbnails -->
754
+ <div
755
+ v-if="showThumbnails"
756
+ class="s-carousel__thumbnails absolute bottom-0 left-0 right-0 z-20 flex gap-2 p-4 bg-gradient-to-t from-black/60 to-transparent"
757
+ >
758
+ <button
759
+ v-for="i in totalSlides"
760
+ :key="i - 1"
761
+ class="s-carousel__thumb w-16 h-12 rounded-lg overflow-hidden border-2 transition-all duration-300"
762
+ :class="activeIndex === i - 1
763
+ ? 'border-primary scale-105 opacity-100'
764
+ : 'border-transparent opacity-60 hover:opacity-80'"
765
+ @click.stop="goTo(i - 1)"
766
+ >
767
+ <slot name="thumbnail" :index="i - 1" :isActive="activeIndex === i - 1">
768
+ <div class="w-full h-full bg-accent" />
769
+ </slot>
770
+ </button>
771
+ </div>
772
+ </div>
773
+ </template>
774
+
775
+ <style scoped>
776
+ .s-carousel {
777
+ --carousel-speed: 500ms;
778
+ --carousel-gap: 0px;
779
+ --carousel-easing: cubic-bezier(0.25, 0.1, 0.25, 1);
780
+ }
781
+
782
+ .s-carousel:focus {
783
+ outline: 2px solid var(--s-primary);
784
+ outline-offset: 2px;
785
+ }
786
+
787
+ /* Prevent text selection during drag */
788
+ .s-carousel--dragging {
789
+ cursor: grabbing !important;
790
+ }
791
+
792
+ .s-carousel--dragging * {
793
+ pointer-events: none;
794
+ }
795
+
796
+ /* Track transitions */
797
+ .s-carousel--slide .s-carousel__track,
798
+ .s-carousel--parallax .s-carousel__track {
799
+ transition: transform var(--carousel-speed) var(--carousel-easing);
800
+ gap: var(--carousel-gap);
801
+ }
802
+
803
+ .s-carousel--dragging .s-carousel__track {
804
+ transition: none;
805
+ }
806
+
807
+ /* ===== FADE EFFECT ===== */
808
+ .s-carousel--fade .s-carousel__track {
809
+ position: relative;
810
+ }
811
+
812
+ .s-carousel--fade :deep(.s-carousel-slide) {
813
+ position: absolute;
814
+ inset: 0;
815
+ opacity: 0;
816
+ transition: opacity var(--carousel-speed) ease-in-out, transform var(--carousel-speed) ease-in-out;
817
+ transform: scale(0.95);
818
+ }
819
+
820
+ .s-carousel--fade :deep(.s-carousel-slide--active) {
821
+ opacity: 1;
822
+ transform: scale(1);
823
+ z-index: 1;
824
+ }
825
+
826
+ /* ===== CUBE EFFECT ===== */
827
+ .s-carousel--cube {
828
+ perspective: 1200px;
829
+ }
830
+
831
+ .s-carousel--cube .s-carousel__track {
832
+ transform-style: preserve-3d;
833
+ position: relative;
834
+ }
835
+
836
+ .s-carousel--cube :deep(.s-carousel-slide) {
837
+ position: absolute;
838
+ inset: 0;
839
+ backface-visibility: hidden;
840
+ transition: transform var(--carousel-speed) var(--carousel-easing);
841
+ }
842
+
843
+ /* ===== FLIP EFFECT ===== */
844
+ .s-carousel--flip {
845
+ perspective: 1200px;
846
+ }
847
+
848
+ .s-carousel--flip .s-carousel__track {
849
+ transform-style: preserve-3d;
850
+ position: relative;
851
+ }
852
+
853
+ .s-carousel--flip :deep(.s-carousel-slide) {
854
+ position: absolute;
855
+ inset: 0;
856
+ backface-visibility: hidden;
857
+ transition: transform var(--carousel-speed) var(--carousel-easing), opacity var(--carousel-speed) ease;
858
+ transform: rotateY(180deg);
859
+ opacity: 0;
860
+ }
861
+
862
+ .s-carousel--flip :deep(.s-carousel-slide--active) {
863
+ transform: rotateY(0deg);
864
+ opacity: 1;
865
+ z-index: 1;
866
+ }
867
+
868
+ /* ===== COVERFLOW EFFECT ===== */
869
+ .s-carousel--coverflow {
870
+ perspective: 1000px;
871
+ }
872
+
873
+ .s-carousel--coverflow .s-carousel__track {
874
+ display: flex;
875
+ align-items: center;
876
+ justify-content: center;
877
+ }
878
+
879
+ .s-carousel--coverflow :deep(.s-carousel-slide) {
880
+ flex-shrink: 0;
881
+ width: 60%;
882
+ transition: transform var(--carousel-speed) ease, opacity var(--carousel-speed) ease;
883
+ transform-origin: center;
884
+ }
885
+
886
+ /* ===== CARDS EFFECT ===== */
887
+ .s-carousel--cards .s-carousel__track {
888
+ position: relative;
889
+ }
890
+
891
+ .s-carousel--cards :deep(.s-carousel-slide) {
892
+ position: absolute;
893
+ inset: 5%;
894
+ width: 90%;
895
+ height: 90%;
896
+ margin: auto;
897
+ transition: transform var(--carousel-speed) var(--carousel-easing),
898
+ opacity var(--carousel-speed) ease,
899
+ box-shadow var(--carousel-speed) ease;
900
+ border-radius: 12px;
901
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
902
+ }
903
+
904
+ .s-carousel--cards :deep(.s-carousel-slide--active) {
905
+ z-index: 10;
906
+ transform: scale(1) translateY(0);
907
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
908
+ }
909
+
910
+ /* ===== ZOOM EFFECT ===== */
911
+ .s-carousel--zoom .s-carousel__track {
912
+ position: relative;
913
+ }
914
+
915
+ .s-carousel--zoom :deep(.s-carousel-slide) {
916
+ position: absolute;
917
+ inset: 0;
918
+ opacity: 0;
919
+ transition: opacity var(--carousel-speed) ease-in-out,
920
+ transform var(--carousel-speed) var(--carousel-easing);
921
+ transform: scale(1.3);
922
+ }
923
+
924
+ .s-carousel--zoom :deep(.s-carousel-slide--active) {
925
+ opacity: 1;
926
+ transform: scale(1);
927
+ z-index: 1;
928
+ }
929
+
930
+ /* ===== CREATIVE EFFECT ===== */
931
+ .s-carousel--creative {
932
+ perspective: 1200px;
933
+ }
934
+
935
+ .s-carousel--creative .s-carousel__track {
936
+ transform-style: preserve-3d;
937
+ position: relative;
938
+ }
939
+
940
+ .s-carousel--creative :deep(.s-carousel-slide) {
941
+ position: absolute;
942
+ inset: 0;
943
+ opacity: 0;
944
+ transition: all var(--carousel-speed) var(--carousel-easing);
945
+ transform: translateX(100%) rotateY(-25deg) scale(0.8);
946
+ transform-origin: left center;
947
+ }
948
+
949
+ .s-carousel--creative :deep(.s-carousel-slide--active) {
950
+ opacity: 1;
951
+ transform: translateX(0) rotateY(0) scale(1);
952
+ z-index: 1;
953
+ }
954
+
955
+ /* ===== PARALLAX EFFECT ===== */
956
+ .s-carousel--parallax :deep(.s-carousel-slide) {
957
+ overflow: hidden;
958
+ }
959
+
960
+ .s-carousel--parallax :deep(.s-carousel-slide > *:first-child) {
961
+ transition: transform var(--carousel-speed) var(--carousel-easing);
962
+ transform: scale(1.2);
963
+ }
964
+
965
+ .s-carousel--parallax :deep(.s-carousel-slide--active > *:first-child) {
966
+ transform: scale(1);
967
+ }
968
+
969
+ /* ===== STACK EFFECT ===== */
970
+ .s-carousel--stack .s-carousel__track {
971
+ position: relative;
972
+ }
973
+
974
+ .s-carousel--stack :deep(.s-carousel-slide) {
975
+ position: absolute;
976
+ inset: 0;
977
+ transition: all var(--carousel-speed) var(--carousel-easing);
978
+ transform-origin: center bottom;
979
+ }
980
+
981
+ .s-carousel--stack :deep(.s-carousel-slide:not(.s-carousel-slide--active)) {
982
+ transform: scale(0.9) translateY(10%);
983
+ opacity: 0.5;
984
+ z-index: 0;
985
+ }
986
+
987
+ .s-carousel--stack :deep(.s-carousel-slide--active) {
988
+ transform: scale(1) translateY(0);
989
+ opacity: 1;
990
+ z-index: 10;
991
+ }
992
+
993
+ /* ===== SWIRL EFFECT ===== */
994
+ .s-carousel--swirl {
995
+ perspective: 1500px;
996
+ }
997
+
998
+ .s-carousel--swirl .s-carousel__track {
999
+ transform-style: preserve-3d;
1000
+ position: relative;
1001
+ }
1002
+
1003
+ .s-carousel--swirl :deep(.s-carousel-slide) {
1004
+ position: absolute;
1005
+ inset: 0;
1006
+ opacity: 0;
1007
+ transition: all var(--carousel-speed) var(--carousel-easing);
1008
+ transform: rotateZ(15deg) rotateY(45deg) scale(0.7);
1009
+ }
1010
+
1011
+ .s-carousel--swirl :deep(.s-carousel-slide--active) {
1012
+ opacity: 1;
1013
+ transform: rotateZ(0) rotateY(0) scale(1);
1014
+ z-index: 1;
1015
+ }
1016
+
1017
+ /* ===== KEN BURNS EFFECT ===== */
1018
+ .s-carousel--kenburns .s-carousel__track {
1019
+ position: relative;
1020
+ }
1021
+
1022
+ .s-carousel--kenburns :deep(.s-carousel-slide) {
1023
+ position: absolute;
1024
+ inset: 0;
1025
+ opacity: 0;
1026
+ transition: opacity calc(var(--carousel-speed) * 1.5) ease-in-out;
1027
+ overflow: hidden;
1028
+ }
1029
+
1030
+ .s-carousel--kenburns :deep(.s-carousel-slide > *:first-child) {
1031
+ transition: transform 8s ease-out;
1032
+ transform: scale(1);
1033
+ }
1034
+
1035
+ .s-carousel--kenburns :deep(.s-carousel-slide--active) {
1036
+ opacity: 1;
1037
+ z-index: 1;
1038
+ }
1039
+
1040
+ .s-carousel--kenburns :deep(.s-carousel-slide--active > *:first-child) {
1041
+ animation: kenburns 8s ease-out forwards;
1042
+ }
1043
+
1044
+ @keyframes kenburns {
1045
+ 0% { transform: scale(1) translate(0, 0); }
1046
+ 100% { transform: scale(1.2) translate(-2%, -1%); }
1047
+ }
1048
+
1049
+ /* Arrow hover effects */
1050
+ .s-carousel__arrow {
1051
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
1052
+ }
1053
+
1054
+ .s-carousel__arrow:hover:not(:disabled) {
1055
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
1056
+ }
1057
+
1058
+ /* Dot/bar active animation */
1059
+ .s-carousel__dot,
1060
+ .s-carousel__bar,
1061
+ .s-carousel__num {
1062
+ transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
1063
+ }
1064
+
1065
+ /* Thumbnail styling */
1066
+ .s-carousel__thumb {
1067
+ flex-shrink: 0;
1068
+ }
1069
+ </style>