@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
@@ -0,0 +1,365 @@
1
+ <script lang="ts">
2
+ export default { inheritAttrs: false }
3
+
4
+ export interface RangeCalendarLabels extends Record<string, string> {
5
+ previous: string
6
+ next: string
7
+ }
8
+
9
+ /** How a range changed: picked by two clicks, or an end reshaped. */
10
+ export type RangeChange = { via: "pick" | "drag" | "keyboard" }
11
+ </script>
12
+
13
+ <script setup lang="ts">
14
+ /*
15
+ * Inline range calendar (reka RangeCalendar). Like LpCalendar the model is ISO
16
+ * strings, here `{ start, end }`, both inclusive. A range is emitted only once
17
+ * both ends are picked: the half-picked state lives inside the calendar, so a
18
+ * consumer never sees a range with a missing end.
19
+ *
20
+ * Ranges can be pressed out the way text is selected on a phone: drag across
21
+ * days to pick one, or grab either end of a finished range and drag it, across
22
+ * rows and into the other month; dragging past the other end flips them. Shift+arrows move the
23
+ * focused end from the keyboard. A reshape emits with `{ via: "drag" }` (or
24
+ * "keyboard"), so a popover around the calendar can stay open while the user
25
+ * fine-tunes instead of closing on the first nudge.
26
+ */
27
+ import { type DateValue, getLocalTimeZone, today } from "@internationalized/date"
28
+ import {
29
+ type DateRange as RekaRange,
30
+ RangeCalendarCell,
31
+ RangeCalendarCellTrigger,
32
+ RangeCalendarGrid,
33
+ RangeCalendarGridBody,
34
+ RangeCalendarGridHead,
35
+ RangeCalendarGridRow,
36
+ RangeCalendarHeadCell,
37
+ RangeCalendarHeader,
38
+ RangeCalendarHeading,
39
+ RangeCalendarNext,
40
+ RangeCalendarPrev,
41
+ RangeCalendarRoot,
42
+ } from "reka-ui"
43
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue"
44
+ import { useLabels } from "../composables/useLpConfig"
45
+ import { useMergedAttrs } from "../composables/useMergedClass"
46
+ import { type DateRange, normalizeRange, parseIsoDay, reshapeRange } from "./dateRange"
47
+ import LpIcon from "./LpIcon.vue"
48
+
49
+ const props = withDefaults(
50
+ defineProps<{
51
+ /** Selected range, ISO "YYYY-MM-DD" ends (v-model). */
52
+ modelValue?: DateRange
53
+ min?: string
54
+ max?: string
55
+ /** Days that cannot be picked at all. */
56
+ isDisabled?: (iso: string) => boolean
57
+ /** Days a range may not include (struck through, and a range cannot span them). */
58
+ isDateUnavailable?: (iso: string) => boolean
59
+ /** Months shown side by side. */
60
+ months?: number
61
+ /** Longest allowed range, in days. */
62
+ maximumDays?: number
63
+ locale?: string
64
+ weekdayFormat?: "narrow" | "short" | "long"
65
+ labels?: Partial<RangeCalendarLabels>
66
+ }>(),
67
+ { months: 1, weekdayFormat: "short" },
68
+ )
69
+
70
+ const emit = defineEmits<{
71
+ (e: "update:modelValue", value: DateRange, change: RangeChange): void
72
+ }>()
73
+
74
+ const text = useLabels<RangeCalendarLabels>(
75
+ "rangeCalendar",
76
+ { previous: "Previous month", next: "Next month" },
77
+ () => props.labels,
78
+ )
79
+
80
+ function toReka(range: DateRange | undefined): RekaRange {
81
+ const r = normalizeRange(range)
82
+ return { start: parseIsoDay(r?.start), end: parseIsoDay(r?.end) }
83
+ }
84
+
85
+ const draft = shallowRef<RekaRange>(toReka(props.modelValue))
86
+ watch(
87
+ () => [props.modelValue?.start, props.modelValue?.end],
88
+ () => {
89
+ draft.value = toReka(props.modelValue)
90
+ },
91
+ )
92
+
93
+ const placeholder = shallowRef<DateValue>(draft.value.start ?? today(getLocalTimeZone()))
94
+
95
+ function onUpdate(v: RekaRange | null) {
96
+ draft.value = v ?? { start: undefined, end: undefined }
97
+ if (v?.start && v.end) emit("update:modelValue", { start: v.start.toString(), end: v.end.toString() }, { via: "pick" })
98
+ }
99
+
100
+ const committed = computed(() => normalizeRange(props.modelValue))
101
+
102
+ /** Whether a day may sit inside a reshaped range. */
103
+ function allowed(iso: string): boolean {
104
+ const day = parseIsoDay(iso)
105
+ if (!day) return false
106
+ if (minValue.value && day.compare(minValue.value) < 0) return false
107
+ if (maxValue.value && day.compare(maxValue.value) > 0) return false
108
+ return !(props.isDisabled?.(iso) ?? false)
109
+ }
110
+
111
+ function reshape(anchor: string, moving: string): DateRange | null {
112
+ return reshapeRange(anchor, moving, {
113
+ allowed,
114
+ unavailable: props.isDateUnavailable,
115
+ maximumDays: props.maximumDays,
116
+ })
117
+ }
118
+
119
+ const root = ref<HTMLElement | null>(null)
120
+
121
+ /*
122
+ * Press-and-drag, the way a phone selects text. A press on either end of the
123
+ * range drags that end; a press anywhere else starts a new range that follows
124
+ * the pointer. A mouse or pen drags at once. A finger has to hold still for
125
+ * HOLD_MS first, so an ordinary swipe still scrolls the page; after that the
126
+ * page stops scrolling and the finger selects. A press that never moves stays
127
+ * an ordinary click for reka.
128
+ */
129
+ const HOLD_MS = 320
130
+ const SLOP_PX = 8
131
+
132
+ /** The day the range pivots around while the pointer moves. */
133
+ let anchor: string | null = null
134
+ let pointerId = -1
135
+ let armed = false
136
+ let held = false
137
+ let dragged = false
138
+ let swallowClick = false
139
+ let lastDay = ""
140
+ let startX = 0
141
+ let startY = 0
142
+ let holdTimer: ReturnType<typeof setTimeout> | undefined
143
+ const dragging = ref(false)
144
+
145
+ function cellAt(x: number, y: number): HTMLElement | null {
146
+ const hit = document.elementFromPoint(x, y)
147
+ const cell = hit?.closest<HTMLElement>("[data-reka-calendar-cell-trigger]")
148
+ if (!cell || !root.value?.contains(cell)) return null
149
+ if (cell.hasAttribute("data-outside-view") || cell.hasAttribute("data-disabled")) return null
150
+ return cell
151
+ }
152
+
153
+ function reset() {
154
+ if (holdTimer) clearTimeout(holdTimer)
155
+ holdTimer = undefined
156
+ anchor = null
157
+ armed = false
158
+ held = false
159
+ dragged = false
160
+ dragging.value = false
161
+ }
162
+
163
+ function onPointerDown(e: PointerEvent) {
164
+ if (e.button !== 0) return
165
+ const cell = (e.target as Element | null)?.closest<HTMLElement>("[data-reka-calendar-cell-trigger]")
166
+ const day = cell?.dataset.value
167
+ if (!cell || !day || cell.hasAttribute("data-disabled") || cell.hasAttribute("data-unavailable")) return
168
+ reset()
169
+ const range = committed.value
170
+ const onEdge = !!range && (day === range.start || day === range.end)
171
+ anchor = onEdge && range ? (day === range.start ? range.end : range.start) : day
172
+ pointerId = e.pointerId
173
+ lastDay = day
174
+ startX = e.clientX
175
+ startY = e.clientY
176
+ // A finger on an end drags at once: the end cells don't pan the page
177
+ // (touch-none), so there is no swipe to tell it apart from.
178
+ if (e.pointerType !== "touch" || onEdge) {
179
+ armed = true
180
+ return
181
+ }
182
+ holdTimer = setTimeout(() => {
183
+ holdTimer = undefined
184
+ armed = true
185
+ held = true
186
+ dragging.value = true
187
+ draft.value = toReka({ start: day, end: day })
188
+ navigator.vibrate?.(8)
189
+ }, HOLD_MS)
190
+ }
191
+
192
+ function onPointerMove(e: PointerEvent) {
193
+ if (anchor === null || e.pointerId !== pointerId) return
194
+ if (!armed) {
195
+ // Moved before the hold landed: that is a scroll, not a selection.
196
+ if (Math.hypot(e.clientX - startX, e.clientY - startY) > SLOP_PX) reset()
197
+ return
198
+ }
199
+ const day = cellAt(e.clientX, e.clientY)?.dataset.value
200
+ if (!day || day === lastDay) return
201
+ const next = reshape(anchor, day)
202
+ if (!next) return
203
+ lastDay = day
204
+ if (!dragged) {
205
+ dragged = true
206
+ dragging.value = true
207
+ // Capture keeps the drag alive past the grid's edge. A pointer the browser
208
+ // no longer tracks cannot be captured, and the drag works without it.
209
+ try {
210
+ root.value?.setPointerCapture(e.pointerId)
211
+ } catch {}
212
+ }
213
+ draft.value = toReka(next)
214
+ }
215
+
216
+ function onPointerUp(e: PointerEvent) {
217
+ if (anchor === null || e.pointerId !== pointerId) return
218
+ const finished = dragged || held
219
+ if (root.value?.hasPointerCapture(e.pointerId)) root.value.releasePointerCapture(e.pointerId)
220
+ reset()
221
+ if (!finished || e.type === "pointercancel") {
222
+ if (finished) draft.value = toReka(props.modelValue)
223
+ return
224
+ }
225
+ // The click that follows would read as "start a new range"; it is swallowed.
226
+ swallowClick = true
227
+ setTimeout(() => (swallowClick = false), 0)
228
+ const { start, end } = draft.value
229
+ if (start && end) emit("update:modelValue", { start: start.toString(), end: end.toString() }, { via: "drag" })
230
+ }
231
+
232
+ function onClickCapture(e: MouseEvent) {
233
+ if (!swallowClick) return
234
+ swallowClick = false
235
+ e.stopPropagation()
236
+ e.preventDefault()
237
+ }
238
+
239
+ // Once a hold has turned a finger into a selection, the page must not scroll
240
+ // under it. Only a non-passive touchmove can say so mid-gesture.
241
+ function onTouchMove(e: TouchEvent) {
242
+ if (armed && anchor !== null) e.preventDefault()
243
+ }
244
+ function onContextMenu(e: Event) {
245
+ if (held || dragging.value) e.preventDefault()
246
+ }
247
+ onMounted(() => root.value?.addEventListener("touchmove", onTouchMove, { passive: false }))
248
+ onBeforeUnmount(() => {
249
+ root.value?.removeEventListener("touchmove", onTouchMove)
250
+ reset()
251
+ })
252
+
253
+ const STEP: Record<string, number> = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }
254
+
255
+ function onKeydownCapture(e: KeyboardEvent) {
256
+ const step = STEP[e.key]
257
+ const range = committed.value
258
+ if (!e.shiftKey || step === undefined || !range) return
259
+ const day = (e.target as HTMLElement | null)?.dataset?.value
260
+ if (!day || (day !== range.start && day !== range.end)) return
261
+ const moved = parseIsoDay(day)?.add({ days: step }).toString()
262
+ if (!moved) return
263
+ e.preventDefault()
264
+ e.stopPropagation()
265
+ const other = day === range.start ? range.end : range.start
266
+ const next = reshape(other, moved)
267
+ if (!next) return
268
+ placeholder.value = parseIsoDay(moved) ?? placeholder.value
269
+ emit("update:modelValue", next, { via: "keyboard" })
270
+ void nextTick(() => root.value?.querySelector<HTMLElement>(`[data-value="${moved}"]:not([data-outside-view])`)?.focus())
271
+ }
272
+
273
+ const minValue = computed(() => parseIsoDay(props.min))
274
+ const maxValue = computed(() => parseIsoDay(props.max))
275
+ const disabledFor = (date: DateValue) => props.isDisabled?.(date.toString()) ?? false
276
+ const unavailableFor = (date: DateValue) => props.isDateUnavailable?.(date.toString()) ?? false
277
+
278
+ const navBtn =
279
+ "flex size-8 items-center justify-center rounded-control text-muted outline-none transition-[color,background-color,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] hover:bg-surface-soft hover:text-ink active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring"
280
+
281
+ const { class: rootClass, attrs: rest } = useMergedAttrs(
282
+ "inline-block rounded-card border border-line bg-surface-raised p-3",
283
+ )
284
+ </script>
285
+
286
+ <template>
287
+ <RangeCalendarRoot
288
+ v-slot="{ weekDays, grid }"
289
+ :ref="(c) => (root = (c as { $el?: HTMLElement } | null)?.$el ?? null)"
290
+ v-model:placeholder="placeholder"
291
+ :model-value="draft"
292
+ :min-value="minValue"
293
+ :max-value="maxValue"
294
+ :is-date-disabled="disabledFor"
295
+ :is-date-unavailable="unavailableFor"
296
+ :number-of-months="months"
297
+ :maximum-days="maximumDays"
298
+ :locale="locale"
299
+ :weekday-format="weekdayFormat"
300
+ prevent-deselect
301
+ paged-navigation
302
+ fixed-weeks
303
+ :class="rootClass"
304
+ v-bind="rest"
305
+ :data-dragging="dragging || undefined"
306
+ @update:model-value="onUpdate"
307
+ @pointerdown="onPointerDown"
308
+ @pointermove="onPointerMove"
309
+ @pointerup="onPointerUp"
310
+ @pointercancel="onPointerUp"
311
+ @click.capture="onClickCapture"
312
+ @contextmenu="onContextMenu"
313
+ @keydown.capture="onKeydownCapture"
314
+ >
315
+ <RangeCalendarHeader class="mb-2 flex items-center justify-between gap-2">
316
+ <RangeCalendarPrev :class="navBtn" :aria-label="text.previous">
317
+ <LpIcon name="lucide:chevron-left" :size="16" />
318
+ </RangeCalendarPrev>
319
+ <RangeCalendarHeading class="text-sm font-semibold text-ink" />
320
+ <RangeCalendarNext :class="navBtn" :aria-label="text.next">
321
+ <LpIcon name="lucide:chevron-right" :size="16" />
322
+ </RangeCalendarNext>
323
+ </RangeCalendarHeader>
324
+
325
+ <div class="flex gap-4">
326
+ <RangeCalendarGrid
327
+ v-for="month in grid"
328
+ :key="month.value.toString()"
329
+ class="border-collapse select-none"
330
+ >
331
+ <RangeCalendarGridHead>
332
+ <RangeCalendarGridRow class="mb-1 flex">
333
+ <RangeCalendarHeadCell
334
+ v-for="day in weekDays"
335
+ :key="day"
336
+ class="w-9 text-center text-[11px] font-medium text-muted"
337
+ >
338
+ {{ day }}
339
+ </RangeCalendarHeadCell>
340
+ </RangeCalendarGridRow>
341
+ </RangeCalendarGridHead>
342
+ <RangeCalendarGridBody>
343
+ <RangeCalendarGridRow v-for="(weekDates, i) in month.rows" :key="`w-${i}`" class="flex">
344
+ <RangeCalendarCell
345
+ v-for="weekDate in weekDates"
346
+ :key="weekDate.toString()"
347
+ :date="weekDate"
348
+ class="py-0.5"
349
+ >
350
+ <!-- Inside the range the pill joins its neighbours (no gap, no
351
+ rounding); the two ends keep the solid brand pill. The
352
+ preview while picking is lighter: with maximumDays reka
353
+ highlights the whole reachable window, not the range. -->
354
+ <RangeCalendarCellTrigger
355
+ :day="weekDate"
356
+ :month="month.value"
357
+ class="flex h-8 w-9 items-center justify-center rounded-control text-sm text-ink outline-none transition-[color,background-color] duration-[var(--duration-fast)] hover:bg-surface-soft focus-visible:ring-2 focus-visible:ring-ring data-[outside-view]:text-muted/40 data-[today]:font-semibold data-[today]:not-data-[selected]:text-brand data-[selected]:rounded-none data-[selected]:bg-brand-soft data-[highlighted]:rounded-none data-[highlighted]:bg-brand-soft/60 data-[selection-start]:rounded-l-control data-[highlighted-start]:rounded-l-control data-[selection-end]:rounded-r-control data-[highlighted-end]:rounded-r-control data-[selection-start]:bg-brand data-[selection-start]:font-semibold data-[selection-start]:text-ink-inverse data-[selection-end]:bg-brand data-[selection-end]:font-semibold data-[selection-end]:text-ink-inverse data-[outside-view]:data-[selected]:bg-transparent data-[outside-view]:data-[highlighted]:bg-transparent data-[disabled]:pointer-events-none data-[disabled]:opacity-35 data-[unavailable]:pointer-events-none data-[unavailable]:line-through data-[unavailable]:opacity-35 data-[selection-start]:cursor-grab data-[selection-end]:cursor-grab data-[selection-start]:touch-none data-[selection-end]:touch-none [-webkit-touch-callout:none] in-data-[dragging]:cursor-grabbing"
358
+ />
359
+ </RangeCalendarCell>
360
+ </RangeCalendarGridRow>
361
+ </RangeCalendarGridBody>
362
+ </RangeCalendarGrid>
363
+ </div>
364
+ </RangeCalendarRoot>
365
+ </template>
@@ -86,6 +86,9 @@ const style = computed(() => ({
86
86
 
87
87
  .lp-roll__item {
88
88
  display: inline-block;
89
+ max-width: 100%;
90
+ overflow: hidden;
91
+ text-overflow: ellipsis;
89
92
  white-space: nowrap;
90
93
  backface-visibility: hidden;
91
94
  }
@@ -55,6 +55,21 @@ const viewportEl = computed<HTMLElement | null>(
55
55
  )
56
56
  defineExpose({ viewportEl })
57
57
 
58
+ /*
59
+ * The viewport is focusable so the keyboard can scroll it, and Chrome marks it
60
+ * :focus-visible as soon as any key is pressed after a click inside, so the
61
+ * browser's white outline framed the whole page on the first shortcut. The
62
+ * ring is kept for focus that arrived by Tab and dropped for focus a pointer
63
+ * put there.
64
+ */
65
+ const pointerFocus = ref(false)
66
+ function onViewportPointerDown() {
67
+ pointerFocus.value = true
68
+ }
69
+ function onViewportBlur() {
70
+ pointerFocus.value = false
71
+ }
72
+
58
73
  // `opacity-0` + the hidden-state fade is what keeps the bar invisible at rest:
59
74
  // with force-mount the element stays in the DOM, so a one-shot fade-out alone
60
75
  // would snap back to visible once the animation finished.
@@ -241,10 +256,15 @@ function onThumbPointerDown() {
241
256
 
242
257
  <ScrollAreaViewport
243
258
  ref="viewportRef"
244
- class="w-full min-h-0 min-w-0 flex-1 [&>div]:!block [&>div]:!min-w-0"
245
- :class="instant ? '' : 'scroll-smooth motion-reduce:scroll-auto'"
259
+ class="w-full min-h-0 min-w-0 flex-1 rounded-[inherit] outline-none [&>div]:!block [&>div]:!min-w-0"
260
+ :class="[
261
+ instant ? '' : 'scroll-smooth motion-reduce:scroll-auto',
262
+ pointerFocus ? '' : 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
263
+ ]"
246
264
  :style="fade ? { maskImage: fadeMask, WebkitMaskImage: fadeMask } : undefined"
247
265
  @scroll.passive="onViewportScroll"
266
+ @pointerdown="onViewportPointerDown"
267
+ @focusout="(e: FocusEvent) => e.target === e.currentTarget && onViewportBlur()"
248
268
  >
249
269
  <div :class="contentClass">
250
270
  <slot />
@@ -16,6 +16,7 @@ export default { inheritAttrs: false }
16
16
  import { Motion } from "motion-v"
17
17
  import { ToggleGroupItem, ToggleGroupRoot } from "reka-ui"
18
18
  import { useId } from "vue"
19
+ import { useFieldControl } from "../composables/useField"
19
20
  import { useMergedAttrs } from "../composables/useMergedClass"
20
21
  import { usePillTransition } from "../composables/usePillTransition"
21
22
  import LpIcon from "./LpIcon.vue"
@@ -25,6 +26,11 @@ export interface SegmentedOption {
25
26
  label?: string
26
27
  /** Optional iconify name shown before the label (or alone, icon-only). */
27
28
  icon?: string
29
+ /**
30
+ * Accessible name for an icon-only segment. Without it the raw `value` is
31
+ * announced, which is an identifier rather than words.
32
+ */
33
+ ariaLabel?: string
28
34
  }
29
35
 
30
36
  const props = withDefaults(
@@ -66,6 +72,8 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
66
72
  ].join(" "),
67
73
  )
68
74
 
75
+ const field = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
76
+
69
77
  const pillId = `lp-segmented-${useId()}`
70
78
  const pillTransition = usePillTransition()
71
79
  </script>
@@ -74,7 +82,9 @@ const pillTransition = usePillTransition()
74
82
  <ToggleGroupRoot
75
83
  :model-value="modelValue"
76
84
  type="single"
77
- :disabled="disabled"
85
+ :disabled="field.disabled"
86
+ :aria-labelledby="field.labelId"
87
+ :aria-describedby="field.describedBy"
78
88
  :rovingFocus="true"
79
89
  :class="rootClass"
80
90
  v-bind="rest"
@@ -84,7 +94,7 @@ const pillTransition = usePillTransition()
84
94
  v-for="opt in options"
85
95
  :key="opt.value"
86
96
  :value="opt.value"
87
- :aria-label="opt.label ? undefined : opt.value"
97
+ :aria-label="opt.ariaLabel ?? (opt.label ? undefined : opt.value)"
88
98
  class="relative inline-flex h-full items-center justify-center gap-1.5 rounded-md px-3 font-medium outline-none transition-colors duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] focus-visible:ring-2 focus-visible:ring-ring data-[state=on]:text-ink data-[state=off]:text-muted data-[state=off]:hover:text-ink disabled:cursor-not-allowed disabled:opacity-55"
89
99
  :class="block ? 'flex-1' : ''"
90
100
  >
Binary file
@@ -10,7 +10,10 @@
10
10
  * of the same title merge, and a combo is listed once.
11
11
  *
12
12
  * Combos are written the way they read ("Ctrl+Shift+M", "Ctrl++", "←→↑↓") and
13
- * split on "+" into one <kbd> each.
13
+ * split on "+" into one <kbd> each; spaces separate the steps of a sequence
14
+ * ("G I" reads "G then I"). In `live` mode an entry whose keys another mounted
15
+ * binding also answers carries a marker, so a clash shows up where people
16
+ * look for keys rather than only in the console.
14
17
  */
15
18
  import { computed } from "vue"
16
19
  import LpModal from "./LpModal.vue"
@@ -18,8 +21,11 @@ import {
18
21
  activeShortcuts,
19
22
  appleModifierLabel,
20
23
  mergeShortcutGroups,
24
+ useAppleKeyboard,
25
+ useHotkeys,
21
26
  type ShortcutGroup,
22
27
  } from "../composables/useHotkeys"
28
+ import { useLabels } from "../composables/useLpConfig"
23
29
 
24
30
  const props = withDefaults(
25
31
  defineProps<{
@@ -31,21 +37,54 @@ const props = withDefaults(
31
37
  description?: string
32
38
  /** Frosted glass panel, passed to LpModal. Follows `provideGlass` when unset. */
33
39
  glass?: boolean
40
+ /**
41
+ * A key that toggles the reference, e.g. "F1". Bound only while the dialog
42
+ * is mounted, also inside inputs and over other overlays, and the browser's
43
+ * own use of the key (Chrome opens its help page on F1) is suppressed.
44
+ */
45
+ hotkey?: string
34
46
  }>(),
35
- { open: false, groups: () => [], live: false, title: "Keyboard shortcuts", glass: undefined },
47
+ { open: false, groups: () => [], live: false, title: undefined, glass: undefined },
36
48
  )
37
49
 
50
+ const text = useLabels("shortcuts", {
51
+ title: "Keyboard shortcuts",
52
+ then: "then",
53
+ conflict: "Also bound elsewhere: only one of them runs",
54
+ group: "General",
55
+ })
56
+ const apple = useAppleKeyboard()
57
+
38
58
  /*
39
59
  * One key per "+", except a "+" that is the key itself: "Ctrl++" is Ctrl and
40
60
  * plus, not Ctrl and two blanks.
41
61
  */
42
- function keysOf(combo: string): string[] {
43
- return combo.split(/\+(?!$)/)
62
+ function keysOf(chord: string): string[] {
63
+ return chord.split(/\+(?!$)/)
64
+ }
65
+
66
+ function stepsOf(combo: string): string[] {
67
+ return combo.trim().split(/\s+/)
44
68
  }
45
69
 
46
70
  const shown = computed(() => (props.live ? mergeShortcutGroups(props.groups, activeShortcuts.value) : props.groups))
47
71
 
48
72
  const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
73
+
74
+ useHotkeys(() =>
75
+ props.hotkey
76
+ ? [
77
+ {
78
+ key: props.hotkey,
79
+ allowInInput: true,
80
+ overLayers: true,
81
+ repeat: false,
82
+ help: { group: text.value.group, label: props.title ?? text.value.title },
83
+ handler: () => emit("update:open", !props.open),
84
+ },
85
+ ]
86
+ : [],
87
+ )
49
88
  </script>
50
89
 
51
90
  <template>
@@ -53,7 +92,7 @@ const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
53
92
  :glass="props.glass"
54
93
  :open="props.open"
55
94
  size="lg"
56
- :title="props.title"
95
+ :title="props.title ?? text.title"
57
96
  :description="props.description"
58
97
  @update:open="(value: boolean) => emit('update:open', value)"
59
98
  >
@@ -62,11 +101,23 @@ const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
62
101
  <h3>{{ group.title }}</h3>
63
102
  <dl>
64
103
  <div v-for="entry in group.entries" :key="entry.combo" class="shortcut-row">
65
- <dt>{{ entry.label }}</dt>
104
+ <dt>
105
+ {{ entry.label }}
106
+ <span
107
+ v-if="entry.conflict"
108
+ class="shortcut-conflict"
109
+ role="img"
110
+ :aria-label="text.conflict"
111
+ :title="text.conflict"
112
+ >!</span>
113
+ </dt>
66
114
  <dd>
67
- <kbd v-for="(key, index) in keysOf(entry.combo)" :key="`${key}-${index}`">
68
- {{ appleModifierLabel(key.trim()) }}
69
- </kbd>
115
+ <template v-for="(step, stepIndex) in stepsOf(entry.combo)" :key="`${step}-${stepIndex}`">
116
+ <span v-if="stepIndex" class="shortcut-then">{{ text.then }}</span>
117
+ <kbd v-for="(key, index) in keysOf(step)" :key="`${key}-${index}`">
118
+ {{ appleModifierLabel(key.trim(), apple) }}
119
+ </kbd>
120
+ </template>
70
121
  </dd>
71
122
  </div>
72
123
  </dl>
@@ -114,6 +165,29 @@ const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
114
165
  min-width: 0;
115
166
  }
116
167
 
168
+ .shortcut-conflict {
169
+ display: inline-flex;
170
+ width: 14px;
171
+ height: 14px;
172
+ margin-left: 6px;
173
+ align-items: center;
174
+ justify-content: center;
175
+ border-radius: 999px;
176
+ background: var(--color-danger-soft);
177
+ color: var(--color-danger);
178
+ font-size: 0.6rem;
179
+ font-weight: 700;
180
+ vertical-align: middle;
181
+ cursor: help;
182
+ }
183
+
184
+ .shortcut-then {
185
+ align-self: center;
186
+ padding: 0 2px;
187
+ color: var(--color-muted);
188
+ font-size: 0.68rem;
189
+ }
190
+
117
191
  .shortcut-row dd {
118
192
  display: flex;
119
193
  flex-shrink: 0;