@leavepulse/ui 0.43.4 → 0.45.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 (437) hide show
  1. package/README.md +121 -7
  2. package/dist/assets/{LpCommandPalette-B-0Est4Z.css → LpCommandPalette-nGNnzXqQ.css} +21 -21
  3. package/dist/assets/{LpDropzone-BBoWvi-J.css → LpDropzone-i4BdMi1H.css} +12 -12
  4. package/dist/assets/{LpImageEditor-Ct7Y3aNu.css → LpImageEditor-CbMA82g8.css} +6 -6
  5. package/dist/assets/{LpRollingText-CR1mb0Vt.css → LpRollingText-BGnE6q9j.css} +3 -0
  6. package/dist/assets/{LpShortcutsDialog-C6YoQ8_M.css → LpShortcutsDialog-CqYX3yy6.css} +28 -7
  7. package/dist/assets/{LpSkeleton-D7xU8IPV.css → LpSkeleton-H3Z5dEIk.css} +4 -1
  8. package/dist/assets/{LpTable-BgPLJOXa.css → LpTable-CPwWxTJS.css} +49 -9
  9. package/dist/chunks/ContextMenuItems-BtKU7074.js +124 -0
  10. package/dist/chunks/{LayoutCanvas-Dd20boUG.js → LayoutCanvas-BkaGXTjx.js} +26 -9
  11. package/dist/chunks/{LayoutNode-DGpZA9LX.js → LayoutNode-B3_9E1Xa.js} +28 -12
  12. package/dist/chunks/{LpActionBar-BlvtGB2P.js → LpActionBar-CnfFVIwC.js} +26 -12
  13. package/dist/chunks/{LpAddressInput-B-Zvxsn7.js → LpAddressInput-BwX8uo4_.js} +54 -49
  14. package/dist/chunks/{LpAlert-BAYHDSS1.js → LpAlert-B6ilrM7T.js} +16 -9
  15. package/dist/chunks/{LpAppShell-BGQVIY-3.js → LpAppShell-C53_RaGF.js} +53 -26
  16. package/dist/chunks/{LpAutocomplete-DExlIZe_.js → LpAutocomplete-C8IgSMsi.js} +52 -24
  17. package/dist/chunks/{LpAvatar-B3-xAOH3.js → LpAvatar-C1XStdOo.js} +19 -10
  18. package/dist/chunks/LpBreadcrumbs-CQJd73Gm.js +95 -0
  19. package/dist/chunks/{LpButton-5VXXCjwF.js → LpButton-CKSwC6Mu.js} +45 -15
  20. package/dist/chunks/{LpCalendar-B7Ko5RdR.js → LpCalendar-DrA2McTU.js} +1 -1
  21. package/dist/chunks/{LpCard-BhI1N_vL.js → LpCard-C2IvucmX.js} +1 -1
  22. package/dist/chunks/{LpCheckbox-CVccKYaH.js → LpCheckbox-Bkj13CbW.js} +8 -4
  23. package/dist/chunks/{LpCodeBlock-Bo0B4TFR.js → LpCodeBlock-ca7ANFyW.js} +49 -17
  24. package/dist/chunks/{LpColorPicker-BlXea7LM.js → LpColorPicker-zz4VGkG4.js} +75 -26
  25. package/dist/chunks/{LpConfirmDialog-Q-bxff8z.js → LpConfirmDialog-DCw5jR1t.js} +59 -17
  26. package/dist/chunks/LpConfirmHost-CbywMpMP.js +49 -0
  27. package/dist/chunks/LpContextMenu-BqkAYa9X.js +69 -0
  28. package/dist/chunks/LpDatePicker-DuusgT69.js +195 -0
  29. package/dist/chunks/LpDateRangePicker-DHeuznfC.js +208 -0
  30. package/dist/chunks/{LpDisclosure-ChQYmjlR.js → LpDisclosure-Cc23-JOT.js} +1 -1
  31. package/dist/chunks/{LpDrawer-BZ6k3hvo.js → LpDrawer-Dt4aB4Fr.js} +65 -28
  32. package/dist/chunks/{LpDropdownMenu-DJpoqRCb.js → LpDropdownMenu-DdJGQzPn.js} +2 -1
  33. package/dist/chunks/{LpEmptyState-Dsdqz1Wj.js → LpEmptyState-BJbZXC8D.js} +1 -1
  34. package/dist/chunks/LpFieldNotice-wtieLUTj.js +64 -0
  35. package/dist/chunks/{LpFileTree-_5vFBgaK.js → LpFileTree-CNurOvkV.js} +25 -10
  36. package/dist/chunks/{LpFileTreeNode-BdcIYKIE.js → LpFileTreeNode-D_qRRdsH.js} +3 -3
  37. package/dist/chunks/LpFormField-CtVYj6tO.js +101 -0
  38. package/dist/chunks/{LpIcon-CCnX5_2j.js → LpIcon-DYtaid0K.js} +20 -6
  39. package/dist/chunks/{LpInput-9EXWUM9B.js → LpInput-D-YGQbEv.js} +58 -20
  40. package/dist/chunks/{LpLightbox-2sYVMY-S.js → LpLightbox-DSDahF23.js} +148 -61
  41. package/dist/chunks/{LpLink-DCND-zyu.js → LpLink-Krkjhe_y.js} +15 -6
  42. package/dist/chunks/{LpLogViewer-CaRy5MeS.js → LpLogViewer-KypbgOyo.js} +300 -72
  43. package/dist/chunks/{LpMapPicker-ul4oYno6.js → LpMapPicker-Cc84LaM3.js} +39 -14
  44. package/dist/chunks/{LpMediaGallery-FF-NquIo.js → LpMediaGallery-YKr-cQPN.js} +7 -4
  45. package/dist/chunks/{LpModal-Bt0pQCI_.js → LpModal-DMMDQHAu.js} +52 -29
  46. package/dist/chunks/{LpModalNav-YaifHrXC.js → LpModalNav-BVPDyIup.js} +10 -7
  47. package/dist/chunks/{LpNotificationBell-DyGGsMAM.js → LpNotificationBell-CCwyJP5C.js} +79 -33
  48. package/dist/chunks/{LpNumberField-CWuX08iX.js → LpNumberField-B77O-z28.js} +21 -8
  49. package/dist/chunks/{LpNumberFlow-amWYaeuA.js → LpNumberFlow-z4WPZcZu.js} +22 -12
  50. package/dist/chunks/{LpOtpInput-y2v-pmiN.js → LpOtpInput-CziPF3Oq.js} +37 -8
  51. package/dist/chunks/{LpPagination-5FxjmmB5.js → LpPagination-BcDlo3r_.js} +31 -20
  52. package/dist/chunks/{LpPasswordInput--sjYCkLS.js → LpPasswordInput-eKzQhbQP.js} +11 -8
  53. package/dist/chunks/LpPhoneInput-BCbrrhgE.js +336 -0
  54. package/dist/chunks/{LpPie-D6OnzwlJ.js → LpPie-BEJ2SfI6.js} +84 -28
  55. package/dist/chunks/{LpPopover-8268UmlC.js → LpPopover-DCKeqiVn.js} +5 -2
  56. package/dist/chunks/{LpProgress-Btq5W4Ut.js → LpProgress-CBU1iI69.js} +5 -4
  57. package/dist/chunks/{LpRadioGroup-xPIuVDO_.js → LpRadioGroup-DmEW0l78.js} +9 -2
  58. package/dist/chunks/LpRangeCalendar-DZuaRV0W.js +331 -0
  59. package/dist/chunks/{LpRollingText-CM5gkSeF.js → LpRollingText-DB7upf-5.js} +1 -1
  60. package/dist/chunks/{LpScrollArea-D8xyKXcF.js → LpScrollArea-Bry1fdOM.js} +14 -2
  61. package/dist/chunks/{LpSection-aM6J_u51.js → LpSection-tKEH0jYf.js} +1 -1
  62. package/dist/chunks/{LpSegmented-fV0Sk92p.js → LpSegmented-C09EEam2.js} +8 -4
  63. package/dist/chunks/{LpSelect-ANIVtrpM.js → LpSelect-DNIL6MB9.js} +50 -31
  64. package/dist/chunks/{LpSidebar-ClBUwoEz.js → LpSidebar-CQNB0-yU.js} +30 -22
  65. package/dist/chunks/{LpSidebarNav-llOcs_Fn.js → LpSidebarNav-kx-LdqNU.js} +16 -11
  66. package/dist/chunks/{LpSkeleton-CTI-vBgW.js → LpSkeleton-BB6XIV-w.js} +1 -1
  67. package/dist/chunks/{LpSlider-BwNIBkAK.js → LpSlider-Cuzmrd7p.js} +7 -2
  68. package/dist/chunks/{LpSparkline-C6xQ2dwv.js → LpSparkline-CB80N8SJ.js} +11 -4
  69. package/dist/chunks/{LpStat-CQaW8R--.js → LpStat-B-7udBRP.js} +2 -2
  70. package/dist/chunks/{LpStepper-Bk-XaQYU.js → LpStepper-C7XiVKZj.js} +34 -19
  71. package/dist/chunks/{LpSwitch-Blizvqyt.js → LpSwitch-OrcOJX9m.js} +41 -27
  72. package/dist/chunks/LpTableFilter-BV8PpLM9.js +158 -0
  73. package/dist/chunks/{LpTableOfContents-CjvxPMpU.js → LpTableOfContents-BUcAfGPQ.js} +36 -41
  74. package/dist/chunks/{LpTabs-Cefe_lys.js → LpTabs-29iW1XOx.js} +20 -6
  75. package/dist/chunks/LpTagsInput-D1SuqbhB.js +300 -0
  76. package/dist/chunks/LpTextarea-uuScWo6-.js +77 -0
  77. package/dist/chunks/LpThemeProvider-Be4r2TQX.js +35 -0
  78. package/dist/chunks/LpThemeSwitcher-B4aVPbNC.js +166 -0
  79. package/dist/chunks/{LpTilt-DuyKbpkA.js → LpTilt-B7KHX1zH.js} +2 -2
  80. package/dist/chunks/{LpTimeField-K6nAGboX.js → LpTimeField-Cqe7fXnh.js} +14 -8
  81. package/dist/chunks/{LpToaster-gDB1EaU3.js → LpToaster-DpJvoCOh.js} +94 -31
  82. package/dist/chunks/{LpTooltip-hCLPAqMG.js → LpTooltip-CXVKcOXT.js} +14 -6
  83. package/dist/chunks/LpTooltipProvider-CftjV7Xc.js +25 -0
  84. package/dist/chunks/{LpTopologyCanvas-Cm1L39uL.js → LpTopologyCanvas-6ozNrQKh.js} +8 -2
  85. package/dist/chunks/{LpUptimeBar-DvAMno0S.js → LpUptimeBar-ugcv25xj.js} +44 -15
  86. package/dist/chunks/icons-CkA0njzm.js +43 -0
  87. package/dist/chunks/{LpThemeSwitcher-Cue-myST.js → useTheme-DJm1JSsY.js} +215 -260
  88. package/dist/component-names.d.ts +1 -1
  89. package/dist/components/ContextMenuItems.vue.d.ts +8 -0
  90. package/dist/components/ContextMenuItems.vue.js +4 -0
  91. package/dist/components/LayoutCanvas.vue.js +1 -1
  92. package/dist/components/LayoutNode.vue.d.ts +4 -0
  93. package/dist/components/LayoutNode.vue.js +1 -1
  94. package/dist/components/LpActionBar.vue.d.ts +3 -0
  95. package/dist/components/LpActionBar.vue.js +1 -1
  96. package/dist/components/LpAddressInput.vue.d.ts +1 -1
  97. package/dist/components/LpAddressInput.vue.js +1 -1
  98. package/dist/components/LpAlert.vue.d.ts +9 -0
  99. package/dist/components/LpAlert.vue.js +1 -1
  100. package/dist/components/LpAppShell.vue.d.ts +10 -0
  101. package/dist/components/LpAppShell.vue.js +1 -1
  102. package/dist/components/LpAutocomplete.vue.d.ts +31 -6
  103. package/dist/components/LpAutocomplete.vue.js +1 -1
  104. package/dist/components/LpAvatar.vue.d.ts +3 -3
  105. package/dist/components/LpAvatar.vue.js +1 -1
  106. package/dist/components/LpBadge.vue.d.ts +2 -2
  107. package/dist/components/LpBreadcrumbs.vue.d.ts +13 -9
  108. package/dist/components/LpBreadcrumbs.vue.js +1 -1
  109. package/dist/components/LpButton.vue.d.ts +35 -98
  110. package/dist/components/LpButton.vue.js +1 -1
  111. package/dist/components/LpCalendar.vue.js +1 -1
  112. package/dist/components/LpCard.vue.js +1 -1
  113. package/dist/components/LpChart.vue.d.ts +47 -3
  114. package/dist/components/LpChart.vue.js +377 -97
  115. package/dist/components/LpCheckbox.vue.js +1 -1
  116. package/dist/components/LpCodeBlock.vue.d.ts +2 -0
  117. package/dist/components/LpCodeBlock.vue.js +1 -1
  118. package/dist/components/LpColorPicker.vue.d.ts +2 -2
  119. package/dist/components/LpColorPicker.vue.js +1 -1
  120. package/dist/components/LpCommandPalette.vue.d.ts +14 -3
  121. package/dist/components/LpCommandPalette.vue.js +142 -77
  122. package/dist/components/LpConfirmDialog.vue.d.ts +15 -3
  123. package/dist/components/LpConfirmDialog.vue.js +1 -1
  124. package/dist/components/LpConfirmHost.vue.d.ts +9 -0
  125. package/dist/components/LpConfirmHost.vue.js +4 -0
  126. package/dist/components/LpContextMenu.vue.d.ts +3 -5
  127. package/dist/components/LpContextMenu.vue.js +1 -1
  128. package/dist/components/LpDatePicker.vue.d.ts +24 -6
  129. package/dist/components/LpDatePicker.vue.js +1 -1
  130. package/dist/components/LpDateRangePicker.vue.d.ts +60 -0
  131. package/dist/components/LpDateRangePicker.vue.js +4 -0
  132. package/dist/components/LpDisclosure.vue.js +1 -1
  133. package/dist/components/LpDrawer.vue.d.ts +10 -0
  134. package/dist/components/LpDrawer.vue.js +1 -1
  135. package/dist/components/LpDropdownMenu.vue.js +1 -1
  136. package/dist/components/LpDropzone.vue.js +23 -7
  137. package/dist/components/LpEmptyState.vue.js +1 -1
  138. package/dist/components/LpFieldNotice.vue.d.ts +8 -0
  139. package/dist/components/LpFieldNotice.vue.js +4 -0
  140. package/dist/components/LpFileTree.vue.d.ts +11 -2
  141. package/dist/components/LpFileTree.vue.js +1 -1
  142. package/dist/components/LpFileTreeNode.vue.js +1 -1
  143. package/dist/components/LpFormField.vue.d.ts +13 -1
  144. package/dist/components/LpFormField.vue.js +1 -1
  145. package/dist/components/LpIcon.vue.d.ts +0 -1
  146. package/dist/components/LpIcon.vue.js +1 -1
  147. package/dist/components/LpImageEditor.vue.js +93 -58
  148. package/dist/components/LpInput.vue.d.ts +22 -3
  149. package/dist/components/LpInput.vue.js +1 -1
  150. package/dist/components/LpLightbox.vue.d.ts +17 -0
  151. package/dist/components/LpLightbox.vue.js +1 -1
  152. package/dist/components/LpLink.vue.d.ts +11 -11
  153. package/dist/components/LpLink.vue.js +1 -1
  154. package/dist/components/LpLogViewer.vue.d.ts +72 -3
  155. package/dist/components/LpLogViewer.vue.js +1 -1
  156. package/dist/components/LpMapPicker.vue.d.ts +4 -4
  157. package/dist/components/LpMapPicker.vue.js +1 -1
  158. package/dist/components/LpMediaGallery.vue.js +1 -1
  159. package/dist/components/LpModal.vue.d.ts +16 -6
  160. package/dist/components/LpModal.vue.js +1 -1
  161. package/dist/components/LpModalNav.vue.d.ts +0 -1
  162. package/dist/components/LpModalNav.vue.js +1 -1
  163. package/dist/components/LpNotificationBell.vue.d.ts +11 -2
  164. package/dist/components/LpNotificationBell.vue.js +1 -1
  165. package/dist/components/LpNumberField.vue.d.ts +2 -0
  166. package/dist/components/LpNumberField.vue.js +1 -1
  167. package/dist/components/LpNumberFlow.vue.js +1 -1
  168. package/dist/components/LpOtpInput.vue.js +1 -1
  169. package/dist/components/LpPagination.vue.d.ts +2 -0
  170. package/dist/components/LpPagination.vue.js +1 -1
  171. package/dist/components/LpPasswordInput.vue.js +1 -1
  172. package/dist/components/LpPhoneInput.vue.d.ts +13 -0
  173. package/dist/components/LpPhoneInput.vue.js +1 -1
  174. package/dist/components/LpPie.vue.d.ts +21 -2
  175. package/dist/components/LpPie.vue.js +1 -1
  176. package/dist/components/LpPopover.vue.d.ts +2 -0
  177. package/dist/components/LpPopover.vue.js +1 -1
  178. package/dist/components/LpProgress.vue.d.ts +1 -1
  179. package/dist/components/LpProgress.vue.js +1 -1
  180. package/dist/components/LpRadioGroup.vue.js +1 -1
  181. package/dist/components/LpRangeCalendar.vue.d.ts +51 -0
  182. package/dist/components/LpRangeCalendar.vue.js +4 -0
  183. package/dist/components/LpRollingText.vue.d.ts +1 -1
  184. package/dist/components/LpRollingText.vue.js +1 -1
  185. package/dist/components/LpScrollArea.vue.d.ts +2 -2
  186. package/dist/components/LpScrollArea.vue.js +1 -1
  187. package/dist/components/LpSection.vue.d.ts +1 -1
  188. package/dist/components/LpSection.vue.js +1 -1
  189. package/dist/components/LpSegmented.vue.d.ts +5 -0
  190. package/dist/components/LpSegmented.vue.js +1 -1
  191. package/dist/components/LpSelect.vue.d.ts +1 -0
  192. package/dist/components/LpSelect.vue.js +1 -1
  193. package/dist/components/LpShortcutsDialog.vue.d.ts +7 -1
  194. package/dist/components/LpShortcutsDialog.vue.js +60 -15
  195. package/dist/components/LpSidebar.vue.d.ts +6 -2
  196. package/dist/components/LpSidebar.vue.js +1 -1
  197. package/dist/components/LpSidebarNav.vue.js +1 -1
  198. package/dist/components/LpSkeleton.vue.js +1 -1
  199. package/dist/components/LpSlider.vue.js +1 -1
  200. package/dist/components/LpSparkline.vue.d.ts +1 -0
  201. package/dist/components/LpSparkline.vue.js +1 -1
  202. package/dist/components/LpStat.vue.js +1 -1
  203. package/dist/components/LpStepper.vue.js +1 -1
  204. package/dist/components/LpSwitch.vue.js +1 -1
  205. package/dist/components/LpTable.vue.d.ts +107 -3
  206. package/dist/components/LpTable.vue.js +540 -128
  207. package/dist/components/LpTableFilter.vue.d.ts +31 -0
  208. package/dist/components/LpTableFilter.vue.js +4 -0
  209. package/dist/components/LpTableOfContents.vue.d.ts +4 -2
  210. package/dist/components/LpTableOfContents.vue.js +1 -1
  211. package/dist/components/LpTabs.vue.d.ts +2 -0
  212. package/dist/components/LpTabs.vue.js +1 -1
  213. package/dist/components/LpTagsInput.vue.d.ts +77 -0
  214. package/dist/components/LpTagsInput.vue.js +4 -0
  215. package/dist/components/LpTextarea.vue.d.ts +19 -6
  216. package/dist/components/LpTextarea.vue.js +1 -1
  217. package/dist/components/LpThemeProvider.vue.d.ts +22 -0
  218. package/dist/components/LpThemeProvider.vue.js +4 -0
  219. package/dist/components/LpThemeSwitcher.vue.d.ts +15 -2
  220. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  221. package/dist/components/LpTilt.vue.js +1 -1
  222. package/dist/components/LpTimeField.vue.js +1 -1
  223. package/dist/components/LpToaster.vue.d.ts +6 -1
  224. package/dist/components/LpToaster.vue.js +1 -1
  225. package/dist/components/LpTooltip.vue.d.ts +1 -2
  226. package/dist/components/LpTooltip.vue.js +1 -1
  227. package/dist/components/LpTooltipProvider.vue.d.ts +22 -0
  228. package/dist/components/LpTooltipProvider.vue.js +4 -0
  229. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  230. package/dist/components/LpUptimeBar.vue.d.ts +4 -0
  231. package/dist/components/LpUptimeBar.vue.js +1 -1
  232. package/dist/components/chart.d.ts +32 -1
  233. package/dist/components/chart.js +42 -6
  234. package/dist/components/codeHighlight.d.ts +6 -0
  235. package/dist/components/codeHighlight.js +92 -20
  236. package/dist/components/color.d.ts +1 -1
  237. package/dist/components/color.js +20 -9
  238. package/dist/components/commandSearch.js +3 -0
  239. package/dist/components/confirm.d.ts +25 -0
  240. package/dist/components/confirm.js +26 -0
  241. package/dist/components/countries.d.ts +6 -0
  242. package/dist/components/countries.js +7 -0
  243. package/dist/components/dateRange.d.ts +43 -0
  244. package/dist/components/dateRange.js +76 -0
  245. package/dist/components/exportData.d.ts +58 -0
  246. package/dist/components/exportData.js +165 -0
  247. package/dist/components/fileTree.js +16 -7
  248. package/dist/components/imageCrop.d.ts +42 -0
  249. package/dist/components/imageCrop.js +47 -0
  250. package/dist/components/link.d.ts +12 -0
  251. package/dist/components/link.js +19 -0
  252. package/dist/components/logSearch.d.ts +18 -0
  253. package/dist/components/logSearch.js +36 -0
  254. package/dist/components/modalDepth.d.ts +18 -2
  255. package/dist/components/modalDepth.js +17 -5
  256. package/dist/components/otp.d.ts +5 -0
  257. package/dist/components/otp.js +10 -0
  258. package/dist/components/phone.d.ts +41 -0
  259. package/dist/components/phone.js +80 -0
  260. package/dist/components/sidebar.d.ts +7 -1
  261. package/dist/components/tableFilter.d.ts +36 -0
  262. package/dist/components/tableFilter.js +84 -0
  263. package/dist/components/tableSort.d.ts +8 -0
  264. package/dist/components/tableSort.js +31 -0
  265. package/dist/components/tags.d.ts +20 -0
  266. package/dist/components/tags.js +37 -0
  267. package/dist/composables/useField.d.ts +38 -0
  268. package/dist/composables/useField.js +45 -0
  269. package/dist/composables/useFieldNotice.d.ts +17 -0
  270. package/dist/composables/useFieldNotice.js +28 -0
  271. package/dist/composables/useForm.d.ts +53 -0
  272. package/dist/composables/useForm.js +207 -0
  273. package/dist/composables/useFormDraft.d.ts +10 -3
  274. package/dist/composables/useFormDraft.js +9 -14
  275. package/dist/composables/useHotkeys.d.ts +81 -5
  276. package/dist/composables/useHotkeys.js +223 -25
  277. package/dist/composables/useInputFilter.d.ts +17 -0
  278. package/dist/composables/useInputFilter.js +47 -10
  279. package/dist/composables/useInputMask.d.ts +59 -0
  280. package/dist/composables/useInputMask.js +170 -0
  281. package/dist/composables/useLpConfig.d.ts +24 -0
  282. package/dist/composables/useLpConfig.js +44 -0
  283. package/dist/composables/usePaintSelect.d.ts +22 -0
  284. package/dist/composables/usePaintSelect.js +169 -0
  285. package/dist/composables/useRovingFocus.js +7 -0
  286. package/dist/composables/useShift.js +7 -2
  287. package/dist/composables/useTilt.d.ts +2 -2
  288. package/dist/composables/useTilt.js +5 -6
  289. package/dist/composables/useToast.d.ts +20 -0
  290. package/dist/composables/useToast.js +28 -4
  291. package/dist/composables/useZoomPan.d.ts +3 -3
  292. package/dist/composables/useZoomPan.js +4 -4
  293. package/dist/icons-all.d.ts +1 -0
  294. package/dist/icons-all.js +3 -0
  295. package/dist/icons.d.ts +14 -1
  296. package/dist/index.d.ts +60 -4
  297. package/dist/index.js +245 -141
  298. package/dist/kit-icons.d.ts +2 -0
  299. package/dist/layout/tree.d.ts +2 -0
  300. package/dist/layout/tree.js +16 -1
  301. package/dist/layout/useLayout.d.ts +15 -0
  302. package/dist/layout/useLayout.js +41 -14
  303. package/dist/theme/backdrop.d.ts +12 -0
  304. package/dist/theme/presets.d.ts +0 -2
  305. package/dist/theme/useTheme.d.ts +32 -9
  306. package/package.json +18 -8
  307. package/src/component-names.ts +9 -7
  308. package/src/components/ContextMenuItems.vue +88 -0
  309. package/src/components/LayoutCanvas.vue +26 -6
  310. package/src/components/LayoutNode.vue +30 -4
  311. package/src/components/LpActionBar.vue +31 -8
  312. package/src/components/LpAddressInput.vue +57 -41
  313. package/src/components/LpAlert.vue +16 -3
  314. package/src/components/LpAppShell.vue +45 -12
  315. package/src/components/LpAutocomplete.vue +47 -10
  316. package/src/components/LpAvatar.vue +20 -6
  317. package/src/components/LpBreadcrumbs.vue +65 -41
  318. package/src/components/LpButton.vue +60 -14
  319. package/src/components/LpChart.vue +351 -28
  320. package/src/components/LpCheckbox.vue +7 -3
  321. package/src/components/LpCodeBlock.vue +50 -14
  322. package/src/components/LpColorPicker.vue +73 -10
  323. package/src/components/LpCommandPalette.vue +115 -20
  324. package/src/components/LpConfirmDialog.vue +68 -17
  325. package/src/components/LpConfirmHost.vue +59 -0
  326. package/src/components/LpContextMenu.vue +15 -116
  327. package/src/components/LpDatePicker.vue +104 -68
  328. package/src/components/LpDateRangePicker.vue +224 -0
  329. package/src/components/LpDrawer.vue +56 -19
  330. package/src/components/LpDropdownMenu.vue +1 -0
  331. package/src/components/LpDropzone.vue +21 -4
  332. package/src/components/LpFieldNotice.vue +65 -0
  333. package/src/components/LpFileTree.vue +33 -7
  334. package/src/components/LpFormField.vue +59 -7
  335. package/src/components/LpIcon.vue +22 -4
  336. package/src/components/LpImageEditor.vue +96 -57
  337. package/src/components/LpInput.vue +62 -11
  338. package/src/components/LpLightbox.vue +140 -29
  339. package/src/components/LpLink.vue +24 -13
  340. package/src/components/LpLogViewer.vue +311 -39
  341. package/src/components/LpMapPicker.vue +36 -13
  342. package/src/components/LpMediaGallery.vue +8 -2
  343. package/src/components/LpModal.vue +54 -28
  344. package/src/components/LpModalNav.vue +5 -2
  345. package/src/components/LpNotificationBell.vue +77 -23
  346. package/src/components/LpNumberField.vue +21 -6
  347. package/src/components/LpNumberFlow.vue +26 -10
  348. package/src/components/LpOtpInput.vue +43 -8
  349. package/src/components/LpPagination.vue +23 -7
  350. package/src/components/LpPasswordInput.vue +4 -1
  351. package/src/components/LpPhoneInput.vue +224 -39
  352. package/src/components/LpPie.vue +102 -20
  353. package/src/components/LpPopover.vue +4 -0
  354. package/src/components/LpProgress.vue +5 -3
  355. package/src/components/LpRadioGroup.vue +9 -2
  356. package/src/components/LpRangeCalendar.vue +365 -0
  357. package/src/components/LpRollingText.vue +3 -0
  358. package/src/components/LpScrollArea.vue +22 -2
  359. package/src/components/LpSegmented.vue +12 -2
  360. package/src/components/LpSelect.vue +0 -0
  361. package/src/components/LpShortcutsDialog.vue +83 -9
  362. package/src/components/LpSidebar.vue +14 -9
  363. package/src/components/LpSidebarNav.vue +17 -5
  364. package/src/components/LpSkeleton.vue +4 -1
  365. package/src/components/LpSlider.vue +7 -1
  366. package/src/components/LpSparkline.vue +11 -3
  367. package/src/components/LpStepper.vue +23 -10
  368. package/src/components/LpSwitch.vue +31 -8
  369. package/src/components/LpTable.vue +668 -90
  370. package/src/components/LpTableFilter.vue +175 -0
  371. package/src/components/LpTableOfContents.vue +50 -32
  372. package/src/components/LpTabs.vue +23 -6
  373. package/src/components/LpTagsInput.vue +364 -0
  374. package/src/components/LpTextarea.vue +44 -6
  375. package/src/components/LpThemeProvider.vue +41 -0
  376. package/src/components/LpThemeSwitcher.vue +76 -33
  377. package/src/components/LpTilt.vue +2 -2
  378. package/src/components/LpTimeField.vue +14 -3
  379. package/src/components/LpToaster.vue +115 -27
  380. package/src/components/LpTooltip.vue +29 -5
  381. package/src/components/LpTooltipProvider.vue +24 -0
  382. package/src/components/LpTopologyCanvas.vue +19 -2
  383. package/src/components/LpUptimeBar.vue +46 -8
  384. package/src/components/chart.ts +82 -8
  385. package/src/components/codeHighlight.ts +111 -15
  386. package/src/components/color.ts +30 -9
  387. package/src/components/commandSearch.ts +6 -0
  388. package/src/components/confirm.ts +58 -0
  389. package/src/components/countries.ts +12 -0
  390. package/src/components/dateRange.ts +134 -0
  391. package/src/components/exportData.ts +228 -0
  392. package/src/components/fileTree.ts +19 -7
  393. package/src/components/imageCrop.ts +107 -0
  394. package/src/components/link.ts +34 -0
  395. package/src/components/logSearch.ts +46 -0
  396. package/src/components/modalDepth.ts +48 -6
  397. package/src/components/otp.ts +16 -0
  398. package/src/components/phone.ts +140 -0
  399. package/src/components/sidebar.ts +7 -1
  400. package/src/components/tableFilter.ts +122 -0
  401. package/src/components/tableSort.ts +37 -0
  402. package/src/components/tags.ts +62 -0
  403. package/src/composables/useField.ts +83 -0
  404. package/src/composables/useFieldNotice.ts +59 -0
  405. package/src/composables/useForm.ts +314 -0
  406. package/src/composables/useFormDraft.ts +25 -20
  407. package/src/composables/useHotkeys.ts +355 -28
  408. package/src/composables/useInputFilter.ts +77 -14
  409. package/src/composables/useInputMask.ts +254 -0
  410. package/src/composables/useLpConfig.ts +87 -0
  411. package/src/composables/usePaintSelect.ts +243 -0
  412. package/src/composables/useRovingFocus.ts +11 -0
  413. package/src/composables/useShift.ts +13 -2
  414. package/src/composables/useTilt.ts +5 -6
  415. package/src/composables/useToast.ts +56 -4
  416. package/src/composables/useZoomPan.ts +6 -6
  417. package/src/iconSubset.d.mts +10 -0
  418. package/src/iconSubset.mjs +51 -0
  419. package/src/icons-all.ts +10 -0
  420. package/src/icons.ts +59 -8
  421. package/src/index.ts +73 -4
  422. package/src/kit-icons.ts +5 -0
  423. package/src/layout/tree.ts +30 -0
  424. package/src/layout/useLayout.ts +68 -18
  425. package/src/nuxt.ts +87 -17
  426. package/src/runtime/config.plugin.ts +14 -0
  427. package/src/runtime/theme.plugin.ts +43 -23
  428. package/src/theme/backdrop.ts +69 -0
  429. package/src/theme/presets.ts +6 -64
  430. package/src/theme/useTheme.ts +206 -100
  431. package/src/tokens/tokens.css +46 -0
  432. package/dist/chunks/LpBreadcrumbs-p4jHe_V-.js +0 -62
  433. package/dist/chunks/LpContextMenu-CwW1QXe_.js +0 -217
  434. package/dist/chunks/LpDatePicker-CwOToxGq.js +0 -164
  435. package/dist/chunks/LpFormField-CazBc2-a.js +0 -62
  436. package/dist/chunks/LpPhoneInput-BDSKVl_z.js +0 -209
  437. package/dist/chunks/LpTextarea-t7F6gv8E.js +0 -47
@@ -22,11 +22,29 @@ import {
22
22
  DialogTitle,
23
23
  } from "reka-ui"
24
24
  import { computed, nextTick, onBeforeUnmount, ref, watch } from "vue"
25
+ import { useLabels } from "../composables/useLpConfig"
25
26
  import { useZoomPan } from "../composables/useZoomPan"
26
27
  import { fileNameOf, type LightboxItem } from "./lightbox"
27
28
  import LpIcon from "./LpIcon.vue"
28
29
  import { useModalLayer } from "./modalDepth"
29
30
 
31
+ export type LightboxLabels = {
32
+ viewer: string
33
+ /** `{index}` and `{total}` are filled in. */
34
+ position: string
35
+ previous: string
36
+ next: string
37
+ zoomIn: string
38
+ zoomOut: string
39
+ rotate: string
40
+ copy: string
41
+ download: string
42
+ close: string
43
+ failed: string
44
+ spoiler: string
45
+ reveal: string
46
+ }
47
+
30
48
  const props = withDefaults(
31
49
  defineProps<{
32
50
  open?: boolean
@@ -46,6 +64,7 @@ const props = withDefaults(
46
64
  loop?: boolean
47
65
  /** Largest zoom level. */
48
66
  maxZoom?: number
67
+ labels?: Partial<LightboxLabels>
49
68
  }>(),
50
69
  {
51
70
  open: false,
@@ -68,7 +87,31 @@ const emit = defineEmits<{
68
87
  (e: "copy", item: LightboxItem, ok: boolean): void
69
88
  }>()
70
89
 
71
- const { claim, release, layer } = useModalLayer()
90
+ const text = useLabels<LightboxLabels>(
91
+ "lightbox",
92
+ {
93
+ viewer: "Image viewer",
94
+ position: "Image {index} of {total}",
95
+ previous: "Previous image",
96
+ next: "Next image",
97
+ zoomIn: "Zoom in (+)",
98
+ zoomOut: "Zoom out (−)",
99
+ rotate: "Rotate (R)",
100
+ copy: "Copy image",
101
+ download: "Download",
102
+ close: "Close (Esc)",
103
+ failed: "This image couldn't be loaded.",
104
+ spoiler: "Spoiler",
105
+ reveal: "Show image",
106
+ },
107
+ () => props.labels,
108
+ )
109
+
110
+ const position = (i: number) =>
111
+ text.value.position.replace("{index}", String(i + 1)).replace("{total}", String(props.items.length))
112
+
113
+ const contentRef = ref<{ $el: HTMLElement } | null>(null)
114
+ const { claim, release, layer } = useModalLayer({ element: () => contentRef.value?.$el })
72
115
  watch(() => props.open, (open) => (open ? claim() : release()), { immediate: true })
73
116
  onBeforeUnmount(release)
74
117
 
@@ -79,7 +122,7 @@ defineSlots<{
79
122
  actions(props: { item: LightboxItem; index: number }): unknown
80
123
  }>()
81
124
 
82
- const zoom = useZoomPan({ max: props.maxZoom })
125
+ const zoom = useZoomPan({ max: () => props.maxZoom })
83
126
 
84
127
  // `zoom` is a plain object, so its refs don't unwrap in the template — surface
85
128
  // the two the chrome reads as computeds rather than writing `.value` in markup.
@@ -87,7 +130,11 @@ const scale = computed(() => zoom.scale.value)
87
130
  const isZoomed = computed(() => zoom.zoomed.value)
88
131
  const isPanning = computed(() => zoom.panning.value)
89
132
 
90
- const current = computed(() => Math.min(Math.max(props.index, 0), Math.max(props.items.length - 1, 0)))
133
+ // Works with and without v-model:index: the prop seeds and steers it, paging
134
+ // moves it locally and reports the move.
135
+ const shown = ref(props.index)
136
+ watch(() => props.index, (i) => (shown.value = i))
137
+ const current = computed(() => Math.min(Math.max(shown.value, 0), Math.max(props.items.length - 1, 0)))
91
138
  const item = computed<LightboxItem | undefined>(() => props.items[current.value])
92
139
  const total = computed(() => props.items.length)
93
140
  const showStrip = computed(() => props.filmstrip ?? total.value > 1)
@@ -113,6 +160,7 @@ function go(next: number) {
113
160
  // Compare against the raw target, not the wrapped one: stepping past the last
114
161
  // image is still "forward" even though the index jumps back to 0.
115
162
  direction.value = next > current.value ? 1 : -1
163
+ shown.value = wrapped
116
164
  emit("update:index", wrapped)
117
165
  emit("change", wrapped, props.items[wrapped])
118
166
  }
@@ -193,6 +241,23 @@ function close() {
193
241
  emit("update:open", false)
194
242
  }
195
243
 
244
+ /*
245
+ * A spoiler stays covered until it is asked for, here as in the gallery: the
246
+ * viewer is often opened straight from a link or a filmstrip, past whatever
247
+ * cover the grid had.
248
+ */
249
+ const revealed = ref<Set<number>>(new Set())
250
+ const covered = (i: number) => !!props.items[i]?.spoiler && !revealed.value.has(i)
251
+ function reveal(i: number) {
252
+ revealed.value = new Set(revealed.value).add(i)
253
+ }
254
+ watch(
255
+ () => props.open,
256
+ (open) => {
257
+ if (!open) revealed.value = new Set()
258
+ },
259
+ )
260
+
196
261
  function onKeydown(e: KeyboardEvent) {
197
262
  switch (e.key) {
198
263
  case "ArrowRight":
@@ -270,21 +335,51 @@ function onViewportClick(e: MouseEvent) {
270
335
  close()
271
336
  }
272
337
 
273
- async function download() {
274
- const target = item.value
275
- if (!target) return
276
- emit("download", target)
338
+ function sameOrigin(src: string): boolean {
339
+ try {
340
+ const url = new URL(src, window.location.href)
341
+ return url.protocol === "blob:" || url.protocol === "data:" || url.origin === window.location.origin
342
+ } catch {
343
+ return false
344
+ }
345
+ }
346
+
347
+ function save(href: string, name: string, newTab = false) {
277
348
  const a = document.createElement("a")
278
- a.href = target.src
279
- a.download = fileNameOf(target)
280
- // Cross-origin sources ignore `download` and just navigate, so open those in
281
- // a new tab instead of replacing the app.
282
- a.rel = "noopener"
349
+ a.href = href
350
+ if (newTab) {
351
+ a.target = "_blank"
352
+ a.rel = "noopener"
353
+ } else {
354
+ a.download = name
355
+ }
283
356
  document.body.appendChild(a)
284
357
  a.click()
285
358
  a.remove()
286
359
  }
287
360
 
361
+ /*
362
+ * A cross-origin `download` attribute is ignored and the link just navigates,
363
+ * which unloaded the whole app in favour of the image. Such a source is fetched
364
+ * into a blob first; one that refuses CORS opens in a new tab instead.
365
+ */
366
+ async function download() {
367
+ const target = item.value
368
+ if (!target) return
369
+ emit("download", target)
370
+ const name = fileNameOf(target)
371
+ if (sameOrigin(target.src)) return save(target.src, name)
372
+ try {
373
+ const response = await fetch(target.src, { mode: "cors" })
374
+ if (!response.ok) throw new Error(String(response.status))
375
+ const url = URL.createObjectURL(await response.blob())
376
+ save(url, name)
377
+ window.setTimeout(() => URL.revokeObjectURL(url), 0)
378
+ } catch {
379
+ save(target.src, name, true)
380
+ }
381
+ }
382
+
288
383
  async function copy() {
289
384
  const target = item.value
290
385
  if (!target) return
@@ -346,14 +441,15 @@ const ARROW =
346
441
  :style="{ zIndex: layer.scrim }"
347
442
  />
348
443
  <DialogContent
444
+ ref="contentRef"
349
445
  class="fixed inset-0 flex flex-col outline-none data-[state=open]:animate-[lightbox-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[lightbox-out_140ms_cubic-bezier(0.4,0,1,1)] motion-reduce:animate-none"
350
446
  :style="{ zIndex: layer.panel }"
351
447
  @keydown="onKeydown"
352
448
  >
353
449
  <!-- reka wants both for a labelled dialog; the caption is the title. -->
354
- <DialogTitle class="sr-only">{{ item?.title ?? "Image viewer" }}</DialogTitle>
450
+ <DialogTitle class="sr-only">{{ item?.title ?? text.viewer }}</DialogTitle>
355
451
  <DialogDescription class="sr-only">
356
- {{ item?.description ?? `Image ${current + 1} of ${total}` }}
452
+ {{ item?.description ?? position(current) }}
357
453
  </DialogDescription>
358
454
 
359
455
  <!-- Toolbar. Chrome drifts in from its own edge, slightly behind the
@@ -369,34 +465,34 @@ const ARROW =
369
465
  <div class="ml-auto flex items-center gap-1">
370
466
  <slot name="actions" :item="item!" :index="current" />
371
467
 
372
- <button :class="BTN" type="button" title="Zoom out (−)" @click="zoom.zoomBy(1 / 1.3)">
468
+ <button :class="BTN" type="button" :title="text.zoomOut" @click="zoom.zoomBy(1 / 1.3)">
373
469
  <LpIcon name="lucide:zoom-out" :size="18" />
374
470
  </button>
375
- <button :class="BTN" type="button" title="Zoom in (+)" @click="zoom.zoomBy(1.3)">
471
+ <button :class="BTN" type="button" :title="text.zoomIn" @click="zoom.zoomBy(1.3)">
376
472
  <LpIcon name="lucide:zoom-in" :size="18" />
377
473
  </button>
378
474
  <button
379
475
  v-if="rotatable"
380
476
  :class="BTN"
381
477
  type="button"
382
- title="Rotate (R)"
478
+ :title="text.rotate"
383
479
  @click="rotate"
384
480
  >
385
481
  <LpIcon name="lucide:rotate-cw" :size="18" />
386
482
  </button>
387
- <button v-if="copyable" :class="BTN" type="button" title="Copy image" @click="copy">
483
+ <button v-if="copyable" :class="BTN" type="button" :title="text.copy" @click="copy">
388
484
  <LpIcon name="lucide:copy" :size="18" />
389
485
  </button>
390
486
  <button
391
487
  v-if="downloadable"
392
488
  :class="BTN"
393
489
  type="button"
394
- title="Download"
490
+ :title="text.download"
395
491
  @click="download"
396
492
  >
397
493
  <LpIcon name="lucide:download" :size="18" />
398
494
  </button>
399
- <button :class="BTN" type="button" title="Close (Esc)" @click="close">
495
+ <button :class="BTN" type="button" :title="text.close" @click="close">
400
496
  <LpIcon name="lucide:x" :size="20" />
401
497
  </button>
402
498
  </div>
@@ -419,7 +515,7 @@ const ARROW =
419
515
  :class="[ARROW, 'left-4']"
420
516
  type="button"
421
517
  :disabled="!canPrev"
422
- aria-label="Previous image"
518
+ :aria-label="text.previous"
423
519
  @click.stop="go(current - 1)"
424
520
  >
425
521
  <LpIcon name="lucide:chevron-left" :size="24" />
@@ -430,14 +526,28 @@ const ARROW =
430
526
  class="flex flex-col items-center gap-3 text-white/60"
431
527
  >
432
528
  <LpIcon name="lucide:image-off" :size="40" />
433
- <p class="text-sm">This image couldn't be loaded.</p>
529
+ <p class="text-sm">{{ text.failed }}</p>
530
+ </div>
531
+ <div
532
+ v-else-if="item && covered(current)"
533
+ class="flex flex-col items-center gap-3 text-white/70"
534
+ >
535
+ <LpIcon name="lucide:eye-off" :size="36" />
536
+ <p class="text-sm font-medium">{{ text.spoiler }}</p>
537
+ <button
538
+ type="button"
539
+ class="rounded-control bg-white/15 px-3 py-1.5 text-sm text-white outline-none transition-colors hover:bg-white/25 focus-visible:ring-2 focus-visible:ring-ring"
540
+ @click.stop="reveal(current)"
541
+ >
542
+ {{ text.reveal }}
543
+ </button>
434
544
  </div>
435
- <!-- Keyed on src so paging remounts the img and replays the slide;
436
- without the key Vue patches it in place and the change is a hard
437
- cut with no sense of direction. -->
545
+ <!-- Keyed on position and src so paging remounts the img and replays
546
+ the slide, even between two items with the same source (whose
547
+ load event would otherwise never fire, leaving the spinner up). -->
438
548
  <img
439
549
  v-else-if="item"
440
- :key="item.src"
550
+ :key="`${current}:${item.src}`"
441
551
  data-lightbox-image
442
552
  :src="item.src"
443
553
  :alt="item.title ?? ''"
@@ -449,7 +559,7 @@ const ARROW =
449
559
  />
450
560
 
451
561
  <LpIcon
452
- v-if="loading && !failed"
562
+ v-if="loading && !failed && !covered(current)"
453
563
  name="lucide:loader-circle"
454
564
  :size="28"
455
565
  class="absolute animate-spin text-white/50"
@@ -459,7 +569,7 @@ const ARROW =
459
569
  :class="[ARROW, 'right-4']"
460
570
  type="button"
461
571
  :disabled="!canNext"
462
- aria-label="Next image"
572
+ :aria-label="text.next"
463
573
  @click.stop="go(current + 1)"
464
574
  >
465
575
  <LpIcon name="lucide:chevron-right" :size="24" />
@@ -494,13 +604,14 @@ const ARROW =
494
604
  :style="{ '--thumb-delay': `${Math.min(i * 30, 240)}ms` }"
495
605
  class="size-14 shrink-0 overflow-hidden rounded-control outline-none ring-2 transition-[opacity,box-shadow,scale] duration-[var(--duration-fast)] hover:scale-105 focus-visible:ring-ring animate-[lightbox-chrome-in_var(--duration-medium)_var(--ease-emphasized)_both] [animation-delay:var(--thumb-delay)] motion-reduce:animate-none"
496
606
  :class="i === current ? 'opacity-100 ring-brand' : 'opacity-45 ring-transparent hover:opacity-80'"
497
- :aria-label="entry.title ?? `Image ${i + 1}`"
607
+ :aria-label="entry.title ?? position(i)"
498
608
  @click="go(i)"
499
609
  >
500
610
  <img
501
611
  :src="entry.thumb ?? entry.src"
502
612
  :alt="entry.title ?? ''"
503
613
  class="size-full object-cover"
614
+ :class="covered(i) ? 'scale-110 blur-md' : ''"
504
615
  draggable="false"
505
616
  />
506
617
  </button>
@@ -7,11 +7,15 @@ export default { inheritAttrs: false }
7
7
 
8
8
  <script setup lang="ts">
9
9
  import { computed, type Component } from "vue"
10
+ import { useLinkComponent } from "../composables/useLpConfig"
10
11
  import { useMergedAttrs } from "../composables/useMergedClass"
12
+ import { resolveLink, type LinkTarget } from "./link"
11
13
 
12
14
  const props = withDefaults(
13
15
  defineProps<{
14
16
  href?: string
17
+ /** Router destination; rendered through the configured link component. */
18
+ to?: LinkTarget
15
19
  external?: boolean
16
20
  /** Shorthand for `tone="muted"`. */
17
21
  muted?: boolean
@@ -23,11 +27,9 @@ const props = withDefaults(
23
27
  */
24
28
  tone?: "brand" | "ink" | "muted" | "soft"
25
29
  /**
26
- * Root element/component. Defaults to a native <a>. Pass a router link
27
- * component (e.g. NuxtLink or RouterLink) to keep client-side navigation;
28
- * the kit stays DOM-agnostic, the consumer supplies the link component.
29
- * Router links take their destination through their own prop (`to`), which
30
- * falls through as a plain attribute.
30
+ * Root element/component. By default an internal `to`/`href` renders the
31
+ * link component set with provideLpConfig (NuxtLink under the Nuxt module),
32
+ * anything else a native <a>. Pass a component here to override per link.
31
33
  */
32
34
  as?: string | Component
33
35
  /**
@@ -50,13 +52,23 @@ const props = withDefaults(
50
52
  */
51
53
  revealOn?: "self" | "group"
52
54
  }>(),
53
- { variant: "default", as: "a", revealOn: "self" },
55
+ { variant: "default", revealOn: "self" },
54
56
  )
55
57
 
56
- // A router link component owns its destination through its own prop (`to`),
57
- // so `href` is only bound when this really renders an anchor. `target`/`rel`
58
- // stay in play either way — router links honour them for external targets.
59
- const isAnchor = computed(() => props.as === "a")
58
+ const linkComponent = useLinkComponent()
59
+
60
+ // An explicit `as` keeps its old contract (href on an anchor, `to` passed on to
61
+ // the component). Otherwise the target decides, and an external link is always
62
+ // a plain anchor.
63
+ const resolved = computed(() => {
64
+ if (props.as) {
65
+ return props.as === "a"
66
+ ? { is: "a", props: { href: props.href } }
67
+ : { is: props.as, props: props.to != null ? { to: props.to } : { href: props.href } }
68
+ }
69
+ const component = props.external ? "a" : linkComponent.value
70
+ return resolveLink(component, { to: props.to, href: props.href }) ?? { is: "a", props: {} }
71
+ })
60
72
 
61
73
  const rel = computed(() => (props.external ? "noopener noreferrer" : undefined))
62
74
  const target = computed(() => (props.external ? "_blank" : undefined))
@@ -121,12 +133,11 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
121
133
 
122
134
  <template>
123
135
  <component
124
- :is="as"
125
- :href="isAnchor ? href : undefined"
136
+ :is="resolved.is"
137
+ v-bind="{ ...resolved.props, ...rest }"
126
138
  :target="target"
127
139
  :rel="rel"
128
140
  :class="rootClass"
129
- v-bind="rest"
130
141
  >
131
142
  <slot />
132
143
  </component>